Compare commits

...

61 Commits

Author SHA1 Message Date
HJ 82db31f7ac Merge branch 'ci-update' into 'develop'
Update gitlab CI file to avoid arm runner that keeps failing certain resource-intensive tasks

See merge request pleroma/pleroma-fe!1914
2024-05-23 16:45:17 +00:00
HJ 5810f6f431 changelog 2024-05-23 08:38:17 +00:00
HJ 8b07d0201e Update gitlab CI file to avoid arm runner that keeps failing certain resource-intensive tasks 2024-05-23 08:36:15 +00:00
HJ fd1011f622 Merge branch 'scrobbles-age' into 'develop'
Add setting to only show scrobbles newer than certain age.

See merge request pleroma/pleroma-fe!1904
2024-05-22 12:25:24 +00:00
Henry Jameson eb27f1205b Merge branch 'scrobbles-age' of ssh://git.pleroma.social:2222/pleroma/pleroma-fe into scrobbles-age 2024-05-22 15:20:42 +03:00
Henry Jameson daa39b6e8f changelog 2024-05-22 15:19:00 +03:00
HJ 3e99006e2a Merge branch 'quotes-count' into 'develop'
Display quotes count on posts and add quotes list page

See merge request pleroma/pleroma-fe!1885
2024-05-22 12:15:57 +00:00
HJ e232ba0ec5 Merge branch 'weblate' into 'develop'
Translations update from Pleroma Weblate

See merge request pleroma/pleroma-fe!1910
2024-05-22 12:15:32 +00:00
HJ 3128ea57e1 Merge branch 'themes3-cache' into 'develop'
implement a simple caching system for themes 3

See merge request pleroma/pleroma-fe!1911
2024-05-22 12:15:21 +00:00
Phantasm 564cc73d31 Translated using Weblate (Czech)
Currently translated at 84.2% (960 of 1140 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/cs/
2024-04-30 20:02:13 +00:00
HJ 9d2572ffdb Update status.scss 2024-04-29 08:09:05 +00:00
HJ a4264b9cd2 Apply 1 suggestion(s) to 1 file(s) 2024-04-29 07:39:00 +00:00
HJ 51709ad318 Merge branch 'develop' into 'scrobbles-age'
# Conflicts:
#   src/i18n/en.json
2024-04-28 19:05:18 +00:00
marcin mikołajczak 4de9daa114 Apply 1 suggestion(s) to 1 file(s)
Co-authored-by: marcin mikołajczak <me@mkljczk.pl>
2024-04-28 18:56:10 +00:00
Phantasm b19749c320 Translated using Weblate (Czech)
Currently translated at 84.5% (960 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/cs/
2024-04-28 17:29:25 +00:00
HJ 3056017f8e Merge branch 'eintei-port-mute-nsfw' into 'develop'
Ability to mute nsfw posts

Closes #1288

See merge request pleroma/pleroma-fe!1913
2024-04-28 17:29:17 +00:00
HJ 36f2fef55a Merge branch 'notif_types' into 'develop'
Add more notification types

See merge request pleroma/pleroma-fe!1912
2024-04-28 17:29:07 +00:00
Henry Jameson 6ff0a7f021 refactor sizesetting into unitsetting allowing more unit types with i18n support 2024-04-24 15:58:26 +03:00
Henry Jameson 6473260487 changelog 2024-04-24 15:25:21 +03:00
Henry Jameson 046678086f add explanation to why post is muted for sensitive muting 2024-04-24 15:22:19 +03:00
Alexander Tumin 59656af44c Allow muting sensitive posts in public timelines 2024-04-24 15:18:11 +03:00
Henry Jameson 6ea69eb51a checksum -> engineChecksum for clarity 2024-04-24 15:09:52 +03:00
Henry Jameson c40b02ac2f changelog 2024-04-22 23:46:12 +03:00
Henry Jameson af236d71f0 changelog 2024-04-22 23:42:08 +03:00
Henry Jameson 5505a89e8a implement a simple caching system for themes 3 2024-04-22 23:40:39 +03:00
Henry Jameson b2e10ac8c1 add more notification types to ask backend about 2024-04-22 22:37:37 +03:00
HJ 15dde2d372 Merge branch 'fix-poll-notifs' into 'develop'
Add poll end notifications to fetched types

Closes pleroma#3230

See merge request pleroma/pleroma-fe!1905
2024-04-22 19:30:29 +00:00
HJ 2cbfcb6a6d Merge branch 'tusooa/status-loading-indicator' into 'develop'
Display loading and error indicator for conversation page

See merge request pleroma/pleroma-fe!1907
2024-04-22 19:23:52 +00:00
HJ e853d746b0 Merge branch 'weblate' into 'develop'
Translations update from Pleroma Weblate

See merge request pleroma/pleroma-fe!1909
2024-04-18 08:25:22 +00:00
SyoBoN 2ede1f669a Translated using Weblate (Japanese (ja_PEDANTIC))
Currently translated at 96.0% (1091 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/ja_PEDANTIC/
2024-04-17 23:37:32 +00:00
HJ 09313a9fcd Merge branch 'public-favorites' into 'develop'
Fix fetching favorites for own profile

See merge request pleroma/pleroma-fe!1908
2024-04-16 08:16:33 +00:00
marcin mikołajczak 1ceffb4e71 Fix fetching favorites for own profile
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-04-15 23:54:46 +02:00
tusooa b173741f87
Display loading and error indicator for conversation page 2024-04-14 11:46:29 -04:00
tusooa 39269c4829 Merge branch 'weblate' into 'develop'
Translations update from Pleroma Weblate

See merge request pleroma/pleroma-fe!1893
2024-04-14 15:21:46 +00:00
Gllm R 3d025eb7bf Translated using Weblate (French)
Currently translated at 99.2% (1128 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2024-04-07 18:02:12 +00:00
Gllm R d6ef47f1c3 Translated using Weblate (French)
Currently translated at 83.9% (954 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/fr/
2024-04-06 14:54:05 +00:00
jammer lammer 82af61f5b4 Translated using Weblate (Portuguese)
Currently translated at 69.8% (793 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/pt/
2024-04-06 14:54:05 +00:00
Phantasm eb03844387 Translated using Weblate (Czech)
Currently translated at 84.5% (960 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/cs/
2024-04-06 14:54:05 +00:00
Phantasm b610caeca8 Translated using Weblate (English)
Currently translated at 100.0% (1136 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/en/
2024-04-06 14:54:05 +00:00
Phantasm 9b65c30c12 Translated using Weblate (Czech)
Currently translated at 74.8% (850 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/cs/
2024-04-06 14:54:05 +00:00
Phantasm 1b667fbb01 Translated using Weblate (English)
Currently translated at 100.0% (1136 of 1136 strings)

Translation: Pleroma/Pleroma-FE
Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/en/
2024-04-06 14:54:05 +00:00
HJ 0635a6c131 Merge branch 'themes3-fixes' into 'develop'
Themes 3 fixes

Closes #1301 and #1303

See merge request pleroma/pleroma-fe!1906
2024-04-06 14:53:53 +00:00
Henry Jameson 3eabdf9ded lint 2024-04-04 22:58:50 +03:00
Henry Jameson ece159822c force user profile links in summary to be text colored... for now. 2024-04-04 22:50:04 +03:00
Henry Jameson c0010d0f48 fix transparent popovers 2024-04-04 22:45:13 +03:00
Henry Jameson 8ead084421 fix #1301 2024-04-04 22:40:50 +03:00
Henry Jameson 19ab07af96 changelog 2024-04-03 23:08:13 +03:00
Henry Jameson 1c23a16bac try to apply lazy part in one go while still having chunked processing 2024-04-03 22:57:44 +03:00
Henry Jameson 9806eea12e only show interface after theme has been applied 2024-04-03 22:52:12 +03:00
Henry Jameson e8159164e3 color input improvements 2024-04-03 22:43:36 +03:00
Henry Jameson dd4867d8de refactor style setter to separate theme generation from theme application 2024-04-03 22:42:34 +03:00
Henry Jameson 2382810823 fix repeater links 2024-04-03 21:27:25 +03:00
Henry Jameson fbea4f9986 fix shout 2024-04-03 21:27:19 +03:00
Henry Jameson 940df1efa7 add fallbacks for lazy stuff loading 2024-04-03 21:10:27 +03:00
Henry Jameson 9bdc8d9b9c fix transparency blur in statuses on firefox 2024-03-29 13:36:43 +02:00
Phantasm d5575f9c13
Add poll end notifications to fetched types 2024-03-26 19:17:55 +01:00
Henry Jameson def68e9cda scrobbles age setting 2024-03-25 23:35:28 +02:00
marcin mikołajczak d28e48e9dc Merge remote-tracking branch 'mkljczk/quotes-count' into quotes-count 2024-01-19 19:01:38 +01:00
marcin mikołajczak f6d3a66a5b shouldDisplayFavsAndRepeats
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-01-19 19:01:11 +01:00
marcin mikołajczak dbe9da0f09 Merge branch 'develop' into 'quotes-count'
# Conflicts:
#   src/services/api/api.service.js
2024-01-14 06:23:30 +00:00
marcin mikołajczak 6c4c8fe51f Display quotes count on posts and add quotes list page
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
2024-01-04 22:47:41 +01:00
62 changed files with 1149 additions and 148 deletions

View File

@ -43,6 +43,8 @@ lint:
test: test:
stage: test stage: test
tags:
- amd64
variables: variables:
APT_CACHE_DIR: apt-cache APT_CACHE_DIR: apt-cache
script: script:
@ -54,6 +56,8 @@ test:
build: build:
stage: build stage: build
tags:
- amd64
script: script:
- yarn - yarn
- npm run build - npm run build

View File

@ -0,0 +1 @@
stop using that one runner for intensive tasks

View File

@ -0,0 +1 @@
Added ability to mute sensitive posts (ported from eintei)

View File

@ -0,0 +1 @@
Synchronized requested notification types with backend, hopefully should fix missing notifications for polls and follow requests

View File

@ -0,0 +1 @@
Add poll end notifications to fetched types.

View File

View File

@ -0,0 +1 @@
Display quotes count on posts and add quotes list page

View File

@ -0,0 +1 @@
Option to only show scrobbles that are recent enough

View File

@ -0,0 +1 @@
Display loading and error indicator for conversation page

View File

@ -0,0 +1 @@
Add caching system for themes3

View File

@ -0,0 +1 @@
fix color inputs and some in-development themes3 issues

View File

@ -32,6 +32,7 @@
"click-outside-vue3": "4.0.1", "click-outside-vue3": "4.0.1",
"cropperjs": "1.5.13", "cropperjs": "1.5.13",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"hash-sum": "^2.0.0",
"js-cookie": "3.0.5", "js-cookie": "3.0.5",
"localforage": "1.10.0", "localforage": "1.10.0",
"parse-link-header": "2.0.0", "parse-link-header": "2.0.0",

View File

@ -14,6 +14,9 @@
--ZI_navbar_popovers: 7500; --ZI_navbar_popovers: 7500;
--ZI_navbar: 7000; --ZI_navbar: 7000;
--ZI_popovers: 6000; --ZI_popovers: 6000;
// Fallback for when stuff is loading
--background: var(--bg);
} }
html { html {
@ -370,6 +373,7 @@ nav {
border: none; border: none;
border-radius: var(--roundness); border-radius: var(--roundness);
cursor: pointer; cursor: pointer;
background-color: var(--background);
box-shadow: var(--shadow); box-shadow: var(--shadow);
font-size: 1em; font-size: 1em;
font-family: sans-serif; font-family: sans-serif;
@ -406,6 +410,7 @@ nav {
width: 100%; width: 100%;
line-height: var(--__line-height); line-height: var(--__line-height);
padding: var(--__vertical-gap) var(--__horizontal-gap); padding: var(--__vertical-gap) var(--__horizontal-gap);
background: transparent;
--__line-height: 1.5em; --__line-height: 1.5em;
--__horizontal-gap: 0.75em; --__horizontal-gap: 0.75em;
@ -470,6 +475,7 @@ nav {
font-size: 100%; font-size: 100%;
font-family: inherit; font-family: inherit;
box-shadow: var(--shadow); box-shadow: var(--shadow);
background-color: transparent;
padding: 0; padding: 0;
line-height: unset; line-height: unset;
cursor: pointer; cursor: pointer;
@ -502,6 +508,8 @@ textarea {
border: none; border: none;
border-radius: var(--roundness); border-radius: var(--roundness);
background-color: var(--background);
color: var(--text);
box-shadow: var(--shadow); box-shadow: var(--shadow);
font-family: var(--font); font-family: var(--font);
font-size: 1em; font-size: 1em;

View File

@ -1,5 +1,6 @@
<template> <template>
<div <div
v-show="$store.state.interface.themeApplied"
id="app-loaded" id="app-loaded"
:style="bgStyle" :style="bgStyle"
> >

View File

@ -14,7 +14,7 @@ import { windowWidth, windowHeight } from '../services/window_utils/window_utils
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js' import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js' import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
import { applyTheme, applyConfig } from '../services/style_setter/style_setter.js' import { applyTheme, applyConfig, tryLoadCache } from '../services/style_setter/style_setter.js'
import FaviconService from '../services/favicon_service/favicon_service.js' import FaviconService from '../services/favicon_service/favicon_service.js'
import { initServiceWorker, updateFocus } from '../services/sw/sw.js' import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
@ -353,21 +353,26 @@ const afterStoreSetup = async ({ store, i18n }) => {
await setConfig({ store }) await setConfig({ store })
const { customTheme, customThemeSource } = store.state.config const { customTheme, customThemeSource, forceThemeRecompilation } = store.state.config
const { theme } = store.state.instance const { theme } = store.state.instance
const customThemePresent = customThemeSource || customTheme const customThemePresent = customThemeSource || customTheme
if (!forceThemeRecompilation && tryLoadCache()) {
store.commit('setThemeApplied')
} else {
if (customThemePresent) { if (customThemePresent) {
if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) { if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
applyTheme(customThemeSource) applyTheme(customThemeSource)
} else { } else {
applyTheme(customTheme) applyTheme(customTheme)
} }
store.commit('setThemeApplied')
} else if (theme) { } else if (theme) {
// do nothing, it will load asynchronously // do nothing, it will load asynchronously
} else { } else {
console.error('Failed to load any theme!') console.error('Failed to load any theme!')
} }
}
applyConfig(store.state.config) applyConfig(store.state.config)

View File

@ -25,6 +25,7 @@ import ListsTimeline from 'components/lists_timeline/lists_timeline.vue'
import ListsEdit from 'components/lists_edit/lists_edit.vue' import ListsEdit from 'components/lists_edit/lists_edit.vue'
import NavPanel from 'src/components/nav_panel/nav_panel.vue' import NavPanel from 'src/components/nav_panel/nav_panel.vue'
import AnnouncementsPage from 'components/announcements_page/announcements_page.vue' import AnnouncementsPage from 'components/announcements_page/announcements_page.vue'
import QuotesTimeline from '../components/quotes_timeline/quotes_timeline.vue'
export default (store) => { export default (store) => {
const validateAuthenticatedRoute = (to, from, next) => { const validateAuthenticatedRoute = (to, from, next) => {
@ -51,6 +52,7 @@ export default (store) => {
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline }, { name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
{ {
name: 'remote-user-profile-acct', name: 'remote-user-profile-acct',
path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)', path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',

View File

@ -9,6 +9,7 @@
padding: 0.2em 8px; padding: 0.2em 8px;
input { input {
color: var(--text);
background: none; background: none;
border: none; border: none;
padding: 0; padding: 0;
@ -19,21 +20,38 @@
min-width: 3em; min-width: 3em;
padding: 0; padding: 0;
} }
}
&.nativeColor { .nativeColor {
flex: 0 0 2em; cursor: pointer;
min-width: 2em; flex: 0 0 auto;
align-self: stretch;
min-height: 100%; input {
appearance: none;
max-width: 0;
min-width: 0;
max-height: 0;
/* stylelint-disable-next-line declaration-no-important */
opacity: 0 !important;
} }
} }
.computedIndicator, .computedIndicator,
.validIndicator,
.invalidIndicator,
.transparentIndicator { .transparentIndicator {
flex: 0 0 2em; flex: 0 0 2em;
margin: 0 0.5em;
min-width: 2em; min-width: 2em;
align-self: stretch; align-self: stretch;
min-height: 100%; min-height: 1.5em;
border-radius: var(--roundness);
}
.invalidIndicator {
background: transparent;
box-sizing: border-box;
border: 2px solid var(--cRed);
} }
.transparentIndicator { .transparentIndicator {
@ -54,11 +72,13 @@
&::after { &::after {
top: 0; top: 0;
left: 0; left: 0;
border-top-left-radius: var(--roundness);
} }
&::before { &::before {
bottom: 0; bottom: 0;
right: 0; right: 0;
border-bottom-right-radius: var(--roundness);
} }
} }
} }

View File

@ -25,30 +25,51 @@
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('update:modelValue', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
<input <div
v-if="validColor" v-if="validColor"
class="validIndicator"
:style="{backgroundColor: modelValue || fallback}"
/>
<div
v-else-if="transparentColor"
class="transparentIndicator"
/>
<div
v-else-if="computedColor"
class="computedIndicator"
:style="{backgroundColor: fallback}"
/>
<div
v-else
class="invalidIndicator"
/>
<label class="nativeColor">
<FAIcon icon="eye-dropper" />
<input
:id="name" :id="name"
class="nativeColor unstyled" class="unstyled"
type="color" type="color"
:value="modelValue || fallback" :value="modelValue || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('update:modelValue', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
<div </label>
v-if="transparentColor"
class="transparentIndicator"
/>
<div
v-if="computedColor"
class="computedIndicator"
:style="{backgroundColor: fallback}"
/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import Checkbox from '../checkbox/checkbox.vue' import Checkbox from '../checkbox/checkbox.vue'
import { hex2rgb } from '../../services/color_convert/color_convert.js' import { hex2rgb } from '../../services/color_convert/color_convert.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faEyeDropper
} from '@fortawesome/free-solid-svg-icons'
library.add(
faEyeDropper
)
export default { export default {
components: { components: {
Checkbox Checkbox
@ -108,12 +129,3 @@ export default {
} }
</script> </script>
<style lang="scss" src="./color_input.scss"></style> <style lang="scss" src="./color_input.scss"></style>
<style lang="scss">
.color-control {
input.text-input {
max-width: 7em;
flex: 1;
}
}
</style>

View File

@ -56,7 +56,8 @@ const conversation = {
expanded: false, expanded: false,
threadDisplayStatusObject: {}, // id => 'showing' | 'hidden' threadDisplayStatusObject: {}, // id => 'showing' | 'hidden'
statusContentPropertiesObject: {}, statusContentPropertiesObject: {},
inlineDivePosition: null inlineDivePosition: null,
loadStatusError: null
} }
}, },
props: [ props: [
@ -392,11 +393,15 @@ const conversation = {
this.setHighlight(this.originalStatusId) this.setHighlight(this.originalStatusId)
}) })
} else { } else {
this.loadStatusError = null
this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId }) this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId })
.then((status) => { .then((status) => {
this.$store.dispatch('addNewStatuses', { statuses: [status] }) this.$store.dispatch('addNewStatuses', { statuses: [status] })
this.fetchConversation() this.fetchConversation()
}) })
.catch((error) => {
this.loadStatusError = error
})
} }
}, },
getReplies (id) { getReplies (id) {

View File

@ -29,6 +29,23 @@
/> />
</div> </div>
<div <div
v-if="isPage && !status"
class="conversation-body"
:class="{ 'panel-body': isExpanded }"
>
<p v-if="!loadStatusError">
<FAIcon
spin
icon="circle-notch"
/>
{{ $t('status.loading') }}
</p>
<p v-else>
{{ $t('status.load_error', { error: loadStatusError }) }}
</p>
</div>
<div
v-else
class="conversation-body" class="conversation-body"
:class="{ 'panel-body': isExpanded }" :class="{ 'panel-body': isExpanded }"
> >
@ -81,7 +98,7 @@
:replies="getReplies(status.id)" :replies="getReplies(status.id)"
:in-profile="inProfile" :in-profile="inProfile"
:profile-user-id="profileUserId" :profile-user-id="profileUserId"
class="conversation-status status-fadein" class="conversation-status status-fadein panel-body"
:simple-tree="treeViewIsSimple" :simple-tree="treeViewIsSimple"
:toggle-thread-display="toggleThreadDisplay" :toggle-thread-display="toggleThreadDisplay"
@ -186,7 +203,7 @@
:replies="getReplies(status.id)" :replies="getReplies(status.id)"
:in-profile="inProfile" :in-profile="inProfile"
:profile-user-id="profileUserId" :profile-user-id="profileUserId"
class="conversation-status status-fadein" class="conversation-status status-fadein panel-body"
:toggle-thread-display="toggleThreadDisplay" :toggle-thread-display="toggleThreadDisplay"
:thread-display-status="threadDisplayStatus" :thread-display-status="threadDisplayStatus"

View File

@ -71,6 +71,7 @@
border-color: var(--border); border-color: var(--border);
border-style: solid; border-style: solid;
border-width: 1px; border-width: 1px;
background-color: var(--background);
} }
.dropdown-menu { .dropdown-menu {
@ -82,6 +83,7 @@
max-width: 100vw; max-width: 100vw;
z-index: var(--ZI_popover_override, var(--ZI_popovers)); z-index: var(--ZI_popover_override, var(--ZI_popovers));
white-space: nowrap; white-space: nowrap;
background-color: var(--background);
.dropdown-divider { .dropdown-divider {
height: 0; height: 0;

View File

@ -63,6 +63,13 @@ const QuickFilterSettings = {
const value = !this.muteBotStatuses const value = !this.muteBotStatuses
this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) this.$store.dispatch('setOption', { name: 'muteBotStatuses', value })
} }
},
muteSensitiveStatuses: {
get () { return this.mergedConfig.muteSensitiveStatuses },
set () {
const value = !this.muteSensitiveStatuses
this.$store.dispatch('setOption', { name: 'muteSensitiveStatuses', value })
}
} }
} }
} }

View File

@ -71,6 +71,18 @@
:aria-hidden="true" :aria-hidden="true"
/>{{ $t('settings.mute_bot_posts') }} />{{ $t('settings.mute_bot_posts') }}
</button> </button>
<button
class="menu-item dropdown-item"
role="menuitemcheckbox"
:aria-checked="muteSensitiveStatuses"
@click="muteSensitiveStatuses = !muteSensitiveStatuses"
>
<span
class="input menu-checkbox"
:class="{ 'menu-checkbox-checked': muteSensitiveStatuses }"
:aria-hidden="true"
/>{{ $t('settings.mute_sensitive_posts') }}
</button>
<button <button
class="menu-item dropdown-item" class="menu-item dropdown-item"
role="menuitemcheckbox" role="menuitemcheckbox"

View File

@ -61,6 +61,13 @@ const QuickViewSettings = {
const value = !this.muteBotStatuses const value = !this.muteBotStatuses
this.$store.dispatch('setOption', { name: 'muteBotStatuses', value }) this.$store.dispatch('setOption', { name: 'muteBotStatuses', value })
} }
},
muteSensitiveStatuses: {
get () { return this.mergedConfig.muteSensitiveStatuses },
set () {
const value = !this.muteSensitiveStatuses
this.$store.dispatch('setOption', { name: 'muteSensitiveStatuses', value })
}
} }
} }
} }

View File

@ -0,0 +1,26 @@
import Timeline from '../timeline/timeline.vue'
const QuotesTimeline = {
created () {
this.$store.commit('clearTimeline', { timeline: 'quotes' })
this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId })
},
components: {
Timeline
},
computed: {
statusId () { return this.$route.params.id },
timeline () { return this.$store.state.statuses.timelines.quotes }
},
watch: {
statusId () {
this.$store.commit('clearTimeline', { timeline: 'quotes' })
this.$store.dispatch('startFetchingTimeline', { timeline: 'quotes', statusId: this.statusId })
}
},
unmounted () {
this.$store.dispatch('stopFetchingTimeline', 'quotes')
}
}
export default QuotesTimeline

View File

@ -0,0 +1,10 @@
<template>
<Timeline
:title="$t('nav.quotes')"
:timeline="timeline"
:timeline-name="'quotes'"
:status-id="statusId"
/>
</template>
<script src='./quotes_timeline.js'></script>

View File

@ -83,3 +83,8 @@
color: var(--funtextCyantext); color: var(--funtextCyantext);
} }
} }
a .RichContent {
/* stylelint-disable-next-line declaration-no-important */
color: var(--link) !important;
}

View File

@ -17,6 +17,10 @@ export default {
units: { units: {
type: Array, type: Array,
default: () => allCssUnits default: () => allCssUnits
},
unitSet: {
type: String,
default: 'none'
} }
}, },
computed: { computed: {
@ -30,6 +34,10 @@ export default {
}, },
methods: { methods: {
...Setting.methods, ...Setting.methods,
getUnitString (value) {
if (this.unitSet === 'none') return value
return this.$t(['settings', 'units', this.unitSet, value].join('.'))
},
updateValue (e) { updateValue (e) {
this.configSink(this.path, parseInt(e.target.value) + this.stateUnit) this.configSink(this.path, parseInt(e.target.value) + this.stateUnit)
}, },

View File

@ -1,7 +1,7 @@
<template> <template>
<span <span
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="SizeSetting" class="UnitSetting"
> >
<label <label
:for="path" :for="path"
@ -23,7 +23,7 @@
:id="path" :id="path"
:model-value="stateUnit" :model-value="stateUnit"
:disabled="disabled" :disabled="disabled"
class="css-unit-input" class="unit-input unstyled"
@change="updateUnit" @change="updateUnit"
> >
<option <option
@ -31,7 +31,7 @@
:key="option" :key="option"
:value="option" :value="option"
> >
{{ option }} {{ getUnitString(option) }}
</option> </option>
</Select> </Select>
{{ ' ' }} {{ ' ' }}
@ -42,20 +42,19 @@
</span> </span>
</template> </template>
<script src="./size_setting.js"></script> <script src="./unit_setting.js"></script>
<style lang="scss"> <style lang="scss">
.SizeSetting { .UnitSetting {
.number-input { .number-input {
max-width: 6.5em; max-width: 6.5em;
text-align: right;
} }
.css-unit-input, .unit-input,
.css-unit-input select { .unit-input select {
margin-left: 0.5em;
width: 4em;
max-width: 4em;
min-width: 4em; min-width: 4em;
width: auto;
} }
} }

View File

@ -31,10 +31,6 @@
margin-bottom: 1em; margin-bottom: 1em;
} }
select {
min-width: 10em;
}
textarea { textarea {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;

View File

@ -31,10 +31,6 @@
margin-bottom: 1em; margin-bottom: 1em;
} }
select {
min-width: 10em;
}
textarea { textarea {
width: 100%; width: 100%;
max-width: 100%; max-width: 100%;

View File

@ -1,6 +1,7 @@
import { filter, trim, debounce } from 'lodash' import { filter, trim, debounce } from 'lodash'
import BooleanSetting from '../helpers/boolean_setting.vue' import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue' import ChoiceSetting from '../helpers/choice_setting.vue'
import UnitSetting from '../helpers/unit_setting.vue'
import IntegerSetting from '../helpers/integer_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
@ -19,6 +20,7 @@ const FilteringTab = {
components: { components: {
BooleanSetting, BooleanSetting,
ChoiceSetting, ChoiceSetting,
UnitSetting,
IntegerSetting IntegerSetting
}, },
computed: { computed: {

View File

@ -44,6 +44,29 @@
{{ $t('settings.mute_bot_posts') }} {{ $t('settings.mute_bot_posts') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li>
<BooleanSetting path="muteSensitiveStatuses">
{{ $t('settings.mute_sensitive_posts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hideMutedFederationRestrictions">
{{ $t('settings.hide_muted_federation_restrictions') }}
</BooleanSetting>
<ul
class="setting-list suboptions"
:class="[{disabled: !streaming}]"
>
<li
v-for="item in muteFederationRestrictionsLevels"
:key="'mute_' + item + '_federation_restriction'"
>
<BooleanSetting :path="'muteFederationRestrictions.' + item">
{{ $t('settings.mute_' + item + '_federation_restriction') }}
</BooleanSetting>
</li>
</ul>
</li>
<li> <li>
<BooleanSetting path="hidePostStats"> <BooleanSetting path="hidePostStats">
{{ $t('settings.hide_post_stats') }} {{ $t('settings.hide_post_stats') }}
@ -96,6 +119,17 @@
{{ $t('settings.hide_scrobbles') }} {{ $t('settings.hide_scrobbles') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li>
<UnitSetting
key="hideScrobblesAfter"
path="hideScrobblesAfter"
:units="['m', 'h', 'd']"
unitSet="time"
expert="1"
>
{{ $t('settings.hide_scrobbles_after') }}
</UnitSetting>
</li>
</ul> </ul>
</div> </div>
<div <div

View File

@ -3,7 +3,7 @@ import ChoiceSetting from '../helpers/choice_setting.vue'
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue' import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import IntegerSetting from '../helpers/integer_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue'
import FloatSetting from '../helpers/float_setting.vue' import FloatSetting from '../helpers/float_setting.vue'
import SizeSetting, { defaultHorizontalUnits } from '../helpers/size_setting.vue' import UnitSetting, { defaultHorizontalUnits } from '../helpers/unit_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'
@ -64,7 +64,7 @@ const GeneralTab = {
ChoiceSetting, ChoiceSetting,
IntegerSetting, IntegerSetting,
FloatSetting, FloatSetting,
SizeSetting, UnitSetting,
InterfaceLanguageSwitcher, InterfaceLanguageSwitcher,
ScopeSelector, ScopeSelector,
ProfileSettingIndicator ProfileSettingIndicator

View File

@ -134,7 +134,7 @@
<li v-if="expertLevel > 0"> <li v-if="expertLevel > 0">
{{ $t('settings.column_sizes') }} {{ $t('settings.column_sizes') }}
<div class="column-settings"> <div class="column-settings">
<SizeSetting <UnitSetting
v-for="column in columns" v-for="column in columns"
:key="column" :key="column"
:path="column + 'ColumnWidth'" :path="column + 'ColumnWidth'"
@ -142,7 +142,7 @@
expert="1" expert="1"
> >
{{ $t('settings.column_sizes_' + column) }} {{ $t('settings.column_sizes_' + column) }}
</SizeSetting> </UnitSetting>
</div> </div>
</li> </li>
<li class="select-multiple"> <li class="select-multiple">
@ -200,6 +200,14 @@
<div class="setting-item"> <div class="setting-item">
<h2>{{ $t('settings.post_look_feel') }}</h2> <h2>{{ $t('settings.post_look_feel') }}</h2>
<ul class="setting-list"> <ul class="setting-list">
<li>
<BooleanSetting
path="forceThemeRecompilation"
:expert="1"
>
{{ $t('settings.force_theme_recompilation_debug') }}
</BooleanSetting>
</li>
<li> <li>
<ChoiceSetting <ChoiceSetting
id="conversationDisplay" id="conversationDisplay"

View File

@ -5,7 +5,7 @@
> >
<div class="panel panel-default"> <div class="panel panel-default">
<div <div
class="panel-heading timeline-heading" class="panel-heading"
:class="{ 'shout-heading': floating }" :class="{ 'shout-heading': floating }"
@click.stop.prevent="togglePanel" @click.stop.prevent="togglePanel"
> >
@ -18,7 +18,7 @@
/> />
</div> </div>
</div> </div>
<div class="shout-window"> <div class="panel-body shout-window">
<div <div
v-for="message in messages" v-for="message in messages"
:key="message.id" :key="message.id"
@ -41,10 +41,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="shout-input"> <div class="panel-body shout-input">
<textarea <textarea
v-model="currentMessage" v-model="currentMessage"
class="shout-input-textarea" class="shout-input-textarea input"
rows="1" rows="1"
@keyup.enter="submit(currentMessage)" @keyup.enter="submit(currentMessage)"
/> />

View File

@ -238,6 +238,9 @@ const Status = {
showActorTypeIndicator () { showActorTypeIndicator () {
return !this.hideBotIndication return !this.hideBotIndication
}, },
sensitiveStatus () {
return this.status.nsfw
},
mentionsLine () { mentionsLine () {
if (!this.headTailLinks) return [] if (!this.headTailLinks) return []
const writtenSet = new Set(this.headTailLinks.writtenMentions.map(_ => _.url)) const writtenSet = new Set(this.headTailLinks.writtenMentions.map(_ => _.url))
@ -265,7 +268,9 @@ const Status = {
// Wordfiltered // Wordfiltered
this.muteWordHits.length > 0 || this.muteWordHits.length > 0 ||
// bot status // bot status
(this.muteBotStatuses && this.botStatus && !this.compact) (this.muteBotStatuses && this.botStatus && !this.compact) ||
// sensitive status
(this.muteSensitiveStatuses && this.sensitiveStatus && !this.compact)
return !this.unmuted && !this.shouldNotMute && reasonsToMute return !this.unmuted && !this.shouldNotMute && reasonsToMute
}, },
userIsMuted () { userIsMuted () {
@ -368,9 +373,15 @@ const Status = {
hidePostStats () { hidePostStats () {
return this.mergedConfig.hidePostStats return this.mergedConfig.hidePostStats
}, },
shouldDisplayFavsAndRepeats () {
return !this.hidePostStats && this.isFocused && (this.combinedFavsAndRepeatsUsers.length > 0 || this.statusFromGlobalRepository.quotes_count)
},
muteBotStatuses () { muteBotStatuses () {
return this.mergedConfig.muteBotStatuses return this.mergedConfig.muteBotStatuses
}, },
muteSensitiveStatuses () {
return this.mergedConfig.muteSensitiveStatuses
},
hideBotIndication () { hideBotIndication () {
return this.mergedConfig.hideBotIndication return this.mergedConfig.hideBotIndication
}, },
@ -414,7 +425,27 @@ const Status = {
return this.quotedStatus && this.displayQuote return this.quotedStatus && this.displayQuote
}, },
scrobblePresent () { scrobblePresent () {
return !this.mergedConfig.hideScrobbles && this.status.user.latestScrobble && this.status.user.latestScrobble.artist if (this.mergedConfig.hideScrobbles) return false
if (!this.status.user.latestScrobble) return false
const value = this.mergedConfig.hideScrobblesAfter.match(/\d+/gs)[0]
const unit = this.mergedConfig.hideScrobblesAfter.match(/\D+/gs)[0]
let multiplier = 60 * 1000 // minutes is smallest unit
switch (unit) {
case 'm':
break
case 'h':
multiplier *= 60 // hour
break
case 'd':
multiplier *= 60 // hour
multiplier *= 24 // day
break
}
const maxAge = Number(value) * multiplier
const createdAt = Date.parse(this.status.user.latestScrobble.created_at)
const age = Date.now() - createdAt
if (age > maxAge) return false
return this.status.user.latestScrobble.artist
}, },
scrobble () { scrobble () {
return this.status.user.latestScrobble return this.status.user.latestScrobble

View File

@ -374,6 +374,7 @@
font-weight: bolder; font-weight: bolder;
font-size: 1.1em; font-size: 1.1em;
line-height: 1em; line-height: 1em;
color: var(--text);
} }
&:hover .stat-title { &:hover .stat-title {

View File

@ -30,6 +30,12 @@
:at="false" :at="false"
/> />
</small> </small>
<small
v-if="muteSensitiveStatuses && status.nsfw"
class="mute-thread"
>
{{ $t('status.sensitive_muted') }}
</small>
<small <small
v-if="showReasonMutedThread" v-if="showReasonMutedThread"
class="mute-thread" class="mute-thread"
@ -478,7 +484,7 @@
<transition name="fade"> <transition name="fade">
<div <div
v-if="!hidePostStats && isFocused && combinedFavsAndRepeatsUsers.length > 0" v-if="shouldDisplayFavsAndRepeats"
class="favs-repeated-users" class="favs-repeated-users"
> >
<div class="stats"> <div class="stats">
@ -506,6 +512,19 @@
</div> </div>
</div> </div>
</UserListPopover> </UserListPopover>
<router-link
v-if="statusFromGlobalRepository.quotes_count > 0"
:to="{ name: 'quotes', params: { id: status.id } }"
>
<div
class="stat-count"
>
<a class="stat-title">{{ $t('status.quotes') }}</a>
<div class="stat-number">
{{ statusFromGlobalRepository.quotes_count }}
</div>
</div>
</router-link>
<div class="avatar-row"> <div class="avatar-row">
<AvatarList :users="combinedFavsAndRepeatsUsers" /> <AvatarList :users="combinedFavsAndRepeatsUsers" />
</div> </div>

View File

@ -174,6 +174,7 @@
font-size: 1em; font-size: 1em;
font-family: var(--font); font-family: var(--font);
border-radius: var(--roundness); border-radius: var(--roundness);
background-color: var(--background);
position: relative; position: relative;
white-space: nowrap; white-space: nowrap;
padding: 6px 1em; padding: 6px 1em;

View File

@ -25,6 +25,7 @@ const Timeline = {
'title', 'title',
'userId', 'userId',
'listId', 'listId',
'statusId',
'tag', 'tag',
'embedded', 'embedded',
'count', 'count',
@ -121,6 +122,7 @@ const Timeline = {
showImmediately, showImmediately,
userId: this.userId, userId: this.userId,
listId: this.listId, listId: this.listId,
statusId: this.statusId,
tag: this.tag tag: this.tag
}) })
}, },
@ -183,6 +185,7 @@ const Timeline = {
showImmediately: true, showImmediately: true,
userId: this.userId, userId: this.userId,
listId: this.listId, listId: this.listId,
statusId: this.statusId,
tag: this.tag tag: this.tag
}).then(({ statuses }) => { }).then(({ statuses }) => {
if (statuses && statuses.length === 0) { if (statuses && statuses.length === 0) {

View File

@ -19,7 +19,8 @@ export const timelineNames = () => {
bookmarks: 'nav.bookmarks', bookmarks: 'nav.bookmarks',
dms: 'nav.dms', dms: 'nav.dms',
'public-timeline': 'nav.public_tl', 'public-timeline': 'nav.public_tl',
'public-external-timeline': 'nav.twkn' 'public-external-timeline': 'nav.twkn',
quotes: 'nav.quotes'
} }
} }

View File

@ -204,6 +204,11 @@
--emoji-size: 1.7em; --emoji-size: 1.7em;
.RichContent {
/* stylelint-disable-next-line declaration-no-important */
--link: var(--text) !important;
}
.top-line, .top-line,
.bottom-line { .bottom-line {
display: flex; display: flex;

View File

@ -127,7 +127,7 @@
:title="$t('user_card.favorites')" :title="$t('user_card.favorites')"
timeline-name="favorites" timeline-name="favorites"
:timeline="favorites" :timeline="favorites"
:user-id="userId" :user-id="isUs ? undefined : userId"
:in-profile="true" :in-profile="true"
:footer-slipgate="footerRef" :footer-slipgate="footerRef"
/> />

View File

@ -678,7 +678,7 @@
"autohide_floating_post_button": "Automaticky skrýt tlačítko nového příspěvku (mobilní zařízení)", "autohide_floating_post_button": "Automaticky skrýt tlačítko nového příspěvku (mobilní zařízení)",
"minimal_scopes_mode": "Minimalizovat možnosti rozsahu příspěvků", "minimal_scopes_mode": "Minimalizovat možnosti rozsahu příspěvků",
"conversation_display": "Styl zobrazení konverzací", "conversation_display": "Styl zobrazení konverzací",
"conversation_display_tree": "Stromový styl", "conversation_display_tree": "Stromové zobrazení",
"conversation_display_tree_quick": "Stromový styl", "conversation_display_tree_quick": "Stromový styl",
"show_scrollbars": "Zobrazit posuvníky bočních sloupců", "show_scrollbars": "Zobrazit posuvníky bočních sloupců",
"third_column_mode": "Pokud je volné místo, zobrazit třetí sloupec obsahující", "third_column_mode": "Pokud je volné místo, zobrazit třetí sloupec obsahující",
@ -737,7 +737,8 @@
"frontend_version": "Frontend verze" "frontend_version": "Frontend verze"
}, },
"commit_value_tooltip": "Hodnota není uložena, stiskněte toto tlačítko pro potvrzení změn", "commit_value_tooltip": "Hodnota není uložena, stiskněte toto tlačítko pro potvrzení změn",
"hard_reset_value_tooltip": "Odstranit nastavení z úložiště a vynutit výchozí hodnotu" "hard_reset_value_tooltip": "Odstranit nastavení z úložiště a vynutit výchozí hodnotu",
"accent": "Akcentní barva"
}, },
"time": { "time": {
"day": "{0} day", "day": "{0} day",
@ -748,7 +749,7 @@
"hours": "{0} hours", "hours": "{0} hours",
"hour_short": "{0}h", "hour_short": "{0}h",
"hours_short": "{0}h", "hours_short": "{0}h",
"in_future": "in {0}", "in_future": "za {0}",
"in_past": "před {0}", "in_past": "před {0}",
"minute": "{0} minute", "minute": "{0} minute",
"minutes": "{0} minutes", "minutes": "{0} minutes",
@ -758,8 +759,8 @@
"months": "{0} měs", "months": "{0} měs",
"month_short": "{0} měs", "month_short": "{0} měs",
"months_short": "{0} měs", "months_short": "{0} měs",
"now": "teď", "now": "právě teď",
"now_short": "teď", "now_short": "nyní",
"second": "{0} second", "second": "{0} second",
"seconds": "{0} seconds", "seconds": "{0} seconds",
"second_short": "{0}s", "second_short": "{0}s",
@ -771,7 +772,23 @@
"year": "{0} r", "year": "{0} r",
"years": "{0} l", "years": "{0} l",
"year_short": "{0}r", "year_short": "{0}r",
"years_short": "{0}l" "years_short": "{0}l",
"unit": {
"seconds_short": "{0}s",
"days": "{0} den | {0} dnů",
"days_short": "{0}d",
"hours": "{0} hodina | {0} hodin",
"hours_short": "{0}h",
"minutes": "{0} minuta | {0} minut",
"months": "{0} měsíc | {0} měsíců",
"months_short": "{0}mo",
"minutes_short": "{0}min",
"seconds": "{0} sekunda | {0} sekund",
"weeks": "{0} týden | {0} týdnů",
"weeks_short": "{0}w",
"years": "{0} rok | {0} roky",
"years_short": "{0}y"
}
}, },
"timeline": { "timeline": {
"collapse": "Zabalit", "collapse": "Zabalit",
@ -783,11 +800,60 @@
"show_new": "Zobrazit nové", "show_new": "Zobrazit nové",
"up_to_date": "Aktuální", "up_to_date": "Aktuální",
"no_more_statuses": "Žádné další příspěvky", "no_more_statuses": "Žádné další příspěvky",
"no_statuses": "Žádné příspěvky" "no_statuses": "Žádné příspěvky",
"socket_reconnected": "Navázáno spojení v reálném čase",
"error": "Chyba při načítání časové osy: {0}",
"reload": "Načíst znovu",
"socket_broke": "Spojení v reálném čase ztraceno: CloseEvent code {0}"
}, },
"status": { "status": {
"reply_to": "Odpověď uživateli", "reply_to": "Odpověď uživateli",
"replies_list": "Odpovědi:" "replies_list": "Odpovědi:",
"many_attachments": "Příspěvek má {number} příloh(u)",
"collapse_attachments": "Sbalit přílohy",
"unpin": "Odepnout z profilu",
"thread_muted": "Vlákno ztlumeno",
"show_attachment_description": "Popis náhledu (otevřete přílohu pro celý popis)",
"move_down": "Posunout přílohu doprava",
"thread_show": "Zobrazit toto vlákno",
"pin": "Připnout na profil",
"mute_conversation": "Ztlumit konverzaci",
"thread_hide": "Skrýt toto vlákno",
"show_full_subject": "Zobrazit celý předmět",
"edited_at": "(naposledy upraveno {time})",
"repeat_confirm_accept_button": "Zopakovat",
"repeat_confirm_title": "Potvrzení zopakování",
"delete_error": "Chyba při mazání příspěvku: {0}",
"delete_confirm": "Opravdu chcete smazat tento příspěvek?",
"delete_confirm_title": "Potvrzení smazání",
"delete_confirm_accept_button": "Smazat",
"delete_confirm_cancel_button": "Ponechat",
"you": "(Vy)",
"hide_attachment": "Skrýt přílohu",
"remove_attachment": "Odstranit přílohu",
"attachment_stop_flash": "Zastavit Flash player",
"nsfw": "NSFW",
"repeat_confirm_cancel_button": "Neopakovat",
"favorites": "Oblíbené",
"repeats": "Opakovaní",
"repeat_confirm": "Opravdu chcete zopakovat tento příspěvek?",
"delete": "Smazat příspěvek",
"copy_link": "Kopírovat odkaz k příspěvku",
"external_source": "Externí zdroj",
"edit": "Upravit příspěvek",
"bookmark": "Přidat do záložek",
"unbookmark": "Odebrat ze záložek",
"mentions": "Zmínky",
"hide_full_subject": "Skrýt celý předmět",
"show_content": "Zobrazit obsah",
"hide_content": "Skrýt obsah",
"unmute_conversation": "Zrušit ztlumení konverzace",
"status_unavailable": "Příspěvek je nedostupný",
"status_deleted": "Tento příspěvek byl smazán",
"expand": "Rozbalit",
"show_all_attachments": "Zobrazit všechny přílohy",
"move_up": "Posunout přílohu doleva",
"open_gallery": "Otevřít galerii"
}, },
"user_card": { "user_card": {
"approve": "Schválit", "approve": "Schválit",
@ -797,7 +863,7 @@
"favorites": "Oblíbené", "favorites": "Oblíbené",
"follow": "Sledovat", "follow": "Sledovat",
"follow_sent": "Požadavek odeslán!", "follow_sent": "Požadavek odeslán!",
"follow_progress": "Odeslílám požadavek…", "follow_progress": "Odesílám požadavek…",
"follow_unfollow": "Přestat sledovat", "follow_unfollow": "Přestat sledovat",
"followees": "Sledovaní", "followees": "Sledovaní",
"followers": "Sledující", "followers": "Sledující",
@ -995,13 +1061,121 @@
"nodb": "Žádné nastavení v databázi", "nodb": "Žádné nastavení v databázi",
"frontends": "Frontendy", "frontends": "Frontendy",
"instance": "Instance", "instance": "Instance",
"limits": "Limity" "limits": "Limity",
"emoji": "Emoji"
}, },
"nodb": { "nodb": {
"heading": "Nastavení v databázi je vypnuto" "heading": "Nastavení v databázi je vypnuto",
"documentation": "dokumentace",
"text2": "Většina konfiguračních možností nebude dostupná."
}, },
"wip_notice": "Tento administrační panel je experimentální a v aktivní vývoji, {adminFeLink}.", "wip_notice": "Tento administrační panel je experimentální a v aktivní vývoji, {adminFeLink}.",
"old_ui_link": "staré administrační rozhraní je dostupné zde", "old_ui_link": "staré administrační rozhraní je dostupné zde",
"reset_all": "Resetovat vše" "reset_all": "Resetovat vše",
"frontend": {
"failure_installing_frontend": "Nepodařilo se nainstalovat frontend {version}: {reason}",
"reinstall": "Přeinstalovat",
"available_frontends": "Dostupné k instalaci",
"is_default": "(Výchozí)",
"versions": "Dostupné verze",
"build_url": "URL sestavení",
"install": "Instalovat",
"install_version": "Instalovat verzi {version}",
"more_install_options": "Více instalačních možností",
"more_default_options": "Více výchozích nastavení pro možnosti",
"set_default": "Nastavit výchozí",
"default_frontend": "Výchozí frontend",
"set_default_version": "Nastavit verzi {version} jako výchozí",
"repository": "Odkaz k repozitáři",
"is_default_custom": "(Výchozí, verze: {version})",
"success_installing_frontend": "Frontend {version} byl úspěšně nainstalován"
},
"captcha": {
"native": "Nativní",
"kocaptcha": "KoCaptcha"
},
"instance": {
"instance": "Informace o instanci",
"captcha_header": "CAPTCHA",
"restrict": {
"activities": "Přístup k příspěvkům a aktivitám",
"timelines": "Přístup k časovým osám",
"profiles": "Přístup k uživatelským profilům",
"header": "Omezit přístup pro anonymní návštěvníky"
},
"registrations": "Registrace uživatelů",
"kocaptcha": "KoCaptcha nastavení"
},
"limits": {
"posts": "Limity příspěvků",
"uploads": "Limity příloh",
"users": "Limity uživatelských profilů",
"arbitrary_limits": "Libovolné limity",
"profile_fields": "Limity profilových polí",
"user_uploads": "Limity médií profilů"
},
"emoji": {
"global_actions": "Globální akce",
"reload": "Znovu načíst emoji",
"importFS": "Importovat emoji ze souborového systému",
"error": "Chyba: {0}",
"create_pack": "Vytvořit balíček",
"delete_pack": "Smazat balíček",
"new_pack_name": "Nový název balíčku",
"create": "Vytvořit",
"emoji_packs": "Emoji balíčky",
"remote_packs": "Vzdálené balíčky",
"do_list": "List",
"emoji_pack": "Emoji balíček",
"edit_pack": "Upravit balíček",
"description": "Popis",
"homepage": "Domovská stránka",
"fallback_src": "Záložní zdroj",
"fallback_sha256": "Záložní SHA256",
"share": "Sdílet",
"save": "Uložit",
"save_meta": "Uložit metadata",
"revert_meta": "Vrátit zpět metadata",
"delete": "Smazat",
"add_file": "Přidat soubor",
"adding_new": "Přidávání nových emoji",
"shortcode": "Zkratka",
"filename": "Jméno souboru",
"new_shortcode": "Zkrat, ponechte prázdné pro odvození",
"delete_confirm": "Opravdu chcete smazat {0}?",
"download_pack": "Stáhnout balíček",
"downloading_pack": "Stahování {0}",
"download": "Stáhnout",
"download_as_name": "Nové jméno",
"download_as_name_full": "Nové jméno, pro opakované použití ponechte prázdné",
"files": "Soubory",
"editing": "Upravování {0}",
"delete_title": "Smazat?",
"emoji_changed": "Neuložené změny emoji souborů, zkontrolujte zvýrazněné emoji",
"replace_warning": "Tímto se NAHRADÍ místní balíček se stejným jménem",
"metadata_changed": "Metadata jsou rozdílné od uložených",
"revert": "Vrátit zpět",
"new_filename": "Jméno souboru, ponechte prázdné pro odvození"
},
"temp_overrides": {
":pleroma": {
":instance": {
":background_image": {
"label": "Obrázek na pozadí",
"description": "Obrázek na pozadí (především používáno PleromaFE)"
},
":description_limit": {
"label": "Limit",
"description": "Limit počtu znaků pro popisy příloh"
},
":public": {
"label": "Instance je veřejná"
},
":limit_to_local_content": {
"label": "Limitovat vyhledávání pouze na místní obsah"
}
}
}
}
} }
} }

View File

@ -186,11 +186,11 @@
"edit_pinned": "Edit pinned items", "edit_pinned": "Edit pinned items",
"edit_finish": "Done editing", "edit_finish": "Done editing",
"mobile_sidebar": "Toggle mobile sidebar", "mobile_sidebar": "Toggle mobile sidebar",
"mobile_notifications": "Open notifications",
"mobile_notifications": "Open notifications (there are unread ones)", "mobile_notifications": "Open notifications (there are unread ones)",
"mobile_notifications_close": "Close notifications", "mobile_notifications_close": "Close notifications",
"mobile_notifications_mark_as_seen": "Mark all as seen", "mobile_notifications_mark_as_seen": "Mark all as seen",
"announcements": "Announcements" "announcements": "Announcements",
"quotes": "Quotes"
}, },
"notifications": { "notifications": {
"broken_favorite": "Unknown status, searching for it…", "broken_favorite": "Unknown status, searching for it…",
@ -395,6 +395,14 @@
"desc": "To enable two-factor authentication, enter the code from your two-factor app:" "desc": "To enable two-factor authentication, enter the code from your two-factor app:"
} }
}, },
"units": {
"time": {
"m": "minutes",
"s": "seconds",
"h": "hours",
"d": "days"
}
},
"lists_navigation": "Show lists in navigation", "lists_navigation": "Show lists in navigation",
"allow_following_move": "Allow auto-follow when following account moves", "allow_following_move": "Allow auto-follow when following account moves",
"attachmentRadius": "Attachments", "attachmentRadius": "Attachments",
@ -502,6 +510,8 @@
"mute_bot_posts": "Mute bot posts", "mute_bot_posts": "Mute bot posts",
"hide_actor_type_indication": "Hide actor type (bots, groups, etc.) indication in posts", "hide_actor_type_indication": "Hide actor type (bots, groups, etc.) indication in posts",
"hide_scrobbles": "Hide scrobbles", "hide_scrobbles": "Hide scrobbles",
"hide_scrobbles_after": "Hide scrobbles older than",
"mute_sensitive_posts": "Mute sensitive posts",
"hide_all_muted_posts": "Hide muted posts", "hide_all_muted_posts": "Hide muted posts",
"max_thumbnails": "Maximum amount of thumbnails per post (empty = no limit)", "max_thumbnails": "Maximum amount of thumbnails per post (empty = no limit)",
"hide_isp": "Hide instance-specific panel", "hide_isp": "Hide instance-specific panel",
@ -635,6 +645,7 @@
"subject_line_email": "Like email: \"re: subject\"", "subject_line_email": "Like email: \"re: subject\"",
"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",
"force_theme_recompilation_debug": "Disable theme cahe, force recompile on each boot (DEBUG)",
"conversation_display": "Conversation display style", "conversation_display": "Conversation display style",
"conversation_display_tree": "Tree-style", "conversation_display_tree": "Tree-style",
"conversation_display_tree_quick": "Tree view", "conversation_display_tree_quick": "Tree view",
@ -906,7 +917,7 @@
"description": "Detailed setting for allowing/disallowing access to certain aspects of API. By default (indeterminate state) it will disallow if instance is not public, ticked checkbox means disallow access even if instance is public, unticked means allow access even if instance is private. Please note that unexpected behavior might happen if some settings are set, i.e. if profile access is disabled posts will show without profile information.", "description": "Detailed setting for allowing/disallowing access to certain aspects of API. By default (indeterminate state) it will disallow if instance is not public, ticked checkbox means disallow access even if instance is public, unticked means allow access even if instance is private. Please note that unexpected behavior might happen if some settings are set, i.e. if profile access is disabled posts will show without profile information.",
"timelines": "Timelines access", "timelines": "Timelines access",
"profiles": "User profiles access", "profiles": "User profiles access",
"activities": "Statues/activities access" "activities": "Statuses/activities access"
} }
}, },
"limits": { "limits": {
@ -931,8 +942,8 @@
"set_default": "Set default", "set_default": "Set default",
"set_default_version": "Set version {version} as default", "set_default_version": "Set version {version} as default",
"wip_notice": "Please note that this section is a WIP and lacks certain features as backend implementation of front-end management is incomplete.", "wip_notice": "Please note that this section is a WIP and lacks certain features as backend implementation of front-end management is incomplete.",
"default_frontend": "Default front-end", "default_frontend": "Default frontend",
"default_frontend_tip": "Default front-end will be shown to all users. Currently there's no way to for a user to select personal front-end. If you switch away from PleromaFE you'll most likely have to use old and buggy AdminFE to do instance configuration until we replace it.", "default_frontend_tip": "Default frontend will be shown to all users. Currently there's no way to for a user to select personal frontend. If you switch away from PleromaFE you'll most likely have to use old and buggy AdminFE to do instance configuration until we replace it.",
"default_frontend_unavail": "Default frontend settings are not available, as this requires configuration in the database", "default_frontend_unavail": "Default frontend settings are not available, as this requires configuration in the database",
"available_frontends": "Available for install", "available_frontends": "Available for install",
"failure_installing_frontend": "Failed to install frontend {version}: {reason}", "failure_installing_frontend": "Failed to install frontend {version}: {reason}",
@ -1047,6 +1058,7 @@
"status": { "status": {
"favorites": "Favorites", "favorites": "Favorites",
"repeats": "Repeats", "repeats": "Repeats",
"quotes": "Quotes",
"repeat_confirm": "Do you really want to repeat this status?", "repeat_confirm": "Do you really want to repeat this status?",
"repeat_confirm_title": "Repeat confirmation", "repeat_confirm_title": "Repeat confirmation",
"repeat_confirm_accept_button": "Repeat", "repeat_confirm_accept_button": "Repeat",
@ -1075,6 +1087,7 @@
"external_source": "External source", "external_source": "External source",
"thread_muted": "Thread muted", "thread_muted": "Thread muted",
"thread_muted_and_words": ", has words:", "thread_muted_and_words": ", has words:",
"sensitive_muted": "Muting sensitive content",
"show_full_subject": "Show full subject", "show_full_subject": "Show full subject",
"hide_full_subject": "Hide full subject", "hide_full_subject": "Hide full subject",
"show_content": "Show content", "show_content": "Show content",
@ -1111,7 +1124,9 @@
"hide_quote": "Hide the quoted status", "hide_quote": "Hide the quoted status",
"display_quote": "Display the quoted status", "display_quote": "Display the quoted status",
"invisible_quote": "Quoted status unavailable: {link}", "invisible_quote": "Quoted status unavailable: {link}",
"more_actions": "More actions on this status" "more_actions": "More actions on this status",
"loading": "Loading...",
"load_error": "Unable to load status: {error}"
}, },
"user_card": { "user_card": {
"approve": "Approve", "approve": "Approve",

View File

@ -90,7 +90,11 @@
"heading": { "heading": {
"totp": "Authentification à double-facteur", "totp": "Authentification à double-facteur",
"recovery": "Récupération de l'authentification à double-facteur" "recovery": "Récupération de l'authentification à double-facteur"
} },
"logout_confirm_title": "Confirmation de déconnexion",
"logout_confirm": "Souhaitez-vous vous déconnecter ?",
"logout_confirm_accept_button": "Déconnexion",
"logout_confirm_cancel_button": "Ne pas se déconnecter"
}, },
"media_modal": { "media_modal": {
"previous": "Précédent", "previous": "Précédent",
@ -110,7 +114,7 @@
"timeline": "Flux personnel", "timeline": "Flux personnel",
"twkn": "Réseau connu", "twkn": "Réseau connu",
"user_search": "Recherche de comptes", "user_search": "Recherche de comptes",
"who_to_follow": "Suggestion de suivit", "who_to_follow": "Suggestion de suivi",
"preferences": "Préférences", "preferences": "Préférences",
"search": "Recherche", "search": "Recherche",
"administration": "Administration", "administration": "Administration",
@ -124,7 +128,10 @@
"edit_pinned": "Éditer les éléments agrafés", "edit_pinned": "Éditer les éléments agrafés",
"edit_finish": "Édition terminée", "edit_finish": "Édition terminée",
"mobile_sidebar": "(Dés)activer le panneau latéral", "mobile_sidebar": "(Dés)activer le panneau latéral",
"mobile_notifications_close": "Fermer les notifications" "mobile_notifications_close": "Fermer les notifications",
"search_close": "Fermer la barre de recherche",
"announcements": "Annonces",
"mobile_notifications_mark_as_seen": "Marquer tout comme vu"
}, },
"notifications": { "notifications": {
"broken_favorite": "Message inconnu, recherche en cours…", "broken_favorite": "Message inconnu, recherche en cours…",
@ -140,7 +147,13 @@
"follow_request": "veut vous suivre", "follow_request": "veut vous suivre",
"error": "Erreur de chargement des notifications: {0}", "error": "Erreur de chargement des notifications: {0}",
"poll_ended": "Sondage terminé", "poll_ended": "Sondage terminé",
"submitted_report": "Rapport envoyé" "submitted_report": "Rapport envoyé",
"unread_announcements": "{num} annonce non lue | {num} annonces non lues",
"unread_chats": "{num} message non lu | {num} messages non lus",
"configuration_tip_settings": "les préférences",
"unread_follow_requests": "{num} nouvelle demande de suivi | {num} nouvelles demandes de suivi",
"configuration_tip": "Vous pouvez personnaliser ce qui est affiché ici dans {theSettings}. {dismiss}",
"configuration_tip_dismiss": "Ne plus montrer"
}, },
"interactions": { "interactions": {
"favs_repeats": "Partages et favoris", "favs_repeats": "Partages et favoris",
@ -154,7 +167,7 @@
"new_status": "Poster un nouveau statut", "new_status": "Poster un nouveau statut",
"account_not_locked_warning": "Votre compte n'est pas {0}. N'importe qui peut vous suivre pour voir vos billets en Abonné·e·s uniquement.", "account_not_locked_warning": "Votre compte n'est pas {0}. N'importe qui peut vous suivre pour voir vos billets en Abonné·e·s uniquement.",
"account_not_locked_warning_link": "verrouillé", "account_not_locked_warning_link": "verrouillé",
"attachments_sensitive": "Marquer les pièce-jointes comme sensible", "attachments_sensitive": "Marquer les pièces jointes comme sensible",
"content_type": { "content_type": {
"text/plain": "Texte brut", "text/plain": "Texte brut",
"text/html": "HTML", "text/html": "HTML",
@ -183,9 +196,13 @@
"preview": "Prévisualisation", "preview": "Prévisualisation",
"media_description": "Description de la pièce-jointe", "media_description": "Description de la pièce-jointe",
"post": "Post", "post": "Post",
"edit_status": "Éditer le status", "edit_status": "Éditer le statut",
"edit_remote_warning": "Des instances distantes pourraient ne pas supporter l'édition et seront incapables de recevoir la nouvelle version de votre post.", "edit_remote_warning": "Des instances distantes pourraient ne pas supporter l'édition et seront incapables de recevoir la nouvelle version de votre post.",
"edit_unsupported_warning": "Pleroma ne supporte pas l'édition de mentions ni de sondages." "edit_unsupported_warning": "Pleroma ne supporte pas l'édition de mentions ni de sondages.",
"reply_option": "Répondre à ce statut",
"quote_option": "Citer ce statut",
"scope_notice_dismiss": "Fermer ce message",
"content_type_selection": "Format du statut"
}, },
"registration": { "registration": {
"bio": "Biographie", "bio": "Biographie",
@ -205,14 +222,18 @@
"email_required": "ne peut pas être laissé vide", "email_required": "ne peut pas être laissé vide",
"password_required": "ne peut pas être laissé vide", "password_required": "ne peut pas être laissé vide",
"password_confirmation_required": "ne peut pas être laissé vide", "password_confirmation_required": "ne peut pas être laissé vide",
"password_confirmation_match": "doit être identique au mot de passe" "password_confirmation_match": "doit être identique au mot de passe",
"birthday_min_age": "doit être le ou avant le {date}",
"birthday_required": "ne peut pas être vide"
}, },
"reason_placeholder": "Cette instance modère les inscriptions manuellement.\nExpliquer ce qui motive votre inscription à l'administration.", "reason_placeholder": "Cette instance modère les inscriptions manuellement.\nExpliquer ce qui motive votre inscription à l'administration.",
"reason": "Motivation d'inscription", "reason": "Motivation d'inscription",
"register": "Enregistrer", "register": "Enregistrer",
"email_language": "Dans quelle langue voulez-vous recevoir les emails du server ?", "email_language": "Dans quelle langue voulez-vous recevoir les emails du server ?",
"bio_optional": "Biographie (optionnelle)", "bio_optional": "Biographie (optionnelle)",
"email_optional": "Courriel (optionnel)" "email_optional": "Courriel (optionnel)",
"birthday": "Anniversaire :",
"birthday_optional": "Anniversaire (optionnel) :"
}, },
"selectable_list": { "selectable_list": {
"select_all": "Tout selectionner" "select_all": "Tout selectionner"
@ -684,7 +705,64 @@
"use_websockets": "Utiliser les websockets (mises à jour en temps réel)", "use_websockets": "Utiliser les websockets (mises à jour en temps réel)",
"user_popover_avatar_action_zoom": "Zoomer sur l'avatar", "user_popover_avatar_action_zoom": "Zoomer sur l'avatar",
"user_popover_avatar_action_open": "Ouvrir le profil", "user_popover_avatar_action_open": "Ouvrir le profil",
"conversation_display_tree_quick": "Vue arborescente" "conversation_display_tree_quick": "Vue arborescente",
"emoji_reactions_scale": "Taille des réactions",
"backup_running": "Cette sauvegarde est en cours, {number} enregistrement effectué. | Cette sauvegarde est en cours, {number} enregistrements effectués.",
"backup_failed": "Cette sauvegarde a échoué.",
"autocomplete_select_first": "Sélectionner automatiquement la première occurrence lorsque les résultats de l'autocomplétion sont disponibles",
"confirm_dialogs_unfollow": "arrête de suivre un utilisateur",
"confirm_dialogs_repeat": "reposte un statut",
"actor_type": "Ce compte est :",
"actor_type_Person": "un utilisateur normal",
"actor_type_Service": "un robot",
"actor_type_Group": "un groupe",
"confirm_dialogs_logout": "à la déconnexion",
"confirm_dialogs_approve_follow": "accepte un nouvel abonné",
"confirm_dialogs_deny_follow": "refuse un nouvel abonné",
"confirm_dialogs_remove_follower": "supprime un abonné",
"actor_type_description": "En marquant votre compte comme un groupe, vous répétez automatiquement les statuts qui le mentionnent.",
"add_language": "Ajouter une langue de remplacement",
"remove_language": "Supprimer",
"primary_language": "Langue principale :",
"fallback_language": "Langue de remplacement {index} :",
"confirm_dialogs": "Demande de confirmation quand",
"confirm_dialogs_block": "bloque un utilisateur",
"confirm_dialogs_mute": "mute un utilisateur",
"confirm_dialogs_delete": "supprime un statut",
"url": "URL",
"preview": "Aperçu",
"reset_value": "Réinitialiser",
"hard_reset_value_tooltip": "Supprime le réglage du stockage, force l'utilisation de la valeur par défaut",
"reset_value_tooltip": "Réinitialiser le brouillon",
"hard_reset_value": "Remise à zéro",
"hide_actor_type_indication": "Cacher le type (robots, groupes, etc.) dans les status",
"notification_extra_follow_requests": "Afficher les nouvelles demandes de suivi",
"user_popover_avatar_action": "Action du clic sur l'avatar",
"user_popover_avatar_action_close": "Fermer la fenêtre contextuelle",
"notification_setting_ignore_inactionable_seen": "Ignorer les status de lecture des notifications non actionnables (favoris, répétitions, etc)",
"notification_setting_ignore_inactionable_seen_tip": "Ceci ne marquera pas ces notifications comme lues, et vous recevrez encore les notifications de bureau si vous le décidez",
"notification_setting_unseen_at_top": "Afficher les notifications non lues au-dessus des autres",
"notification_setting_filters_chrome_push": "Sur certains navigateurs (chrome), il peut être impossible de filtrer complètement les notifications par type lorsqu'elles arrivent",
"enable_web_push_always_show": "Toujours afficher les notifications web",
"commit_value": "Sauvegarder",
"hide_scrobbles": "Masquer les scrobbles",
"notification_setting_annoyance": "Agacement",
"notification_setting_drawer_marks_as_seen": "Fermer le tiroir marque toutes les notifications comme lues (mobile)",
"commit_value_tooltip": "Les valeurs ne sont pas sauvegardées, appuyez sur ce bouton pour soumettre vos changements",
"birthday": {
"show_birthday": "Afficher mon anniversaire",
"label": "Anniversaire"
},
"notification_visibility_native_notifications": "Afficher une notification native",
"notification_visibility_follow_requests": "Demandes de suivi",
"notification_visibility_reports": "Rapports",
"notification_extra_chats": "Afficher les discussions non lues",
"notification_extra_announcements": "Afficher les annonces non lues",
"notification_extra_tip": "Afficher les astuces de personnalisation pour les notifications extras",
"enable_web_push_always_show_tip": "Certains navigateurs (Chromium, Chrome) exigent que les messages push donnent toujours lieu à une notification, sinon le message générique \"Le site web a été mis à jour en arrière-plan\" s'affiche ; activez cette option pour empêcher l'affichage de cette notification, car Chrome semble masquer les notifications push si l'onglet est au centre de l'attention. Cela peut entraîner l'affichage de notifications en double sur d'autres navigateurs.",
"user_popover_avatar_overlay": "Afficher la fenêtre contextuelle sur l'avatar de l'utilisateur",
"notification_visibility_in_column": "Afficher la colonne / le tiroir de notifications",
"notification_show_extra": "Afficher les extras dans la colonne de notifications"
}, },
"timeline": { "timeline": {
"collapse": "Fermer", "collapse": "Fermer",
@ -758,7 +836,20 @@
"show_all_conversation": "Montrer tout le fil ({numStatus} autre message) | Montrer tout le fil ({numStatus} autre messages)", "show_all_conversation": "Montrer tout le fil ({numStatus} autre message) | Montrer tout le fil ({numStatus} autre messages)",
"edit": "Éditer le status", "edit": "Éditer le status",
"edited_at": "(dernière édition {time})", "edited_at": "(dernière édition {time})",
"status_history": "Historique du status" "status_history": "Historique du status",
"delete_error": "Erreur de suppression du statut : {0}",
"repeat_confirm": "Voulez-vous réellement reposter ce statut ?",
"reaction_count_label": "{num} personne a réagi | {num} personnes ont réagi",
"repeat_confirm_cancel_button": "Ne pas reposter",
"hide_quote": "Masquer les status cités",
"display_quote": "Afficher les status cités",
"invisible_quote": "Citation de statut non disponible : {link}",
"delete_confirm_title": "Confirmer la suppression",
"more_actions": "Plus d'action sur ce statut",
"delete_confirm_cancel_button": "Conserver",
"repeat_confirm_title": "Confirmer reposte",
"repeat_confirm_accept_button": "Reposter",
"delete_confirm_accept_button": "Supprimer"
}, },
"user_card": { "user_card": {
"approve": "Accepter", "approve": "Accepter",
@ -828,7 +919,39 @@
"edit_profile": "Éditer le profil", "edit_profile": "Éditer le profil",
"deactivated": "Désactivé", "deactivated": "Désactivé",
"follow_cancel": "Annuler la requête", "follow_cancel": "Annuler la requête",
"remove_follower": "Retirer l'abonné·e" "remove_follower": "Retirer l'abonné·e",
"remove_follower_confirm_accept_button": "Supprimer",
"approve_confirm_cancel_button": "Ne pas approuver",
"block_confirm_accept_button": "Bloquer",
"mute_confirm_title": "Confirmation de mise en sourdine",
"block_confirm_cancel_button": "Ne pas bloquer",
"unfollow_confirm": "Voulez-vous vraiment arrêter de suivre {user} ?",
"unfollow_confirm_accept_button": "Ne plus suivre",
"birthday": "Né(e) le {birthday}",
"edit_note": "Éditer note",
"edit_note_apply": "Appliquer",
"edit_note_cancel": "Abandonner",
"note": "Note",
"group": "Groupe",
"unfollow_confirm_title": "Confirmer l'arrêt de suivi",
"block_confirm_title": "Confirmer le blocage",
"deny_confirm_accept_button": "Refuser",
"deny_confirm_cancel_button": "Ne pas refuser",
"deny_confirm": "Voulez-vous refuser la demande de suivi de {user} ?",
"deny_confirm_title": "Refuser la confirmation",
"remove_follower_confirm_cancel_button": "Conserver",
"mute_duration_prompt": "Mettre cet utilisateur en sourdine pour (0 pour une durée indéterminée) :",
"remove_follower_confirm_title": "Confirmation de suppression d'utilisateur",
"note_blank": "(Aucun)",
"mute_confirm": "Voulez-vous vraiment mettre {user} en sourdine ?",
"mute_confirm_accept_button": "Mettre en sourdine",
"mute_confirm_cancel_button": "Ne pas mettre en sourdine",
"remove_follower_confirm": "Voulez-vous vraiment supprimer {user} de vos abonnés ?",
"approve_confirm_accept_button": "Approuver",
"approve_confirm": "Voulez-vous approuver la demande de suivi de {user} ?",
"block_confirm": "Voulez-vous vraiment bloquer {user} ?",
"approve_confirm_title": "Approuver confirmation",
"unfollow_confirm_cancel_button": "Ne pas arrêter le suivi"
}, },
"user_profile": { "user_profile": {
"timeline_title": "Flux du compte", "timeline_title": "Flux du compte",
@ -857,7 +980,10 @@
"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" "bookmark": "Favori",
"autocomplete_available": "{number} résultat est disponible. Utilisez les touches haut et bas pour naviguer à l'intérieur. | {number} résultats sont disponibles. Utilisez les touches haut et bas pour naviguer à l'intérieur.",
"toggle_expand": "Développer ou réduire la notification pour afficher le message dans son intégralité",
"toggle_mute": "Développer ou réduire la notification pour révéler le contenu en sourdine"
}, },
"upload": { "upload": {
"error": { "error": {
@ -950,7 +1076,9 @@
"symbols": "Symboles", "symbols": "Symboles",
"travel-and-places": "Voyages & lieux" "travel-and-places": "Voyages & lieux"
}, },
"regional_indicator": "Indicateur régional {letter}" "regional_indicator": "Indicateur régional {letter}",
"unpacked": "Émojis non catégorisés",
"hide_custom_emoji": "Masquer les émojis personnalisés"
}, },
"remote_user_resolver": { "remote_user_resolver": {
"error": "Non trouvé.", "error": "Non trouvé.",
@ -1012,7 +1140,7 @@
"person_talking": "{count} personnes discutant", "person_talking": "{count} personnes discutant",
"hashtags": "Mot-dièses", "hashtags": "Mot-dièses",
"people_talking": "{count} personnes discutant", "people_talking": "{count} personnes discutant",
"no_results": "Aucun résultats", "no_results": "Aucun résultat",
"no_more_results": "Pas de résultats supplémentaires", "no_more_results": "Pas de résultats supplémentaires",
"load_more": "Charger plus de résultats" "load_more": "Charger plus de résultats"
}, },
@ -1083,7 +1211,8 @@
"update_changelog_here": "Liste compète des changements", "update_changelog_here": "Liste compète des changements",
"art_by": "Œuvre par {linkToArtist}", "art_by": "Œuvre par {linkToArtist}",
"big_update_content": "Nous n'avons pas fait de nouvelle version depuis un moment, les choses peuvent vous paraitre différentes de vos habitudes.", "big_update_content": "Nous n'avons pas fait de nouvelle version depuis un moment, les choses peuvent vous paraitre différentes de vos habitudes.",
"update_bugs": "Veuillez rapporter les problèmes sur {pleromaGitlab}, comme beaucoup de changements on été fait, même si nous testons entièrement et utilisons la version de dévelopement nous-même, nous avons pu en louper. Les retours et suggestions sont bienvenues sur ce que vous avez pu rencontrer, ou sur comment améliorer Pleroma (BE) et Pleroma-FE." "update_bugs": "Veuillez rapporter les problèmes sur {pleromaGitlab}, comme beaucoup de changements on été fait, même si nous testons entièrement et utilisons la version de dévelopement nous-même, nous avons pu en louper. Les retours et suggestions sont bienvenues sur ce que vous avez pu rencontrer, ou sur comment améliorer Pleroma (BE) et Pleroma-FE.",
"big_update_title": "Soyez indulgent avec nous"
}, },
"unicode_domain_indicator": { "unicode_domain_indicator": {
"tooltip": "Ce domaine contient des caractères non ascii." "tooltip": "Ce domaine contient des caractères non ascii."
@ -1097,5 +1226,158 @@
"state_open": "Ouvert", "state_open": "Ouvert",
"state_closed": "Fermé", "state_closed": "Fermé",
"state_resolved": "Résolut" "state_resolved": "Résolut"
},
"announcements": {
"page_header": "Annonces",
"title": "Annonce",
"mark_as_read_action": "Marquer comme lu",
"post_form_header": "Faire une annonce",
"post_placeholder": "Écrivez le contenu de l'annonce ici...",
"post_action": "Envoyer",
"post_error": "Erreur : {error}",
"close_error": "Fermer",
"delete_action": "Supprimer",
"start_time_prompt": "Heure de début : ",
"end_time_prompt": "Heure de fin : ",
"all_day_prompt": "L'événement dure toute la journée",
"inactive_message": "Cette annonce n'est pas active",
"published_time_display": "Publié le {time}",
"start_time_display": "Démarre à {time}",
"end_time_display": "Se termine à {time}",
"edit_action": "Modifier",
"submit_edit_action": "Envoyer",
"cancel_edit_action": "Annuler"
},
"admin_dash": {
"frontend": {
"success_installing_frontend": "Installation réussie de l'interface {version}",
"failure_installing_frontend": "Échec de l'installation de l'interface {version} : {reason}",
"default_frontend_unavail": "Les paramètres de l'interface ne sont pas disponibles, ils doivent être configurés dans la base de données",
"build_url": "Construction URL",
"reinstall": "Réinstaller",
"repository": "Lien du dépôt",
"versions": "Versions disponibles",
"default_frontend_tip": "L'interface par défaut sera affichée à tous les utilisateurs. Si vous décidez de quitter PleromaFE, vous devrez utiliser l'ancienne AdminFE buguée pour configurer votre instance jusqu'à ce que nous la remplacions.",
"is_default": "(Défaut)",
"is_default_custom": "(Défaut, version : {version})",
"install": "Installation",
"install_version": "Installation de la version {version}",
"more_install_options": "Plus d'options d'installation",
"more_default_options": "Plus d'options de paramétrages par défaut",
"set_default": "Définir la valeur par défaut",
"set_default_version": "Définir la version {version} comme version par défaut",
"wip_notice": "Veuillez noter que cette section est en cours de développement et que certaines fonctionnalités de l'interface ne sont pas implémentées côté serveur.",
"default_frontend": "Interface par défaut",
"available_frontends": "Disponible pour installation"
},
"temp_overrides": {
":pleroma": {
":instance": {
":public": {
"label": "Cette instance est publique",
"description": "En désactivant cette option, toutes les API ne seront accessibles qu'aux utilisateurs connectés, ce qui rendra les chronologies publiques et fédérées inaccessibles aux visiteurs anonymes."
},
":limit_to_local_content": {
"label": "Limitez la recherche au contenu local",
"description": "Désactive la recherche globale sur le réseau pour les utilisateurs non authentifiés (par défaut), tous les utilisateurs ou aucun"
},
":description_limit": {
"label": "Limite",
"description": "Limite de nombre de caractères pour la description des fichiers joints"
},
":background_image": {
"description": "Image de fond (principalement utilisé par PleromaFE)",
"label": "Image de fond d'écran"
}
}
}
},
"tabs": {
"emoji": "Émoji",
"limits": "Limites",
"frontends": "Interfaces",
"instance": "Instance",
"nodb": "Pas de configuration de base de données"
},
"instance": {
"kocaptcha": "Réglages KoCaptcha",
"access": "Accès à l'instance",
"restrict": {
"header": "Restreindre l'accès aux visiteurs anonymes",
"profiles": "Accès aux profils d'utilisateur",
"activities": "Accès aux status/activités",
"description": "Paramètre détaillé permettant d'autoriser/interdire l'accès à certains aspects de l'API. Par défaut (état indéterminé), l'accès est interdit si l'instance n'est pas publique ; si la case est cochée, l'accès est interdit même si l'instance est publique ; si la case n'est pas cochée, l'accès est autorisé même si l'instance est privée. Veuillez noter qu'un comportement inattendu peut se produire si certains paramètres sont définis, par exemple si l'accès au profil est désactivé, les messages s'afficheront sans les informations relatives au profil.",
"timelines": "Accès aux flux"
},
"registrations": "Inscription des utilisateurs",
"captcha_header": "CAPTCHA",
"instance": "Informations sur l'instance"
},
"emoji": {
"global_actions": "Actions globales",
"reload": "Recharger les émojis",
"importFS": "Importer les émojis depuis le système de fichiers",
"error": "Erreur : {0}",
"create_pack": "Créer un pack",
"delete_pack": "Supprimer un paquet",
"new_pack_name": "Renommer le pack",
"create": "Créer",
"emoji_packs": "Pack d'émojis",
"remote_packs": "Packs d'autres instances",
"do_list": "Liste",
"remote_pack_instance": "Instance du pack",
"emoji_pack": "Pack d'émoji",
"edit_pack": "Modifier le pack",
"description": "Description",
"homepage": "Page d'accueil",
"fallback_src": "Source de remplacement",
"fallback_sha256": "Remplacement SHA256",
"share": "Partager",
"save": "Sauvegarder",
"save_meta": "Sauvegarder les métadonnées",
"revert_meta": "Annuler métadonnées",
"delete": "Supprimer",
"revert": "Revenir en arrière",
"add_file": "Ajouter un fichier",
"adding_new": "Ajouter un nouvel émoji",
"shortcode": "Shortcode",
"filename": "Nom du fichier",
"new_filename": "Nom de fichier, laisser blanc pour inférer",
"delete_confirm": "Êtes-vous sûr de vouloir supprimer {0} ?",
"download_pack": "Télécharger pack",
"downloading_pack": "Télécharge {0}",
"download": "Téléchargement",
"download_as_name": "Nouveau nom",
"download_as_name_full": "Nouveau nom, laissez blanc pour réutiliser le précédent",
"files": "Fichiers",
"editing": "Édition de {0}",
"delete_title": "Supprimer ?",
"metadata_changed": "Métadonnées différentes de celles sauvegardées",
"emoji_changed": "Modifications du fichier émoji non sauvegardées, vérifier l'émoji surligné",
"replace_warning": "Vous allez REMPLACER le pack local qui porte ce nom"
},
"window_title": "Administration",
"nodb": {
"heading": "La configuration de base de données est désactivée",
"documentation": "documentation",
"text2": "La majorité des options de configuration ne seront pas disponibles.",
"text": "Vous devez modifier les fichiers de configuration du serveur pour que {property} soit définie à {value}, plus de détails dans la {documentation}."
},
"limits": {
"arbitrary_limits": "Limites arbitraires",
"posts": "Limites des statuts",
"uploads": "Limites des pièces jointes",
"users": "Limites du profil d'utilisateur",
"profile_fields": "Limites des champs du profile",
"user_uploads": "Limites des médias du profil"
},
"captcha": {
"native": "Natif",
"kocaptcha": "KoCaptcha"
},
"wip_notice": "Ce tableau de bord d'administration est expérimental et en cours de développement, {adminFeLink}.",
"old_ui_link": "L'ancien espace d'administration est disponible ici",
"reset_all": "Tout réinitialiser",
"commit_all": "Tout sauvegarder"
} }
} }

View File

@ -1243,7 +1243,8 @@
"tabs": { "tabs": {
"limits": "制限", "limits": "制限",
"instance": "インスタンス", "instance": "インスタンス",
"frontends": "フロントエンド" "frontends": "フロントエンド",
"emoji": "絵文字"
}, },
"limits": { "limits": {
"arbitrary_limits": "変更可能な制限", "arbitrary_limits": "変更可能な制限",
@ -1252,6 +1253,27 @@
"profile_fields": "追加情報欄の制限", "profile_fields": "追加情報欄の制限",
"user_uploads": "プロフィール画像の制限", "user_uploads": "プロフィール画像の制限",
"users": "ユーザープロフィールの設定" "users": "ユーザープロフィールの設定"
},
"emoji": {
"create_pack": "パックを作成",
"delete_pack": "パックを削除",
"create": "作成",
"emoji_packs": "絵文字パック",
"remote_packs": "リモートのパック",
"emoji_pack": "絵文字パック",
"edit_pack": "パックを編集",
"homepage": "ホームページ",
"save": "保存",
"save_meta": "メタデータを保存",
"shortcode": "ショートコード",
"filename": "ファイル名",
"delete_confirm": "{0}を削除してもよろしいですか?",
"download_pack": "パックをダウンロード",
"downloading_pack": "{0}をダウンロード中",
"download": "ダウンロード",
"editing": "{0}を編集中",
"error": "エラー: {0}",
"delete": "削除"
} }
}, },
"lists": { "lists": {

View File

@ -11,7 +11,8 @@
"title": "Características", "title": "Características",
"who_to_follow": "Quem seguir", "who_to_follow": "Quem seguir",
"upload_limit": "Limite de carregamento", "upload_limit": "Limite de carregamento",
"pleroma_chat_messages": "Chat do Pleroma" "pleroma_chat_messages": "Chat do Pleroma",
"shout": "Shoutbox"
}, },
"finder": { "finder": {
"error_fetching_user": "Erro ao pesquisar utilizador", "error_fetching_user": "Erro ao pesquisar utilizador",
@ -36,11 +37,27 @@
"error_retry": "Por favor, tenta novamente", "error_retry": "Por favor, tenta novamente",
"loading": "A carregar…", "loading": "A carregar…",
"dismiss": "Ignorar", "dismiss": "Ignorar",
"role": "role": {
{
"moderator": "Moderador", "moderator": "Moderador",
"admin": "Admin" "admin": "Admin"
} },
"undo": "Refazer",
"yes": "Sim",
"no": "Não",
"unpin": "Desafixar o item",
"scroll_to_top": "Rolar para o topo",
"flash_content": "Clique para mostrar conteúdo Flash usando o Ruffle (Experimental, talvez não funcione).",
"flash_security": "Note que isso pode ser potencialmente perigoso dado que o conteúdo Flash ainda é código arbitrário.",
"flash_fail": "Falha ao carregar conteúdo flash, veja o console para detalhes.",
"scope_in_timeline": {
"direct": "Direct",
"private": "Apenas-seguidores",
"public": "Público",
"unlisted": "Não-listado"
},
"pin": "Fixar o item",
"generic_error_message": "Um erro ocorreu: {0}",
"never_show_again": "Não mostrar mais"
}, },
"image_cropper": { "image_cropper": {
"crop_picture": "Cortar imagem", "crop_picture": "Cortar imagem",
@ -64,11 +81,17 @@
"recovery_code": "Código de recuperação", "recovery_code": "Código de recuperação",
"authentication_code": "Código de autenticação", "authentication_code": "Código de autenticação",
"enter_two_factor_code": "Introduza o código de dois fatores", "enter_two_factor_code": "Introduza o código de dois fatores",
"enter_recovery_code": "Introduza um código de recuperação" "enter_recovery_code": "Introduza um código de recuperação",
"logout_confirm_title": "Confirmação de logoff",
"logout_confirm": "Você realmente quer sair?",
"logout_confirm_accept_button": "Sair",
"logout_confirm_cancel_button": "Não sair"
}, },
"media_modal": { "media_modal": {
"previous": "Anterior", "previous": "Anterior",
"next": "Próximo" "next": "Próximo",
"counter": "{current} / {total}",
"hide": "Fechar visualizador de mídia"
}, },
"nav": { "nav": {
"about": "Sobre", "about": "Sobre",
@ -88,7 +111,18 @@
"administration": "Administração", "administration": "Administração",
"chats": "Salas de Chat", "chats": "Salas de Chat",
"timelines": "Cronologias", "timelines": "Cronologias",
"bookmarks": "Itens Guardados" "bookmarks": "Itens Guardados",
"home_timeline": "Timeline da home",
"lists": "Listas",
"edit_pinned": "Editar itens fixados",
"edit_nav_mobile": "Customizar barra de navegação",
"mobile_notifications_mark_as_seen": "Marcar todas como vistas",
"search_close": "Fechar barra de busca",
"mobile_notifications_close": "Fechar notificações",
"announcements": "Anúncios",
"edit_finish": "Edição finalizada",
"mobile_sidebar": "Alternar barra lateral móvel",
"mobile_notifications": "Abrir notificações (há notificações não lidas)"
}, },
"notifications": { "notifications": {
"broken_favorite": "Publicação desconhecida, a procurar…", "broken_favorite": "Publicação desconhecida, a procurar…",
@ -102,7 +136,15 @@
"reacted_with": "reagiu com {0}", "reacted_with": "reagiu com {0}",
"migrated_to": "migrou para", "migrated_to": "migrou para",
"follow_request": "quer seguir-te", "follow_request": "quer seguir-te",
"error": "Erro ao obter notificações: {0}" "error": "Erro ao obter notificações: {0}",
"unread_announcements": "{num} anúncio não lido | {num} anúncios não lidos",
"unread_chats": "{num} mensagem não lida | {num} mensagens não lidas",
"configuration_tip": "Você pode customizar o que você deseja mostrar aqui em {theSettings}. {dismiss}",
"unread_follow_requests": "{num} novo pedido de seguidor | {num} novos pedidos de seguidores",
"configuration_tip_settings": "as configurações",
"configuration_tip_dismiss": "Não mostrar novamente",
"poll_ended": "enquete finalizada",
"submitted_report": "enviado um relatório"
}, },
"post_status": { "post_status": {
"new_status": "Publicar nova publicação", "new_status": "Publicar nova publicação",
@ -136,7 +178,14 @@
"media_description": "Descrição da multimédia", "media_description": "Descrição da multimédia",
"media_description_error": "Falha ao atualizar ficheiro, tente novamente", "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_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." "direct_warning_to_all": "Esta publicação será visível para todos os utilizadores mencionados.",
"edit_status": "Editar status",
"reply_option": "Responder a esse status",
"quote_option": "Citar esse status",
"edit_remote_warning": "Outras instâncias remotas talvez não suportem edição e sejam incapazes de receber a última versão do seu post.",
"content_type_selection": "Formato do post",
"scope_notice_dismiss": "Fechar essa notificação",
"edit_unsupported_warning": "Pleroma não suporta editar menções ou enquetes."
}, },
"registration": { "registration": {
"bio": "Biografia", "bio": "Biografia",
@ -156,8 +205,18 @@
"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 corresponder à palavra-passe" "password_confirmation_match": "deve corresponder à palavra-passe",
} "birthday_required": "não pode ser deixado em branco",
"birthday_min_age": "deve ser em ou antes de {date}"
},
"birthday": "Data de nascimento:",
"reason": "Razão para registrar",
"register": "Registrar",
"reason_placeholder": "Essa instância aprova os registros manualmente.\nPermita ao administrador saber o porquê do seu registro.",
"birthday_optional": "Data de nascimento (opcional):",
"bio_optional": "Bio (opcional)",
"email_optional": "Email (opcional)",
"email_language": "Em qual linguagem você deseja receber emails do servidor?"
}, },
"settings": { "settings": {
"app_name": "Nome da aplicação", "app_name": "Nome da aplicação",
@ -523,7 +582,56 @@
"autohide_floating_post_button": "Automaticamente ocultar o botão 'Nova Publicação' (telemóvel)", "autohide_floating_post_button": "Automaticamente ocultar o botão 'Nova Publicação' (telemóvel)",
"notification_visibility_moves": "Utilizador Migrado", "notification_visibility_moves": "Utilizador Migrado",
"accent": "Destaque", "accent": "Destaque",
"pad_emoji": "Preencher espaços ao adicionar emojis do seletor" "pad_emoji": "Preencher espaços ao adicionar emojis do seletor",
"confirm_dialogs_logout": "saindo",
"move_account_error": "Erro ao mover conta: {error}",
"confirm_dialogs_delete": "excluindo um status",
"save": "Salvar mudanças",
"lists_navigation": "Mostrar listas na navegação",
"email_language": "Linguagem para receber emails do servidor",
"account_backup_description": "Isso permite a você baixar um arquivo das informações da sua conta e os seus posts, mas eles ainda não podem ser importados para uma conta do Pleroma.",
"add_backup_error": "Erro ao adicionar um novo backup: {error}",
"confirm_dialogs": "Pedir por confirmação quando",
"confirm_dialogs_repeat": "repetindo um status",
"account_alias": "Apelidos de conta",
"account_alias_table_head": "Apelido",
"list_aliases_error": "Erro ao buscar por apelidos: {error}",
"hide_list_aliases_error_action": "Fechar",
"confirm_dialogs_deny_follow": "negando um seguidor",
"confirm_dialogs_approve_follow": "aprovando um seguidor",
"backup_running": "Esse backup está em andamento, {number} registro processado. | Esse backup está em progresso, {number} registros processados.",
"add_backup": "Criar um novo backup",
"added_backup": "Adicionado um novo backup.",
"backup_failed": "Esse backup falhou.",
"list_backups_error": "Erro ao buscar a lista de backup: {error}",
"move_account_notes": "Se você deseja mover a conta para outro lugar, você deve ir para sua conta de destino e adicionar um apelido apontando para cá.",
"add_alias_error": "Erro ao adicionar apelido: {error}",
"move_account": "Mover conta",
"actor_type": "Essa conta é:",
"actor_type_description": "Marcando a sua conta como um grupo irá fazer com que ela automaticamente repita os status que a mencionam.",
"actor_type_Person": "um usuário normal",
"actor_type_Service": "um bot",
"actor_type_Group": "um grupo",
"account_backup": "Backup da conta",
"confirm_dialogs_unfollow": "deixando de seguir usuário",
"confirm_dialogs_block": "bloqueando um usuário",
"confirm_dialogs_remove_follower": "removendo um seguidor",
"remove_alias": "Remover esse apelido",
"new_alias_target": "Adicionar um novo apelido (e.g. {example})",
"added_alias": "Apelido adicionado.",
"move_account_target": "Conta de destino (e.g. {example})",
"moved_account": "Conta movida.",
"remove_language": "Remover",
"primary_language": "Linguagem primária:",
"fallback_language": "Linguagem de reserva {index}:",
"add_language": "Adicionar linguagem de reserva",
"expert_mode": "Mostrar avançados",
"setting_changed": "As configurações são diferentes do padrão",
"setting_server_side": "Essas configurações estão atreladas ao seu perfil e afetarão todas as sessões e clientes",
"mention_links": "Links de menção",
"confirm_dialogs_mute": "mutando um usuário",
"backup_not_ready": "Esse backup não está pronto ainda.",
"remove_backup": "Remover"
}, },
"timeline": { "timeline": {
"collapse": "Esconder", "collapse": "Esconder",
@ -699,7 +807,20 @@
"load_all": "A carregar todos os {emojiAmount} emojis", "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.", "load_all_hint": "Carregado o primeiro emoji {saneAmount}, carregar todos os emojis pode causar problemas de desempenho.",
"keep_open": "Manter o seletor aberto", "keep_open": "Manter o seletor aberto",
"stickers": "Autocolantes" "stickers": "Autocolantes",
"hide_custom_emoji": "Ocultar emojis customizados",
"unicode_groups": {
"symbols": "Símbolos",
"activities": "Atividades",
"animals-and-nature": "Animais & Natureza",
"people-and-body": "Pessoas & Corpo",
"smileys-and-emotion": "Sorriso & Emoção",
"travel-and-places": "Viagem & Lugares",
"food-and-drink": "Comida & Bebidas",
"objects": "Objetos"
},
"regional_indicator": "Indicador regional {letter}",
"unpacked": "Emoji desempacotado"
}, },
"polls": { "polls": {
"single_choice": "Escolha única", "single_choice": "Escolha única",
@ -713,7 +834,9 @@
"expiry": "Tempo para finalizar sondagem", "expiry": "Tempo para finalizar sondagem",
"multiple_choices": "Escolha múltipla", "multiple_choices": "Escolha múltipla",
"type": "Tipo de sondagem", "type": "Tipo de sondagem",
"add_poll": "Adicionar Sondagem" "add_poll": "Adicionar Sondagem",
"votes_count": "{count} voto | {count} votos",
"people_voted_count": "{count} pessoa votou | {count} pessoas votaram"
}, },
"importer": { "importer": {
"error": "Ocorreu um erro ao importar este ficheiro.", "error": "Ocorreu um erro ao importar este ficheiro.",
@ -737,7 +860,9 @@
"load_older": "Carregar interações mais antigas", "load_older": "Carregar interações mais antigas",
"follows": "Novos seguidores", "follows": "Novos seguidores",
"favs_repeats": "Gostos e Partilhas", "favs_repeats": "Gostos e Partilhas",
"moves": "O utilizador migra" "moves": "O utilizador migra",
"emoji_reactions": "Reações de Emoji",
"reports": "Relatórios"
}, },
"errors": { "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." "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."
@ -828,5 +953,35 @@
"day_short": "{0}d", "day_short": "{0}d",
"days": "{0} dias", "days": "{0} dias",
"day": "{0} dia" "day": "{0} dia"
},
"report": {
"state_closed": "Fechar",
"reported_statuses": "Estado das denúncias:",
"reported_user": "Usuário denunciado:",
"state_resolved": "Resolvido",
"state": "Estado:",
"state_open": "Abrir",
"notes": "Notas:"
},
"announcements": {
"start_time_display": "Inicia às {time}",
"post_form_header": "Enviar anúncio",
"post_placeholder": "Digite o conteúdo do seu anúncio aqui...",
"page_header": "Anúncios",
"title": "Anúncio",
"mark_as_read_action": "Marcar como lido",
"post_action": "Postar",
"post_error": "Erro: {error}",
"close_error": "Fechar",
"delete_action": "Apagar",
"start_time_prompt": "Tempo de início: ",
"end_time_prompt": "Tempo de término: ",
"all_day_prompt": "Esse é um evento para o dia todo",
"published_time_display": "Publicado às {time}",
"end_time_display": "Finaliza às {time}",
"edit_action": "Editar",
"submit_edit_action": "Enviar",
"cancel_edit_action": "Cancelar",
"inactive_message": "Esse anúncio está inativo"
} }
} }

View File

@ -202,12 +202,13 @@ const api = {
timeline = 'friends', timeline = 'friends',
tag = false, tag = false,
userId = false, userId = false,
listId = false listId = false,
statusId = false
}) { }) {
if (store.state.fetchers[timeline]) return if (store.state.fetchers[timeline]) return
const fetcher = store.state.backendInteractor.startFetchingTimeline({ const fetcher = store.state.backendInteractor.startFetchingTimeline({
timeline, store, userId, listId, tag timeline, store, userId, listId, statusId, tag
}) })
store.commit('addFetcher', { fetcherName: timeline, fetcher }) store.commit('addFetcher', { fetcherName: timeline, fetcher })
}, },

View File

@ -28,6 +28,7 @@ export const defaultState = {
theme: undefined, theme: undefined,
customTheme: undefined, customTheme: undefined,
customThemeSource: undefined, customThemeSource: undefined,
forceThemeRecompilation: false,
hideISP: false, hideISP: false,
hideInstanceWallpaper: false, hideInstanceWallpaper: false,
hideShoutbox: false, hideShoutbox: false,
@ -36,11 +37,13 @@ export const defaultState = {
hideMutedThreads: undefined, // instance default hideMutedThreads: undefined, // instance default
hideWordFilteredPosts: undefined, // instance default hideWordFilteredPosts: undefined, // instance default
muteBotStatuses: undefined, // instance default muteBotStatuses: undefined, // instance default
muteSensitiveStatuses: undefined, // instance default
collapseMessageWithSubject: undefined, // instance default collapseMessageWithSubject: undefined, // instance default
padEmoji: true, padEmoji: true,
hideAttachments: false, hideAttachments: false,
hideAttachmentsInConv: false, hideAttachmentsInConv: false,
hideScrobbles: false, hideScrobbles: false,
hideScrobblesAfter: '2d',
maxThumbnails: 16, maxThumbnails: 16,
hideNsfw: true, hideNsfw: true,
preloadImage: true, preloadImage: true,

View File

@ -71,6 +71,7 @@ const defaultState = {
hideSitename: false, hideSitename: false,
hideUserStats: false, hideUserStats: false,
muteBotStatuses: false, muteBotStatuses: false,
muteSensitiveStatuses: false,
modalOnRepeat: false, modalOnRepeat: false,
modalOnUnfollow: false, modalOnUnfollow: false,
modalOnBlock: true, modalOnBlock: true,
@ -377,7 +378,8 @@ const instance = {
commit('setInstanceOption', { name: 'themeData', value: themeData }) commit('setInstanceOption', { name: 'themeData', value: themeData })
// No need to apply theme if there's user theme already // No need to apply theme if there's user theme already
const { customTheme } = rootState.config const { customTheme } = rootState.config
if (customTheme) return const { themeApplied } = rootState.interface
if (customTheme || themeApplied) return
// New theme presets don't have 'theme' property, they use 'source' // New theme presets don't have 'theme' property, they use 'source'
const themeSource = themeData.source const themeSource = themeData.source
@ -386,6 +388,7 @@ const instance = {
} else { } else {
applyTheme(themeData.theme) applyTheme(themeData.theme)
} }
commit('setThemeApplied')
}) })
}, },
fetchEmoji ({ dispatch, state }) { fetchEmoji ({ dispatch, state }) {

View File

@ -1,4 +1,5 @@
const defaultState = { const defaultState = {
themeApplied: false,
settingsModalState: 'hidden', settingsModalState: 'hidden',
settingsModalLoadedUser: false, settingsModalLoadedUser: false,
settingsModalLoadedAdmin: false, settingsModalLoadedAdmin: false,
@ -35,6 +36,9 @@ const interfaceMod = {
state.settings.currentSaveStateNotice = { error: true, errorData: error } state.settings.currentSaveStateNotice = { error: true, errorData: error }
} }
}, },
setThemeApplied (state) {
state.themeApplied = true
},
setNotificationPermission (state, permission) { setNotificationPermission (state, permission) {
state.notificationPermission = permission state.notificationPermission = permission
}, },

View File

@ -108,6 +108,7 @@ const PLEROMA_POST_ANNOUNCEMENT_URL = '/api/v1/pleroma/admin/announcements'
const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}` const PLEROMA_EDIT_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}` const PLEROMA_DELETE_ANNOUNCEMENT_URL = id => `/api/v1/pleroma/admin/announcements/${id}`
const PLEROMA_SCROBBLES_URL = id => `/api/v1/pleroma/accounts/${id}/scrobbles` const PLEROMA_SCROBBLES_URL = id => `/api/v1/pleroma/accounts/${id}/scrobbles`
const PLEROMA_STATUS_QUOTES_URL = id => `/api/v1/pleroma/statuses/${id}/quotes`
const PLEROMA_USER_FAVORITES_TIMELINE_URL = id => `/api/v1/pleroma/accounts/${id}/favourites` const PLEROMA_USER_FAVORITES_TIMELINE_URL = id => `/api/v1/pleroma/accounts/${id}/favourites`
const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config' const PLEROMA_ADMIN_CONFIG_URL = '/api/pleroma/admin/config'
@ -685,6 +686,7 @@ const fetchTimeline = ({
until = false, until = false,
userId = false, userId = false,
listId = false, listId = false,
statusId = false,
tag = false, tag = false,
withMuted = false, withMuted = false,
replyVisibility = 'all', replyVisibility = 'all',
@ -702,7 +704,8 @@ const fetchTimeline = ({
favorites: MASTODON_USER_FAVORITES_TIMELINE_URL, favorites: MASTODON_USER_FAVORITES_TIMELINE_URL,
publicFavorites: PLEROMA_USER_FAVORITES_TIMELINE_URL, publicFavorites: PLEROMA_USER_FAVORITES_TIMELINE_URL,
tag: MASTODON_TAG_TIMELINE_URL, tag: MASTODON_TAG_TIMELINE_URL,
bookmarks: MASTODON_BOOKMARK_TIMELINE_URL bookmarks: MASTODON_BOOKMARK_TIMELINE_URL,
quotes: PLEROMA_STATUS_QUOTES_URL
} }
const isNotifications = timeline === 'notifications' const isNotifications = timeline === 'notifications'
const params = [] const params = []
@ -721,6 +724,10 @@ const fetchTimeline = ({
url = url(listId) url = url(listId)
} }
if (timeline === 'quotes') {
url = url(statusId)
}
if (minId) { if (minId) {
params.push(['min_id', minId]) params.push(['min_id', minId])
} }

View File

@ -5,8 +5,8 @@ import followRequestFetcher from '../../services/follow_request_fetcher/follow_r
import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js' import listsFetcher from '../../services/lists_fetcher/lists_fetcher.service.js'
const backendInteractorService = credentials => ({ const backendInteractorService = credentials => ({
startFetchingTimeline ({ timeline, store, userId = false, listId = false, tag }) { startFetchingTimeline ({ timeline, store, userId = false, listId = false, statusId = false, tag }) {
return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, tag }) return timelineFetcher.startFetching({ timeline, store, credentials, userId, listId, statusId, tag })
}, },
fetchTimeline (args) { fetchTimeline (args) {

View File

@ -331,6 +331,7 @@ export const parseStatus = (data) => {
output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined) output.quote_id = pleroma.quote_id ? pleroma.quote_id : (output.quote ? output.quote.id : undefined)
output.quote_url = pleroma.quote_url output.quote_url = pleroma.quote_url
output.quote_visible = pleroma.quote_visible output.quote_visible = pleroma.quote_visible
output.quotes_count = pleroma.quotes_count
} else { } else {
output.text = data.content output.text = data.content
output.summary = data.spoiler_text output.summary = data.spoiler_text

View File

@ -8,8 +8,11 @@ const mastoApiNotificationTypes = [
'favourite', 'favourite',
'reblog', 'reblog',
'follow', 'follow',
'follow_request',
'move', 'move',
'poll',
'pleroma:emoji_reaction', 'pleroma:emoji_reaction',
'pleroma:chat_mention',
'pleroma:report' 'pleroma:report'
] ]

View File

@ -1,12 +1,18 @@
import { hex2rgb } from '../color_convert/color_convert.js' import { hex2rgb } from '../color_convert/color_convert.js'
import { generatePreset } from '../theme_data/theme_data.service.js' import { generatePreset } from '../theme_data/theme_data.service.js'
import { init } from '../theme_data/theme_data_3.service.js' import { init, getEngineChecksum } from '../theme_data/theme_data_3.service.js'
import { convertTheme2To3 } from '../theme_data/theme2_to_theme3.js' import { convertTheme2To3 } from '../theme_data/theme2_to_theme3.js'
import { getCssRules } from '../theme_data/css_utils.js' import { getCssRules } from '../theme_data/css_utils.js'
import { defaultState } from '../../modules/config.js' import { defaultState } from '../../modules/config.js'
import { chunk } from 'lodash' import { chunk } from 'lodash'
export const applyTheme = async (input) => { export const generateTheme = async (input, callbacks) => {
const {
onNewRule = (rule, isLazy) => {},
onLazyFinished = () => {},
onEagerFinished = () => {}
} = callbacks
let extraRules let extraRules
if (input.themeFileVersion === 1) { if (input.themeFileVersion === 1) {
extraRules = convertTheme2To3(input) extraRules = convertTheme2To3(input)
@ -17,11 +23,6 @@ export const applyTheme = async (input) => {
// Assuming that "worst case scenario background" is panel background since it's the most likely one // Assuming that "worst case scenario background" is panel background since it's the most likely one
const themes3 = init(extraRules, extraRules[0].directives['--bg'].split('|')[1].trim()) const themes3 = init(extraRules, extraRules[0].directives['--bg'].split('|')[1].trim())
const body = document.body
const styleSheet = new CSSStyleSheet()
document.adoptedStyleSheets = [styleSheet]
body.classList.add('hidden')
getCssRules(themes3.eager, themes3.staticVars).forEach(rule => { getCssRules(themes3.eager, themes3.staticVars).forEach(rule => {
// Hacks to support multiple selectors on same component // Hacks to support multiple selectors on same component
@ -37,13 +38,12 @@ export const applyTheme = async (input) => {
parts[1], parts[1],
'}' '}'
].join('') ].join('')
styleSheet.insertRule(newRule, 'index-max') onNewRule(newRule, false)
} else { } else {
styleSheet.insertRule(rule, 'index-max') onNewRule(rule, false)
} }
}) })
onEagerFinished()
body.classList.remove('hidden')
// Optimization - instead of processing all lazy rules in one go, process them in small chunks // Optimization - instead of processing all lazy rules in one go, process them in small chunks
// so that UI can do other things and be somewhat responsive while less important rules are being // so that UI can do other things and be somewhat responsive while less important rules are being
@ -61,13 +61,15 @@ export const applyTheme = async (input) => {
parts[0], parts[0],
', ', ', ',
parts[0].replace(/\.modal-view/, '#modal'), parts[0].replace(/\.modal-view/, '#modal'),
', ',
parts[0].replace(/\.modal-view/, '.shout-panel'),
' {', ' {',
parts[1], parts[1],
'}' '}'
].join('') ].join('')
styleSheet.insertRule(newRule, 'index-max') onNewRule(newRule, true)
} else { } else {
styleSheet.insertRule(rule, 'index-max') onNewRule(rule, true)
} }
}) })
// const t1 = performance.now() // const t1 = performance.now()
@ -76,10 +78,72 @@ export const applyTheme = async (input) => {
counter += 1 counter += 1
if (counter < chunks.length) { if (counter < chunks.length) {
setTimeout(processChunk, 0) setTimeout(processChunk, 0)
} else {
onLazyFinished()
} }
}) })
} }
setTimeout(processChunk, 0)
return { lazyProcessFunc: processChunk }
}
export const tryLoadCache = () => {
const json = localStorage.getItem('pleroma-fe-theme-cache')
if (!json) return null
let cache
try {
cache = JSON.parse(json)
} catch (e) {
console.error('Failed to decode theme cache:', e)
return false
}
if (cache.engineChecksum === getEngineChecksum()) {
const styleSheet = new CSSStyleSheet()
const lazyStyleSheet = new CSSStyleSheet()
cache.data[0].forEach(rule => styleSheet.insertRule(rule, 'index-max'))
cache.data[1].forEach(rule => lazyStyleSheet.insertRule(rule, 'index-max'))
document.adoptedStyleSheets = [styleSheet, lazyStyleSheet]
return true
} else {
console.warn('Engine checksum doesn\'t match, cache not usable, clearing')
localStorage.removeItem('pleroma-fe-theme-cache')
}
}
export const applyTheme = async (input, onFinish = (data) => {}) => {
const styleSheet = new CSSStyleSheet()
const styleArray = []
const lazyStyleSheet = new CSSStyleSheet()
const lazyStyleArray = []
const { lazyProcessFunc } = await generateTheme(
input,
{
onNewRule (rule, isLazy) {
if (isLazy) {
lazyStyleSheet.insertRule(rule, 'index-max')
lazyStyleArray.push(rule)
} else {
styleSheet.insertRule(rule, 'index-max')
styleArray.push(rule)
}
},
onEagerFinished () {
document.adoptedStyleSheets = [styleSheet]
},
onLazyFinished () {
document.adoptedStyleSheets = [styleSheet, lazyStyleSheet]
const cache = { engineChecksum: getEngineChecksum(), data: [styleArray, lazyStyleArray] }
onFinish(cache)
localStorage.setItem('pleroma-fe-theme-cache', JSON.stringify(cache))
}
}
)
setTimeout(lazyProcessFunc, 0)
return Promise.resolve() return Promise.resolve()
} }

View File

@ -158,12 +158,12 @@ export default [
'alertPopupNeutral', 'alertPopupNeutral',
'alertPopupNeutralText', 'alertPopupNeutralText',
'badgeNotification',
'badgeNotificationText',
'badgeNeutral', 'badgeNeutral',
'badgeNeutralText', 'badgeNeutralText',
'badgeNotification',
'badgeNotificationText',
'chatBg', 'chatBg',
'chatMessageIncomingBg', 'chatMessageIncomingBg',

View File

@ -517,6 +517,8 @@ export const convertTheme2To3 = (data) => {
} else if (newRule.component === 'Badge') { } else if (newRule.component === 'Badge') {
if (newRule.variant === 'notification') { if (newRule.variant === 'notification') {
return [newRule, { component: 'Root', directives: { '--badgeNotification': 'color | ' + newRule.directives.background } }] return [newRule, { component: 'Root', directives: { '--badgeNotification': 'color | ' + newRule.directives.background } }]
} else if (newRule.variant === 'neutral') {
return [{ ...newRule, variant: 'normal' }]
} else { } else {
return [newRule] return [newRule]
} }

View File

@ -1,4 +1,5 @@
import { convert, brightness } from 'chromatism' import { convert, brightness } from 'chromatism'
import sum from 'hash-sum'
import { flattenDeep } from 'lodash' import { flattenDeep } from 'lodash'
import { import {
alphaBlend, alphaBlend,
@ -142,8 +143,12 @@ componentsContext.keys().forEach(key => {
components[component.name] = component components[component.name] = component
}) })
const engineChecksum = sum(components)
const ruleToSelector = genericRuleToSelector(components) const ruleToSelector = genericRuleToSelector(components)
export const getEngineChecksum = () => engineChecksum
export const init = (extraRuleset, ultimateBackgroundColor) => { export const init = (extraRuleset, ultimateBackgroundColor) => {
const staticVars = {} const staticVars = {}
const stacked = {} const stacked = {}
@ -463,6 +468,7 @@ export const init = (extraRuleset, ultimateBackgroundColor) => {
return { return {
lazy: result.filter(x => typeof x === 'function'), lazy: result.filter(x => typeof x === 'function'),
eager: result.filter(x => typeof x !== 'function'), eager: result.filter(x => typeof x !== 'function'),
staticVars staticVars,
engineChecksum
} }
} }

View File

@ -24,6 +24,7 @@ const fetchAndUpdate = ({
showImmediately = false, showImmediately = false,
userId = false, userId = false,
listId = false, listId = false,
statusId = false,
tag = false, tag = false,
until, until,
since since
@ -47,6 +48,7 @@ const fetchAndUpdate = ({
args.userId = userId args.userId = userId
args.listId = listId args.listId = listId
args.statusId = statusId
args.tag = tag args.tag = tag
args.withMuted = !hideMutedPosts args.withMuted = !hideMutedPosts
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) { if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
@ -78,15 +80,15 @@ const fetchAndUpdate = ({
}) })
} }
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, tag = false }) => { const startFetching = ({ timeline = 'friends', credentials, store, userId = false, listId = false, statusId = false, tag = false }) => {
const rootState = store.rootState || store.state const rootState = store.rootState || store.state
const timelineData = rootState.statuses.timelines[camelCase(timeline)] const timelineData = rootState.statuses.timelines[camelCase(timeline)]
const showImmediately = timelineData.visibleStatuses.length === 0 const showImmediately = timelineData.visibleStatuses.length === 0
timelineData.userId = userId timelineData.userId = userId
timelineData.listId = listId timelineData.listId = listId
fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, tag }) fetchAndUpdate({ timeline, credentials, store, showImmediately, userId, listId, statusId, tag })
const boundFetchAndUpdate = () => const boundFetchAndUpdate = () =>
fetchAndUpdate({ timeline, credentials, store, userId, listId, tag }) fetchAndUpdate({ timeline, credentials, store, userId, listId, statusId, tag })
return promiseInterval(boundFetchAndUpdate, 10000) return promiseInterval(boundFetchAndUpdate, 10000)
} }
const timelineFetcher = { const timelineFetcher = {