Merge remote-tracking branch 'origin/develop' into websocket-fixes

* origin/develop: (119 commits)
  Apply 1 suggestion(s) to 1 file(s)
  Make it possible to localize user highlight options
  remove shoutbox test hacks
  fix shoutbox header, use custom scroll-to-bottom system, remove vue-chat-scroll, temporarily add chat test hack
  update changelog with 2.3.0
  change icons around
  Translated using Weblate (Japanese)
  Update timeline_quick_settings.js
  add screen_name_ui to tests
  separate screen_name and screen_name_ui with decoded punycode
  Update CHANGELOG.md
  add basic validation for statusless status notifications
  changelog mention
  fix chat unread badge
  update shelljs to get rid of warnings on build
  save a few characters
  focus input in emoji picker and react picker
  fix vue warnings
  add only to wording
  basic loggedin check for reply filtering
  ...
This commit is contained in:
Henry Jameson 2021-03-08 22:01:28 +02:00
commit 2e7bd99444
89 changed files with 2193 additions and 628 deletions

1
.mailmap Normal file
View file

@ -0,0 +1 @@
rinpatch <rin@patch.cx> <rinpatch@sdf.org>

View file

@ -3,9 +3,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/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Added ### Added
- Added a quick settings to timeline header for easier access
- Added option to mark posts as sensitive by default
## [2.3.0] - 2021-03-01
### Fixed
- Button to remove uploaded media in post status form is now properly placed and sized.
- Fixed shoutbox not working in mobile layout
- Fixed missing highlighted border in expanded conversations again
- Fixed some UI jumpiness when opening images particularly in chat view
- Fixed chat unread badge looking weird
- Fixed punycode names not working properly
- Fixed notifications crashing on an invalid notification
### Changed
- Display 'people voted' instead of 'votes' for multi-choice polls
- Optimized chat to not get horrible performance after keeping the same chat open for a long time
- When opening emoji picker or react picker, it automatically focuses the search field
- Language picker now uses native language names
### Added
- Added reason field for registration when approval is required
- Group staff members by role in the About page
## [2.2.3] - 2021-01-18
### Added
- Added Report button to status ellipsis menu for easier reporting - Added Report button to status ellipsis menu for easier reporting
### Fixed ### Fixed
@ -16,6 +40,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix not being able to re-enable websocket until page refresh - Fix not being able to re-enable websocket until page refresh
- Fix annoying issue where timeline might have few posts when streaming is enabled - Fix annoying issue where timeline might have few posts when streaming is enabled
### Changed
- Don't filter own posts when they hit your wordfilter
## [2.2.2] - 2020-12-22 ## [2.2.2] - 2020-12-22
### Added ### Added
- Mouseover titles for emojis in reaction picker - Mouseover titles for emojis in reaction picker

View file

@ -34,7 +34,6 @@
"punycode.js": "^2.1.0", "punycode.js": "^2.1.0",
"v-click-outside": "^2.1.1", "v-click-outside": "^2.1.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-chat-scroll": "^1.2.1",
"vue-i18n": "^7.3.2", "vue-i18n": "^7.3.2",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.6.11",
@ -103,7 +102,7 @@
"selenium-server": "2.53.1", "selenium-server": "2.53.1",
"semver": "^5.3.0", "semver": "^5.3.0",
"serviceworker-webpack-plugin": "^1.0.0", "serviceworker-webpack-plugin": "^1.0.0",
"shelljs": "^0.7.4", "shelljs": "^0.8.4",
"sinon": "^2.1.0", "sinon": "^2.1.0",
"sinon-chai": "^2.8.0", "sinon-chai": "^2.8.0",
"stylelint": "^13.6.1", "stylelint": "^13.6.1",

View file

@ -178,6 +178,13 @@ a {
&.-fullwidth { &.-fullwidth {
width: 100%; width: 100%;
} }
&.-hover-highlight {
&:hover svg {
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
}
}
} }
input, textarea, .select, .input { input, textarea, .select, .input {
@ -579,6 +586,7 @@ nav {
color: var(--faint, $fallback--faint); color: var(--faint, $fallback--faint);
box-shadow: 0px 0px 4px rgba(0,0,0,.6); box-shadow: 0px 0px 4px rgba(0,0,0,.6);
box-shadow: var(--topBarShadow); box-shadow: var(--topBarShadow);
box-sizing: border-box;
} }
.fade-enter-active, .fade-leave-active { .fade-enter-active, .fade-leave-active {
@ -880,6 +888,11 @@ nav {
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
// Get rid of scrollbar on body as scrolling happens on different element
body {
overflow: hidden;
}
// Ensures the fixed position of the mobile browser bars on scroll up / down events. // Ensures the fixed position of the mobile browser bars on scroll up / down events.
// Prevents the mobile browser bars from overlapping or hiding the message posting form. // Prevents the mobile browser bars from overlapping or hiding the message posting form.
@media all and (max-width: 800px) { @media all and (max-width: 800px) {

View file

@ -51,6 +51,7 @@ const getInstanceConfig = async ({ store }) => {
const vapidPublicKey = data.pleroma.vapid_public_key const vapidPublicKey = data.pleroma.vapid_public_key
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit }) store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
if (vapidPublicKey) { if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey }) store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })

View file

@ -42,7 +42,7 @@
class="basic-user-card-screen-name" class="basic-user-card-screen-name"
:to="userProfileLink(user)" :to="userProfileLink(user)"
> >
@{{ user.screen_name }} @{{ user.screen_name_ui }}
</router-link> </router-link>
</div> </div>
<slot /> <slot />

View file

@ -73,7 +73,7 @@ const Chat = {
}, },
formPlaceholder () { formPlaceholder () {
if (this.recipient) { if (this.recipient) {
return this.$t('chats.message_user', { nickname: this.recipient.screen_name }) return this.$t('chats.message_user', { nickname: this.recipient.screen_name_ui })
} else { } else {
return '' return ''
} }
@ -234,6 +234,13 @@ const Chat = {
const scrollable = this.$refs.scrollable const scrollable = this.$refs.scrollable
return scrollable && scrollable.scrollTop <= 0 return scrollable && scrollable.scrollTop <= 0
}, },
cullOlderCheck () {
window.setTimeout(() => {
if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) {
this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId)
}
}, 5000)
},
handleScroll: _.throttle(function () { handleScroll: _.throttle(function () {
if (!this.currentChat) { return } if (!this.currentChat) { return }
@ -241,6 +248,7 @@ const Chat = {
this.fetchChat({ maxId: this.currentChatMessageService.minId }) this.fetchChat({ maxId: this.currentChatMessageService.minId })
} else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) { } else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) {
this.jumpToBottomButtonVisible = false this.jumpToBottomButtonVisible = false
this.cullOlderCheck()
if (this.newMessageCount > 0) { if (this.newMessageCount > 0) {
// Use a delay before marking as read to prevent situation where new messages // Use a delay before marking as read to prevent situation where new messages
// arrive just as you're leaving the view and messages that you didn't actually // arrive just as you're leaving the view and messages that you didn't actually

View file

@ -98,10 +98,10 @@
.unread-message-count { .unread-message-count {
font-size: 0.8em; font-size: 0.8em;
left: 50%; left: 50%;
transform: translate(-50%, 0);
border-radius: 100%;
margin-top: -1rem; margin-top: -1rem;
padding: 0; padding: 0.1em;
border-radius: 50px;
position: absolute;
} }
.chat-loading-error { .chat-loading-error {

View file

@ -5,6 +5,8 @@
</template> </template>
<script> <script>
import localeService from 'src/services/locale/locale.service.js'
export default { export default {
name: 'Timeago', name: 'Timeago',
props: ['date'], props: ['date'],
@ -16,7 +18,7 @@ export default {
if (this.date.getTime() === today.getTime()) { if (this.date.getTime() === today.getTime()) {
return this.$t('display_date.today') return this.$t('display_date.today')
} else { } else {
return this.date.toLocaleDateString('en', { day: 'numeric', month: 'long' }) return this.date.toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale), { day: 'numeric', month: 'long' })
} }
} }
} }

View file

@ -35,6 +35,18 @@ const chatPanel = {
userProfileLink (user) { userProfileLink (user) {
return generateProfileLink(user.id, user.username, this.$store.state.instance.restrictedNicknames) return generateProfileLink(user.id, user.username, this.$store.state.instance.restrictedNicknames)
} }
},
watch: {
messages (newVal) {
const scrollEl = this.$el.querySelector('.chat-window')
if (!scrollEl) return
if (scrollEl.scrollTop + scrollEl.offsetHeight + 20 > scrollEl.scrollHeight) {
this.$nextTick(() => {
if (!scrollEl) return
scrollEl.scrollTop = scrollEl.scrollHeight - scrollEl.offsetHeight
})
}
}
} }
} }

View file

@ -10,17 +10,15 @@
@click.stop.prevent="togglePanel" @click.stop.prevent="togglePanel"
> >
<div class="title"> <div class="title">
<span>{{ $t('shoutbox.title') }}</span> {{ $t('shoutbox.title') }}
<FAIcon <FAIcon
v-if="floating" v-if="floating"
icon="times" icon="times"
class="close-icon"
/> />
</div> </div>
</div> </div>
<div <div class="chat-window">
v-chat-scroll
class="chat-window"
>
<div <div
v-for="message in messages" v-for="message in messages"
:key="message.id" :key="message.id"
@ -94,6 +92,13 @@
.icon { .icon {
color: $fallback--text; color: $fallback--text;
color: var(--text, $fallback--text); color: var(--text, $fallback--text);
margin-right: 0.5em;
}
.title {
display: flex;
justify-content: space-between;
align-items: center;
} }
} }

View file

@ -12,7 +12,7 @@ export default Vue.component('chat-title', {
], ],
computed: { computed: {
title () { title () {
return this.user ? this.user.screen_name : '' return this.user ? this.user.screen_name_ui : ''
}, },
htmlTitle () { htmlTitle () {
return this.user ? this.user.name_html : '' return this.user ? this.user.name_html : ''

View file

@ -50,7 +50,6 @@
.Conversation { .Conversation {
.conversation-status { .conversation-status {
border-left: none;
border-bottom-width: 1px; border-bottom-width: 1px;
border-bottom-style: solid; border-bottom-style: solid;
border-bottom-color: var(--border, $fallback--border); border-bottom-color: var(--border, $fallback--border);

View file

@ -194,11 +194,18 @@ const EmojiInput = {
} }
}, },
methods: { methods: {
focusPickerInput () {
const pickerEl = this.$refs.picker.$el
if (!pickerEl) return
const pickerInput = pickerEl.querySelector('input')
if (pickerInput) pickerInput.focus()
},
triggerShowPicker () { triggerShowPicker () {
this.showPicker = true this.showPicker = true
this.$refs.picker.startEmojiLoad() this.$refs.picker.startEmojiLoad()
this.$nextTick(() => { this.$nextTick(() => {
this.scrollIntoView() this.scrollIntoView()
this.focusPickerInput()
}) })
// This temporarily disables "click outside" handler // This temporarily disables "click outside" handler
// since external trigger also means click originates // since external trigger also means click originates
@ -214,6 +221,7 @@ const EmojiInput = {
if (this.showPicker) { if (this.showPicker) {
this.scrollIntoView() this.scrollIntoView()
this.$refs.picker.startEmojiLoad() this.$refs.picker.startEmojiLoad()
this.$nextTick(this.focusPickerInput)
} }
}, },
replace (replacement) { replace (replacement) {

View file

@ -9,6 +9,7 @@
<button <button
v-if="!hideEmojiButton" v-if="!hideEmojiButton"
class="button-unstyled emoji-picker-icon" class="button-unstyled emoji-picker-icon"
type="button"
@click.prevent="togglePicker" @click.prevent="togglePicker"
> >
<FAIcon :icon="['far', 'smile-beam']" /> <FAIcon :icon="['far', 'smile-beam']" />

View file

@ -116,8 +116,8 @@ export const suggestUsers = ({ dispatch, state }) => {
return diff + nameAlphabetically + screenNameAlphabetically return diff + nameAlphabetically + screenNameAlphabetically
/* eslint-disable camelcase */ /* eslint-disable camelcase */
}).map(({ screen_name, name, profile_image_url_original }) => ({ }).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
displayText: screen_name, displayText: screen_name_ui,
detailText: name, detailText: name,
imageUrl: profile_image_url_original, imageUrl: profile_image_url_original,
replacement: '@' + screen_name + ' ' replacement: '@' + screen_name + ' '

View file

@ -139,6 +139,11 @@
@import '../../_variables.scss'; @import '../../_variables.scss';
.ExtraButtons { .ExtraButtons {
/* override of popover internal stuff */
.popover-trigger-button {
width: auto;
}
.popover-trigger { .popover-trigger {
position: static; position: static;
padding: 10px; padding: 10px;

View file

@ -12,11 +12,11 @@
v-model="language" v-model="language"
> >
<option <option
v-for="(langCode, i) in languageCodes" v-for="lang in languages"
:key="langCode" :key="lang.code"
:value="langCode" :value="lang.code"
> >
{{ languageNames[i] }} {{ lang.name }}
</option> </option>
</select> </select>
<FAIcon <FAIcon
@ -29,6 +29,7 @@
<script> <script>
import languagesObject from '../../i18n/messages' import languagesObject from '../../i18n/messages'
import localeService from '../../services/locale/locale.service.js'
import ISO6391 from 'iso-639-1' import ISO6391 from 'iso-639-1'
import _ from 'lodash' import _ from 'lodash'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -42,12 +43,8 @@ library.add(
export default { export default {
computed: { computed: {
languageCodes () { languages () {
return languagesObject.languages return _.map(languagesObject.languages, (code) => ({ code: code, name: this.getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
},
languageNames () {
return _.map(this.languageCodes, this.getLanguageName)
}, },
language: { language: {
@ -61,12 +58,13 @@ export default {
methods: { methods: {
getLanguageName (code) { getLanguageName (code) {
const specialLanguageNames = { const specialLanguageNames = {
'ja': 'Japanese (日本語)', 'ja_easy': 'やさしいにほんご',
'ja_easy': 'Japanese (やさしいにほんご)', 'zh': '简体中文',
'zh': 'Simplified Chinese (简体中文)', 'zh_Hant': '繁體中文'
'zh_Hant': 'Traditional Chinese (繁體中文)'
} }
return specialLanguageNames[code] || ISO6391.getName(code) const languageName = specialLanguageNames[code] || ISO6391.getNativeName(code)
const browserLocale = localeService.internalToBrowserLocale(code)
return languageName.charAt(0).toLocaleUpperCase(browserLocale) + languageName.slice(1)
} }
} }
} }

View file

@ -73,11 +73,21 @@
} }
} }
@keyframes media-fadein {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.modal-image { .modal-image {
max-width: 90%; max-width: 90%;
max-height: 90%; max-height: 90%;
box-shadow: 0px 5px 15px 0 rgba(0, 0, 0, 0.5); box-shadow: 0px 5px 15px 0 rgba(0, 0, 0, 0.5);
image-orientation: from-image; // NOTE: only FF supports this image-orientation: from-image; // NOTE: only FF supports this
animation: 0.1s cubic-bezier(0.7, 0, 1, 0.6) media-fadein;
} }
.modal-view-button-arrow { .modal-view-button-arrow {

View file

@ -25,6 +25,7 @@
<div> <div>
<button <button
class="button-unstyled -link" class="button-unstyled -link"
type="button"
@click.prevent="requireTOTP" @click.prevent="requireTOTP"
> >
{{ $t('login.enter_two_factor_code') }} {{ $t('login.enter_two_factor_code') }}
@ -32,6 +33,7 @@
<br> <br>
<button <button
class="button-unstyled -link" class="button-unstyled -link"
type="button"
@click.prevent="abortMFA" @click.prevent="abortMFA"
> >
{{ $t('general.cancel') }} {{ $t('general.cancel') }}

View file

@ -27,6 +27,7 @@
<div> <div>
<button <button
class="button-unstyled -link" class="button-unstyled -link"
type="button"
@click.prevent="requireRecovery" @click.prevent="requireRecovery"
> >
{{ $t('login.enter_recovery_code') }} {{ $t('login.enter_recovery_code') }}
@ -34,6 +35,7 @@
<br> <br>
<button <button
class="button-unstyled -link" class="button-unstyled -link"
type="button"
@click.prevent="abortMFA" @click.prevent="abortMFA"
> >
{{ $t('general.cancel') }} {{ $t('general.cancel') }}

View file

@ -50,74 +50,74 @@
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.FORCE_NSFW)" @click="toggleTag(tags.FORCE_NSFW)"
> >
{{ $t('user_card.admin_menu.force_nsfw') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }" :class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_NSFW) }"
/> />
{{ $t('user_card.admin_menu.force_nsfw') }}
</button> </button>
<button <button
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.STRIP_MEDIA)" @click="toggleTag(tags.STRIP_MEDIA)"
> >
{{ $t('user_card.admin_menu.strip_media') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }" :class="{ 'menu-checkbox-checked': hasTag(tags.STRIP_MEDIA) }"
/> />
{{ $t('user_card.admin_menu.strip_media') }}
</button> </button>
<button <button
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.FORCE_UNLISTED)" @click="toggleTag(tags.FORCE_UNLISTED)"
> >
{{ $t('user_card.admin_menu.force_unlisted') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }" :class="{ 'menu-checkbox-checked': hasTag(tags.FORCE_UNLISTED) }"
/> />
{{ $t('user_card.admin_menu.force_unlisted') }}
</button> </button>
<button <button
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.SANDBOX)" @click="toggleTag(tags.SANDBOX)"
> >
{{ $t('user_card.admin_menu.sandbox') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }" :class="{ 'menu-checkbox-checked': hasTag(tags.SANDBOX) }"
/> />
{{ $t('user_card.admin_menu.sandbox') }}
</button> </button>
<button <button
v-if="user.is_local" v-if="user.is_local"
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)" @click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
> >
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }" :class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_REMOTE_SUBSCRIPTION) }"
/> />
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
</button> </button>
<button <button
v-if="user.is_local" v-if="user.is_local"
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)" @click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
> >
{{ $t('user_card.admin_menu.disable_any_subscription') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }" :class="{ 'menu-checkbox-checked': hasTag(tags.DISABLE_ANY_SUBSCRIPTION) }"
/> />
{{ $t('user_card.admin_menu.disable_any_subscription') }}
</button> </button>
<button <button
v-if="user.is_local" v-if="user.is_local"
class="button-default dropdown-item" class="button-default dropdown-item"
@click="toggleTag(tags.QUARANTINE)" @click="toggleTag(tags.QUARANTINE)"
> >
{{ $t('user_card.admin_menu.quarantine') }}
<span <span
class="menu-checkbox" class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }" :class="{ 'menu-checkbox-checked': hasTag(tags.QUARANTINE) }"
/> />
{{ $t('user_card.admin_menu.quarantine') }}
</button> </button>
</span> </span>
</div> </div>
@ -163,25 +163,6 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.menu-checkbox {
float: right;
min-width: 22px;
max-width: 22px;
min-height: 22px;
max-height: 22px;
line-height: 22px;
text-align: center;
border-radius: 0px;
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
box-shadow: 0px 0px 2px black inset;
box-shadow: var(--inputShadow);
&.menu-checkbox-checked::after {
content: '✓';
}
}
.moderation-tools-popover { .moderation-tools-popover {
height: 100%; height: 100%;
.trigger { .trigger {

View file

@ -11,7 +11,7 @@
> >
<small> <small>
<router-link :to="userProfileLink"> <router-link :to="userProfileLink">
{{ notification.from_profile.screen_name }} {{ notification.from_profile.screen_name_ui }}
</router-link> </router-link>
</small> </small>
<button <button
@ -54,14 +54,14 @@
<bdi <bdi
v-if="!!notification.from_profile.name_html" v-if="!!notification.from_profile.name_html"
class="username" class="username"
:title="'@'+notification.from_profile.screen_name" :title="'@'+notification.from_profile.screen_name_ui"
v-html="notification.from_profile.name_html" v-html="notification.from_profile.name_html"
/> />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<span <span
v-else v-else
class="username" class="username"
:title="'@'+notification.from_profile.screen_name" :title="'@'+notification.from_profile.screen_name_ui"
>{{ notification.from_profile.name }}</span> >{{ notification.from_profile.name }}</span>
<span v-if="notification.type === 'like'"> <span v-if="notification.type === 'like'">
<FAIcon <FAIcon
@ -152,7 +152,7 @@
:to="userProfileLink" :to="userProfileLink"
class="follow-name" class="follow-name"
> >
@{{ notification.from_profile.screen_name }} @{{ notification.from_profile.screen_name_ui }}
</router-link> </router-link>
<div <div
v-if="notification.type === 'follow_request'" v-if="notification.type === 'follow_request'"
@ -177,7 +177,7 @@
class="move-text" class="move-text"
> >
<router-link :to="targetUserProfileLink"> <router-link :to="targetUserProfileLink">
@{{ notification.target.screen_name }} @{{ notification.target.screen_name_ui }}
</router-link> </router-link>
</div> </div>
<template v-else> <template v-else>

View file

@ -58,7 +58,12 @@
{{ $t('polls.vote') }} {{ $t('polls.vote') }}
</button> </button>
<div class="total"> <div class="total">
{{ totalVotesCount }} {{ $t("polls.votes") }}&nbsp;·&nbsp; <template v-if="typeof poll.voters_count === 'number'">
{{ $tc("polls.people_voted_count", poll.voters_count, { count: poll.voters_count }) }}&nbsp;·&nbsp;
</template>
<template v-else>
{{ $tc("polls.votes_count", poll.votes_count, { count: poll.votes_count }) }}&nbsp;·&nbsp;
</template>
</div> </div>
<i18n :path="expired ? 'polls.expired' : 'polls.expires_in'"> <i18n :path="expired ? 'polls.expired' : 'polls.expires_in'">
<Timeago <Timeago

View file

@ -21,20 +21,17 @@
@keydown.enter.stop.prevent="nextOption(index)" @keydown.enter.stop.prevent="nextOption(index)"
> >
</div> </div>
<div <button
v-if="options.length > 2" v-if="options.length > 2"
class="icon-container" class="delete-option button-unstyled -hover-highlight"
>
<FAIcon
icon="times"
class="delete"
@click="deleteOption(index)" @click="deleteOption(index)"
/> >
<FAIcon icon="times" />
</button>
</div> </div>
</div> <button
<a
v-if="options.length < maxOptions" v-if="options.length < maxOptions"
class="add-option faint" class="add-option faint button-unstyled -hover-highlight"
@click="addOption" @click="addOption"
> >
<FAIcon <FAIcon
@ -43,7 +40,7 @@
/> />
{{ $t("polls.add_option") }} {{ $t("polls.add_option") }}
</a> </button>
<div class="poll-type-expiry"> <div class="poll-type-expiry">
<div <div
class="poll-type" class="poll-type"
@ -116,7 +113,6 @@
align-self: flex-start; align-self: flex-start;
padding-top: 0.25em; padding-top: 0.25em;
padding-left: 0.1em; padding-left: 0.1em;
cursor: pointer;
} }
.poll-option { .poll-option {
@ -135,19 +131,11 @@
} }
} }
.icon-container { .delete-option {
// Hack: Move the icon over the input box // Hack: Move the icon over the input box
width: 1.5em; width: 1.5em;
margin-left: -1.5em; margin-left: -1.5em;
z-index: 1; z-index: 1;
.delete {
cursor: pointer;
&:hover {
color: inherit;
}
}
} }
.poll-type-expiry { .poll-type-expiry {
@ -163,6 +151,7 @@
border: none; border: none;
box-shadow: none; box-shadow: none;
background-color: transparent; background-color: transparent;
padding-right: 0.75em;
} }
} }

View file

@ -3,25 +3,32 @@ const Popover = {
props: { props: {
// Action to trigger popover: either 'hover' or 'click' // Action to trigger popover: either 'hover' or 'click'
trigger: String, trigger: String,
// Either 'top' or 'bottom' // Either 'top' or 'bottom'
placement: String, placement: String,
// Takes object with properties 'x' and 'y', values of these can be // Takes object with properties 'x' and 'y', values of these can be
// 'container' for using offsetParent as boundaries for either axis // 'container' for using offsetParent as boundaries for either axis
// or 'viewport' // or 'viewport'
boundTo: Object, boundTo: Object,
// Takes a selector to use as a replacement for the parent container // Takes a selector to use as a replacement for the parent container
// for getting boundaries for x an y axis // for getting boundaries for x an y axis
boundToSelector: String, boundToSelector: String,
// Takes a top/bottom/left/right object, how much space to leave // Takes a top/bottom/left/right object, how much space to leave
// between boundary and popover element // between boundary and popover element
margin: Object, margin: Object,
// Takes a x/y object and tells how many pixels to offset from // Takes a x/y object and tells how many pixels to offset from
// anchor point on either axis // anchor point on either axis
offset: Object, offset: Object,
// Replaces the classes you may want for the popover container. // Replaces the classes you may want for the popover container.
// Use 'popover-default' in addition to get the default popover // Use 'popover-default' in addition to get the default popover
// styles with your custom class. // styles with your custom class.
popoverClass: String, popoverClass: String,
// If true, subtract padding when calculating position for the popover, // If true, subtract padding when calculating position for the popover,
// use it when popover offset looks to be different on top vs bottom. // use it when popover offset looks to be different on top vs bottom.
removePadding: Boolean removePadding: Boolean
@ -121,9 +128,12 @@ const Popover = {
} }
}, },
showPopover () { showPopover () {
if (this.hidden) this.$emit('show') const wasHidden = this.hidden
this.hidden = false this.hidden = false
this.$nextTick(this.updateStyles) this.$nextTick(() => {
if (wasHidden) this.$emit('show')
this.updateStyles()
})
}, },
hidePopover () { hidePopover () {
if (!this.hidden) this.$emit('close') if (!this.hidden) this.$emit('close')

View file

@ -6,6 +6,7 @@
<button <button
ref="trigger" ref="trigger"
class="button-unstyled -fullwidth popover-trigger-button" class="button-unstyled -fullwidth popover-trigger-button"
type="button"
@click="onClick" @click="onClick"
> >
<slot name="trigger" /> <slot name="trigger" />
@ -81,10 +82,9 @@
.dropdown-item { .dropdown-item {
line-height: 21px; line-height: 21px;
margin-right: 5px;
overflow: auto; overflow: auto;
display: block; display: block;
padding: .25rem 1.0rem .25rem 1.5rem; padding: .5em 0.75em;
clear: both; clear: both;
font-weight: 400; font-weight: 400;
text-align: inherit; text-align: inherit;
@ -100,10 +100,9 @@
--btnText: var(--popoverText, $fallback--text); --btnText: var(--popoverText, $fallback--text);
&-icon { &-icon {
padding-left: 0.5rem;
svg { svg {
margin-right: 0.25rem; width: 22px;
margin-right: 0.75rem;
color: var(--menuPopoverIcon, $fallback--icon) color: var(--menuPopoverIcon, $fallback--icon)
} }
} }
@ -122,6 +121,33 @@
} }
} }
.menu-checkbox {
display: inline-block;
vertical-align: middle;
min-width: 22px;
max-width: 22px;
min-height: 22px;
max-height: 22px;
line-height: 22px;
text-align: center;
border-radius: 0px;
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
box-shadow: 0px 0px 2px black inset;
box-shadow: var(--inputShadow);
margin-right: 0.75em;
&.menu-checkbox-checked::after {
font-size: 1.25em;
content: '✓';
}
&.menu-checkbox-radio::after {
font-size: 2em;
content: '•';
}
}
} }
} }
</style> </style>

View file

@ -115,7 +115,7 @@ const PostStatusForm = {
? this.copyMessageScope ? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope : this.$store.state.users.currentUser.default_scope
const { postContentType: contentType } = this.$store.getters.mergedConfig const { postContentType: contentType, sensitiveByDefault } = this.$store.getters.mergedConfig
return { return {
dropFiles: [], dropFiles: [],
@ -126,7 +126,7 @@ const PostStatusForm = {
newStatus: { newStatus: {
spoilerText: this.subject || '', spoilerText: this.subject || '',
status: statusText, status: statusText,
nsfw: false, nsfw: !!sensitiveByDefault,
files: [], files: [],
poll: {}, poll: {},
mediaDescriptions: {}, mediaDescriptions: {},

View file

@ -302,11 +302,12 @@
:key="file.url" :key="file.url"
class="media-upload-wrapper" class="media-upload-wrapper"
> >
<FAIcon <button
class="fa-scale-110 fa-old-padding" class="button-unstyled hider"
icon="times"
@click="removeMediaFile(file)" @click="removeMediaFile(file)"
/> >
<FAIcon icon="times" />
</button>
<attachment <attachment
:attachment="file" :attachment="file"
:set-media="() => $store.dispatch('setMedia', newStatus.files)" :set-media="() => $store.dispatch('setMedia', newStatus.files)"
@ -516,26 +517,11 @@
} }
.attachments .media-upload-wrapper { .attachments .media-upload-wrapper {
padding: 0 0.5em; position: relative;
.attachment { .attachment {
margin: 0; margin: 0;
padding: 0; padding: 0;
position: relative;
}
.fa-scale-110 fa-old-padding {
position: absolute;
margin: 10px;
margin: .75em;
padding: .5em;
background: rgba(230,230,230,0.6);
z-index: 2;
color: black;
border-radius: $fallback--attachmentRadius;
border-radius: var(--attachmentRadius, $fallback--attachmentRadius);
font-weight: bold;
cursor: pointer;
} }
} }

View file

@ -23,6 +23,12 @@ const ReactButton = {
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
} }
close() close()
},
focusInput () {
this.$nextTick(() => {
const input = this.$el.querySelector('input')
if (input) input.focus()
})
} }
}, },
computed: { computed: {

View file

@ -1,10 +1,12 @@
<template> <template>
<Popover <Popover
trigger="click" trigger="click"
class="ReactButton"
placement="top" placement="top"
:offset="{ y: 5 }" :offset="{ y: 5 }"
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
remove-padding remove-padding
@show="focusInput"
> >
<div <div
slot="content" slot="content"
@ -42,7 +44,7 @@
</div> </div>
<span <span
slot="trigger" slot="trigger"
class="ReactButton" class="popover-trigger"
:title="$t('tool_tip.add_reaction')" :title="$t('tool_tip.add_reaction')"
> >
<FAIcon <FAIcon
@ -58,22 +60,24 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.reaction-picker-filter { .ReactButton {
.reaction-picker-filter {
padding: 0.5em; padding: 0.5em;
display: flex; display: flex;
input { input {
flex: 1; flex: 1;
} }
} }
.reaction-picker-divider { .reaction-picker-divider {
height: 1px; height: 1px;
width: 100%; width: 100%;
margin: 0.5em; margin: 0.5em;
background-color: var(--border, $fallback--border); background-color: var(--border, $fallback--border);
} }
.reaction-picker { .reaction-picker {
width: 10em; width: 10em;
height: 9em; height: 9em;
font-size: 1.5em; font-size: 1.5em;
@ -90,7 +94,8 @@
linear-gradient(to top, white, white); linear-gradient(to top, white, white);
transition: mask-size 150ms; transition: mask-size 150ms;
mask-size: 100% 20px, 100% 20px, auto; mask-size: 100% 20px, 100% 20px, auto;
// Autoprefixed seem to ignore this one, and also syntax is different
/* Autoprefixed seem to ignore this one, and also syntax is different */
-webkit-mask-composite: xor; -webkit-mask-composite: xor;
mask-composite: exclude; mask-composite: exclude;
@ -105,9 +110,14 @@
transform: scale(1.25); transform: scale(1.25);
} }
} }
} }
.ReactButton { /* override of popover internal stuff */
.popover-trigger-button {
width: auto;
}
.popover-trigger {
padding: 10px; padding: 10px;
margin: -10px; margin: -10px;
@ -115,6 +125,7 @@
color: $fallback--text; color: $fallback--text;
color: var(--text, $fallback--text); color: var(--text, $fallback--text);
} }
}
} }
</style> </style>

View file

@ -10,7 +10,8 @@ const registration = {
fullname: '', fullname: '',
username: '', username: '',
password: '', password: '',
confirm: '' confirm: '',
reason: ''
}, },
captcha: {} captcha: {}
}), }),
@ -24,7 +25,8 @@ const registration = {
confirm: { confirm: {
required, required,
sameAsPassword: sameAs('password') sameAsPassword: sameAs('password')
} },
reason: { required: requiredIf(() => this.accountApprovalRequired) }
} }
} }
}, },
@ -38,7 +40,10 @@ const registration = {
computed: { computed: {
token () { return this.$route.params.token }, token () { return this.$route.params.token },
bioPlaceholder () { bioPlaceholder () {
return this.$t('registration.bio_placeholder').replace(/\s*\n\s*/g, ' \n') return this.replaceNewlines(this.$t('registration.bio_placeholder'))
},
reasonPlaceholder () {
return this.replaceNewlines(this.$t('registration.reason_placeholder'))
}, },
...mapState({ ...mapState({
registrationOpen: (state) => state.instance.registrationOpen, registrationOpen: (state) => state.instance.registrationOpen,
@ -46,7 +51,8 @@ const registration = {
isPending: (state) => state.users.signUpPending, isPending: (state) => state.users.signUpPending,
serverValidationErrors: (state) => state.users.signUpErrors, serverValidationErrors: (state) => state.users.signUpErrors,
termsOfService: (state) => state.instance.tos, termsOfService: (state) => state.instance.tos,
accountActivationRequired: (state) => state.instance.accountActivationRequired accountActivationRequired: (state) => state.instance.accountActivationRequired,
accountApprovalRequired: (state) => state.instance.accountApprovalRequired
}) })
}, },
methods: { methods: {
@ -73,6 +79,9 @@ const registration = {
}, },
setCaptcha () { setCaptcha () {
this.getCaptcha().then(cpt => { this.captcha = cpt }) this.getCaptcha().then(cpt => { this.captcha = cpt })
},
replaceNewlines (str) {
return str.replace(/\s*\n\s*/g, ' \n')
} }
} }
} }

View file

@ -162,6 +162,23 @@
</ul> </ul>
</div> </div>
<div
v-if="accountApprovalRequired"
class="form-group"
>
<label
class="form--label"
for="reason"
>{{ $t('registration.reason') }}</label>
<textarea
id="reason"
v-model="user.reason"
:disabled="isPending"
class="form-control"
:placeholder="reasonPlaceholder"
/>
</div>
<div <div
v-if="captcha.type != 'none'" v-if="captcha.type != 'none'"
id="captcha-group" id="captcha-group"

View file

@ -8,6 +8,7 @@
class="button-unstyled scope" class="button-unstyled scope"
:class="css.direct" :class="css.direct"
:title="$t('post_status.scope.direct')" :title="$t('post_status.scope.direct')"
type="button"
@click="changeVis('direct')" @click="changeVis('direct')"
> >
<FAIcon <FAIcon
@ -20,6 +21,7 @@
class="button-unstyled scope" class="button-unstyled scope"
:class="css.private" :class="css.private"
:title="$t('post_status.scope.private')" :title="$t('post_status.scope.private')"
type="button"
@click="changeVis('private')" @click="changeVis('private')"
> >
<FAIcon <FAIcon
@ -32,6 +34,7 @@
class="button-unstyled scope" class="button-unstyled scope"
:class="css.unlisted" :class="css.unlisted"
:title="$t('post_status.scope.unlisted')" :title="$t('post_status.scope.unlisted')"
type="button"
@click="changeVis('unlisted')" @click="changeVis('unlisted')"
> >
<FAIcon <FAIcon
@ -44,6 +47,7 @@
class="button-unstyled scope" class="button-unstyled scope"
:class="css.public" :class="css.public"
:title="$t('post_status.scope.public')" :title="$t('post_status.scope.public')"
type="button"
@click="changeVis('public')" @click="changeVis('public')"
> >
<FAIcon <FAIcon

View file

@ -15,6 +15,7 @@
> >
<button <button
class="btn button-default search-button" class="btn button-default search-button"
type="submit"
@click="newQuery(searchTerm)" @click="newQuery(searchTerm)"
> >
<FAIcon icon="search" /> <FAIcon icon="search" />

View file

@ -7,6 +7,7 @@
v-if="hidden" v-if="hidden"
class="button-unstyled nav-icon" class="button-unstyled nav-icon"
:title="$t('nav.search')" :title="$t('nav.search')"
type="button"
@click.prevent.stop="toggleHidden" @click.prevent.stop="toggleHidden"
> >
<FAIcon <FAIcon
@ -27,6 +28,7 @@
> >
<button <button
class="button-default search-button" class="button-default search-button"
type="submit"
@click="find(searchTerm)" @click="find(searchTerm)"
> >
<FAIcon <FAIcon
@ -36,6 +38,7 @@
</button> </button>
<button <button
class="button-unstyled cancel-search" class="button-unstyled cancel-search"
type="button"
@click.prevent.stop="toggleHidden" @click.prevent.stop="toggleHidden"
> >
<FAIcon <FAIcon

View file

@ -0,0 +1,57 @@
<template>
<label
class="BooleanSetting"
>
<Checkbox
:checked="state"
:disabled="disabled"
@change="update"
>
<span
v-if="!!$slots.default"
class="label"
>
<slot />
</span>
<ModifiedIndicator :changed="isChanged" />
</Checkbox>
</label>
</template>
<script>
import { get, set } from 'lodash'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import ModifiedIndicator from './modified_indicator.vue'
export default {
components: {
Checkbox,
ModifiedIndicator
},
props: [
'path',
'disabled'
],
computed: {
pathDefault () {
const [firstSegment, ...rest] = this.path.split('.')
return [firstSegment + 'DefaultValue', ...rest].join('.')
},
state () {
return get(this.$parent, this.path)
},
isChanged () {
return get(this.$parent, this.path) !== get(this.$parent, this.pathDefault)
}
},
methods: {
update (e) {
set(this.$parent, this.path, e)
}
}
}
</script>
<style lang="scss">
.BooleanSetting {
}
</style>

View file

@ -0,0 +1,51 @@
<template>
<span
v-if="changed"
class="ModifiedIndicator"
>
<Popover
trigger="hover"
>
<span slot="trigger">
&nbsp;
<FAIcon
icon="wrench"
/>
</span>
<div
slot="content"
class="modified-tooltip"
>
{{ $t('settings.setting_changed') }}
</div>
</Popover>
</span>
</template>
<script>
import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faWrench } from '@fortawesome/free-solid-svg-icons'
library.add(
faWrench
)
export default {
components: { Popover },
props: ['changed']
}
</script>
<style lang="scss">
.ModifiedIndicator {
display: inline-block;
position: relative;
.modified-tooltip {
margin: 0.5em 1em;
min-width: 10em;
text-align: center;
}
}
</style>

View file

@ -1,29 +1,15 @@
import { import { defaultState as configDefaultState } from 'src/modules/config.js'
instanceDefaultProperties,
multiChoiceProperties,
defaultState as configDefaultState
} from 'src/modules/config.js'
const SharedComputedObject = () => ({ const SharedComputedObject = () => ({
user () { user () {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
// Getting localized values for instance-default properties // Getting values for default properties
...instanceDefaultProperties ...Object.keys(configDefaultState)
.filter(key => multiChoiceProperties.includes(key))
.map(key => [ .map(key => [
key + 'DefaultValue', key + 'DefaultValue',
function () { function () {
return this.$store.getters.instanceDefaultConfig[key] return this.$store.getters.defaultConfig[key]
}
])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
...instanceDefaultProperties
.filter(key => !multiChoiceProperties.includes(key))
.map(key => [
key + 'LocalizedValue',
function () {
return this.$t('settings.values.' + this.$store.getters.instanceDefaultConfig[key])
} }
]) ])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}), .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),

View file

@ -1,5 +1,5 @@
import { filter, trim } from 'lodash' import { filter, trim } from 'lodash'
import Checkbox from 'src/components/checkbox/checkbox.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@ -18,7 +18,7 @@ const FilteringTab = {
} }
}, },
components: { components: {
Checkbox BooleanSetting
}, },
computed: { computed: {
...SharedComputedObject(), ...SharedComputedObject(),

View file

@ -5,34 +5,34 @@
<span class="label">{{ $t('settings.notification_visibility') }}</span> <span class="label">{{ $t('settings.notification_visibility') }}</span>
<ul class="option-list"> <ul class="option-list">
<li> <li>
<Checkbox v-model="notificationVisibility.likes"> <BooleanSetting path="notificationVisibility.likes">
{{ $t('settings.notification_visibility_likes') }} {{ $t('settings.notification_visibility_likes') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="notificationVisibility.repeats"> <BooleanSetting path="notificationVisibility.repeats">
{{ $t('settings.notification_visibility_repeats') }} {{ $t('settings.notification_visibility_repeats') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="notificationVisibility.follows"> <BooleanSetting path="notificationVisibility.follows">
{{ $t('settings.notification_visibility_follows') }} {{ $t('settings.notification_visibility_follows') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="notificationVisibility.mentions"> <BooleanSetting path="notificationVisibility.mentions">
{{ $t('settings.notification_visibility_mentions') }} {{ $t('settings.notification_visibility_mentions') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="notificationVisibility.moves"> <BooleanSetting path="notificationVisibility.moves">
{{ $t('settings.notification_visibility_moves') }} {{ $t('settings.notification_visibility_moves') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="notificationVisibility.emojiReactions"> <BooleanSetting path="notificationVisibility.emojiReactions">
{{ $t('settings.notification_visibility_emoji_reactions') }} {{ $t('settings.notification_visibility_emoji_reactions') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>
@ -60,14 +60,14 @@
</label> </label>
</div> </div>
<div> <div>
<Checkbox v-model="hidePostStats"> <BooleanSetting path="hidePostStats">
{{ $t('settings.hide_post_stats') }} {{ $t('settings.instance_default', { value: hidePostStatsLocalizedValue }) }} {{ $t('settings.hide_post_stats') }}
</Checkbox> </BooleanSetting>
</div> </div>
<div> <div>
<Checkbox v-model="hideUserStats"> <BooleanSetting path="hideUserStats">
{{ $t('settings.hide_user_stats') }} {{ $t('settings.instance_default', { value: hideUserStatsLocalizedValue }) }} {{ $t('settings.hide_user_stats') }}
</Checkbox> </BooleanSetting>
</div> </div>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@ -75,14 +75,14 @@
<p>{{ $t('settings.filtering_explanation') }}</p> <p>{{ $t('settings.filtering_explanation') }}</p>
<textarea <textarea
id="muteWords" id="muteWords"
class="resize-height"
v-model="muteWordsString" v-model="muteWordsString"
class="resize-height"
/> />
</div> </div>
<div> <div>
<Checkbox v-model="hideFilteredStatuses"> <BooleanSetting path="hideFilteredStatuses">
{{ $t('settings.hide_filtered_statuses') }} {{ $t('settings.instance_default', { value: hideFilteredStatusesLocalizedValue }) }} {{ $t('settings.hide_filtered_statuses') }}
</Checkbox> </BooleanSetting>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,4 +1,4 @@
import Checkbox from 'src/components/checkbox/checkbox.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue' import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
@ -26,7 +26,7 @@ const GeneralTab = {
} }
}, },
components: { components: {
Checkbox, BooleanSetting,
InterfaceLanguageSwitcher InterfaceLanguageSwitcher
}, },
computed: { computed: {

View file

@ -7,14 +7,14 @@
<interface-language-switcher /> <interface-language-switcher />
</li> </li>
<li v-if="instanceSpecificPanelPresent"> <li v-if="instanceSpecificPanelPresent">
<Checkbox v-model="hideISP"> <BooleanSetting path="hideISP">
{{ $t('settings.hide_isp') }} {{ $t('settings.hide_isp') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li v-if="instanceWallpaperUsed"> <li v-if="instanceWallpaperUsed">
<Checkbox v-model="hideInstanceWallpaper"> <BooleanSetting path="hideInstanceWallpaper">
{{ $t('settings.hide_wallpaper') }} {{ $t('settings.hide_wallpaper') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>
@ -22,51 +22,51 @@
<h2>{{ $t('nav.timeline') }}</h2> <h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<Checkbox v-model="hideMutedPosts"> <BooleanSetting path="hideMutedPosts">
{{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsLocalizedValue }) }} {{ $t('settings.hide_muted_posts') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="collapseMessageWithSubject"> <BooleanSetting path="collapseMessageWithSubject">
{{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectLocalizedValue }) }} {{ $t('settings.collapse_subject') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="streaming"> <BooleanSetting path="streaming">
{{ $t('settings.streaming') }} {{ $t('settings.streaming') }}
</Checkbox> </BooleanSetting>
<ul <ul
class="setting-list suboptions" class="setting-list suboptions"
:class="[{disabled: !streaming}]" :class="[{disabled: !streaming}]"
> >
<li> <li>
<Checkbox <BooleanSetting
v-model="pauseOnUnfocused" path="pauseOnUnfocused"
:disabled="!streaming" :disabled="!streaming"
> >
{{ $t('settings.pause_on_unfocused') }} {{ $t('settings.pause_on_unfocused') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</li> </li>
<li> <li>
<Checkbox v-model="useStreamingApi"> <BooleanSetting path="useStreamingApi">
{{ $t('settings.useStreamingApi') }} {{ $t('settings.useStreamingApi') }}
<br> <br>
<small> <small>
{{ $t('settings.useStreamingApiWarning') }} {{ $t('settings.useStreamingApiWarning') }}
</small> </small>
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="emojiReactionsOnTimeline"> <BooleanSetting path="emojiReactionsOnTimeline">
{{ $t('settings.emoji_reactions_on_timeline') }} {{ $t('settings.emoji_reactions_on_timeline') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="virtualScrolling"> <BooleanSetting path="virtualScrolling">
{{ $t('settings.virtual_scrolling') }} {{ $t('settings.virtual_scrolling') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>
@ -75,14 +75,14 @@
<h2>{{ $t('settings.composing') }}</h2> <h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<Checkbox v-model="scopeCopy"> <BooleanSetting path="scopeCopy">
{{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyLocalizedValue }) }} {{ $t('settings.scope_copy') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="alwaysShowSubjectInput"> <BooleanSetting path="alwaysShowSubjectInput">
{{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputLocalizedValue }) }} {{ $t('settings.subject_input_always_show') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<div> <div>
@ -143,19 +143,24 @@
</div> </div>
</li> </li>
<li> <li>
<Checkbox v-model="minimalScopesMode"> <BooleanSetting path="minimalScopesMode">
{{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeLocalizedValue }) }} {{ $t('settings.minimal_scopes_mode') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="autohideFloatingPostButton"> <BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="autohideFloatingPostButton">
{{ $t('settings.autohide_floating_post_button') }} {{ $t('settings.autohide_floating_post_button') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="padEmoji"> <BooleanSetting path="padEmoji">
{{ $t('settings.pad_emoji') }} {{ $t('settings.pad_emoji') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>
@ -164,14 +169,14 @@
<h2>{{ $t('settings.attachments') }}</h2> <h2>{{ $t('settings.attachments') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<Checkbox v-model="hideAttachments"> <BooleanSetting path="hideAttachments">
{{ $t('settings.hide_attachments_in_tl') }} {{ $t('settings.hide_attachments_in_tl') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="hideAttachmentsInConv"> <BooleanSetting path="hideAttachmentsInConv">
{{ $t('settings.hide_attachments_in_convo') }} {{ $t('settings.hide_attachments_in_convo') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<label for="maxThumbnails"> <label for="maxThumbnails">
@ -179,7 +184,7 @@
</label> </label>
<input <input
id="maxThumbnails" id="maxThumbnails"
v-model.number="maxThumbnails" path.number="maxThumbnails"
class="number-input" class="number-input"
type="number" type="number"
min="0" min="0"
@ -187,48 +192,48 @@
> >
</li> </li>
<li> <li>
<Checkbox v-model="hideNsfw"> <BooleanSetting path="hideNsfw">
{{ $t('settings.nsfw_clickthrough') }} {{ $t('settings.nsfw_clickthrough') }}
</Checkbox> </BooleanSetting>
</li> </li>
<ul class="setting-list suboptions"> <ul class="setting-list suboptions">
<li> <li>
<Checkbox <BooleanSetting
v-model="preloadImage" path="preloadImage"
:disabled="!hideNsfw" :disabled="!hideNsfw"
> >
{{ $t('settings.preload_images') }} {{ $t('settings.preload_images') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox <BooleanSetting
v-model="useOneClickNsfw" path="useOneClickNsfw"
:disabled="!hideNsfw" :disabled="!hideNsfw"
> >
{{ $t('settings.use_one_click_nsfw') }} {{ $t('settings.use_one_click_nsfw') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
<li> <li>
<Checkbox v-model="stopGifs"> <BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }} {{ $t('settings.stop_gifs') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="loopVideo"> <BooleanSetting path="loopVideo">
{{ $t('settings.loop_video') }} {{ $t('settings.loop_video') }}
</Checkbox> </BooleanSetting>
<ul <ul
class="setting-list suboptions" class="setting-list suboptions"
:class="[{disabled: !streaming}]" :class="[{disabled: !streaming}]"
> >
<li> <li>
<Checkbox <BooleanSetting
v-model="loopVideoSilentOnly" path="loopVideoSilentOnly"
:disabled="!loopVideo || !loopSilentAvailable" :disabled="!loopVideo || !loopSilentAvailable"
> >
{{ $t('settings.loop_video_silent_only') }} {{ $t('settings.loop_video_silent_only') }}
</Checkbox> </BooleanSetting>
<div <div
v-if="!loopSilentAvailable" v-if="!loopSilentAvailable"
class="unavailable" class="unavailable"
@ -239,14 +244,14 @@
</ul> </ul>
</li> </li>
<li> <li>
<Checkbox v-model="playVideosInModal"> <BooleanSetting path="playVideosInModal">
{{ $t('settings.play_videos_in_modal') }} {{ $t('settings.play_videos_in_modal') }}
</Checkbox> </BooleanSetting>
</li> </li>
<li> <li>
<Checkbox v-model="useContainFit"> <BooleanSetting path="useContainFit">
{{ $t('settings.use_contain_fit') }} {{ $t('settings.use_contain_fit') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>
@ -255,9 +260,9 @@
<h2>{{ $t('settings.notifications') }}</h2> <h2>{{ $t('settings.notifications') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<Checkbox v-model="webPushNotifications"> <BooleanSetting path="webPushNotifications">
{{ $t('settings.enable_web_push_notifications') }} {{ $t('settings.enable_web_push_notifications') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>
@ -266,9 +271,9 @@
<h2>{{ $t('settings.fun') }}</h2> <h2>{{ $t('settings.fun') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<Checkbox v-model="greentext"> <BooleanSetting path="greentext">
{{ $t('settings.greentext') }} {{ $t('settings.instance_default', { value: greentextLocalizedValue }) }} {{ $t('settings.greentext') }}
</Checkbox> </BooleanSetting>
</li> </li>
</ul> </ul>
</div> </div>

View file

@ -111,16 +111,17 @@
.profile-fields { .profile-fields {
display: flex; display: flex;
&>.emoji-input { & > .emoji-input {
flex: 1 1 auto; flex: 1 1 auto;
margin: 0 .2em .5em; margin: 0 0.2em 0.5em;
min-width: 0; min-width: 0;
} }
&>.icon-container { .delete-field {
width: 20px; width: 20px;
align-self: center; align-self: center;
margin: 0 .2em .5em; margin: 0 0.2em 0.5em;
padding: 0 0.5em;
} }
} }
} }

View file

@ -124,24 +124,24 @@
:placeholder="$t('settings.profile_fields.value')" :placeholder="$t('settings.profile_fields.value')"
> >
</EmojiInput> </EmojiInput>
<div <button
class="icon-container" class="delete-field button-unstyled -hover-highlight"
@click="deleteField(i)"
> >
<FAIcon <FAIcon
v-show="newFields.length > 1" v-show="newFields.length > 1"
icon="times" icon="times"
@click="deleteField(i)"
/> />
</button>
</div> </div>
</div> <button
<a
v-if="newFields.length < maxFields" v-if="newFields.length < maxFields"
class="add-field faint" class="add-field faint button-unstyled -hover-highlight"
@click="addField" @click="addField"
> >
<FAIcon icon="plus" /> <FAIcon icon="plus" />
{{ $t("settings.profile_fields.add_field") }} {{ $t("settings.profile_fields.add_field") }}
</a> </button>
</div> </div>
<p> <p>
<Checkbox v-model="bot"> <Checkbox v-model="bot">

View file

@ -1,6 +1,7 @@
import ProgressButton from 'src/components/progress_button/progress_button.vue' import ProgressButton from 'src/components/progress_button/progress_button.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Mfa from './mfa.vue' import Mfa from './mfa.vue'
import localeService from 'src/services/locale/locale.service.js'
const SecurityTab = { const SecurityTab = {
data () { data () {
@ -37,7 +38,7 @@ const SecurityTab = {
return { return {
id: oauthToken.id, id: oauthToken.id,
appName: oauthToken.app_name, appName: oauthToken.app_name,
validUntil: new Date(oauthToken.valid_until).toLocaleDateString() validUntil: new Date(oauthToken.valid_until).toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale))
} }
}) })
} }

View file

@ -109,7 +109,7 @@
v-if="chat" v-if="chat"
@click="toggleDrawer" @click="toggleDrawer"
> >
<router-link :to="{ name: 'chat' }"> <router-link :to="{ name: 'chat-panel' }">
<FAIcon <FAIcon
fixed-width fixed-width
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"

View file

@ -1,4 +1,6 @@
import map from 'lodash/map' import map from 'lodash/map'
import groupBy from 'lodash/groupBy'
import { mapGetters, mapState } from 'vuex'
import BasicUserCard from '../basic_user_card/basic_user_card.vue' import BasicUserCard from '../basic_user_card/basic_user_card.vue'
const StaffPanel = { const StaffPanel = {
@ -10,9 +12,21 @@ const StaffPanel = {
BasicUserCard BasicUserCard
}, },
computed: { computed: {
staffAccounts () { groupedStaffAccounts () {
return map(this.$store.state.instance.staffAccounts, nickname => this.$store.getters.findUser(nickname)).filter(_ => _) const staffAccounts = map(this.staffAccounts, this.findUser).filter(_ => _)
} const groupedStaffAccounts = groupBy(staffAccounts, 'role')
return [
{ role: 'admin', users: groupedStaffAccounts['admin'] },
{ role: 'moderator', users: groupedStaffAccounts['moderator'] }
].filter(group => group.users)
},
...mapGetters([
'findUser'
]),
...mapState({
staffAccounts: state => state.instance.staffAccounts
})
} }
} }

View file

@ -7,17 +7,34 @@
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div
v-for="group in groupedStaffAccounts"
:key="group.role"
class="staff-group"
>
<h4>{{ $t('general.role.' + group.role) }}</h4>
<basic-user-card <basic-user-card
v-for="user in staffAccounts" v-for="user in group.users"
:key="user.screen_name" :key="user.screen_name"
:user="user" :user="user"
/> />
</div> </div>
</div> </div>
</div> </div>
</div>
</template> </template>
<script src="./staff_panel.js" ></script> <script src="./staff_panel.js" ></script>
<style lang="scss"> <style lang="scss">
.staff-group {
padding-left: 1em;
padding-top: 1em;
.basic-user-card {
padding-left: 0;
}
}
</style> </style>

View file

@ -136,7 +136,7 @@ const Status = {
} }
}, },
retweet () { return !!this.statusoid.retweeted_status }, retweet () { return !!this.statusoid.retweeted_status },
retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name }, retweeter () { return this.statusoid.user.name || this.statusoid.user.screen_name_ui },
retweeterHtml () { return this.statusoid.user.name_html }, retweeterHtml () { return this.statusoid.user.name_html },
retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) }, retweeterProfileLink () { return this.generateUserProfileLink(this.statusoid.user.id, this.statusoid.user.screen_name) },
status () { status () {
@ -157,6 +157,7 @@ const Status = {
return muteWordHits(this.status, this.muteWords) return muteWordHits(this.status, this.muteWords)
}, },
muted () { muted () {
if (this.statusoid.user.id === this.currentUser.id) return false
const { status } = this const { status } = this
const { reblog } = status const { reblog } = status
const relationship = this.$store.getters.relationship(status.user.id) const relationship = this.$store.getters.relationship(status.user.id)
@ -215,7 +216,7 @@ const Status = {
return this.status.in_reply_to_screen_name return this.status.in_reply_to_screen_name
} else { } else {
const user = this.$store.getters.findUser(this.status.in_reply_to_user_id) const user = this.$store.getters.findUser(this.status.in_reply_to_user_id)
return user && user.screen_name return user && user.screen_name_ui
} }
}, },
replySubject () { replySubject () {

View file

@ -26,7 +26,7 @@
icon="retweet" icon="retweet"
/> />
<router-link :to="userProfileLink"> <router-link :to="userProfileLink">
{{ status.user.screen_name }} {{ status.user.screen_name_ui }}
</router-link> </router-link>
</small> </small>
<small <small
@ -156,10 +156,10 @@
</h4> </h4>
<router-link <router-link
class="account-name" class="account-name"
:title="status.user.screen_name" :title="status.user.screen_name_ui"
:to="userProfileLink" :to="userProfileLink"
> >
{{ status.user.screen_name }} {{ status.user.screen_name_ui }}
</router-link> </router-link>
<img <img
v-if="!!(status.user && status.user.favicon)" v-if="!!(status.user && status.user.favicon)"

View file

@ -93,7 +93,9 @@ export default Vue.component('tab-switcher', {
<button <button
disabled={slot.data.attrs.disabled} disabled={slot.data.attrs.disabled}
onClick={this.clickTab(index)} onClick={this.clickTab(index)}
class={classesTab.join(' ')}> class={classesTab.join(' ')}
type="button"
>
<img src={slot.data.attrs.image} title={slot.data.attrs['image-tooltip']}/> <img src={slot.data.attrs.image} title={slot.data.attrs['image-tooltip']}/>
{slot.data.attrs.label ? '' : slot.data.attrs.label} {slot.data.attrs.label ? '' : slot.data.attrs.label}
</button> </button>

View file

@ -9,6 +9,7 @@
<script> <script>
import * as DateUtils from 'src/services/date_utils/date_utils.js' import * as DateUtils from 'src/services/date_utils/date_utils.js'
import localeService from 'src/services/locale/locale.service.js'
export default { export default {
name: 'Timeago', name: 'Timeago',
@ -21,9 +22,10 @@ export default {
}, },
computed: { computed: {
localeDateString () { localeDateString () {
const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
return typeof this.time === 'string' return typeof this.time === 'string'
? new Date(Date.parse(this.time)).toLocaleString() ? new Date(Date.parse(this.time)).toLocaleString(browserLocale)
: this.time.toLocaleString() : this.time.toLocaleString(browserLocale)
} }
}, },
created () { created () {

View file

@ -2,12 +2,14 @@ import Status from '../status/status.vue'
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
import Conversation from '../conversation/conversation.vue' import Conversation from '../conversation/conversation.vue'
import TimelineMenu from '../timeline_menu/timeline_menu.vue' import TimelineMenu from '../timeline_menu/timeline_menu.vue'
import TimelineQuickSettings from './timeline_quick_settings.vue'
import { debounce, throttle, keyBy } from 'lodash' import { debounce, throttle, keyBy } from 'lodash'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' import { faCircleNotch, faCog } from '@fortawesome/free-solid-svg-icons'
library.add( library.add(
faCircleNotch faCircleNotch,
faCog
) )
export const getExcludedStatusIdsByPinning = (statuses, pinnedStatusIds) => { export const getExcludedStatusIdsByPinning = (statuses, pinnedStatusIds) => {
@ -47,7 +49,8 @@ const Timeline = {
components: { components: {
Status, Status,
Conversation, Conversation,
TimelineMenu TimelineMenu,
TimelineQuickSettings
}, },
computed: { computed: {
newStatusCount () { newStatusCount () {

View file

@ -16,6 +16,7 @@
> >
{{ $t('timeline.up_to_date') }} {{ $t('timeline.up_to_date') }}
</div> </div>
<TimelineQuickSettings v-if="!embedded" />
</div> </div>
<div :class="classes.body"> <div :class="classes.body">
<div <div
@ -103,9 +104,12 @@
max-width: 100%; max-width: 100%;
flex-wrap: nowrap; flex-wrap: nowrap;
align-items: center; align-items: center;
position: relative;
.loadmore-button { .loadmore-button {
flex-shrink: 0; flex-shrink: 0;
} }
.loadmore-text { .loadmore-text {
flex-shrink: 0; flex-shrink: 0;
line-height: 1em; line-height: 1em;

View file

@ -0,0 +1,63 @@
import Popover from '../popover/popover.vue'
import BooleanSetting from '../settings_modal/helpers/boolean_setting.vue'
import { mapGetters } from 'vuex'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faFilter, faFont, faWrench } from '@fortawesome/free-solid-svg-icons'
library.add(
faFilter,
faFont,
faWrench
)
const TimelineQuickSettings = {
components: {
Popover,
BooleanSetting
},
methods: {
setReplyVisibility (visibility) {
this.$store.dispatch('setOption', { name: 'replyVisibility', value: visibility })
this.$store.dispatch('queueFlushAll')
},
openTab (tab) {
this.$store.dispatch('openSettingsModalTab', tab)
}
},
computed: {
...mapGetters(['mergedConfig']),
loggedIn () {
return !!this.$store.state.users.currentUser
},
replyVisibilitySelf: {
get () { return this.mergedConfig.replyVisibility === 'self' },
set () { this.setReplyVisibility('self') }
},
replyVisibilityFollowing: {
get () { return this.mergedConfig.replyVisibility === 'following' },
set () { this.setReplyVisibility('following') }
},
replyVisibilityAll: {
get () { return this.mergedConfig.replyVisibility === 'all' },
set () { this.setReplyVisibility('all') }
},
hideMedia: {
get () { return this.mergedConfig.hideAttachments || this.mergedConfig.hideAttachmentsInConv },
set () {
const value = !this.hideMedia
this.$store.dispatch('setOption', { name: 'hideAttachments', value })
this.$store.dispatch('setOption', { name: 'hideAttachmentsInConv', value })
}
},
hideMutedPosts: {
get () { return this.mergedConfig.hideMutedPosts || this.mergedConfig.hideFilteredStatuses },
set () {
const value = !this.hideMutedPosts
this.$store.dispatch('setOption', { name: 'hideMutedPosts', value })
this.$store.dispatch('setOption', { name: 'hideFilteredStatuses', value })
}
}
}
}
export default TimelineQuickSettings

View file

@ -0,0 +1,107 @@
<template>
<Popover
trigger="click"
class="TimelineQuickSettings"
:bound-to="{ x: 'container' }"
>
<div
slot="content"
class="timeline-settings-menu dropdown-menu"
>
<div v-if="loggedIn">
<button
class="button-default dropdown-item"
@click="replyVisibilityAll = true"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-radio': replyVisibilityAll }"
/>{{ $t('settings.reply_visibility_all') }}
</button>
<button
class="button-default dropdown-item"
@click="replyVisibilityFollowing = true"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-radio': replyVisibilityFollowing }"
/>{{ $t('settings.reply_visibility_following_short') }}
</button>
<button
class="button-default dropdown-item"
@click="replyVisibilitySelf = true"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-radio': replyVisibilitySelf }"
/>{{ $t('settings.reply_visibility_self_short') }}
</button>
<div
role="separator"
class="dropdown-divider"
/>
</div>
<button
class="button-default dropdown-item"
@click="hideMedia = !hideMedia"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hideMedia }"
/>{{ $t('settings.hide_media_previews') }}
</button>
<button
class="button-default dropdown-item"
@click="hideMutedPosts = !hideMutedPosts"
>
<span
class="menu-checkbox"
:class="{ 'menu-checkbox-checked': hideMutedPosts }"
/>{{ $t('settings.hide_all_muted_posts') }}
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click="openTab('filtering')"
>
<FAIcon icon="font" />{{ $t('settings.word_filter') }}
</button>
<button
class="button-default dropdown-item dropdown-item-icon"
@click="openTab('general')"
>
<FAIcon icon="wrench" />{{ $t('settings.more_settings') }}
</button>
</div>
<div slot="trigger">
<FAIcon icon="filter" />
</div>
</Popover>
</template>
<script src="./timeline_quick_settings.js"></script>
<style lang="scss">
.TimelineQuickSettings {
align-self: stretch;
> button {
font-size: 1.2em;
padding-left: 0.7em;
padding-right: 0.2em;
line-height: 100%;
height: 100%;
}
.dropdown-item {
margin: 0;
}
.timeline-settings-menu {
display: flex;
min-width: 12em;
flex-direction: column;
}
}
</style>

View file

@ -2,8 +2,8 @@
<StillImage <StillImage
v-if="user" v-if="user"
class="Avatar" class="Avatar"
:alt="user.screen_name" :alt="user.screen_name_ui"
:title="user.screen_name" :title="user.screen_name_ui"
:src="imgSrc(user.profile_image_url_original)" :src="imgSrc(user.profile_image_url_original)"
:class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }" :class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }"
:image-load-error="imageLoadError" :image-load-error="imageLoadError"

View file

@ -73,23 +73,23 @@
<div class="bottom-line"> <div class="bottom-line">
<router-link <router-link
class="user-screen-name" class="user-screen-name"
:title="user.screen_name" :title="user.screen_name_ui"
:to="userProfileLink(user)" :to="userProfileLink(user)"
> >
@{{ user.screen_name }} @{{ user.screen_name_ui }}
</router-link> </router-link>
<template v-if="!hideBio"> <template v-if="!hideBio">
<span <span
v-if="!!visibleRole" v-if="!!visibleRole"
class="alert user-role" class="alert user-role"
> >
{{ visibleRole }} {{ $t(`general.role.${visibleRole}`) }}
</span> </span>
<span <span
v-if="user.bot" v-if="user.bot"
class="alert user-role" class="alert user-role"
> >
bot {{ $t('user_card.bot') }}
</span> </span>
</template> </template>
<span v-if="user.locked"> <span v-if="user.locked">
@ -141,10 +141,10 @@
v-model="userHighlightType" v-model="userHighlightType"
class="userHighlightSel" class="userHighlightSel"
> >
<option value="disabled">No highlight</option> <option value="disabled">{{ $t('user_card.highlight.disabled') }}</option>
<option value="solid">Solid bg</option> <option value="solid">{{ $t('user_card.highlight.solid') }}</option>
<option value="striped">Striped bg</option> <option value="striped">{{ $t('user_card.highlight.striped') }}</option>
<option value="side">Side stripe</option> <option value="side">{{ $t('user_card.highlight.side') }}</option>
</select> </select>
<FAIcon <FAIcon
class="select-down-icon" class="select-down-icon"
@ -507,7 +507,6 @@
.user-role { .user-role {
flex: none; flex: none;
text-transform: capitalize;
color: $fallback--text; color: $fallback--text;
color: var(--alertNeutralText, $fallback--text); color: var(--alertNeutralText, $fallback--text);
background-color: $fallback--fg; background-color: $fallback--fg;

View file

@ -26,7 +26,7 @@
<!-- eslint-disable vue/no-v-html --> <!-- eslint-disable vue/no-v-html -->
<span v-html="user.name_html" /> <span v-html="user.name_html" />
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
<span class="user-list-screen-name">{{ user.screen_name }}</span> <span class="user-list-screen-name">{{ user.screen_name_ui }}</span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -6,7 +6,7 @@
<div class="user-reporting-panel panel"> <div class="user-reporting-panel panel">
<div class="panel-heading"> <div class="panel-heading">
<div class="title"> <div class="title">
{{ $t('user_reporting.title', [user.screen_name]) }} {{ $t('user_reporting.title', [user.screen_name_ui]) }}
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">

View file

@ -75,7 +75,11 @@
"confirm": "Confirm", "confirm": "Confirm",
"verify": "Verify", "verify": "Verify",
"close": "Close", "close": "Close",
"peek": "Peek" "peek": "Peek",
"role": {
"admin": "Admin",
"moderator": "Moderator"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "Crop picture", "crop_picture": "Crop picture",
@ -148,6 +152,8 @@
"add_option": "Add Option", "add_option": "Add Option",
"option": "Option", "option": "Option",
"votes": "votes", "votes": "votes",
"people_voted_count": "{count} person voted | {count} people voted",
"votes_count": "{count} vote | {count} votes",
"vote": "Vote", "vote": "Vote",
"type": "Poll type", "type": "Poll type",
"single_choice": "Single choice", "single_choice": "Single choice",
@ -222,6 +228,8 @@
"username_placeholder": "e.g. lain", "username_placeholder": "e.g. lain",
"fullname_placeholder": "e.g. Lain Iwakura", "fullname_placeholder": "e.g. Lain Iwakura",
"bio_placeholder": "e.g.\nHi, I'm Lain.\nIm an anime girl living in suburban Japan. You may know me from the Wired.", "bio_placeholder": "e.g.\nHi, I'm Lain.\nIm an anime girl living in suburban Japan. You may know me from the Wired.",
"reason": "Reason to register",
"reason_placeholder": "This instance approves registrations manually.\nLet the administration know why you want to register.",
"validations": { "validations": {
"username_required": "cannot be left blank", "username_required": "cannot be left blank",
"fullname_required": "cannot be left blank", "fullname_required": "cannot be left blank",
@ -242,6 +250,7 @@
"settings": { "settings": {
"app_name": "App name", "app_name": "App name",
"security": "Security", "security": "Security",
"setting_changed": "Setting is different from default",
"enter_current_password_to_confirm": "Enter your current password to confirm your identity", "enter_current_password_to_confirm": "Enter your current password to confirm your identity",
"mfa": { "mfa": {
"otp": "OTP", "otp": "OTP",
@ -316,6 +325,7 @@
"export_theme": "Save preset", "export_theme": "Save preset",
"filtering": "Filtering", "filtering": "Filtering",
"filtering_explanation": "All statuses containing these words will be muted, one per line", "filtering_explanation": "All statuses containing these words will be muted, one per line",
"word_filter": "Word filter",
"follow_export": "Follow export", "follow_export": "Follow export",
"follow_export_button": "Export your follows to a csv file", "follow_export_button": "Export your follows to a csv file",
"follow_import": "Follow import", "follow_import": "Follow import",
@ -326,7 +336,9 @@
"general": "General", "general": "General",
"hide_attachments_in_convo": "Hide attachments in conversations", "hide_attachments_in_convo": "Hide attachments in conversations",
"hide_attachments_in_tl": "Hide attachments in timeline", "hide_attachments_in_tl": "Hide attachments in timeline",
"hide_media_previews": "Hide media previews",
"hide_muted_posts": "Hide posts of muted users", "hide_muted_posts": "Hide posts of muted users",
"hide_all_muted_posts": "Hide muted posts",
"max_thumbnails": "Maximum amount of thumbnails per post", "max_thumbnails": "Maximum amount of thumbnails per post",
"hide_isp": "Hide instance-specific panel", "hide_isp": "Hide instance-specific panel",
"hide_wallpaper": "Hide instance wallpaper", "hide_wallpaper": "Hide instance wallpaper",
@ -396,6 +408,8 @@
"reply_visibility_all": "Show all replies", "reply_visibility_all": "Show all replies",
"reply_visibility_following": "Only show replies directed at me or users I'm following", "reply_visibility_following": "Only show replies directed at me or users I'm following",
"reply_visibility_self": "Only show replies directed at me", "reply_visibility_self": "Only show replies directed at me",
"reply_visibility_following_short": "Show replies to my follows",
"reply_visibility_self_short": "Show replies to self only",
"autohide_floating_post_button": "Automatically hide New Post button (mobile)", "autohide_floating_post_button": "Automatically hide New Post button (mobile)",
"saving_err": "Error saving settings", "saving_err": "Error saving settings",
"saving_ok": "Settings saved", "saving_ok": "Settings saved",
@ -420,6 +434,7 @@
"subject_line_mastodon": "Like mastodon: copy as is", "subject_line_mastodon": "Like mastodon: copy as is",
"subject_line_noop": "Do not copy", "subject_line_noop": "Do not copy",
"post_status_content_type": "Post status content type", "post_status_content_type": "Post status content type",
"sensitive_by_default": "Mark posts as sensitive by default",
"stop_gifs": "Play-on-hover GIFs", "stop_gifs": "Play-on-hover GIFs",
"streaming": "Enable automatic streaming of new posts when scrolled to the top", "streaming": "Enable automatic streaming of new posts when scrolled to the top",
"user_mutes": "Users", "user_mutes": "Users",
@ -449,6 +464,7 @@
"notification_mutes": "To stop receiving notifications from a specific user, use a mute.", "notification_mutes": "To stop receiving notifications from a specific user, use a mute.",
"notification_blocks": "Blocking a user stops all notifications as well as unsubscribes them.", "notification_blocks": "Blocking a user stops all notifications as well as unsubscribes them.",
"enable_web_push_notifications": "Enable web push notifications", "enable_web_push_notifications": "Enable web push notifications",
"more_settings": "More settings",
"style": { "style": {
"switcher": { "switcher": {
"keep_color": "Keep colors", "keep_color": "Keep colors",
@ -714,6 +730,7 @@
"mute_progress": "Muting…", "mute_progress": "Muting…",
"hide_repeats": "Hide repeats", "hide_repeats": "Hide repeats",
"show_repeats": "Show repeats", "show_repeats": "Show repeats",
"bot": "Bot",
"admin_menu": { "admin_menu": {
"moderation": "Moderation", "moderation": "Moderation",
"grant_admin": "Grant Admin", "grant_admin": "Grant Admin",
@ -732,6 +749,12 @@
"quarantine": "Disallow user posts from federating", "quarantine": "Disallow user posts from federating",
"delete_user": "Delete user", "delete_user": "Delete user",
"delete_user_confirmation": "Are you absolutely sure? This action cannot be undone." "delete_user_confirmation": "Are you absolutely sure? This action cannot be undone."
},
"highlight": {
"disabled": "No highlight",
"solid": "Solid bg",
"striped": "Striped bg",
"side": "Side stripe"
} }
}, },
"user_profile": { "user_profile": {

View file

@ -35,7 +35,11 @@
"retry": "Reprovi", "retry": "Reprovi",
"error_retry": "Bonvolu reprovi", "error_retry": "Bonvolu reprovi",
"loading": "Enlegante…", "loading": "Enlegante…",
"peek": "Antaŭmontri" "peek": "Antaŭmontri",
"role": {
"moderator": "Reguligisto",
"admin": "Administranto"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "Tondi bildon", "crop_picture": "Tondi bildon",
@ -365,7 +369,8 @@
"post": "Afiŝoj/Priskriboj de uzantoj", "post": "Afiŝoj/Priskriboj de uzantoj",
"alert_neutral": "Neŭtrala", "alert_neutral": "Neŭtrala",
"alert_warning": "Averto", "alert_warning": "Averto",
"toggled": "Ŝaltita" "toggled": "Ŝaltita",
"wallpaper": "Fonbildo"
}, },
"radii": { "radii": {
"_tab_label": "Rondeco" "_tab_label": "Rondeco"
@ -516,7 +521,9 @@
"mute_import_error": "Eraris enporto de silentigoj", "mute_import_error": "Eraris enporto de silentigoj",
"mute_import": "Enporto de silentigoj", "mute_import": "Enporto de silentigoj",
"mute_export_button": "Elportu viajn silentigojn al CSV-dosiero", "mute_export_button": "Elportu viajn silentigojn al CSV-dosiero",
"mute_export": "Elporto de silentigoj" "mute_export": "Elporto de silentigoj",
"hide_wallpaper": "Kaŝi fonbildon de nodo",
"setting_changed": "Agordo malsamas de la implicita"
}, },
"timeline": { "timeline": {
"collapse": "Maletendi", "collapse": "Maletendi",
@ -586,7 +593,8 @@
"show_repeats": "Montri ripetojn", "show_repeats": "Montri ripetojn",
"hide_repeats": "Kaŝi ripetojn", "hide_repeats": "Kaŝi ripetojn",
"unsubscribe": "Ne ricevi sciigojn", "unsubscribe": "Ne ricevi sciigojn",
"subscribe": "Ricevi sciigojn" "subscribe": "Ricevi sciigojn",
"bot": "Roboto"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Historio de uzanto", "timeline_title": "Historio de uzanto",
@ -612,7 +620,8 @@
"error": { "error": {
"base": "Alŝuto malsukcesis.", "base": "Alŝuto malsukcesis.",
"file_too_big": "Dosiero estas tro granda [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "file_too_big": "Dosiero estas tro granda [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Reprovu pli poste" "default": "Reprovu pli poste",
"message": "Malsukcesis alŝuto: {0}"
}, },
"file_size_units": { "file_size_units": {
"B": "B", "B": "B",
@ -645,7 +654,9 @@
"votes": "voĉoj", "votes": "voĉoj",
"option": "Elekteblo", "option": "Elekteblo",
"add_option": "Aldoni elekteblon", "add_option": "Aldoni elekteblon",
"add_poll": "Aldoni enketon" "add_poll": "Aldoni enketon",
"votes_count": "{count} voĉdono | {count} voĉdonoj",
"people_voted_count": "{count} persono voĉdonis | {count} personoj voĉdonis"
}, },
"importer": { "importer": {
"error": "Eraris enporto de ĉi tiu dosiero.", "error": "Eraris enporto de ĉi tiu dosiero.",
@ -732,7 +743,9 @@
"repeats": "Ripetoj", "repeats": "Ripetoj",
"favorites": "Ŝatoj", "favorites": "Ŝatoj",
"status_deleted": "Ĉi tiu afiŝo foriĝis", "status_deleted": "Ĉi tiu afiŝo foriĝis",
"nsfw": "Konsterna" "nsfw": "Konsterna",
"expand": "Etendi",
"external_source": "Ekstera fonto"
}, },
"time": { "time": {
"years_short": "{0}j", "years_short": "{0}j",

View file

@ -562,7 +562,8 @@
"mute_import": "Importar silenciados", "mute_import": "Importar silenciados",
"mute_export_button": "Exportar los silenciados a un archivo csv", "mute_export_button": "Exportar los silenciados a un archivo csv",
"mute_export": "Exportar silenciados", "mute_export": "Exportar silenciados",
"hide_wallpaper": "Ocultar el fondo de pantalla de la instancia" "hide_wallpaper": "Ocultar el fondo de pantalla de la instancia",
"setting_changed": "La configuración es diferente a la predeterminada"
}, },
"time": { "time": {
"day": "{0} día", "day": "{0} día",
@ -693,7 +694,11 @@
"show_repeats": "Mostrar repetidos", "show_repeats": "Mostrar repetidos",
"hide_repeats": "Ocultar repetidos", "hide_repeats": "Ocultar repetidos",
"message": "Mensaje", "message": "Mensaje",
"hidden": "Oculto" "hidden": "Oculto",
"roles": {
"moderator": "Moderador",
"admin": "Administrador"
}
}, },
"user_profile": { "user_profile": {
"timeline_title": "Linea Temporal del Usuario", "timeline_title": "Linea Temporal del Usuario",

View file

@ -280,7 +280,7 @@
"hide_followers_description": "Ne pas afficher qui est abonné à moi", "hide_followers_description": "Ne pas afficher qui est abonné à moi",
"show_admin_badge": "Afficher le badge d'Administrateur⋅ice sur mon profil", "show_admin_badge": "Afficher le badge d'Administrateur⋅ice sur mon profil",
"show_moderator_badge": "Afficher le badge de Modérateur⋅ice sur mon profil", "show_moderator_badge": "Afficher le badge de Modérateur⋅ice sur mon profil",
"nsfw_clickthrough": "Masquer les images marquées comme contenu adulte ou sensible", "nsfw_clickthrough": "Activer le clic pour dévoiler les pièces jointes et cacher l'aperçu des liens pour les statuts marqués comme sensibles",
"oauth_tokens": "Jetons OAuth", "oauth_tokens": "Jetons OAuth",
"token": "Jeton", "token": "Jeton",
"refresh_token": "Rafraichir le jeton", "refresh_token": "Rafraichir le jeton",
@ -409,7 +409,13 @@
"tabs": "Onglets", "tabs": "Onglets",
"toggled": "(Dés)activé", "toggled": "(Dés)activé",
"highlight": "Éléments mis en valeur", "highlight": "Éléments mis en valeur",
"popover": "Infobulles, menus" "popover": "Infobulles, menus",
"chat": {
"border": "Bordure",
"outgoing": "Sortant(s)",
"incoming": "Entrant(s)"
},
"wallpaper": "Fond d'écran"
}, },
"radii": { "radii": {
"_tab_label": "Rondeur" "_tab_label": "Rondeur"
@ -485,7 +491,7 @@
"notification_visibility_emoji_reactions": "Réactions", "notification_visibility_emoji_reactions": "Réactions",
"hide_follows_count_description": "Masquer le nombre de suivis", "hide_follows_count_description": "Masquer le nombre de suivis",
"useStreamingApiWarning": "(Non recommandé, expérimental, connu pour rater des messages)", "useStreamingApiWarning": "(Non recommandé, expérimental, connu pour rater des messages)",
"type_domains_to_mute": "Écrire les domaines à masquer", "type_domains_to_mute": "Chercher les domaines à masquer",
"fun": "Rigolo", "fun": "Rigolo",
"greentext": "greentexting", "greentext": "greentexting",
"allow_following_move": "Suivre automatiquement quand ce compte migre", "allow_following_move": "Suivre automatiquement quand ce compte migre",
@ -509,7 +515,21 @@
"mute_import_error": "Erreur à l'import des masquages", "mute_import_error": "Erreur à l'import des masquages",
"mute_import": "Import des masquages", "mute_import": "Import des masquages",
"mute_export_button": "Exporter vos masquages dans un fichier CSV", "mute_export_button": "Exporter vos masquages dans un fichier CSV",
"mute_export": "Export des masquages" "mute_export": "Export des masquages",
"notification_setting_hide_notification_contents": "Cacher l'expéditeur et le contenu des notifications push",
"notification_setting_block_from_strangers": "Bloquer les notifications des utilisateur⋅ice⋅s que vous ne suivez pas",
"virtual_scrolling": "Optimiser le rendu du fil d'actualité",
"reset_background_confirm": "Voulez-vraiment réinitialiser l'arrière-plan ?",
"reset_banner_confirm": "Voulez-vraiment réinitialiser la bannière ?",
"reset_avatar_confirm": "Voulez-vraiment réinitialiser l'avatar ?",
"reset_profile_banner": "Réinitialiser la bannière du profil",
"reset_profile_background": "Réinitialiser l'arrière-plan du profil",
"reset_avatar": "Réinitialiser l'avatar",
"profile_fields": {
"value": "Contenu",
"name": "Étiquette",
"add_field": "Ajouter un champ"
}
}, },
"timeline": { "timeline": {
"collapse": "Fermer", "collapse": "Fermer",
@ -521,7 +541,9 @@
"show_new": "Afficher plus", "show_new": "Afficher plus",
"up_to_date": "À jour", "up_to_date": "À jour",
"no_more_statuses": "Pas plus de statuts", "no_more_statuses": "Pas plus de statuts",
"no_statuses": "Aucun statuts" "no_statuses": "Aucun statuts",
"reload": "Recharger",
"error": "Erreur lors de l'affichage du fil d'actualité : {0}"
}, },
"status": { "status": {
"favorites": "Favoris", "favorites": "Favoris",
@ -536,7 +558,19 @@
"mute_conversation": "Masquer la conversation", "mute_conversation": "Masquer la conversation",
"unmute_conversation": "Démasquer la conversation", "unmute_conversation": "Démasquer la conversation",
"status_unavailable": "Status indisponible", "status_unavailable": "Status indisponible",
"copy_link": "Copier le lien au status" "copy_link": "Copier le lien au status",
"expand": "Développer",
"nsfw": "Contenu sensible",
"status_deleted": "Ce post a été effacé",
"hide_content": "Cacher le contenu",
"show_content": "Montrer le contenu",
"hide_full_subject": "Cacher le sujet",
"show_full_subject": "Montrer le sujet en entier",
"thread_muted_and_words": ", contient les mots :",
"thread_muted": "Fil de discussion masqué",
"external_source": "Source externe",
"unbookmark": "Supprimer des favoris",
"bookmark": "Ajouter aux favoris"
}, },
"user_card": { "user_card": {
"approve": "Accepter", "approve": "Accepter",
@ -591,7 +625,12 @@
"subscribe": "Abonner", "subscribe": "Abonner",
"unsubscribe": "Désabonner", "unsubscribe": "Désabonner",
"hide_repeats": "Cacher les partages", "hide_repeats": "Cacher les partages",
"show_repeats": "Montrer les partages" "show_repeats": "Montrer les partages",
"roles": {
"moderator": "Modérateur⋅ice",
"admin": "Administrateur⋅ice"
},
"message": "Message"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Journal de l'utilisateur⋅ice", "timeline_title": "Journal de l'utilisateur⋅ice",
@ -619,13 +658,15 @@
"user_settings": "Paramètres utilisateur", "user_settings": "Paramètres utilisateur",
"add_reaction": "Ajouter une réaction", "add_reaction": "Ajouter une réaction",
"accept_follow_request": "Accepter la demande de suivit", "accept_follow_request": "Accepter la demande de suivit",
"reject_follow_request": "Rejeter la demande de suivit" "reject_follow_request": "Rejeter la demande de suivit",
"bookmark": "Favori"
}, },
"upload": { "upload": {
"error": { "error": {
"base": "L'envoi a échoué.", "base": "L'envoi a échoué.",
"file_too_big": "Fichier trop gros [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "file_too_big": "Fichier trop gros [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Réessayez plus tard" "default": "Réessayez plus tard",
"message": "Envoi échoué : {0}"
}, },
"file_size_units": { "file_size_units": {
"B": "O", "B": "O",
@ -759,5 +800,27 @@
}, },
"shoutbox": { "shoutbox": {
"title": "Shoutbox" "title": "Shoutbox"
},
"display_date": {
"today": "Aujourd'hui"
},
"file_type": {
"file": "Fichier",
"image": "Image",
"video": "Vidéo",
"audio": "Audio"
},
"chats": {
"empty_chat_list_placeholder": "Vous n'avez pas encore de discussions. Démarrez-en une nouvelle !",
"error_sending_message": "Quelque chose s'est mal passé pendant l'envoi du message.",
"error_loading_chat": "Quelque chose s'est mal passé au chargement de la discussion.",
"delete_confirm": "Voulez-vous vraiment effacer ce message ?",
"more": "Plus",
"empty_message_error": "Impossible d'envoyer un message vide",
"new": "Nouvelle discussion",
"chats": "Discussions",
"delete": "Effacer",
"message_user": "Message à {nickname}",
"you": "Vous :"
} }
} }

View file

@ -17,7 +17,11 @@
"close": "Chiudi", "close": "Chiudi",
"retry": "Riprova", "retry": "Riprova",
"error_retry": "Per favore, riprova", "error_retry": "Per favore, riprova",
"loading": "Carico…" "loading": "Carico…",
"role": {
"moderator": "Moderatore",
"admin": "Amministratore"
}
}, },
"nav": { "nav": {
"mentions": "Menzioni", "mentions": "Menzioni",
@ -30,7 +34,7 @@
"administration": "Amministrazione", "administration": "Amministrazione",
"back": "Indietro", "back": "Indietro",
"interactions": "Interazioni", "interactions": "Interazioni",
"dms": "Messaggi diretti", "dms": "Messaggi privati",
"user_search": "Ricerca utenti", "user_search": "Ricerca utenti",
"search": "Ricerca", "search": "Ricerca",
"who_to_follow": "Chi seguire", "who_to_follow": "Chi seguire",
@ -44,7 +48,7 @@
"notifications": "Notifiche", "notifications": "Notifiche",
"read": "Letto!", "read": "Letto!",
"broken_favorite": "Stato sconosciuto, lo sto cercando…", "broken_favorite": "Stato sconosciuto, lo sto cercando…",
"favorited_you": "ha gradito il tuo messaggio", "favorited_you": "gradisce il tuo messaggio",
"load_older": "Carica notifiche precedenti", "load_older": "Carica notifiche precedenti",
"repeated_you": "ha condiviso il tuo messaggio", "repeated_you": "ha condiviso il tuo messaggio",
"follow_request": "vuole seguirti", "follow_request": "vuole seguirti",
@ -417,7 +421,8 @@
"mute_import": "Importa silenziati", "mute_import": "Importa silenziati",
"mute_export_button": "Esporta la tua lista di silenziati in un file CSV", "mute_export_button": "Esporta la tua lista di silenziati in un file CSV",
"mute_export": "Esporta silenziati", "mute_export": "Esporta silenziati",
"hide_wallpaper": "Nascondi sfondo della stanza" "hide_wallpaper": "Nascondi sfondo della stanza",
"setting_changed": "Valore personalizzato"
}, },
"timeline": { "timeline": {
"error_fetching": "Errore nell'aggiornamento", "error_fetching": "Errore nell'aggiornamento",
@ -487,7 +492,8 @@
"follow_progress": "Richiedo…", "follow_progress": "Richiedo…",
"follow_sent": "Richiesta inviata!", "follow_sent": "Richiesta inviata!",
"favorites": "Preferiti", "favorites": "Preferiti",
"message": "Contatta" "message": "Contatta",
"bot": "Bot"
}, },
"chat": { "chat": {
"title": "Chat" "title": "Chat"
@ -515,18 +521,18 @@
"register": "Registrati", "register": "Registrati",
"username": "Nome utente", "username": "Nome utente",
"description": "Accedi con OAuth", "description": "Accedi con OAuth",
"hint": "Accedi per partecipare alla discussione", "hint": "Accedi per conversare",
"authentication_code": "Codice di autenticazione", "authentication_code": "Codice di autenticazione",
"enter_recovery_code": "Inserisci un codice di recupero", "enter_recovery_code": "Inserisci un codice di recupero",
"enter_two_factor_code": "Inserisci un codice two-factor", "enter_two_factor_code": "Inserisci un codice 2FA",
"recovery_code": "Codice di recupero", "recovery_code": "Codice di recupero",
"heading": { "heading": {
"totp": "Autenticazione two-factor", "totp": "Autenticazione 2FA",
"recovery": "Recupero two-factor" "recovery": "Recupero 2FA"
} }
}, },
"post_status": { "post_status": {
"account_not_locked_warning": "Il tuo profilo non è {0}. Chiunque può seguirti e vedere i tuoi messaggi riservati ai tuoi seguaci.", "account_not_locked_warning": "Il tuo profilo non è {0}. Chiunque può seguirti e vedere i tuoi messaggi per seguaci.",
"account_not_locked_warning_link": "protetto", "account_not_locked_warning_link": "protetto",
"attachments_sensitive": "Nascondi gli allegati", "attachments_sensitive": "Nascondi gli allegati",
"content_type": { "content_type": {
@ -536,7 +542,7 @@
"text/html": "HTML" "text/html": "HTML"
}, },
"content_warning": "Oggetto (facoltativo)", "content_warning": "Oggetto (facoltativo)",
"default": "Sono appena atterrato a Fiumicino.", "default": "Sono appena atterrato a Città Laggiù.",
"direct_warning": "Questo post sarà visibile solo dagli utenti menzionati.", "direct_warning": "Questo post sarà visibile solo dagli utenti menzionati.",
"posting": "Sto pubblicando", "posting": "Sto pubblicando",
"scope": { "scope": {
@ -578,7 +584,9 @@
"fullname_placeholder": "es. Lupo Lucio", "fullname_placeholder": "es. Lupo Lucio",
"username_placeholder": "es. mister_wolf", "username_placeholder": "es. mister_wolf",
"new_captcha": "Clicca l'immagine per avere un altro captcha", "new_captcha": "Clicca l'immagine per avere un altro captcha",
"captcha": "CAPTCHA" "captcha": "CAPTCHA",
"reason_placeholder": "L'amministratore esamina ciascuna richiesta.\nFornisci il motivo della tua iscrizione.",
"reason": "Motivo dell'iscrizione"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Sequenza dell'Utente", "timeline_title": "Sequenza dell'Utente",
@ -646,20 +654,22 @@
}, },
"polls": { "polls": {
"add_poll": "Sondaggio", "add_poll": "Sondaggio",
"add_option": "Alternativa", "add_option": "Aggiungi opzione",
"option": "Opzione", "option": "Opzione",
"votes": "voti", "votes": "voti",
"vote": "Vota", "vote": "Vota",
"type": "Tipo di sondaggio", "type": "Tipo di sondaggio",
"single_choice": "Scelta singola", "single_choice": "Scelta singola",
"multiple_choices": "Scelta multipla", "multiple_choices": "Scelta multipla",
"expiry": "Scadenza", "expiry": "Età",
"expires_in": "Scade fra {0}", "expires_in": "Chiude fra {0}",
"expired": "Scaduto {0} fa", "expired": "Chiuso {0} fa",
"not_enough_options": "Aggiungi altre risposte" "not_enough_options": "Aggiungi altre risposte",
"votes_count": "{count} voto | {count} voti",
"people_voted_count": "{count} votante | {count} votanti"
}, },
"interactions": { "interactions": {
"favs_repeats": "Condivisi e preferiti", "favs_repeats": "Condivisi e Graditi",
"load_older": "Carica vecchie interazioni", "load_older": "Carica vecchie interazioni",
"moves": "Utenti migrati", "moves": "Utenti migrati",
"follows": "Nuovi seguìti" "follows": "Nuovi seguìti"
@ -668,8 +678,8 @@
"load_all": "Carico tutti i {emojiAmount} emoji", "load_all": "Carico tutti i {emojiAmount} emoji",
"load_all_hint": "Primi {saneAmount} emoji caricati, caricarli tutti potrebbe causare rallentamenti.", "load_all_hint": "Primi {saneAmount} emoji caricati, caricarli tutti potrebbe causare rallentamenti.",
"unicode": "Emoji Unicode", "unicode": "Emoji Unicode",
"custom": "Emoji personale", "custom": "Emoji della stanza",
"add_emoji": "Inserisci Emoji", "add_emoji": "Inserisci emoji",
"search_emoji": "Cerca un emoji", "search_emoji": "Cerca un emoji",
"keep_open": "Tieni aperto il menù", "keep_open": "Tieni aperto il menù",
"emoji": "Emoji", "emoji": "Emoji",
@ -684,7 +694,7 @@
"remote_user_resolver": "Cerca utenti remoti" "remote_user_resolver": "Cerca utenti remoti"
}, },
"errors": { "errors": {
"storage_unavailable": "Pleroma non ha potuto accedere ai dati del tuo browser. Le tue credenziali o le tue impostazioni locali non potranno essere salvate e potresti incontrare strani errori. Prova ad abilitare i cookie." "storage_unavailable": "Pleroma non può accedere ai dati del tuo browser. Il tuo accesso o le tue impostazioni non saranno salvate e potresti incontrare strani errori. Prova ad abilitare i cookie."
}, },
"status": { "status": {
"pinned": "Intestato", "pinned": "Intestato",

View file

@ -4,7 +4,7 @@
}, },
"exporter": { "exporter": {
"export": "エクスポート", "export": "エクスポート",
"processing": "処理中です。処理が完了すると、ファイルをダウンロードするよう指示があります" "processing": "処理中です。処理が完了すると、ファイルをダウンロードするよう指示があります"
}, },
"features_panel": { "features_panel": {
"chat": "チャット", "chat": "チャット",
@ -13,10 +13,12 @@
"scope_options": "公開範囲選択", "scope_options": "公開範囲選択",
"text_limit": "文字の数", "text_limit": "文字の数",
"title": "有効な機能", "title": "有効な機能",
"who_to_follow": "おすすめユーザー" "who_to_follow": "おすすめユーザー",
"upload_limit": "ファイルサイズの上限",
"pleroma_chat_messages": "Pleroma チャット"
}, },
"finder": { "finder": {
"error_fetching_user": "ユーザー検索がエラーになりました", "error_fetching_user": "ユーザー検索がエラーになりました",
"find_user": "ユーザーを探す" "find_user": "ユーザーを探す"
}, },
"general": { "general": {
@ -31,7 +33,17 @@
"disable": "無効", "disable": "無効",
"enable": "有効", "enable": "有効",
"confirm": "確認", "confirm": "確認",
"verify": "検査" "verify": "検査",
"peek": "隠す",
"close": "閉じる",
"dismiss": "無視",
"retry": "もう一度お試し下さい",
"error_retry": "もう一度お試し下さい",
"loading": "読み込み中…",
"role": {
"moderator": "モデレーター",
"admin": "管理者"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "画像を切り抜く", "crop_picture": "画像を切り抜く",
@ -57,9 +69,9 @@
"enter_recovery_code": "リカバリーコードを入力してください", "enter_recovery_code": "リカバリーコードを入力してください",
"enter_two_factor_code": "2段階認証コードを入力してください", "enter_two_factor_code": "2段階認証コードを入力してください",
"recovery_code": "リカバリーコード", "recovery_code": "リカバリーコード",
"heading" : { "heading": {
"totp" : "2段階認証", "totp": "2段階認証",
"recovery" : "2段階リカバリー" "recovery": "2段階リカバリー"
} }
}, },
"media_modal": { "media_modal": {
@ -76,21 +88,29 @@
"dms": "ダイレクトメッセージ", "dms": "ダイレクトメッセージ",
"public_tl": "パブリックタイムライン", "public_tl": "パブリックタイムライン",
"timeline": "タイムライン", "timeline": "タイムライン",
"twkn": "接続しているすべてのネットワーク", "twkn": "すべてのネットワーク",
"user_search": "ユーザーを探す", "user_search": "ユーザーを探す",
"search": "検索", "search": "検索",
"who_to_follow": "おすすめユーザー", "who_to_follow": "おすすめユーザー",
"preferences": "設定" "preferences": "設定",
"administration": "管理",
"bookmarks": "ブックマーク",
"timelines": "タイムライン",
"chats": "チャット"
}, },
"notifications": { "notifications": {
"broken_favorite": "ステータスが見つかりません。探しています...", "broken_favorite": "ステータスが見つかりません。探しています",
"favorited_you": "あなたのステータスがお気に入りされました", "favorited_you": "あなたのステータスがお気に入りされました",
"followed_you": "フォローされました", "followed_you": "フォローされました",
"load_older": "古い通知をみる", "load_older": "古い通知をみる",
"notifications": "通知", "notifications": "通知",
"read": "読んだ!", "read": "読んだ!",
"repeated_you": "あなたのステータスがリピートされました", "repeated_you": "あなたのステータスがリピートされました",
"no_more_notifications": "通知はありません" "no_more_notifications": "通知はありません",
"reacted_with": "{0} でリアクションしました",
"migrated_to": "インスタンスを引っ越しました",
"follow_request": "あなたをフォローしたいです",
"error": "通知の取得に失敗しました: {0}"
}, },
"polls": { "polls": {
"add_poll": "投票を追加", "add_poll": "投票を追加",
@ -104,7 +124,9 @@
"expiry": "投票期間", "expiry": "投票期間",
"expires_in": "投票は {0} で終了します", "expires_in": "投票は {0} で終了します",
"expired": "投票は {0} 前に終了しました", "expired": "投票は {0} 前に終了しました",
"not_enough_options": "相異なる選択肢が不足しています" "not_enough_options": "相異なる選択肢が不足しています",
"votes_count": "{count} 票 | {count} 票",
"people_voted_count": "{count} 人投票 | {count} 人投票"
}, },
"emoji": { "emoji": {
"stickers": "ステッカー", "stickers": "ステッカー",
@ -113,7 +135,9 @@
"search_emoji": "絵文字を検索", "search_emoji": "絵文字を検索",
"add_emoji": "絵文字を挿入", "add_emoji": "絵文字を挿入",
"custom": "カスタム絵文字", "custom": "カスタム絵文字",
"unicode": "Unicode絵文字" "unicode": "Unicode絵文字",
"load_all": "全 {emojiAmount} 絵文字を読み込む",
"load_all_hint": "最初の {saneAmount} 絵文字を読み込みました、全て読み込むと重くなる可能性があります。"
}, },
"stickers": { "stickers": {
"add_sticker": "ステッカーを追加" "add_sticker": "ステッカーを追加"
@ -121,7 +145,8 @@
"interactions": { "interactions": {
"favs_repeats": "リピートとお気に入り", "favs_repeats": "リピートとお気に入り",
"follows": "新しいフォロワー", "follows": "新しいフォロワー",
"load_older": "古いインタラクションを見る" "load_older": "古いインタラクションを見る",
"moves": "ユーザーの引っ越し"
}, },
"post_status": { "post_status": {
"new_status": "投稿する", "new_status": "投稿する",
@ -142,15 +167,20 @@
"posting": "投稿", "posting": "投稿",
"scope_notice": { "scope_notice": {
"public": "この投稿は、誰でも見ることができます", "public": "この投稿は、誰でも見ることができます",
"private": "この投稿は、あなたのフォロワーだけが、見ることができます", "private": "この投稿は、あなたのフォロワーだけが、見ることができます",
"unlisted": "この投稿は、パブリックタイムラインと、接続しているすべてのネットワークには、表示されません" "unlisted": "この投稿は、パブリックタイムラインと、接続しているすべてのネットワークには、表示されません"
}, },
"scope": { "scope": {
"direct": "ダイレクト: メンションされたユーザーのみに届きます。", "direct": "ダイレクト: メンションされたユーザーのみに届きます",
"private": "フォロワーげんてい: フォロワーのみに届きます。", "private": "フォロワー限定: フォロワーのみに届きます",
"public": "パブリック: パブリックタイムラインに届きます。", "public": "パブリック: パブリックタイムラインに届きます",
"unlisted": "アンリステッド: パブリックタイムラインに届きません。" "unlisted": "アンリステッド: パブリックタイムラインに届きません"
} },
"media_description_error": "メディアのアップロードに失敗しました。もう一度お試しください",
"empty_status_error": "投稿内容を入力してください",
"preview_empty": "何もありません",
"preview": "プレビュー",
"media_description": "メディアの説明"
}, },
"registration": { "registration": {
"bio": "プロフィール", "bio": "プロフィール",
@ -171,7 +201,9 @@
"password_required": "必須", "password_required": "必須",
"password_confirmation_required": "必須", "password_confirmation_required": "必須",
"password_confirmation_match": "パスワードが違います" "password_confirmation_match": "パスワードが違います"
} },
"reason_placeholder": "このインスタンスは、新規登録を手動で受け付けています。\n登録したい理由を、インスタンスの管理者に教えてください。",
"reason": "登録するための目的"
}, },
"selectable_list": { "selectable_list": {
"select_all": "すべて選択" "select_all": "すべて選択"
@ -181,17 +213,17 @@
"security": "セキュリティ", "security": "セキュリティ",
"enter_current_password_to_confirm": "あなたのアイデンティティを証明するため、現在のパスワードを入力してください", "enter_current_password_to_confirm": "あなたのアイデンティティを証明するため、現在のパスワードを入力してください",
"mfa": { "mfa": {
"otp" : "OTP", "otp": "OTP",
"setup_otp" : "OTPのセットアップ", "setup_otp": "OTPのセットアップ",
"wait_pre_setup_otp" : "OTPのプリセット", "wait_pre_setup_otp": "OTPのプリセット",
"confirm_and_enable" : "OTPの確認と有効化", "confirm_and_enable": "OTPの確認と有効化",
"title": "2段階認証", "title": "2段階認証",
"generate_new_recovery_codes" : "新しいリカバリーコードを生成", "generate_new_recovery_codes": "新しいリカバリーコードを生成",
"warning_of_generate_new_codes" : "新しいリカバリーコードを生成すると、古いコードは使用できなくなります。", "warning_of_generate_new_codes": "新しいリカバリーコードを生成すると、古いコードは使用できなくなります。",
"recovery_codes" : "リカバリーコード。", "recovery_codes": "リカバリーコード。",
"waiting_a_recovery_codes": "バックアップコードを受信しています...", "waiting_a_recovery_codes": "バックアップコードを受信しています",
"recovery_codes_warning" : "コードを紙に書くか、安全な場所に保存してください。そうでなければ、あなたはコードを再び見ることはできません。もし2段階認証アプリのアクセスを喪失し、なおかつ、リカバリーコードもないならば、あなたは自分のアカウントから閉め出されます。", "recovery_codes_warning": "コードを紙に書くか、安全な場所に保存してください。そうでなければ、あなたはコードを再び見ることはできません。もし2段階認証アプリのアクセスを喪失し、なおかつ、リカバリーコードもないならば、あなたは自分のアカウントから閉め出されます。",
"authentication_methods" : "認証方法", "authentication_methods": "認証方法",
"scan": { "scan": {
"title": "スキャン", "title": "スキャン",
"desc": "あなたの2段階認証アプリを使って、このQRコードをスキャンするか、テキストキーを入力してください:", "desc": "あなたの2段階認証アプリを使って、このQRコードをスキャンするか、テキストキーを入力してください:",
@ -231,7 +263,7 @@
"data_import_export_tab": "インポートとエクスポート", "data_import_export_tab": "インポートとエクスポート",
"default_vis": "デフォルトの公開範囲", "default_vis": "デフォルトの公開範囲",
"delete_account": "アカウントを消す", "delete_account": "アカウントを消す",
"delete_account_description": "あなたのアカウントとメッセージが、消えます。", "delete_account_description": "あなたのデータが消えて、アカウントが使えなくなります。",
"delete_account_error": "アカウントを消すことが、できなかったかもしれません。インスタンスの管理者に、連絡してください。", "delete_account_error": "アカウントを消すことが、できなかったかもしれません。インスタンスの管理者に、連絡してください。",
"delete_account_instructions": "本当にアカウントを消してもいいなら、パスワードを入力してください。", "delete_account_instructions": "本当にアカウントを消してもいいなら、パスワードを入力してください。",
"discoverable": "検索などのサービスでこのアカウントを見つけることを許可する", "discoverable": "検索などのサービスでこのアカウントを見つけることを許可する",
@ -239,12 +271,12 @@
"pad_emoji": "ピッカーから絵文字を挿入するとき、絵文字の両側にスペースを入れる", "pad_emoji": "ピッカーから絵文字を挿入するとき、絵文字の両側にスペースを入れる",
"export_theme": "保存", "export_theme": "保存",
"filtering": "フィルタリング", "filtering": "フィルタリング",
"filtering_explanation": "これらの言葉を含むすべてのものがミュートされます。1行に1つの言葉を書いてください", "filtering_explanation": "これらの言葉を含むすべてのものがミュートされます。1行に1つの言葉を書いてください",
"follow_export": "フォローのエクスポート", "follow_export": "フォローのエクスポート",
"follow_export_button": "エクスポート", "follow_export_button": "エクスポート",
"follow_export_processing": "お待ちください。まもなくファイルをダウンロードできます。", "follow_export_processing": "お待ちください。まもなくファイルをダウンロードできます。",
"follow_import": "フォローのインポート", "follow_import": "フォローのインポート",
"follow_import_error": "フォローのインポートがエラーになりました", "follow_import_error": "フォローのインポートがエラーになりました",
"follows_imported": "フォローがインポートされました! 少し時間がかかるかもしれません。", "follows_imported": "フォローがインポートされました! 少し時間がかかるかもしれません。",
"foreground": "フォアグラウンド", "foreground": "フォアグラウンド",
"general": "全般", "general": "全般",
@ -305,7 +337,7 @@
"profile_background": "プロフィールのバックグラウンド", "profile_background": "プロフィールのバックグラウンド",
"profile_banner": "プロフィールバナー", "profile_banner": "プロフィールバナー",
"profile_tab": "プロフィール", "profile_tab": "プロフィール",
"radii_help": "インターフェースの丸さを設定する", "radii_help": "インターフェースの丸さを設定する",
"replies_in_timeline": "タイムラインのリプライ", "replies_in_timeline": "タイムラインのリプライ",
"reply_visibility_all": "すべてのリプライを見る", "reply_visibility_all": "すべてのリプライを見る",
"reply_visibility_following": "私に宛てられたリプライと、フォローしている人からのリプライを見る", "reply_visibility_following": "私に宛てられたリプライと、フォローしている人からのリプライを見る",
@ -332,7 +364,7 @@
"streaming": "上までスクロールしたとき、自動的にストリーミングする", "streaming": "上までスクロールしたとき、自動的にストリーミングする",
"text": "文字", "text": "文字",
"theme": "テーマ", "theme": "テーマ",
"theme_help": "カラーテーマをカスタマイズできます", "theme_help": "カラーテーマをカスタマイズできます",
"theme_help_v2_1": "チェックボックスをONにすると、コンポーネントごとに、色と透明度をオーバーライドできます。「すべてクリア」ボタンを押すと、すべてのオーバーライドをやめます。", "theme_help_v2_1": "チェックボックスをONにすると、コンポーネントごとに、色と透明度をオーバーライドできます。「すべてクリア」ボタンを押すと、すべてのオーバーライドをやめます。",
"theme_help_v2_2": "バックグラウンドとテキストのコントラストを表すアイコンがあります。マウスをホバーすると、詳しい説明が出ます。透明な色を使っているときは、最悪の場合のコントラストが示されます。", "theme_help_v2_2": "バックグラウンドとテキストのコントラストを表すアイコンがあります。マウスをホバーすると、詳しい説明が出ます。透明な色を使っているときは、最悪の場合のコントラストが示されます。",
"tooltipRadius": "ツールチップとアラート", "tooltipRadius": "ツールチップとアラート",
@ -356,7 +388,24 @@
"save_load_hint": "「残す」オプションをONにすると、テーマを選んだときとロードしたとき、現在の設定を残します。また、テーマをエクスポートするとき、これらのオプションを維持します。すべてのチェックボックスをOFFにすると、テーマをエクスポートしたとき、すべての設定を保存します。", "save_load_hint": "「残す」オプションをONにすると、テーマを選んだときとロードしたとき、現在の設定を残します。また、テーマをエクスポートするとき、これらのオプションを維持します。すべてのチェックボックスをOFFにすると、テーマをエクスポートしたとき、すべての設定を保存します。",
"reset": "リセット", "reset": "リセット",
"clear_all": "すべてクリア", "clear_all": "すべてクリア",
"clear_opacity": "透明度をクリア" "clear_opacity": "透明度をクリア",
"help": {
"snapshot_missing": "テーマのスナップショットがありません。思っていた見た目と違うかもしれません。",
"migration_snapshot_ok": "念のために、テーマのスナップショットが読み込まれました。テーマのデータを読み込むことができます。",
"fe_downgraded": "フロントエンドが前のバージョンに戻りました。",
"fe_upgraded": "フロントエンドと一緒に、テーマエンジンが新しくなりました。",
"older_version_imported": "古いフロントエンドで作られたファイルをインポートしました。",
"future_version_imported": "新しいフロントエンドで作られたファイルをインポートしました。",
"v2_imported": "古いフロントエンドのためのファイルをインポートしました。設定した通りにならないかもしれません。",
"upgraded_from_v2": "フロントエンドが新しくなったので、今までの見た目と少し違うかもしれません。",
"snapshot_source_mismatch": "フロントエンドがロールバックと更新を繰り返したため、バージョンが競合しています。",
"migration_napshot_gone": "スナップショットがありません、覚えているものと見た目が違うかもしれません。",
"snapshot_present": "テーマのスナップショットが読み込まれました。設定は上書きされました。代わりとして実データを読み込むことができます。"
},
"use_source": "新しいバージョン",
"use_snapshot": "古いバージョン",
"load_theme": "テーマの読み込み",
"keep_as_is": "変更しない"
}, },
"common": { "common": {
"color": "色", "color": "色",
@ -364,9 +413,9 @@
"contrast": { "contrast": {
"hint": "コントラストは {ratio} です。{level}。({context})", "hint": "コントラストは {ratio} です。{level}。({context})",
"level": { "level": {
"aa": "AAレベルガイドライン (ミニマル) を満たします", "aa": "AAレベルガイドライン (最低限) を満たします",
"aaa": "AAAレベルガイドライン (レコメンデッド) を満たします。", "aaa": "AAAレベルガイドライン (推奨) を満たします",
"bad": "ガイドラインを満たしません" "bad": "ガイドラインを満たしません"
}, },
"context": { "context": {
"18pt": "大きい (18ポイント以上) テキスト", "18pt": "大きい (18ポイント以上) テキスト",
@ -391,7 +440,27 @@
"borders": "境界", "borders": "境界",
"buttons": "ボタン", "buttons": "ボタン",
"inputs": "インプットフィールド", "inputs": "インプットフィールド",
"faint_text": "薄いテキスト" "faint_text": "薄いテキスト",
"alert_neutral": "それ以外",
"chat": {
"border": "境界線",
"outgoing": "送信",
"incoming": "受信"
},
"tabs": "タブ",
"toggled": "切り替えたとき",
"disabled": "無効なとき",
"selectedMenu": "選択されたメニューアイテム",
"selectedPost": "選択された投稿",
"pressed": "押したとき",
"highlight": "強調された要素",
"icons": "アイコン",
"poll": "投票グラフ",
"wallpaper": "壁紙",
"underlay": "アンダーレイ",
"popover": "ツールチップ、メニュー、ポップオーバー",
"post": "投稿/プロフィール",
"alert_warning": "警告"
}, },
"radii": { "radii": {
"_tab_label": "丸さ" "_tab_label": "丸さ"
@ -409,8 +478,8 @@
"always_drop_shadow": "ブラウザーがサポートしていれば、常に {0} が使われます。", "always_drop_shadow": "ブラウザーがサポートしていれば、常に {0} が使われます。",
"drop_shadow_syntax": "{0} は、{1} パラメーターと {2} キーワードをサポートしていません。", "drop_shadow_syntax": "{0} は、{1} パラメーターと {2} キーワードをサポートしていません。",
"avatar_inset": "内側の影と外側の影を同時に使うと、透明なアバターの表示が乱れます。", "avatar_inset": "内側の影と外側の影を同時に使うと、透明なアバターの表示が乱れます。",
"spread_zero": "広がりが 0 よりも大きな影は、0 と同じです", "spread_zero": "広がりが 0 よりも大きな影は、0 と同じです",
"inset_classic": "内側の影は {0} を使います" "inset_classic": "内側の影は {0} を使います"
}, },
"components": { "components": {
"panel": "パネル", "panel": "パネル",
@ -424,7 +493,8 @@
"buttonPressed": "ボタン (押されているとき)", "buttonPressed": "ボタン (押されているとき)",
"buttonPressedHover": "ボタン (ホバー、かつ、押されているとき)", "buttonPressedHover": "ボタン (ホバー、かつ、押されているとき)",
"input": "インプットフィールド" "input": "インプットフィールド"
} },
"hintV3": "影の場合は、 {0} 表記を使って他の色スロットを使うこともできます。"
}, },
"fonts": { "fonts": {
"_tab_label": "フォント", "_tab_label": "フォント",
@ -445,7 +515,7 @@
"content": "本文", "content": "本文",
"error": "エラーの例", "error": "エラーの例",
"button": "ボタン", "button": "ボタン",
"text": "これは{0}と{1}の例です", "text": "これは{0}と{1}の例です",
"mono": "monospace", "mono": "monospace",
"input": "羽田空港に着きました。", "input": "羽田空港に着きました。",
"faint_link": "とても助けになるマニュアル", "faint_link": "とても助けになるマニュアル",
@ -459,7 +529,52 @@
"title": "バージョン", "title": "バージョン",
"backend_version": "バックエンドのバージョン", "backend_version": "バックエンドのバージョン",
"frontend_version": "フロントエンドのバージョン" "frontend_version": "フロントエンドのバージョン"
} },
"notification_setting_hide_notification_contents": "送った人と内容を、プッシュ通知に表示しない",
"notification_setting_privacy": "プライバシー",
"notification_setting_block_from_strangers": "フォローしていないユーザーからの通知を拒否する",
"notification_setting_filters": "フィルター",
"fun": "お楽しみ",
"virtual_scrolling": "タイムラインの描画を最適化する",
"type_domains_to_mute": "ミュートしたいドメインを検索",
"useStreamingApiWarning": "(実験中で、投稿を取りこぼすかもしれないので、おすすめしません)",
"useStreamingApi": "投稿と通知を、すぐに受け取る",
"user_mutes": "ユーザー",
"reset_background_confirm": "本当にバックグラウンドを初期化しますか?",
"reset_banner_confirm": "本当にバナーを初期化しますか?",
"reset_avatar_confirm": "本当にアバターを初期化しますか?",
"hide_wallpaper": "インスタンスのバックグラウンドを隠す",
"reset_profile_background": "プロフィールのバックグラウンドを初期化",
"reset_profile_banner": "プロフィールのバナーを初期化",
"reset_avatar": "アバターを初期化",
"notification_visibility_emoji_reactions": "リアクション",
"notification_visibility_moves": "ユーザーの引っ越し",
"new_email": "新しいメールアドレス",
"profile_fields": {
"value": "内容",
"name": "ラベル",
"add_field": "枠を追加",
"label": "プロフィール補足情報"
},
"accent": "アクセント",
"mutes_imported": "ミュートをインポートしました!少し時間がかかるかもしれません。",
"emoji_reactions_on_timeline": "絵文字リアクションをタイムラインに表示",
"domain_mutes": "ドメイン",
"mutes_and_blocks": "ミュートとブロック",
"chatMessageRadius": "チャットメッセージ",
"change_email_error": "メールアドレスを変えることが、できなかったかもしれません。",
"changed_email": "メールアドレスが、変わりました!",
"change_email": "メールアドレスを変える",
"bot": "これは bot アカウントです",
"mute_export_button": "ミュートをCSVファイルにエクスポートする",
"import_mutes_from_a_csv_file": "CSVファイルからミュートをインポートする",
"mute_import_error": "ミュートのインポートに失敗しました",
"mute_import": "ミュートのインポート",
"mute_export": "ミュートのエクスポート",
"allow_following_move": "フォロー中のアカウントが引っ越したとき、自動フォローを許可する",
"setting_changed": "規定の設定と異なっています",
"greentext": "引用を緑色で表示",
"sensitive_by_default": "はじめから投稿をセンシティブとして設定"
}, },
"time": { "time": {
"day": "{0}日", "day": "{0}日",
@ -505,7 +620,9 @@
"show_new": "読み込み", "show_new": "読み込み",
"up_to_date": "最新", "up_to_date": "最新",
"no_more_statuses": "これで終わりです", "no_more_statuses": "これで終わりです",
"no_statuses": "ステータスはありません" "no_statuses": "ステータスはありません",
"reload": "再読み込み",
"error": "タイムラインの読み込みに失敗しました: {0}"
}, },
"status": { "status": {
"favorites": "お気に入り", "favorites": "お気に入り",
@ -518,7 +635,21 @@
"reply_to": "返信", "reply_to": "返信",
"replies_list": "返信:", "replies_list": "返信:",
"mute_conversation": "スレッドをミュート", "mute_conversation": "スレッドをミュート",
"unmute_conversation": "スレッドのミュートを解除" "unmute_conversation": "スレッドのミュートを解除",
"nsfw": "閲覧注意",
"expand": "広げる",
"status_deleted": "この投稿は削除されました",
"hide_content": "隠す",
"show_content": "見る",
"hide_full_subject": "隠す",
"show_full_subject": "全部見る",
"thread_muted_and_words": "以下の単語を含むため:",
"thread_muted": "ミュートされたスレッド",
"external_source": "外部ソース",
"copy_link": "リンクをコピー",
"status_unavailable": "利用できません",
"unbookmark": "ブックマーク解除",
"bookmark": "ブックマーク"
}, },
"user_card": { "user_card": {
"approve": "受け入れ", "approve": "受け入れ",
@ -539,7 +670,7 @@
"media": "メディア", "media": "メディア",
"mention": "メンション", "mention": "メンション",
"mute": "ミュート", "mute": "ミュート",
"muted": "ミュートしています", "muted": "ミュートしています",
"per_day": "/日", "per_day": "/日",
"remote_follow": "リモートフォロー", "remote_follow": "リモートフォロー",
"report": "通報", "report": "通報",
@ -547,11 +678,11 @@
"subscribe": "購読", "subscribe": "購読",
"unsubscribe": "購読を解除", "unsubscribe": "購読を解除",
"unblock": "ブロック解除", "unblock": "ブロック解除",
"unblock_progress": "ブロックを解除しています...", "unblock_progress": "ブロックを解除しています",
"block_progress": "ブロックしています...", "block_progress": "ブロックしています",
"unmute": "ミュート解除", "unmute": "ミュート解除",
"unmute_progress": "ミュートを解除しています...", "unmute_progress": "ミュートを解除しています",
"mute_progress": "ミュートしています...", "mute_progress": "ミュートしています",
"admin_menu": { "admin_menu": {
"moderation": "モデレーション", "moderation": "モデレーション",
"grant_admin": "管理者権限を付与", "grant_admin": "管理者権限を付与",
@ -570,7 +701,16 @@
"quarantine": "他のインスタンスからの投稿を止める", "quarantine": "他のインスタンスからの投稿を止める",
"delete_user": "ユーザーを削除", "delete_user": "ユーザーを削除",
"delete_user_confirmation": "あなたの精神状態に何か問題はございませんか? この操作を取り消すことはできません。" "delete_user_confirmation": "あなたの精神状態に何か問題はございませんか? この操作を取り消すことはできません。"
} },
"roles": {
"moderator": "モデレーター",
"admin": "管理者"
},
"show_repeats": "リピートを見る",
"hide_repeats": "リピートを隠す",
"message": "メッセージ",
"hidden": "隠す",
"bot": "bot"
}, },
"user_profile": { "user_profile": {
"timeline_title": "ユーザータイムライン", "timeline_title": "ユーザータイムライン",
@ -595,13 +735,18 @@
"repeat": "リピート", "repeat": "リピート",
"reply": "返信", "reply": "返信",
"favorite": "お気に入り", "favorite": "お気に入り",
"user_settings": "ユーザー設定" "user_settings": "ユーザー設定",
"bookmark": "ブックマーク",
"reject_follow_request": "フォローリクエストを拒否",
"accept_follow_request": "フォローリクエストを許可",
"add_reaction": "リアクションを追加"
}, },
"upload":{ "upload": {
"error": { "error": {
"base": "アップロードに失敗しました。", "base": "アップロードに失敗しました。",
"file_too_big": "ファイルが大きすぎます [{filesize} {filesizeunit} / {allowedsize} {allowedsizeunit}]", "file_too_big": "ファイルが大きすぎます [{filesize} {filesizeunit} / {allowedsize} {allowedsizeunit}]",
"default": "しばらくしてから試してください" "default": "しばらくしてから試してください",
"message": "アップロードに失敗: {0}"
}, },
"file_size_units": { "file_size_units": {
"B": "B", "B": "B",
@ -626,6 +771,77 @@
"check_email": "パスワードをリセットするためのリンクが記載されたメールが届いているか確認してください。", "check_email": "パスワードをリセットするためのリンクが記載されたメールが届いているか確認してください。",
"return_home": "ホームページに戻る", "return_home": "ホームページに戻る",
"too_many_requests": "試行回数の制限に達しました。しばらく時間を置いてから再試行してください。", "too_many_requests": "試行回数の制限に達しました。しばらく時間を置いてから再試行してください。",
"password_reset_disabled": "このインスタンスではパスワードリセットは無効になっています。インスタンスの管理者に連絡してください。" "password_reset_disabled": "このインスタンスではパスワードリセットは無効になっています。インスタンスの管理者に連絡してください。",
"password_reset_required_but_mailer_is_disabled": "パスワードの初期化が必要ですが、初期化は使えません。インスタンスの管理者に連絡してください。",
"password_reset_required": "ログインするためにパスワードを初期化してください。"
},
"about": {
"mrf": {
"mrf_policies_desc": "MRFポリシーは、インスタンスの振る舞いを操作します。以下のポリシーが有効になっています:",
"federation": "連合",
"simple": {
"media_nsfw_desc": "このインスタンスでは、以下のインスタンスからの投稿に対して、メディアを閲覧注意に設定します:",
"media_nsfw": "メディアを閲覧注意に設定",
"media_removal_desc": "このインスタンスでは、以下のインスタンスからの投稿に対して、メディアを除去します:",
"media_removal": "メディア除去",
"ftl_removal": "「接続しているすべてのネットワーク」タイムラインから除外",
"ftl_removal_desc": "このインスタンスでは、以下のインスタンスを「接続しているすべてのネットワーク」タイムラインから除外します:",
"quarantine_desc": "このインスタンスでは、以下のインスタンスに対して公開投稿のみを送信します:",
"quarantine": "検疫",
"reject_desc": "このインスタンスでは、以下のインスタンスからのメッセージを受け付けません:",
"accept_desc": "このインスタンスでは、以下のインスタンスからのメッセージのみを受け付けます:",
"accept": "許可",
"simple_policies": "インスタンス固有のポリシー",
"reject": "拒否"
},
"mrf_policies": "有効なMRFポリシー",
"keyword": {
"replace": "置き換え",
"ftl_removal": "「接続しているすべてのネットワーク」タイムラインから除外",
"keyword_policies": "キーワードポリシー",
"is_replaced_by": "→",
"reject": "拒否"
}
},
"staff": "スタッフ"
},
"display_date": {
"today": "今日"
},
"file_type": {
"file": "ファイル",
"image": "画像",
"video": "ビデオ",
"audio": "オーディオ"
},
"remote_user_resolver": {
"error": "見つかりませんでした。",
"searching_for": "検索中",
"remote_user_resolver": "リモートユーザーリゾルバ"
},
"errors": {
"storage_unavailable": "ブラウザのストレージに接続できなかったため、ログインや設定情報は保存されません。Cookieを有効にしてください。"
},
"shoutbox": {
"title": "Shoutbox"
},
"chats": {
"empty_chat_list_placeholder": "チャットはありません。新規チャットのボタンを押して始めましょう!",
"error_sending_message": "メッセージの送信に失敗しました。",
"error_loading_chat": "チャットの読み込みに失敗しました。",
"delete_confirm": "このメッセージを本当に消してもいいですか?",
"more": "もっと見る",
"empty_message_error": "メッセージを入力して下さい",
"new": "新規チャット",
"chats": "チャット一覧",
"delete": "削除",
"message_user": "{nickname} にメッセージ",
"you": "あなた:"
},
"domain_mute_card": {
"unmute_progress": "ミュート解除中…",
"unmute": "ミュート解除",
"mute_progress": "ミュート中…",
"mute": "ミュート"
} }
} }

View file

@ -9,7 +9,9 @@
"scope_options": "범위 옵션", "scope_options": "범위 옵션",
"text_limit": "텍스트 제한", "text_limit": "텍스트 제한",
"title": "기능", "title": "기능",
"who_to_follow": "팔로우 추천" "who_to_follow": "팔로우 추천",
"upload_limit": "최대 파일용량",
"pleroma_chat_messages": "Pleroma 채트"
}, },
"finder": { "finder": {
"error_fetching_user": "사용자 정보 불러오기 실패", "error_fetching_user": "사용자 정보 불러오기 실패",
@ -17,7 +19,27 @@
}, },
"general": { "general": {
"apply": "적용", "apply": "적용",
"submit": "보내기" "submit": "보내기",
"loading": "로딩중…",
"peek": "숨기기",
"close": "닫기",
"verify": "검사",
"confirm": "확인",
"enable": "유효",
"disable": "무효",
"cancel": "취소",
"dismiss": "무시",
"show_less": "접기",
"show_more": "더 보기",
"optional": "필수 아님",
"retry": "다시 시도하십시오",
"error_retry": "다시 시도하십시오",
"generic_error": "잘못되었습니다",
"more": "더 보기",
"role": {
"moderator": "중재자",
"admin": "관리자"
}
}, },
"login": { "login": {
"login": "로그인", "login": "로그인",
@ -26,10 +48,19 @@
"password": "암호", "password": "암호",
"placeholder": "예시: lain", "placeholder": "예시: lain",
"register": "가입", "register": "가입",
"username": "사용자 이름" "username": "사용자 이름",
"heading": {
"recovery": "2단계 복구",
"totp": "2단계인증"
},
"recovery_code": "복구 코드",
"enter_two_factor_code": "2단계인증 코드를 입력하십시오",
"enter_recovery_code": "복구 코드를 입력하십시오",
"authentication_code": "인증 코드",
"hint": "로그인하여 대화에 참가합시다"
}, },
"nav": { "nav": {
"about": "About", "about": "인스턴스 소개",
"back": "뒤로", "back": "뒤로",
"chat": "로컬 챗", "chat": "로컬 챗",
"friend_requests": "팔로우 요청", "friend_requests": "팔로우 요청",
@ -37,18 +68,29 @@
"dms": "다이렉트 메시지", "dms": "다이렉트 메시지",
"public_tl": "공개 타임라인", "public_tl": "공개 타임라인",
"timeline": "타임라인", "timeline": "타임라인",
"twkn": "모든 알려진 네트워크", "twkn": "알려진 네트워크",
"user_search": "사용자 검색", "user_search": "사용자 검색",
"preferences": "환경설정" "preferences": "환경설정",
"chats": "채트",
"timelines": "타임라인",
"who_to_follow": "추천된 사용자",
"search": "검색",
"bookmarks": "북마크",
"interactions": "대화",
"administration": "관리"
}, },
"notifications": { "notifications": {
"broken_favorite": "알 수 없는 게시물입니다, 검색 합니다...", "broken_favorite": "알 수 없는 게시물입니다, 검색합니다…",
"favorited_you": "당신의 게시물을 즐겨찾기", "favorited_you": "당신의 게시물을 즐겨찾기",
"followed_you": "당신을 팔로우", "followed_you": "당신을 팔로우",
"load_older": "오래 된 알림 불러오기", "load_older": "오래 된 알림 불러오기",
"notifications": "알림", "notifications": "알림",
"read": "읽음!", "read": "읽음!",
"repeated_you": "당신의 게시물을 리핏" "repeated_you": "당신의 게시물을 리핏",
"no_more_notifications": "알림이 없습니다",
"migrated_to": "이사했습니다",
"reacted_with": "{0} 로 반응했습니다",
"error": "알림 불러오기 실패: {0}"
}, },
"post_status": { "post_status": {
"new_status": "새 게시물 게시", "new_status": "새 게시물 게시",
@ -56,10 +98,13 @@
"account_not_locked_warning_link": "잠김", "account_not_locked_warning_link": "잠김",
"attachments_sensitive": "첨부물을 민감함으로 설정", "attachments_sensitive": "첨부물을 민감함으로 설정",
"content_type": { "content_type": {
"text/plain": "평문" "text/plain": "평문",
"text/bbcode": "BBCode",
"text/markdown": "Markdown",
"text/html": "HTML"
}, },
"content_warning": "주제 (필수 아님)", "content_warning": "주제 (필수 아님)",
"default": "LA에 도착!", "default": "인천공항에 도착했습니다.",
"direct_warning": "이 게시물을 멘션 된 사용자들에게만 보여집니다", "direct_warning": "이 게시물을 멘션 된 사용자들에게만 보여집니다",
"posting": "게시", "posting": "게시",
"scope": { "scope": {
@ -67,7 +112,15 @@
"private": "팔로워 전용 - 팔로워들에게만", "private": "팔로워 전용 - 팔로워들에게만",
"public": "공개 - 공개 타임라인으로", "public": "공개 - 공개 타임라인으로",
"unlisted": "비공개 - 공개 타임라인에 게시 안 함" "unlisted": "비공개 - 공개 타임라인에 게시 안 함"
} },
"preview_empty": "아무것도 없습니다",
"preview": "미리보기",
"scope_notice": {
"public": "이 글은 누구나 볼 수 있습니다"
},
"media_description_error": "파일을 올리지 못하였습니다. 다시한번 시도하여 주십시오",
"empty_status_error": "글을 입력하십시오",
"media_description": "첨부파일 설명"
}, },
"registration": { "registration": {
"bio": "소개", "bio": "소개",
@ -85,7 +138,9 @@
"password_required": "공백으로 둘 수 없습니다", "password_required": "공백으로 둘 수 없습니다",
"password_confirmation_required": "공백으로 둘 수 없습니다", "password_confirmation_required": "공백으로 둘 수 없습니다",
"password_confirmation_match": "패스워드와 일치해야 합니다" "password_confirmation_match": "패스워드와 일치해야 합니다"
} },
"fullname_placeholder": "예: 김례인",
"username_placeholder": "예: lain"
}, },
"settings": { "settings": {
"attachmentRadius": "첨부물", "attachmentRadius": "첨부물",
@ -112,7 +167,7 @@
"data_import_export_tab": "데이터 불러오기 / 내보내기", "data_import_export_tab": "데이터 불러오기 / 내보내기",
"default_vis": "기본 공개 범위", "default_vis": "기본 공개 범위",
"delete_account": "계정 삭제", "delete_account": "계정 삭제",
"delete_account_description": "계정과 메시지를 영구히 삭제.", "delete_account_description": "데이터가 영구히 삭제되고 계정이 불활성화됩니다.",
"delete_account_error": "계정을 삭제하는데 문제가 있습니다. 계속 발생한다면 인스턴스 관리자에게 문의하세요.", "delete_account_error": "계정을 삭제하는데 문제가 있습니다. 계속 발생한다면 인스턴스 관리자에게 문의하세요.",
"delete_account_instructions": "계정 삭제를 확인하기 위해 아래에 패스워드 입력.", "delete_account_instructions": "계정 삭제를 확인하기 위해 아래에 패스워드 입력.",
"export_theme": "프리셋 저장", "export_theme": "프리셋 저장",
@ -156,7 +211,7 @@
"notification_visibility_repeats": "반복", "notification_visibility_repeats": "반복",
"no_rich_text_description": "모든 게시물의 서식을 지우기", "no_rich_text_description": "모든 게시물의 서식을 지우기",
"hide_follows_description": "내가 팔로우하는 사람을 표시하지 않음", "hide_follows_description": "내가 팔로우하는 사람을 표시하지 않음",
"hide_followers_description": "나를 따르는 사람을 보여주지 마라.", "hide_followers_description": "나를 따르는 사람을 숨기기",
"nsfw_clickthrough": "NSFW 이미지 \"클릭해서 보이기\"를 활성화", "nsfw_clickthrough": "NSFW 이미지 \"클릭해서 보이기\"를 활성화",
"oauth_tokens": "OAuth 토큰", "oauth_tokens": "OAuth 토큰",
"token": "토큰", "token": "토큰",
@ -247,7 +302,16 @@
"borders": "테두리", "borders": "테두리",
"buttons": "버튼", "buttons": "버튼",
"inputs": "입력칸", "inputs": "입력칸",
"faint_text": "흐려진 텍스트" "faint_text": "흐려진 텍스트",
"chat": {
"border": "경계선",
"outgoing": "송신",
"incoming": "수신"
},
"selectedMenu": "선택된 메뉴 요소",
"selectedPost": "선택된 글",
"icons": "아이콘",
"alert_warning": "경고"
}, },
"radii": { "radii": {
"_tab_label": "둥글기" "_tab_label": "둥글기"
@ -303,14 +367,45 @@
"button": "버튼", "button": "버튼",
"text": "더 많은 {0} 그리고 {1}", "text": "더 많은 {0} 그리고 {1}",
"mono": "내용", "mono": "내용",
"input": "LA에 막 도착!", "input": "인천공항에 도착했습니다.",
"faint_link": "도움 되는 설명서", "faint_link": "도움 되는 설명서",
"fine_print": "우리의 {0} 를 읽고 도움 되지 않는 것들을 배우자!", "fine_print": "우리의 {0} 를 읽고 도움 되지 않는 것들을 배우자!",
"header_faint": "이건 괜찮아", "header_faint": "이건 괜찮아",
"checkbox": "나는 약관을 대충 훑어보았습니다", "checkbox": "나는 약관을 대충 훑어보았습니다",
"link": "작고 귀여운 링크" "link": "작고 귀여운 링크"
} }
} },
"block_export": "차단 목록 내보내기",
"mfa": {
"scan": {
"secret_code": "키",
"title": "스캔"
},
"authentication_methods": "인증 방법",
"waiting_a_recovery_codes": "예비 코드를 수신하고 있습니다…",
"recovery_codes": "복구 코드.",
"generate_new_recovery_codes": "새로운 복구 코드를 작성",
"title": "2단계인증",
"confirm_and_enable": "OTP 확인과 활성화",
"setup_otp": "OTP 설치",
"otp": "OTP"
},
"security": "보안",
"emoji_reactions_on_timeline": "이모지 반응을 타임라인으로 표시",
"avatar_size_instruction": "크기를 150x150 이상으로 설정할 것을 추장합니다.",
"blocks_tab": "차단",
"notification_setting_privacy": "보안",
"user_mutes": "사용자",
"notification_visibility_emoji_reactions": "반응",
"profile_fields": {
"value": "내용"
},
"mutes_and_blocks": "침묵과 차단",
"chatMessageRadius": "챗 메시지",
"change_email": "전자메일 주소 바꾸기",
"changed_email": "메일주소가 갱신되었습니다!",
"bot": "이 계정은 bot입니다",
"mutes_tab": "침묵"
}, },
"timeline": { "timeline": {
"collapse": "접기", "collapse": "접기",
@ -339,7 +434,7 @@
"its_you": "당신입니다!", "its_you": "당신입니다!",
"mute": "침묵", "mute": "침묵",
"muted": "침묵 됨", "muted": "침묵 됨",
"per_day": " / 하루", "per_day": "/ 하루",
"remote_follow": "원격 팔로우", "remote_follow": "원격 팔로우",
"statuses": "게시물" "statuses": "게시물"
}, },
@ -357,7 +452,7 @@
"favorite": "즐겨찾기", "favorite": "즐겨찾기",
"user_settings": "사용자 설정" "user_settings": "사용자 설정"
}, },
"upload":{ "upload": {
"error": { "error": {
"base": "업로드 실패.", "base": "업로드 실패.",
"file_too_big": "파일이 너무 커요 [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "file_too_big": "파일이 너무 커요 [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
@ -370,5 +465,122 @@
"GiB": "기비바이트", "GiB": "기비바이트",
"TiB": "테비바이트" "TiB": "테비바이트"
} }
},
"interactions": {
"follows": "새 팔로워",
"favs_repeats": "반복과 즐겨찾기"
},
"emoji": {
"load_all": "전체 {emojiAmount} 이모지 불러오기",
"unicode": "Unicode 이모지",
"custom": "전용 이모지",
"add_emoji": "이모지 넣기",
"search_emoji": "이모지 검색",
"emoji": "이모지",
"stickers": "스티커"
},
"polls": {
"add_poll": "투표를 추가",
"votes": "표",
"vote": "투표",
"type": "투표 형식",
"expiry": "투표 기간",
"votes_count": "{count} 표 | {count} 표",
"people_voted_count": "{count} 명 투표 | {count} 명 투표",
"option": "선택지",
"add_option": "선택지 추가"
},
"media_modal": {
"next": "다음",
"previous": "이전"
},
"importer": {
"error": "이 파일을 가져올 때 오류가 발생하였습니다.",
"success": "정상히 불러왔습니다.",
"submit": "보내기"
},
"image_cropper": {
"cancel": "취소",
"save_without_cropping": "그대로 저장",
"save": "저장",
"crop_picture": "사진 자르기"
},
"exporter": {
"processing": "처리중입니다, 처리가 끝나면 파일을 다운로드하라는 지시가 있겠습니다",
"export": "내보내기"
},
"domain_mute_card": {
"unmute_progress": "침묵을 해제중…",
"unmute": "침묵 해제",
"mute_progress": "침묵으로 설정중…",
"mute": "침묵"
},
"about": {
"staff": "운영자",
"mrf": {
"simple": {
"media_nsfw_desc": "이 인스턴스에서는 아래의 인스턴스로부터 보내온 투고에 붙혀 있는 매체는 민감함으로 설정됩니다:",
"media_nsfw": "매체를 민감함으로 설정",
"media_removal_desc": "이 인스턴스에서는 아래의 인스턴스로부터 보내온 투고에 붙혀 있는 매체는 제거됩니다:",
"media_removal": "매체 제거",
"ftl_removal_desc": "이 인스턴스에서 아래의 인스턴스들은 \"알려진 모든 네트워크\" 타임라인에서 제외됩니다:",
"ftl_removal": "\"알려진 모든 네트워크\" 타임라인에서 제외",
"quarantine_desc": "이 인스턴스는 아래의 인스턴스에게 공개투고만을 보냅니다:",
"quarantine": "검역",
"reject_desc": "이 인스턴스에서는 아래의 인스턴스로부터 보내온 투고를 받아들이지 않습니다:",
"accept_desc": "이 인스턴스에서는 아래의 인스턴스로부터 보내온 투고만이 접수됩니다:",
"reject": "거부",
"accept": "허가",
"simple_policies": "인스턴스 특유의 폴리시"
},
"mrf_policies": "사용되는 MRF 폴리시",
"keyword": {
"is_replaced_by": "→",
"replace": "바꾸기",
"reject": "거부",
"ftl_removal": "\"알려진 모든 네트워크\" 타임라인에서 제외",
"keyword_policies": "단어 폴리시"
},
"federation": "연합"
}
},
"shoutbox": {
"title": "Shoutbox"
},
"time": {
"years_short": "{0} 년",
"year_short": "{0} 년",
"years": "{0} 년",
"year": "{0} 년",
"weeks_short": "{0} 주일",
"week_short": "{0} 주일",
"weeks": "{0} 주일",
"week": "{0} 주일",
"seconds_short": "{0} 초",
"second_short": "{0} 초",
"seconds": "{0} 초",
"second": "{0} 초",
"now_short": "방금",
"now": "방끔",
"months_short": "{0} 달 전",
"month_short": "{0} 달 전",
"months": "{0} 달 전",
"month": "{0} 달 전",
"minutes_short": "{0} 분",
"minute_short": "{0} 분",
"minutes": "{0} 분",
"minute": "{0} 분",
"in_past": "{0} 전",
"hours_short": "{0} 시간",
"hour_short": "{0} 시간",
"hours": "{0} 시간",
"hour": "{0} 시간",
"days_short": "{0} 일",
"day_short": "{0} 일",
"days": "{0} 일",
"day": "{0} 일"
},
"remote_user_resolver": {
"error": "찾을 수 없습니다."
} }
} }

View file

@ -57,9 +57,9 @@
"enter_recovery_code": "Skriv inn en gjenopprettingskode", "enter_recovery_code": "Skriv inn en gjenopprettingskode",
"enter_two_factor_code": "Skriv inn en to-faktors kode", "enter_two_factor_code": "Skriv inn en to-faktors kode",
"recovery_code": "Gjenopprettingskode", "recovery_code": "Gjenopprettingskode",
"heading" : { "heading": {
"totp" : "To-faktors autentisering", "totp": "To-faktors autentisering",
"recovery" : "To-faktors gjenoppretting" "recovery": "To-faktors gjenoppretting"
} }
}, },
"media_modal": { "media_modal": {
@ -72,7 +72,7 @@
"chat": "Lokal nettprat", "chat": "Lokal nettprat",
"friend_requests": "Følgeforespørsler", "friend_requests": "Følgeforespørsler",
"mentions": "Nevnt", "mentions": "Nevnt",
"interactions": "Interaksjooner", "interactions": "Interaksjoner",
"dms": "Direktemeldinger", "dms": "Direktemeldinger",
"public_tl": "Offentlig Tidslinje", "public_tl": "Offentlig Tidslinje",
"timeline": "Tidslinje", "timeline": "Tidslinje",
@ -80,7 +80,9 @@
"user_search": "Søk etter brukere", "user_search": "Søk etter brukere",
"search": "Søk", "search": "Søk",
"who_to_follow": "Kontoer å følge", "who_to_follow": "Kontoer å følge",
"preferences": "Innstillinger" "preferences": "Innstillinger",
"timelines": "Tidslinjer",
"bookmarks": "Bokmerker"
}, },
"notifications": { "notifications": {
"broken_favorite": "Ukjent status, leter etter den...", "broken_favorite": "Ukjent status, leter etter den...",
@ -90,7 +92,8 @@
"notifications": "Varslinger", "notifications": "Varslinger",
"read": "Les!", "read": "Les!",
"repeated_you": "Gjentok din status", "repeated_you": "Gjentok din status",
"no_more_notifications": "Ingen gjenstående varsler" "no_more_notifications": "Ingen gjenstående varsler",
"follow_request": "ønsker å følge deg"
}, },
"polls": { "polls": {
"add_poll": "Legg til undersøkelse", "add_poll": "Legg til undersøkelse",
@ -171,17 +174,17 @@
"security": "Sikkerhet", "security": "Sikkerhet",
"enter_current_password_to_confirm": "Skriv inn ditt nåverende passord for å bekrefte din identitet", "enter_current_password_to_confirm": "Skriv inn ditt nåverende passord for å bekrefte din identitet",
"mfa": { "mfa": {
"otp" : "OTP", "otp": "OTP",
"setup_otp" : "Set opp OTP", "setup_otp": "Set opp OTP",
"wait_pre_setup_otp" : "forhåndsstiller OTP", "wait_pre_setup_otp": "forhåndsstiller OTP",
"confirm_and_enable" : "Bekreft og slå på OTP", "confirm_and_enable": "Bekreft og slå på OTP",
"title": "To-faktors autentisering", "title": "To-faktors autentisering",
"generate_new_recovery_codes" : "Generer nye gjenopprettingskoder", "generate_new_recovery_codes": "Generer nye gjenopprettingskoder",
"warning_of_generate_new_codes" : "Når du genererer nye gjenopprettingskoder, vil de gamle slutte å fungere.", "warning_of_generate_new_codes": "Når du genererer nye gjenopprettingskoder, vil de gamle slutte å fungere.",
"recovery_codes" : "Gjenopprettingskoder.", "recovery_codes": "Gjenopprettingskoder.",
"waiting_a_recovery_codes": "Mottar gjenopprettingskoder...", "waiting_a_recovery_codes": "Mottar gjenopprettingskoder...",
"recovery_codes_warning" : "Skriv disse kodene ned eller plasser dem ett sikkert sted - ellers så vil du ikke se dem igjen. Dersom du mister tilgang til din to-faktors app og dine gjenopprettingskoder, vil du bli stengt ute av kontoen din.", "recovery_codes_warning": "Skriv disse kodene ned eller plasser dem ett sikkert sted - ellers så vil du ikke se dem igjen. Dersom du mister tilgang til din to-faktors app og dine gjenopprettingskoder, vil du bli stengt ute av kontoen din.",
"authentication_methods" : "Autentiseringsmetoder", "authentication_methods": "Autentiseringsmetoder",
"scan": { "scan": {
"title": "Skann", "title": "Skann",
"desc": "Ved hjelp av din to-faktors applikasjon, skann denne QR-koden eller skriv inn tekstnøkkelen", "desc": "Ved hjelp av din to-faktors applikasjon, skann denne QR-koden eller skriv inn tekstnøkkelen",
@ -579,7 +582,7 @@
"favorite": "Lik", "favorite": "Lik",
"user_settings": "Brukerinnstillinger" "user_settings": "Brukerinnstillinger"
}, },
"upload":{ "upload": {
"error": { "error": {
"base": "Det oppsto en feil under opplastning.", "base": "Det oppsto en feil under opplastning.",
"file_too_big": "Fil for stor [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "file_too_big": "Fil for stor [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",

View file

@ -5,37 +5,66 @@
"features_panel": { "features_panel": {
"chat": "Chat", "chat": "Chat",
"gopher": "Gopher", "gopher": "Gopher",
"media_proxy": "Proxy de mídia", "media_proxy": "Proxy de multimédia",
"scope_options": "Opções de privacidade", "scope_options": "Opções de privacidade",
"text_limit": "Limite de caracteres", "text_limit": "Limite de caracteres",
"title": "Funções", "title": "Características",
"who_to_follow": "Quem seguir" "who_to_follow": "Quem seguir",
"upload_limit": "Limite de carregamento",
"pleroma_chat_messages": "Chat do Pleroma"
}, },
"finder": { "finder": {
"error_fetching_user": "Erro ao procurar usuário", "error_fetching_user": "Erro ao pesquisar utilizador",
"find_user": "Buscar usuário" "find_user": "Pesquisar utilizador"
}, },
"general": { "general": {
"apply": "Aplicar", "apply": "Aplicar",
"submit": "Enviar", "submit": "Enviar",
"more": "Mais", "more": "Mais",
"generic_error": "Houve um erro", "generic_error": "Ocorreu um erro",
"optional": "opcional" "optional": "opcional",
"peek": "Espreitar",
"close": "Fechar",
"verify": "Verificar",
"confirm": "Confirmar",
"enable": "Ativar",
"disable": "Desativar",
"cancel": "Cancelar",
"show_less": "Mostrar menos",
"show_more": "Mostrar mais",
"retry": "Tenta novamente",
"error_retry": "Por favor, tenta novamente",
"loading": "A carregar…",
"dismiss": "Ignorar",
"role":
{
"moderator": "Moderador",
"admin": "Admin"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "Cortar imagem", "crop_picture": "Cortar imagem",
"save": "Salvar", "save": "Guardar",
"cancel": "Cancelar" "cancel": "Cancelar",
"save_without_cropping": "Guardar sem recortar"
}, },
"login": { "login": {
"login": "Entrar", "login": "Iniciar Sessão",
"description": "Entrar com OAuth", "description": "Iniciar sessão com OAuth",
"logout": "Sair", "logout": "Terminar sessão",
"password": "Senha", "password": "Palavra-passe",
"placeholder": "p.e. lain", "placeholder": "ex. lain",
"register": "Registrar", "register": "Registar",
"username": "Usuário", "username": "Nome de Utilizador",
"hint": "Entre para participar da discussão" "hint": "Entra para participar na discussão",
"heading": {
"totp": "Autenticação de dois fatores",
"recovery": "Recuperação de dois fatores"
},
"recovery_code": "Código de recuperação",
"authentication_code": "Código de autenticação",
"enter_two_factor_code": "Introduza o código de dois fatores",
"enter_recovery_code": "Introduza um código de recuperação"
}, },
"media_modal": { "media_modal": {
"previous": "Anterior", "previous": "Anterior",
@ -45,100 +74,125 @@
"about": "Sobre", "about": "Sobre",
"back": "Voltar", "back": "Voltar",
"chat": "Chat local", "chat": "Chat local",
"friend_requests": "Solicitações de seguidores", "friend_requests": "Pedidos de seguidores",
"mentions": "Menções", "mentions": "Menções",
"dms": "Mensagens diretas", "dms": "Mensagens Diretas",
"public_tl": "Linha do tempo pública", "public_tl": "Cronologia Pública",
"timeline": "Linha do tempo", "timeline": "Cronologia",
"twkn": "Toda a rede conhecida", "twkn": "Rede conhecida",
"user_search": "Buscar usuários", "user_search": "Pesquisa por Utilizadores",
"who_to_follow": "Quem seguir", "who_to_follow": "Quem seguir",
"preferences": "Preferências" "preferences": "Preferências",
"search": "Pesquisar",
"interactions": "Interações",
"administration": "Administração",
"chats": "Salas de Chat",
"timelines": "Cronologias",
"bookmarks": "Itens Guardados"
}, },
"notifications": { "notifications": {
"broken_favorite": "Status desconhecido, buscando...", "broken_favorite": "Publicação desconhecida, a procurar…",
"favorited_you": "favoritou sua postagem", "favorited_you": "gostou do teu post",
"followed_you": "seguiu você", "followed_you": "seguiu-te",
"load_older": "Carregar notificações antigas", "load_older": "Carregar notificações antigas",
"notifications": "Notificações", "notifications": "Notificações",
"read": "Lido!", "read": "Lido!",
"repeated_you": "repetiu sua postagem", "repeated_you": "partilhou o teu post",
"no_more_notifications": "Mais nenhuma notificação" "no_more_notifications": "Sem mais notificações",
"reacted_with": "reagiu com {0}",
"migrated_to": "migrou para",
"follow_request": "quer seguir-te",
"error": "Erro ao obter notificações: {0}"
}, },
"post_status": { "post_status": {
"new_status": "Postar novo status", "new_status": "Publicar nova publicação",
"account_not_locked_warning": "Sua conta não é {0}. Qualquer pessoa pode te seguir e ver seus posts privados (só para seguidores).", "account_not_locked_warning": "A sua conta não é {0}. Qualquer pessoa pode seguir-te e ver os seus posts privados (só para seguidores).",
"account_not_locked_warning_link": "restrita", "account_not_locked_warning_link": "restrito",
"attachments_sensitive": "Marcar anexos como sensíveis", "attachments_sensitive": "Marcar anexos como sensíveis",
"content_type": { "content_type": {
"text/plain": "Texto puro" "text/plain": "Texto puro",
"text/bbcode": "BBCode",
"text/html": "HTML",
"text/markdown": "Remarcação"
}, },
"content_warning": "Assunto (opcional)", "content_warning": "Assunto (opcional)",
"default": "Acabei de chegar no Rio!", "default": "Acabei de chegar a Lisboa.",
"direct_warning": "Este post será visível apenas para os usuários mencionados.", "direct_warning": "Este post será visível apenas para os usuários mencionados.",
"posting": "Publicando", "posting": "A publicar",
"scope": { "scope": {
"direct": "Direto - Enviar somente aos usuários mencionados", "direct": "Direto - Enviar somente aos usuários mencionados",
"private": "Apenas para seguidores - Enviar apenas para seguidores", "private": "Apenas para seguidores - Enviar apenas para seguidores",
"public": "Público - Enviar a linhas do tempo públicas", "public": "Público - Publicar em cronologias públicas",
"unlisted": "Não listado - Não enviar a linhas do tempo públicas" "unlisted": "Não listado - Não exibir em cronologias públicas"
} },
"scope_notice": {
"unlisted": "Esta publicação não será visível na Cronologia pública e na Rede conhecida por todos",
"private": "Esta publicação será apenas visível para os teus seguidores",
"public": "Esta publicação será visível para todos"
},
"empty_status_error": "Não consegues publicar um post vazio e sem ficheiros",
"preview_empty": "Vazio",
"preview": "Pré-visualização",
"media_description": "Descrição da multimédia",
"media_description_error": "Falha ao atualizar ficheiro, tente novamente",
"direct_warning_to_first_only": "Esta publicação só será visível para os utilizadores mencionados no início da mensagem.",
"direct_warning_to_all": "Esta publicação será visível para todos os utilizadores mencionados."
}, },
"registration": { "registration": {
"bio": "Biografia", "bio": "Biografia",
"email": "Correio eletrônico", "email": "Endereço de e-mail",
"fullname": "Nome para exibição", "fullname": "Nome para exibição",
"password_confirm": "Confirmação de senha", "password_confirm": "Confirmação de palavra-passe",
"registration": "Registro", "registration": "Registo",
"token": "Código do convite", "token": "Código do convite",
"captcha": "CAPTCHA", "captcha": "CAPTCHA",
"new_captcha": "Clique na imagem para carregar um novo captcha", "new_captcha": "Clique na imagem para carregar um novo captcha",
"username_placeholder": "p. ex. lain", "username_placeholder": "ex. lain",
"fullname_placeholder": "p. ex. Lain Iwakura", "fullname_placeholder": "ex. Lain Iwakura",
"bio_placeholder": "e.g.\nOi, sou Lain\nSou uma garota que vive no subúrbio do Japão. Você deve me conhecer da Rede.", "bio_placeholder": "ex.\nOlá, sou a Lain\nSou uma menina de anime que vive no Japão suburbano. Devem conhecer-me do \"the Wired\".",
"validations": { "validations": {
"username_required": "não pode ser deixado em branco", "username_required": "não pode ser deixado em branco",
"fullname_required": "não pode ser deixado em branco", "fullname_required": "não pode ser deixado em branco",
"email_required": "não pode ser deixado em branco", "email_required": "não pode ser deixado em branco",
"password_required": "não pode ser deixado em branco", "password_required": "não pode ser deixado em branco",
"password_confirmation_required": "não pode ser deixado em branco", "password_confirmation_required": "não pode ser deixado em branco",
"password_confirmation_match": "deve ser idêntica à senha" "password_confirmation_match": "deve corresponder à palavra-passe"
} }
}, },
"settings": { "settings": {
"app_name": "Nome do aplicativo", "app_name": "Nome da aplicação",
"attachmentRadius": "Anexos", "attachmentRadius": "Anexos",
"attachments": "Anexos", "attachments": "Anexos",
"avatar": "Avatar", "avatar": "Avatar",
"avatarAltRadius": "Avatares (Notificações)", "avatarAltRadius": "Avatares (Notificações)",
"avatarRadius": "Avatares", "avatarRadius": "Avatares",
"background": "Pano de Fundo", "background": "Imagem de Fundo",
"bio": "Biografia", "bio": "Biografia",
"blocks_tab": "Bloqueios", "blocks_tab": "Bloqueios",
"btnRadius": "Botões", "btnRadius": "Botões",
"cBlue": "Azul (Responder, seguir)", "cBlue": "Azul (Responder, seguir)",
"cGreen": "Verde (Repetir)", "cGreen": "Verde (Partilhar)",
"cOrange": "Laranja (Favoritar)", "cOrange": "Laranja (Favoritar)",
"cRed": "Vermelho (Cancelar)", "cRed": "Vermelho (Cancelar)",
"change_password": "Mudar senha", "change_password": "Mudar palavra-passe",
"change_password_error": "Houve um erro ao modificar sua senha.", "change_password_error": "Ocorreu um erro ao modificar a sua palavra-passe.",
"changed_password": "Senha modificada com sucesso!", "changed_password": "Palavra-passe modificada com sucesso!",
"collapse_subject": "Esconder posts com assunto", "collapse_subject": "Esconder posts com assunto",
"composing": "Escrita", "composing": "Escrita",
"confirm_new_password": "Confirmar nova senha", "confirm_new_password": "Confirmar nova palavra-passe",
"current_avatar": "Seu avatar atual", "current_avatar": "Seu avatar atual",
"current_password": "Sua senha atual", "current_password": "Palavra-passe atual",
"current_profile_banner": "Sua capa de perfil atual", "current_profile_banner": "Sua capa de perfil atual",
"data_import_export_tab": "Importação/exportação de dados", "data_import_export_tab": "Importação/exportação de dados",
"default_vis": "Opção de privacidade padrão", "default_vis": "Opção de privacidade padrão",
"delete_account": "Deletar conta", "delete_account": "Eliminar conta",
"delete_account_description": "Deletar sua conta e mensagens permanentemente.", "delete_account_description": "Apagar os seus dados permanentemente e desativar a sua conta.",
"delete_account_error": "Houve um problema ao deletar sua conta. Se ele persistir, por favor entre em contato com o/a administrador/a da instância.", "delete_account_error": "Ocorreu um erro ao remover a sua conta. Se este persistir, por favor entre em contato com o/a administrador/a da instância.",
"delete_account_instructions": "Digite sua senha no campo abaixo para confirmar a exclusão da conta.", "delete_account_instructions": "Escreva a sua palavra-passe no campo abaixo para confirmar a remoção da conta.",
"avatar_size_instruction": "O tamanho mínimo recomendado para imagens de avatar é 150x150 pixels.", "avatar_size_instruction": "O tamanho mínimo recomendado para imagens de avatar é 150x150 pixels.",
"export_theme": "Salvar predefinições", "export_theme": "Guardar predefinições",
"filtering": "Filtragem", "filtering": "Filtragem",
"filtering_explanation": "Todas as postagens contendo estas palavras serão silenciadas; uma palavra por linha.", "filtering_explanation": "Todas as publicações que contenham estas palavras serão silenciadas; uma palavra por linha",
"follow_export": "Exportar quem você segue", "follow_export": "Exportar quem você segue",
"follow_export_button": "Exportar quem você segue para um arquivo CSV", "follow_export_button": "Exportar quem você segue para um arquivo CSV",
"follow_export_processing": "Processando. Em breve você receberá a solicitação de download do arquivo", "follow_export_processing": "Processando. Em breve você receberá a solicitação de download do arquivo",
@ -148,7 +202,7 @@
"foreground": "Primeiro Plano", "foreground": "Primeiro Plano",
"general": "Geral", "general": "Geral",
"hide_attachments_in_convo": "Ocultar anexos em conversas", "hide_attachments_in_convo": "Ocultar anexos em conversas",
"hide_attachments_in_tl": "Ocultar anexos na linha do tempo.", "hide_attachments_in_tl": "Ocultar anexos na cronologia",
"max_thumbnails": "Número máximo de miniaturas por post", "max_thumbnails": "Número máximo de miniaturas por post",
"hide_isp": "Esconder painel específico da instância", "hide_isp": "Esconder painel específico da instância",
"preload_images": "Pré-carregar imagens", "preload_images": "Pré-carregar imagens",
@ -159,7 +213,7 @@
"import_followers_from_a_csv_file": "Importe seguidores a partir de um arquivo CSV", "import_followers_from_a_csv_file": "Importe seguidores a partir de um arquivo CSV",
"import_theme": "Carregar pré-definição", "import_theme": "Carregar pré-definição",
"inputRadius": "Campos de entrada", "inputRadius": "Campos de entrada",
"checkboxRadius": "Checkboxes", "checkboxRadius": "Caixas de seleção",
"instance_default": "(padrão: {value})", "instance_default": "(padrão: {value})",
"instance_default_simple": "(padrão)", "instance_default_simple": "(padrão)",
"interface": "Interface", "interface": "Interface",
@ -171,16 +225,16 @@
"loop_video": "Repetir vídeos", "loop_video": "Repetir vídeos",
"loop_video_silent_only": "Repetir apenas vídeos sem som (como os \"gifs\" do Mastodon)", "loop_video_silent_only": "Repetir apenas vídeos sem som (como os \"gifs\" do Mastodon)",
"mutes_tab": "Silenciados", "mutes_tab": "Silenciados",
"play_videos_in_modal": "Tocar vídeos diretamente no visualizador de mídia", "play_videos_in_modal": "Reproduzir vídeos diretamente no visualizador de multimédia",
"use_contain_fit": "Não cortar o anexo na miniatura", "use_contain_fit": "Não cortar o anexo na miniatura",
"name": "Nome", "name": "Nome",
"name_bio": "Nome & Biografia", "name_bio": "Nome & Biografia",
"new_password": "Nova senha", "new_password": "Nova palavra-passe",
"notification_visibility": "Tipos de notificação para mostrar", "notification_visibility": "Tipos de notificação para mostrar",
"notification_visibility_follows": "Seguidas", "notification_visibility_follows": "Seguidas",
"notification_visibility_likes": "Favoritos", "notification_visibility_likes": "Favoritos",
"notification_visibility_mentions": "Menções", "notification_visibility_mentions": "Menções",
"notification_visibility_repeats": "Repetições", "notification_visibility_repeats": "Partilhas",
"no_rich_text_description": "Remover formatação de todos os posts", "no_rich_text_description": "Remover formatação de todos os posts",
"no_blocks": "Sem bloqueios", "no_blocks": "Sem bloqueios",
"no_mutes": "Sem silenciados", "no_mutes": "Sem silenciados",
@ -188,7 +242,7 @@
"hide_followers_description": "Não mostrar quem me segue", "hide_followers_description": "Não mostrar quem me segue",
"show_admin_badge": "Mostrar título de Administrador em meu perfil", "show_admin_badge": "Mostrar título de Administrador em meu perfil",
"show_moderator_badge": "Mostrar título de Moderador em meu perfil", "show_moderator_badge": "Mostrar título de Moderador em meu perfil",
"nsfw_clickthrough": "Habilitar clique para ocultar anexos sensíveis", "nsfw_clickthrough": "Ativar clique em anexos e pré-visualizações de links para ocultar anexos NSFW",
"oauth_tokens": "Token OAuth", "oauth_tokens": "Token OAuth",
"token": "Token", "token": "Token",
"refresh_token": "Atualizar Token", "refresh_token": "Atualizar Token",
@ -201,7 +255,7 @@
"profile_banner": "Capa de perfil", "profile_banner": "Capa de perfil",
"profile_tab": "Perfil", "profile_tab": "Perfil",
"radii_help": "Arredondar arestas da interface (em pixel)", "radii_help": "Arredondar arestas da interface (em pixel)",
"replies_in_timeline": "Respostas na linha do tempo", "replies_in_timeline": "Respostas na cronologia",
"reply_visibility_all": "Mostrar todas as respostas", "reply_visibility_all": "Mostrar todas as respostas",
"reply_visibility_following": "Só mostrar respostas direcionadas a mim ou a usuários que sigo", "reply_visibility_following": "Só mostrar respostas direcionadas a mim ou a usuários que sigo",
"reply_visibility_self": "Só mostrar respostas direcionadas a mim", "reply_visibility_self": "Só mostrar respostas direcionadas a mim",
@ -215,7 +269,7 @@
"settings": "Configurações", "settings": "Configurações",
"subject_input_always_show": "Sempre mostrar campo de assunto", "subject_input_always_show": "Sempre mostrar campo de assunto",
"subject_line_behavior": "Copiar assunto ao responder", "subject_line_behavior": "Copiar assunto ao responder",
"subject_line_email": "Como em email: \"re: assunto\"", "subject_line_email": "Como num e-mail: \"re: assunto\"",
"subject_line_mastodon": "Como o Mastodon: copiar como está", "subject_line_mastodon": "Como o Mastodon: copiar como está",
"subject_line_noop": "Não copiar", "subject_line_noop": "Não copiar",
"post_status_content_type": "Tipo de conteúdo do status", "post_status_content_type": "Tipo de conteúdo do status",
@ -225,7 +279,7 @@
"theme": "Tema", "theme": "Tema",
"theme_help": "Use cores em código hexadecimal (#rrggbb) para personalizar seu esquema de cores.", "theme_help": "Use cores em código hexadecimal (#rrggbb) para personalizar seu esquema de cores.",
"theme_help_v2_1": "Você também pode sobrescrever as cores e opacidade de alguns componentes ao modificar o checkbox, use \"Limpar todos\" para limpar todas as modificações.", "theme_help_v2_1": "Você também pode sobrescrever as cores e opacidade de alguns componentes ao modificar o checkbox, use \"Limpar todos\" para limpar todas as modificações.",
"theme_help_v2_2": "Alguns ícones sob registros são indicadores de fundo/contraste de textos, passe por cima para informações detalhadas. Tenha ciência de que os indicadores de contraste não funcionam muito bem com transparência.", "theme_help_v2_2": "Alguns ícones em registo são indicadores de fundo/contraste de textos, passe por cima para obter informações detalhadas. Tenha em atenção que os indicadores de contraste não funcionam muito bem com transparência.",
"tooltipRadius": "Dicas/alertas", "tooltipRadius": "Dicas/alertas",
"upload_a_photo": "Enviar uma foto", "upload_a_photo": "Enviar uma foto",
"user_settings": "Configurações de Usuário", "user_settings": "Configurações de Usuário",
@ -245,7 +299,24 @@
"save_load_hint": "Manter as opções preserva as opções atuais ao selecionar ou carregar temas; também salva as opções ao exportar um tempo. Quanto todos os campos estiverem desmarcados, tudo será salvo ao exportar o tema.", "save_load_hint": "Manter as opções preserva as opções atuais ao selecionar ou carregar temas; também salva as opções ao exportar um tempo. Quanto todos os campos estiverem desmarcados, tudo será salvo ao exportar o tema.",
"reset": "Restaurar o padrão", "reset": "Restaurar o padrão",
"clear_all": "Limpar tudo", "clear_all": "Limpar tudo",
"clear_opacity": "Limpar opacidade" "clear_opacity": "Limpar opacidade",
"help": {
"upgraded_from_v2": "O PleromaFE foi atualizado, a aparência do tema poderá ser um pouco diferente.",
"snapshot_source_mismatch": "Conflito de versões: o mais provável é que o FE tenha revertido e voltado a atualizar, foi alterado o tema numa versão anterior do FE, o mais provável é desejar utilizar a versão anterior; caso contrário, utilize a nova versão.",
"migration_napshot_gone": "Por algum motivo, a pré-visualização estava em falta, algumas coisas poderão parecer diferentes do que se lembra.",
"migration_snapshot_ok": "Para estar seguro, foi carregada uma versão de pré-visualização do tema. Pode tentar carregar dados do tema.",
"fe_downgraded": "Versão do PleromaFE revertida.",
"fe_upgraded": "O criador de temas do PleromaFE foi atualizado depois da atualização da versão.",
"snapshot_missing": "Não existia nenhuma pré-visualização do tema no ficheiro, então pode parecer diferente do previsto originalmente.",
"snapshot_present": "Foi carregada uma pré-visualização do tema, todos os valores são substituídos. Caso contrário, pode carregar o tema completo.",
"older_version_imported": "O ficheiro que importaste foi criado numa versão antiga do FE.",
"future_version_imported": "O ficheiro que importaste foi criado para uma versão mais recente do FE.",
"v2_imported": "O ficheiro que importaste foi feito para uma versão antiga do FE. Tentamos maximizar a compatibilidade, porém, poderão existir incongruências."
},
"use_source": "Nova versão",
"use_snapshot": "Versão antiga",
"keep_as_is": "Manter como está",
"load_theme": "Carregar tema"
}, },
"common": { "common": {
"color": "Cor", "color": "Cor",
@ -280,7 +351,27 @@
"borders": "Bordas", "borders": "Bordas",
"buttons": "Botões", "buttons": "Botões",
"inputs": "Caixas de entrada", "inputs": "Caixas de entrada",
"faint_text": "Texto esmaecido" "faint_text": "Texto esmaecido",
"chat": {
"border": "Borda",
"outgoing": "Enviadas",
"incoming": "Recebidas"
},
"tabs": "Abas",
"toggled": "Alternado",
"disabled": "Desativado",
"selectedMenu": "Elemento do menu seleccionado",
"selectedPost": "Publicação seleccionada",
"pressed": "Pressionado",
"highlight": "Elementos destacados",
"icons": "Ícones",
"poll": "Gráfico da sondagem",
"wallpaper": "Fundo de ecrã",
"underlay": "Sublinhado",
"popover": "Sugestões, menus, etiquetas",
"post": "Publicações/Bios",
"alert_neutral": "Neutro",
"alert_warning": "Precaução"
}, },
"radii": { "radii": {
"_tab_label": "Arredondado" "_tab_label": "Arredondado"
@ -298,7 +389,7 @@
"always_drop_shadow": "Atenção, esta sombra sempre utiliza {0} quando compatível com o navegador.", "always_drop_shadow": "Atenção, esta sombra sempre utiliza {0} quando compatível com o navegador.",
"drop_shadow_syntax": "{0} não é compatível com o parâmetro {1} e a palavra-chave {2}.", "drop_shadow_syntax": "{0} não é compatível com o parâmetro {1} e a palavra-chave {2}.",
"avatar_inset": "Tenha em mente que combinar as sombras de inserção e a não-inserção em avatares pode causar resultados inesperados em avatares transparentes.", "avatar_inset": "Tenha em mente que combinar as sombras de inserção e a não-inserção em avatares pode causar resultados inesperados em avatares transparentes.",
"spread_zero": "Sombras com uma difusão > 0 aparecerão como se fossem definidas como 0.", "spread_zero": "Sombras com difusão > 0 aparecerão como se fossem definidas como zero",
"inset_classic": "Sombras de inserção utilizarão {0}" "inset_classic": "Sombras de inserção utilizarão {0}"
}, },
"components": { "components": {
@ -313,7 +404,8 @@
"buttonPressed": "Botão (pressionado)", "buttonPressed": "Botão (pressionado)",
"buttonPressedHover": "Botão (pressionado+em cima)", "buttonPressedHover": "Botão (pressionado+em cima)",
"input": "Campo de entrada" "input": "Campo de entrada"
} },
"hintV3": "Para as sombras, também pode usar a notação {0} para usar outro espaço de cor."
}, },
"fonts": { "fonts": {
"_tab_label": "Fontes", "_tab_label": "Fontes",
@ -336,30 +428,143 @@
"button": "Botão", "button": "Botão",
"text": "Vários {0} e {1}", "text": "Vários {0} e {1}",
"mono": "conteúdo", "mono": "conteúdo",
"input": "Acabei de chegar no Rio!", "input": "Acabei de chegar a Lisboa.",
"faint_link": "manual útil", "faint_link": "manual útil",
"fine_print": "Leia nosso {0} para não aprender nada!", "fine_print": "Leia nosso {0} para não aprender nada!",
"header_faint": "Está ok!", "header_faint": "Isto está bem",
"checkbox": "Li os termos e condições", "checkbox": "Li os termos e condições",
"link": "um belo link" "link": "um belo link"
} }
} },
"mfa": {
"scan": {
"secret_code": "Chave",
"title": "Scan",
"desc": "Utilizando a sua aplicação de dois fatores, faça scan deste código QR ou insira a chave de texto:"
},
"authentication_methods": "Métodos de autenticação",
"recovery_codes": "Códigos de recuperação.",
"generate_new_recovery_codes": "Gerar novos códigos de recuperação",
"confirm_and_enable": "Confirmar e ativar a palavra-passe de utilização única",
"otp": "Palavra-passe de utilização única",
"verify": {
"desc": "Para ativar a autenticação de dois fatores, introduza o código da sua aplicação de dois fatores:"
},
"recovery_codes_warning": "Anote os códigos ou armazene-os num lugar seguro - caso contrário, não os voltará a ver. Se perder acesso à sua aplicação de dois fatores e aos códigos de recuperação, a sua conta ficará bloqueada.",
"waiting_a_recovery_codes": "A receber códigos de recuperação…",
"warning_of_generate_new_codes": "Quando gera novos códigos de recuperação, os antigos deixam de funcionar.",
"title": "Autenticação de Dois Fatores",
"wait_pre_setup_otp": "pré-configuração de palavra-passe de utilização única",
"setup_otp": "Configurar palavra-passe de utilização única"
},
"security": "Segurança",
"mute_import_error": "Erro ao importar os silenciados",
"mute_import": "Importar silenciados",
"mute_export_button": "Exporta os silenciados para um ficheiro csv",
"mute_export": "Exportar silenciados",
"blocks_imported": "Lista de utilizadores bloqueados importada! O processo pode demorar alguns instantes.",
"block_import_error": "Erro ao importar a lista de utilizadores bloqueados",
"block_import": "Importar utilizadores bloqueados",
"block_export_button": "Exporta a tua lista de utilizadores bloqueados para um ficheiro csv",
"block_export": "Exportar utilizadores bloqueados",
"enter_current_password_to_confirm": "Introduza a sua palavra-passe atual para confirmar a sua identidade",
"mutes_and_blocks": "Silenciados e Bloqueados",
"chatMessageRadius": "Mensagem de texto",
"changed_email": "Endereço de e-mail modificado com sucesso!",
"change_email_error": "Ocorreu um erro ao modificar o seu endereço de e-mail.",
"change_email": "Mudar Endereço de E-mail",
"bot": "Esta uma conta robô",
"import_mutes_from_a_csv_file": "Importar silenciados de um ficheiro csv",
"mutes_imported": "Silenciados importados! Processá-los pode demorar alguns instantes.",
"allow_following_move": "Permitir seguimento automático quando a conta for migrada para outra instância",
"domain_mutes": "Domínios",
"discoverable": "Permitir a descoberta desta conta em resultados de busca e outros serviços",
"emoji_reactions_on_timeline": "Mostrar reações de emoji na timeline",
"hide_muted_posts": "Esconder posts de utilizadores silenciados",
"hide_follows_count_description": "Não mostrar o número de contas seguidas",
"hide_followers_count_description": "Não mostrar o número de seguidores",
"notification_visibility_emoji_reactions": "Reações",
"new_email": "Novo endereço de e-mail",
"profile_fields": {
"value": "Conteúdo",
"add_field": "Adicionar campo",
"label": "Metadados do perfil",
"name": "Etiqueta"
},
"import_blocks_from_a_csv_file": "Importar bloqueados a partir de um arquivo CSV",
"hide_wallpaper": "Esconder papel de parede da instância",
"notification_setting_privacy": "Privacidade",
"notification_setting_filters": "Filtros",
"fun": "Divertido",
"user_mutes": "Utilizadores",
"type_domains_to_mute": "Pesquisar domínios para silenciar",
"useStreamingApiWarning": "(não recomendado, experimental, pode omitir publicações)",
"useStreamingApi": "Receber publicações e notificações em tempo real",
"minimal_scopes_mode": "Minimizar as opções de publicação",
"search_user_to_mute": "Pesquisar utilizadores que pretende silenciar",
"search_user_to_block": "Pesquisa quais utilizadores desejas bloquear",
"notification_setting_hide_notification_contents": "Ocultar o remetente e o conteúdo das notificações push",
"version": {
"frontend_version": "Versão do Frontend",
"backend_version": "Versão do Backend",
"title": "Versão"
},
"notification_blocks": "Bloquear um utilizador previne todas as notificações, bem como as desativa.",
"notification_mutes": "Para deixar de receber notificações de um utilizador específico, silencia-o.",
"notification_setting_block_from_strangers": "Bloqueia as notificações de utilizadores que não segues",
"greentext": "Texto verde (meme arrows)",
"virtual_scrolling": "Otimizar a apresentação da cronologia",
"reset_background_confirm": "Tens a certeza que desejas redefinir o fundo?",
"reset_banner_confirm": "Tens a certeza que desejas redefinir a imagem do cabeçalho?",
"reset_avatar_confirm": "Tens a certeza que desejas redefinir o avatar?",
"reset_profile_banner": "Redefinir imagem do cabeçalho do perfil",
"reset_profile_background": "Redefinir fundo de perfil",
"reset_avatar": "Redefinir avatar",
"autohide_floating_post_button": "Automaticamente ocultar o botão 'Nova Publicação' (telemóvel)",
"notification_visibility_moves": "Utilizador Migrado",
"accent": "Destaque",
"pad_emoji": "Preencher espaços ao adicionar emojis do seletor"
}, },
"timeline": { "timeline": {
"collapse": "Esconder", "collapse": "Esconder",
"conversation": "Conversa", "conversation": "Conversa",
"error_fetching": "Erro ao buscar atualizações", "error_fetching": "Erro ao buscar atualizações",
"load_older": "Carregar postagens antigas", "load_older": "Carregar postagens antigas",
"no_retweet_hint": "Posts apenas para seguidores ou diretos não podem ser repetidos", "no_retweet_hint": "Posts apenas para seguidores ou diretos não podem ser partilhados",
"repeated": "Repetido", "repeated": "partilhado",
"show_new": "Mostrar novas", "show_new": "Mostrar novas",
"up_to_date": "Atualizado", "up_to_date": "Atualizado",
"no_more_statuses": "Sem mais posts", "no_more_statuses": "Sem mais posts",
"no_statuses": "Sem posts" "no_statuses": "Sem posts",
"reload": "Recarregar",
"error": "Erro a obter a cronologia: {0}"
}, },
"status": { "status": {
"reply_to": "Responder a", "reply_to": "Responder a",
"replies_list": "Respostas:" "replies_list": "Respostas:",
"unbookmark": "Remover post dos Items Guardados",
"expand": "Expandir",
"nsfw": "NSFW (Não apropriado para trabalho)",
"status_deleted": "Esta publicação foi apagada",
"hide_content": "Ocultar o conteúdo",
"show_content": "Mostrar o conteúdo",
"hide_full_subject": "Ocultar o assunto completo",
"show_full_subject": "Mostrar o assunto completo",
"thread_muted_and_words": ", contém:",
"thread_muted": "Conversação silenciada",
"external_source": "Fonte externa",
"copy_link": "Copiar o link do post",
"status_unavailable": "Publicação indisponível",
"unmute_conversation": "Mostrar a conversação",
"mute_conversation": "Silenciar a conversação",
"delete_confirm": "Tens a certeza que desejas apagar a publicação?",
"bookmark": "Guardar",
"pin": "Fixar no perfil",
"pinned": "Afixado",
"unpin": "Desafixar do perfil",
"delete": "Eliminar publicação",
"repeats": "Partilhados",
"favorites": "Favoritos"
}, },
"user_card": { "user_card": {
"approve": "Aprovar", "approve": "Aprovar",
@ -377,21 +582,48 @@
"following": "Seguindo!", "following": "Seguindo!",
"follows_you": "Segue você!", "follows_you": "Segue você!",
"its_you": "É você!", "its_you": "É você!",
"media": "Mídia", "media": "Multimédia",
"mute": "Silenciar", "mute": "Silenciar",
"muted": "Silenciado", "muted": "Silenciado",
"per_day": "por dia", "per_day": "por dia",
"remote_follow": "Seguir remotamente", "remote_follow": "Seguir remotamente",
"statuses": "Postagens", "statuses": "Postagens",
"unblock": "Desbloquear", "unblock": "Desbloquear",
"unblock_progress": "Desbloqueando...", "unblock_progress": "A desbloquear…",
"block_progress": "Bloqueando...", "block_progress": "A bloquear…",
"unmute": "Retirar silêncio", "unmute": "Retirar silêncio",
"unmute_progress": "Retirando silêncio...", "unmute_progress": "A retirar silêncio…",
"mute_progress": "Silenciando..." "mute_progress": "A silenciar…",
"admin_menu": {
"delete_user_confirmation": "Tens a certeza? Esta ação não pode ser revertida.",
"delete_user": "Eliminar utilizador",
"quarantine": "Não permitir publicações de utilizadores de instâncias remotas",
"disable_any_subscription": "Não permitir que nenhum utilizador te siga",
"disable_remote_subscription": "Não permitir seguidores de instâncias remotas",
"sandbox": "Forçar publicações apenas para seguidores",
"force_unlisted": "Forçar publicações como não listadas",
"strip_media": "Eliminar ficheiros multimédia das publicações",
"force_nsfw": "Marcar todas as publicações como NSFW (não apropriado para o trabalho)",
"delete_account": "Eliminar Conta",
"deactivate_account": "Desativar conta",
"activate_account": "Ativar conta",
"revoke_moderator": "Revogar permissões de Moderador",
"grant_moderator": "Conceder permissões de Moderador",
"revoke_admin": "Revogar permissões de Admin",
"grant_admin": "Conceder permissões de Admin",
"moderation": "Moderação"
},
"show_repeats": "Mostrar partilhas",
"hide_repeats": "Ocultar partilhas",
"unsubscribe": "Retirar subscrição",
"subscribe": "Subscrever",
"report": "Denunciar",
"message": "Mensagem",
"mention": "Mencionar",
"hidden": "Ocultar"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Linha do tempo do usuário", "timeline_title": "Cronologia do Utilizador",
"profile_does_not_exist": "Desculpe, este perfil não existe.", "profile_does_not_exist": "Desculpe, este perfil não existe.",
"profile_loading_error": "Desculpe, houve um erro ao carregar este perfil." "profile_loading_error": "Desculpe, houve um erro ao carregar este perfil."
}, },
@ -400,17 +632,22 @@
"who_to_follow": "Quem seguir" "who_to_follow": "Quem seguir"
}, },
"tool_tip": { "tool_tip": {
"media_upload": "Envio de mídia", "media_upload": "Envio de multimédia",
"repeat": "Repetir", "repeat": "Partilhar",
"reply": "Responder", "reply": "Responder",
"favorite": "Favoritar", "favorite": "Favoritar",
"user_settings": "Configurações do usuário" "user_settings": "Configurações do usuário",
"bookmark": "Guardar",
"reject_follow_request": "Rejeitar o pedido de seguimento",
"accept_follow_request": "Aceitar o pedido de seguimento",
"add_reaction": "Adicionar Reação"
}, },
"upload":{ "upload": {
"error": { "error": {
"base": "Falha no envio.", "base": "Falha no envio.",
"file_too_big": "Arquivo grande demais [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "file_too_big": "Arquivo grande demais [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Tente novamente mais tarde" "default": "Tente novamente mais tarde",
"message": "Falha ao enviar: {0}"
}, },
"file_size_units": { "file_size_units": {
"B": "B", "B": "B",
@ -419,5 +656,179 @@
"GiB": "GiB", "GiB": "GiB",
"TiB": "TiB" "TiB": "TiB"
} }
},
"about": {
"mrf": {
"simple": {
"quarantine": "Quarentena",
"reject": "Rejeitar",
"accept": "Aceitar",
"media_removal_desc": "Este domínio remove multimédia das publicações dos seguintes domínios:",
"media_removal": "Remoção de multimédia",
"ftl_removal_desc": "Este domínio remove os seguintes domínios da cronologia \"Rede conhecida por todos\":",
"quarantine_desc": "Este domínio apenas irá publicar nos seguintes domínios:",
"reject_desc": "Este domínio não aceitará mensagens dos seguintes domínios:",
"accept_desc": "Este domínio aceita apenas mensagens dos seguintes domínios:",
"simple_policies": "Políticas especificas do domínio",
"media_nsfw": "Forçar definição de multimédia como Sensível",
"ftl_removal": "Remoção da cronologia da \"Rede conhecida por todos\"",
"media_nsfw_desc": "Este domínio força a multimédia a ser marcada como sensível nos seguintes domínios:"
},
"keyword": {
"replace": "Substituir",
"reject": "Rejeitar",
"is_replaced_by": "→",
"keyword_policies": "Política de Palavras-Chave",
"ftl_removal": "Remoção da cronologia da \"Rede conhecida por todos\""
},
"federation": "Federação",
"mrf_policies": "Ativar Políticas MRF",
"mrf_policies_desc": "Políticas MRF manipulam o comportamento da federação nos domínios. As seguintes políticas estão ativadas:"
},
"staff": "Staff"
},
"remote_user_resolver": {
"searching_for": "A pesquisar por",
"error": "Não encontrado.",
"remote_user_resolver": "Resolução de utilizador remoto"
},
"emoji": {
"unicode": "Emoji Unicode",
"custom": "Emoji customizado",
"add_emoji": "Inserir emoji",
"search_emoji": "Pesquisar por um emoji",
"emoji": "Emoji",
"load_all": "A carregar todos os {emojiAmount} emojis",
"load_all_hint": "Carregado o primeiro emoji {saneAmount}, carregar todos os emojis pode causar problemas de desempenho.",
"keep_open": "Manter o seletor aberto",
"stickers": "Autocolantes"
},
"polls": {
"single_choice": "Escolha única",
"vote": "Vota",
"votes": "votos",
"option": "Opção",
"add_option": "Adicionar Opção",
"not_enough_options": "Demasiado poucas opções únicas na sondagem",
"expired": "A sondagem terminou há {0}",
"expires_in": "A sondagem termina em {0}",
"expiry": "Tempo para finalizar sondagem",
"multiple_choices": "Escolha múltipla",
"type": "Tipo de sondagem",
"add_poll": "Adicionar Sondagem"
},
"importer": {
"error": "Ocorreu um erro ao importar este ficheiro.",
"success": "Importado com sucesso.",
"submit": "Enviar"
},
"exporter": {
"processing": "A processar, brevemente ser-te-á pedido que descarregues o ficheiro",
"export": "Exportar"
},
"domain_mute_card": {
"mute_progress": "A silenciar…",
"mute": "Silenciar",
"unmute": "Remover silêncio",
"unmute_progress": "A remover o silêncio…"
},
"selectable_list": {
"select_all": "Seleccionar tudo"
},
"interactions": {
"load_older": "Carregar interações mais antigas",
"follows": "Novos seguidores",
"favs_repeats": "Gostos e Partilhas",
"moves": "O utilizador migra"
},
"errors": {
"storage_unavailable": "O Pleroma não conseguiu aceder ao armazenamento do navegador. A sua sessão ou definições locais não serão armazenadas e poderá encontrar problemas inesperados. Tente ativar as cookies."
},
"shoutbox": {
"title": "Chat Geral"
},
"chats": {
"chats": "Chats",
"empty_chat_list_placeholder": "Não tens conversações ainda. Inicia uma nova conversa!",
"error_sending_message": "Ocorreu algo de errado ao enviar a mensagem.",
"error_loading_chat": "Ocorreu algo de errado ao carregar o chat.",
"delete_confirm": "Desejas realmente apagar esta mensagem?",
"more": "Mais",
"empty_message_error": "Não podes publicar uma mensagem vazia",
"new": "Nova conversação",
"delete": "Apagar",
"message_user": "Mensagem de {nickname}",
"you": "Tu:"
},
"search": {
"hashtags": "Hashtags",
"no_results": "Sem resultados",
"person_talking": "{count} pessoa a falar",
"people_talking": "{0} pessoas a falar",
"people": "Pessoas"
},
"display_date": {
"today": "Hoje"
},
"file_type": {
"file": "Ficheiro",
"image": "Imagem",
"video": "Vídeo",
"audio": "Áudio"
},
"password_reset": {
"password_reset_required_but_mailer_is_disabled": "Deves repor a tua palavra-passe, porém, a reposição de palavra-passe está desativada. Contacta o administrador da tua instância.",
"password_reset_required": "Deves repor a tua palavra-passe para iniciar sessão.",
"password_reset_disabled": "A reposição da palavra-passe foi desativada. Contacta o administrador da tua instância.",
"too_many_requests": "Alcançaste o limite de tentativas, tenta novamente mais tarde.",
"return_home": "Voltar à página principal",
"check_email": "Verifica o teu endereço de e-mail para obter um link para repor a tua palavra-passe.",
"placeholder": "O teu endereço de e-mail ou nome de utilizador",
"instruction": "Introduz o teu endereço de e-mail ou nome de utilizador. Enviaremos um link para repores a tua palavra-passe.",
"password_reset": "Repor palavra-passe",
"forgot_password": "Esqueceu-se da palavra-passe?"
},
"user_reporting": {
"generic_error": "Ocorreu um erro ao processar o teu pedido.",
"submit": "Enviar",
"forward_to": "Encaminhar para {0}",
"forward_description": "A conta é de outro servidor. Enviar também uma cópia da denúncia à outra instância?",
"additional_comments": "Comentários adicionais",
"add_comment_description": "Esta denúncia será enviada aos moderadores desta instância. Podes fornecer uma explicação pela qual te encontras a denunciar esta conta abaixo:",
"title": "Denunciar {0}"
},
"time": {
"years_short": "{0}a",
"year_short": "{0}a",
"years": "{0} anos",
"year": "{0} ano",
"weeks_short": "{0}sem",
"week_short": "{0}sem",
"weeks": "{0} semanas",
"week": "{0} semana",
"seconds_short": "{0}s",
"second_short": "{0}s",
"seconds": "{0} segundos",
"second": "{0} segundo",
"now": "agora mesmo",
"now_short": "agora",
"months_short": "{0}m",
"month_short": "{0}m",
"months": "{0} meses",
"month": "{0} mês",
"minutes_short": "{0}min",
"minute_short": "{0}min",
"minutes": "{0} minutos",
"minute": "{0} minuto",
"in_past": "há {0}",
"in_future": "em {0}",
"hours_short": "{0}h",
"hour_short": "{0}h",
"hours": "{0} horas",
"hour": "{0} hora",
"days_short": "{0}d",
"day_short": "{0}d",
"days": "{0} dias",
"day": "{0} dia"
} }
} }

View file

@ -24,7 +24,11 @@
"retry": "Попробуйте еще раз", "retry": "Попробуйте еще раз",
"error_retry": "Пожалуйста попробуйте еще раз", "error_retry": "Пожалуйста попробуйте еще раз",
"close": "Закрыть", "close": "Закрыть",
"loading": "Загрузка…" "loading": "Загрузка…",
"role": {
"moderator": "Модератор",
"admin": "Администратор"
}
}, },
"login": { "login": {
"login": "Войти", "login": "Войти",
@ -183,14 +187,14 @@
"change_password": "Сменить пароль", "change_password": "Сменить пароль",
"change_password_error": "Произошла ошибка при попытке изменить пароль.", "change_password_error": "Произошла ошибка при попытке изменить пароль.",
"changed_password": "Пароль изменён успешно!", "changed_password": "Пароль изменён успешно!",
"collapse_subject": "Сворачивать посты с темой", "collapse_subject": "Сворачивать статусы с темой",
"confirm_new_password": "Подтверждение нового пароля", "confirm_new_password": "Подтверждение нового пароля",
"current_avatar": "Текущий аватар", "current_avatar": "Текущий аватар",
"current_password": "Текущий пароль", "current_password": "Текущий пароль",
"current_profile_banner": "Текущий баннер профиля", "current_profile_banner": "Текущий баннер профиля",
"data_import_export_tab": "Импорт / Экспорт данных", "data_import_export_tab": "Импорт / Экспорт данных",
"delete_account": "Удалить аккаунт", "delete_account": "Удалить аккаунт",
"delete_account_description": "Удалить ваш аккаунт и все ваши сообщения.", "delete_account_description": "Удалить вашу учётную запись и все ваши сообщения.",
"delete_account_error": "Возникла ошибка в процессе удаления вашего аккаунта. Если это повторяется, свяжитесь с администратором вашего сервера.", "delete_account_error": "Возникла ошибка в процессе удаления вашего аккаунта. Если это повторяется, свяжитесь с администратором вашего сервера.",
"delete_account_instructions": "Введите ваш пароль в поле ниже для подтверждения удаления.", "delete_account_instructions": "Введите ваш пароль в поле ниже для подтверждения удаления.",
"export_theme": "Сохранить Тему", "export_theme": "Сохранить Тему",
@ -238,7 +242,7 @@
"hide_followers_count_description": "Не показывать число моих подписчиков", "hide_followers_count_description": "Не показывать число моих подписчиков",
"show_admin_badge": "Показывать значок администратора в моем профиле", "show_admin_badge": "Показывать значок администратора в моем профиле",
"show_moderator_badge": "Показывать значок модератора в моем профиле", "show_moderator_badge": "Показывать значок модератора в моем профиле",
"nsfw_clickthrough": "Включить скрытие NSFW вложений и не показывать изображения в предпросмотре ссылок для NSFW статусов", "nsfw_clickthrough": "Включить скрытие вложений и предпросмотра ссылок для NSFW статусов",
"oauth_tokens": "OAuth токены", "oauth_tokens": "OAuth токены",
"token": "Токен", "token": "Токен",
"refresh_token": "Рефреш токен", "refresh_token": "Рефреш токен",
@ -295,7 +299,14 @@
"use_source": "Новая версия", "use_source": "Новая версия",
"use_snapshot": "Старая версия", "use_snapshot": "Старая версия",
"keep_as_is": "Оставить, как есть", "keep_as_is": "Оставить, как есть",
"load_theme": "Загрузить тему" "load_theme": "Загрузить тему",
"help": {
"fe_upgraded": "Движок тем для фронт-энда Pleroma был изменен после обновления.",
"older_version_imported": "Файл, который вы импортировали, был сделан в старой версии фронт-энда.",
"future_version_imported": "Файл, который вы импортировали, был сделан в новой версии фронт-энда.",
"v2_imported": "Файл, который вы импортировали, был сделан под старый фронт-энд. Мы стараемся улучшить совместимость, но все еще возможны несостыковки.",
"upgraded_from_v2": "Фронт-энд Pleroma был изменен. Выбранная тема может выглядеть слегка по-другому."
}
}, },
"common": { "common": {
"color": "Цвет", "color": "Цвет",
@ -330,7 +341,9 @@
"borders": "Границы", "borders": "Границы",
"buttons": "Кнопки", "buttons": "Кнопки",
"inputs": "Поля ввода", "inputs": "Поля ввода",
"faint_text": "Маловажный текст" "faint_text": "Маловажный текст",
"post": "Сообщения и описание пользователя",
"alert_neutral": "Нейтральный"
}, },
"radii": { "radii": {
"_tab_label": "Скругление" "_tab_label": "Скругление"
@ -451,7 +464,19 @@
"virtual_scrolling": "Оптимизировать рендеринг ленты", "virtual_scrolling": "Оптимизировать рендеринг ленты",
"hide_wallpaper": "Скрыть обои узла", "hide_wallpaper": "Скрыть обои узла",
"accent": "Акцент", "accent": "Акцент",
"upload_a_photo": "Загрузить фото" "upload_a_photo": "Загрузить фото",
"notification_mutes": "Чтобы не получать уведомления от определённого пользователя, заглушите его.",
"reset_avatar_confirm": "Вы действительно хотите сбросить личный образ?",
"reset_profile_banner": "Сбросить личный баннер",
"reset_profile_background": "Сбросить личные обои",
"reset_avatar": "Сбросить личный образ",
"search_user_to_mute": "Искать, кого вы хотите заглушить",
"search_user_to_block": "Искать, кого вы хотите заблокировать",
"pad_emoji": "Выделять эмодзи пробелами при добавлении из панели",
"avatar_size_instruction": "Желательный наименьший размер личного образа 150 на 150 пикселей.",
"enable_web_push_notifications": "Включить web push-уведомления",
"notification_blocks": "Блокировка пользователя выключает все уведомления от него, а также отписывает вас от него.",
"notification_setting_hide_notification_contents": "Скрыть отправителя и содержимое push-уведомлений"
}, },
"timeline": { "timeline": {
"collapse": "Свернуть", "collapse": "Свернуть",
@ -465,7 +490,7 @@
"error": "Ошибка при обновлении ленты: {0}" "error": "Ошибка при обновлении ленты: {0}"
}, },
"status": { "status": {
"bookmark": "В закладки", "bookmark": "Добавить в закладки",
"unbookmark": "Удалить из закладок", "unbookmark": "Удалить из закладок",
"status_deleted": "Пост удален", "status_deleted": "Пост удален",
"reply_to": "Ответ", "reply_to": "Ответ",
@ -473,7 +498,11 @@
"favorites": "Понравилось", "favorites": "Понравилось",
"unmute_conversation": "Прекратить игнорировать разговор", "unmute_conversation": "Прекратить игнорировать разговор",
"mute_conversation": "Игнорировать разговор", "mute_conversation": "Игнорировать разговор",
"thread_muted": "Разговор игнорируется" "thread_muted": "Разговор игнорируется",
"external_source": "Перейти к источнику",
"delete_confirm": "Вы действительно хотите удалить данный статус?",
"delete": "Удалить",
"copy_link": "Скопировать ссылку"
}, },
"user_card": { "user_card": {
"block": "Заблокировать", "block": "Заблокировать",
@ -515,7 +544,8 @@
"media": "С вложениями", "media": "С вложениями",
"mention": "Упомянуть", "mention": "Упомянуть",
"show_repeats": "Показывать повторы", "show_repeats": "Показывать повторы",
"hide_repeats": "Скрыть повторы" "hide_repeats": "Скрыть повторы",
"report": "Пожаловаться"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Лента пользователя" "timeline_title": "Лента пользователя"
@ -584,7 +614,9 @@
"title": "Особенности", "title": "Особенности",
"gopher": "Gopher", "gopher": "Gopher",
"who_to_follow": "Предложения кого читать", "who_to_follow": "Предложения кого читать",
"pleroma_chat_messages": "Pleroma Чат" "pleroma_chat_messages": "Pleroma Чат",
"upload_limit": "Наибольший размер загружаемого файла",
"scope_options": "Настраиваемая видимость статусов"
}, },
"tool_tip": { "tool_tip": {
"accept_follow_request": "Принять запрос на чтение", "accept_follow_request": "Принять запрос на чтение",
@ -673,6 +705,7 @@
"you": "Вы:" "you": "Вы:"
}, },
"remote_user_resolver": { "remote_user_resolver": {
"error": "Не найдено." "error": "Не найдено.",
"searching_for": "Ищем"
} }
} }

View file

@ -17,7 +17,11 @@
"more": "Більше", "more": "Більше",
"submit": "Відправити", "submit": "Відправити",
"apply": "Застосувати", "apply": "Застосувати",
"peek": "Глянути" "peek": "Глянути",
"role": {
"moderator": "Модератор",
"admin": "Адміністратор"
}
}, },
"finder": { "finder": {
"error_fetching_user": "Користувача не знайдено", "error_fetching_user": "Користувача не знайдено",
@ -25,11 +29,11 @@
}, },
"features_panel": { "features_panel": {
"gopher": "Gopher", "gopher": "Gopher",
"pleroma_chat_messages": "Локальні балачки", "pleroma_chat_messages": "Чати",
"chat": "Міні-чат", "chat": "Міні-чат",
"who_to_follow": "Кого відстежувати", "who_to_follow": "Кого відстежувати",
"title": "Особливості", "title": "Особливості",
"scope_options": "Параметри осягу", "scope_options": "Параметри обсягу",
"media_proxy": "Посередник медіа-даних", "media_proxy": "Посередник медіа-даних",
"text_limit": "Ліміт символів", "text_limit": "Ліміт символів",
"upload_limit": "Обмеження завантажень" "upload_limit": "Обмеження завантажень"
@ -39,9 +43,9 @@
"export": "Експорт" "export": "Експорт"
}, },
"domain_mute_card": { "domain_mute_card": {
"unmute_progress": "Вимикаю…", "unmute_progress": "Вмикаю…",
"unmute": "Вимкнути заглушення", "unmute": "Вимкнути заглушення",
"mute_progress": "Вмикаю…", "mute_progress": "Вимикаю…",
"mute": "Ігнорувати" "mute": "Ігнорувати"
}, },
"shoutbox": { "shoutbox": {
@ -51,13 +55,13 @@
"staff": "Адміністрація", "staff": "Адміністрація",
"mrf": { "mrf": {
"simple": { "simple": {
"media_nsfw_desc": "Даний інстанс примусово позначає медіа в наступних інстансах як NSFW:", "media_nsfw_desc": "Даний інстанс примусово позначає медіа в наступних інстансах як дратівливий:",
"media_nsfw": "Примусове визначення медіа як дратівливого", "media_nsfw": "Примусове визначення медіа як дратівливого",
"media_removal_desc": "Поточний інстанс видаляє медіа з дописів на перелічених інстансах:", "media_removal_desc": "Поточний інстанс видаляє медіа з дописів на перелічених інстансах:",
"media_removal": "Видалення медіа", "media_removal": "Видалення медіа",
"ftl_removal_desc": "Цей інстанс видаляє перелічені інстанси з \"Усієї відомої мережі\":", "ftl_removal_desc": "Цей інстанс видаляє перелічені інстанси з Федеративної стрічки:",
"ftl_removal": "Видалення з \"Усієї відомої мережі\"", "ftl_removal": "Видалення зі стрічки Федеративної мережі",
"quarantine_desc": "Поточний інстанс буде надсилати тільки публічні дописи наступним інстансам:", "quarantine_desc": "Поточний інстанс надсилатиме тільки публічні дописи наступним інстансам:",
"quarantine": "Карантин", "quarantine": "Карантин",
"reject_desc": "Поточний інстанс не прийматиме повідомлення з перелічених інстансів:", "reject_desc": "Поточний інстанс не прийматиме повідомлення з перелічених інстансів:",
"accept": "Прийняти", "accept": "Прийняти",
@ -66,7 +70,7 @@
"simple_policies": "Правила поточного інстансу" "simple_policies": "Правила поточного інстансу"
}, },
"mrf_policies_desc": "Правила MRF розповсюджуються на даний інстанс. Наступні правила активні:", "mrf_policies_desc": "Правила MRF розповсюджуються на даний інстанс. Наступні правила активні:",
"mrf_policies": "Активні правила MRF (модуль переписування повідомлень)", "mrf_policies": "Активувати правила MRF (модуль переписування повідомлень)",
"keyword": { "keyword": {
"is_replaced_by": "→", "is_replaced_by": "→",
"replace": "Замінити", "replace": "Замінити",
@ -135,7 +139,7 @@
"error": "Помилка при оновленні сповіщень: {0}" "error": "Помилка при оновленні сповіщень: {0}"
}, },
"nav": { "nav": {
"chats": "Локальні балачки", "chats": "Чати",
"timelines": "Стрічки", "timelines": "Стрічки",
"twkn": "Уся відома мережа", "twkn": "Уся відома мережа",
"about": "Інформація", "about": "Інформація",
@ -546,7 +550,8 @@
"disabled": "Вимкнено", "disabled": "Вимкнено",
"selectedMenu": "Вибраний пункт меню", "selectedMenu": "Вибраний пункт меню",
"tabs": "Вкладки", "tabs": "Вкладки",
"pressed": "Натиснуто" "pressed": "Натиснуто",
"wallpaper": "Шпалери"
}, },
"common_colors": { "common_colors": {
"rgbo": "Піктограми, акценти, значки", "rgbo": "Піктограми, акценти, значки",
@ -602,7 +607,8 @@
"frontend_version": "Версія фронтенду", "frontend_version": "Версія фронтенду",
"backend_version": "Версія бекенду", "backend_version": "Версія бекенду",
"title": "Версія" "title": "Версія"
} },
"hide_wallpaper": "Сховати шпалери екземпляру"
}, },
"selectable_list": { "selectable_list": {
"select_all": "Вибрати все" "select_all": "Вибрати все"

View file

@ -39,7 +39,11 @@
"close": "关闭", "close": "关闭",
"retry": "重试", "retry": "重试",
"error_retry": "请重试", "error_retry": "请重试",
"loading": "载入中…" "loading": "载入中…",
"role": {
"moderator": "监察员",
"admin": "管理员"
}
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "裁剪图片", "crop_picture": "裁剪图片",
@ -120,7 +124,9 @@
"expiry": "投票期限", "expiry": "投票期限",
"expires_in": "投票于 {0} 后结束", "expires_in": "投票于 {0} 后结束",
"expired": "投票 {0} 前已结束", "expired": "投票 {0} 前已结束",
"not_enough_options": "投票的选项太少" "not_enough_options": "投票的选项太少",
"votes_count": "{count} 票 | {count} 票",
"people_voted_count": "{count} 人已投票 | {count} 人已投票"
}, },
"stickers": { "stickers": {
"add_sticker": "添加贴纸" "add_sticker": "添加贴纸"
@ -183,7 +189,9 @@
"password_required": "不能留空", "password_required": "不能留空",
"password_confirmation_required": "不能留空", "password_confirmation_required": "不能留空",
"password_confirmation_match": "密码不一致" "password_confirmation_match": "密码不一致"
} },
"reason_placeholder": "此实例的注册需要手动批准。\n请让管理员知道您为什么想要注册。",
"reason": "注册理由"
}, },
"selectable_list": { "selectable_list": {
"select_all": "选择全部" "select_all": "选择全部"
@ -552,7 +560,8 @@
"mute_import": "隐藏名单导入", "mute_import": "隐藏名单导入",
"mute_export_button": "导出你的隐藏名单到一个 csv 文件", "mute_export_button": "导出你的隐藏名单到一个 csv 文件",
"mute_export": "隐藏名单导出", "mute_export": "隐藏名单导出",
"hide_wallpaper": "隐藏实例壁纸" "hide_wallpaper": "隐藏实例壁纸",
"setting_changed": "与默认设置不同"
}, },
"time": { "time": {
"day": "{0} 天", "day": "{0} 天",
@ -683,7 +692,8 @@
"show_repeats": "显示转发", "show_repeats": "显示转发",
"hide_repeats": "隐藏转发", "hide_repeats": "隐藏转发",
"message": "消息", "message": "消息",
"mention": "提及" "mention": "提及",
"bot": "机器人"
}, },
"user_profile": { "user_profile": {
"timeline_title": "用户时间线", "timeline_title": "用户时间线",

View file

@ -25,7 +25,7 @@
"add_poll": "增加投票" "add_poll": "增加投票"
}, },
"notifications": { "notifications": {
"reacted_with": "和 {0} 互動過", "reacted_with": "作出了 {0} 的反應",
"migrated_to": "遷移到", "migrated_to": "遷移到",
"no_more_notifications": "沒有更多的通知", "no_more_notifications": "沒有更多的通知",
"repeated_you": "轉發了你的發文", "repeated_you": "轉發了你的發文",
@ -54,7 +54,7 @@
"mentions": "提及", "mentions": "提及",
"friend_requests": "關注請求", "friend_requests": "關注請求",
"back": "後退", "back": "後退",
"administration": "管理", "administration": "管理",
"about": "關於" "about": "關於"
}, },
"media_modal": { "media_modal": {
@ -216,7 +216,8 @@
"incoming": "收到", "incoming": "收到",
"outgoing": "發出", "outgoing": "發出",
"border": "邊框" "border": "邊框"
} },
"wallpaper": "桌布"
}, },
"preview": { "preview": {
"header_faint": "這很正常", "header_faint": "這很正常",
@ -412,7 +413,7 @@
"hide_follows_description": "不要顯示我所關注的人", "hide_follows_description": "不要顯示我所關注的人",
"hide_followers_description": "不要顯示關注我的人", "hide_followers_description": "不要顯示關注我的人",
"hide_follows_count_description": "不顯示關注數", "hide_follows_count_description": "不顯示關注數",
"nsfw_clickthrough": "將敏感附件隱藏,點擊才能打開", "nsfw_clickthrough": "將敏感附件和鏈接隱藏,點擊才能打開",
"valid_until": "有效期至", "valid_until": "有效期至",
"panelRadius": "面板", "panelRadius": "面板",
"pause_on_unfocused": "在離開頁面時暫停時間線推送", "pause_on_unfocused": "在離開頁面時暫停時間線推送",
@ -526,7 +527,8 @@
"mute_import": "靜音導入", "mute_import": "靜音導入",
"mute_import_error": "導入靜音時出錯", "mute_import_error": "導入靜音時出錯",
"mute_export_button": "將靜音導出到csv文件", "mute_export_button": "將靜音導出到csv文件",
"mute_export": "靜音導出" "mute_export": "靜音導出",
"hide_wallpaper": "隱藏實例桌布"
}, },
"chats": { "chats": {
"more": "更多", "more": "更多",
@ -571,16 +573,20 @@
"thread_muted_and_words": ",有这些字:", "thread_muted_and_words": ",有这些字:",
"hide_full_subject": "隱藏完整標題", "hide_full_subject": "隱藏完整標題",
"show_content": "顯示內容", "show_content": "顯示內容",
"hide_content": "隱藏內容" "hide_content": "隱藏內容",
"status_deleted": "該帖已被刪除",
"expand": "展开",
"external_source": "外部來源",
"nsfw": "工作不安全"
}, },
"time": { "time": {
"hours": "{0} 小時", "hours": "{0} 時",
"days_short": "{0}天", "days_short": "{0}天",
"day_short": "{0}天", "day_short": "{0}天",
"days": "{0} 天", "days": "{0} 天",
"hour": "{0} 小时", "hour": "{0} ",
"hour_short": "{0}h", "hour_short": "{0}",
"hours_short": "{0}h", "hours_short": "{0}",
"years_short": "{0} y", "years_short": "{0} y",
"now": "剛剛", "now": "剛剛",
"day": "{0} 天", "day": "{0} 天",
@ -654,7 +660,8 @@
"reload": "重新載入", "reload": "重新載入",
"up_to_date": "已是最新", "up_to_date": "已是最新",
"no_more_statuses": "没有更多發文", "no_more_statuses": "没有更多發文",
"no_statuses": "没有發文" "no_statuses": "没有發文",
"error": "取得時間線時發生錯誤:{0}"
}, },
"interactions": { "interactions": {
"load_older": "載入更早的互動", "load_older": "載入更早的互動",
@ -745,7 +752,11 @@
"unmute": "取消靜音", "unmute": "取消靜音",
"unmute_progress": "取消靜音中…", "unmute_progress": "取消靜音中…",
"hide_repeats": "隱藏轉發", "hide_repeats": "隱藏轉發",
"show_repeats": "顯示轉發" "show_repeats": "顯示轉發",
"roles": {
"moderator": "主持人",
"admin": "管理員"
}
}, },
"user_profile": { "user_profile": {
"timeline_title": "用戶時間線", "timeline_title": "用戶時間線",
@ -787,7 +798,8 @@
"error": { "error": {
"base": "上傳失敗。", "base": "上傳失敗。",
"file_too_big": "文件太大[{filesize} {filesizeunit} / {allowedsize} {allowedsizeunit}]", "file_too_big": "文件太大[{filesize} {filesizeunit} / {allowedsize} {allowedsizeunit}]",
"default": "稍後再試" "default": "稍後再試",
"message": "上傳錯誤:{0}"
} }
}, },
"search": { "search": {

View file

@ -28,7 +28,6 @@ import pushNotifications from './lib/push_notifications_plugin.js'
import messages from './i18n/messages.js' import messages from './i18n/messages.js'
import VueChatScroll from 'vue-chat-scroll'
import VueClickOutside from 'v-click-outside' import VueClickOutside from 'v-click-outside'
import PortalVue from 'portal-vue' import PortalVue from 'portal-vue'
import VBodyScrollLock from './directives/body_scroll_lock' import VBodyScrollLock from './directives/body_scroll_lock'
@ -42,7 +41,6 @@ const currentLocale = (window.navigator.language || 'en').split('-')[0]
Vue.use(Vuex) Vue.use(Vuex)
Vue.use(VueRouter) Vue.use(VueRouter)
Vue.use(VueI18n) Vue.use(VueI18n)
Vue.use(VueChatScroll)
Vue.use(VueClickOutside) Vue.use(VueClickOutside)
Vue.use(PortalVue) Vue.use(PortalVue)
Vue.use(VBodyScrollLock) Vue.use(VBodyScrollLock)

View file

@ -18,6 +18,7 @@ const chat = {
actions: { actions: {
initializeChat (store, socket) { initializeChat (store, socket) {
const channel = socket.channel('chat:public') const channel = socket.channel('chat:public')
channel.on('new_msg', (msg) => { channel.on('new_msg', (msg) => {
store.commit('addMessage', msg) store.commit('addMessage', msg)
}) })

View file

@ -115,6 +115,9 @@ const chats = {
}, },
handleMessageError ({ commit }, value) { handleMessageError ({ commit }, value) {
commit('handleMessageError', { commit, ...value }) commit('handleMessageError', { commit, ...value })
},
cullOlderMessages ({ commit }, chatId) {
commit('cullOlderMessages', chatId)
} }
}, },
mutations: { mutations: {
@ -227,6 +230,9 @@ const chats = {
handleMessageError (state, { chatId, fakeId, isRetry }) { handleMessageError (state, { chatId, fakeId, isRetry }) {
const chatMessageService = state.openedChatMessageServices[chatId] const chatMessageService = state.openedChatMessageServices[chatId]
chatService.handleMessageError(chatMessageService, fakeId, isRetry) chatService.handleMessageError(chatMessageService, fakeId, isRetry)
},
cullOlderMessages (state, chatId) {
chatService.cullOlderMessages(state.openedChatMessageServices[chatId])
} }
} }
} }

View file

@ -67,7 +67,8 @@ export const defaultState = {
greentext: undefined, // instance default greentext: undefined, // instance default
hidePostStats: undefined, // instance default hidePostStats: undefined, // instance default
hideUserStats: undefined, // instance default hideUserStats: undefined, // instance default
virtualScrolling: undefined // instance default virtualScrolling: undefined, // instance default
sensitiveByDefault: undefined // instance default
} }
// caching the instance default properties // caching the instance default properties
@ -76,18 +77,22 @@ export const instanceDefaultProperties = Object.entries(defaultState)
.map(([key, value]) => key) .map(([key, value]) => key)
const config = { const config = {
state: defaultState, state: { ...defaultState },
getters: { getters: {
mergedConfig (state, getters, rootState, rootGetters) { defaultConfig (state, getters, rootState, rootGetters) {
const { instance } = rootState const { instance } = rootState
return { return {
...state, ...defaultState,
...instanceDefaultProperties ...Object.fromEntries(
.map(key => [key, state[key] === undefined instanceDefaultProperties.map(key => [key, instance[key]])
? instance[key] )
: state[key] }
]) },
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) mergedConfig (state, getters, rootState, rootGetters) {
const { defaultConfig } = rootGetters
return {
...defaultConfig,
...state
} }
} }
}, },

View file

@ -43,6 +43,7 @@ const defaultState = {
subjectLineBehavior: 'email', subjectLineBehavior: 'email',
theme: 'pleroma-dark', theme: 'pleroma-dark',
virtualScrolling: true, virtualScrolling: true,
sensitiveByDefault: false,
// Nasty stuff // Nasty stuff
customEmoji: [], customEmoji: [],

View file

@ -13,7 +13,11 @@ import {
omitBy omitBy
} from 'lodash' } from 'lodash'
import { set } from 'vue' import { set } from 'vue'
import { isStatusNotification, maybeShowNotification } from '../services/notification_utils/notification_utils.js' import {
isStatusNotification,
isValidNotification,
maybeShowNotification
} from '../services/notification_utils/notification_utils.js'
import apiService from '../services/api/api.service.js' import apiService from '../services/api/api.service.js'
const emptyTl = (userId = 0) => ({ const emptyTl = (userId = 0) => ({
@ -310,8 +314,24 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
} }
} }
const updateNotificationsMinMaxId = (state, notification) => {
state.notifications.maxId = notification.id > state.notifications.maxId
? notification.id
: state.notifications.maxId
state.notifications.minId = notification.id < state.notifications.minId
? notification.id
: state.notifications.minId
}
const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters, newNotificationSideEffects }) => { const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters, newNotificationSideEffects }) => {
each(notifications, (notification) => { each(notifications, (notification) => {
// If invalid notification, update ids but don't add it to store
if (!isValidNotification(notification)) {
console.error('Invalid notification:', notification)
updateNotificationsMinMaxId(state, notification)
return
}
if (isStatusNotification(notification.type)) { if (isStatusNotification(notification.type)) {
notification.action = addStatusToGlobalStorage(state, notification.action).item notification.action = addStatusToGlobalStorage(state, notification.action).item
notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item notification.status = notification.status && addStatusToGlobalStorage(state, notification.status).item
@ -323,12 +343,7 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
// Only add a new notification if we don't have one for the same action // Only add a new notification if we don't have one for the same action
if (!state.notifications.idStore.hasOwnProperty(notification.id)) { if (!state.notifications.idStore.hasOwnProperty(notification.id)) {
state.notifications.maxId = notification.id > state.notifications.maxId updateNotificationsMinMaxId(state, notification)
? notification.id
: state.notifications.maxId
state.notifications.minId = notification.id < state.notifications.minId
? notification.id
: state.notifications.minId
state.notifications.data.push(notification) state.notifications.data.push(notification)
state.notifications.idStore[notification.id] = notification state.notifications.idStore[notification.id] = notification

View file

@ -48,6 +48,22 @@ const deleteMessage = (storage, messageId) => {
} }
} }
const cullOlderMessages = (storage) => {
const maxIndex = storage.messages.length
const minIndex = maxIndex - 50
if (maxIndex <= 50) return
storage.messages = _.sortBy(storage.messages, ['id'])
storage.minId = storage.messages[minIndex].id
for (const message of storage.messages) {
if (message.id < storage.minId) {
delete storage.idIndex[message.id]
delete storage.idempotencyKeyIndex[message.idempotency_key]
}
}
storage.messages = storage.messages.slice(minIndex, maxIndex)
}
const handleMessageError = (storage, fakeId, isRetry) => { const handleMessageError = (storage, fakeId, isRetry) => {
if (!storage) { return } if (!storage) { return }
const fakeMessage = storage.idIndex[fakeId] const fakeMessage = storage.idIndex[fakeId]
@ -201,6 +217,7 @@ const ChatService = {
empty, empty,
getView, getView,
deleteMessage, deleteMessage,
cullOlderMessages,
resetNewMessageCount, resetNewMessageCount,
clear, clear,
handleMessageError handleMessageError

View file

@ -188,7 +188,12 @@ export const parseUser = (data) => {
output.follow_request_count = data.pleroma.follow_request_count output.follow_request_count = data.pleroma.follow_request_count
output.tags = data.pleroma.tags output.tags = data.pleroma.tags
output.deactivated = data.pleroma.deactivated
// deactivated was changed to is_active in Pleroma 2.3.0
// so check if is_active is present
output.deactivated = typeof data.pleroma.is_active !== 'undefined'
? !data.pleroma.is_active // new backend
: data.pleroma.deactivated // old backend
output.notification_settings = data.pleroma.notification_settings output.notification_settings = data.pleroma.notification_settings
output.unread_chat_count = data.pleroma.unread_chat_count output.unread_chat_count = data.pleroma.unread_chat_count
@ -198,7 +203,8 @@ export const parseUser = (data) => {
output.rights = output.rights || {} output.rights = output.rights || {}
output.notification_settings = output.notification_settings || {} output.notification_settings = output.notification_settings || {}
// Convert punycode to unicode // Convert punycode to unicode for UI
output.screen_name_ui = output.screen_name
if (output.screen_name.includes('@')) { if (output.screen_name.includes('@')) {
const parts = output.screen_name.split('@') const parts = output.screen_name.split('@')
let unicodeDomain = punycode.toUnicode(parts[1]) let unicodeDomain = punycode.toUnicode(parts[1])
@ -206,7 +212,7 @@ export const parseUser = (data) => {
// Add some identifier so users can potentially spot spoofing attempts: // Add some identifier so users can potentially spot spoofing attempts:
// lain.com and xn--lin-6cd.com would appear identical otherwise. // lain.com and xn--lin-6cd.com would appear identical otherwise.
unicodeDomain = '🌏' + unicodeDomain unicodeDomain = '🌏' + unicodeDomain
output.screen_name = [parts[0], unicodeDomain].join('@') output.screen_name_ui = [parts[0], unicodeDomain].join('@')
} }
} }

View file

@ -0,0 +1,12 @@
const specialLanguageCodes = {
'ja_easy': 'ja',
'zh_Hant': 'zh-HANT'
}
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
const localeService = {
internalToBrowserLocale
}
export default localeService

View file

@ -22,6 +22,13 @@ const statusNotifications = ['like', 'mention', 'repeat', 'pleroma:emoji_reactio
export const isStatusNotification = (type) => includes(statusNotifications, type) export const isStatusNotification = (type) => includes(statusNotifications, type)
export const isValidNotification = (notification) => {
if (isStatusNotification(notification.type) && !notification.status) {
return false
}
return true
}
const sortById = (a, b) => { const sortById = (a, b) => {
const seqA = Number(a.id) const seqA = Number(a.id)
const seqB = Number(b.id) const seqB = Number(b.id)

View file

@ -242,9 +242,18 @@ export const generateShadows = (input, colors) => {
panelHeader: 'panel', panelHeader: 'panel',
input: 'input' input: 'input'
} }
const inputShadows = input.shadows && !input.themeEngineVersion
? shadows2to3(input.shadows, input.opacity) const cleanInputShadows = Object.fromEntries(
: input.shadows || {} Object.entries(input.shadows || {})
.map(([name, shadowSlot]) => [
name,
// defaulting color to black to avoid potential problems
shadowSlot.map(shadowDef => ({ color: '#000000', ...shadowDef }))
])
)
const inputShadows = cleanInputShadows && !input.themeEngineVersion
? shadows2to3(cleanInputShadows, input.opacity)
: cleanInputShadows || {}
const shadows = Object.entries({ const shadows = Object.entries({
...DEFAULT_SHADOWS, ...DEFAULT_SHADOWS,
...inputShadows ...inputShadows

View file

@ -31,13 +31,15 @@ const testGetters = {
const localUser = { const localUser = {
id: 100, id: 100,
is_local: true, is_local: true,
screen_name: 'testUser' screen_name: 'testUser',
screen_name_ui: 'testUser'
} }
const extUser = { const extUser = {
id: 100, id: 100,
is_local: false, is_local: false,
screen_name: 'testUser@test.instance' screen_name: 'testUser@test.instance',
screen_name_ui: 'testUser@test.instance'
} }
const externalProfileStore = new Vuex.Store({ const externalProfileStore = new Vuex.Store({

View file

@ -88,4 +88,21 @@ describe('chatService', () => {
expect(view.map(i => i.type)).to.eql(['date', 'message', 'message', 'date', 'message']) expect(view.map(i => i.type)).to.eql(['date', 'message', 'message', 'date', 'message'])
}) })
}) })
describe('.cullOlderMessages', () => {
it('keeps 50 newest messages and idIndex matches', () => {
const chat = chatService.empty()
for (let i = 100; i > 0; i--) {
// Use decimal values with toFixed to hack together constant length predictable strings
chatService.add(chat, { messages: [{ ...message1, id: 'a' + (i / 1000).toFixed(3), idempotency_key: i }] })
}
chatService.cullOlderMessages(chat)
expect(chat.messages.length).to.eql(50)
expect(chat.messages[0].id).to.eql('a0.051')
expect(chat.minId).to.eql('a0.051')
expect(chat.messages[49].id).to.eql('a0.100')
expect(Object.keys(chat.idIndex).length).to.eql(50)
})
})
}) })

View file

@ -315,7 +315,7 @@ describe('API Entities normalizer', () => {
it('converts IDN to unicode and marks it as internatonal', () => { it('converts IDN to unicode and marks it as internatonal', () => {
const user = makeMockUserMasto({ acct: 'lain@xn--lin-6cd.com' }) const user = makeMockUserMasto({ acct: 'lain@xn--lin-6cd.com' })
expect(parseUser(user)).to.have.property('screen_name').that.equal('lain@🌏lаin.com') expect(parseUser(user)).to.have.property('screen_name_ui').that.equal('lain@🌏lаin.com')
}) })
}) })

View file

@ -7842,9 +7842,10 @@ shebang-regex@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
shelljs@^0.7.4: shelljs@^0.8.4:
version "0.7.8" version "0.8.4"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
dependencies: dependencies:
glob "^7.0.0" glob "^7.0.0"
interpret "^1.0.0" interpret "^1.0.0"
@ -8922,10 +8923,6 @@ void-elements@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
vue-chat-scroll@^1.2.1:
version "1.3.5"
resolved "https://registry.yarnpkg.com/vue-chat-scroll/-/vue-chat-scroll-1.3.5.tgz#a5ee5bae5058f614818a96eac5ee3be4394a2f68"
vue-eslint-parser@^5.0.0: vue-eslint-parser@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1" resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1"