Merge pull request '2022.10 stable' (#177) from develop into stable

Reviewed-on: AkkomaGang/pleroma-fe#177
This commit is contained in:
floatingghost 2022-10-08 11:13:01 +00:00
commit c8c8d40827
48 changed files with 2973 additions and 1755 deletions

View file

@ -1,47 +0,0 @@
# This file is a template, and might need editing before it works on your project.
# Official framework image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/node/tags/
image: node:12
stages:
- lint
- build
- test
- deploy
lint:
stage: lint
script:
- yarn
- npm run lint
- npm run stylelint
test:
stage: test
variables:
APT_CACHE_DIR: apt-cache
script:
- mkdir -pv $APT_CACHE_DIR && apt-get -qq update
- apt install firefox-esr -y --no-install-recommends
- firefox --version
- yarn
- yarn unit
build:
stage: build
script:
- yarn
- npm run build
artifacts:
paths:
- dist/
docs-deploy:
stage: deploy
image: alpine:latest
only:
- develop@pleroma/pleroma-fe
before_script:
- apk add curl
script:
- curl -X POST -F"token=$DOCS_PIPELINE_TRIGGER" -F'ref=master' https://git.pleroma.social/api/v4/projects/673/trigger/pipeline

View file

@ -4,6 +4,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## Unreleased
### Added
- Implemented remote interaction with statuses
## 2022.09 - 2022-09-10
### Added
- Automatic post translations. Must be configured on the backend in order to work.
- Post editing, including a log of previous edits.
### Changed
- Top bar now has navigation shortcuts. Can be enabled or disabled by admins or users.
- Optional replacement of timeline drop-down with navigation buttons. Also configurable.
- Posts and posts with replies are now separated on user profiles.
- Custom emoji from remote instances on a post can now also be used.
## 2022.08 - 2022-08-12
### Added
- Ability to quote public and unlisted posts
- Bubble timeline
### Changed
- Emoji in emoji picker is separated by packs
### Removed
- Chats, they were half-baked. Just use PMs.
## 2022.07 - 2022-07-16
### Fixed
- AdminFE button no longer scrolls page to top when clicked
- Pinned statuses no longer appear at bottom of user timeline (still appear as part of the timeline when fetched deep enough)
@ -16,6 +43,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Attachments are ALWAYS in same order as user uploaded, no more "videos first"
- Attachment description is prefilled with backend-provided default when uploading
- Proper visual feedback that next image is loading when browsing
- Misskey-Flavoured Markdown support
- Custom emoji reactions
### Changed
- (You)s are optional (opt-in) now, bolding your nickname is also optional (opt-out)

View file

@ -6,6 +6,7 @@ You have several timelines to browse trough
- **Bookmarks** all the posts you've bookmarked. You can bookmark a post by clicking the three dots on the bottom right of the post and choose Bookmark.
- **Direct Messages** all posts with `direct` scope addressed to you or mentioning you.
- **Public Timelines** all public posts made by users on the instance you're on
- **Bubble Timeline** all public posts from instances recommended by your admin(s) in the instance settings. This won't appear if they haven't set anything up for it.
- **The Whole Known Network** also known as **TWKN** or **Federated Timeline** - all public posts known by your instance. Due to nature of the network your instance may not know *all* the posts on the network, so only posts known by your instance are shown there.
Note that by default you will see all posts made by other users on your Home Timeline, this contrast behavior of Twitter and Mastodon, which shows you only non-reply posts and replies to people you follow. You can change said behavior in the [settings](settings.md#filtering).

View file

@ -1,7 +1,7 @@
{
"name": "pleroma_fe",
"version": "1.0.0",
"description": "A Qvitter-style frontend for certain GS servers.",
"version": "3.2.0",
"description": "A frontend for Akkoma instances",
"author": "Roger Braun <roger@rogerbraun.net>",
"private": true,
"scripts": {
@ -20,7 +20,7 @@
"@chenfengyuan/vue-qrcode": "2.0.0",
"@fortawesome/fontawesome-svg-core": "1.3.0",
"@fortawesome/free-regular-svg-icons": "^6.1.2",
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/vue-fontawesome": "3.0.1",
"@kazvmoe-infra/pinch-zoom-element": "1.2.0",
"@vuelidate/core": "2.0.0-alpha.42",
@ -41,7 +41,7 @@
"qrcode": "1",
"ruffle-mirror": "2021.12.31",
"vue": "^3.2.31",
"vue-i18n": "^9.2.0-beta.39",
"vue-i18n": "^9.2.2",
"vue-router": "4.0.14",
"vue-template-compiler": "2.6.11",
"vuex": "4.0.2"

View file

@ -61,7 +61,6 @@
<EditStatusModal v-if="editingAvailable" />
<StatusHistoryModal v-if="editingAvailable" />
<SettingsModal />
<UpdateNotification />
<GlobalNoticeList />
</div>
</template>

View file

@ -398,7 +398,6 @@ const afterStoreSetup = async ({ store, i18n }) => {
store.dispatch('startFetchingAnnouncements')
getTOS({ store })
getStickers({ store })
store.dispatch('getSupportedTranslationlanguages')
const router = createRouter({
history: createWebHistory(),

View file

@ -20,6 +20,9 @@ const About = {
return this.$store.state.instance.showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP &&
this.$store.state.instance.instanceSpecificPanelContent
},
showLocalBubblePanel () {
return this.$store.state.instance.localBubbleInstances.length > 0
}
}
}

View file

@ -3,7 +3,7 @@
<instance-specific-panel v-if="showInstanceSpecificPanel" />
<staff-panel />
<terms-of-service-panel />
<LocalBubblePanel />
<LocalBubblePanel v-if="showLocalBubblePanel" />
<MRFTransparencyPanel />
<features-panel v-if="showFeaturesPanel" />
</div>

View file

@ -52,6 +52,9 @@ const AccountActions = {
unblockUser () {
this.$store.dispatch('unblockUser', this.user.id)
},
removeUserFromFollowers () {
this.$store.dispatch('removeUserFromFollowers', this.user.id)
},
reportUser () {
this.$store.dispatch('openUserReportingModal', { userId: this.user.id })
}

View file

@ -28,6 +28,13 @@
class="dropdown-divider"
/>
</template>
<button
v-if="relationship.followed_by"
class="btn button-default btn-block dropdown-item"
@click="removeUserFromFollowers"
>
{{ $t('user_card.remove_follower') }}
</button>
<button
v-if="relationship.blocking"
class="btn button-default btn-block dropdown-item"

View file

@ -8,7 +8,8 @@ import {
faThumbtack,
faShareAlt,
faExternalLinkAlt,
faHistory
faHistory,
faFilePen
} from '@fortawesome/free-solid-svg-icons'
import {
faBookmark as faBookmarkReg,
@ -24,7 +25,8 @@ library.add(
faShareAlt,
faExternalLinkAlt,
faFlag,
faHistory
faHistory,
faFilePen
)
const ExtraButtons = {
@ -36,7 +38,8 @@ const ExtraButtons = {
data () {
return {
expanded: false,
showingDeleteDialog: false
showingDeleteDialog: false,
showingRedraftDialog: false
}
},
methods: {
@ -122,6 +125,34 @@ const ExtraButtons = {
const stripFieldsList = ['attachments', 'created_at', 'emojis', 'text', 'raw_html', 'nsfw', 'poll', 'summary', 'summary_raw_html']
stripFieldsList.forEach(p => delete originalStatus[p])
this.$store.dispatch('openStatusHistoryModal', originalStatus)
},
redraftStatus () {
if (this.shouldConfirmDelete) {
this.showRedraftStatusConfirmDialog()
} else {
this.doRedraftStatus()
}
},
doRedraftStatus () {
this.$store.dispatch('fetchStatusSource', { id: this.status.id })
.then(data => this.$store.dispatch('openPostStatusModal', {
isRedraft: true,
statusId: this.status.id,
subject: data.spoiler_text,
statusText: data.text,
statusIsSensitive: this.status.nsfw,
statusPoll: this.status.poll,
statusFiles: [...this.status.attachments],
statusScope: this.status.visibility,
statusContentType: data.content_type
}))
this.doDeleteStatus()
},
showRedraftStatusConfirmDialog () {
this.showingRedraftDialog = true
},
hideRedraftStatusConfirmDialog () {
this.showingRedraftDialog = false
}
},
computed: {

View file

@ -95,6 +95,17 @@
icon="history"
/><span>{{ $t("status.edit_history") }}</span>
</button>
<button
v-if="ownStatus"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="redraftStatus"
@click="close"
>
<FAIcon
fixed-width
icon="file-pen"
/><span>{{ $t("status.redraft") }}</span>
</button>
<button
v-if="canDelete"
class="button-default dropdown-item dropdown-item-icon"
@ -179,6 +190,16 @@
>
{{ $t('status.delete_confirm') }}
</ConfirmModal>
<ConfirmModal
v-if="showingRedraftDialog"
:title="$t('status.redraft_confirm_title')"
:cancel-text="$t('status.redraft_confirm_cancel_button')"
:confirm-text="$t('status.redraft_confirm_accept_button')"
@cancelled="hideRedraftStatusConfirmDialog"
@accepted="doRedraftStatus"
>
{{ $t('status.redraft_confirm') }}
</ConfirmModal>
</teleport>
</template>
</Popover>

View file

@ -31,7 +31,10 @@ const FavoriteButton = {
}
},
computed: {
...mapGetters(['mergedConfig'])
...mapGetters(['mergedConfig']),
remoteInteractionLink () {
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
}
}
}

View file

@ -13,13 +13,19 @@
:spin="animated"
/>
</button>
<span v-else>
<a
v-else
class="button-unstyled interactive"
target="_blank"
role="button"
:href="remoteInteractionLink"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
:title="$t('tool_tip.favorite')"
:icon="['far', 'star']"
/>
</span>
</a>
<span
v-if="!mergedConfig.hidePostStats && status.fave_num > 0"
class="action-counter"

View file

@ -1,6 +1,7 @@
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import RemoteFollow from '../remote_follow/remote_follow.vue'
import FollowButton from '../follow_button/follow_button.vue'
import RemoveFollowerButton from '../remove_follower_button/remove_follower_button.vue'
const FollowCard = {
props: [
@ -10,7 +11,8 @@ const FollowCard = {
components: {
BasicUserCard,
RemoteFollow,
FollowButton
FollowButton,
RemoveFollowerButton
},
computed: {
isMe () {

View file

@ -22,6 +22,11 @@
class="follow-card-follow-button"
:user="user"
/>
<RemoveFollowerButton
v-if="noFollowsYou && relationship.followed_by"
:relationship="relationship"
class="follow-card-button"
/>
</template>
</div>
</basic-user-card>
@ -40,6 +45,12 @@
line-height: 1.5em;
}
&-button {
margin-top: 0.5em;
padding: 0 1.5em;
margin-left: 1em;
}
&-follow-button {
margin-top: 0.5em;
margin-left: auto;

View file

@ -86,7 +86,8 @@ const PostStatusForm = {
'fileLimit',
'submitOnEnter',
'emojiPickerPlacement',
'optimisticPosting'
'optimisticPosting',
'isRedraft'
],
emits: [
'posted',
@ -141,7 +142,7 @@ const PostStatusForm = {
contentType
}
if (this.statusId) {
if (this.statusId || this.isRedraft) {
const statusContentType = this.statusContentType || contentType
statusParams = {
spoilerText: this.subject || '',
@ -259,7 +260,7 @@ const PostStatusForm = {
return this.newStatus.files.length >= this.fileLimit
},
isEdit () {
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== ''
return typeof this.statusId !== 'undefined' && this.statusId.trim() !== '' && !this.isRedraft
},
...mapGetters(['mergedConfig']),
...mapState({

View file

@ -28,7 +28,8 @@ const PostStatusModal = {
},
watch: {
params (newVal, oldVal) {
if (get(newVal, 'repliedUser.id') !== get(oldVal, 'repliedUser.id')) {
if (get(newVal, 'repliedUser.id') !== get(oldVal, 'repliedUser.id') ||
get(newVal, 'statusId') !== get(oldVal, 'statusId')) {
this.resettingForm = true
this.$nextTick(() => {
this.resettingForm = false

View file

@ -0,0 +1,25 @@
export default {
props: ['relationship'],
data () {
return {
inProgress: false
}
},
computed: {
label () {
if (this.inProgress) {
return this.$t('user_card.follow_progress')
} else {
return this.$t('user_card.remove_follower')
}
}
},
methods: {
onClick () {
this.inProgress = true
this.$store.dispatch('removeUserFromFollowers', this.relationship.id).then(() => {
this.inProgress = false
})
}
}
}

View file

@ -0,0 +1,13 @@
<template>
<button
class="btn button-default follow-button"
:class="{ toggled: inProgress }"
:disabled="inProgress"
:title="$t('user_card.remove_follower')"
@click="onClick"
>
{{ label }}
</button>
</template>
<script src="./remove_follower_button.js"></script>

View file

@ -9,6 +9,9 @@ const ReplyButton = {
computed: {
loggedIn () {
return !!this.$store.state.users.currentUser
},
remoteInteractionLink () {
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
}
}
}

View file

@ -12,13 +12,19 @@
icon="reply"
/>
</button>
<span v-else>
<a
v-else
class="button-unstyled interactive"
target="_blank"
role="button"
:href="remoteInteractionLink"
>
<FAIcon
icon="reply"
class="fa-scale-110 fa-old-padding"
:title="$t('tool_tip.reply')"
/>
</span>
</a>
<span
v-if="status.replies_count > 0"
class="action-counter"

View file

@ -51,6 +51,9 @@ const RetweetButton = {
},
shouldConfirmRepeat () {
return this.mergedConfig.modalOnRepeat
},
remoteInteractionLink () {
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
}
}
}

View file

@ -20,13 +20,19 @@
:title="$t('timeline.no_retweet_hint')"
/>
</span>
<span v-else>
<a
v-else
class="button-unstyled interactive"
target="_blank"
role="button"
:href="remoteInteractionLink"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="retweet"
:title="$t('tool_tip.repeat')"
/>
</span>
</a>
<span
v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
class="no-event"

View file

@ -12,7 +12,8 @@ export default {
'path',
'disabled',
'options',
'expert'
'expert',
'hideDefaultLabel'
],
computed: {
pathDefault () {

View file

@ -16,7 +16,11 @@
:value="option.value"
>
{{ option.label }}
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
<template
v-if="hideDefaultLabel !== true"
>
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
</template>
</option>
</Select>
<ModifiedIndicator :changed="isChanged" />

View file

@ -19,7 +19,7 @@ const SharedComputedObject = () => ({
.map(key => [key, {
get () { return this.$store.getters.mergedConfig[key] },
set (value) {
this.$store.dispatch('setOption', { name: key, value })
this.$store.dispatch('setOption', { name: key, value, manual: true })
}
}])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
@ -27,7 +27,7 @@ const SharedComputedObject = () => ({
.map(key => ['serverSide_' + key, {
get () { return this.$store.state.serverSideConfig[key] },
set (value) {
this.$store.dispatch('setServerSideOption', { name: key, value })
this.$store.dispatch('setServerSideOption', { name: key, value, manual: true })
}
}])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),

View file

@ -8,11 +8,12 @@ import SharedComputedObject from '../helpers/shared_computed_object.js'
import ServerSideIndicator from '../helpers/server_side_indicator.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faGlobe
faGlobe, faSync
} from '@fortawesome/free-solid-svg-icons'
library.add(
faGlobe
faGlobe,
faSync
)
const GeneralTab = {
@ -48,6 +49,8 @@ const GeneralTab = {
value: tab,
label: this.$t(`user_card.${tab}`)
})),
profilesExpanded: false,
newProfileName: '',
loopSilentAvailable:
// Firefox
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
@ -88,8 +91,22 @@ const GeneralTab = {
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
}
},
settingsProfiles () {
return (this.$store.state.instance.settingsProfiles || [])
},
settingsProfile: {
get: function () { return this.$store.getters.mergedConfig.profile },
set: function (val) {
this.$store.dispatch('setOption', { name: 'profile', value: val })
this.$store.dispatch('getSettingsProfile')
}
},
settingsVersion () {
return this.$store.getters.mergedConfig.profileVersion
},
translationLanguages () {
return (this.$store.getters.mergedConfig.supportedTranslationLanguages.target || []).map(lang => ({ key: lang.code, value: lang.code, label: lang.name }))
const langs = this.$store.state.instance.translationLanguages || []
return (langs || []).map(lang => ({ key: lang.code, value: lang.code, label: lang.name }))
},
translationLanguage: {
get: function () { return this.$store.getters.mergedConfig.translationLanguage },
@ -105,6 +122,30 @@ const GeneralTab = {
},
setTranslationLanguage (value) {
this.$store.dispatch('setOption', { name: 'translationLanguage', value })
},
toggleExpandedSettings () {
this.profilesExpanded = !this.profilesExpanded
},
loadSettingsProfile (name) {
this.$store.commit('setOption', { name: 'profile', value: name })
this.$store.dispatch('getSettingsProfile', true)
},
createSettingsProfile () {
this.$store.dispatch('setOption', { name: 'profile', value: this.newProfileName })
this.$store.dispatch('setOption', { name: 'profileVersion', value: 1 })
this.$store.dispatch('syncSettings')
this.newProfileName = ''
},
forceSync () {
this.$store.dispatch('getSettingsProfile')
},
refreshProfiles () {
this.$store.dispatch('listSettingsProfiles')
},
deleteSettingsProfile (name) {
if (confirm(this.$t('settings.settings_profile_delete_confirm'))) {
this.$store.dispatch('deleteSettingsProfile', name)
}
}
}
}

View file

@ -1,7 +1,6 @@
<template>
<div :label="$t('settings.general')">
<div class="setting-item">
<h2>{{ $t('settings.interface') }}</h2>
<ul class="setting-list">
<li>
<interface-language-switcher
@ -10,6 +9,94 @@
:set-language="val => language = val"
/>
</li>
<li
v-if="user && (settingsProfiles.length > 0)"
>
<h2>{{ $t('settings.settings_profile') }}</h2>
<p>
{{ $t('settings.settings_profile_currently', { name: settingsProfile, version: settingsVersion }) }}
<button
class="btn button-default"
@click="forceSync()"
>
{{ $t('settings.settings_profile_force_sync') }}
</button>
</p>
<div
@click="toggleExpandedSettings"
>
<template
v-if="profilesExpanded"
>
<button class="btn button-default">
{{ $t('settings.settings_profiles_unshow') }}
</button>
</template>
<template
v-else
>
<button class="btn button-default">
{{ $t('settings.settings_profiles_show') }}
</button>
</template>
</div>
<br>
<template
v-if="profilesExpanded"
>
<div
v-for="profile in settingsProfiles"
:key="profile.id"
class="settings-profile"
>
<h4>{{ profile.name }} ({{ profile.version }})</h4>
<template
v-if="settingsProfile === profile.name"
>
{{ $t('settings.settings_profile_in_use') }}
</template>
<template
v-else
>
<button
class="btn button-default"
@click="loadSettingsProfile(profile.name)"
>
{{ $t('settings.settings_profile_use') }}
</button>
<button
class="btn button-default"
@click="deleteSettingsProfile(profile.name)"
>
{{ $t('settings.settings_profile_delete') }}
</button>
</template>
</div>
<button class="btn button-default" @click="refreshProfiles()">
{{ $t('settings.settings_profiles_refresh') }}
<FAIcon icon="sync" @click="refreshProfiles()" />
</button>
<h3>{{ $t('settings.settings_profile_creation') }}</h3>
<label for="settings-profile-new-name">
{{ $t('settings.settings_profile_creation_new_name_label') }}
</label>
<input v-model="newProfileName" id="settings-profile-new-name">
<button
class="btn button-default"
@click="createSettingsProfile"
>
{{ $t('settings.settings_profile_creation_submit') }}
</button>
</template>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.interface') }}</h2>
<ul class="setting-list">
<li v-if="instanceSpecificPanelPresent">
<BooleanSetting path="hideISP">
{{ $t('settings.hide_isp') }}
@ -463,7 +550,6 @@
</BooleanSetting>
</li>
<li>
<!-- <BooleanSetting path="serverSide_defaultNSFW"> -->
<BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
</BooleanSetting>
@ -546,3 +632,13 @@
</template>
<script src="./general_tab.js"></script>
<style lang="scss">
.settings-profile {
margin-bottom: 1em;
}
#settings-profile-new-name {
margin-left: 1em;
margin-right: 1em;
}
</style>

View file

@ -83,7 +83,7 @@ const StatusContent = {
return this.status.attachments.map(file => fileType.fileType(file.mimetype))
},
translationLanguages () {
return (this.$store.getters.mergedConfig.supportedTranslationLanguages.source || []).map(lang => ({ key: lang.code, value: lang.code, label: lang.name }))
return (this.$store.state.instance.supportedTranslationLanguages.source || []).map(lang => ({ key: lang.code, value: lang.code, label: lang.name }))
},
...mapGetters(['mergedConfig'])
},

View file

@ -60,7 +60,7 @@
v-if="status.translation"
class="translation"
>
<h4>{{ $t('status.translated_from', { language: status.translation.detected_language }) }}</h4>
<h4>{{ $t(`languages.translated_from.${status.translation.detected_language.toLowerCase()}`) }}</h4>
<RichContent
:class="{ '-single-line': singleLine }"
class="text media-body"
@ -85,7 +85,7 @@
:key="language.key"
:value="language.value"
>
{{ language.label }}
{{ $t(`languages.${language.value.toLowerCase()}`) }}
</option>
</Select>
{{ ' ' }}

View file

@ -11,12 +11,13 @@ const StillImage = {
],
data () {
return {
stopGifs: this.$store.getters.mergedConfig.stopGifs
stopGifs: this.$store.getters.mergedConfig.stopGifs,
isAnimated: false
}
},
computed: {
animated () {
return this.stopGifs && (this.mimetype === 'image/gif' || this.src.endsWith('.gif'))
return this.stopGifs && this.isAnimated
},
style () {
const appendPx = (str) => /\d$/.test(str) ? str + 'px' : str
@ -31,17 +32,89 @@ const StillImage = {
const image = this.$refs.src
if (!image) return
this.imageLoadHandler && this.imageLoadHandler(image)
this.detectAnimation(image)
this.drawThumbnail()
},
onError () {
this.imageLoadError && this.imageLoadError()
},
detectAnimation (image) {
if (this.mimetype === 'image/gif' || this.src.endsWith('.gif')) {
this.isAnimated = true
return
}
// harmless CORS errors without-- clean console with
if (!this.$store.state.instance.mediaProxyAvailable) return
// Animated JPEGs?
if (!(this.src.endsWith('.webp') || this.src.endsWith('.png'))) return
// Browser Cache should ensure image doesn't get loaded twice if cache exists
fetch(image.src, {
referrerPolicy: 'same-origin'
})
.then(data => {
// We don't need to read the whole file so only call it once
data.body.getReader().read()
.then(reader => {
if (this.src.endsWith('.webp') && this.isAnimatedWEBP(reader.value)) {
this.isAnimated = true
return
}
if (this.src.endsWith('.png') && this.isAnimatedPNG(reader.value)) {
this.isAnimated = true
}
})
})
.catch(() => {
// this.imageLoadError && this.imageLoadError()
})
},
isAnimatedWEBP (data) {
/**
* WEBP HEADER CHUNK
* === START HEADER ===
* 82 73 70 70 ("RIFF")
* xx xx xx xx (SIZE)
* 87 69 66 80 ("WEBP")
* === END OF HEADER ===
* 86 80 56 88 ("VP8X") Extended VP8X
* xx xx xx xx (VP8X)
* [++] RSVILEX(A)R (1 byte)
* A Animated bit
*/
// Relevant bytes
const segment = data.slice(4 * 3, (4 * 5) + 1)
// Check for VP8X string
if (segment.join('').includes(['86805688'])) {
// Check for Animation bit
return !!((segment[8] >> 1) & 1)
}
// No VP8X = Not Animated (X is for Extended)
return false
},
isAnimatedPNG (data) {
// Find acTL before IDAT in PNG; if found it is animated
const segment = []
for (let i = 0; i < data.length; i++) {
segment.push(String.fromCharCode(data[i]))
}
const str = segment.join('')
const idatPos = str.indexOf('IDAT')
return (str.substring(0, idatPos > 0 ? idatPos : 0).indexOf('acTL') > 0)
},
drawThumbnail () {
const canvas = this.$refs.canvas
if (!canvas) return
if (!this.$refs.canvas) return
const image = this.$refs.src
const width = image.naturalWidth
const height = image.naturalHeight
canvas.width = width
canvas.height = height
canvas.getContext('2d').drawImage(image, 0, 0, width, height)
},
onError () {
this.imageLoadError && this.imageLoadError()
}
},
updated () {
// On computed animated change
this.drawThumbnail()
}
}

View file

@ -135,7 +135,6 @@
a {
display: block;
padding: 0.6em 0.65em;
padding-bottom: 0;
&:hover {
background-color: $fallback--lightBg;

View file

@ -23,7 +23,8 @@ const TimelineMenuContent = {
...mapState({
currentUser: state => state.users.currentUser,
privateMode: state => state.instance.private,
federating: state => state.instance.federating
federating: state => state.instance.federating,
showBubbleTimeline: state => (state.instance.localBubbleInstances.length > 0)
})
}
}

View file

@ -16,7 +16,7 @@
>{{ $t("nav.home_timeline") }}</span>
</router-link>
</li>
<li v-if="currentUser">
<li v-if="currentUser && showBubbleTimeline">
<router-link
class="menu-item"
:to="{ name: 'bubble-timeline' }"

View file

@ -5,7 +5,7 @@
"keyword": {
"ftl_removal": "Von der Zeitleiste \"Das gesamte bekannte Netzwerk\" entfernen",
"is_replaced_by": "→",
"keyword_policies": "Keyword Richtlinien",
"keyword_policies": "Richtlinien für Schlüsselwörter",
"reject": "Ablehnen",
"replace": "Ersetzen"
},
@ -16,12 +16,15 @@
"accept_desc": "Diese Instanz akzeptiert nur Nachrichten von den folgenden Instanzen:",
"ftl_removal": "Von der Zeitleiste \"Das bekannte Netzwerk\" entfernen",
"ftl_removal_desc": "Dieser Instanz entfernt folgende Instanzen von der \"Das bekannte Netzwerk\" Zeitleiste:",
"instance": "Instanz",
"media_nsfw": "Erzwingen Medien als heikel zu makieren",
"media_nsfw_desc": "Diese Instanz makiert die Medien in Beiträgen der folgenden Instanzen als heikel:",
"media_removal": "Medienentfernung",
"media_removal_desc": "Diese Instanz entfernt Medien von den Beiträgen der folgenden Instanzen:",
"not_applicable": "entfällt",
"quarantine": "Quarantäne",
"quarantine_desc": "Diese Instanz sendet nur öffentliche Beiträge zu den folgenden Instanzen:",
"quarantine_desc": "Diese Instanz sendet keine Beiträge zu den folgenden Instanzen:",
"reason": "Grund",
"reject": "Ablehnen",
"reject_desc": "Diese Instanz akzeptiert keine Nachrichten der folgenden Instanzen:",
"simple_policies": "Instanzspezifische Richtlinien"
@ -29,6 +32,27 @@
},
"staff": "Mitarbeiter"
},
"announcements": {
"all_day_prompt": "Dies ist ein Ganztagsereignis",
"cancel_edit_action": "Abbrechen",
"close_error": "Schließen",
"delete_action": "Löschen",
"edit_action": "Bearbeiten",
"end_time_display": "Endet um {time}",
"end_time_prompt": "Ende: ",
"inactive_message": "Diese Ankündigung ist inaktiv",
"mark_as_read_action": "Als gelesen markieren",
"page_header": "Ankündigungen",
"post_action": "Veröffentlichen",
"post_error": "Fehler: {error}",
"post_form_header": "Ankündigung veröffentlichen",
"post_placeholder": "Inhalt der Ankündigung",
"published_time_display": "Veröffentlicht um {time}",
"start_time_display": "Startet um {time}",
"start_time_prompt": "Start: ",
"submit_edit_action": "Absenden",
"title": "Ankündigung"
},
"chats": {
"chats": "Chats",
"delete": "Löschen",
@ -109,6 +133,13 @@
"admin": "Admin",
"moderator": "Moderator"
},
"scope_in_timeline": {
"direct": "Direkt",
"local": "Lokal - nur deine eigene Instanz kann diesen Beitrag sehen",
"private": "Nur an Folgende",
"public": "Öffentlich",
"unlisted": "Nicht gelistet"
},
"show_less": "Zeige weniger",
"show_more": "Zeige mehr",
"submit": "Absenden",
@ -131,6 +162,84 @@
"load_older": "Lade ältere Interaktionen",
"moves": "Benutzer migriert zu"
},
"languages": {
"ar": "Arabisch",
"az": "Aserbaidschanisch",
"bg": "Bulgarisch",
"cs": "Tschechisch",
"da": "Dänisch",
"de": "Deutsch",
"el": "Griechisch",
"en": "Englisch",
"eo": "Esperanto",
"es": "Spanisch",
"fa": "Persisch",
"fi": "Finnisch",
"fr": "Französisch",
"ga": "Irisch",
"he": "Hebräisch",
"hi": "Hindi",
"hu": "Ungarisch",
"id": "Indonesisch",
"it": "Italienisch",
"ja": "Japanisch",
"ko": "Koreanisch",
"lt": "Litauisch",
"lv": "Lettisch",
"nl": "Niederländisch",
"pl": "Polnisch",
"pt": "Portugiesisch",
"ru": "Russisch",
"sk": "Slowakisch",
"sv": "Schwedisch",
"tr": "Türkisch",
"translated_from": {
"ar": "Übersetzt aus dem Arabischen",
"az": "Übersetzt aus dem Aserbaidschanischen",
"bg": "Übersetzt aus dem Bulgarischen",
"cs": "Übersetzt aus dem Tschechischen",
"da": "Übersetzt aus dem Dänischen",
"de": "Übersetzt aus dem Deutschen",
"el": "Übersetzt aus dem Griechischen",
"en": "Übersetzt aus dem Englischen",
"eo": "Übersetzt von @:languages.eo",
"es": "Übersetzt aus dem Spanischen",
"fa": "Übersetzt aus dem Persischen",
"fi": "Übersetzt aus dem Finnischen",
"fr": "Übersetzt aus dem Französischen",
"ga": "Übersetzt aus dem Irischen",
"he": "Übersetzt aus dem Hebräischen",
"hi": "Übersetzt von @:languages.hi",
"hu": "Übersetzt aus dem Ungarischen",
"id": "Übersetzt aus dem Indonesischen",
"it": "Übersetzt aus dem Italienischen",
"ja": "Übersetzt aus dem Japanischen",
"ko": "Übersetzt aus dem Koreanischen",
"lt": "Übersetzt aus dem Litauischen",
"lv": "Übersetzt aus dem Lettischen",
"nl": "Übersetzt aus dem Niederländischen",
"pl": "Übersetzt aus dem Polnischen",
"pt": "Übersetzt aus dem Portugiesischen",
"ru": "Übersetzt aus dem Russischen",
"sk": "Übersetzt aus dem Slowakischen",
"sv": "Übersetzt aus dem Schwedischen",
"tr": "Übersetzt aus dem Türkischen",
"uk": "Übersetzt aus dem Ukrainischen",
"zh": "Übersetzt aus dem Chinesischen"
},
"uk": "Ukrainisch",
"zh": "Chinesisch"
},
"lists": {
"create": "Erstellen",
"delete": "Liste löschen",
"following_only": "Auf Folgende begrenzen",
"lists": "Listen",
"new": "Neue Liste",
"save": "Änderungen speichern",
"search": "Benutzer suchen",
"title": "Listen-Titel"
},
"login": {
"authentication_code": "Authentifizierungscode",
"description": "Mit OAuth anmelden",
@ -144,38 +253,45 @@
"login": "Anmelden",
"logout": "Abmelden",
"password": "Passwort",
"placeholder": "z.B. lain",
"placeholder": "meinbenutzername",
"recovery_code": "Wiederherstellungscode",
"register": "Registrieren",
"username": "Benutzername"
},
"media_modal": {
"counter": "{current} / {total}",
"hide": "Medienansicht schließen",
"next": "Weiter",
"previous": "Zurück"
},
"nav": {
"about": "Über",
"administration": "Administration",
"announcements": "Ankündigungen",
"back": "Zurück",
"bookmarks": "Lesezeichen",
"chats": "Chats",
"dms": "Direktnachrichten",
"friend_requests": "Followanfragen",
"home_timeline": "Heim Zeitlinie",
"home_timeline": "Heimzeitleiste",
"home_timeline_description": "Beiträge von Leuten, denen du folgst",
"interactions": "Interaktionen",
"lists": "Listen",
"mentions": "Erwähnungen",
"preferences": "Voreinstellungen",
"public_timeline_description": "Öffentliche Beiträge von dieser Instanz",
"public_tl": "Öffentliche Zeitleiste",
"search": "Suche",
"timeline": "Zeitleiste",
"timelines": "Zeitlinie",
"twkn": "Bekannte Netzwerk",
"twkn": "Bekanntes Netzwerk",
"twkn_timeline_description": "Beiträge aus dem gesamten bekannten Netzwerk",
"user_search": "Benutzersuche",
"who_to_follow": "Wem folgen"
},
"notifications": {
"broken_favorite": "Unbekannte Nachricht, suche danach…",
"error": "Error beim laden von Neuigkeiten",
"error": "Fehler beim Laden neuer Benachrichtigungen: {0}",
"favorited_you": "favorisierte deine Nachricht",
"follow_request": "möchte dir folgen",
"followed_you": "folgt dir",
@ -183,6 +299,7 @@
"migrated_to": "migrierte zu",
"no_more_notifications": "Keine Benachrichtigungen mehr",
"notifications": "Benachrichtigungen",
"poll_ended": "Umfrage wurde beendet",
"reacted_with": "reagierte mit {0}",
"read": "Gelesen!",
"repeated_you": "wiederholte deine Nachricht"
@ -223,27 +340,34 @@
"text/bbcode": "BBCode",
"text/html": "HTML",
"text/markdown": "Markdown",
"text/plain": "Nur Text"
"text/plain": "Nur Text",
"text/x.misskeymarkdown": "MFM"
},
"content_warning": "Betreff (optional)",
"default": "Sitze gerade im Hofbräuhaus.",
"content_warning": "Inhaltswarnung (optional)",
"default": "Sitze gerade im Hofbräuhaus",
"direct_warning_to_all": "Dieser Beitrag wird für alle erwähnten Benutzer sichtbar sein.",
"direct_warning_to_first_only": "Dieser Beitrag wird für alle Benutzer, die am Anfang der Nachricht erwähnt wurden, sichtbar sein.",
"empty_status_error": "Eine leere Nachricht ohne Anhänge kann nicht gesendet werden",
"edit_remote_warning": "Änderungen könnten auf manchen Instanzen nicht sichtbar sein!",
"edit_status": "Beitrag ändern",
"edit_unsupported_warning": "Umfragen und Erwähnungen werden durch die Bearbeitung nicht geändert.",
"empty_status_error": "Eine Nachricht ohne Text und ohne Anhänge kann nicht gesendet werden",
"media_description": "Medienbeschreibung",
"media_description_error": "Medien konnten nicht neu geladen werden, versuche es erneut",
"new_status": "Neuen Status veröffentlichen",
"media_not_sensitive_warning": "Es wurde eine Inhaltswarnung eingestellt, aber die Anhänge sind nicht als heikel gekennzeichnet!",
"new_status": "Neuer Post",
"post": "Post",
"posting": "Veröffentlichen",
"preview": "Vorschau",
"preview_empty": "Leer",
"scope": {
"direct": "Direkt - Beitrag nur an erwähnte Profile",
"local": "Lokal - diesen Beitrag nicht föderieren",
"private": "Nur Follower - Beitrag nur für Follower sichtbar",
"public": "Öffentlich - Beitrag an öffentliche Zeitleisten",
"unlisted": "Nicht gelistet - Nicht in öffentlichen Zeitleisten anzeigen"
},
"scope_notice": {
"local": "Dieser Bericht ist auf anderen Instanzen nicht sichbar",
"private": "Dieser Beitrag wird nur für deine Follower sichtbar sein",
"public": "Dieser Beitrag wird für alle sichtbar sein",
"unlisted": "Dieser Beitrag wird weder in der öffentlichen Zeitleiste noch im gesamten bekannten Netzwerk sichtbar sein"
@ -251,11 +375,12 @@
},
"registration": {
"bio": "Bio",
"bio_placeholder": "z.B.\nHallo, ich bin Lain.\nIch bin ein super süßes blushy-crushy Anime Girl aus dem vorstädtischen Japan. Du kennst mich vielleicht von Wired.",
"bio_placeholder": "z. B.\nHallo! Willkommen auf meinem Profil.\nIch mag Anime und Spiele. Hoffentlich können wir Freunde sein!",
"captcha": "CAPTCHA",
"email": "Email",
"email_language": "In welcher Sprache möchtest du E-Mails vom Server erhalten?",
"fullname": "Angezeigter Name",
"fullname_placeholder": "z.B. Lain Iwakura",
"fullname_placeholder": "z. B. Atsuko Kagari",
"new_captcha": "Zum Erstellen eines neuen Captcha auf das Bild klicken",
"password_confirm": "Passwort bestätigen",
"reason": "Grund zur Anmeldung",
@ -263,7 +388,7 @@
"register": "Registrierung",
"registration": "Registrierung",
"token": "Einladungsschlüssel",
"username_placeholder": "z.B. lain",
"username_placeholder": "z. B. akko",
"validations": {
"email_required": "darf nicht leer sein",
"fullname_required": "darf nicht leer sein",
@ -290,7 +415,19 @@
},
"settings": {
"accent": "Akzent",
"account_alias": "Account-Pseudonyme",
"account_alias_table_head": "Pseudonym",
"account_backup": "Sicherungskopie des Accounts",
"account_backup_description": "Dies ermöglicht es, ein Archiv aller Informationen und Beiträge des Accounts herunterzuladen, aber dieses Archiv kann nicht in einen Pleroma-Account importiert werden.",
"account_backup_table_head": "Sicherungskopie",
"account_privacy": "Privatsphäre",
"add_alias_error": "Fehler beim Hinzufügen eines Pseudonyms: {error}",
"add_backup": "Neue Sicherungskopie erstellen",
"add_backup_error": "Fehler beim Erstellen der Sicherungskopie: {error}",
"added_alias": "Pseudonym hinzugefügt.",
"added_backup": "Sicherungskopie hinzugefügt.",
"allow_following_move": "Erlaube auto-follow, wenn von dir verfolgte Accounts umziehen",
"always_show_post_button": "Immer einen schwebenden Knopf zum Erstellen neuer Beiträge anzeigen",
"app_name": "Anwendungsname",
"attachmentRadius": "Anhänge",
"attachments": "Anhänge",
@ -300,6 +437,7 @@
"avatarRadius": "Avatare",
"avatar_size_instruction": "Die empfohlene minimale Größe für Avatare ist 150x150 Pixel.",
"background": "Hintergrund",
"backup_not_ready": "Diese Sicherungskopie ist noch nicht fertig.",
"bio": "Bio",
"block_export": "Block Export",
"block_export_button": "Exportiere deine Blocks in eine csv Datei",
@ -321,10 +459,27 @@
"changed_password": "Passwort erfolgreich geändert!",
"chatMessageRadius": "Chat Nachricht",
"checkboxRadius": "Auswahlfelder",
"collapse_subject": "Beiträge mit Betreff einklappen",
"collapse_subject": "Beiträge mit Inhaltswarnungen einklappen",
"columns": "Spalten",
"composing": "Verfassen",
"confirm_dialogs": "Bestätigung erforderlich für:",
"confirm_dialogs_approve_follow": "Annehmen einer Followanfrage",
"confirm_dialogs_block": "Jemanden blockieren",
"confirm_dialogs_delete": "Löschen eines Beitrages",
"confirm_dialogs_deny_follow": "Ablehnen einer Followanfrage",
"confirm_dialogs_mute": "Jemanden stummschalten",
"confirm_dialogs_repeat": "Wiederholen eines Beitrages",
"confirm_dialogs_unfollow": "Folgen beenden",
"confirm_new_password": "Neues Passwort bestätigen",
"confirmation_dialogs": "Bestätigungs-Einstellungen",
"conversation_display": "Anzeige wie ein Gespräch",
"conversation_display_linear": "lineare Anzeige",
"conversation_display_tree": "hierarchische Anzeige",
"conversation_other_replies_button": "Zeige den \"andere Antworten\"-Knopf",
"conversation_other_replies_button_below": "Unter Beiträgen",
"conversation_other_replies_button_inside": "Innerhalb von Beiträgen",
"current_avatar": "Dein derzeitiger Avatar",
"current_mascot": "Das ausgewählte Maskottchen",
"current_password": "Aktuelles Passwort",
"data_import_export_tab": "Datenimport/-export",
"default_vis": "Standard-Sichtbarkeitsumfang",
@ -332,11 +487,15 @@
"delete_account_description": "Lösche deine Daten und deaktiviere deinen Account unwiderruflich.",
"delete_account_error": "Es ist ein Fehler beim Löschen deines Accounts aufgetreten. Tritt dies weiterhin auf, wende dich an den Administrator der Instanz.",
"delete_account_instructions": "Tippe dein Passwort unten in das Feld ein, um die Löschung deines Accounts zu bestätigen.",
"disable_sticky_headers": "Spaltenüberschriften nicht am Bildschirmrand anheften",
"discoverable": "Erlaube, dass dieser Account in Suchergebnissen auftaucht",
"domain_mutes": "Domains",
"download_backup": "Herunterladen",
"email_language": "Sprache für E-Mails des Servers",
"emoji_reactions_on_timeline": "Zeige Emoji-Reaktionen auf der Zeitleiste",
"enable_web_push_notifications": "Web-Pushbenachrichtigungen aktivieren",
"enter_current_password_to_confirm": "Gib dein aktuelles Passwort ein, um deine Identität zu bestätigen",
"expert_mode": "Erweiterte Einstellungen anzeigen",
"export_theme": "Farbschema speichern",
"file_export_import": {
"backup_restore": "Einstellungen backuppen",
@ -344,8 +503,8 @@
"backup_settings_theme": "Einstellungen und Theme in eine Datei speichern",
"errors": {
"file_slightly_new": "Geringfügige Abweichung in der Dateiversion, einige Einstellungen konnten möglicherweise nicht geladen werden",
"file_too_new": "Inkompatible Major Version: {fileMajor}, dieses PleromaFE Version (settings ver {feMajor}) ist zu alt",
"file_too_old": "Inkompatible Major Version: {fileMajor}, die Dateiversion ist zu alt und wird nicht mehr unterstützt (min. set. ver. {feMajor})",
"file_too_new": "Inkompatible Major-Version: {fileMajor}, diese PleromaFE-Version (Einstellungs-Version {feMajor}) ist zu alt",
"file_too_old": "Inkompatible Major-Version: {fileMajor}, die Dateiversion ist zu alt und wird nicht mehr unterstützt (mind. Version {feMajor})",
"invalid_file": "Die ausgewählte Datei kann nicht zur Wiederherstellung verwendet werden. Keine Änderungen wurden umgesetzt."
},
"restore_settings": "Einstellungen von einer Datei wiederherstellen"
@ -364,18 +523,26 @@
"hide_all_muted_posts": "Verstecke stummgeschaltete Posts",
"hide_attachments_in_convo": "Anhänge in Unterhaltungen ausblenden",
"hide_attachments_in_tl": "Anhänge in der Zeitleiste ausblenden",
"hide_bot_indication": "Bot-Hinweis in Beiträgen ausblenden",
"hide_favorites_description": "Favoriten-Liste verbergen (andere erhalten trotzdem Benachrichtigungen)",
"hide_filtered_statuses": "Gefilterte Beiträge verbergen",
"hide_followers_count_description": "Verberge die Anzahl deiner Folgenden",
"hide_followers_description": "Zeige nicht, wer mir folgt",
"hide_follows_count_description": "Verberge die Anzahl deiner Gefolgten",
"hide_follows_description": "Zeige nicht, wem ich folge",
"hide_isp": "Instanz-spezifisches Panel ausblenden",
"hide_list_aliases_error_action": "Schließen",
"hide_media_previews": "Verstecke Vorschau von Medien",
"hide_muted_posts": "Verberge Beiträge stummgeschalteter Nutzer",
"hide_muted_threads": "Stummgeschaltete Unterhaltungen ausblenden",
"hide_post_stats": "Beitragsstatistiken verbergen (z.B. die Anzahl der Favoriten)",
"hide_shoutbox": "Shoutbox der Instanz verbergen",
"hide_site_favicon": "Favicon der Instanz im Top-Panel nicht anzeigen",
"hide_site_name": "Instanznamen im Top-Panel nicht anzeigen",
"hide_threads_with_blocked_users": "Unterhaltungen, die blockierte Benutzer erwähnen, stummschalten",
"hide_user_stats": "Benutzerstatistiken verbergen (z.B. die Anzahl der Follower)",
"hide_wallpaper": "Verstecke Instanzhintergrundbild",
"hide_wordfiltered_statuses": "Beiträge, die durch den Wortfilter erkannt wurden, ausblenden",
"import_blocks_from_a_csv_file": "Importiere Blocks von einer CSV Datei",
"import_followers_from_a_csv_file": "Importiere Follower aus einer CSV-Datei",
"import_mutes_from_a_csv_file": "Importiere stummgeschaltete User von einer cvs Datei",
@ -388,10 +555,23 @@
"invalid_theme_imported": "Die ausgewählte Datei ist kein unterstütztes Pleroma-Theme. Keine Änderungen wurden vorgenommen.",
"limited_availability": "In deinem Browser nicht verfügbar",
"links": "Links",
"list_aliases_error": "Fehler beim Abrufen von Pseudonymen: {error}",
"list_backups_error": "Fehler beim Abrufen von Sicherungskopien: {error}",
"lock_account_description": "Sperre deinen Account, um neue Follower zu genehmigen oder abzulehnen",
"loop_video": "Videos wiederholen",
"loop_video_silent_only": "Nur Videos ohne Ton wiederholen (z.B. Mastodons \"gifs\")",
"mascot": "Mastodon-FE-Maskottchen",
"max_depth_in_thread": "Maximale Tiefe, bis zu der Unterhaltungen standardmäßig angezeigt werden",
"max_thumbnails": "Maximale Anzahl von Vorschaubildern pro Beitrag",
"mention_link_bolden_you": "eigene Erwähnungen hervorheben",
"mention_link_display": "Erwähungs-Links anzeigen",
"mention_link_display_full": "immer als vollständige Namen (z. B. {'@'}foo{'@'}example.org)",
"mention_link_display_full_for_remote": "vollständige Namen nur für Nutzer anderer Instanzen (z. B. {'@'}foo{'@'}example.org)",
"mention_link_display_short": "immer kurze Namen (z. B. {'@'}foo)",
"mention_link_fade_domain": "Domain schwächer anzeigen (z. B. das {'@'}example.org in {'@'}foo{'@'}example.org)",
"mention_link_show_avatar": "Benutzer-Avatar neben Link anzeigen",
"mention_link_show_tooltip": "Vollständigen Benutzernamen als Tooltip für Benutzer anderer Instanzen anzeigen",
"mention_links": "Erwähnungs-Links",
"mfa": {
"authentication_methods": "Authentifizierungsmethoden",
"confirm_and_enable": "Bestätige und aktiviere OTP",
@ -415,6 +595,12 @@
},
"minimal_scopes_mode": "Minimiere Reichweitenoptionen",
"more_settings": "Weitere Einstellungen",
"move_account": "Account umziehen",
"move_account_error": "Fehler beim Umzug: {error}",
"move_account_notes": "Wenn der Account woanders hin umgezogen werden soll, muss dieser Account erst als ein Pseudonym des anderen Accounts eingestellt werden.",
"move_account_target": "Ziel-Account (z. B. {example})",
"moved_account": "Account umgezogen.",
"mute_bot_posts": "Bot-Beiträge stummschalten",
"mute_export": "Stumm geschaltete User exportieren",
"mute_export_button": "Stumm geschaltete User in eine cvs Datei exportieren",
"mute_import": "Stumm geschaltete User importieren",
@ -424,6 +610,7 @@
"mutes_tab": "Stummschaltungen",
"name": "Name",
"name_bio": "Name & Bio",
"new_alias_target": "Neues Pseudonym hinzufügen (z. B. {example})",
"new_email": "Neue Email",
"new_password": "Neues Passwort",
"no_blocks": "Keine Blocks",
@ -433,6 +620,7 @@
"notification_mutes": "Um nicht mehr die Benachrichtigungen von einem bestimmten User zu bekommen, verwende eine Stummschaltung.",
"notification_setting_block_from_strangers": "Benachrichtigungen von Nutzern blockieren, denen Du nicht folgst",
"notification_setting_filters": "Filter",
"notification_setting_hide_if_cw": "Inhalt von Push-Nachrichten verbergen, wenn eine Inhaltswarnung besteht",
"notification_setting_hide_notification_contents": "Absender und Inhalte von Push-Nachrichten verbergen",
"notification_setting_privacy": "Privatsphäre",
"notification_visibility": "Benachrichtigungstypen, die angezeigt werden sollen",
@ -441,6 +629,7 @@
"notification_visibility_likes": "Favoriten",
"notification_visibility_mentions": "Erwähnungen",
"notification_visibility_moves": "Nutzer zieht um",
"notification_visibility_polls": "Abschluss von Umfragen, in denen du abgestimmt hast",
"notification_visibility_repeats": "Wiederholungen",
"notifications": "Benachrichtigungen",
"nsfw_clickthrough": "Aktiviere ausblendbares Overlay für Anhänge, die als NSFW markiert sind",
@ -449,7 +638,8 @@
"panelRadius": "Panel",
"pause_on_unfocused": "Streaming pausieren, wenn das Tab nicht fokussiert ist",
"play_videos_in_modal": "Videos in größerem Medienfenster abspielen",
"post_status_content_type": "Beitragsart",
"post_status_content_type": "Standard-Beitragsart",
"posts": "Beiträge",
"preload_images": "Bilder vorausladen",
"presets": "Voreinstellungen",
"profile_background": "Profilhintergrund",
@ -463,6 +653,10 @@
"profile_tab": "Profil",
"radii_help": "Kantenrundung (in Pixel) der Oberfläche anpassen",
"refresh_token": "Token aktualisieren",
"remove_alias": "Dieses Pseudonym entfernen",
"remove_backup": "Entfernen",
"render_mfm": "Misskey-Markdown darstellen",
"render_mfm_on_hover": "MFM-Animationen pausieren, solange sich der Mauszeiger nicht über dem Beitrag befindet",
"replies_in_timeline": "Antworten in der Zeitleiste",
"reply_visibility_all": "Alle Antworten zeigen",
"reply_visibility_following": "Zeige nur Antworten an mich oder an Benutzer, denen ich folge",
@ -486,13 +680,21 @@
"security": "Sicherheit",
"security_tab": "Sicherheit",
"sensitive_by_default": "Alle Beiträge standardmäßig als heikel markieren",
"sensitive_if_subject": "Bilder automatisch als heikel markieren, wenn der Beitrag eine Inhaltswarnung hat",
"set_new_avatar": "Setze einen neuen Avatar",
"set_new_mascot": "Neues Maskottchen einstellen",
"set_new_profile_background": "Setze einen neuen Hintergrund für dein Profil",
"set_new_profile_banner": "Setze einen neuen Banner für dein Profil",
"setting_changed": "Einstellungen weichen von den Standardeinstellungen ab",
"setting_server_side": "Diese Einstellung hängt an deinem Profil und gilt für alle Sitzungen und Clients",
"settings": "Einstellungen",
"show_admin_badge": "Zeige Admin-Abzeichen auf meinem Profil",
"show_moderator_badge": "Zeige Moderator-Abzeichen auf meinem Profil",
"show_nav_shortcuts": "Zusätzliche Schnellnavigation im Top-Panel anzeigen",
"show_panel_nav_shortcuts": "Zeitleisten-Schnellnavigation im Panel oben anzeigen",
"show_scrollbars": "Scrollbalken der Seitenspalte anzeigen",
"show_wider_shortcuts": "Mehr Platz zwischen Schnellnagivationen im Top-Panel anzeigen",
"show_yous": "(Du)'s anzeigen",
"stop_gifs": "Animationen nur beim Darüberfahren abspielen",
"streaming": "Aktiviere automatisches Laden (Streaming) von neuen Beiträgen",
"style": {
@ -574,7 +776,7 @@
"fine_print": "Lies unser {0}, um nichts Nützliches zu lernen!",
"header": "Vorschau",
"header_faint": "Das ist in Ordnung",
"input": "Sitze gerade im Hofbräuhaus.",
"input": "Sitze gerade im Hofbräuhaus",
"link": "ein netter kleiner Link",
"mono": "Inhalt",
"text": "Ein Haufen mehr von {0} und {1}"
@ -641,9 +843,9 @@
"use_source": "Neue Version"
}
},
"subject_input_always_show": "Betreff-Feld immer anzeigen",
"subject_line_behavior": "Betreff beim Antworten kopieren",
"subject_line_email": "Wie Email: \"re: Betreff\"",
"subject_input_always_show": "Feld für Inhaltswarnung immer anzeigen",
"subject_line_behavior": "Inhaltswarnung beim Antworten kopieren",
"subject_line_email": "Wie E-Mail: \"re: Inhaltswarnung\"",
"subject_line_mastodon": "Wie Mastodon: unverändert kopieren",
"subject_line_noop": "Nicht kopieren",
"text": "Text",
@ -651,15 +853,25 @@
"theme_help": "Benutze HTML-Farbcodes (#rrggbb) um dein Farbschema anzupassen.",
"theme_help_v2_1": "Du kannst auch die Farben und die Deckkraft bestimmter Komponenten überschreiben, indem du das Kontrollkästchen umschaltest. Verwende die Schaltfläche \"Alle löschen\", um alle Überschreibungen zurückzusetzen.",
"theme_help_v2_2": "Unter einigen Einträgen befinden sich Symbole für Hintergrund-/Textkontrastindikatoren, für detaillierte Informationen fahre mit der Maus darüber. Bitte beachte, dass bei der Verwendung von Transparenz Kontrastindikatoren den schlechtest möglichen Fall darstellen.",
"third_column_mode": "Wenn genug Platz ist, dritte Spalte anzeigen mit",
"third_column_mode_none": "Dritte Spalte nicht anzeigen",
"third_column_mode_notifications": "Benachrichtigungs-Spalte",
"third_column_mode_postform": "Eingabe für Beiträge und Navigation",
"token": "Zeichen",
"tooltipRadius": "Tooltips/Warnungen",
"translation_language": "Sprache für automatische Übersetzungen",
"tree_advanced": "Weitere Knöpfe zum Öffnen und Schließen von Antworten anzeigen",
"tree_fade_ancestors": "Vorgänger des aktuellen Beitrags schwach darstellen",
"type_domains_to_mute": "Tippe die Domains ein, die du stummschalten willst",
"upload_a_photo": "Lade ein Foto hoch",
"useStreamingApi": "Empfange Posts und Benachrichtigungen in Echtzeit",
"useStreamingApiWarning": "(Nicht empfohlen, experimentell, bekannt dafür, Posts zu überspringen)",
"use_at_icon": "{'@'}-Symbol als Icon und nicht als Text anzeigen",
"use_contain_fit": "Vorschaubilder nicht zuschneiden",
"use_one_click_nsfw": "Heikle Anhänge mit nur einem Klick öffnen",
"user_mutes": "User",
"user_profile_default_tab": "Standard-Tab des Benutzerprofils",
"user_profiles": "Benutzerprofil",
"user_settings": "Benutzereinstellungen",
"valid_until": "Gültig bis",
"values": {
@ -671,35 +883,75 @@
"frontend_version": "Frontend Version",
"title": "Version"
},
"virtual_scrolling": "Rendering der Timeline optimieren",
"word_filter": "Wort Filter"
"virtual_scrolling": "Anzeige der Zeitleiste optimieren",
"word_filter": "Wortfilter",
"wordfilter": "Wortfilter"
},
"status": {
"ancestor_follow": "Zeige {numReplies} andere Antwort unter diesem Beitrag | Zeige {numReplies} andere Antworten unter diesem Beitrag",
"ancestor_follow_with_icon": "{icon} {text}",
"attachment_stop_flash": "Flash-Player stoppen",
"bookmark": "Lesezeichen setzen",
"collapse_attachments": "Anhänge einklappen",
"copy_link": "Beitragslink kopieren",
"delete": "Lösche Beitrag",
"delete_confirm": "Möchtest du diese Beitrag wirklich löschen?",
"delete_confirm_accept_button": "Ja, löschen",
"delete_confirm_cancel_button": "Nein, behalten",
"delete_confirm_title": "Löschen bestätigen",
"edit": "Bearbeiten",
"edit_history": "Bearbeitungsverlauf",
"edit_history_modal_title": "{historyCount} Mal bearbeitet | {historyCount} Mal bearbeitet",
"edited_at": "Bearbeitet um {time}",
"expand": "Ausklappen",
"external_source": "Externe Quelle",
"favorites": "Favoriten",
"hide_attachment": "Anhänge verbergen",
"hide_content": "Inhalt verbergen",
"hide_full_subject": "Vollständiges Thema verbergen",
"hide_full_subject": "Vollständige Inhaltswarnung verbergen",
"many_attachments": "Beitrag hat {number} Anhang | Beitrag hat {number} Anhänge",
"mentions": "Erwähnungen",
"move_down": "Anhang nach rechts verschieben",
"move_up": "Anhang nach links verschieben",
"mute_conversation": "Konversation stummstellen",
"nsfw": "NSFW",
"open_gallery": "Galerie öffnen",
"override_translation_source_language": "Ursprungsspache überschreiben",
"pin": "An Profil anheften",
"pinned": "Angeheftet",
"plus_more": "+{number} mehr",
"remove_attachment": "Anhang entfernen",
"repeat_confirm": "Beitrag wirklich wiederholen?",
"repeat_confirm_accept_button": "Ja, wiederholen",
"repeat_confirm_cancel_button": "Nein, nicht wiederholen",
"repeat_confirm_title": "Wiederholen bestätigen",
"repeats": "Geteilte Beiträge",
"replies_list": "Antworten:",
"replies_list_with_others": "Zeige noch {numReplies} Antwort | Zeige noch {numReplies} Antworten",
"reply_to": "Antworten auf",
"show_all_attachments": "Alle Anhänge anzeigen",
"show_all_conversation": "Ganzes Gespräch anzeigen (noch {numStatus} Beitrag) | Ganzes Gespräch anzeigen (noch {numStatus} Beiträge)",
"show_all_conversation_with_icon": "{icon} {text}",
"show_attachment_description": "Vorschau-Beschreibung (Anhang öffnen für vollständige Beschreibung)",
"show_attachment_in_modal": "Anhang in einem Fenster anzeigen",
"show_content": "Inhalt anzeigen",
"show_full_subject": "Vollständiges Thema anzeigen",
"show_full_subject": "Vollständige Inhaltswarnung anzeigen",
"show_only_conversation_under_this": "Nur Antworten auf diesen Bericht anzeigen",
"status_deleted": "Dieser Beitrag wurde gelöscht",
"status_unavailable": "Beitrag nicht verfügbar",
"thread_muted": "Thread stummgeschaltet",
"thread_follow": "Zeige noch {numStatus} Antwort | Zeige noch {numStatus} Antworten",
"thread_follow_with_icon": "{icon} {text}",
"thread_hide": "Diese Unterhaltung stummschalten",
"thread_muted": "Unterhaltung stummgeschaltet",
"thread_muted_and_words": ", enthält folgende Wörter:",
"thread_show": "Diese Unterhaltung anzeigen",
"thread_show_full": "Zeige {numStatus} Antwort | Zeige {numStatus} Antworten",
"thread_show_full_with_icon": "{icon} {text}",
"translate": "Übersetzen",
"unbookmark": "Lesezeichen entfernen",
"unmute_conversation": "Konversation nicht mehr stummstellen",
"unpin": "Nicht mehr an Profil anheften"
"unpin": "Nicht mehr an Profil anheften",
"you": "(Du)"
},
"time": {
"in_future": "in {0}",
@ -729,7 +981,7 @@
"error": "Fehler beim Lesen der Timeline: {0}",
"load_older": "Lade ältere Beiträge",
"no_more_statuses": "Keine weiteren Beiträge",
"no_retweet_hint": "Der Beitrag ist als nur-für-Follower oder als Direktnachricht markiert und kann nicht wiederholt werden",
"no_retweet_hint": "Der Beitrag ist als nur-für-Follower oder Direktnachricht markiert und kann nicht wiederholt oder zitiert werden",
"no_statuses": "Keine Beiträge",
"reload": "Neu laden",
"repeated": "wiederholte",
@ -744,6 +996,7 @@
"bookmark": "Lesezeichen",
"favorite": "Favorisieren",
"media_upload": "Medien hochladen",
"quote": "Zitieren",
"reject_follow_request": "Folgeanfrage ablehnen",
"repeat": "Wiederholen",
"reply": "Antworten",
@ -770,6 +1023,7 @@
"deactivate_account": "Konto deaktivieren",
"delete_account": "Konto löschen",
"delete_user": "Nutzer löschen",
"delete_user_data_and_deactivate_confirmation": "Dies löscht unwiderruflich alle Daten dieses Accounts und deaktiviert ihn. Bist du ganz sicher?",
"disable_any_subscription": "Alle Folgeanfragen für diesen Nutzer grundsätzlich ablehnen",
"disable_remote_subscription": "Nutzer anderer Instanzen vom Folgen dieses Nutzers ausschließen",
"force_nsfw": "Alle Beiträge als pervers markieren",
@ -784,13 +1038,29 @@
"strip_media": "Medien von Beiträgen entfernen"
},
"approve": "Genehmigen",
"approve_confirm": "Willst du diesen Benutzer dir wirklich folgen lassen?",
"approve_confirm_accept_button": "Ja, akzeptieren",
"approve_confirm_cancel_button": "Nein, ablehnen",
"approve_confirm_title": "Folgeanfrage bestätigen",
"block": "Blockieren",
"block_confirm": "Willst du {user} wirklich blockieren?",
"block_confirm_accept_button": "Ja, blockieren",
"block_confirm_cancel_button": "Nein, nicht blockieren",
"block_confirm_title": "Benutzer blockieren",
"block_progress": "Blocken…",
"blocked": "Blockiert!",
"bot": "Bot",
"deactivated": "Deaktiviert",
"deny": "Ablehnen",
"deny_confirm": "Willst du die Folgeanfrage dieses Benutzers wirklich ablehnen?",
"deny_confirm_accept_button": "Ja, ablehnen",
"deny_confirm_cancel_button": "Nein, abbrechen",
"deny_confirm_title": "Folgeanfrage ablehnen",
"domain_muted": "Domain nicht mehr blockieren",
"edit_profile": "Profil bearbeiten",
"favorites": "Favoriten",
"follow": "Folgen",
"follow_cancel": "Anfrage ablehnen",
"follow_progress": "Anfragen…",
"follow_sent": "Anfrage gesendet!",
"follow_unfollow": "Folgen beenden",
@ -811,16 +1081,27 @@
"mention": "Erwähnungen",
"message": "Nachricht",
"mute": "Stummschalten",
"mute_confirm": "Willst du {user} wirklich stummschalten?",
"mute_confirm_accept_button": "Ja, stummschalten",
"mute_confirm_cancel_button": "Nein, nicht stummschalten",
"mute_confirm_title": "Benutzer stummschalten",
"mute_domain": "Domain blockieren",
"mute_progress": "Stummschalten erfolgt…",
"muted": "Stummgeschaltet",
"note": "Private Notiz",
"per_day": "pro Tag",
"remote_follow": "Folgen",
"replies": "Mit Antworten",
"report": "Melden",
"show_repeats": "Geteilte Beiträge anzeigen",
"statuses": "Beiträge",
"subscribe": "Folgen",
"unblock": "Entblocken",
"unblock_progress": "Entblocken…",
"unfollow_confirm": "Willst du {user} wirklich nicht mehr folgen?",
"unfollow_confirm_accept_button": "Ja, nicht mehr folgen",
"unfollow_confirm_cancel_button": "Nein, weiter folgen",
"unfollow_confirm_title": "Benutzer nicht mehr folgen",
"unmute": "Stummschalten aufheben",
"unmute_progress": "Aufhebung erfolgt…",
"unsubscribe": "Entfolgen"

View file

@ -164,6 +164,74 @@
"load_older": "Load older interactions",
"moves": "User migrates"
},
"languages": {
"bg": "Bulgarian",
"en": "English",
"ar": "Arabic",
"az": "Azerbaijani",
"zh": "Chinese",
"cs": "Czech",
"da": "Danish",
"nl": "Dutch",
"eo": "Esperanto",
"fi": "Finnish",
"fr": "French",
"de": "German",
"el": "Greek",
"he": "Hebrew",
"hi": "Hindi",
"hu": "Hungarian",
"id": "Indonesian",
"ga": "Irish",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"fa": "Persian",
"pl": "Polish",
"pt": "Portuguese",
"ru": "Russian",
"sk": "Slovak",
"es": "Spanish",
"sv": "Swedish",
"tr": "Turkish",
"uk": "Ukrainian",
"lt": "Lithuanian",
"lv": "Latvian",
"translated_from": {
"bg": "Translated from @:languages.bg",
"en": "Translated from @:languages.en",
"ar": "Translated from @:languages.ar",
"az": "Translated from @:languages.az",
"zh": "Translated from @:languages.zh",
"cs": "Translated from @:languages.cs",
"da": "Translated from @:languages.da",
"nl": "Translated from @:languages.nl",
"eo": "Translated from @:languages.eo",
"fi": "Translated from @:languages.fi",
"fr": "Translated from @:languages.fr",
"de": "Translated from @:languages.de",
"el": "Translated from @:languages.el",
"he": "Translated from @:languages.he",
"hi": "Translated from @:languages.hi",
"hu": "Translated from @:languages.hu",
"id": "Translated from @:languages.id",
"ga": "Translated from @:languages.ga",
"it": "Translated from @:languages.it",
"ja": "Translated from @:languages.ja",
"ko": "Translated from @:languages.ko",
"fa": "Translated from @:languages.fa",
"pl": "Translated from @:languages.pl",
"pt": "Translated from @:languages.pt",
"ru": "Translated from @:languages.ru",
"sk": "Translated from @:languages.sk",
"es": "Translated from @:languages.es",
"sv": "Translated from @:languages.sv",
"tr": "Translated from @:languages.tr",
"uk": "Translated from @:languages.uk",
"lt": "Translated from @:languages.lt",
"lv": "Translated from @:languages.lv"
}
},
"lists": {
"create": "Create",
"delete": "Delete list",
@ -625,6 +693,19 @@
"setting_changed": "Setting is different from default",
"setting_server_side": "This setting is tied to your profile and affects all sessions and clients",
"settings": "Settings",
"settings_profile": "Settings Profiles",
"settings_profile_currently": "Currently using {name} (version: {version})",
"settings_profiles_show": "Show all settings profiles",
"settings_profiles_unshow": "Hide all settings profiles",
"settings_profile_in_use": "In use",
"settings_profile_creation": "Create new profile",
"settings_profile_creation_submit": "Create",
"settings_profile_creation_new_name_label": "Name",
"settings_profile_use": "Use",
"settings_profile_delete": "Delete",
"settings_profile_delete_confirm": "Do you really want to delete this profile?",
"settings_profile_force_sync": "Synchronize",
"settings_profiles_refresh": "Reload settings profiles",
"show_admin_badge": "Show \"Admin\" badge in my profile",
"show_moderator_badge": "Show \"Moderator\" badge in my profile",
"show_nav_shortcuts": "Show extra navigation shortcuts in top panel",
@ -824,6 +905,12 @@
"word_filter": "Word filter",
"wordfilter": "Wordfilter"
},
"settings_profile": {
"synchronizing": "Synchronizing setting profile \"{profile}\"...",
"synchronized": "Synchronized settings!",
"synchronization_error": "Could not synchronize settings: {err}",
"creating": "Creating new setting profile \"{profile}\"..."
},
"status": {
"ancestor_follow": "See {numReplies} other reply under this post | See {numReplies} other replies under this post",
"ancestor_follow_with_icon": "{icon} {text}",
@ -857,6 +944,11 @@
"pin": "Pin on profile",
"pinned": "Pinned",
"plus_more": "+{number} more",
"redraft": "Delete & redraft",
"redraft_confirm": "Do you really want to delete and redraft this post? Interactions to the original post will not be preserved.",
"redraft_confirm_accept_button": "Yes, delete and redraft",
"redraft_confirm_cancel_button": "No, keep the original",
"redraft_confirm_title": "Confirm delete & redraft",
"remove_attachment": "Remove attachment",
"repeat_confirm": "Do you really want to repeat this post?",
"repeat_confirm_accept_button": "Yes, repeat it",
@ -1032,6 +1124,7 @@
"note": "Private note",
"per_day": "per day",
"remote_follow": "Remote follow",
"remove_follower": "Remove follower",
"replies": "With Replies",
"report": "Report",
"show_repeats": "Show repeats",

View file

@ -164,6 +164,74 @@
"load_older": "Chargez d'anciennes interactions",
"moves": "Migrations de comptes"
},
"languages": {
"ar": "arabe",
"az": "azéri",
"bg": "bulgare",
"cs": "tchèque",
"da": "danois",
"de": "allemand",
"el": "grec",
"en": "anglais",
"eo": "espéranto",
"es": "espagnol",
"fa": "persan",
"fi": "finnois",
"fr": "français",
"ga": "irlandais",
"he": "hébreu",
"hi": "hindi",
"hu": "hongrois",
"id": "indonésien",
"it": "italien",
"ja": "japonais",
"ko": "coréen",
"lt": "lituanien",
"lv": "letton",
"nl": "néerlandais",
"pl": "polonais",
"pt": "portugais",
"ru": "russe",
"sk": "slovaque",
"sv": "suédois",
"tr": "turc",
"translated_from": {
"ar": "Traduit de l'@:languages.ar",
"az": "Traduit de l'@:languages.az",
"bg": "Traduit du @:languages.bg",
"cs": "Traduit du @:languages.cs",
"da": "Traduit du @:languages.da",
"de": "Traduit de l'@:languages.de",
"el": "Traduit du @:languages.el",
"en": "Traduit de l'@:languages.en",
"eo": "Traduit de l'@:languages.eo",
"es": "Traduit de l'@:languages.es",
"fa": "Traduit du @:languages.fa",
"fi": "Traduit du @:languages.fi",
"fr": "Traduit du @:languages.fr",
"ga": "Traduit de l'@:languages.ga",
"he": "Traduit de l'@:languages.he",
"hi": "Traduit de l'@:languages.hi",
"hu": "Traduit du @:languages.hu",
"id": "Traduit de l'@:languages.id",
"it": "Traduit de l'@:languages.it",
"ja": "Traduit du @:languages.ja",
"ko": "Traduit du @:languages.ko",
"lt": "Traduit du @:languages.lt",
"lv": "Traduit du @:languages.lv",
"nl": "Traduit du @:languages.nl",
"pl": "Traduit du @:languages.pl",
"pt": "Traduit du @:languages.pt",
"ru": "Traduit du @:languages.ru",
"sk": "Traduit du @:languages.sk",
"sv": "Traduit du @:languages.sv",
"tr": "Traduit du @:languages.tr",
"uk": "Traduit de l'@:languages.uk",
"zh": "Traduit du @:languages.zh"
},
"uk": "ukrainien",
"zh": "chinois"
},
"lists": {
"create": "Créer",
"delete": "Supprimer la liste",
@ -223,7 +291,7 @@
"twkn": "Réseau connu",
"twkn_timeline_description": "Les status du réseau entier",
"user_search": "Recherche de comptes",
"who_to_follow": "Suggestion de suivit"
"who_to_follow": "Suggestion de suivi"
},
"notifications": {
"broken_favorite": "Message inconnu, recherche en cours…",
@ -285,6 +353,7 @@
"direct_warning_to_first_only": "Ce message sera visible uniquement pour personnes mentionnées au début du message.",
"edit_remote_warning": "Les modifications apportées au status pourraient ne pas être visible sur certaines instances !",
"edit_status": "Modifier le statut",
"edit_unsupported_warning": "Les sondages et les mentions ne peuvent être modifier.",
"empty_status_error": "Impossible de publier un statut vide sans pièces-jointes",
"media_description": "Description de la pièce-jointe",
"media_description_error": "Échec de téléversement du media, essayez encore",
@ -315,7 +384,7 @@
"email": "Courriel",
"email_language": "Dans quelle langue souhaitez-vous recevoir des courriels ?",
"fullname": "Pseudonyme",
"fullname_placeholder": "ex. Lain Iwakura",
"fullname_placeholder": "ex : Misato Katsuragi",
"new_captcha": "Cliquez sur l'image pour avoir un nouveau captcha",
"password_confirm": "Confirmation du mot de passe",
"reason": "Motivation d'inscription",
@ -323,7 +392,7 @@
"register": "Enregistrer",
"registration": "Inscription",
"token": "Jeton d'invitation",
"username_placeholder": "ex. lain",
"username_placeholder": "ex : misato",
"validations": {
"email_required": "ne peut pas être laissé vide",
"fullname_required": "ne peut pas être laissé vide",
@ -361,7 +430,7 @@
"add_backup_error": "Erreur pendant la création d'une nouvelle archive: {error}",
"added_alias": "Alias créé",
"added_backup": "Archive créée",
"allow_following_move": "Activer le suivit automatique à la migration des comptes",
"allow_following_move": "Activer le suivi automatique à la migration des comptes",
"always_show_post_button": "Toujours afficher le bouton de Nouveau statut",
"app_name": "Nom de l'application",
"attachmentRadius": "Pièces jointes",
@ -394,9 +463,19 @@
"changed_password": "Mot de passe modifié avec succès !",
"chatMessageRadius": "Message de chat",
"checkboxRadius": "Cases à cocher",
"collapse_subject": "Réduire les messages avec des sujets",
"collapse_subject": "Réduire les messages avec des avertissements",
"columns": "Colonnes",
"composing": "Composition",
"confirm_dialogs": "Demander confirmation :",
"confirm_dialogs_approve_follow": "Accepter une demande de suivi",
"confirm_dialogs_block": "Bloquer un compte",
"confirm_dialogs_delete": "Supprimer un statut",
"confirm_dialogs_deny_follow": "Rejeter une demande de suivi",
"confirm_dialogs_mute": "Masquer un compte",
"confirm_dialogs_repeat": "Partager un statut",
"confirm_dialogs_unfollow": "Désabonner",
"confirm_new_password": "Confirmation du nouveau mot de passe",
"confirmation_dialogs": "Options de confirmation",
"conversation_display": "Affichage des fils",
"conversation_display_linear": "Vue linéaire",
"conversation_display_tree": "Vue arborescente",
@ -606,7 +685,7 @@
"security": "Sécurité",
"security_tab": "Sécurité",
"sensitive_by_default": "Marquer les messages comme sensible par défaut",
"sensitive_if_subject": "Automatiquement marquer les images comme sensible quand le statut a un sujet",
"sensitive_if_subject": "Automatiquement marquer les images comme sensible quand le statut a un avertissement",
"set_new_avatar": "Changer d'avatar",
"set_new_mascot": "Changer de mascotte",
"set_new_profile_background": "Changer d'image de fond",
@ -769,9 +848,9 @@
"use_source": "Nouvelle version"
}
},
"subject_input_always_show": "Toujours afficher le champ Sujet",
"subject_line_behavior": "Copier le sujet en répondant",
"subject_line_email": "Similaire au courriel: « re: sujet »",
"subject_input_always_show": "Toujours afficher le champ Avertissement",
"subject_line_behavior": "Copier l'avertissement en répondant",
"subject_line_email": "Similaire au courriel: « re: avertissement »",
"subject_line_mastodon": "Comme mastodon: copier tel quel",
"subject_line_noop": "Ne pas copier",
"text": "Texte",
@ -785,7 +864,8 @@
"third_column_mode_postform": "Création de statut et navigation",
"token": "Jeton",
"tooltipRadius": "Info-bulles/alertes",
"tree_advanced": "Navigation plus flexible en vue arborescente",
"translation_language": "Langue cible de la traduction automatique",
"tree_advanced": "Afficher les boutons pour développer et fermer les fils de discussion",
"tree_fade_ancestors": "Afficher les statuts précédents en gris clair",
"type_domains_to_mute": "Chercher les domaines à masquer",
"upload_a_photo": "Envoyer une photo",
@ -795,6 +875,7 @@
"use_contain_fit": "Ne pas rogner les miniatures des pièces-jointes",
"use_one_click_nsfw": "Ouvrir les pièces-jointes sensibles avec un seul clic",
"user_mutes": "Comptes",
"user_profile_default_tab": "Onglet affiché par défaut dans les profils",
"user_profiles": "Profils utilisateurs",
"user_settings": "Paramètres utilisateur",
"valid_until": "Valable jusque",
@ -820,12 +901,19 @@
"copy_link": "Copier le lien au status",
"delete": "Supprimer statuts",
"delete_confirm": "Voulez-vous vraiment supprimer ce statuts ?",
"delete_confirm_accept_button": "Supprimer",
"delete_confirm_cancel_button": "Garder",
"delete_confirm_title": "Confirmer la suppression du statut",
"edit": "Modifier",
"edit_history": "Histoire de modifications",
"edit_history_modal_title": "modifié {historyCount} fois",
"edited_at": "modifié {time}",
"expand": "Développer",
"external_source": "Source externe",
"favorites": "Favoris",
"hide_attachment": "Masquer la pièce jointe",
"hide_content": "Cacher le contenu",
"hide_full_subject": "Cacher le sujet",
"hide_full_subject": "Cacher l'avertissement",
"many_attachments": "Le statut a {number} pièce jointe | Le statut a {number} pièces jointes",
"mentions": "Mentions",
"move_down": "Déplacer à droit",
@ -833,13 +921,18 @@
"mute_conversation": "Masquer la conversation",
"nsfw": "Contenu sensible",
"open_gallery": "Afficher la galerie",
"override_translation_source_language": "Changer la langue détectée",
"pin": "Agrafer sur le profil",
"pinned": "Agraffé",
"plus_more": "+{number} autre | +{number} autres",
"remove_attachment": "Supprimer la pièce jointe",
"repeat_confirm": "Partager ce statut ?",
"repeat_confirm_accept_button": "Partager",
"repeat_confirm_cancel_button": "Annuler",
"repeat_confirm_title": "Confirmer le partage",
"repeats": "Partages",
"replies_list": "Réponses:",
"replies_list_with_others": "Réponses (+{numReplies} autre): | Réponses (+{numReplies} autres) :",
"replies_list_with_others": "Afficher +{numReplies} réponse | Afficher +{numReplies} réponses",
"reply_to": "Réponse à",
"show_all_attachments": "Afficher toutes les pièces jointes",
"show_all_conversation": "Afficher le fils entier ({numStatus} autre statut) | Afficher le fil entier ({numStatus} autres statuts)",
@ -847,18 +940,20 @@
"show_attachment_description": "Aperçu (ouvrir la pièce joint pour voir la description complète)",
"show_attachment_in_modal": "Ouvrir dans la visionneuse",
"show_content": "Montrer le contenu",
"show_full_subject": "Montrer le sujet en entier",
"show_full_subject": "Montrer l'avertissement en entier",
"show_only_conversation_under_this": "N'afficher que les réponses a ce statut",
"status_deleted": "Ce post a été effacé",
"status_unavailable": "Status indisponible",
"thread_follow": "Afficher la partie restante du fil ({numStatus} statut au total) | Afficher la partie restante du fil ({numStatus} statuts au total)",
"thread_follow": "Afficher {numStatus} réponse en plus | Afficher {numStatus} réponses en plus",
"thread_follow_with_icon": "{icon} {text}",
"thread_hide": "Masquer ce fil",
"thread_muted": "Fil de discussion masqué",
"thread_muted_and_words": ", contient les mots :",
"thread_show": "Afficher ce fil",
"thread_show_full": "Afficher tout les statuts dans ce fil ({numStatus} au total, profondeur maximale {depth})",
"thread_show_full": "Afficher {numStatus} réponse | Afficher les {numStatus} réponses",
"thread_show_full_with_icon": "{icon} {text}",
"translate": "Traduction",
"translated_from": "Traduit d'une autre langue ({language})",
"unbookmark": "Supprimer des favoris",
"unmute_conversation": "Démasquer la conversation",
"unpin": "Dégrafer du profil",
@ -901,14 +996,17 @@
"socket_reconnected": "Connexion temps-réel établie",
"up_to_date": "À jour"
},
"toast": {
"no_translation_target_set": "Aucune langue cible choisi pour la traduction automatique. Veuillez en choisir une dans les préférences."
},
"tool_tip": {
"accept_follow_request": "Accepter la demande de suivit",
"accept_follow_request": "Accepter la demande de suivi",
"add_reaction": "Ajouter une réaction",
"bookmark": "Favori",
"favorite": "Favoriser",
"media_upload": "Envoyer un media",
"quote": "Citer",
"reject_follow_request": "Rejeter la demande de suivit",
"reject_follow_request": "Rejeter la demande de suivi",
"repeat": "Répéter",
"reply": "Répondre",
"user_settings": "Paramètres utilisateur"

View file

@ -164,6 +164,74 @@
"load_older": "古いインタラクションを見る",
"moves": "ユーザーの引っ越し"
},
"languages": {
"ar": "アラビア語",
"az": "アゼルバイジャン語",
"bg": "ブルガリア語",
"cs": "チェコ語",
"da": "デンマーク語",
"de": "ドイツ語",
"el": "ギリシャ語",
"en": "英語",
"eo": "エス語",
"es": "スペイン語",
"fa": "ペルシャ語",
"fi": "フィンランド語",
"fr": "フランス語",
"ga": "アイルランド語",
"he": "ヘブライ語",
"hi": "ヒンディー語",
"hu": "ハンガリー語",
"id": "インドネシア語",
"it": "イタリア語",
"ja": "日本語",
"ko": "韓国語",
"lt": "リトアニア語",
"lv": "ラトビア語",
"nl": "オランダ語",
"pl": "ポーランド語",
"pt": "ポルトガル語",
"ru": "ロシア語",
"sk": "スロバキア語",
"sv": "スウェーデン語",
"tr": "トルコ語",
"translated_from": {
"ar": "アラビア語から翻訳しました",
"az": "アゼルバイジャン語から翻訳しました",
"bg": "ブルガリア語から翻訳しました",
"cs": "チェコ語から翻訳しました",
"da": "デンマーク語から翻訳しました",
"de": "ドイツ語から翻訳しました",
"el": "ギリシャ語から翻訳しました",
"en": "英語から翻訳しました",
"eo": "エス語から翻訳しました",
"es": "スペイン語から翻訳しました",
"fa": "ペルシア語から翻訳しました",
"fi": "フィンランド語から翻訳しました",
"fr": "フランス語から翻訳しました",
"ga": "アイルランド語から翻訳しました",
"he": "ヘブライ語から翻訳しました",
"hi": "ヒンディー語から翻訳しました",
"hu": "ハンガリー語から翻訳しました",
"id": "インドネシア語から翻訳しました",
"it": "イタリア語から翻訳しました",
"ja": "日本語から翻訳しました",
"ko": "韓国語から翻訳しました",
"lt": "リトアニア語から翻訳しました",
"lv": "ラトビア語から翻訳しました",
"nl": "オランダ語から翻訳しました",
"pl": "ポーランド語から翻訳しました",
"pt": "ポルトガル語から翻訳しました",
"ru": "ロシア語から翻訳しました",
"sk": "スロバキア語から翻訳しました",
"sv": "スウェーデン語から翻訳しました",
"tr": "トルコ語から翻訳しました",
"uk": "ウクライナ語から翻訳しました",
"zh": "中国語から翻訳しました"
},
"uk": "ウクライナ語",
"zh": "中国語"
},
"lists": {
"create": "作成",
"delete": "削除",
@ -289,7 +357,7 @@
"empty_status_error": "投稿内容を入力してください",
"media_description": "メディアの説明",
"media_description_error": "メディアのアップロードに失敗しました。もう一度お試しください",
"media_not_sensitive_warning": "注意: 説明が付けていますがNSFW警告が付けていません",
"media_not_sensitive_warning": "注意: 説明が付いていますがNSFWが付いていません",
"new_status": "投稿する",
"post": "投稿",
"posting": "投稿",
@ -625,6 +693,19 @@
"setting_changed": "規定の設定と異なっています",
"setting_server_side": "この設定は、全クライエントに適用します",
"settings": "設定",
"settings_profile": "設定プロファイル",
"settings_profile_creation": "プロファイル作成",
"settings_profile_creation_new_name_label": "プロファイル名",
"settings_profile_creation_submit": "作成",
"settings_profile_currently": "現在利用されています:{name} (バージョン {version})",
"settings_profile_delete": "削除",
"settings_profile_delete_confirm": "プロファイルを削除しますか?",
"settings_profile_force_sync": "同期する",
"settings_profile_in_use": "利用されています",
"settings_profile_use": "利用",
"settings_profiles_refresh": "再ロード",
"settings_profiles_show": "全プロファイルを表示",
"settings_profiles_unshow": "隠す",
"show_admin_badge": "\"管理者\"のバッジを見せる",
"show_moderator_badge": "\"モデレーター\"のバッジを見せる",
"show_nav_shortcuts": "ページ上にショートカットを追加",
@ -824,6 +905,12 @@
"word_filter": "単語フィルタ",
"wordfilter": "単語フィルター"
},
"settings_profile": {
"creating": "新しい設定プロファイル {profile}を作成しています",
"synchronization_error": "同期できませんでした: {err}",
"synchronized": "同期しました!",
"synchronizing": "設定プロファイル 「{profile}」を同期しています"
},
"status": {
"ancestor_follow": "{numReplies}件の返信を見る",
"ancestor_follow_with_icon": "{icon} {text}",
@ -857,6 +944,11 @@
"pin": "プロフィールにピン留め",
"pinned": "ピン留め",
"plus_more": "ほか{number}件",
"redraft": "削除して編集",
"redraft_confirm": "削除して編集しますか?",
"redraft_confirm_accept_button": "削除して編集",
"redraft_confirm_cancel_button": "キャンセル",
"redraft_confirm_title": "確認してください",
"remove_attachment": "削除",
"repeat_confirm": "リピートしますか?",
"repeat_confirm_accept_button": "リピート",

View file

@ -164,6 +164,74 @@
"load_older": "Oudere interacties laden",
"moves": "Gebruikermigraties"
},
"languages": {
"ar": "Arabisch",
"az": "Azerbeidzjaans",
"bg": "Bulgaars",
"cs": "Tsjechisch",
"da": "Deens",
"de": "Duits",
"el": "Grieks",
"en": "Engels",
"eo": "Esperanto",
"es": "Spaans",
"fa": "Persisch",
"fi": "Fins",
"fr": "Frans",
"ga": "Iers",
"he": "Hebreeuws",
"hi": "Hindi",
"hu": "Hongaars",
"id": "Indonesisch",
"it": "Italiaans",
"ja": "Japans",
"ko": "Koreaans",
"lt": "Litouws",
"lv": "Lets",
"nl": "Nederlands",
"pl": "Pools",
"pt": "Portugees",
"ru": "Russisch",
"sk": "Slowaaks",
"sv": "Zweeds",
"tr": "Turks",
"translated_from": {
"ar": "Vertaald uit het @:languages.ar",
"az": "Vertaald uit het @:languages.az",
"bg": "Vertaald uit het @:languages.bg",
"cs": "Vertaald uit het @:languages.cs",
"da": "Vertaald uit het @:languages.da",
"de": "Vertaald uit het @:languages.de",
"el": "Vertaald uit het @:languages.el",
"en": "Vertaald uit het @:languages.en",
"eo": "Vertaald uit het @:languages.eo",
"es": "Vertaald uit het @:languages.es",
"fa": "Vertaald uit het @:languages.fa",
"fi": "Vertaald uit het @:languages.fi",
"fr": "Vertaald uit het @:languages.fr",
"ga": "Vertaald uit het @:languages.ga",
"he": "Vertaald uit het @:languages.he",
"hi": "Vertaald uit het @:languages.hi",
"hu": "Vertaald uit het @:languages.hu",
"id": "Vertaald uit het @:languages.id",
"it": "Vertaald uit het @:languages.it",
"ja": "Vertaald uit het @:languages.ja",
"ko": "Vertaald uit het @:languages.ko",
"lt": "Vertaald uit het @:languages.lt",
"lv": "Vertaald uit het @:languages.lv",
"nl": "Vertaald uit het @:languages.nl",
"pl": "Vertaald uit het @:languages.pl",
"pt": "Vertaald uit het @:languages.pt",
"ru": "Vertaald uit het @:languages.ru",
"sk": "Vertaald uit het @:languages.sk",
"sv": "Vertaald uit het @:languages.sv",
"tr": "Vertaald uit het @:languages.tr",
"uk": "Vertaald uit het @:languages.uk",
"zh": "Vertaald uit het @:languages.zh"
},
"uk": "Oekraeens",
"zh": "Chinees"
},
"lists": {
"create": "Aanmaken",
"delete": "Lijst verwijderen",
@ -279,10 +347,13 @@
"text/plain": "Platte tekst",
"text/x.misskeymarkdown": "MFM"
},
"content_warning": "Onderwerp (optioneel)",
"content_warning": "Content Waarschuwing (optioneel)",
"default": "Zojuist gearriveerd op de Zweinstein Hogeschool",
"direct_warning_to_all": "Dit bericht zal zichtbaar zijn voor alle vermelde gebruikers.",
"direct_warning_to_first_only": "Dit bericht zal alleen zichtbaar zijn voor de vermelde gebruikers aan het begin van het bericht.",
"edit_remote_warning": "De gemaakte wijzigingen aan het bericht zijn mogelijk niet zichtbaar op sommige instanties!",
"edit_status": "Bericht Aanpassen",
"edit_unsupported_warning": "Peilingen en vermeldingen zullen niet veranderen tijdens het wijzigen.",
"empty_status_error": "Kan geen leeg bericht zonder bijlagen plaatsen",
"media_description": "Mediaomschrijving",
"media_description_error": "Kon media niet ophalen, probeer het opnieuw",
@ -392,12 +463,14 @@
"changed_password": "Wachtwoord succesvol gewijzigd!",
"chatMessageRadius": "Chatbericht",
"checkboxRadius": "Checkboxen",
"collapse_subject": "Berichten met een onderwerp inklappen",
"collapse_subject": "Berichten met een content waarschuwing inklappen",
"columns": "Kolommen",
"composing": "Opstellen",
"confirm_dialogs": "Bevestiging vereisen voor:",
"confirm_dialogs_approve_follow": "Een volgverzoek accepteren",
"confirm_dialogs_block": "Iemand blokkeren",
"confirm_dialogs_delete": "Een bericht verwijderen",
"confirm_dialogs_deny_follow": "Een volgverzoek afwijzen",
"confirm_dialogs_mute": "Iemand negeren",
"confirm_dialogs_repeat": "Herhalen van een bericht",
"confirm_dialogs_unfollow": "Iemand ontvolgen",
@ -612,7 +685,7 @@
"security": "Beveiliging",
"security_tab": "Beveiliging",
"sensitive_by_default": "Berichten standaard als gevoelig markeren",
"sensitive_if_subject": "Automatisch afbeeldingen als gevoelig markeren indien een onderwerp opgegeven is",
"sensitive_if_subject": "Automatisch afbeeldingen als gevoelig markeren indien een content waarschuwing opgegeven is",
"set_new_avatar": "Nieuwe avatar instellen",
"set_new_mascot": "Nieuwe mascotte instellen",
"set_new_profile_background": "Nieuwe profiel achtergrond instellen",
@ -708,7 +781,7 @@
"fine_print": "Lees onze {0} om niets nuttig te leren!",
"header": "Voorvertoning",
"header_faint": "Alles komt goed",
"input": "Tijd voor anime!",
"input": "Zojuist aangekomen bij Luna Nova Academie",
"link": "een leuke kleine link",
"mono": "inhoud",
"text": "Nog een boel andere {0} en {1}"
@ -775,9 +848,9 @@
"use_source": "Nieuwe versie"
}
},
"subject_input_always_show": "Altijd onderwerpveld tonen",
"subject_line_behavior": "Onderwerp kopiëren bij beantwoorden",
"subject_line_email": "Zoals e-mail: \"re: onderwerp\"",
"subject_input_always_show": "Altijd het contentwaarschuwings-veld tonen",
"subject_line_behavior": "Content waarschuwing kopiëren bij beantwoorden",
"subject_line_email": "Zoals e-mail: \"re: waarschuwing\"",
"subject_line_mastodon": "Zoals mastodon: kopiëren zoals het is",
"subject_line_noop": "Niet kopiëren",
"text": "Tekst",
@ -791,7 +864,8 @@
"third_column_mode_postform": "Berichtformulier en navigatie",
"token": "Token",
"tooltipRadius": "Tooltips/alarmen",
"tree_advanced": "Flexibelere navigatie toestaan in boom weergave",
"translation_language": "Taal voor Automatisch Vertalen",
"tree_advanced": "Extra knoppen tonen om antwoorden te openen en sluiten",
"tree_fade_ancestors": "Ouders van huidige bericht met gedempte tekst tonen",
"type_domains_to_mute": "Zoek domeinen om te negeren",
"upload_a_photo": "Foto uploaden",
@ -801,6 +875,7 @@
"use_contain_fit": "Bijlage in miniaturen niet bijsnijden",
"use_one_click_nsfw": "Gevoelige bijlagen met slechts één klik openen",
"user_mutes": "Gebruikers",
"user_profile_default_tab": "Standaard Tabblad op Gebruikersprofiel",
"user_profiles": "Gebruikersprofielen",
"user_settings": "Gebruikersinstellingen",
"valid_until": "Geldig tot",
@ -826,12 +901,19 @@
"copy_link": "Link naar bericht kopiëren",
"delete": "Bericht verwijderen",
"delete_confirm": "Wil je echt dit bericht verwijderen?",
"delete_confirm_accept_button": "Ja, verwijderen",
"delete_confirm_cancel_button": "Nee, houden zoals het is",
"delete_confirm_title": "Verwijderen bevestigen",
"edit": "Wijzigen",
"edit_history": "Historie Wijzigen",
"edit_history_modal_title": "{historyCount} keer gewijzigd | {historyCount} keren gewijzigd",
"edited_at": "Gewijzigd op {time}",
"expand": "Uitvouwen",
"external_source": "Externe bron",
"favorites": "Favorieten",
"hide_attachment": "Bijlage verbergen",
"hide_content": "Inhoud verbergen",
"hide_full_subject": "Volledig onderwerp verbergen",
"hide_full_subject": "Volledige content waarschuwing verbergen",
"many_attachments": "Bericht heeft {number} bijlage | Bericht heeft {number} bijlagen",
"mentions": "Vermeldingen",
"move_down": "Bijlage naar rechts schuiven",
@ -839,32 +921,39 @@
"mute_conversation": "Gesprek negeren",
"nsfw": "Gevoelig",
"open_gallery": "Gallerij openen",
"override_translation_source_language": "Bron-taal omzeilen",
"pin": "Aan profiel vastmaken",
"pinned": "Vastgezet",
"plus_more": "+{number} meer",
"remove_attachment": "Bijlage verwijderen",
"repeat_confirm": "Weet je zeker dat je dit bericht wilt herhalen?",
"repeat_confirm_accept_button": "Ja, herhalen",
"repeat_confirm_cancel_button": "Nee, niet herhalen",
"repeat_confirm_title": "Herhalen bevestigen",
"repeats": "Herhalingen",
"replies_list": "Antwoorden:",
"replies_list_with_others": "Antwoorden (+{numReplies} andere): | Antwoorden (+{numReplies} anderen):",
"replies_list_with_others": "Bekijk {numReplies} meer antwoord | Bekijk {numReplies} meer antwoorden",
"reply_to": "Antwoorden aan",
"show_all_attachments": "Alle bijlagen tonen",
"show_all_conversation": "Volledig gesprek tonen ({numStatus} ander bericht) | Volledig gesprek tonen ({numStatus} andere berichten)",
"show_all_conversation_with_icon": "{icon} {text}",
"show_attachment_description": "Voorbeeld beschrijving (open bijlage om de volledige beschrijving te zien)",
"show_attachment_in_modal": "In media venster tonen",
"show_attachment_in_modal": "Bijlage in apart venster tonen",
"show_content": "Inhoud tonen",
"show_full_subject": "Volledig onderwerp tonen",
"show_full_subject": "Volledige content waarschuwing tonen",
"show_only_conversation_under_this": "Alleen antwoorden op dit bericht tonen",
"status_deleted": "Dit bericht is verwijderd",
"status_unavailable": "Bericht niet beschikbaar",
"thread_follow": "Rest van gesprek tonen ({numStatus} bericht in totaal) | Rest van gesprek tonen ({numStatus} berichten in totaal)",
"thread_follow": "Toon {numStatus} meer antwoord | Toon {numStatus} meer antwoorden",
"thread_follow_with_icon": "{icon} {text}",
"thread_hide": "Gesprek verbergen",
"thread_muted": "Gesprek genegeerd",
"thread_muted_and_words": ", heeft woorden:",
"thread_show": "Gesprek tonen",
"thread_show_full": "Alle berichten in dit gesprek tonen ({numStatus} bericht in totaal, max. diepte {depth}) | Alle berichten in dit gesprek tonen ({numStatus} berichten in totaal, max. diepte {depth})",
"thread_show_full": "Toon {numStatus} antwoord | Toon {numStatus} antwoorden",
"thread_show_full_with_icon": "{icon} {text}",
"translate": "Vertalen",
"translated_from": "Vertaald uit het {language}",
"unbookmark": "Bladwijzer verwijderen",
"unmute_conversation": "Gesprek niet meer negeren",
"unpin": "Van profiel losmaken",
@ -907,6 +996,9 @@
"socket_reconnected": "Realtime verbinding opgezet",
"up_to_date": "Up-to-date"
},
"toast": {
"no_translation_target_set": "Er is geen taal gekozen om naar te vertalen - dit kan fout gaan. Stel een doelwit taal in in je instellingen."
},
"tool_tip": {
"accept_follow_request": "Volgverzoek accepteren",
"add_reaction": "Reactie toevoegen",
@ -955,12 +1047,24 @@
"strip_media": "Media van berichten verwijderen"
},
"approve": "Goedkeuren",
"approve_confirm": "Weet je zeker dat je deze gebruiker wilt toestaan om je te volgen?",
"approve_confirm_accept_button": "Ja, toestaan",
"approve_confirm_cancel_button": "Nee, weigeren",
"approve_confirm_title": "Volgverzoek toestaan",
"block": "Blokkeren",
"block_confirm": "Weet je zeker dat je {user} wilt blokkeren?",
"block_confirm_accept_button": "Ja, blokkeren",
"block_confirm_cancel_button": "Nee, niet blokkeren",
"block_confirm_title": "Gebruiker blokkeren",
"block_progress": "Blokkeren…",
"blocked": "Geblokkeerd!",
"bot": "Bot",
"deactivated": "Gedeactiveerd",
"deny": "Weigeren",
"deny_confirm": "Weet je zeker dat je deze gebruiker wilt weigeren om je te volgen?",
"deny_confirm_accept_button": "Ja, weigeren",
"deny_confirm_cancel_button": "Nee, niet weigeren",
"deny_confirm_title": "Volgverzoek weigeren",
"domain_muted": "Domein deblokkeren",
"edit_profile": "Profiel wijzigen",
"favorites": "Favorieten",
@ -986,18 +1090,27 @@
"mention": "Vermelden",
"message": "Bericht",
"mute": "Negeren",
"mute_confirm": "Weet je zeker dat je {user} wil negeren?",
"mute_confirm_accept_button": "Ja, negeren",
"mute_confirm_cancel_button": "Nee, niet negeren",
"mute_confirm_title": "Gebruiker negeren",
"mute_domain": "Domein blokkeren",
"mute_progress": "Negeren…",
"muted": "Genegeerd",
"note": "Privé notitie",
"per_day": "per dag",
"remote_follow": "Van afstand volgen",
"replies": "Met Antwoorden",
"report": "Rapporteren",
"show_repeats": "Herhalingen tonen",
"statuses": "Berichten",
"subscribe": "Abonneren",
"unblock": "Blokkeren opheffen",
"unblock_progress": "Blokkeren opheffen…",
"unfollow_confirm": "Weet je zeker dat je {user} wil ontvolgen?",
"unfollow_confirm_accept_button": "Ja, ontvolgen",
"unfollow_confirm_cancel_button": "Nee, niet ontvolgen",
"unfollow_confirm_title": "Gebruiker ontvolgen",
"unmute": "Negeren opheffen",
"unmute_progress": "Negeren opheffen…",
"unsubscribe": "Abonnement opzeggen"

View file

@ -3,6 +3,16 @@ import { WSConnectionStatus } from '../services/api/api.service.js'
const retryTimeout = (multiplier) => 1000 * multiplier
const isVisible = (store, message, visibility) => {
if (visibility === 'all') {
return true
} else if (visibility === 'following') {
return store.getters.relationship(message.in_reply_to_user_id).following
} else if (visibility === 'self') {
return message.in_reply_to_user_id === store.rootState.users.currentUser.id
}
return false
}
const api = {
state: {
retryMultiplier: 1,
@ -85,20 +95,21 @@ const api = {
state.mastoUserSocket.addEventListener(
'message',
({ detail: message }) => {
const replyVisibility = rootState.config.replyVisibility
if (!message) return // pings
if (message.event === 'notification') {
dispatch('addNewNotifications', {
notifications: [message.notification],
older: false
})
} else if (message.event === 'update') {
} else if (message.event === 'update' && isVisible(store, message.status, replyVisibility)) {
dispatch('addNewStatuses', {
statuses: [message.status],
userId: false,
showImmediately: timelineData.visibleStatuses.length === 0,
timeline: 'friends'
})
} else if (message.event === 'status.update') {
} else if (message.event === 'status.update' && isVisible(store, message.status, replyVisibility)) {
dispatch('addNewStatuses', {
statuses: [message.status],
userId: false,
@ -200,7 +211,17 @@ const api = {
...rest
})
},
startFetchingConfig (store) {
if (store.state.fetchers.config) return
const fetcher = store.state.backendInteractor.startFetchingConfig({ store })
store.commit('addFetcher', { fetcherName: 'config', fetcher })
},
stopFetchingConfig (store) {
const fetcher = store.state.fetchers.config
if (!fetcher) return
store.commit('removeFetcher', { fetcherName: 'config', fetcher })
},
// Notifications
startFetchingNotifications (store) {
if (store.state.fetchers.notifications) return
@ -262,10 +283,15 @@ const api = {
getSupportedTranslationlanguages (store) {
store.state.backendInteractor.getSupportedTranslationlanguages({ store })
.then((data) => {
store.dispatch('setOption', { name: 'supportedTranslationLanguages', value: data })
store.dispatch('setInstanceOption', { name: 'supportedTranslationLanguages', value: data })
})
},
listSettingsProfiles (store) {
store.state.backendInteractor.listSettingsProfiles({ store })
.then((data) => {
store.commit('setInstanceOption', { name: 'settingsProfiles', value: data })
})
},
// Pleroma websocket
setWsToken (store, token) {
store.commit('setWsToken', token)

View file

@ -21,6 +21,8 @@ export const multiChoiceProperties = [
]
export const defaultState = {
profile: 'default',
profileVersion: 0,
expertLevel: 0, // used to track which settings to show and hide
colors: {},
theme: undefined,
@ -72,7 +74,7 @@ export const defaultState = {
highlight: {},
interfaceLanguage: browserLocale,
hideScopeNotice: false,
useStreamingApi: true,
useStreamingApi: false,
sidebarRight: undefined, // instance default
scopeCopy: undefined, // instance default
subjectLineBehavior: undefined, // instance default
@ -160,6 +162,42 @@ const config = {
}
},
actions: {
syncSettings: (store) => {
store.commit('setOption', { name: 'profileVersion', value: store.state.profileVersion + 1 })
const notice = {
level: 'info',
messageKey: 'settings_profile.synchronizing',
messageArgs: { profile: store.state.profile },
timeout: 5000
}
store.dispatch('pushGlobalNotice', notice)
store.rootState.api.backendInteractor.saveSettingsProfile({
settings: store.state, profileName: store.state.profile, version: store.state.profileVersion
}).then(() => {
store.dispatch('removeGlobalNotice', notice)
store.dispatch('pushGlobalNotice', {
level: 'success',
messageKey: 'settings_profile.synchronized',
messageArgs: { profile: store.state.profile },
timeout: 2000
})
store.dispatch('listSettingsProfiles')
}).catch((err) => {
store.dispatch('removeGlobalNotice', notice)
store.dispatch('pushGlobalNotice', {
level: 'error',
messageKey: 'settings_profile.synchronization_error',
messageArgs: { error: err.message },
timeout: 5000
})
console.error(err)
})
},
deleteSettingsProfile (store, name) {
store.rootState.api.backendInteractor.deleteSettingsProfile({ profileName: name }).then(() => {
store.dispatch('listSettingsProfiles')
})
},
loadSettings ({ dispatch }, data) {
const knownKeys = new Set(Object.keys(defaultState))
const presentKeys = new Set(Object.keys(data))
@ -177,8 +215,11 @@ const config = {
setHighlight ({ commit, dispatch }, { user, color, type }) {
commit('setHighlight', { user, color, type })
},
setOption ({ commit, dispatch }, { name, value }) {
setOption ({ commit, dispatch }, { name, value, manual }) {
commit('setOption', { name, value })
if (manual === true) {
dispatch('syncSettings')
}
switch (name) {
case 'theme':
setPreset(value)
@ -196,6 +237,36 @@ const config = {
dispatch('setLayoutWidth', undefined)
break
}
},
getSettingsProfile (store, forceUpdate = false) {
const profile = store.state.profile
store.rootState.api.backendInteractor.getSettingsProfile({ store, profileName: profile })
.then(({ settings, version }) => {
console.log('found settings version', version)
if (forceUpdate || (version > store.state.profileVersion)) {
store.commit('setOption', { name: 'profileVersion', value: version })
Object.entries(settings).forEach(([name, value]) => {
if (store.state[name] !== value) {
store.dispatch('setOption', { name, value })
}
})
} else {
console.log('settings are up to date')
}
})
.catch((err) => {
console.error(`could not fetch profile ${profile}`, err)
if (err.statusCode === 404) {
// create profile
store.dispatch('pushGlobalNotice', {
level: 'warning',
messageKey: 'settings_profile.creating',
messageArgs: { profile },
timeout: 5000
})
store.dispatch('syncSettings')
}
})
}
}
}

View file

@ -3,6 +3,8 @@ import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
import apiService from '../services/api/api.service.js'
import { instanceDefaultProperties } from './config.js'
const REMOTE_INTERACTION_URL = '/main/ostatus'
const defaultState = {
// Stuff from apiConfig
name: 'Pleroma FE',
@ -128,6 +130,18 @@ const instance = {
},
instanceDomain (state) {
return new URL(state.server).hostname
},
remoteInteractionLink (state) {
const server = state.server.endsWith('/') ? state.server.slice(0, -1) : state.server
const link = server + REMOTE_INTERACTION_URL
return ({ statusId, nickname }) => {
if (statusId) {
return `${link}?status_id=${statusId}`
} else {
return `${link}?nickname=${nickname}`
}
}
}
},
actions: {

View file

@ -54,6 +54,11 @@ const unblockUser = (store, id) => {
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
}
const removeUserFromFollowers = (store, id) => {
return store.rootState.api.backendInteractor.removeUserFromFollowers({ id })
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
}
const muteUser = (store, id) => {
const predictedRelationship = store.state.relationships[id] || { id }
predictedRelationship.muting = true
@ -317,6 +322,9 @@ const users = {
unblockUser (store, id) {
return unblockUser(store, id)
},
removeUserFromFollowers (store, id) {
return removeUserFromFollowers(store, id)
},
blockUsers (store, ids = []) {
return Promise.all(ids.map(id => blockUser(store, id)))
},
@ -521,6 +529,7 @@ const users = {
store.commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
store.dispatch('stopFetchingNotifications')
store.dispatch('stopFetchingFollowRequests')
store.dispatch('stopFetchingConfig')
store.commit('clearNotifications')
store.commit('resetStatuses')
store.dispatch('setLastTimeline', 'public-timeline')
@ -581,6 +590,10 @@ const users = {
store.dispatch('setLayoutWidth', windowWidth())
store.dispatch('setLayoutHeight', windowHeight())
store.dispatch('getSupportedTranslationlanguages')
store.dispatch('getSettingsProfile')
store.dispatch('listSettingsProfiles')
store.dispatch('startFetchingConfig')
// Fetch our friends
store.rootState.api.backendInteractor.fetchFriends({ id: user.id })

View file

@ -68,6 +68,7 @@ const MASTODON_BLOCK_USER_URL = id => `/api/v1/accounts/${id}/block`
const MASTODON_UNBLOCK_USER_URL = id => `/api/v1/accounts/${id}/unblock`
const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
const MASTODON_REMOVE_USER_FROM_FOLLOWERS = id => `/api/v1/accounts/${id}/remove_from_followers`
const MASTODON_SUBSCRIBE_USER = id => `/api/v1/pleroma/accounts/${id}/subscribe`
const MASTODON_UNSUBSCRIBE_USER = id => `/api/v1/pleroma/accounts/${id}/unsubscribe`
const MASTODON_SET_NOTE_URL = id => `/api/v1/accounts/${id}/note`
@ -102,6 +103,8 @@ const PLEROMA_ANNOUNCEMENTS_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const AKKOMA_SETTING_PROFILE_URL = (name) => `/api/v1/akkoma/frontend_settings/pleroma-fe/${name}`
const AKKOMA_SETTING_PROFILE_LIST = `/api/v1/akkoma/frontend_settings/pleroma-fe`
const oldfetch = window.fetch
@ -303,6 +306,13 @@ const unblockUser = ({ id, credentials }) => {
}).then((data) => data.json())
}
const removeUserFromFollowers = ({ id, credentials }) => {
return fetch(MASTODON_REMOVE_USER_FROM_FOLLOWERS(id), {
headers: authHeaders(credentials),
method: 'POST'
}).then((data) => data.json())
}
const approveUser = ({ id, credentials }) => {
let url = MASTODON_APPROVE_USER_URL(id)
return fetch(url, {
@ -1451,6 +1461,40 @@ const deleteAnnouncement = ({ id, credentials }) => {
})
}
const getSettingsProfile = ({ profileName, credentials }) => {
return promisedRequest({
url: AKKOMA_SETTING_PROFILE_URL(profileName),
credentials
})
}
const saveSettingsProfile = ({ profileName, credentials, settings, version }) => {
return promisedRequest({
url: AKKOMA_SETTING_PROFILE_URL(profileName),
method: 'PUT',
credentials,
payload: {
settings,
version
}
})
}
const deleteSettingsProfile = ({ profileName, credentials }) => {
return promisedRequest({
url: AKKOMA_SETTING_PROFILE_URL(profileName),
method: 'DELETE',
credentials
})
}
const listSettingsProfiles = ({ credentials }) => {
return promisedRequest({
url: AKKOMA_SETTING_PROFILE_LIST,
credentials
})
}
export const getMastodonSocketURI = ({ credentials, stream, args = {} }) => {
return Object.entries({
...(credentials
@ -1589,6 +1633,7 @@ const apiService = {
unmuteConversation,
blockUser,
unblockUser,
removeUserFromFollowers,
fetchUser,
fetchUserRelationship,
favorite,
@ -1677,7 +1722,11 @@ const apiService = {
deleteAnnouncement,
adminFetchAnnouncements,
translateStatus,
getSupportedTranslationlanguages
getSupportedTranslationlanguages,
getSettingsProfile,
saveSettingsProfile,
listSettingsProfiles,
deleteSettingsProfile
}
export default apiService

View file

@ -4,6 +4,7 @@ import notificationsFetcher from '../notifications_fetcher/notifications_fetcher
import followRequestFetcher from '../../services/follow_request_fetcher/follow_request_fetcher.service'
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
import announcementsFetcher from '../../services/announcements_fetcher/announcements_fetcher.service.js'
import configFetcher from '../config_fetcher/config_fetcher.service.js'
const backendInteractorService = credentials => ({
startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag }) {
@ -18,6 +19,10 @@ const backendInteractorService = credentials => ({
return notificationsFetcher.startFetching({ store, credentials })
},
startFetchingConfig ({ store }) {
return configFetcher.startFetching({ store, credentials })
},
fetchNotifications (args) {
return notificationsFetcher.fetchAndUpdate({ ...args, credentials })
},

View file

@ -0,0 +1,14 @@
import { promiseInterval } from '../promise_interval/promise_interval.js'
const startFetching = ({ credentials, store }) => {
console.log('startFetching: Config')
const boundFetchAndUpdate = () => store.dispatch('getSettingsProfile')
boundFetchAndUpdate()
return promiseInterval(boundFetchAndUpdate, 10 * 60000)
}
const configFetcher = {
startFetching
}
export default configFetcher

3200
yarn.lock

File diff suppressed because it is too large Load diff