aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/utils.js9
-rw-r--r--package.json1
-rw-r--r--postcss.config.js5
-rw-r--r--src/App.js6
-rw-r--r--src/App.vue1
-rw-r--r--src/components/basic_user_card/basic_user_card.vue1
-rw-r--r--src/components/extra_buttons/extra_buttons.js13
-rw-r--r--src/components/extra_buttons/extra_buttons.vue15
-rw-r--r--src/components/gallery/gallery.vue8
-rw-r--r--src/components/instance_specific_panel/instance_specific_panel.js3
-rw-r--r--src/components/instance_specific_panel/instance_specific_panel.vue8
-rw-r--r--src/components/interactions/interactions.js4
-rw-r--r--src/components/interactions/interactions.vue9
-rw-r--r--src/components/link-preview/link-preview.js14
-rw-r--r--src/components/link-preview/link-preview.vue2
-rw-r--r--src/components/mobile_nav/mobile_nav.js4
-rw-r--r--src/components/mobile_nav/mobile_nav.vue1
-rw-r--r--src/components/mobile_post_status_modal/mobile_post_status_modal.vue11
-rw-r--r--src/components/search/search.js4
-rw-r--r--src/components/search/search.vue11
-rw-r--r--src/components/status/status.js2
-rw-r--r--src/components/tab_switcher/tab_switcher.js32
-rw-r--r--src/components/user_profile/user_profile.js74
-rw-r--r--src/components/user_profile/user_profile.vue29
-rw-r--r--src/components/who_to_follow/who_to_follow.js3
-rw-r--r--src/i18n/en.json6
-rw-r--r--src/i18n/es.json20
-rw-r--r--src/i18n/fi.json9
-rw-r--r--src/i18n/ja.json17
-rw-r--r--src/i18n/ja_pedantic.json17
-rw-r--r--src/i18n/messages.js1
-rw-r--r--src/i18n/nb.json440
-rw-r--r--src/i18n/te.json352
-rw-r--r--src/modules/statuses.js12
-rw-r--r--src/modules/users.js11
-rw-r--r--src/services/api/api.service.js23
-rw-r--r--src/services/backend_interactor_service/backend_interactor_service.js4
-rw-r--r--src/services/entity_normalizer/entity_normalizer.service.js2
-rw-r--r--src/services/errors/errors.js35
-rw-r--r--src/services/follow_manipulate/follow_manipulate.js30
-rw-r--r--yarn.lock99
41 files changed, 1172 insertions, 176 deletions
diff --git a/build/utils.js b/build/utils.js
index b45ffc16..c094c3c8 100644
--- a/build/utils.js
+++ b/build/utils.js
@@ -27,16 +27,17 @@ exports.cssLoaders = function (options) {
return [
{
test: /\.(post)?css$/,
- use: generateLoaders(['css-loader']),
+ use: generateLoaders(['css-loader', 'postcss-loader']),
},
{
test: /\.less$/,
- use: generateLoaders(['css-loader', 'less-loader']),
+ use: generateLoaders(['css-loader', 'postcss-loader', 'less-loader']),
},
{
test: /\.sass$/,
use: generateLoaders([
'css-loader',
+ 'postcss-loader',
{
loader: 'sass-loader',
options: {
@@ -47,11 +48,11 @@ exports.cssLoaders = function (options) {
},
{
test: /\.scss$/,
- use: generateLoaders(['css-loader', 'sass-loader'])
+ use: generateLoaders(['css-loader', 'postcss-loader', 'sass-loader'])
},
{
test: /\.styl(us)?$/,
- use: generateLoaders(['css-loader', 'stylus-loader']),
+ use: generateLoaders(['css-loader', 'postcss-loader', 'stylus-loader']),
},
]
}
diff --git a/package.json b/package.json
index 28f3beba..0f6ae9c8 100644
--- a/package.json
+++ b/package.json
@@ -93,6 +93,7 @@
"nightwatch": "^0.9.8",
"opn": "^4.0.2",
"ora": "^0.3.0",
+ "postcss-loader": "^3.0.0",
"raw-loader": "^0.5.1",
"sass": "^1.17.3",
"sass-loader": "git://github.com/webpack-contrib/sass-loader",
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 00000000..88752c6c
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ plugins: [
+ require('autoprefixer')
+ ]
+}
diff --git a/src/App.js b/src/App.js
index 3624171e..e9cd5917 100644
--- a/src/App.js
+++ b/src/App.js
@@ -89,7 +89,11 @@ export default {
sitename () { return this.$store.state.instance.name },
chat () { return this.$store.state.chat.channel.state === 'joined' },
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
- showInstanceSpecificPanel () { return this.$store.state.instance.showInstanceSpecificPanel },
+ showInstanceSpecificPanel () {
+ return this.$store.state.instance.showInstanceSpecificPanel &&
+ !this.$store.state.config.hideISP &&
+ this.$store.state.instance.instanceSpecificPanelContent
+ },
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
isMobileLayout () { return this.$store.state.interface.mobileLayout }
},
diff --git a/src/App.vue b/src/App.vue
index bf6e62e2..719e00a4 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -107,6 +107,7 @@
:floating="true"
class="floating-chat mobile-hidden"
/>
+ <MobilePostStatusModal />
<UserReportingModal />
<portal-target name="modal" />
</div>
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index 568e9359..8a02174e 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -87,6 +87,7 @@
&-expanded-content {
flex: 1;
margin-left: 0.7em;
+ min-width: 0;
}
}
</style>
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index 2ec72729..2d05ad39 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -16,6 +16,16 @@ const ExtraButtons = {
this.$store.dispatch('unpinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
+ },
+ muteConversation () {
+ this.$store.dispatch('muteConversation', this.status.id)
+ .then(() => this.$emit('onSuccess'))
+ .catch(err => this.$emit('onError', err.error.error))
+ },
+ unmuteConversation () {
+ this.$store.dispatch('unmuteConversation', this.status.id)
+ .then(() => this.$emit('onSuccess'))
+ .catch(err => this.$emit('onError', err.error.error))
}
},
computed: {
@@ -30,9 +40,6 @@ const ExtraButtons = {
},
canPin () {
return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted')
- },
- enabled () {
- return this.canPin || this.canDelete
}
}
}
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index cdad1666..564d34df 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -1,6 +1,5 @@
<template>
<v-popover
- v-if="enabled"
trigger="click"
placement="top"
class="extra-button-popover"
@@ -10,6 +9,20 @@
<div slot="popover">
<div class="dropdown-menu">
<button
+ v-if="!status.muted"
+ class="dropdown-item dropdown-item-icon"
+ @click.prevent="muteConversation"
+ >
+ <i class="icon-eye-off" /><span>{{ $t("status.mute_conversation") }}</span>
+ </button>
+ <button
+ v-if="status.muted"
+ class="dropdown-item dropdown-item-icon"
+ @click.prevent="unmuteConversation"
+ >
+ <i class="icon-eye-off" /><span>{{ $t("status.unmute_conversation") }}</span>
+ </button>
+ <button
v-if="!status.pinned && canPin"
v-close-popover
class="dropdown-item dropdown-item-icon"
diff --git a/src/components/gallery/gallery.vue b/src/components/gallery/gallery.vue
index 6adfb76c..6169d294 100644
--- a/src/components/gallery/gallery.vue
+++ b/src/components/gallery/gallery.vue
@@ -61,13 +61,17 @@
}
&.contain-fit {
- img, video {
+ img,
+ video,
+ canvas {
object-fit: contain;
}
}
&.cover-fit {
- img, video {
+ img,
+ video,
+ canvas {
object-fit: cover;
}
}
diff --git a/src/components/instance_specific_panel/instance_specific_panel.js b/src/components/instance_specific_panel/instance_specific_panel.js
index 9bb5e945..09e3d055 100644
--- a/src/components/instance_specific_panel/instance_specific_panel.js
+++ b/src/components/instance_specific_panel/instance_specific_panel.js
@@ -2,9 +2,6 @@ const InstanceSpecificPanel = {
computed: {
instanceSpecificPanelContent () {
return this.$store.state.instance.instanceSpecificPanelContent
- },
- show () {
- return !this.$store.state.config.hideISP
}
}
}
diff --git a/src/components/instance_specific_panel/instance_specific_panel.vue b/src/components/instance_specific_panel/instance_specific_panel.vue
index a7cf6b48..7448ca06 100644
--- a/src/components/instance_specific_panel/instance_specific_panel.vue
+++ b/src/components/instance_specific_panel/instance_specific_panel.vue
@@ -1,8 +1,5 @@
<template>
- <div
- v-if="show"
- class="instance-specific-panel"
- >
+ <div class="instance-specific-panel">
<div class="panel panel-default">
<div class="panel-body">
<!-- eslint-disable vue/no-v-html -->
@@ -14,6 +11,3 @@
</template>
<script src="./instance_specific_panel.js" ></script>
-
-<style lang="scss">
-</style>
diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js
index d4e3cc17..1f8a9de9 100644
--- a/src/components/interactions/interactions.js
+++ b/src/components/interactions/interactions.js
@@ -13,8 +13,8 @@ const Interactions = {
}
},
methods: {
- onModeSwitch (index, dataset) {
- this.filterMode = tabModeDict[dataset.filter]
+ onModeSwitch (key) {
+ this.filterMode = tabModeDict[key]
}
},
components: {
diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue
index d71c99d5..08cee343 100644
--- a/src/components/interactions/interactions.vue
+++ b/src/components/interactions/interactions.vue
@@ -10,18 +10,15 @@
:on-switch="onModeSwitch"
>
<span
- data-tab-dummy
- data-filter="mentions"
+ key="mentions"
:label="$t('nav.mentions')"
/>
<span
- data-tab-dummy
- data-filter="likes+repeats"
+ key="likes+repeats"
:label="$t('interactions.favs_repeats')"
/>
<span
- data-tab-dummy
- data-filter="follows"
+ key="follows"
:label="$t('interactions.follows')"
/>
</tab-switcher>
diff --git a/src/components/link-preview/link-preview.js b/src/components/link-preview/link-preview.js
index 2f6da55e..444aafbe 100644
--- a/src/components/link-preview/link-preview.js
+++ b/src/components/link-preview/link-preview.js
@@ -5,6 +5,11 @@ const LinkPreview = {
'size',
'nsfw'
],
+ data () {
+ return {
+ imageLoaded: false
+ }
+ },
computed: {
useImage () {
// Currently BE shoudn't give cards if tagged NSFW, this is a bit paranoid
@@ -15,6 +20,15 @@ const LinkPreview = {
useDescription () {
return this.card.description && /\S/.test(this.card.description)
}
+ },
+ created () {
+ if (this.useImage) {
+ const newImg = new Image()
+ newImg.onload = () => {
+ this.imageLoaded = true
+ }
+ newImg.src = this.card.image
+ }
}
}
diff --git a/src/components/link-preview/link-preview.vue b/src/components/link-preview/link-preview.vue
index 493774c2..69171977 100644
--- a/src/components/link-preview/link-preview.vue
+++ b/src/components/link-preview/link-preview.vue
@@ -7,7 +7,7 @@
rel="noopener"
>
<div
- v-if="useImage"
+ v-if="useImage && imageLoaded"
class="card-image"
:class="{ 'small-image': size === 'small' }"
>
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index 9b341a3b..c2bb76ee 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -1,14 +1,12 @@
import SideDrawer from '../side_drawer/side_drawer.vue'
import Notifications from '../notifications/notifications.vue'
-import MobilePostStatusModal from '../mobile_post_status_modal/mobile_post_status_modal.vue'
import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
import GestureService from '../../services/gesture_service/gesture_service'
const MobileNav = {
components: {
SideDrawer,
- Notifications,
- MobilePostStatusModal
+ Notifications
},
data: () => ({
notificationsCloseGesture: undefined,
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index f67b7ff8..d1c24e56 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -70,7 +70,6 @@
ref="sideDrawer"
:logout="logout"
/>
- <MobilePostStatusModal />
</div>
</template>
diff --git a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue b/src/components/mobile_post_status_modal/mobile_post_status_modal.vue
index 5db7584b..b6d7d3ba 100644
--- a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue
+++ b/src/components/mobile_post_status_modal/mobile_post_status_modal.vue
@@ -34,14 +34,19 @@
@import '../../_variables.scss';
.post-form-modal-view {
- max-height: 100%;
- display: block;
+ align-items: flex-start;
}
.post-form-modal-panel {
flex-shrink: 0;
- margin: 25% 0 4em 0;
+ margin-top: 25%;
+ margin-bottom: 2em;
width: 100%;
+ max-width: 700px;
+
+ @media (orientation: landscape) {
+ margin-top: 8%;
+ }
}
.new-status-button {
diff --git a/src/components/search/search.js b/src/components/search/search.js
index b434e127..8e903052 100644
--- a/src/components/search/search.js
+++ b/src/components/search/search.js
@@ -75,8 +75,8 @@ const Search = {
const length = this[tabName].length
return length === 0 ? '' : ` (${length})`
},
- onResultTabSwitch (_index, dataset) {
- this.currenResultTab = dataset.filter
+ onResultTabSwitch (key) {
+ this.currenResultTab = key
},
getActiveTab () {
if (this.visibleStatuses.length > 0) {
diff --git a/src/components/search/search.vue b/src/components/search/search.vue
index 4350e672..746bbaa2 100644
--- a/src/components/search/search.vue
+++ b/src/components/search/search.vue
@@ -31,21 +31,18 @@
<tab-switcher
ref="tabSwitcher"
:on-switch="onResultTabSwitch"
- :custom-active="currenResultTab"
+ :active-tab="currenResultTab"
>
<span
- data-tab-dummy
- data-filter="statuses"
+ key="statuses"
:label="$t('user_card.statuses') + resultCount('visibleStatuses')"
/>
<span
- data-tab-dummy
- data-filter="people"
+ key="people"
:label="$t('search.people') + resultCount('users')"
/>
<span
- data-tab-dummy
- data-filter="hashtags"
+ key="hashtags"
:label="$t('search.hashtags') + resultCount('hashtags')"
/>
</tab-switcher>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 3c172e5b..502d9583 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -335,7 +335,7 @@ const Status = {
return
}
}
- if (target.className.match(/hashtag/)) {
+ if (target.rel.match(/(?:^|\s)tag(?:$|\s)/) || target.className.match(/hashtag/)) {
// Extract tag name from link url
const tag = extractTagFromUrl(target.href)
if (tag) {
diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js
index a5fe019c..08d5d08f 100644
--- a/src/components/tab_switcher/tab_switcher.js
+++ b/src/components/tab_switcher/tab_switcher.js
@@ -4,12 +4,22 @@ import './tab_switcher.scss'
export default Vue.component('tab-switcher', {
name: 'TabSwitcher',
- props: ['renderOnlyFocused', 'onSwitch', 'customActive'],
+ props: ['renderOnlyFocused', 'onSwitch', 'activeTab'],
data () {
return {
active: this.$slots.default.findIndex(_ => _.tag)
}
},
+ computed: {
+ activeIndex () {
+ // In case of controlled component
+ if (this.activeTab) {
+ return this.$slots.default.findIndex(slot => this.activeTab === slot.key)
+ } else {
+ return this.active
+ }
+ }
+ },
beforeUpdate () {
const currentSlot = this.$slots.default[this.active]
if (!currentSlot.tag) {
@@ -17,21 +27,13 @@ export default Vue.component('tab-switcher', {
}
},
methods: {
- activateTab (index, dataset) {
+ activateTab (index) {
return () => {
if (typeof this.onSwitch === 'function') {
- this.onSwitch.call(null, index, this.$slots.default[index].elm.dataset)
+ this.onSwitch.call(null, this.$slots.default[index].key)
}
this.active = index
}
- },
- isActiveTab (index) {
- const customActiveIndex = this.$slots.default.findIndex(slot => {
- const dataFilter = slot.data && slot.data.attrs && slot.data.attrs['data-filter']
- return this.customActive && this.customActive === dataFilter
- })
-
- return customActiveIndex > -1 ? customActiveIndex === index : index === this.active
}
},
render (h) {
@@ -41,13 +43,13 @@ export default Vue.component('tab-switcher', {
const classesTab = ['tab']
const classesWrapper = ['tab-wrapper']
- if (this.isActiveTab(index)) {
+ if (this.activeIndex === index) {
classesTab.push('active')
classesWrapper.push('active')
}
if (slot.data.attrs.image) {
return (
- <div class={ classesWrapper.join(' ')}>
+ <div class={classesWrapper.join(' ')}>
<button
disabled={slot.data.attrs.disabled}
onClick={this.activateTab(index)}
@@ -59,7 +61,7 @@ export default Vue.component('tab-switcher', {
)
}
return (
- <div class={ classesWrapper.join(' ')}>
+ <div class={classesWrapper.join(' ')}>
<button
disabled={slot.data.attrs.disabled}
onClick={this.activateTab(index)}
@@ -71,7 +73,7 @@ export default Vue.component('tab-switcher', {
const contents = this.$slots.default.map((slot, index) => {
if (!slot.tag) return
- const active = index === this.active
+ const active = this.activeIndex === index
if (this.renderOnlyFocused) {
return active
? <div class="active">{slot}</div>
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 39b99dac..00055707 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -22,21 +22,23 @@ const FriendList = withLoadMore({
additionalPropNames: ['userId']
})(List)
+const defaultTabKey = 'statuses'
+
const UserProfile = {
data () {
return {
error: false,
- userId: null
+ userId: null,
+ tab: defaultTabKey
}
},
created () {
- // Make sure that timelines used in this page are empty
- this.cleanUp()
const routeParams = this.$route.params
this.load(routeParams.name || routeParams.id)
+ this.tab = get(this.$route, 'query.tab', defaultTabKey)
},
destroyed () {
- this.cleanUp()
+ this.stopFetching()
},
computed: {
timeline () {
@@ -67,17 +69,36 @@ const UserProfile = {
},
methods: {
load (userNameOrId) {
+ const startFetchingTimeline = (timeline, userId) => {
+ // Clear timeline only if load another user's profile
+ if (userId !== this.$store.state.statuses.timelines[timeline].userId) {
+ this.$store.commit('clearTimeline', { timeline })
+ }
+ this.$store.dispatch('startFetchingTimeline', { timeline, userId })
+ }
+
+ const loadById = (userId) => {
+ this.userId = userId
+ startFetchingTimeline('user', userId)
+ startFetchingTimeline('media', userId)
+ if (this.isUs) {
+ startFetchingTimeline('favorites', userId)
+ }
+ // Fetch all pinned statuses immediately
+ this.$store.dispatch('fetchPinnedStatuses', userId)
+ }
+
+ // Reset view
+ this.userId = null
+ this.error = false
+
// Check if user data is already loaded in store
const user = this.$store.getters.findUser(userNameOrId)
if (user) {
- this.userId = user.id
- this.fetchTimelines()
+ loadById(user.id)
} else {
this.$store.dispatch('fetchUser', userNameOrId)
- .then(({ id }) => {
- this.userId = id
- this.fetchTimelines()
- })
+ .then(({ id }) => loadById(id))
.catch((reason) => {
const errorMessage = get(reason, 'error.error')
if (errorMessage === 'No user with such user_id') { // Known error
@@ -90,40 +111,33 @@ const UserProfile = {
})
}
},
- fetchTimelines () {
- const userId = this.userId
- this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId })
- this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId })
- if (this.isUs) {
- this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId })
- }
- // Fetch all pinned statuses immediately
- this.$store.dispatch('fetchPinnedStatuses', userId)
- },
- cleanUp () {
+ stopFetching () {
this.$store.dispatch('stopFetching', 'user')
this.$store.dispatch('stopFetching', 'favorites')
this.$store.dispatch('stopFetching', 'media')
- this.$store.commit('clearTimeline', { timeline: 'user' })
- this.$store.commit('clearTimeline', { timeline: 'favorites' })
- this.$store.commit('clearTimeline', { timeline: 'media' })
+ },
+ switchUser (userNameOrId) {
+ this.stopFetching()
+ this.load(userNameOrId)
+ },
+ onTabSwitch (tab) {
+ this.tab = tab
+ this.$router.replace({ query: { tab } })
}
},
watch: {
'$route.params.id': function (newVal) {
if (newVal) {
- this.cleanUp()
- this.load(newVal)
+ this.switchUser(newVal)
}
},
'$route.params.name': function (newVal) {
if (newVal) {
- this.cleanUp()
- this.load(newVal)
+ this.switchUser(newVal)
}
},
- $route () {
- this.$refs.tabSwitcher.activateTab(0)()
+ '$route.query': function (newVal) {
+ this.tab = newVal.tab || defaultTabKey
}
},
components: {
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index cffa28f1..42516916 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -12,22 +12,24 @@
rounded="top"
/>
<tab-switcher
- ref="tabSwitcher"
+ :active-tab="tab"
:render-only-focused="true"
+ :on-switch="onTabSwitch"
>
- <div :label="$t('user_card.statuses')">
- <Timeline
- :count="user.statuses_count"
- :embedded="true"
- :title="$t('user_profile.timeline_title')"
- :timeline="timeline"
- timeline-name="user"
- :user-id="userId"
- :pinned-status-ids="user.pinnedStatusIds"
- />
- </div>
+ <Timeline
+ key="statuses"
+ :label="$t('user_card.statuses')"
+ :count="user.statuses_count"
+ :embedded="true"
+ :title="$t('user_profile.timeline_title')"
+ :timeline="timeline"
+ timeline-name="user"
+ :user-id="userId"
+ :pinned-status-ids="user.pinnedStatusIds"
+ />
<div
v-if="followsTabVisible"
+ key="followees"
:label="$t('user_card.followees')"
:disabled="!user.friends_count"
>
@@ -42,6 +44,7 @@
</div>
<div
v-if="followersTabVisible"
+ key="followers"
:label="$t('user_card.followers')"
:disabled="!user.followers_count"
>
@@ -58,6 +61,7 @@
</FollowerList>
</div>
<Timeline
+ key="media"
:label="$t('user_card.media')"
:disabled="!media.visibleStatuses.length"
:embedded="true"
@@ -68,6 +72,7 @@
/>
<Timeline
v-if="isUs"
+ key="favorites"
:label="$t('user_card.favorites')"
:disabled="!favorites.visibleStatuses.length"
:embedded="true"
diff --git a/src/components/who_to_follow/who_to_follow.js b/src/components/who_to_follow/who_to_follow.js
index f8100257..8fab6c4d 100644
--- a/src/components/who_to_follow/who_to_follow.js
+++ b/src/components/who_to_follow/who_to_follow.js
@@ -21,7 +21,8 @@ const WhoToFollow = {
name: i.display_name,
screen_name: i.acct,
profile_image_url: i.avatar || '/images/avi.png',
- profile_image_url_original: i.avatar || '/images/avi.png'
+ profile_image_url_original: i.avatar || '/images/avi.png',
+ statusnet_profile_url: i.url
}
this.users.push(user)
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 60a3e284..6a9af55c 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -262,7 +262,7 @@
"loop_video": "Loop videos",
"loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")",
"mutes_tab": "Mutes",
- "play_videos_in_modal": "Play videos directly in the media viewer",
+ "play_videos_in_modal": "Play videos in a popup frame",
"use_contain_fit": "Don't crop the attachment in thumbnails",
"name": "Name",
"name_bio": "Name & Bio",
@@ -508,7 +508,9 @@
"pinned": "Pinned",
"delete_confirm": "Do you really want to delete this status?",
"reply_to": "Reply to",
- "replies_list": "Replies:"
+ "replies_list": "Replies:",
+ "mute_conversation": "Mute conversation",
+ "unmute_conversation": "Unmute conversation"
},
"user_card": {
"approve": "Approve",
diff --git a/src/i18n/es.json b/src/i18n/es.json
index f88e90f7..3ca3588e 100644
--- a/src/i18n/es.json
+++ b/src/i18n/es.json
@@ -291,13 +291,13 @@
"profile_background": "Fondo del Perfil",
"profile_banner": "Cabecera del Perfil",
"profile_tab": "Perfil",
- "radii_help": "Estable el redondeo de las esquinas del interfaz (en píxeles)",
+ "radii_help": "Estable el redondeo de las esquinas de la interfaz (en píxeles)",
"replies_in_timeline": "Réplicas en la línea temporal",
- "reply_link_preview": "Activar la previsualización del enlace de responder al pasar el ratón por encim",
+ "reply_link_preview": "Activar la previsualización del enlace de responder al pasar el ratón por encima",
"reply_visibility_all": "Mostrar todas las réplicas",
"reply_visibility_following": "Solo mostrar réplicas para mí o usuarios a los que sigo",
"reply_visibility_self": "Solo mostrar réplicas para mí",
- "autohide_floating_post_button": "Ocultar automáticamente el botón 'Nueva Publicación' (móvil)",
+ "autohide_floating_post_button": "Ocultar automáticamente el botón 'Nueva Publicación' (para móviles)",
"saving_err": "Error al guardar los ajustes",
"saving_ok": "Ajustes guardados",
"search_user_to_block": "Buscar usuarios a bloquear",
@@ -320,8 +320,8 @@
"text": "Texto",
"theme": "Tema",
"theme_help": "Use códigos de color hexadecimales (#rrggbb) para personalizar su tema de colores.",
- "theme_help_v2_1": "También puede invalidar los colores y la opacidad de ciertos componentes si activa la casilla de verificación, use el botón \"Borrar todo\" para deshacer los cambios.",
- "theme_help_v2_2": "Los iconos debajo de algunas entradas son indicadores de contraste de fondo/texto, desplace el ratón para obtener información detallada. Tenga en cuenta que cuando se utilizan indicadores de contraste de transparencia se muestra el peor caso posible.",
+ "theme_help_v2_1": "También puede invalidar los colores y la opacidad de ciertos componentes si activa la casilla de verificación. Use el botón \"Borrar todo\" para deshacer los cambios.",
+ "theme_help_v2_2": "Los iconos debajo de algunas entradas son indicadores de contraste de fondo/texto, desplace el ratón por encima para obtener información más detallada. Tenga en cuenta que cuando se utilizan indicadores de contraste de transparencia se muestra el peor caso posible.",
"tooltipRadius": "Información/alertas",
"upload_a_photo": "Subir una foto",
"user_settings": "Ajustes de Usuario",
@@ -395,14 +395,14 @@
"shadow_id": "Sombra #{value}",
"blur": "Difuminar",
"spread": "Cantidad",
- "inset": "Insertada",
+ "inset": "Sombra interior",
"hint": "Para las sombras, también puede usar --variable como un valor de color para usar las variables CSS3. Tenga en cuenta que establecer la opacidad no funcionará en este caso.",
"filter_hint": {
"always_drop_shadow": "Advertencia, esta sombra siempre usa {0} cuando el navegador lo soporta.",
"drop_shadow_syntax": "{0} no soporta el parámetro {1} y la palabra clave {2}.",
- "avatar_inset": "Tenga en cuenta que la combinación de sombras insertadas como no-insertadas en los avatares, puede dar resultados inesperados con los avatares transparentes.",
+ "avatar_inset": "Tenga en cuenta que la combinación de sombras interiores como no-interiores en los avatares, puede dar resultados inesperados con los avatares transparentes.",
"spread_zero": "Sombras con una cantidad > 0 aparecerá como si estuviera puesto a cero",
- "inset_classic": "Las sombras insertadas estarán usando {0}"
+ "inset_classic": "Las sombras interiores estarán usando {0}"
},
"components": {
"panel": "Panel",
@@ -420,7 +420,7 @@
},
"fonts": {
"_tab_label": "Fuentes",
- "help": "Seleccione la fuente para utilizar para los elementos de la interfaz de usuario. Para \"personalizado\", debe ingresar el nombre exacto de la fuente tal como aparece en el sistema.",
+ "help": "Seleccione la fuente a utilizar para los elementos de la interfaz de usuario. Para \"personalizado\", debe ingresar el nombre exacto de la fuente tal como aparece en el sistema.",
"components": {
"interface": "Interfaz",
"input": "Campos de entrada",
@@ -507,7 +507,7 @@
"unpin": "Desclavar de tu perfil",
"pinned": "Fijado",
"delete_confirm": "¿Realmente quieres borrar la publicación?",
- "reply_to": "Responder a",
+ "reply_to": "Respondiendo a",
"replies_list": "Respuestas:"
},
"user_card": {
diff --git a/src/i18n/fi.json b/src/i18n/fi.json
index f4179495..e7ed5408 100644
--- a/src/i18n/fi.json
+++ b/src/i18n/fi.json
@@ -278,8 +278,15 @@
"status": {
"favorites": "Tykkäykset",
"repeats": "Toistot",
+ "delete": "Poista",
+ "pin": "Kiinnitä profiiliisi",
+ "unpin": "Poista kiinnitys",
+ "pinned": "Kiinnitetty",
+ "delete_confirm": "Haluatko varmasti postaa viestin?",
"reply_to": "Vastaus",
- "replies_list": "Vastaukset:"
+ "replies_list": "Vastaukset:",
+ "mute_conversation": "Hiljennä keskustelu",
+ "unmute_conversation": "Poista hiljennys"
},
"user_card": {
"approve": "Hyväksy",
diff --git a/src/i18n/ja.json b/src/i18n/ja.json
index c77f28a6..b4c6015d 100644
--- a/src/i18n/ja.json
+++ b/src/i18n/ja.json
@@ -78,6 +78,7 @@
"timeline": "タイムライン",
"twkn": "つながっているすべてのネットワーク",
"user_search": "ユーザーをさがす",
+ "search": "さがす",
"who_to_follow": "おすすめユーザー",
"preferences": "せってい"
},
@@ -105,6 +106,9 @@
"expired": "いれふだは {0} まえに、おわりました",
"not_enough_options": "ユニークなオプションが、たりません"
},
+ "stickers": {
+ "add_sticker": "ステッカーをふやす"
+ },
"interactions": {
"favs_repeats": "リピートとおきにいり",
"follows": "あたらしいフォロー",
@@ -506,7 +510,9 @@
"pinned": "ピンどめ",
"delete_confirm": "ほんとうに、このステータスを、けしてもいいですか?",
"reply_to": "へんしん:",
- "replies_list": "へんしん:"
+ "replies_list": "へんしん:",
+ "mute_conversation": "スレッドをミュートする",
+ "unmute_conversation": "スレッドをミュートするのをやめる"
},
"user_card": {
"approve": "うけいれ",
@@ -531,6 +537,8 @@
"remote_follow": "リモートフォロー",
"report": "つうほう",
"statuses": "ステータス",
+ "subscribe": "サブスクライブ",
+ "unsubscribe": "サブスクライブをやめる",
"unblock": "ブロックをやめる",
"unblock_progress": "ブロックをとりけしています...",
"block_progress": "ブロックしています...",
@@ -595,5 +603,12 @@
"GiB": "GiB",
"TiB": "TiB"
}
+ },
+ "search": {
+ "people": "ひとびと",
+ "hashtags": "ハッシュタグ",
+ "person_talking": "{count} にんが、はなしています",
+ "people_talking": "{count} にんが、はなしています",
+ "no_results": "みつかりませんでした"
}
}
diff --git a/src/i18n/ja_pedantic.json b/src/i18n/ja_pedantic.json
index 992a2fa6..42bb53d4 100644
--- a/src/i18n/ja_pedantic.json
+++ b/src/i18n/ja_pedantic.json
@@ -78,6 +78,7 @@
"timeline": "タイムライン",
"twkn": "接続しているすべてのネットワーク",
"user_search": "ユーザーを探す",
+ "search": "検索",
"who_to_follow": "おすすめユーザー",
"preferences": "設定"
},
@@ -105,6 +106,9 @@
"expired": "投票は {0} 前に終了しました",
"not_enough_options": "相異なる選択肢が不足しています"
},
+ "stickers": {
+ "add_sticker": "ステッカーを追加"
+ },
"interactions": {
"favs_repeats": "リピートとお気に入り",
"follows": "新しいフォロワー",
@@ -506,7 +510,9 @@
"pinned": "ピン留め",
"delete_confirm": "本当にこのステータスを削除してもよろしいですか?",
"reply_to": "返信",
- "replies_list": "返信:"
+ "replies_list": "返信:",
+ "mute_conversation": "スレッドをミュート",
+ "unmute_conversation": "スレッドのミュートを解除"
},
"user_card": {
"approve": "受け入れ",
@@ -531,6 +537,8 @@
"remote_follow": "リモートフォロー",
"report": "通報",
"statuses": "ステータス",
+ "subscribe": "購読",
+ "unsubscribe": "購読を解除",
"unblock": "ブロック解除",
"unblock_progress": "ブロックを解除しています...",
"block_progress": "ブロックしています...",
@@ -595,5 +603,12 @@
"GiB": "GiB",
"TiB": "TiB"
}
+ },
+ "search": {
+ "people": "人々",
+ "hashtags": "ハッシュタグ",
+ "person_talking": "{count} 人が話しています",
+ "people_talking": "{count} 人が話しています",
+ "no_results": "見つかりませんでした"
}
}
diff --git a/src/i18n/messages.js b/src/i18n/messages.js
index f4b3d98b..89c8a8c8 100644
--- a/src/i18n/messages.js
+++ b/src/i18n/messages.js
@@ -33,6 +33,7 @@ const messages = {
pt: require('./pt.json'),
ro: require('./ro.json'),
ru: require('./ru.json'),
+ te: require('./te.json'),
zh: require('./zh.json')
}
diff --git a/src/i18n/nb.json b/src/i18n/nb.json
index 298dc0b9..248b05bc 100644
--- a/src/i18n/nb.json
+++ b/src/i18n/nb.json
@@ -2,14 +2,18 @@
"chat": {
"title": "Nettprat"
},
+ "exporter": {
+ "export": "Eksporter",
+ "processing": "Arbeider, du vil snart bli spurt om å laste ned filen din"
+ },
"features_panel": {
"chat": "Nettprat",
"gopher": "Gopher",
"media_proxy": "Media proxy",
"scope_options": "Velg mottakere",
- "text_limit": "Tekst-grense",
+ "text_limit": "Tekstgrense",
"title": "Egenskaper",
- "who_to_follow": "Hvem å følge"
+ "who_to_follow": "Kontoer å følge"
},
"finder": {
"error_fetching_user": "Feil ved henting av bruker",
@@ -17,23 +21,66 @@
},
"general": {
"apply": "Bruk",
- "submit": "Send"
+ "submit": "Send",
+ "more": "Mer",
+ "generic_error": "Det oppsto en feil",
+ "optional": "valgfritt",
+ "show_more": "Vis mer",
+ "show_less": "Vis mindre",
+ "cancel": "Avbryt",
+ "disable": "Slå av",
+ "enable": "Slå på",
+ "confirm": "Godta",
+ "verify": "Godkjenn"
+ },
+ "image_cropper": {
+ "crop_picture": "Minsk bilde",
+ "save": "Lagre",
+ "save_without_cropping": "Lagre uten å minske bildet",
+ "cancel": "Avbryt"
+ },
+ "importer": {
+ "submit": "Send",
+ "success": "Importering fullført",
+ "error": "Det oppsto en feil under importering av denne filen"
},
"login": {
"login": "Logg inn",
+ "description": "Log inn med OAuth",
"logout": "Logg ut",
"password": "Passord",
"placeholder": "f. eks lain",
"register": "Registrer",
- "username": "Brukernavn"
+ "username": "Brukernavn",
+ "hint": "Logg inn for å delta i diskusjonen",
+ "authentication_code": "Verifikasjonskode",
+ "enter_recovery_code": "Skriv inn en gjenopprettingskode",
+ "enter_two_factor_code": "Skriv inn en to-faktors kode",
+ "recovery_code": "Gjenopprettingskode",
+ "heading" : {
+ "totp" : "To-faktors autentisering",
+ "recovery" : "To-faktors gjenoppretting"
+ }
+ },
+ "media_modal": {
+ "previous": "Forrige",
+ "next": "Neste"
},
"nav": {
+ "about": "Om",
+ "back": "Tilbake",
"chat": "Lokal nettprat",
"friend_requests": "Følgeforespørsler",
"mentions": "Nevnt",
+ "interactions": "Interaksjooner",
+ "dms": "Direktemeldinger",
"public_tl": "Offentlig Tidslinje",
"timeline": "Tidslinje",
- "twkn": "Det hele kjente nettverket"
+ "twkn": "Det hele kjente nettverket",
+ "user_search": "Søk etter brukere",
+ "search": "Søk",
+ "who_to_follow": "Kontoer å følge",
+ "preferences": "Innstillinger"
},
"notifications": {
"broken_favorite": "Ukjent status, leter etter den...",
@@ -42,19 +89,52 @@
"load_older": "Last eldre varsler",
"notifications": "Varslinger",
"read": "Les!",
- "repeated_you": "Gjentok din status"
+ "repeated_you": "Gjentok din status",
+ "no_more_notifications": "Ingen gjenstående varsler"
+ },
+ "polls": {
+ "add_poll": "Legg til undersøkelse",
+ "add_option": "Legg til svaralternativ",
+ "option": "Svaralternativ",
+ "votes": "stemmer",
+ "vote": "Stem",
+ "type": "Undersøkelsestype",
+ "single_choice": "Enkeltvalg",
+ "multiple_choices": "Flervalg",
+ "expiry": "Undersøkelsestid",
+ "expires_in": "Undersøkelsen er over om {0}",
+ "expired": "Undersøkelsen ble ferdig {0} siden",
+ "not_enough_options": "For få unike svaralternativer i undersøkelsen"
+ },
+ "stickers": {
+ "add_sticker": "Legg til klistremerke"
+ },
+ "interactions": {
+ "favs_repeats": "Gjentakelser og favoritter",
+ "follows": "Nye følgere",
+ "load_older": "Last eldre interaksjoner"
},
"post_status": {
+ "new_status": "Legg ut ny status",
"account_not_locked_warning": "Kontoen din er ikke {0}. Hvem som helst kan følge deg for å se dine statuser til følgere",
"account_not_locked_warning_link": "låst",
"attachments_sensitive": "Merk vedlegg som sensitive",
"content_type": {
- "text/plain": "Klar tekst"
+ "text/plain": "Klar tekst",
+ "text/html": "HTML",
+ "text/markdown": "Markdown",
+ "text/bbcode": "BBCode"
},
"content_warning": "Tema (valgfritt)",
"default": "Landet akkurat i L.A.",
- "direct_warning": "Denne statusen vil kun bli sett av nevnte brukere",
+ "direct_warning_to_all": "Denne statusen vil være synlig av nevnte brukere",
+ "direct_warning_to_first_only": "Denne statusen vil være synlig for de brukerene som blir nevnt først i statusen.",
"posting": "Publiserer",
+ "scope_notice": {
+ "public": "Denne statusen vil være synlig for alle",
+ "private": "Denne statusen vil være synlig for dine følgere",
+ "unlisted": "Denne statusen vil ikke være synlig i Offentlig Tidslinje eller Det Hele Kjente Nettverket"
+ },
"scope": {
"direct": "Direkte, publiser bare til nevnte brukere",
"private": "Bare følgere, publiser bare til brukere som følger deg",
@@ -68,9 +148,49 @@
"fullname": "Visningsnavn",
"password_confirm": "Bekreft passord",
"registration": "Registrering",
- "token": "Invitasjons-bevis"
+ "token": "Invitasjons-bevis",
+ "captcha": "CAPTCHA",
+ "new_captcha": "Trykk på bildet for å få en ny captcha",
+ "username_placeholder": "f.eks. Lain Iwakura",
+ "fullname_placeholder": "f.eks. Lain Iwakura",
+ "bio_placeholder": "e.g.\nHei, jeg er Lain.\nJeg er en animert jente som bor i forstaden i Japan. Du kjenner meg kanskje fra the Wired.",
+ "validations": {
+ "username_required": "kan ikke stå tomt",
+ "fullname_required": "kan ikke stå tomt",
+ "email_required": "kan ikke stå tomt",
+ "password_required": "kan ikke stå tomt",
+ "password_confirmation_required": "kan ikke stå tomt",
+ "password_confirmation_match": "skal være det samme som passord"
+ }
+ },
+ "selectable_list": {
+ "select_all": "Velg alle"
},
"settings": {
+ "app_name": "Applikasjonsnavn",
+ "security": "Sikkerhet",
+ "enter_current_password_to_confirm": "Skriv inn ditt nåverende passord for å bekrefte din identitet",
+ "mfa": {
+ "otp" : "OTP",
+ "setup_otp" : "Set opp OTP",
+ "wait_pre_setup_otp" : "forhåndsstiller OTP",
+ "confirm_and_enable" : "Bekreft og slå på OTP",
+ "title": "To-faktors autentisering",
+ "generate_new_recovery_codes" : "Generer nye gjenopprettingskoder",
+ "warning_of_generate_new_codes" : "Når du genererer nye gjenopprettingskoder, vil de gamle slutte å fungere.",
+ "recovery_codes" : "Gjenopprettingskoder.",
+ "waiting_a_recovery_codes": "Mottar gjenopprettingskoder...",
+ "recovery_codes_warning" : "Skriv disse kodene ned eller plasser dem ett sikkert sted - ellers så vil du ikke se dem igjen. Dersom du mister tilgang til din to-faktors app og dine gjenopprettingskoder, vil du bli stengt ute av kontoen din.",
+ "authentication_methods" : "Autentiseringsmetoder",
+ "scan": {
+ "title": "Skann",
+ "desc": "Ved hjelp av din to-faktors applikasjon, skann denne QR-koden eller skriv inn tekstnøkkelen",
+ "secret_code": "Nøkkel"
+ },
+ "verify": {
+ "desc": "For å skru på to-faktors autentisering, skriv inn koden i fra din to-faktors app:"
+ }
+ },
"attachmentRadius": "Vedlegg",
"attachments": "Vedlegg",
"autoload": "Automatisk lasting når du blar ned til bunnen",
@@ -79,6 +199,12 @@
"avatarRadius": "Profilbilde",
"background": "Bakgrunn",
"bio": "Biografi",
+ "block_export": "Eksporter blokkeringer",
+ "block_export_button": "Eksporter blokkeringer til en csv fil",
+ "block_import": "Import blokkeringer",
+ "block_import_error": "Det oppsto en feil under importering av blokkeringer",
+ "blocks_imported": "Blokkeringer importert, det vil ta litt å prossesere dem",
+ "blocks_tab": "Blokkeringer",
"btnRadius": "Knapper",
"cBlue": "Blå (Svar, følg)",
"cGreen": "Grønn (Gjenta)",
@@ -88,6 +214,7 @@
"change_password_error": "Feil ved endring av passord",
"changed_password": "Passord endret",
"collapse_subject": "Sammenfold statuser med tema",
+ "composing": "komponering",
"confirm_new_password": "Bekreft nytt passord",
"current_avatar": "Ditt nåværende profilbilde",
"current_password": "Nåværende passord",
@@ -95,15 +222,15 @@
"data_import_export_tab": "Data import / eksport",
"default_vis": "Standard visnings-omfang",
"delete_account": "Slett konto",
- "delete_account_description": "Slett din konto og alle dine statuser",
+ "delete_account_description": "Fjern din konto og alle dine meldinger for alltid.",
"delete_account_error": "Det oppsto et problem ved sletting av kontoen din, hvis dette problemet forblir kontakt din administrator",
"delete_account_instructions": "Skriv inn ditt passord i feltet nedenfor for å bekrefte sletting av konto",
+ "avatar_size_instruction": "Den anbefalte minste-størrelsen for profilbilder er 150x150 piksler",
"export_theme": "Lagre tema",
"filtering": "Filtrering",
"filtering_explanation": "Alle statuser som inneholder disse ordene vil bli dempet, en kombinasjon av tegn per linje",
"follow_export": "Eksporter følginger",
"follow_export_button": "Eksporter følgingene dine til en .csv fil",
- "follow_export_processing": "Jobber, du vil snart bli spurt om å laste ned filen din.",
"follow_import": "Importer følginger",
"follow_import_error": "Feil ved importering av følginger.",
"follows_imported": "Følginger importert! Behandling vil ta litt tid.",
@@ -111,10 +238,22 @@
"general": "Generell",
"hide_attachments_in_convo": "Gjem vedlegg i samtaler",
"hide_attachments_in_tl": "Gjem vedlegg på tidslinje",
+ "hide_muted_posts": "Gjem statuser i fra gjemte brukere",
+ "max_thumbnails": "Maks antall forhåndsbilder per status",
+ "hide_isp": "Gjem instans-spesifikt panel",
+ "preload_images": "Forhåndslast bilder",
+ "use_one_click_nsfw": "Åpne sensitive vedlegg med ett klikk",
+ "hide_post_stats": "Gjem status statistikk (f.eks. antall likes",
+ "hide_user_stats": "Gjem bruker statistikk (f.eks. antall følgere)",
+ "hide_filtered_statuses": "Gjem filtrerte statuser",
+ "import_blocks_from_a_csv_file": "Importer blokkeringer fra en csv fil",
"import_followers_from_a_csv_file": "Importer følginger fra en csv fil",
"import_theme": "Last tema",
- "inputRadius": "Input felt",
+ "inputRadius": "Tekst felt",
+ "checkboxRadius": "Sjekkbokser",
"instance_default": "(standard: {value})",
+ "instance_default_simple": "(standard)",
+ "interface": "Grensesnitt",
"interfaceLanguage": "Grensesnitt-språk",
"invalid_theme_imported": "Den valgte filen er ikke ett støttet Pleroma-tema, ingen endringer til ditt tema ble gjort",
"limited_availability": "Ikke tilgjengelig i din nettleser",
@@ -122,6 +261,9 @@
"lock_account_description": "Begrens din konto til bare godkjente følgere",
"loop_video": "Gjenta videoer",
"loop_video_silent_only": "Gjenta bare videoer uten lyd, (for eksempel Mastodon sine \"gifs\")",
+ "mutes_tab": "Dempinger",
+ "play_videos_in_modal": "Spill videoer direkte i media-avspilleren",
+ "use_contain_fit": "Ikke minsk vedlegget i forhåndsvisninger",
"name": "Navn",
"name_bio": "Navn & Biografi",
"new_password": "Nytt passord",
@@ -131,10 +273,16 @@
"notification_visibility_mentions": "Nevnt",
"notification_visibility_repeats": "Gjentakelser",
"no_rich_text_description": "Fjern all formatering fra statuser",
+ "no_blocks": "Ingen blokkeringer",
+ "no_mutes": "Ingen dempinger",
+ "hide_follows_description": "Ikke hvis hvem jeg følger",
+ "hide_followers_description": "Ikke hvis hvem som følger meg",
+ "show_admin_badge": "Hvis ett administratormerke på min profil",
+ "show_moderator_badge": "Hvis ett moderatormerke på min profil",
"nsfw_clickthrough": "Krev trykk for å vise statuser som kan være upassende",
"oauth_tokens": "OAuth Tokens",
"token": "Pollett",
- "refresh_token": "Refresh Token",
+ "refresh_token": "Fornyingspolett",
"valid_until": "Gyldig til",
"revoke_token": "Tilbakekall",
"panelRadius": "Panel",
@@ -149,25 +297,196 @@
"reply_visibility_all": "Vis alle svar",
"reply_visibility_following": "Vis bare svar som er til meg eller folk jeg følger",
"reply_visibility_self": "Vis bare svar som er til meg",
+ "autohide_floating_post_button": "Skjul Ny Status knapp automatisk (mobil)",
"saving_err": "Feil ved lagring av innstillinger",
"saving_ok": "Innstillinger lagret",
+ "search_user_to_block": "Søk etter hvem du vil blokkere",
+ "search_user_to_mute": "Søk etter hvem du vil dempe",
"security_tab": "Sikkerhet",
+ "scope_copy": "Kopier mottakere når du svarer noen (Direktemeldinger blir alltid kopiert",
+ "minimal_scopes_mode": "Minimaliser mottakervalg",
"set_new_avatar": "Rediger profilbilde",
"set_new_profile_background": "Rediger profil-bakgrunn",
"set_new_profile_banner": "Sett ny profil-banner",
"settings": "Innstillinger",
+ "subject_input_always_show": "Alltid hvis tema-felt",
+ "subject_line_behavior": "Kopier tema når du svarer",
+ "subject_line_email": "Som email: \"re: tema\"",
+ "subject_line_mastodon": "Som mastodon: kopier som den er",
+ "subject_line_noop": "Ikke koper",
+ "post_status_content_type": "Status innholdstype",
"stop_gifs": "Spill av GIFs når du holder over dem",
"streaming": "Automatisk strømming av nye statuser når du har bladd til toppen",
"text": "Tekst",
"theme": "Tema",
"theme_help": "Bruk heksadesimale fargekoder (#rrggbb) til å endre farge-temaet ditt.",
+ "theme_help_v2_1": "Du kan også overskrive noen komponenter sine farger og opasitet ved å sjekke av sjekkboksen, bruk \"Nullstill alt\" knappen for å fjerne alle overskrivelser.",
+ "theme_help_v2_2": "Ikoner under noen av innstillingene er bakgrunn/tekst kontrast indikatorer, hold over dem for detaljert informasjon. Vennligst husk at disse indikatorene viser det verste utfallet.",
"tooltipRadius": "Verktøytips/advarsler",
+ "upload_a_photo": "Last opp ett bilde",
"user_settings": "Brukerinstillinger",
"values": {
"false": "nei",
"true": "ja"
+ },
+ "notifications": "Varsler",
+ "notification_setting": "Motta varsler i fra:",
+ "notification_setting_follows": "Brukere du følger",
+ "notification_setting_non_follows": "Brukere du ikke følger",
+ "notification_setting_followers": "Brukere som følger deg",
+ "notification_setting_non_followers": "Brukere som ikke følger deg",
+ "notification_mutes": "For å stoppe å motta varsler i fra en spesifikk bruker, kan du dempe dem.",
+ "notification_blocks": "Hvis du blokkerer en bruker vil det stoppe alle varsler og i tilleg få dem til å slutte å følge deg",
+ "enable_web_push_notifications": "Skru på pushnotifikasjoner i nettlesere",
+ "style": {
+ "switcher": {
+ "keep_color": "Behold farger",
+ "keep_shadows": "Behold skygger",
+ "keep_opacity": "Behold opasitet",
+ "keep_roundness": "Behold rundhet",
+ "keep_fonts": "Behold fonter",
+ "save_load_hint": "\"Behold\" alternativer beholder de instillingene som er satt når du velger eller laster inn temaer, det lagrer også disse alternativene når du eksporterer ett tema, Når alle sjekkboksene er tomme, vil alt bli lagret når du eksporterer ett tema.",
+ "reset": "Still in på nytt",
+ "clear_all": "Nullstill alt",
+ "clear_opacity": "Nullstill opasitet"
+ },
+ "common": {
+ "color": "Farge",
+ "opacity": "Opasitet",
+ "contrast": {
+ "hint": "Kontrast forholdet er {ratio}, it {level} {context}",
+ "level": {
+ "aa": "møter Nivå AA retningslinje (minimal)",
+ "aaa": "møter Nivå AAA retningslinje (recommended)",
+ "bad": "møter ingen tilgjengeligshetsretningslinjer"
+ },
+ "context": {
+ "18pt": "for stor (18pt+) tekst",
+ "text": "for tekst"
+ }
+ }
+ },
+ "common_colors": {
+ "_tab_label": "Vanlig",
+ "main": "Vanlige farger",
+ "foreground_hint": "Se \"Avansert\" fanen for mer detaljert kontroll",
+ "rgbo": "Ikoner, aksenter, merker"
+ },
+ "advanced_colors": {
+ "_tab_label": "Avansert",
+ "alert": "Varslingsbakgrunn",
+ "alert_error": "Feil",
+ "badge": "Merkebakgrunn",
+ "badge_notification": "Varsling",
+ "panel_header": "Panelhode",
+ "top_bar": "Topplinje",
+ "borders": "Kanter",
+ "buttons": "Knapper",
+ "inputs": "Tekstfelt",
+ "faint_text": "Svak tekst"
+ },
+ "radii": {
+ "_tab_label": "Rundhet"
+ },
+ "shadows": {
+ "_tab_label": "Skygger og belysning",
+ "component": "Komponent",
+ "override": "Overskriv",
+ "shadow_id": "Skygge #{value}",
+ "blur": "Uklarhet",
+ "spread": "Spredning",
+ "inset": "Insett",
+ "hint": "For skygger kan du sette --variable som en fargeveerdi for å bruke CSS3 variabler. Vær oppmerksom på at å sette opasitet da ikke vil fungere her.",
+ "filter_hint": {
+ "always_drop_shadow": "Advarsel, denne skyggen bruker alltid {0} når nettleseren støtter det.",
+ "drop_shadow_syntax": "{0} støtter ikke {1} parameter og {2} nøkkelord.",
+ "avatar_inset": "Vær oppmerksom på at å kombinere både insatte og uinsatte skygger på profilbilder kan gi uforventede resultater med gjennomsiktige profilbilder.",
+ "spread_zero": "Skygger med spredning > 0 vil fremstå som de var satt til 0",
+ "inset_classic": "Insette skygger vil bruke {0}"
+ },
+ "components": {
+ "panel": "Panel",
+ "panelHeader": "Panelhode",
+ "topBar": "Topplinje",
+ "avatar": "Profilbilde (i profilvisning)",
+ "avatarStatus": "Profilbilde (i statusvisning)",
+ "popup": "Popups og tooltips",
+ "button": "Knapp",
+ "buttonHover": "Knapp (holdt)",
+ "buttonPressed": "Knapp (nedtrykt)",
+ "buttonPressedHover": "Knapp (nedtrykt+holdt)",
+ "input": "Tekstfelt"
+ }
+ },
+ "fonts": {
+ "_tab_label": "Fonter",
+ "help": "Velg font til elementene i brukergrensesnittet. For \"egendefinert\" må du skrive inn det nøyaktige font-navnet som det fremstår på systemet",
+ "components": {
+ "interface": "Grensesnitt",
+ "input": "Tekstfelt",
+ "post": "Statustekst",
+ "postCode": "Monospaced tekst i en status (rik tekst)"
+ },
+ "family": "Font naavn",
+ "size": "Størrelse (i piksler)",
+ "weight": "Vekt (dristighet)",
+ "custom": "Egendefinert"
+ },
+ "preview": {
+ "header": "Forhåndsvisning",
+ "content": "Innhold",
+ "error": "Eksempel feil",
+ "button": "Knapp",
+ "text": "Mye mer {0} og {1}",
+ "mono": "innhold",
+ "input": "Landet akkurat i L.A.",
+ "faint_link": "hjelpfull brukerveiledning",
+ "fine_print": "Les vår {0} for å lære ingenting nyttig!",
+ "header_faint": "Dette er OK",
+ "checkbox": "Jeg har skumlest vilkår og betingelser",
+ "link": "en flott liten link"
+ }
+ },
+ "version": {
+ "title": "Versjon",
+ "backend_version": "Backend Versjon",
+ "frontend_version": "Frontend Versjon"
}
},
+ "time": {
+ "day": "{0} dag",
+ "days": "{0} dager",
+ "day_short": "{0}d",
+ "days_short": "{0}d",
+ "hour": "{0} time",
+ "hours": "{0} timer",
+ "hour_short": "{0}t",
+ "hours_short": "{0}t",
+ "in_future": "om {0}",
+ "in_past": "{0} siden",
+ "minute": "{0} minutt",
+ "minutes": "{0} minutter",
+ "minute_short": "{0}min",
+ "minutes_short": "{0}min",
+ "month": "{0} måned",
+ "months": "{0} måneder",
+ "month_short": "{0}md.",
+ "months_short": "{0}md.",
+ "now": "akkurat nå",
+ "now_short": "nå",
+ "second": "{0} sekund",
+ "seconds": "{0} sekunder",
+ "second_short": "{0}s",
+ "seconds_short": "{0}s",
+ "week": "{0} uke",
+ "weeks": "{0} uker",
+ "week_short": "{0}u",
+ "weeks_short": "{0}u",
+ "year": "{0} år",
+ "years": "{0} år",
+ "year_short": "{0}år",
+ "years_short": "{0}år"
+ },
"timeline": {
"collapse": "Sammenfold",
"conversation": "Samtale",
@@ -176,29 +495,116 @@
"no_retweet_hint": "Status er markert som bare til følgere eller direkte og kan ikke gjentas",
"repeated": "gjentok",
"show_new": "Vis nye",
- "up_to_date": "Oppdatert"
+ "up_to_date": "Oppdatert",
+ "no_more_statuses": "Ingen flere statuser",
+ "no_statuses": "Ingen statuser"
+ },
+ "status": {
+ "favorites": "Favoritter",
+ "repeats": "Gjentakelser",
+ "delete": "Slett status",
+ "pin": "Fremhev på profil",
+ "unpin": "Fjern fremhevelse",
+ "pinned": "Fremhevet",
+ "delete_confirm": "Har du virkelig lyst til å slette denne statusen?",
+ "reply_to": "Svar til",
+ "replies_list": "Svar:"
},
"user_card": {
"approve": "Godkjenn",
"block": "Blokker",
"blocked": "Blokkert!",
"deny": "Avslå",
+ "favorites": "Favoritter",
"follow": "Følg",
+ "follow_sent": "Forespørsel sendt!",
+ "follow_progress": "Forespør…",
+ "follow_again": "Gjenta forespørsel?",
+ "follow_unfollow": "Avfølg",
"followees": "Følger",
"followers": "Følgere",
"following": "Følger!",
"follows_you": "Følger deg!",
+ "its_you": "Det er deg!",
+ "media": "Media",
"mute": "Demp",
"muted": "Dempet",
"per_day": "per dag",
"remote_follow": "Følg eksternt",
- "statuses": "Statuser"
+ "report": "Rapport",
+ "statuses": "Statuser",
+ "subscribe": "Abonner",
+ "unsubscribe": "Avabonner",
+ "unblock": "Fjern blokkering",
+ "unblock_progress": "Fjerner blokkering...",
+ "block_progress": "Blokkerer...",
+ "unmute": "Fjern demping",
+ "unmute_progress": "Fjerner demping...",
+ "mute_progress": "Demper...",
+ "admin_menu": {
+ "moderation": "Moderering",
+ "grant_admin": "Gi Administrator",
+ "revoke_admin": "Fjern Administrator",
+ "grant_moderator": "Gi Moderator",
+ "revoke_moderator": "Fjern Moderator",
+ "activate_account": "Aktiver konto",
+ "deactivate_account": "Deaktiver kontro",
+ "delete_account": "Slett konto",
+ "force_nsfw": "Merk alle statuser som sensitive",
+ "strip_media": "Fjern media i fra statuser",
+ "force_unlisted": "Tving statuser til å være uopplistet",
+ "sandbox": "Tving statuser til å bare vises til følgere",
+ "disable_remote_subscription": "Fjern mulighet til å følge brukeren fra andre instanser",
+ "disable_any_subscription": "Fjern mulighet til å følge brukeren",
+ "quarantine": "Gjør at statuser fra brukeren ikke kan sendes til andre instanser",
+ "delete_user": "Slett bruker",
+ "delete_user_confirmation": "Er du helt sikker? Denne handlingen kan ikke omgjøres."
+ }
},
"user_profile": {
- "timeline_title": "Bruker-tidslinje"
+ "timeline_title": "Bruker-tidslinje",
+ "profile_does_not_exist": "Beklager, denne profilen eksisterer ikke.",
+ "profile_loading_error": "Beklager, det oppsto en feil under lasting av denne profilen."
+ },
+ "user_reporting": {
+ "title": "Rapporterer {0}",
+ "add_comment_description": "Rapporten blir sent til moderatorene av din instans. Du kan gi en forklaring på hvorfor du rapporterer denne kontoen under:",
+ "additional_comments": "Videre kommentarer",
+ "forward_description": "Denne kontoen er fra en annen server, vil du sende en kopi av rapporten til dem også?",
+ "forward_to": "Videresend til {0}",
+ "submit": "Send",
+ "generic_error": "Det oppsto en feil under behandling av din forespørsel."
},
"who_to_follow": {
"more": "Mer",
- "who_to_follow": "Hvem å følge"
+ "who_to_follow": "Kontoer å følge"
+ },
+ "tool_tip": {
+ "media_upload": "Last opp media",
+ "repeat": "Gjenta",
+ "reply": "Svar",
+ "favorite": "Lik",
+ "user_settings": "Brukerinnstillinger"
+ },
+ "upload":{
+ "error": {
+ "base": "Det oppsto en feil under opplastning.",
+ "file_too_big": "Fil for stor [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
+ "default": "Prøv igjen senere"
+ },
+ "file_size_units": {
+ "B": "B",
+ "KiB": "KiB",
+ "MiB": "MiB",
+ "GiB": "GiB",
+ "TiB": "TiB"
+ }
+ },
+ "search": {
+ "people": "Folk",
+ "hashtags": "Emneknagger",
+ "person_talking": "{count} person snakker om dette",
+ "people_talking": "{count} personer snakker om dette",
+ "no_results": "Ingen resultater"
}
}
diff --git a/src/i18n/te.json b/src/i18n/te.json
new file mode 100644
index 00000000..f0953d97
--- /dev/null
+++ b/src/i18n/te.json
@@ -0,0 +1,352 @@
+{
+ "chat.title": "చాట్",
+ "features_panel.chat": "చాట్",
+ "features_panel.gopher": "గోఫర్",
+ "features_panel.media_proxy": "మీడియా ప్రాక్సీ",
+ "features_panel.scope_options": "స్కోప్ ఎంపికలు",
+ "features_panel.text_limit": "వచన పరిమితి",
+ "features_panel.title": "లక్షణాలు",
+ "features_panel.who_to_follow": "ఎవరిని అనుసరించాలి",
+ "finder.error_fetching_user": "వినియోగదారుని పొందడంలో లోపం",
+ "finder.find_user": "వినియోగదారుని కనుగొనండి",
+ "general.apply": "వర్తించు",
+ "general.submit": "సమర్పించు",
+ "general.more": "మరిన్ని",
+ "general.generic_error": "ఒక తప్పిదం సంభవించినది",
+ "general.optional": "ఐచ్చికం",
+ "image_cropper.crop_picture": "చిత్రాన్ని కత్తిరించండి",
+ "image_cropper.save": "దాచు",
+ "image_cropper.save_without_cropping": "కత్తిరించకుండా సేవ్ చేయి",
+ "image_cropper.cancel": "రద్దుచేయి",
+ "login.login": "లాగిన్",
+ "login.description": "OAuth తో లాగిన్ అవ్వండి",
+ "login.logout": "లాగౌట్",
+ "login.password": "సంకేతపదము",
+ "login.placeholder": "ఉదా. lain",
+ "login.register": "నమోదు చేసుకోండి",
+ "login.username": "వాడుకరి పేరు",
+ "login.hint": "చర్చలో చేరడానికి లాగిన్ అవ్వండి",
+ "media_modal.previous": "ముందరి పుట",
+ "media_modal.next": "తరువాత",
+ "nav.about": "గురించి",
+ "nav.back": "వెనక్కి",
+ "nav.chat": "స్థానిక చాట్",
+ "nav.friend_requests": "అనుసరించడానికి అభ్యర్థనలు",
+ "nav.mentions": "ప్రస్తావనలు",
+ "nav.dms": "నేరుగా పంపిన సందేశాలు",
+ "nav.public_tl": "ప్రజా కాలక్రమం",
+ "nav.timeline": "కాలక్రమం",
+ "nav.twkn": "మొత్తం తెలిసిన నెట్వర్క్",
+ "nav.user_search": "వాడుకరి శోధన",
+ "nav.who_to_follow": "ఎవరిని అనుసరించాలి",
+ "nav.preferences": "ప్రాధాన్యతలు",
+ "notifications.broken_favorite": "తెలియని స్థితి, దాని కోసం శోధిస్తోంది...",
+ "notifications.favorited_you": "మీ స్థితిని ఇష్టపడ్డారు",
+ "notifications.followed_you": "మిమ్మల్ని అనుసరించారు",
+ "notifications.load_older": "పాత నోటిఫికేషన్లను లోడ్ చేయండి",
+ "notifications.notifications": "ప్రకటనలు",
+ "notifications.read": "చదివాను!",
+ "notifications.repeated_you": "మీ స్థితిని పునరావృతం చేసారు",
+ "notifications.no_more_notifications": "ఇక నోటిఫికేషన్లు లేవు",
+ "post_status.new_status": "క్రొత్త స్థితిని పోస్ట్ చేయండి",
+ "post_status.account_not_locked_warning": "మీ ఖాతా {౦} కాదు. ఎవరైనా మిమ్మల్ని అనుసరించి అనుచరులకు మాత్రమే ఉద్దేశించిన పోస్టులను చూడవచ్చు.",
+ "post_status.account_not_locked_warning_link": "తాళం వేయబడినది",
+ "post_status.attachments_sensitive": "జోడింపులను సున్నితమైనవిగా గుర్తించండి",
+ "post_status.content_type.text/plain": "సాధారణ అక్షరాలు",
+ "post_status.content_type.text/html": "హెచ్‌టిఎమ్ఎల్",
+ "post_status.content_type.text/markdown": "మార్క్డౌన్",
+ "post_status.content_warning": "విషయం (ఐచ్ఛికం)",
+ "post_status.default": "ఇప్పుడే విజయవాడలో దిగాను.",
+ "post_status.direct_warning": "ఈ పోస్ట్ మాత్రమే పేర్కొన్న వినియోగదారులకు మాత్రమే కనిపిస్తుంది.",
+ "post_status.posting": "పోస్ట్ చేస్తున్నా",
+ "post_status.scope.direct": "ప్రత్యక్ష - పేర్కొన్న వినియోగదారులకు మాత్రమే పోస్ట్ చేయబడుతుంది",
+ "post_status.scope.private": "అనుచరులకు మాత్రమే - అనుచరులకు మాత్రమే పోస్ట్ చేయబడుతుంది",
+ "post_status.scope.public": "పబ్లిక్ - ప్రజా కాలక్రమాలకు పోస్ట్ చేయబడుతుంది",
+ "post_status.scope.unlisted": "జాబితా చేయబడనిది - ప్రజా కాలక్రమాలకు పోస్ట్ చేయవద్దు",
+ "registration.bio": "బయో",
+ "registration.email": "ఈ మెయిల్",
+ "registration.fullname": "ప్రదర్శన పేరు",
+ "registration.password_confirm": "పాస్వర్డ్ నిర్ధారణ",
+ "registration.registration": "నమోదు",
+ "registration.token": "ఆహ్వాన టోకెన్",
+ "registration.captcha": "కాప్చా",
+ "registration.new_captcha": "కొత్త కాప్చా పొందుటకు చిత్రం మీద క్లిక్ చేయండి",
+ "registration.username_placeholder": "ఉదా. lain",
+ "registration.fullname_placeholder": "ఉదా. Lain Iwakura",
+ "registration.bio_placeholder": "e.g.\nHi, I'm Lain.\nI’m an anime girl living in suburban Japan. You may know me from the Wired.",
+ "registration.validations.username_required": "ఖాళీగా విడిచిపెట్టరాదు",
+ "registration.validations.fullname_required": "ఖాళీగా విడిచిపెట్టరాదు",
+ "registration.validations.email_required": "ఖాళీగా విడిచిపెట్టరాదు",
+ "registration.validations.password_required": "ఖాళీగా విడిచిపెట్టరాదు",
+ "registration.validations.password_confirmation_required": "ఖాళీగా విడిచిపెట్టరాదు",
+ "registration.validations.password_confirmation_match": "సంకేతపదం వలె ఉండాలి",
+ "settings.app_name": "అనువర్తన పేరు",
+ "settings.attachmentRadius": "జోడింపులు",
+ "settings.attachments": "జోడింపులు",
+ "settings.autoload": "క్రిందికి స్క్రోల్ చేయబడినప్పుడు స్వయంచాలక లోడింగ్ని ప్రారంభించు",
+ "settings.avatar": "అవతారం",
+ "settings.avatarAltRadius": "అవతారాలు (ప్రకటనలు)",
+ "settings.avatarRadius": "అవతారాలు",
+ "settings.background": "బ్యాక్‌గ్రౌండు",
+ "settings.bio": "బయో",
+ "settings.blocks_tab": "బ్లాక్‌లు",
+ "settings.btnRadius": "బటన్లు",
+ "settings.cBlue": "నీలం (ప్రత్యుత్తరం, అనుసరించండి)",
+ "settings.cGreen": "Green (Retweet)",
+ "settings.cOrange": "ఆరెంజ్ (ఇష్టపడు)",
+ "settings.cRed": "Red (Cancel)",
+ "settings.change_password": "పాస్‌వర్డ్ మార్చండి",
+ "settings.change_password_error": "మీ పాస్వర్డ్ను మార్చడంలో సమస్య ఉంది.",
+ "settings.changed_password": "పాస్వర్డ్ విజయవంతంగా మార్చబడింది!",
+ "settings.collapse_subject": "Collapse posts with subjects",
+ "settings.composing": "Composing",
+ "settings.confirm_new_password": "కొత్త పాస్వర్డ్ను నిర్ధారించండి",
+ "settings.current_avatar": "మీ ప్రస్తుత అవతారం",
+ "settings.current_password": "ప్రస్తుత పాస్వర్డ్",
+ "settings.current_profile_banner": "మీ ప్రస్తుత ప్రొఫైల్ బ్యానర్",
+ "settings.data_import_export_tab": "Data Import / Export",
+ "settings.default_vis": "Default visibility scope",
+ "settings.delete_account": "Delete Account",
+ "settings.delete_account_description": "మీ ఖాతా మరియు మీ అన్ని సందేశాలను శాశ్వతంగా తొలగించండి.",
+ "settings.delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
+ "settings.delete_account_instructions": "ఖాతా తొలగింపును నిర్ధారించడానికి దిగువ ఇన్పుట్లో మీ పాస్వర్డ్ను టైప్ చేయండి.",
+ "settings.avatar_size_instruction": "అవతార్ చిత్రాలకు సిఫార్సు చేసిన కనీస పరిమాణం 150x150 పిక్సెల్స్.",
+ "settings.export_theme": "Save preset",
+ "settings.filtering": "వడపోత",
+ "settings.filtering_explanation": "All statuses containing these words will be muted, one per line",
+ "settings.follow_export": "Follow export",
+ "settings.follow_export_button": "Export your follows to a csv file",
+ "settings.follow_export_processing": "Processing, you'll soon be asked to download your file",
+ "settings.follow_import": "Follow import",
+ "settings.follow_import_error": "అనుచరులను దిగుమతి చేయడంలో లోపం",
+ "settings.follows_imported": "Follows imported! Processing them will take a while.",
+ "settings.foreground": "Foreground",
+ "settings.general": "General",
+ "settings.hide_attachments_in_convo": "సంభాషణలలో జోడింపులను దాచు",
+ "settings.hide_attachments_in_tl": "కాలక్రమంలో జోడింపులను దాచు",
+ "settings.hide_muted_posts": "మ్యూట్ చేసిన వినియోగదారుల యొక్క పోస్ట్లను దాచిపెట్టు",
+ "settings.max_thumbnails": "Maximum amount of thumbnails per post",
+ "settings.hide_isp": "Hide instance-specific panel",
+ "settings.preload_images": "Preload images",
+ "settings.use_one_click_nsfw": "కేవలం ఒక క్లిక్ తో NSFW జోడింపులను తెరవండి",
+ "settings.hide_post_stats": "Hide post statistics (e.g. the number of favorites)",
+ "settings.hide_user_stats": "Hide user statistics (e.g. the number of followers)",
+ "settings.hide_filtered_statuses": "Hide filtered statuses",
+ "settings.import_followers_from_a_csv_file": "Import follows from a csv file",
+ "settings.import_theme": "Load preset",
+ "settings.inputRadius": "Input fields",
+ "settings.checkboxRadius": "Checkboxes",
+ "settings.instance_default": "(default: {value})",
+ "settings.instance_default_simple": "(default)",
+ "settings.interface": "Interface",
+ "settings.interfaceLanguage": "Interface language",
+ "settings.invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
+ "settings.limited_availability": "మీ బ్రౌజర్లో అందుబాటులో లేదు",
+ "settings.links": "Links",
+ "settings.lock_account_description": "మీ ఖాతాను ఆమోదించిన అనుచరులకు మాత్రమే పరిమితం చేయండి",
+ "settings.loop_video": "Loop videos",
+ "settings.loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")",
+ "settings.mutes_tab": "మ్యూట్ చేయబడినవి",
+ "settings.play_videos_in_modal": "మీడియా వీక్షికలో నేరుగా వీడియోలను ప్లే చేయి",
+ "settings.use_contain_fit": "అటాచ్మెంట్ సూక్ష్మచిత్రాలను కత్తిరించవద్దు",
+ "settings.name": "Name",
+ "settings.name_bio": "పేరు & బయో",
+ "settings.new_password": "కొత్త సంకేతపదం",
+ "settings.notification_visibility": "చూపించవలసిన నోటిఫికేషన్ రకాలు",
+ "settings.notification_visibility_follows": "Follows",
+ "settings.notification_visibility_likes": "ఇష్టాలు",
+ "settings.notification_visibility_mentions": "ప్రస్తావనలు",
+ "settings.notification_visibility_repeats": "పునఃప్రసారాలు",
+ "settings.no_rich_text_description": "అన్ని పోస్ట్ల నుండి రిచ్ టెక్స్ట్ ఫార్మాటింగ్ను స్ట్రిప్ చేయండి",
+ "settings.no_blocks": "బ్లాక్స్ లేవు",
+ "settings.no_mutes": "మ్యూట్లు లేవు",
+ "settings.hide_follows_description": "నేను ఎవరిని అనుసరిస్తున్నానో చూపించవద్దు",
+ "settings.hide_followers_description": "నన్ను ఎవరు అనుసరిస్తున్నారో చూపవద్దు",
+ "settings.show_admin_badge": "నా ప్రొఫైల్ లో అడ్మిన్ బ్యాడ్జ్ చూపించు",
+ "settings.show_moderator_badge": "నా ప్రొఫైల్లో మోడరేటర్ బ్యాడ్జ్ని చూపించు",
+ "settings.nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding",
+ "settings.oauth_tokens": "OAuth tokens",
+ "settings.token": "Token",
+ "settings.refresh_token": "Refresh Token",
+ "settings.valid_until": "Valid Until",
+ "settings.revoke_token": "Revoke",
+ "settings.panelRadius": "Panels",
+ "settings.pause_on_unfocused": "Pause streaming when tab is not focused",
+ "settings.presets": "Presets",
+ "settings.profile_background": "Profile Background",
+ "settings.profile_banner": "Profile Banner",
+ "settings.profile_tab": "Profile",
+ "settings.radii_help": "Set up interface edge rounding (in pixels)",
+ "settings.replies_in_timeline": "Replies in timeline",
+ "settings.reply_link_preview": "Enable reply-link preview on mouse hover",
+ "settings.reply_visibility_all": "Show all replies",
+ "settings.reply_visibility_following": "Only show replies directed at me or users I'm following",
+ "settings.reply_visibility_self": "Only show replies directed at me",
+ "settings.saving_err": "Error saving settings",
+ "settings.saving_ok": "Settings saved",
+ "settings.security_tab": "Security",
+ "settings.scope_copy": "Copy scope when replying (DMs are always copied)",
+ "settings.set_new_avatar": "Set new avatar",
+ "settings.set_new_profile_background": "Set new profile background",
+ "settings.set_new_profile_banner": "Set new profile banner",
+ "settings.settings": "Settings",
+ "settings.subject_input_always_show": "Always show subject field",
+ "settings.subject_line_behavior": "Copy subject when replying",
+ "settings.subject_line_email": "Like email: \"re: subject\"",
+ "settings.subject_line_mastodon": "Like mastodon: copy as is",
+ "settings.subject_line_noop": "Do not copy",
+ "settings.post_status_content_type": "Post status content type",
+ "settings.stop_gifs": "Play-on-hover GIFs",
+ "settings.streaming": "Enable automatic streaming of new posts when scrolled to the top",
+ "settings.text": "Text",
+ "settings.theme": "Theme",
+ "settings.theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
+ "settings.theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.",
+ "settings.theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.",
+ "settings.tooltipRadius": "Tooltips/alerts",
+ "settings.upload_a_photo": "Upload a photo",
+ "settings.user_settings": "User Settings",
+ "settings.values.false": "no",
+ "settings.values.true": "yes",
+ "settings.notifications": "Notifications",
+ "settings.enable_web_push_notifications": "Enable web push notifications",
+ "settings.style.switcher.keep_color": "Keep colors",
+ "settings.style.switcher.keep_shadows": "Keep shadows",
+ "settings.style.switcher.keep_opacity": "Keep opacity",
+ "settings.style.switcher.keep_roundness": "Keep roundness",
+ "settings.style.switcher.keep_fonts": "Keep fonts",
+ "settings.style.switcher.save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme. When all checkboxes unset, exporting theme will save everything.",
+ "settings.style.switcher.reset": "Reset",
+ "settings.style.switcher.clear_all": "Clear all",
+ "settings.style.switcher.clear_opacity": "Clear opacity",
+ "settings.style.common.color": "Color",
+ "settings.style.common.opacity": "Opacity",
+ "settings.style.common.contrast.hint": "Contrast ratio is {ratio}, it {level} {context}",
+ "settings.style.common.contrast.level.aa": "meets Level AA guideline (minimal)",
+ "settings.style.common.contrast.level.aaa": "meets Level AAA guideline (recommended)",
+ "settings.style.common.contrast.level.bad": "doesn't meet any accessibility guidelines",
+ "settings.style.common.contrast.context.18pt": "for large (18pt+) text",
+ "settings.style.common.contrast.context.text": "for text",
+ "settings.style.common_colors._tab_label": "Common",
+ "settings.style.common_colors.main": "Common colors",
+ "settings.style.common_colors.foreground_hint": "See \"Advanced\" tab for more detailed control",
+ "settings.style.common_colors.rgbo": "Icons, accents, badges",
+ "settings.style.advanced_colors._tab_label": "Advanced",
+ "settings.style.advanced_colors.alert": "Alert background",
+ "settings.style.advanced_colors.alert_error": "Error",
+ "settings.style.advanced_colors.badge": "Badge background",
+ "settings.style.advanced_colors.badge_notification": "Notification",
+ "settings.style.advanced_colors.panel_header": "Panel header",
+ "settings.style.advanced_colors.top_bar": "Top bar",
+ "settings.style.advanced_colors.borders": "Borders",
+ "settings.style.advanced_colors.buttons": "Buttons",
+ "settings.style.advanced_colors.inputs": "Input fields",
+ "settings.style.advanced_colors.faint_text": "Faded text",
+ "settings.style.radii._tab_label": "Roundness",
+ "settings.style.shadows._tab_label": "Shadow and lighting",
+ "settings.style.shadows.component": "Component",
+ "settings.style.shadows.override": "Override",
+ "settings.style.shadows.shadow_id": "Shadow #{value}",
+ "settings.style.shadows.blur": "Blur",
+ "settings.style.shadows.spread": "Spread",
+ "settings.style.shadows.inset": "Inset",
+ "settings.style.shadows.hint": "For shadows you can also use --variable as a color value to use CSS3 variables. Please note that setting opacity won't work in this case.",
+ "settings.style.shadows.filter_hint.always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.",
+ "settings.style.shadows.filter_hint.drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.",
+ "settings.style.shadows.filter_hint.avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.",
+ "settings.style.shadows.filter_hint.spread_zero": "Shadows with spread > 0 will appear as if it was set to zero",
+ "settings.style.shadows.filter_hint.inset_classic": "Inset shadows will be using {0}",
+ "settings.style.shadows.components.panel": "Panel",
+ "settings.style.shadows.components.panelHeader": "Panel header",
+ "settings.style.shadows.components.topBar": "Top bar",
+ "settings.style.shadows.components.avatar": "User avatar (in profile view)",
+ "settings.style.shadows.components.avatarStatus": "User avatar (in post display)",
+ "settings.style.shadows.components.popup": "Popups and tooltips",
+ "settings.style.shadows.components.button": "Button",
+ "settings.style.shadows.components.buttonHover": "Button (hover)",
+ "settings.style.shadows.components.buttonPressed": "Button (pressed)",
+ "settings.style.shadows.components.buttonPressedHover": "Button (pressed+hover)",
+ "settings.style.shadows.components.input": "Input field",
+ "settings.style.fonts._tab_label": "Fonts",
+ "settings.style.fonts.help": "Select font to use for elements of UI. For \"custom\" you have to enter exact font name as it appears in system.",
+ "settings.style.fonts.components.interface": "Interface",
+ "settings.style.fonts.components.input": "Input fields",
+ "settings.style.fonts.components.post": "Post text",
+ "settings.style.fonts.components.postCode": "Monospaced text in a post (rich text)",
+ "settings.style.fonts.family": "Font name",
+ "settings.style.fonts.size": "Size (in px)",
+ "settings.style.fonts.weight": "Weight (boldness)",
+ "settings.style.fonts.custom": "Custom",
+ "settings.style.preview.header": "Preview",
+ "settings.style.preview.content": "Content",
+ "settings.style.preview.error": "Example error",
+ "settings.style.preview.button": "Button",
+ "settings.style.preview.text": "A bunch of more {0} and {1}",
+ "settings.style.preview.mono": "content",
+ "settings.style.preview.input": "Just landed in L.A.",
+ "settings.style.preview.faint_link": "helpful manual",
+ "settings.style.preview.fine_print": "Read our {0} to learn nothing useful!",
+ "settings.style.preview.header_faint": "This is fine",
+ "settings.style.preview.checkbox": "I have skimmed over terms and conditions",
+ "settings.style.preview.link": "a nice lil' link",
+ "settings.version.title": "Version",
+ "settings.version.backend_version": "Backend Version",
+ "settings.version.frontend_version": "Frontend Version",
+ "timeline.collapse": "Collapse",
+ "timeline.conversation": "Conversation",
+ "timeline.error_fetching": "Error fetching updates",
+ "timeline.load_older": "Load older statuses",
+ "timeline.no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated",
+ "timeline.repeated": "repeated",
+ "timeline.show_new": "Show new",
+ "timeline.up_to_date": "Up-to-date",
+ "timeline.no_more_statuses": "No more statuses",
+ "timeline.no_statuses": "No statuses",
+ "status.reply_to": "Reply to",
+ "status.replies_list": "Replies:",
+ "user_card.approve": "Approve",
+ "user_card.block": "Block",
+ "user_card.blocked": "Blocked!",
+ "user_card.deny": "Deny",
+ "user_card.favorites": "Favorites",
+ "user_card.follow": "Follow",
+ "user_card.follow_sent": "Request sent!",
+ "user_card.follow_progress": "Requesting…",
+ "user_card.follow_again": "Send request again?",
+ "user_card.follow_unfollow": "Unfollow",
+ "user_card.followees": "Following",
+ "user_card.followers": "Followers",
+ "user_card.following": "Following!",
+ "user_card.follows_you": "Follows you!",
+ "user_card.its_you": "It's you!",
+ "user_card.media": "Media",
+ "user_card.mute": "Mute",
+ "user_card.muted": "Muted",
+ "user_card.per_day": "per day",
+ "user_card.remote_follow": "Remote follow",
+ "user_card.statuses": "Statuses",
+ "user_card.unblock": "Unblock",
+ "user_card.unblock_progress": "Unblocking...",
+ "user_card.block_progress": "Blocking...",
+ "user_card.unmute": "Unmute",
+ "user_card.unmute_progress": "Unmuting...",
+ "user_card.mute_progress": "Muting...",
+ "user_profile.timeline_title": "User Timeline",
+ "user_profile.profile_does_not_exist": "Sorry, this profile does not exist.",
+ "user_profile.profile_loading_error": "Sorry, there was an error loading this profile.",
+ "who_to_follow.more": "More",
+ "who_to_follow.who_to_follow": "Who to follow",
+ "tool_tip.media_upload": "Upload Media",
+ "tool_tip.repeat": "Repeat",
+ "tool_tip.reply": "Reply",
+ "tool_tip.favorite": "Favorite",
+ "tool_tip.user_settings": "User Settings",
+ "upload.error.base": "Upload failed.",
+ "upload.error.file_too_big": "File too big [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
+ "upload.error.default": "Try again later",
+ "upload.file_size_units.B": "B",
+ "upload.file_size_units.KiB": "KiB",
+ "upload.file_size_units.MiB": "MiB",
+ "upload.file_size_units.GiB": "GiB",
+ "upload.file_size_units.TiB": "TiB"
+}
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index 7d5d5a67..e863d8a5 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -430,6 +430,10 @@ export const mutations = {
const newStatus = state.allStatusesObject[status.id]
newStatus.pinned = status.pinned
},
+ setMuted (state, status) {
+ const newStatus = state.allStatusesObject[status.id]
+ newStatus.muted = status.muted
+ },
setRetweeted (state, { status, value }) {
const newStatus = state.allStatusesObject[status.id]
@@ -564,6 +568,14 @@ const statuses = {
rootState.api.backendInteractor.unpinOwnStatus(statusId)
.then((status) => commit('setPinned', status))
},
+ muteConversation ({ rootState, commit }, statusId) {
+ return rootState.api.backendInteractor.muteConversation(statusId)
+ .then((status) => commit('setMuted', status))
+ },
+ unmuteConversation ({ rootState, commit }, statusId) {
+ return rootState.api.backendInteractor.unmuteConversation(statusId)
+ .then((status) => commit('setMuted', status))
+ },
retweet ({ rootState, commit }, status) {
// Optimistic retweeting...
commit('setRetweeted', { status, value: true })
diff --git a/src/modules/users.js b/src/modules/users.js
index 10def9cd..4d78aef5 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -3,7 +3,6 @@ import oauthApi from '../services/new_api/oauth.js'
import { compact, map, each, merge, last, concat, uniq } from 'lodash'
import { set } from 'vue'
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
-import { humanizeErrors } from './errors'
// TODO: Unify with mergeOrAdd in statuses.js
export const mergeOrAdd = (arr, obj, item) => {
@@ -382,16 +381,8 @@ const users = {
store.dispatch('loginUser', data.access_token)
} catch (e) {
let errors = e.message
- // replace ap_id with username
- if (typeof errors === 'object') {
- if (errors.ap_id) {
- errors.username = errors.ap_id
- delete errors.ap_id
- }
- errors = humanizeErrors(errors)
- }
store.commit('signUpFailure', errors)
- throw Error(errors)
+ throw e
}
},
async getCaptcha (store) {
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index d4ad1c4e..083d4f4f 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -1,7 +1,7 @@
import { each, map, concat, last } from 'lodash'
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
import 'whatwg-fetch'
-import { StatusCodeError } from '../errors/errors'
+import { RegistrationError, StatusCodeError } from '../errors/errors'
/* eslint-env browser */
const EXTERNAL_PROFILE_URL = '/api/externalprofile/show.json'
@@ -67,6 +67,8 @@ const MASTODON_PROFILE_UPDATE_URL = '/api/v1/accounts/update_credentials'
const MASTODON_REPORT_USER_URL = '/api/v1/reports'
const MASTODON_PIN_OWN_STATUS = id => `/api/v1/statuses/${id}/pin`
const MASTODON_UNPIN_OWN_STATUS = id => `/api/v1/statuses/${id}/unpin`
+const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
+const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
const MASTODON_SEARCH_2 = `/api/v2/search`
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
@@ -199,12 +201,11 @@ const register = ({ params, credentials }) => {
...rest
})
})
- .then((response) => [response.ok, response])
- .then(([ok, response]) => {
- if (ok) {
+ .then((response) => {
+ if (response.ok) {
return response.json()
} else {
- return response.json().then((error) => { throw new Error(error) })
+ return response.json().then((error) => { throw new RegistrationError(error) })
}
})
}
@@ -253,6 +254,16 @@ const unpinOwnStatus = ({ id, credentials }) => {
.then((data) => parseStatus(data))
}
+const muteConversation = ({ id, credentials }) => {
+ return promisedRequest({ url: MASTODON_MUTE_CONVERSATION(id), credentials, method: 'POST' })
+ .then((data) => parseStatus(data))
+}
+
+const unmuteConversation = ({ id, credentials }) => {
+ return promisedRequest({ url: MASTODON_UNMUTE_CONVERSATION(id), credentials, method: 'POST' })
+ .then((data) => parseStatus(data))
+}
+
const blockUser = ({ id, credentials }) => {
return fetch(MASTODON_BLOCK_USER_URL(id), {
headers: authHeaders(credentials),
@@ -921,6 +932,8 @@ const apiService = {
unfollowUser,
pinOwnStatus,
unpinOwnStatus,
+ muteConversation,
+ unmuteConversation,
blockUser,
unblockUser,
fetchUser,
diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js
index bdfe0465..846d9415 100644
--- a/src/services/backend_interactor_service/backend_interactor_service.js
+++ b/src/services/backend_interactor_service/backend_interactor_service.js
@@ -117,6 +117,8 @@ const backendInteractorService = credentials => {
const fetchPinnedStatuses = (id) => apiService.fetchPinnedStatuses({ credentials, id })
const pinOwnStatus = (id) => apiService.pinOwnStatus({ credentials, id })
const unpinOwnStatus = (id) => apiService.unpinOwnStatus({ credentials, id })
+ const muteConversation = (id) => apiService.muteConversation({ credentials, id })
+ const unmuteConversation = (id) => apiService.unmuteConversation({ credentials, id })
const getCaptcha = () => apiService.getCaptcha()
const register = (params) => apiService.register({ credentials, params })
@@ -178,6 +180,8 @@ const backendInteractorService = credentials => {
fetchPinnedStatuses,
pinOwnStatus,
unpinOwnStatus,
+ muteConversation,
+ unmuteConversation,
tagUser,
untagUser,
addRight,
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index 8b4d2594..6cc1851d 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -65,6 +65,7 @@ export const parseUser = (data) => {
if (relationship) {
output.follows_you = relationship.followed_by
+ output.requested = relationship.requested
output.following = relationship.following
output.statusnet_blocking = relationship.blocking
output.muted = relationship.muting
@@ -240,6 +241,7 @@ export const parseStatus = (data) => {
output.external_url = data.url
output.poll = data.poll
output.pinned = data.pinned
+ output.muted = data.muted
} else {
output.favorited = data.favorited
output.fave_num = data.fave_num
diff --git a/src/services/errors/errors.js b/src/services/errors/errors.js
index 548f3c68..590552da 100644
--- a/src/services/errors/errors.js
+++ b/src/services/errors/errors.js
@@ -1,3 +1,5 @@
+import { humanizeErrors } from '../../modules/errors'
+
export function StatusCodeError (statusCode, body, options, response) {
this.name = 'StatusCodeError'
this.statusCode = statusCode
@@ -12,3 +14,36 @@ export function StatusCodeError (statusCode, body, options, response) {
}
StatusCodeError.prototype = Object.create(Error.prototype)
StatusCodeError.prototype.constructor = StatusCodeError
+
+export class RegistrationError extends Error {
+ constructor (error) {
+ super()
+ if (Error.captureStackTrace) {
+ Error.captureStackTrace(this)
+ }
+
+ try {
+ // the error is probably a JSON object with a single key, "errors", whose value is another JSON object containing the real errors
+ if (typeof error === 'string') {
+ error = JSON.parse(error)
+ if (error.hasOwnProperty('error')) {
+ error = JSON.parse(error.error)
+ }
+ }
+
+ if (typeof error === 'object') {
+ // replace ap_id with username
+ if (error.ap_id) {
+ error.username = error.ap_id
+ delete error.ap_id
+ }
+ this.message = humanizeErrors(error)
+ } else {
+ this.message = error
+ }
+ } catch (e) {
+ // can't parse it, so just treat it like a string
+ this.message = error
+ }
+ }
+}
diff --git a/src/services/follow_manipulate/follow_manipulate.js b/src/services/follow_manipulate/follow_manipulate.js
index b2486e7c..529fdb9b 100644
--- a/src/services/follow_manipulate/follow_manipulate.js
+++ b/src/services/follow_manipulate/follow_manipulate.js
@@ -2,17 +2,17 @@ const fetchUser = (attempt, user, store) => new Promise((resolve, reject) => {
setTimeout(() => {
store.state.api.backendInteractor.fetchUser({ id: user.id })
.then((user) => store.commit('addNewUsers', [user]))
- .then(() => resolve([user.following, attempt]))
+ .then(() => resolve([user.following, user.requested, user.locked, attempt]))
.catch((e) => reject(e))
}, 500)
-}).then(([following, attempt]) => {
- if (!following && attempt <= 3) {
+}).then(([following, sent, locked, attempt]) => {
+ if (!following && !(locked && sent) && attempt <= 3) {
// If we BE reports that we still not following that user - retry,
// increment attempts by one
return fetchUser(++attempt, user, store)
} else {
// If we run out of attempts, just return whatever status is.
- return following
+ return sent
}
})
@@ -21,14 +21,10 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
.then((updated) => {
store.commit('updateUserRelationship', [updated])
- // For locked users we just mark it that we sent the follow request
- if (updated.locked) {
- resolve({ sent: true })
- }
-
- if (updated.following) {
- // If we get result immediately, just stop.
- resolve({ sent: false })
+ if (updated.following || (user.locked && user.requested)) {
+ // If we get result immediately or the account is locked, just stop.
+ resolve({ sent: updated.requested })
+ return
}
// But usually we don't get result immediately, so we ask server
@@ -39,14 +35,8 @@ export const requestFollow = (user, store) => new Promise((resolve, reject) => {
// Recursive Promise, it will call itself up to 3 times.
return fetchUser(1, user, store)
- .then((following) => {
- if (following) {
- // We confirmed and everything's good.
- resolve({ sent: false })
- } else {
- // If after all the tries, just treat it as if user is locked
- resolve({ sent: false })
- }
+ .then((sent) => {
+ resolve({ sent })
})
})
})
diff --git a/yarn.lock b/yarn.lock
index 13d94a23..d6c8b4a6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1387,10 +1387,29 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
+caller-callsite@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
+ integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=
+ dependencies:
+ callsites "^2.0.0"
+
+caller-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4"
+ integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=
+ dependencies:
+ caller-callsite "^2.0.0"
+
callsite@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
+callsites@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+ integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=
+
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -1817,6 +1836,16 @@ cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
parse-json "^2.2.0"
require-from-string "^1.1.0"
+cosmiconfig@^5.0.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
+ integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
+ dependencies:
+ import-fresh "^2.0.0"
+ is-directory "^0.3.1"
+ js-yaml "^3.13.1"
+ parse-json "^4.0.0"
+
create-ecdh@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
@@ -2390,7 +2419,7 @@ errno@^0.1.3, errno@~0.1.7:
dependencies:
prr "~1.0.1"
-error-ex@^1.2.0:
+error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
dependencies:
@@ -3503,6 +3532,21 @@ immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
+import-cwd@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
+ integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=
+ dependencies:
+ import-from "^2.1.0"
+
+import-fresh@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
+ integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY=
+ dependencies:
+ caller-path "^2.0.0"
+ resolve-from "^3.0.0"
+
import-fresh@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.0.0.tgz#a3d897f420cab0e671236897f75bc14b4885c390"
@@ -3510,6 +3554,13 @@ import-fresh@^3.0.0:
parent-module "^1.0.0"
resolve-from "^4.0.0"
+import-from@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1"
+ integrity sha1-M1238qev/VOqpHHUuAId7ja387E=
+ dependencies:
+ resolve-from "^3.0.0"
+
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@@ -3949,7 +4000,7 @@ js-yaml@3.x, js-yaml@^3.4.3:
argparse "^1.0.7"
esprima "^4.0.0"
-js-yaml@^3.13.0:
+js-yaml@^3.13.0, js-yaml@^3.13.1:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
dependencies:
@@ -3979,7 +4030,7 @@ json-loader@^0.5.4:
version "0.5.7"
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d"
-json-parse-better-errors@^1.0.2:
+json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@@ -5315,6 +5366,14 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
+parse-json@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+ integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
+ dependencies:
+ error-ex "^1.3.1"
+ json-parse-better-errors "^1.0.1"
+
parseqs@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
@@ -5541,6 +5600,14 @@ postcss-load-config@^1.1.0:
postcss-load-options "^1.2.0"
postcss-load-plugins "^2.3.0"
+postcss-load-config@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003"
+ integrity sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==
+ dependencies:
+ cosmiconfig "^5.0.0"
+ import-cwd "^2.0.0"
+
postcss-load-options@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c"
@@ -5555,6 +5622,16 @@ postcss-load-plugins@^2.3.0:
cosmiconfig "^2.1.1"
object-assign "^4.1.0"
+postcss-loader@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d"
+ integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==
+ dependencies:
+ loader-utils "^1.1.0"
+ postcss "^7.0.0"
+ postcss-load-config "^2.0.0"
+ schema-utils "^1.0.0"
+
postcss-merge-idents@^2.1.5:
version "2.1.7"
resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
@@ -5740,6 +5817,15 @@ postcss@^6.0.1, postcss@^6.0.8:
source-map "^0.6.1"
supports-color "^5.4.0"
+postcss@^7.0.0:
+ version "7.0.17"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
+ integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
postcss@^7.0.5:
version "7.0.8"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.8.tgz#2a3c5f2bdd00240cd0d0901fd998347c93d36696"
@@ -6203,6 +6289,11 @@ requires-port@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+resolve-from@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
+ integrity sha1-six699nWiBvItuZTM17rywoYh0g=
+
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -6844,7 +6935,7 @@ supports-color@^5.3.0, supports-color@^5.4.0:
dependencies:
has-flag "^3.0.0"
-supports-color@^6.0.0:
+supports-color@^6.0.0, supports-color@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
dependencies: