From acde0b316c86df2e98815086230abc9a3500f746 Mon Sep 17 00:00:00 2001
From: Shpuld Shpuldson <shpuld@gmail.com>
Date: Tue, 7 Nov 2017 12:22:33 +0200
Subject: [PATCH 01/21] Changes inside status html: restrict image/video sizes,
 make blockquotes waste less space.

---
 src/components/status/status.vue | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index b8f71dd4..cc315a90 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -185,6 +185,15 @@
 
      .status-content {
          margin: 3px 15px 4px 0;
+         img, video {
+           max-width: 100%;
+           max-height: 400px;
+         }
+
+         blockquote {
+           margin: 0.2em 0 0.2em 2em;
+           font-style: italic;
+         }
      }
 
      p {

From 7516cd859f0c9bc078548f801cbb6a63b72ced97 Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 15:14:37 +0100
Subject: [PATCH 02/21] Prepare for i18n.

---
 package.json                                  |  1 +
 src/components/nav_panel/nav_panel.vue        |  8 +--
 .../notifications/notifications.vue           |  6 +-
 src/components/settings/settings.vue          | 20 +++---
 src/components/timeline/timeline.vue          | 12 ++--
 src/components/user_card/user_card.vue        |  2 +-
 .../user_card_content/user_card_content.vue   | 28 ++++----
 .../user_settings/user_settings.vue           | 32 ++++-----
 src/i18n/messages.js                          | 70 +++++++++++++++++++
 src/main.js                                   | 11 +++
 yarn.lock                                     |  4 ++
 11 files changed, 142 insertions(+), 52 deletions(-)
 create mode 100644 src/i18n/messages.js

diff --git a/package.json b/package.json
index 63fd490d..e8d84274 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
     "sanitize-html": "^1.13.0",
     "sass-loader": "^4.0.2",
     "vue": "^2.3.4",
+    "vue-i18n": "^7.3.2",
     "vue-router": "^2.5.3",
     "vue-template-compiler": "^2.3.4",
     "vue-timeago": "^3.1.2",
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index d4339778..aea841e9 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -4,22 +4,22 @@
       <ul class="base03-border">
         <li v-if='currentUser'>
           <router-link class="base00-background" to='/main/friends'>
-            Timeline
+            {{ $t("nav.timeline") }}
           </router-link>
         </li>
         <li v-if='currentUser'>
           <router-link class="base00-background" :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
-            Mentions
+            {{ $t("nav.mentions") }}
           </router-link>
         </li>
         <li>
           <router-link class="base00-background" to='/main/public'>
-            Public Timeline
+            {{ $t("nav.public_tl") }}
           </router-link>
         </li>
         <li>
           <router-link class="base00-background" to='/main/all'>
-            The Whole Known Network
+            {{ $t("nav.twkn") }}
           </router-link>
         </li>
       </ul>
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 2ad7c488..dfc7b0c9 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -3,8 +3,8 @@
     <div class="panel panel-default base00-background">
       <div class="panel-heading base01-background base04">
         <span class="unseen-count" v-if="unseenCount">{{unseenCount}}</span>
-        Notifications
-        <button @click.prevent="markAsSeen" class="base05 base01-background read-button">Read!</button>
+        {{$t('notifications.notifications')}}
+        <button @click.prevent="markAsSeen" class="base05 base01-background read-button">{{$t('notifications.read')}}</button>
       </div>
       <div class="panel-body base03-border">
         <div v-for="notification in visibleNotifications" :key="notification" class="notification" :class='{"unseen": !notification.seen}'>
@@ -44,7 +44,7 @@
                 <i class="fa icon-user-plus lit"></i>
               </h1>
               <div>
-                <router-link :to="{ name: 'user-profile', params: { id: notification.action.user.id } }">@{{ notification.action.user.screen_name }}</router-link> followed you
+                <router-link :to="{ name: 'user-profile', params: { id: notification.action.user.id } }">@{{ notification.action.user.screen_name }}</router-link> {{$t('notifications.followed_you')}}
               </div>
             </div>
           </div>
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index 6ff96fec..5978e4ed 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -1,40 +1,40 @@
 <template>
   <div class="settings panel panel-default base00-background">
     <div class="panel-heading base01-background base04">
-      Settings
+      {{$t('settings.settings')}}
     </div>
     <div class="panel-body">
       <div class="setting-item">
-        <h2>Theme</h2>
+        <h2>{{$t('settings.theme')}}</h2>
         <style-switcher></style-switcher>
       </div>
       <div class="setting-item">
-        <h2>Filtering</h2>
-        <p>All notices containing these words will be muted, one per line</p>
+        <h2>{{$t('settings.filtering')}}</h2>
+        <p>{{$t('settings.filtering_explanation')}}</p>
         <textarea id="muteWords" v-model="muteWordsString"></textarea>
       </div>
       <div class="setting-item">
-        <h2>Attachments</h2>
+        <h2>{{$t('settings.attachments')}}</h2>
         <ul class="setting-list">
             <li>
                 <input type="checkbox" id="hideAttachments" v-model="hideAttachmentsLocal">
-                <label for="hideAttachments">Hide attachments in timeline</label>
+                <label for="hideAttachments">{{$t('settings.hide_attachments_in_tl')}}</label>
             </li>
             <li>
                 <input type="checkbox" id="hideAttachmentsInConv" v-model="hideAttachmentsInConvLocal">
-                <label for="hideAttachmentsInConv">Hide attachments in conversations</label>
+                <label for="hideAttachmentsInConv">{{$t('settings.hide_attachments_in_convo')}}</label>
             </li>
             <li>
                 <input type="checkbox" id="hideNsfw" v-model="hideNsfwLocal">
-                <label for="hideNsfw">Enable clickthrough NSFW attachment hiding</label>
+                <label for="hideNsfw">{{$t('settings.nsfw_clickthrough')}}</label>
             </li>
             <li>
                 <input type="checkbox" id="autoLoad" v-model="autoLoadLocal">
-                <label for="autoLoad">Enable automatic loading when scrolled to the bottom</label>
+                <label for="autoLoad">{{$t('settings.autoload')}}</label>
             </li>
             <li>
                 <input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal">
-                <label for="hoverPreview">Enable reply-link preview on mouse hover</label>
+                <label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label>
             </li>
         </ul>
       </div>
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index f36770d6..01f330c2 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -5,20 +5,20 @@
         {{title}}
       </div>
       <button @click.prevent="showNewStatuses" class="base05 base01-background loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError">
-        Show new ({{timeline.newStatusCount}})
+        {{$t('timeline.show_new')}} ({{timeline.newStatusCount}})
       </button>
       <div @click.prevent class="base06 error  loadmore-text" v-if="timelineError">
-          Error fetching updates
+        {{$t('timeline.error_fetching')}}
       </div>
       <div @click.prevent class="base04 base01-background loadmore-text" v-if="!timeline.newStatusCount > 0 && !timelineError">
-        Up-to-date
+        {{$t('timeline.up_to_date')}}
       </div>
     </div>
     <div class="panel-body">
       <div class="timeline">
         <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status"></status-or-conversation>
         <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading">
-          <div class="base01-background base03-border new-status-notification text-center">Load older statuses.</div>
+          <div class="base01-background base03-border new-status-notification text-center">{{$t('timeline.load_older')}}</div>
         </a>
           <div class="base01-background base03-border new-status-notification text-center" v-else>...</div>
       </div>
@@ -27,7 +27,7 @@
   <div class="timeline panel panel-default" v-else-if="viewing == 'followers'">
     <div class="panel-heading timeline-heading base01-background base04">
       <div class="title">
-        Followers
+        {{$t('user_card.followers')}}
       </div>
     </div>
     <div class="panel-body">
@@ -39,7 +39,7 @@
   <div class="timeline panel panel-default" v-else-if="viewing == 'friends'">
     <div class="panel-heading timeline-heading base01-background base04">
       <div class="title">
-        Following
+        {{$t('user_card.followees')}}
       </div>
     </div>
     <div class="panel-body">
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index cc2f3978..a9b8b602 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -10,7 +10,7 @@
       <div class="user-name">
         {{ user.name }}
         <span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
-            Follows you!
+            {{ $t('user_card.follows_you') }}
         </span>
       </div>
       <a :href="user.statusnet_profile_url" target="blank"><div class="user-screen-name">@{{ user.screen_name }}</div></a>
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index baa71cd0..4895f36f 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -19,27 +19,31 @@
         </div>
         <div v-if="isOtherUser" class="user-interactions">
           <div v-if="user.follows_you && loggedIn" class="following base06">
-            Follows you!
+            {{ $t('user_card.follows_you') }}
           </div>
           <div class="follow" v-if="loggedIn">
             <span v-if="user.following">
               <!--Following them!-->
               <button @click="unfollowUser" class="base04 base00-background pressed">
-                Following!
+                {{ $t('user_card.following') }}
               </button>
             </span>
             <span v-if="!user.following">
               <button @click="followUser" class="base05 base02-background">
-                Follow
+                {{ $t('user_card.follow') }}
               </button>
             </span>
           </div>
           <div class='mute' v-if='isOtherUser'>
             <span v-if='user.muted'>
-              <button @click="toggleMute" class="base04 base00-background pressed">Muted</button>
+              <button @click="toggleMute" class="base04 base00-background pressed">
+                {{ $t('user_card.muted') }}
+              </button>
             </span>
             <span v-if='!user.muted'>
-              <button @click="toggleMute" class="base05 base02-background">Mute</button>
+              <button @click="toggleMute" class="base05 base02-background">
+                {{ $t('user_card.mute') }}
+              </button>
             </span>
           </div>
         </div>
@@ -48,18 +52,18 @@
     <div class="panel-body profile-panel-body" :style="bodyStyle">
       <div class="user-counts">
         <div class="user-count">
-          <a href="#" v-on:click.prevent="setProfileView('statuses')" v-if="switcher"><h5 class="base05">Statuses</h5></a>
-          <h5 v-else>Statuses</h5>
-          <span class="base05">{{user.statuses_count}} <br><span class="dailyAvg">{{dailyAvg}} per day</span></span>
+          <a href="#" v-on:click.prevent="setProfileView('statuses')" v-if="switcher"><h5 class="base05">{{ $t('user_card.statuses') }}</h5></a>
+          <h5 v-else>{{ $t('user_card.statuses') }}</h5>
+          <span class="base05">{{user.statuses_count}} <br><span class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span></span>
         </div>
         <div class="user-count">
-          <a href="#" v-on:click.prevent="setProfileView('friends')" v-if="switcher"><h5 class="base05">Following</h5></a>
-          <h5 v-else>Following</h5>
+          <a href="#" v-on:click.prevent="setProfileView('friends')" v-if="switcher"><h5 class="base05">{{ $t('user_card.followees') }}</h5></a>
+          <h5 v-else>{{ $t('user_card.followees') }}</h5>
           <span class="base05">{{user.friends_count}}</span>
         </div>
         <div class="user-count">
-          <a href="#" v-on:click.prevent="setProfileView('followers')" v-if="switcher"><h5 class="base05">Followers</h5></a>
-          <h5 v-else>Followers</h5>
+          <a href="#" v-on:click.prevent="setProfileView('followers')" v-if="switcher"><h5 class="base05">{{ $t('user_card.followers') }}</h5></a>
+          <h5 v-else>{{ $t('user_card.followers') }}</h5>
           <span class="base05">{{user.followers_count}}</span>
         </div>
       </div>
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
index 11da79e4..003ee3bd 100644
--- a/src/components/user_settings/user_settings.vue
+++ b/src/components/user_settings/user_settings.vue
@@ -1,53 +1,53 @@
 <template>
   <div class="settings panel panel-default base00-background">
     <div class="panel-heading base01-background base04">
-      User Settings
+      {{$t('settings.user_settings')}}
     </div>
     <div class="panel-body profile-edit">
       <div class="setting-item">
-        <h3>Name & Bio</h3>
-        <p>Name</p>
+        <h3>{{$t('settings.name_bio')}}</h3>
+        <p>{{$t('settings.name')}}</p>
         <input class='name-changer base03-border' id='username' v-model="newname" :value="user.screen_name"></input>
-        <p>Bio</p>
+        <p>{{$t('settings.bio')}}</p>
         <textarea class="bio base03-border" v-model="newbio"></textarea>
-        <button :disabled='newname.length <= 0' class="btn btn-default base05 base01-background" @click="updateProfile">Submit</button>
+        <button :disabled='newname.length <= 0' class="btn btn-default base05 base01-background" @click="updateProfile">{{$t('general.submit')}}</button>
       </div>
       <div class="setting-item">
-        <h3>Avatar</h3>
-        <p>Your current avatar:</p>
+        <h3>{{$t('settings.avatar')}}</h3>
+        <p>{{$t('settings.current_avatar')}}</p>
         <img :src="user.profile_image_url_original" class="old-avatar"></img>
-        <p>Set new avatar:</p>
+        <p>{{$t('settings.set_new_avatar')}}</p>
         <img class="new-avatar" v-bind:src="previews[0]" v-if="previews[0]">
         </img>
         <div>
           <input type="file" @change="uploadFile(0, $event)" ></input>
         </div>
         <i class="fa icon-spin4 animate-spin" v-if="uploading[0]"></i>
-        <button class="btn btn-default base05 base01-background" v-else-if="previews[0]" @click="submitAvatar">Submit</button>
+        <button class="btn btn-default base05 base01-background" v-else-if="previews[0]" @click="submitAvatar">{{$t('general.submit')}}</button>
       </div>
       <div class="setting-item">
-        <h3>Profile Banner</h3>
-        <p>Your current profile banner:</p>
+        <h3>{{$t('settings.profile_banner')}}</h3>
+        <p>{{$t('settings.current_profile_banner')}}</p>
         <img :src="user.cover_photo" class="banner"></img>
-        <p>Set new profile banner:</p>
+        <p>{{$t('settings.set_new_profile_banner')}}</p>
         <img class="banner" v-bind:src="previews[1]" v-if="previews[1]">
         </img>
         <div>
           <input type="file" @change="uploadFile(1, $event)" ></input>
         </div>
         <i class="fa icon-spin4 animate-spin uploading" v-if="uploading[1]"></i>
-        <button class="btn btn-default base05 base01-background" v-else-if="previews[1]" @click="submitBanner">Submit</button>
+        <button class="btn btn-default base05 base01-background" v-else-if="previews[1]" @click="submitBanner">{{$t('general.submit')}}</button>
       </div>
       <div class="setting-item">
-        <h3>Profile Background</h3>
-        <p>Set new profile background:</p>
+        <h3>{{$t('settings.profile_background')}}</h3>
+        <p>{{$t('settings.set_new_profile_background')}}</p>
         <img class="bg" v-bind:src="previews[2]" v-if="previews[2]">
         </img>
         <div>
           <input type="file" @change="uploadFile(2, $event)" ></input>
         </div>
         <i class="fa icon-spin4 animate-spin uploading" v-if="uploading[2]"></i>
-        <button class="btn btn-default base05 base01-background" v-else-if="previews[2]" @click="submitBg">Submit</button>
+        <button class="btn btn-default base05 base01-background" v-else-if="previews[2]" @click="submitBg">{{$t('general.submit')}}</button>
       </div>
     </div>
   </div>
diff --git a/src/i18n/messages.js b/src/i18n/messages.js
new file mode 100644
index 00000000..b39c57de
--- /dev/null
+++ b/src/i18n/messages.js
@@ -0,0 +1,70 @@
+const de = {
+  nav: {
+    timeline: 'Zeitleiste'
+  }
+}
+
+const en = {
+  nav: {
+    timeline: 'Timeline',
+    mentions: 'Mentions',
+    public_tl: 'Public Timeline',
+    twkn: 'The Whole Known Network'
+  },
+  user_card: {
+    follows_you: 'Follows you!',
+    following: 'Following!',
+    follow: 'Follow',
+    statuses: 'Statuses',
+    mute: 'Mute',
+    muted: 'Muted',
+    followers: 'Followers',
+    followees: 'Following',
+    per_day: 'per day'
+  },
+  timeline: {
+    show_new: 'Show new',
+    error_fetching: 'Error fetching updates',
+    up_to_date: 'Up-to-date',
+    load_older: 'Load older statuses'
+  },
+  settings: {
+    user_settings: 'User Settings',
+    name_bio: 'Name & Bio',
+    name: 'Name',
+    bio: 'Bio',
+    avatar: 'Avatar',
+    current_avatar: 'Your current avatar',
+    set_new_avatar: 'Set new avatar',
+    profile_banner: 'Profile Banner',
+    current_profile_banner: 'Your current profile banner',
+    set_new_profile_banner: 'Set new profile banner',
+    profile_background: 'Profile Background',
+    set_new_profile_background: 'Set new profile background',
+    settings: 'Settings',
+    theme: 'Theme',
+    filtering: 'Filtering',
+    filtering_explanation: 'All notices containing these words will be muted, one per line',
+    attachments: 'Attachments',
+    hide_attachments_in_tl: 'Hide attachments in timeline',
+    hide_attachments_in_convo: 'Hide attachments in conversations',
+    nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding',
+    autoload: 'Enable automatic loading when scrolled to the bottom',
+    reply_link_preview: 'Enable reply-link preview on mouse hover'
+  },
+  notifications: {
+    notifications: 'Notfications',
+    read: 'Read!',
+    followed_you: 'followed you'
+  },
+  general: {
+    submit: 'Submit'
+  }
+}
+
+const messages = {
+  de,
+  en
+}
+
+export default messages
diff --git a/src/main.js b/src/main.js
index b994e154..ce941ee1 100644
--- a/src/main.js
+++ b/src/main.js
@@ -19,9 +19,12 @@ import apiModule from './modules/api.js'
 import configModule from './modules/config.js'
 
 import VueTimeago from 'vue-timeago'
+import VueI18n from 'vue-i18n'
 
 import createPersistedState from './lib/persisted_state.js'
 
+import messages from './i18n/messages.js'
+
 Vue.use(Vuex)
 Vue.use(VueRouter)
 Vue.use(VueTimeago, {
@@ -30,6 +33,7 @@ Vue.use(VueTimeago, {
     'en-US': require('../static/timeago.json')
   }
 })
+Vue.use(VueI18n)
 
 const persistedStateOptions = {
   paths: [
@@ -79,10 +83,17 @@ const router = new VueRouter({
   }
 })
 
+const i18n = new VueI18n({
+  locale: 'en',
+  fallbackLocale: 'en',
+  messages
+})
+
 /* eslint-disable no-new */
 new Vue({
   router,
   store,
+  i18n,
   el: '#app',
   render: h => h(App)
 })
diff --git a/yarn.lock b/yarn.lock
index 965f6f31..d0d2dde9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5696,6 +5696,10 @@ vue-hot-reload-api@^2.0.1:
   version "2.0.9"
   resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.0.9.tgz#2e8cfbfc8e531eea57d8c1f0bd761047c7e11b56"
 
+vue-i18n@^7.3.2:
+  version "7.3.2"
+  resolved "https://registry.yarnpkg.com/vue-i18n/-/vue-i18n-7.3.2.tgz#1205bb8811323fd5c44e57e4fd619beaf2f7a9a1"
+
 vue-loader@^11.1.0:
   version "11.1.0"
   resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-11.1.0.tgz#8f3fcdd8a233ce96b3e99bd3d56e83cc0f2050f2"

From 74b513122e8dc6768ceb267947cb5a2f206ce7bd Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 15:23:00 +0100
Subject: [PATCH 03/21] Set locale from browser settings.

---
 src/main.js | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/main.js b/src/main.js
index ce941ee1..9d2930b6 100644
--- a/src/main.js
+++ b/src/main.js
@@ -83,8 +83,10 @@ const router = new VueRouter({
   }
 })
 
+const currentLocale = (window.navigator.language || 'en').split('-')[0]
+
 const i18n = new VueI18n({
-  locale: 'en',
+  locale: currentLocale,
   fallbackLocale: 'en',
   messages
 })

From 8fb83502f075b27e82eb2b806af811ede13dd4cd Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 15:42:34 +0100
Subject: [PATCH 04/21] Add translation to readme.

---
 README.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/README.md b/README.md
index ffaea0b5..7bdc29cc 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,10 @@
 
 ![screenshot](https://my.mixtape.moe/kjzioz.PNG)
 
+# For Translators
+
+To translate Pleroma, add your language to i18n/messages.js. Pleroma will set your language by your browser locale, but you can temporarily force it in the code by changing the locale in main.js.
+
 # FOR ADMINS
 
 You don't need to build Pleroma yourself. Check out https://git.pleroma.social/pleroma/pleroma-fe/wikis/dual-boot-with-qvitter to see how to run Pleroma and Qvitter at the same time.

From ed18d44e190fea34bfe9bad260cf4cf16114e9d7 Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 17:12:32 +0100
Subject: [PATCH 05/21] update readme

---
 README.md | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/README.md b/README.md
index 7bdc29cc..0aad8537 100644
--- a/README.md
+++ b/README.md
@@ -27,12 +27,6 @@ npm run build
 
 # run unit tests
 npm run unit
-
-# run e2e tests
-npm run e2e
-
-# run all tests
-npm test
 ```
 
 For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).

From f89f120c447c0192abf704a584756daddaea9d8f Mon Sep 17 00:00:00 2001
From: Shpuld Shpludson <shp@cock.li>
Date: Tue, 7 Nov 2017 16:55:08 +0000
Subject: [PATCH 06/21] Add fi to localization.

---
 src/i18n/messages.js | 59 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index b39c57de..19704fdb 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -4,6 +4,64 @@ const de = {
   }
 }
 
+const fi = {
+  nav: {
+    timeline: 'Aikajana',
+    mentions: 'Maininnat',
+    public_tl: 'Julkinen Aikajana',
+    twkn: 'Koko Tunnettu Verkosto'
+  },
+  user_card: {
+    follows_you: 'Seuraa sinua!',
+    following: 'Seuraat!',
+    follow: 'Seuraa',
+    statuses: 'Viestit',
+    mute: 'Hiljennä',
+    muted: 'Hiljennetty',
+    followers: 'Seuraajat',
+    followees: 'Seuraa',
+    per_day: 'päivässä'
+  },
+  timeline: {
+    show_new: 'Näytä uudet',
+    error_fetching: 'Virhe ladatessa viestejä',
+    up_to_date: 'Ajantasalla',
+    load_older: 'Lataa vanhempia viestejä'
+  },
+  settings: {
+    user_settings: 'Käyttäjän asetukset',
+    name_bio: 'Nimi ja kuvaus',
+    name: 'Nimi',
+    bio: 'Kuvaus',
+    avatar: 'Profiilikuva',
+    current_avatar: 'Nykyinen profiilikuvasi',
+    set_new_avatar: 'Aseta uusi profiilikuva',
+    profile_banner: 'Juliste',
+    current_profile_banner: 'Nykyinen julisteesi',
+    set_new_profile_banner: 'Aseta uusi juliste',
+    profile_background: 'Taustakuva',
+    set_new_profile_background: 'Aseta uusi taustakuva',
+    settings: 'Asetukset',
+    theme: 'Teema',
+    filtering: 'Suodatus',
+    filtering_explanation: 'Kaikki viestit, jotka sisältävät näitä sanoja, suodatetaan. Yksi sana per rivi.',
+    attachments: 'Liitteet',
+    hide_attachments_in_tl: 'Piilota liitteet aikajanalla',
+    hide_attachments_in_convo: 'Piilota liitteet keskusteluissa',
+    nsfw_clickthrough: 'Piilota NSFW liitteet klikkauksen taakse.',
+    autoload: 'Lataa vanhempia viestejä automaattisesti ruudun pohjalla',
+    reply_link_preview: 'Keskusteluiden vastauslinkkien esikatselu'
+  },
+  notifications: {
+    notifications: 'Ilmoitukset',
+    read: 'Lue!',
+    followed_you: 'seuraa sinua'
+  },
+  general: {
+    submit: 'Lähetä'
+  }
+}
+
 const en = {
   nav: {
     timeline: 'Timeline',
@@ -64,6 +122,7 @@ const en = {
 
 const messages = {
   de,
+  fi,
   en
 }
 

From 71395ebca2fd3ec9a9ed3dbfa71a4a3f38c5d5d9 Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 18:20:40 +0100
Subject: [PATCH 07/21] Add japanese translation.

Thanks, https://knzk.me/@imncls!
---
 src/i18n/messages.js | 61 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 19704fdb..b532d65a 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -120,10 +120,69 @@ const en = {
   }
 }
 
+const jp = {
+  nav: {
+    timeline: 'タイムライン',
+    mentions: '通知',
+    public_tl: '公開タイムライン',
+    twkn: '接続しているすべてのネットワーク'
+  },
+  user_card: {
+    follows_you: 'フォローされました!',
+    following: 'フォロー中!',
+    follow: 'フォロー',
+    statuses: 'ステータス',
+    mute: 'ミュート',
+    muted: 'ミュート済み',
+    followers: 'フォロワー',
+    followees: 'フォロー',
+    per_day: '/日'
+  },
+  timeline: {
+    show_new: '新しいものを表示',
+    error_fetching: '更新の取得中にエラーが発生しました',
+    up_to_date: '最新',
+    load_older: '古いステータスを読み込む'
+  },
+  settings: {
+    user_settings: 'ユーザー設定',
+    name_bio: '名前 & プロフィール',
+    name: '名前',
+    bio: 'プロフィール',
+    avatar: 'アバター',
+    current_avatar: 'あなたの現在のアバター',
+    set_new_avatar: '新しいアバターを設定する',
+    profile_banner: 'プロフィールバナー',
+    current_profile_banner: '現在のプロフィールバナー',
+    set_new_profile_banner: '新しいプロフィールバナーを設定する',
+    profile_background: 'プロフィールの背景',
+    set_new_profile_background: '新しいプロフィールの背景を設定する',
+    settings: '設定',
+    theme: 'テーマ',
+    filtering: 'フィルタリング',
+    filtering_explanation: 'これらの単語を含むすべての通知はミュートされます、1行に1つのワードを入力してください',
+    attachments: '添付ファイル',
+    hide_attachments_in_tl: 'タイムラインの添付ファイルを隠す',
+    hide_attachments_in_convo: '会話の中の添付ファイルを隠す',
+    nsfw_clickthrough: 'NSFWファイルの非表示を有効にする',
+    autoload: '下にスクロールした時に自動で読み込むようにする',
+    reply_link_preview: 'マウスカーソルを重ねたときに返信リンクプレビューを表示するようにする'
+  },
+  notifications: {
+    notifications: '通知',
+    read: '読んだ!',
+    followed_you: 'フォローされました'
+  },
+  general: {
+    submit: '送信'
+  }
+}
+
 const messages = {
   de,
   fi,
-  en
+  en,
+  jp
 }
 
 export default messages

From 4d4282a7597d5dbbdf3d5c94e3c6d3e4904c9c65 Mon Sep 17 00:00:00 2001
From: Sebastian Huebner <sebastian@hueb-ner.de>
Date: Tue, 7 Nov 2017 18:22:25 +0100
Subject: [PATCH 08/21] added ger translation

---
 src/i18n/messages.js | 52 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index b39c57de..2e39b338 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -1,6 +1,58 @@
 const de = {
   nav: {
     timeline: 'Zeitleiste'
+    mentions: 'Erwähnungen',
+    public_tl: 'Lokale Zeitleiste',
+    twkn: 'Das gesamte Netzwerk'
+  },
+  user_card: {
+    follows_you: 'Folgt dir!',
+    following: 'Folgst du!',
+    follow: 'Folgen',
+    statuses: 'Beiträge',
+    mute: 'Stummschalten',
+    muted: 'Stummgeschaltet',
+    followers: 'Folgende',
+    followees: 'Folgt',
+    per_day: 'pro Tag'
+  },
+  timeline: {
+    show_new: 'Zeige Neuere',
+    error_fetching: 'Error beim Laden',
+    up_to_date: 'Aktuell',
+    load_older: 'Lade ältere Beiträge'
+  },
+  settings: {
+    user_settings: 'Benutzereinstellungen',
+    name_bio: 'Name & Bio',
+    name: 'Name',
+    bio: 'Bio',
+    avatar: 'Avatar',
+    current_avatar: 'Dein derzeitiger Avatar',
+    set_new_avatar: 'Setze neuen Avatar',
+    profile_banner: 'Profil Banner',
+    current_profile_banner: 'Dein derzeitiger Profil Banner',
+    set_new_profile_banner: 'Setze neuen Profil Banner',
+    profile_background: 'Profil Hintergrund',
+    set_new_profile_background: 'Setze neuen Profil Hintergrund',
+    settings: 'Einstellungen',
+    theme: 'Theme',
+    filtering: 'Filter',
+    filtering_explanation: 'Alle Beiträge die diese Wörter enthalten werden ausgeblendet. Ein Wort pro Zeile.',
+    attachments: 'Anhänge',
+    hide_attachments_in_tl: 'Anhänge in der Timeline ausblenden',
+    hide_attachments_in_convo: 'Anhänge in Unterhaltungen ausblenden',
+    nsfw_clickthrough: 'Aktiviere ausblendbares Overlay für als NSFW markierte Anhänge',
+    autoload: 'Aktiviere automatisches Laden von Beiträgen beim scrollen',
+    reply_link_preview: 'Aktiviere reply-link Vorschau bei Maus-Hover'
+  },
+  notifications: {
+    notifications: 'Benachrichtigungen',
+    read: 'Gelesen!',
+    followed_you: 'folgt dir'
+  },
+  general: {
+    submit: 'Absenden'
   }
 }
 

From df895b0510209e21da2c4d3f0b1e2586eaf34594 Mon Sep 17 00:00:00 2001
From: Sebastian Huebner <sebastian@hueb-ner.de>
Date: Tue, 7 Nov 2017 18:22:25 +0100
Subject: [PATCH 09/21] added ger translation

---
 src/i18n/messages.js | 52 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index b532d65a..7ac8056f 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -1,6 +1,58 @@
 const de = {
   nav: {
     timeline: 'Zeitleiste'
+    mentions: 'Erwähnungen',
+    public_tl: 'Lokale Zeitleiste',
+    twkn: 'Das gesamte Netzwerk'
+  },
+  user_card: {
+    follows_you: 'Folgt dir!',
+    following: 'Folgst du!',
+    follow: 'Folgen',
+    statuses: 'Beiträge',
+    mute: 'Stummschalten',
+    muted: 'Stummgeschaltet',
+    followers: 'Folgende',
+    followees: 'Folgt',
+    per_day: 'pro Tag'
+  },
+  timeline: {
+    show_new: 'Zeige Neuere',
+    error_fetching: 'Error beim Laden',
+    up_to_date: 'Aktuell',
+    load_older: 'Lade ältere Beiträge'
+  },
+  settings: {
+    user_settings: 'Benutzereinstellungen',
+    name_bio: 'Name & Bio',
+    name: 'Name',
+    bio: 'Bio',
+    avatar: 'Avatar',
+    current_avatar: 'Dein derzeitiger Avatar',
+    set_new_avatar: 'Setze neuen Avatar',
+    profile_banner: 'Profil Banner',
+    current_profile_banner: 'Dein derzeitiger Profil Banner',
+    set_new_profile_banner: 'Setze neuen Profil Banner',
+    profile_background: 'Profil Hintergrund',
+    set_new_profile_background: 'Setze neuen Profil Hintergrund',
+    settings: 'Einstellungen',
+    theme: 'Theme',
+    filtering: 'Filter',
+    filtering_explanation: 'Alle Beiträge die diese Wörter enthalten werden ausgeblendet. Ein Wort pro Zeile.',
+    attachments: 'Anhänge',
+    hide_attachments_in_tl: 'Anhänge in der Timeline ausblenden',
+    hide_attachments_in_convo: 'Anhänge in Unterhaltungen ausblenden',
+    nsfw_clickthrough: 'Aktiviere ausblendbares Overlay für als NSFW markierte Anhänge',
+    autoload: 'Aktiviere automatisches Laden von Beiträgen beim scrollen',
+    reply_link_preview: 'Aktiviere reply-link Vorschau bei Maus-Hover'
+  },
+  notifications: {
+    notifications: 'Benachrichtigungen',
+    read: 'Gelesen!',
+    followed_you: 'folgt dir'
+  },
+  general: {
+    submit: 'Absenden'
   }
 }
 

From 33ad62bf720d783520f36c6de437a9868a1b4260 Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 18:34:12 +0100
Subject: [PATCH 10/21] Japanese is ja.

---
 src/i18n/messages.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index b532d65a..f0d45914 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -120,7 +120,7 @@ const en = {
   }
 }
 
-const jp = {
+const ja = {
   nav: {
     timeline: 'タイムライン',
     mentions: '通知',
@@ -182,7 +182,7 @@ const messages = {
   de,
   fi,
   en,
-  jp
+  ja
 }
 
 export default messages

From 8a3118d1a73b738adf069493f3e1e9a32a0f6044 Mon Sep 17 00:00:00 2001
From: Sebastian Huebner <sebastian@hueb-ner.de>
Date: Tue, 7 Nov 2017 18:22:25 +0100
Subject: [PATCH 11/21] added ger translation

---
 src/i18n/messages.js | 52 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index f0d45914..a8a35190 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -1,6 +1,58 @@
 const de = {
   nav: {
     timeline: 'Zeitleiste'
+    mentions: 'Erwähnungen',
+    public_tl: 'Lokale Zeitleiste',
+    twkn: 'Das gesamte Netzwerk'
+  },
+  user_card: {
+    follows_you: 'Folgt dir!',
+    following: 'Folgst du!',
+    follow: 'Folgen',
+    statuses: 'Beiträge',
+    mute: 'Stummschalten',
+    muted: 'Stummgeschaltet',
+    followers: 'Folgende',
+    followees: 'Folgt',
+    per_day: 'pro Tag'
+  },
+  timeline: {
+    show_new: 'Zeige Neuere',
+    error_fetching: 'Error beim Laden',
+    up_to_date: 'Aktuell',
+    load_older: 'Lade ältere Beiträge'
+  },
+  settings: {
+    user_settings: 'Benutzereinstellungen',
+    name_bio: 'Name & Bio',
+    name: 'Name',
+    bio: 'Bio',
+    avatar: 'Avatar',
+    current_avatar: 'Dein derzeitiger Avatar',
+    set_new_avatar: 'Setze neuen Avatar',
+    profile_banner: 'Profil Banner',
+    current_profile_banner: 'Dein derzeitiger Profil Banner',
+    set_new_profile_banner: 'Setze neuen Profil Banner',
+    profile_background: 'Profil Hintergrund',
+    set_new_profile_background: 'Setze neuen Profil Hintergrund',
+    settings: 'Einstellungen',
+    theme: 'Theme',
+    filtering: 'Filter',
+    filtering_explanation: 'Alle Beiträge die diese Wörter enthalten werden ausgeblendet. Ein Wort pro Zeile.',
+    attachments: 'Anhänge',
+    hide_attachments_in_tl: 'Anhänge in der Timeline ausblenden',
+    hide_attachments_in_convo: 'Anhänge in Unterhaltungen ausblenden',
+    nsfw_clickthrough: 'Aktiviere ausblendbares Overlay für als NSFW markierte Anhänge',
+    autoload: 'Aktiviere automatisches Laden von Beiträgen beim scrollen',
+    reply_link_preview: 'Aktiviere reply-link Vorschau bei Maus-Hover'
+  },
+  notifications: {
+    notifications: 'Benachrichtigungen',
+    read: 'Gelesen!',
+    followed_you: 'folgt dir'
+  },
+  general: {
+    submit: 'Absenden'
   }
 }
 

From 0320f03cd202e6f49a3175baa9a20a434c995156 Mon Sep 17 00:00:00 2001
From: Sebastian Huebner <sebastian@hueb-ner.de>
Date: Tue, 7 Nov 2017 18:43:28 +0100
Subject: [PATCH 12/21] make linter happy

---
 src/i18n/messages.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index a8a35190..975f7a91 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -1,6 +1,6 @@
 const de = {
   nav: {
-    timeline: 'Zeitleiste'
+    timeline: 'Zeitleiste',
     mentions: 'Erwähnungen',
     public_tl: 'Lokale Zeitleiste',
     twkn: 'Das gesamte Netzwerk'

From 5cf972b3485cecc42b9931313d229e82c3a3e045 Mon Sep 17 00:00:00 2001
From: Roger Braun <rbraun@Bobble.local>
Date: Tue, 7 Nov 2017 18:44:43 +0100
Subject: [PATCH 13/21] Update ja translation.

---
 src/i18n/messages.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index f0d45914..4993f4e4 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -160,7 +160,7 @@ const ja = {
     settings: '設定',
     theme: 'テーマ',
     filtering: 'フィルタリング',
-    filtering_explanation: 'これらの単語を含むすべての通知はミュートされます、1行に1つのワードを入力してください',
+    filtering_explanation: 'これらの単語を含むすべてのものはミュートされます、1行に1つのワードを入力してください',
     attachments: '添付ファイル',
     hide_attachments_in_tl: 'タイムラインの添付ファイルを隠す',
     hide_attachments_in_convo: '会話の中の添付ファイルを隠す',

From 608d1e6776769b933e194f96b4892a888880f60f Mon Sep 17 00:00:00 2001
From: eal <eal@waifu.club>
Date: Tue, 7 Nov 2017 22:38:28 +0200
Subject: [PATCH 14/21] Add blocks.

---
 .../user_card_content/user_card_content.vue   | 22 +++++++++++++++++++
 src/i18n/messages.js                          |  2 ++
 src/services/api/api.service.js               | 20 +++++++++++++++++
 .../backend_interactor_service.js             | 10 +++++++++
 4 files changed, 54 insertions(+)

diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index 4895f36f..8aef7e8a 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -46,6 +46,18 @@
               </button>
             </span>
           </div>
+          <div class='block' v-if='isOtherUser'>
+            <span v-if='user.statusnet_blocking'>
+              <button @click="unblockUser" class="base04 base00-background pressed">
+                {{ $t('user_card.blocked') }}
+              </button>
+            </span>
+            <span v-if='!user.statusnet_blocking'>
+              <button @click="blockUser" class="base05 base02-background">
+                {{ $t('user_card.block') }}
+              </button>
+            </span>
+          </div>
         </div>
       </div>
     </div>
@@ -113,6 +125,16 @@
         store.state.api.backendInteractor.unfollowUser(this.user.id)
           .then((unfollowedUser) => store.commit('addNewUsers', [unfollowedUser]))
       },
+      blockUser () {
+        const store = this.$store
+        store.state.api.backendInteractor.blockUser(this.user.id)
+          .then((blockedUser) => store.commit('addNewUsers', [blockedUser]))
+      },
+      unblockUser () {
+        const store = this.$store
+        store.state.api.backendInteractor.unblockUser(this.user.id)
+          .then((unblockedUser) => store.commit('addNewUsers', [unblockedUser]))
+      },
       toggleMute () {
         const store = this.$store
         store.commit('setMuted', {user: this.user, muted: !this.user.muted})
diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 3cbde819..3102d946 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -125,6 +125,8 @@ const en = {
     follows_you: 'Follows you!',
     following: 'Following!',
     follow: 'Follow',
+    blocked: 'Blocked!',
+    block: 'Block',
     statuses: 'Statuses',
     mute: 'Mute',
     muted: 'Muted',
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index a1c6b657..5abaea7e 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -26,6 +26,8 @@ const BANNER_UPDATE_URL = '/api/account/update_profile_banner.json'
 const PROFILE_UPDATE_URL = '/api/account/update_profile.json'
 const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
 const QVITTER_USER_TIMELINE_URL = '/api/qvitter/statuses/user_timeline.json'
+const BLOCKING_URL = '/api/blocks/create.json'
+const UNBLOCKING_URL = '/api/blocks/destroy.json'
 // const USER_URL = '/api/users/show.json'
 
 import { each, map } from 'lodash'
@@ -184,6 +186,22 @@ const unfollowUser = ({id, credentials}) => {
   }).then((data) => data.json())
 }
 
+const blockUser = ({id, credentials}) => {
+  let url = `${BLOCKING_URL}?user_id=${id}`
+  return fetch(url, {
+    headers: authHeaders(credentials),
+    method: 'POST'
+  }).then((data) => data.json())
+}
+
+const unblockUser = ({id, credentials}) => {
+  let url = `${UNBLOCKING_URL}?user_id=${id}`
+  return fetch(url, {
+    headers: authHeaders(credentials),
+    method: 'POST'
+  }).then((data) => data.json())
+}
+
 const fetchFriends = ({id, credentials}) => {
   let url = `${FRIENDS_URL}?user_id=${id}`
   return fetch(url, { headers: authHeaders(credentials) })
@@ -343,6 +361,8 @@ const apiService = {
   fetchFollowers,
   followUser,
   unfollowUser,
+  blockUser,
+  unblockUser,
   favorite,
   unfavorite,
   retweet,
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index a99ea38a..51a46e45 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -30,6 +30,14 @@ const backendInteractorService = (credentials) => {
     return apiService.unfollowUser({credentials, id})
   }
 
+  const blockUser = (id) => {
+    return apiService.blockUser({credentials, id})
+  }
+
+  const unblockUser = (id) => {
+    return apiService.unblockUser({credentials, id})
+  }
+
   const startFetching = ({timeline, store, userId = false}) => {
     return timelineFetcherService.startFetching({timeline, store, credentials, userId})
   }
@@ -55,6 +63,8 @@ const backendInteractorService = (credentials) => {
     fetchFollowers,
     followUser,
     unfollowUser,
+    blockUser,
+    unblockUser,
     fetchAllFollowing,
     verifyCredentials: apiService.verifyCredentials,
     startFetching,

From d6c89a9c09a531408d2e8a91725add1cad9fcea3 Mon Sep 17 00:00:00 2001
From: Tibike <miklosflame@mail.ru>
Date: Wed, 8 Nov 2017 02:14:18 +0200
Subject: [PATCH 15/21] Added Hungarian translation

---
 src/i18n/messages.js | 59 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 3cbde819..5f467939 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -172,6 +172,64 @@ const en = {
   }
 }
 
+const en = {
+  nav: {
+    timeline: 'Idővonal',
+    mentions: 'Említéseim',
+    public_tl: 'Publikus Idővonal',
+    twkn: 'Az Egész Ismert Hálózat'
+  },
+  user_card: {
+    follows_you: 'Követ téged!',
+    following: 'Követve!',
+    follow: 'Követ',
+    statuses: 'Állapotok',
+    mute: 'Némít',
+    muted: 'Némított',
+    followers: 'Követők',
+    followees: 'Követettek',
+    per_day: 'naponta'
+  },
+  timeline: {
+    show_new: 'Újak mutatása',
+    error_fetching: 'Hiba a frissítések beszerzésénél',
+    up_to_date: 'Naprakész',
+    load_older: 'Régebbi állapotok betöltése'
+  },
+  settings: {
+    user_settings: 'Felhasználói beállítások',
+    name_bio: 'Név és Bio',
+    name: 'Név',
+    bio: 'Bio',
+    avatar: 'Avatár',
+    current_avatar: 'Jelenlegi avatár',
+    set_new_avatar: 'Új avatár',
+    profile_banner: 'Profil Banner',
+    current_profile_banner: 'Jelenlegi profil banner',
+    set_new_profile_banner: 'Új profil banner',
+    profile_background: 'Profil háttérkép',
+    set_new_profile_background: 'Új profil háttér beállítása',
+    settings: 'Beállítások',
+    theme: 'Téma',
+    filtering: 'Szűrés',
+    filtering_explanation: 'Minden tartalom mely ezen szavakat tartalmazza némítva lesz, soronként egy',
+    attachments: 'Csatolmányok',
+    hide_attachments_in_tl: 'Csatolmányok elrejtése az idővonalon',
+    hide_attachments_in_convo: 'Csatolmányok elrejtése a társalgásokban',
+    nsfw_clickthrough: 'NSFW átkattintási tartalom elrejtésének engedélyezése',
+    autoload: 'Autoatikus betöltés engedélyezése lap aljára görgetéskor',
+    reply_link_preview: 'Válasz-link előzetes mutatása egér rátételkor'
+  },
+  notifications: {
+    notifications: 'Értesítések',
+    read: 'Olvasva!',
+    followed_you: 'követ téged'
+  },
+  general: {
+    submit: 'Elküld'
+  }
+}
+
 const ja = {
   nav: {
     timeline: 'タイムライン',
@@ -234,6 +292,7 @@ const messages = {
   de,
   fi,
   en,
+  hu,
   ja
 }
 

From 38bd0dbfcda8e65389d9ed9379b4dffee8970eb7 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 8 Nov 2017 09:05:10 +0100
Subject: [PATCH 16/21] Add french translation.

Thanks, azu!
---
 src/i18n/messages.js | 61 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 3102d946..65d4ea6a 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -232,11 +232,70 @@ const ja = {
   }
 }
 
+const fr = {
+  nav: {
+    timeline: 'Journal',
+    mentions: 'Notifications',
+    public_tl: 'Statuts Locaux',
+    twkn: 'Le Réseau Tout Entier'
+  },
+  user_card: {
+    follows_you: 'Vous Suit!',
+    following: 'Suivis!',
+    follow: 'Suivi',
+    statuses: 'Statuts',
+    mute: 'En Sourdine',
+    muted: 'Mis En Sourdine',
+    followers: 'Vous Suivent',
+    followees: 'Suivis',
+    per_day: 'par jour'
+  },
+  timeline: {
+    show_new: 'Afficher plus',
+    error_fetching: 'Erreur en cherchant des mises à jours',
+    up_to_date: 'A jour',
+    load_older: 'Afficher plus'
+  },
+  settings: {
+    user_settings: 'Paramètres Utilisateur',
+    name_bio: 'Nom & Bio',
+    name: 'Nom',
+    bio: 'Bio',
+    avatar: 'Avatar',
+    current_avatar: 'Votre avatar',
+    set_new_avatar: 'Changer d\'avatar',
+    profile_banner: 'Couverture du Profil',
+    current_profile_banner: 'Couverture du Profil',
+    set_new_profile_banner: 'Nouvelle couverture',
+    profile_background: 'Image de fond',
+    set_new_profile_background: 'Nouvelle image de fond',
+    settings: 'Paramètres',
+    theme: 'Thème',
+    filtering: 'Filtre',
+    filtering_explanation: 'Tout les statuts contenant ces mots vont être mis sous silence, un mot par ligne.',
+    attachments: 'Pièces jointes',
+    hide_attachments_in_tl: 'Cacher les pièces jointes dans le journal',
+    hide_attachments_in_convo: 'Cacher les pièces jointes dans les conversations',
+    nsfw_clickthrough: 'Activer le clic pour afficher les images taggées NSFW',
+    autoload: 'Activer le chargement automatique une fois le bas de la page atteint',
+    reply_link_preview: 'Activer un preview sur passage de la souris'
+  },
+  notifications: {
+    notifications: 'Notfications',
+    read: 'Lu!',
+    followed_you: 'vous a suivi'
+  },
+  general: {
+    submit: 'Envoyer'
+  }
+}
+
 const messages = {
   de,
   fi,
   en,
-  ja
+  ja,
+  fr
 }
 
 export default messages

From 32cb5e1a48bbffe294e4e9524dfe8b9270c758f8 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 8 Nov 2017 09:09:34 +0100
Subject: [PATCH 17/21] Add italian translation.

Thank, Eidon!
---
 src/i18n/messages.js | 61 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 60 insertions(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 65d4ea6a..68347416 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -290,12 +290,71 @@ const fr = {
   }
 }
 
+const it = {
+  nav: {
+    timeline: 'Sequenza temporale',
+    mentions: 'Menzioni',
+    public_tl: 'Sequenza temporale pubblica',
+    twkn: 'L\'intiera rete conosciuta'
+  },
+  user_card: {
+    follows_you: 'Ti segue!',
+    following: 'Lo stai seguendo!',
+    follow: 'Segui',
+    statuses: 'Messaggi',
+    mute: 'Ammutolisci',
+    muted: 'Ammutoliti',
+    followers: 'Chi ti segue',
+    followees: 'Chi stai seguendo',
+    per_day: 'al giorno'
+  },
+  timeline: {
+    show_new: 'Mostra nuovi',
+    error_fetching: 'Errori nel prelievo aggiornamenti',
+    up_to_date: 'Aggiornato',
+    load_older: 'Carica messaggi più vecchi'
+  },
+  settings: {
+    user_settings: 'Configurazione dell\'utente',
+    name_bio: 'Nome & Introduzione',
+    name: 'Nome',
+    bio: 'Introduzione',
+    avatar: 'Avatar',
+    current_avatar: 'Il tuo attuale avatar',
+    set_new_avatar: 'Scegli un nuovo avatar',
+    profile_banner: 'Sfondo del tuo profilo',
+    current_profile_banner: 'Sfondo attuale',
+    set_new_profile_banner: 'Scegli un nuovo sfondo per il tuo profilo',
+    profile_background: 'Sfondo della tua pagina',
+    set_new_profile_background: 'Scegli un nuovo sfondo per la tua pagina',
+    settings: 'Settaggi',
+    theme: 'Tema',
+    filtering: 'Filtri',
+    filtering_explanation: 'Filtra via le notifiche che contengono le seguenti parole (inserisci rigo per rigo le parole di innesco)',
+    attachments: 'Allegati',
+    hide_attachments_in_tl: 'Nascondi gli allegati presenti nella sequenza temporale',
+    hide_attachments_in_convo: 'Nascondi gli allegati presenti nelle conversazioni',
+    nsfw_clickthrough: 'Abilita la trasparenza degli allegati NSFW',
+    autoload: 'Abilita caricamento automatico quando si raggiunge il fondo schermo',
+    reply_link_preview: 'Ability il reply-link preview al passaggio del mouse'
+  },
+  notifications: {
+    notifications: 'Notifiche',
+    read: 'Leggi!',
+    followed_you: 'ti ha seguito'
+  },
+  general: {
+    submit: 'Invia'
+  }
+}
+
 const messages = {
   de,
   fi,
   en,
   ja,
-  fr
+  fr,
+  it
 }
 
 export default messages

From 483fef731a8004c1f7170a893e09abf679ccfdc1 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 8 Nov 2017 09:10:32 +0100
Subject: [PATCH 18/21] Fix typo.

---
 src/i18n/messages.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 68347416..b412d45b 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -165,7 +165,7 @@ const en = {
     reply_link_preview: 'Enable reply-link preview on mouse hover'
   },
   notifications: {
-    notifications: 'Notfications',
+    notifications: 'Notifications',
     read: 'Read!',
     followed_you: 'followed you'
   },

From c65974c8c8fa967672e48fb39c65bab13b51814e Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 8 Nov 2017 09:12:48 +0100
Subject: [PATCH 19/21] Fix typo.

---
 src/i18n/messages.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 5f467939..43bded78 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -172,7 +172,7 @@ const en = {
   }
 }
 
-const en = {
+const hu = {
   nav: {
     timeline: 'Idővonal',
     mentions: 'Említéseim',

From 62a3c6308221807b0c1e111cfd813d20bf43ae1d Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 8 Nov 2017 09:31:52 +0100
Subject: [PATCH 20/21] Unify statuses/notices.

---
 src/i18n/messages.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index 7bdd003a..befac232 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -156,7 +156,7 @@ const en = {
     settings: 'Settings',
     theme: 'Theme',
     filtering: 'Filtering',
-    filtering_explanation: 'All notices containing these words will be muted, one per line',
+    filtering_explanation: 'All statuses containing these words will be muted, one per line',
     attachments: 'Attachments',
     hide_attachments_in_tl: 'Hide attachments in timeline',
     hide_attachments_in_convo: 'Hide attachments in conversations',

From 5dca57cc058bfb95e40e32714057cbf0d24ce679 Mon Sep 17 00:00:00 2001
From: Roger Braun <roger@rogerbraun.net>
Date: Wed, 8 Nov 2017 09:57:51 +0100
Subject: [PATCH 21/21] Add Polish translation.

Thanks, Roka!
---
 src/i18n/messages.js | 63 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index befac232..da2f936a 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -406,6 +406,66 @@ const it = {
   }
 }
 
+const pl = {
+  nav: {
+    timeline: 'Oś czasu',
+    mentions: 'Wzmianki',
+    public_tl: 'Publiczna oś czasu',
+    twkn: 'Cała znana sieć'
+  },
+  user_card: {
+    follows_you: 'Obserwuje cię!',
+    following: 'Obserwowany!',
+    follow: 'Obserwuj',
+    blocked: 'Zablokowany!',
+    block: 'Zablokuj',
+    statuses: 'Statusy',
+    mute: 'Wycisz',
+    muted: 'Wyciszony',
+    followers: 'Obserwujący',
+    followees: 'Obserwowani',
+    per_day: 'dziennie'
+  },
+  timeline: {
+    show_new: 'Pokaż nowe',
+    error_fetching: 'Błąd pobierania',
+    up_to_date: 'Na bieżąco',
+    load_older: 'Załaduj starsze statusy'
+  },
+  settings: {
+    user_settings: 'Ustawienia użytkownika',
+    name_bio: 'Imię i bio',
+    name: 'Imię',
+    bio: 'Bio',
+    avatar: 'Awatar',
+    current_avatar: 'Twój obecny awatar',
+    set_new_avatar: 'Ustaw nowy awatar',
+    profile_banner: 'Banner profilui',
+    current_profile_banner: 'Twój obecny banner profilu',
+    set_new_profile_banner: 'Ustaw nowy banner profilu',
+    profile_background: 'Tło profilu',
+    set_new_profile_background: 'Ustaw nowe tło profilu',
+    settings: 'Ustawienia',
+    theme: 'Motyw',
+    filtering: 'Filtrowanie',
+    filtering_explanation: 'Wszystkie statusy zawierające te słowa będą wyciszone. Jedno słowo na linijkę',
+    attachments: 'Załączniki',
+    hide_attachments_in_tl: 'Ukryj załączniki w osi czasu',
+    hide_attachments_in_convo: 'Ukryj załączniki w rozmowach',
+    nsfw_clickthrough: 'Włącz domyślne ukrywanie załączników o treści nieprzyzwoitej (NSFW)',
+    autoload: 'Włącz automatyczne ładowanie po przewinięciu do końca strony',
+    reply_link_preview: 'Włącz dymek z podglądem postu po najechaniu na znak odpowiedzi'
+  },
+  notifications: {
+    notifications: 'Powiadomienia',
+    read: 'Przeczytane!',
+    followed_you: 'obserwuje cię'
+  },
+  general: {
+    submit: 'Wyślij'
+  }
+}
+
 const messages = {
   de,
   fi,
@@ -413,7 +473,8 @@ const messages = {
   hu,
   ja,
   fr,
-  it
+  it,
+  pl
 }
 
 export default messages