Merge remote-tracking branch 'origin/develop' into disjointed-popovers

* origin/develop:
  add SK (Slovak) translation
  ReactButton: Workaround for android composition mode
  EmojiPicker: Workaround to search immediately on mobile
  Fix top bar input text colour
  Show underlay for mobile
  Fix tests
  Add English translations for correctly i18nized time units
  Delegate relativeTime plural rules to vue-i18n
  restore notifications page, fix z-index issues
  Make lint happy
  Add English translations for backup UI
  Add backup UI
  Add English translation for list aliases error
  Log errors when listing aliases
  Add changelog
  Add Engilsh translation for migration
  Add frontend ui for aliases and migration
  Change translation key
  Explain better what delete does in moderation menu
shigusegubu
Henry Jameson 2 years ago
commit 4dc4a91224
  1. 1
      CHANGELOG.md
  2. 1
      src/App.scss
  3. 2
      src/App.vue
  4. 2
      src/boot/routes.js
  5. 4
      src/components/desktop_nav/desktop_nav.scss
  6. 5
      src/components/emoji_picker/emoji_picker.js
  7. 1
      src/components/emoji_picker/emoji_picker.vue
  8. 4
      src/components/notifications/notifications.js
  9. 2
      src/components/notifications/notifications.vue
  10. 3
      src/components/react_button/react_button.js
  11. 1
      src/components/react_button/react_button.vue
  12. 29
      src/components/settings_modal/tabs/data_import_export_tab.js
  13. 61
      src/components/settings_modal/tabs/data_import_export_tab.vue
  14. 55
      src/components/settings_modal/tabs/security_tab/security_tab.js
  15. 108
      src/components/settings_modal/tabs/security_tab/security_tab.vue
  16. 2
      src/components/timeago/timeago.vue
  17. 2
      src/components/timeline/timeline.scss
  18. 1
      src/i18n/ca.json
  19. 1
      src/i18n/de.json
  20. 63
      src/i18n/en.json
  21. 1
      src/i18n/eo.json
  22. 3
      src/i18n/es.json
  23. 3
      src/i18n/eu.json
  24. 3
      src/i18n/fi.json
  25. 3
      src/i18n/fr.json
  26. 3
      src/i18n/he.json
  27. 3
      src/i18n/id.json
  28. 1
      src/i18n/it.json
  29. 3
      src/i18n/ja_easy.json
  30. 3
      src/i18n/ja_pedantic.json
  31. 1
      src/i18n/messages.js
  32. 3
      src/i18n/nb.json
  33. 1
      src/i18n/nl.json
  34. 3
      src/i18n/oc.json
  35. 3
      src/i18n/pl.json
  36. 1
      src/i18n/pt.json
  37. 3
      src/i18n/ru.json
  38. 1
      src/i18n/service_worker_messages.js
  39. 512
      src/i18n/sk.json
  40. 1
      src/i18n/uk.json
  41. 3
      src/i18n/vi.json
  42. 3
      src/i18n/zh.json
  43. 1
      src/i18n/zh_Hant.json
  44. 71
      src/services/api/api.service.js
  45. 16
      src/services/date_utils/date_utils.js
  46. 10
      test/unit/specs/services/date_utils/date_utils.spec.js

@ -47,6 +47,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Ability to rearrange order of attachments when uploading
- Enabled users to zoom and pan images in media viewer with mouse and touch
- Timelines/panels and conversations have sticky headers now
- Added frontend ui for account migration
## [2.4.2] - 2022-01-09

@ -317,7 +317,6 @@ nav {
border-top-right-radius: 0;
}
.underlay,
#sidebar,
#notifs-column {
display: none;

@ -9,7 +9,7 @@
/>
<MobileNav v-if="layoutType === 'mobile'" />
<DesktopNav v-else />
<notifications v-if="currentUser" />
<Notifications v-if="currentUser" />
<div
id="content"
class="app-layout container"

@ -62,7 +62,7 @@ export default (store) => {
{ name: 'password-reset', path: '/password-reset', component: PasswordReset, props: true },
{ name: 'registration-token', path: '/registration/:token', component: Registration },
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute },
{ name: 'notifications', path: '/:username/notifications', component: Notifications, beforeEnter: validateAuthenticatedRoute },
{ name: 'notifications', path: '/:username/notifications', component: Notifications, props: () => ({ disableTeleport: true }), beforeEnter: validateAuthenticatedRoute },
{ name: 'login', path: '/login', component: AuthForm },
{ name: 'shout-panel', path: '/shout-panel', component: ShoutPanel, props: () => ({ floating: false }) },
{ name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },

@ -4,6 +4,10 @@
width: 100%;
z-index: var(--ZI_navbar);
input {
color: var(--inputTopbarText, var(--inputText));
}
a {
color: var(--topBarLink, $fallback--link);
}

@ -6,6 +6,7 @@ import {
faStickyNote,
faSmileBeam
} from '@fortawesome/free-solid-svg-icons'
import { trim } from 'lodash'
library.add(
faBoxOpen,
@ -176,7 +177,7 @@ const EmojiPicker = {
filteredEmoji () {
return filterByKeyword(
this.$store.state.instance.customEmoji || [],
this.keyword
trim(this.keyword)
)
},
customEmojiBuffer () {
@ -197,7 +198,7 @@ const EmojiPicker = {
id: 'standard',
text: this.$t('emoji.unicode'),
icon: 'box-open',
emojis: filterByKeyword(standardEmojis, this.keyword)
emojis: filterByKeyword(standardEmojis, trim(this.keyword))
}
]
},

@ -47,6 +47,7 @@
type="text"
class="form-control"
:placeholder="$t('emoji.search_emoji')"
@input="$event.target.composing = false"
>
</div>
<div

@ -28,7 +28,9 @@ const Notifications = {
// meant for "Interactions" timeline
minimalMode: Boolean,
// Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline
filterMode: Array
filterMode: Array,
// Disable teleporting (i.e. for /users/user/notifications)
disableTeleport: Boolean
},
data () {
return {

@ -1,5 +1,5 @@
<template>
<teleport :disabled="minimalMode" :to="teleportTarget">
<teleport :disabled="minimalMode || disableTeleport" :to="teleportTarget">
<div
:class="{ minimal: minimalMode }"
class="Notifications"

@ -1,6 +1,7 @@
import Popover from '../popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
import { trim } from 'lodash'
library.add(faSmileBeam)
@ -43,7 +44,7 @@ const ReactButton = {
},
emojis () {
if (this.filterWord !== '') {
const filterWordLowercase = this.filterWord.toLowerCase()
const filterWordLowercase = trim(this.filterWord.toLowerCase())
let orderedEmojiList = []
for (const emoji of this.$store.state.instance.emoji) {
if (emoji.replacement === this.filterWord) return [emoji]

@ -13,6 +13,7 @@
<div class="reaction-picker-filter">
<input
v-model="filterWord"
@input="$event.target.composing = false"
size="1"
:placeholder="$t('emoji.search_emoji')"
>

@ -7,11 +7,16 @@ const DataImportExportTab = {
data () {
return {
activeTab: 'profile',
newDomainToMute: ''
newDomainToMute: '',
listBackupsError: false,
addBackupError: false,
addedBackup: false,
backups: []
}
},
created () {
this.$store.dispatch('fetchTokens')
this.fetchBackups()
},
components: {
Importer,
@ -72,6 +77,28 @@ const DataImportExportTab = {
}
return user.screen_name
}).join('\n')
},
addBackup () {
this.$store.state.api.backendInteractor.addBackup()
.then((res) => {
this.addedBackup = true
this.addBackupError = false
})
.catch((error) => {
this.addedBackup = false
this.addBackupError = error
})
.then(() => this.fetchBackups())
},
fetchBackups () {
this.$store.state.api.backendInteractor.listBackups()
.then((res) => {
this.backups = res
this.listBackupsError = false
})
.catch((error) => {
this.listBackupsError = error.error
})
}
}
}

@ -53,6 +53,67 @@
:export-button-label="$t('settings.mute_export_button')"
/>
</div>
<div class="setting-item">
<h2>{{ $t('settings.account_backup') }}</h2>
<p>{{ $t('settings.account_backup_description') }}</p>
<table>
<thead>
<tr>
<th>{{ $t('settings.account_backup_table_head') }}</th>
<th />
</tr>
</thead>
<tbody>
<tr
v-for="backup in backups"
:key="backup.id"
>
<td>{{ backup.inserted_at }}</td>
<td class="actions">
<a
v-if="backup.processed"
target="_blank"
:href="backup.url"
>
{{ $t('settings.download_backup') }}
</a>
<span
v-else
>
{{ $t('settings.backup_not_ready') }}
</span>
</td>
</tr>
</tbody>
</table>
<div
v-if="listBackupsError"
class="alert error"
>
{{ $t('settings.list_backups_error', { error }) }}
<button
:title="$t('settings.hide_list_backups_error_action')"
@click="listBackupsError = false"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div>
<button
class="btn button-default"
@click="addBackup"
>
{{ $t('settings.add_backup') }}
</button>
<p v-if="addedBackup">
{{ $t('settings.added_backup') }}
</p>
<template v-if="addBackupError !== false">
<p>{{ $t('settings.add_backup_error', { error: addBackupError }) }}</p>
</template>
</div>
</div>
</template>

@ -15,11 +15,21 @@ const SecurityTab = {
deleteAccountError: false,
changePasswordInputs: [ '', '', '' ],
changedPassword: false,
changePasswordError: false
changePasswordError: false,
moveAccountTarget: '',
moveAccountPassword: '',
movedAccount: false,
moveAccountError: false,
aliases: [],
listAliasesError: false,
addAliasTarget: '',
addedAlias: false,
addAliasError: false
}
},
created () {
this.$store.dispatch('fetchTokens')
this.fetchAliases()
},
components: {
ProgressButton,
@ -92,6 +102,49 @@ const SecurityTab = {
}
})
},
moveAccount () {
const params = {
targetAccount: this.moveAccountTarget,
password: this.moveAccountPassword
}
this.$store.state.api.backendInteractor.moveAccount(params)
.then((res) => {
if (res.status === 'success') {
this.movedAccount = true
this.moveAccountError = false
} else {
this.movedAccount = false
this.moveAccountError = res.error
}
})
},
removeAlias (alias) {
this.$store.state.api.backendInteractor.deleteAlias({ alias })
.then(() => this.fetchAliases())
},
addAlias () {
this.$store.state.api.backendInteractor.addAlias({ alias: this.addAliasTarget })
.then((res) => {
this.addedAlias = true
this.addAliasError = false
this.addAliasTarget = ''
})
.catch((error) => {
this.addedAlias = false
this.addAliasError = error
})
.then(() => this.fetchAliases())
},
fetchAliases () {
this.$store.state.api.backendInteractor.listAliases()
.then((res) => {
this.aliases = res.aliases
this.listAliasesError = false
})
.catch((error) => {
this.listAliasesError = error.error
})
},
logout () {
this.$store.dispatch('logout')
this.$router.replace('/')

@ -103,6 +103,114 @@
</table>
</div>
<mfa />
<div class="setting-item">
<h2>{{ $t('settings.account_alias') }}</h2>
<table>
<thead>
<tr>
<th>{{ $t('settings.account_alias_table_head') }}</th>
<th />
</tr>
</thead>
<tbody>
<tr
v-for="alias in aliases"
:key="alias"
>
<td>{{ alias }}</td>
<td class="actions">
<button
class="btn button-default"
@click="removeAlias(alias)"
>
{{ $t('settings.remove_alias') }}
</button>
</td>
</tr>
</tbody>
</table>
<div
v-if="listAliasesError"
class="alert error"
>
{{ $t('settings.list_aliases_error', { error }) }}
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
:title="$t('settings.hide_list_aliases_error_action')"
@click="listAliasesError = false"
/>
</div>
<div>
<i18n
path="settings.new_alias_target"
tag="p"
>
<code
place="example"
>
foo@example.org
</code>
</i18n>
<input
v-model="addAliasTarget"
>
</div>
<button
class="btn button-default"
@click="addAlias"
>
{{ $t('settings.save') }}
</button>
<p v-if="addedAlias">
{{ $t('settings.added_alias') }}
</p>
<template v-if="addAliasError !== false">
<p>{{ $t('settings.add_alias_error', { error: addAliasError }) }}</p>
</template>
</div>
<div class="setting-item">
<h2>{{ $t('settings.move_account') }}</h2>
<p>{{ $t('settings.move_account_notes') }}</p>
<div>
<i18n
path="settings.move_account_target"
tag="p"
>
<code
place="example"
>
foo@example.org
</code>
</i18n>
<input
v-model="moveAccountTarget"
>
</div>
<div>
<p>{{ $t('settings.current_password') }}</p>
<input
v-model="moveAccountPassword"
type="password"
autocomplete="current-password"
>
</div>
<button
class="btn button-default"
@click="moveAccount"
>
{{ $t('settings.save') }}
</button>
<p v-if="movedAccount">
{{ $t('settings.moved_account') }}
</p>
<template v-if="moveAccountError !== false">
<p>{{ $t('settings.move_account_error', { error: moveAccountError }) }}</p>
</template>
</div>
<div class="setting-item">
<h2>{{ $t('settings.delete_account') }}</h2>
<p v-if="!deletingAccount">

@ -3,7 +3,7 @@
:datetime="time"
:title="localeDateString"
>
{{ $t(relativeTime.key, [relativeTime.num]) }}
{{ $tc(relativeTime.key, relativeTime.num, [relativeTime.num]) }}
</time>
</template>

@ -11,7 +11,7 @@
.conversation-heading {
top: calc(var(--__panel-heading-height) * var(--currentPanelStack, 2));
z-index: 1;
z-index: 2;
}
&.-nonpanel {

@ -621,7 +621,6 @@
"disable_any_subscription": "Deshabilita completament seguir algú",
"quarantine": "Deshabilita la federació a les entrades de les usuàries",
"moderation": "Moderació",
"delete_user_confirmation": "Estàs completament segur/a? Aquesta acció no es pot desfer.",
"revoke_admin": "Revoca l'Admin",
"activate_account": "Activa el compte",
"deactivate_account": "Desactiva el compte",

@ -582,7 +582,6 @@
"statuses": "Beiträge",
"admin_menu": {
"sandbox": "Erzwinge Beiträge nur für Follower sichtbar zu sein",
"delete_user_confirmation": "Achtung! Diese Entscheidung kann nicht rückgängig gemacht werden! Trotzdem durchführen?",
"grant_admin": "Administratorprivilegien gewähren",
"delete_user": "Nutzer löschen",
"strip_media": "Medien von Beiträgen entfernen",

@ -317,6 +317,16 @@
"mute_import_error": "Error importing mutes",
"mutes_imported": "Mutes imported! Processing them will take a while.",
"import_mutes_from_a_csv_file": "Import mutes from a csv file",
"account_backup": "Account backup",
"account_backup_description": "This allows you to download an archive of your account information and your posts, but they cannot yet be imported into a Pleroma account.",
"account_backup_table_head": "Backup",
"download_backup": "Download",
"backup_not_ready": "This backup is not ready yet.",
"remove_backup": "Remove",
"list_backups_error": "Error fetching backup list: {error}",
"add_backup": "Create a new backup",
"added_backup": "Added a new backup.",
"add_backup_error": "Error adding a new backup: {error}",
"blocks_tab": "Blocks",
"bot": "This is a bot account",
"btnRadius": "Buttons",
@ -342,6 +352,19 @@
"delete_account_description": "Permanently delete your data and deactivate your account.",
"delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
"delete_account_instructions": "Type your password in the input below to confirm account deletion.",
"account_alias": "Account aliases",
"account_alias_table_head": "Alias",
"list_aliases_error": "Error fetching aliases: {error}",
"hide_list_aliases_error_action": "Close",
"remove_alias": "Remove this alias",
"new_alias_target": "Add a new alias (e.g. {example})",
"added_alias": "Alias is added.",
"add_alias_error": "Error adding alias: {error}",
"move_account": "Move account",
"move_account_notes": "If you want to move the account somewhere else, you must go to your target account and add an alias pointing here.",
"move_account_target": "Target account (e.g. {example})",
"moved_account": "Account is moved.",
"move_account_error": "Error moving account: {error}",
"discoverable": "Allow discovery of this account in search results and other services",
"domain_mutes": "Domains",
"avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
@ -692,39 +715,27 @@
}
},
"time": {
"day": "{0} day",
"days": "{0} days",
"day_short": "{0}d",
"unit": {
"days": "{0} day | {0} days",
"days_short": "{0}d",
"hour": "{0} hour",
"hours": "{0} hours",
"hour_short": "{0}h",
"hours": "{0} hour | {0} hours",
"hours_short": "{0}h",
"in_future": "in {0}",
"in_past": "{0} ago",
"minute": "{0} minute",
"minutes": "{0} minutes",
"minute_short": "{0}min",
"minutes": "{0} minute | {0} minutes",
"minutes_short": "{0}min",
"month": "{0} month",
"months": "{0} months",
"month_short": "{0}mo",
"months": "{0} month | {0} months",
"months_short": "{0}mo",
"now": "just now",
"now_short": "now",
"second": "{0} second",
"seconds": "{0} seconds",
"second_short": "{0}s",
"seconds": "{0} second | {0} seconds",
"seconds_short": "{0}s",
"week": "{0} week",
"weeks": "{0} weeks",
"week_short": "{0}w",
"weeks": "{0} week | {0} weeks",
"weeks_short": "{0}w",
"year": "{0} year",
"years": "{0} years",
"year_short": "{0}y",
"years": "{0} year | {0} years",
"years_short": "{0}y"
},
"in_future": "in {0}",
"in_past": "{0} ago",
"now": "just now",
"now_short": "now"
},
"timeline": {
"collapse": "Collapse",
"conversation": "Conversation",
@ -849,7 +860,7 @@
"disable_any_subscription": "Disallow following user at all",
"quarantine": "Disallow user posts from federating",
"delete_user": "Delete user",
"delete_user_confirmation": "Are you absolutely sure? This action cannot be undone."
"delete_user_data_and_deactivate_confirmation": "This will permanently delete the data from this account and deactivate it. Are you absolutely sure?"
},
"highlight": {
"disabled": "No highlight",

@ -606,7 +606,6 @@
"mention": "Mencio",
"hidden": "Kaŝita",
"admin_menu": {
"delete_user_confirmation": "Ĉu vi tute certas? Ĉi tiu ago ne estas malfarebla.",
"delete_user": "Forigi uzanton",
"quarantine": "Malpermesi federadon de afiŝoj de uzanto",
"disable_any_subscription": "Malpermesi ĉian abonadon al uzanto",

@ -731,8 +731,7 @@
"disable_remote_subscription": "No permitir que usuarios de instancias remotas te siga",
"disable_any_subscription": "No permitir que ningún usuario te siga",
"quarantine": "No permitir publicaciones de usuarios de instancias remotas",
"delete_user": "Eliminar usuario",
"delete_user_confirmation": "¿Estás completamente seguro? Esta acción no se puede deshacer."
"delete_user": "Eliminar usuario"
},
"show_repeats": "Mostrar repetidos",
"hide_repeats": "Ocultar repetidos",

@ -609,8 +609,7 @@
"disable_remote_subscription": "Ez utzi istantzia kanpoko erabiltzaileak zuri jarraitzea",
"disable_any_subscription": "Ez utzi beste erabiltzaileak zuri jarraitzea",
"quarantine": "Ez onartu mezuak beste instantzietatik",
"delete_user": "Erabiltzailea ezabatu",
"delete_user_confirmation": "Erabat ziur zaude? Ekintza hau ezin da desegin."
"delete_user": "Erabiltzailea ezabatu"
}
},
"user_profile": {

@ -620,8 +620,7 @@
"sandbox": "Pakota viestit vain seuraajille",
"disable_remote_subscription": "Estä seuraaminen ulkopuolisilta sivuilta",
"quarantine": "Estä käyttäjän viestin federoituminen",
"delete_user": "Poista käyttäjä",
"delete_user_confirmation": "Oletko aivan varma? Tätä ei voi kumota."
"delete_user": "Poista käyttäjä"
},
"favorites": "Tykkäykset",
"mention": "Mainitse",

@ -659,8 +659,7 @@
"disable_remote_subscription": "Interdir de s'abonner a l'utilisateur depuis l'instance distante",
"disable_any_subscription": "Interdir de s'abonner à l'utilisateur tout court",
"quarantine": "Interdir les statuts de l'utilisateur à fédérer",
"delete_user": "Supprimer l'utilisateur",
"delete_user_confirmation": "Êtes-vous absolument-sûr⋅e ? Cette action ne peut être annulée."
"delete_user": "Supprimer l'utilisateur"
},
"mention": "Mention",
"hidden": "Caché",

@ -347,8 +347,7 @@
"disable_remote_subscription": "אל תאפשר עקיבה של המשתמש מאינסטנס אחר",
"disable_any_subscription": "אל תאפשר עקיבה של המשתמש בכלל",
"quarantine": "אל תאפשר פדרציה של ההודעות של המשתמש",
"delete_user": "מחק משתמש",
"delete_user_confirmation": "בטוח? פעולה זו הינה בלתי הפיכה."
"delete_user": "מחק משתמש"
}
},
"user_profile": {

@ -327,8 +327,7 @@
"delete_account": "Hapus akun",
"force_nsfw": "Tandai semua postingan sebagai NSFW",
"strip_media": "Hapus media dari postingan-postingan",
"delete_user": "Hapus pengguna",
"delete_user_confirmation": "Apakah Anda benar-benar yakin? Tindakan ini tidak dapat dibatalkan."
"delete_user": "Hapus pengguna"
},
"follow_unfollow": "Berhenti mengikuti",
"followees": "Mengikuti",

@ -485,7 +485,6 @@
"deny": "Nega",
"remote_follow": "Segui da remoto",
"admin_menu": {
"delete_user_confirmation": "Ne sei completamente sicuro? Non potrai tornare indietro.",
"delete_user": "Elimina utente",
"quarantine": "I messaggi non arriveranno alle altre stanze",
"disable_any_subscription": "Rendi utente non seguibile",

@ -608,8 +608,7 @@
"disable_remote_subscription": "ほかのインスタンスからフォローされないようにする",
"disable_any_subscription": "フォローされないようにする",
"quarantine": "ほかのインスタンスのユーザーのとうこうをとめる",
"delete_user": "ユーザーをけす",
"delete_user_confirmation": "あなたは、ほんとうに、きはたしかですか? これは、とりけすことが、できません。"
"delete_user": "ユーザーをけす"
}
},
"user_profile": {

@ -729,8 +729,7 @@
"disable_remote_subscription": "他のインスタンスからフォローされないようにする",
"disable_any_subscription": "フォローされないようにする",
"quarantine": "他のインスタンスからの投稿を止める",
"delete_user": "ユーザーを削除",
"delete_user_confirmation": "あなたの精神状態に何か問題はございませんか? この操作を取り消すことはできません。"
"delete_user": "ユーザーを削除"
},
"roles": {
"moderator": "モデレーター",

@ -32,6 +32,7 @@ const loaders = {
pt: () => import('./pt.json'),
ro: () => import('./ro.json'),
ru: () => import('./ru.json'),
sk: () => import('./sk.json'),
te: () => import('./te.json'),
uk: () => import('./uk.json'),
zh: () => import('./zh.json'),

@ -553,8 +553,7 @@
"disable_remote_subscription": "Fjern mulighet til å følge brukeren fra andre instanser",
"disable_any_subscription": "Fjern mulighet til å følge brukeren",
"quarantine": "Gjør at statuser fra brukeren ikke kan sendes til andre instanser",
"delete_user": "Slett bruker",
"delete_user_confirmation": "Er du helt sikker? Denne handlingen kan ikke omgjøres."
"delete_user": "Slett bruker"
}
},
"user_profile": {

@ -580,7 +580,6 @@
"remote_follow": "Volg vanop afstand",
"statuses": "Statussen",
"admin_menu": {
"delete_user_confirmation": "Weet je het heel zeker? Deze uitvoering kan niet ongedaan worden gemaakt.",
"delete_user": "Gebruiker verwijderen",
"quarantine": "Federeren van gebruikers berichten verbieden",
"disable_any_subscription": "Volgen van gebruiker in zijn geheel verbieden",

@ -501,8 +501,7 @@
"disable_remote_subscription": "Desactivar lo seguiment d’utilizaire d’instàncias alonhadas",
"disable_any_subscription": "Desactivar tot seguiment",
"quarantine": "Defendre la federacion de las publicacions de l’utilizaire",
"delete_user": "Suprimir l’utilizaire",
"delete_user_confirmation": "Volètz vertadièrament far aquò? Aquesta accion se pòt pas anullar."
"delete_user": "Suprimir l’utilizaire"
}
},
"user_profile": {

@ -762,8 +762,7 @@
"disable_remote_subscription": "Zakaż obserwowania użytkownika ze zdalnych instancji",
"disable_any_subscription": "Zakaż całkowicie obserwowania użytkownika",
"quarantine": "Zakaż federowania postów od tego użytkownika",
"delete_user": "Usuń użytkownika",
"delete_user_confirmation": "Czy jesteś absolutnie pewny(-a)? Ta operacja nie może być cofnięta."
"delete_user": "Usuń użytkownika"
},
"message": "Napisz",
"edit_profile": "Edytuj profil",

@ -594,7 +594,6 @@
"unmute_progress": "A retirar silêncio…",
"mute_progress": "A silenciar…",
"admin_menu": {
"delete_user_confirmation": "Tens a certeza? Esta ação não pode ser revertida.",
"delete_user": "Eliminar utilizador",
"quarantine": "Não permitir publicações de utilizadores de instâncias remotas",
"disable_any_subscription": "Não permitir que nenhum utilizador te siga",

@ -576,8 +576,7 @@
"disable_remote_subscription": "Запретить читать с других узлов",
"disable_any_subscription": "Запретить читать пользователя",
"quarantine": "Не федерировать статусы пользователя",
"delete_user": "Удалить пользователя",
"delete_user_confirmation": "Вы уверены? Это действие нельзя отменить."
"delete_user": "Удалить пользователя"
},
"media": "С вложениями",
"mention": "Упомянуть",

@ -27,6 +27,7 @@ const messages = {
pt: require('../lib/notification-i18n-loader.js!./pt.json'),
ro: require('../lib/notification-i18n-loader.js!./ro.json'),
ru: require('../lib/notification-i18n-loader.js!./ru.json'),
sk: require('../lib/notification-i18n-loader.js!./sk.json'),
te: require('../lib/notification-i18n-loader.js!./te.json'),
zh: require('../lib/notification-i18n-loader.js!./zh.json'),
en: require('../lib/notification-i18n-loader.js!./en.json')

@ -0,0 +1,512 @@
{
"about": {
"mrf": {
"federation": "Federácia",
"keyword": {
"keyword_policies": "Pravidlá pre kľúčové slová",
"ftl_removal": "Odstránenie z časovej osy \"Celej známej siete\"",
"reject": "Odmietni",
"replace": "Nahraď",
"is_replaced_by": "→"
},
"mrf_policies": "Povoliť MRF pravidlá",
"mrf_policies_desc": "MRF pravidlá upravujú správanie servera v rámci federácie s inými. Nasledovné pravidlá sú aktívne:",
"simple": {
"simple_policies": "Pravidlá špecifické pre tento server",
"instance": "Server",
"reason": "Dôvod",
"not_applicable": "N/A",
"accept": "Prijať",
"accept_desc": "Tento server preberá správy len z nasledovných serverov:",
"reject": "Odmietnuť",
"reject_desc": "Tento server preberá správy spravy z nasledovných serverov:",
"quarantine": "Karanténa",
"quarantine_desc": "Tento server posiela verejné oznamy len na nasledovné servre:",
"ftl_removal": "Odstránenie časovej osy \"Známa sieť\"",
"ftl_removal_desc": "Tento server odstraňuje nasledovné serverov zo svojej časovej osy \"Známa sieť\":",
"media_removal": "Odstránenie médií",
"media_removal_desc": "Tento server odstraňuje médiá zo správ nasledovných serverov:",
"media_nsfw": "Označenie médií ako citlivých",
"media_nsfw_desc": "Tento server označuje média ako citlivé v správach z nasledovných serverov:"
}
},
"staff": "Personál"
},
"shoutbox": {
"title": "Verejné fórum"
},
"domain_mute_card": {
"mute": "Utíš",
"mute_progress": "Utišujem…",
"unmute": "Povoľ oznamy",
"unmute_progress": "Povoľujem oznamy…"
},
"exporter": {
"export": "Export",
"processing": "Spracováva sa, čoskoro sa ti ponúknu na stiahnutie súbory s dátami exportu"
},
"features_panel": {
"shout": "Verejné fórum",
"pleroma_chat_messages": "Pleroma Chat",
"gopher": "Gopher",
"media_proxy": "Proxy pre médiá",
"scope_options": "Nastavenia rámca",
"text_limit": "Limit počtu znakov",
"title": "Vlastnosti",
"who_to_follow": "Koho nasledovať",
"upload_limit": "Limit nahrávania"
},
"finder": {
"error_fetching_user": "Chyba načítavania užívateľa",
"find_user": "Nájsť užívateľa"
},
"general": {
"apply": "Použiť",
"submit": "Odoslať",
"more": "Viac",
"loading": "Nahrávam…",
"generic_error": "Nastala chyba",
"error_retry": "Zopakuj znova, prosím",
"retry": "Zopakuj znova",
"optional": "nepovinné",
"show_more": "Zobraz viac",
"show_less": "Zobraz menej",
"dismiss": "Zahoď",
"cancel": "Zruš",
"disable": "Vypni",
"enable": "Zapni",
"confirm": "Potvrdiť",
"verify": "Overiť",
"close": "Zatvoriť",
"peek": "Vybrať",
"role": {
"admin": "Správca",
"moderator": "Moderátor"
},
"flash_content": "Klikni pre zobrazenie Flash obsahu prostredníctvom Ruffle (experimentálne, nemusí fungovať).",
"flash_security": "Flash obsah je potencionálne nebezpečný, keďže je to produkt s uzatvoreným kódom.",
"flash_fail": "Nepodarilo sa nahrať Flash obsah, pre detaily pozri konzolu prehliadača.",
"scope_in_timeline": {
"direct": "Priame",
"private": "Len pre nasledovníkov",
"public": "Verejné",
"unlisted": "Nezaradené"
}
},
"image_cropper": {
"crop_picture": "Orezať obrázok",
"save": "Uložiť",
"save_without_cropping": "Ulož bez orezania",
"cancel": "Zrušiť"
},
"importer": {
"submit": "Odoslať",
"success": "Úspečne naimportované.",
"error": "Pri importe súboru nastala chyba."
},
"login": {
"login": "Prihlásiť sa",
"description": "Prihlásiť pomocou OAuth",
"logout": "Odhlásiť sa",
"password": "Heslo",
"placeholder": "napr. peter",
"register": "Registrácia",
"username": "Meno užívateľa",
"hint": "Prihlás sa, aby si sa mohol zúčastniť konverzácie",
"authentication_code": "Autentifikačný kód",
"enter_recovery_code": "Zadaj kód obnovenia",
"enter_two_factor_code": "Zadaj 2-fázový validačný kód",
"recovery_code": "Kód obnovenia",
"heading": {
"totp": "2-fázové overenie",
"recovery": "2-fázové obnova"
}
},
"media_modal": {
"previous": "Predchádzajúce",
"next": "Nasledujúce",
"counter": "{current} / {total}",
"hide": "Zatvoriť prehliadač médií"
},
"nav": {
"about": "O stránke",
"administration": "Administrácia",
"back": "Späť",
"friend_requests": "Žiadosti o priateľstvo",
"mentions": "Zmienky",
"interactions": "Interakcie",
"dms": "Priame správy",
"public_tl": "Verejná časová os",
"timeline": "Časová os",
"home_timeline": "Domáca časová os",
"twkn": "Známa sieť",
"bookmarks": "Záložky",
"user_search": "Hľadanie užívateľa",
"search": "Hladať",
"who_to_follow": "Koho nasledovať",
"preferences": "Nastavenia",
"timelines": "Časové osy",
"chats": "Chaty"
},
"notifications": {
"broken_favorite": "Neznáma správa, dohľadávam ju…",
"error": "Chyba získavania upozornení: {0}",
"favorited_you": "si obľúbil tvoju správu",
"followed_you": "ťa nasleduje",
"follow_request": "ťa chce nasledovať",
"load_older": "Nahrať staršie upozornenia",
"notifications": "Upozornenia",
"read": "Prečítané!",
"repeated_you": "zopakoval tvoju správu",
"no_more_notifications": "Žiadne ďalšie upozornenia",
"migrated_to": "sa presťahoval na",
"reacted_with": "reagoval nasledovne {0}"
},
"polls": {
"add_poll": "Pridať anketu",
"add_option": "Pridať možnosť",
"option": "Možnosť",
"votes": "hlasy",
"people_voted_count": "{count} volič | {count} voličov",
"votes_count": "{count} hlas | {count} hlasov",
"vote": "Hlas",
"type": "Typ ankety",
"single_choice": "Výber jednej možnosti",
"multiple_choices": "Výber viacerých možností",
"expiry": "Vek ankety",
"expires_in": "Anketa končí za {0}",
"expired": "Anketa skončila pre {0}",
"not_enough_options": "Príliš málo jedinečných možností v ankete"
},
"emoji": {
"stickers": "Nálepka",
"emoji": "Emotikon",
"keep_open": "Ponechaj okno výberu otvorené",
"search_emoji": "Vyhladať emotikon",
"add_emoji": "Vložiť emotikon",
"custom": "Vlastný emotikon",
"unicode": "Unicode emotikon",
"load_all_hint": "Nahralo sa prvých {saneAmount} emotikonov, nahranie všetkých by mohlo spôsobiť zníženie výkonu.",
"load_all": "Nahrať všetkých {emojiAmount} emotikonov"
},
"errors": {
"storage_unavailable": "Pleroma nemôže používať úložisko prehliadača. Tvoje prihlasovacie meno a lokálne nastavenia nebudú uchované a môžu sa vyskytnúť neočakávané chyby. Skús povoliť cookie."
},
"interactions": {
"favs_repeats": "Zopakovania a obľúbené",
"follows": "Nový nasledovatelia",
"moves": "Užívateľ sa sťahuje",
"load_older": "Nahrať staršiu komunikáciu"
},
"post_status": {
"new_status": "Poslať novú správu",
"account_not_locked_warning": "Tvoj účen nie je {0}. Ktokoľvek ťa môže začať nasledovať a tak vidieť správy určené len pre nasledovateľov.",
"account_not_locked_warning_link": "uzamknuté",
"attachments_sensitive": "Označiť prílohy ako citlivé",
"media_description": "Popis média",
"content_type": {
"text/plain": "Obyčajný text",
"text/html": "HTML",
"text/markdown": "Markdown",
"text/bbcode": "BBCode"
},
"content_warning": "Nadpis (nepovinné)",
"default": "Práve som ...",
"direct_warning_to_all": "Túto správu bude vidieť každý užívateľ, ktorého v nej spomenieš.",
"direct_warning_to_first_only": "Táto správa bude viditeľná len pre užívateľov, ktorých vymenuješ na začiatku správy.",
"posting": "Posielanie",
"post": "Poslať",
"preview": "Náhľad",
"preview_empty": "Prázdne",
"empty_status_error": "Nie je možné odoslať prázdnu správu bez priložených súborov",
"media_description_error": "Nepodarilo sa aktualizovať média, skús znova",
"scope_notice": {
"public": "Túto správu bude vidieť každý",
"private": "Túto správu budú vidieť len tvoji nasledovníci",
"unlisted": "Táto správa nebude viditeľná na verejnej časovej osi a v celej známej sieti"
},
"scope": {
"direct": "Priama správa - zobrazí sa len užívateľom spomenutým v správe",
"private": "Pre nasledovníkov - zobrazí sa len tvojim nasledovníkom",
"public": "Verejné - zobrazí sa vo všetkých časových osiach",
"unlisted": "Nezaradené - nezobrazí sa v žiadnej časovej osy"
}
},
"registration": {
"bio": "Životopis",
"email": "Email",
"fullname": "Zobrazované meno",
"password_confirm": "Potvrdenie hesla",
"registration": "Registrácia",
"token": "Pozývací kód",
"captcha": "CAPTCHA",
"new_captcha": "Klikni na obrázok a vnikne nová captcha",
"username_placeholder": "napr. peter",
"fullname_placeholder": "napr. Peter Kukurica",
"bio_placeholder": "e.g.\nHi, I'm Lain.\nI’m an anime girl living in suburban Japan. You may know me from the Wired.",
"reason": "Dôvod registrácie",
"reason_placeholder": "Tento server schvaľuje registrácie manuálne.\nZanechaj správcom dôvod, prečo máš záujem vytvoriť si tu účet.",
"register": "Registrácia",
"validations": {
"username_required": "nemôže byť prázdne",
"fullname_required": "nemôže byť prázdne",
"email_required": "nemôže byť prázdne",
"password_required": "nemôže byť prázdne",
"password_confirmation_required": "nemôže byť prázdne",
"password_confirmation_match": "musí byť rovnaké ako heslo"
}
},
"remote_user_resolver": {
"remote_user_resolver": "Vzdialené overenie užívateľa",
"searching_for": "Hľadám...",
"error": "Nenájdené."
},
"selectable_list": {
"select_all": "Vybrať všetko"
},
"time": {
"day": "{0} deň",
"days": "{0} dní",
"day_short": "{0}d",
"days_short": "{0}d",
"hour": "{0} hodina",
"hours": "{0} hodín",
"hour_short": "{0}h",
"hours_short": "{0}h",
"in_future": "za {0}",
"in_past": "pred {0}",
"minute": "{0} minúta",
"minutes": "{0} minút",
"minute_short": "{0}min",
"minutes_short": "{0}min",
"month": "{0} mesiac",
"months": "{0} mesiacov",
"month_short": "{0}mes",
"months_short": "{0}mes",
"now": "práve teraz",
"now_short": "teraz",
"second": "{0} sekunda",
"seconds": "{0} sekúnd",
"second_short": "{0}s",
"seconds_short": "{0}s",
"week": "{0} týždeň",
"weeks": "{0} týždňov",
"week_short": "{0}t",
"weeks_short": "{0}t",
"year": "{0} rok",
"years": "{0} rokov",
"year_short": "{0}r",
"years_short": "{0}r"
},
"timeline": {
"collapse": "Zbaliť",
"conversation": "Konverzácia",
"error": "Chyba pri nahrávaní časovej správy: {0}",
"load_older": "Nahrať staršie správy",
"no_retweet_hint": "Správa je označená ako len-pre-nasledovateľov alebo ako priama a nemôže byť zopakovaná na tvojej časovej osy.",
"repeated": "zopakované",
"show_new": "Zobraziť nové",
"reload": "Znovu nahrať",
"up_to_date": "Aktuálne",
"no_more_statuses": "Žiadne ďalšie správy",
"no_statuses": "Žiadne správy",
"socket_reconnected": "Prepojenie v reálnom čase bolo úspešne vytvorené",
"socket_broke": "Strata prepojenia v reálnom čase: chyba CloseEvent kód {0}"
},
"status": {
"favorites": "Obľúbené",
"repeats": "Opakovania",
"delete": "Zmazať správu",
"pin": "Pripnúť na stránku užívateľa",
"unpin": "Odopnúť zo stránky užívateľa",
"pinned": "Pripnuté",
"bookmark": "Vytvoriť záložku",
"unbookmark": "Zmazať záložku",
"delete_confirm": "Skutočne chceš zmazať túto správu?",
"reply_to": "Odpovedať komu",
"mentions": "Spomenutia",
"replies_list": "Odpovede:",
"replies_list_with_others": "Odpoveď (+{numReplies} iný): | Odpoveď (+{numReplies} iných):",
"mute_conversation": "Stíšiť konverzáciu",
"unmute_conversation": "Oznamovať konverzáciu",
"status_unavailable": "Neznámy status",
"copy_link": "Skopírovať odkaz do správy",
"external_source": "Vzdialený zdroj",
"thread_muted": "Konverzácia stíšená",
"thread_muted_and_words": ", má slová:",
"show_full_subject": "Zobraziť celý nadpis",
"hide_full_subject": "Skry celý nadpis",
"show_content": "Zobraziť obsah",
"hide_content": "Skryť obsah",
"status_deleted": "Táto správa bola zmazaná",
"nsfw": "NSFW",
"expand": "Rozbaliť správu",
"you": "(ty)",
"plus_more": "+{number} ďalších",
"many_attachments": "Správa má {number} príloh",
"collapse_attachments": "Zabaliť médiá",
"show_all_attachments": "Zobraz všetky prílohy",
"show_attachment_in_modal": "Zobraz médiá modálne",
"show_attachment_description": "Náhľad popisku (otvor prílohu pre zobrazenie celého popisku)",
"hide_attachment": "Skryť prílohy",
"remove_attachment": "Odstrániť prílohy",
"attachment_stop_flash": "Zastaviť prehrávač Flashu",
"move_up": "Presuň prílohu doľava",
"move_down": "Presuň prílohu doprava",
"open_gallery": "Otvoriť galériu",
"thread_hide": "Skry túto konverzáciu",
"thread_show": "Zobraz túto konverzáciu",
"thread_show_full": "Zobraz všetko pod touto konverzáciou (celkovo {numStatus} správa, max hĺbka {depth}) | Zobraz všetko pod touto konverzáciou (celkovo {numStatus} správ, max hĺbka {depth})",
"thread_show_full_with_icon": "{icon} {text}",
"thread_follow": "Zobraz zvyšnú časť tejto konverzácie (celkovo {numStatus} správa) | Zobraz zvyšnú časť tejto konverzácie (celkovo {numStatus} správ)",
"thread_follow_with_icon": "{icon} {text}",
"ancestor_follow": "Pozri {numReplies} ďalšiu odpoveď pod touto správou | Pozri {numReplies} ďalších odpovedí pod touto správou",
"ancestor_follow_with_icon": "{icon} {text}",
"show_all_conversation_with_icon": "{icon} {text}",
"show_all_conversation": "Zobraz celú konverzáciu ({numStatus} iná správa) | Zobraz celú konverzáciu ({numStatus} iných správ)",
"show_only_conversation_under_this": "Zobraz len správy súvisiace s touto správou"
},
"user_card": {
"approve": "Schváliť",
"block": "Zablokovať",
"blocked": "Blokované!",
"deactivated": "Neaktívne",
"deny": "Zakázané",
"edit_profile": "Uraviť profil",
"favorites": "Obľúbené",
"follow": "Nasledovať",
"follow_cancel": "Požiadavka zrušená",
"follow_sent": "Požiadavka zaslaná!",
"follow_progress": "Žiadam o povolenie…",
"follow_unfollow": "Prestať sledovať",
"followees": "Nasleduje",
"followers": "Nasledovatelia",
"following": "Nasleduješ!",
"follows_you": "Nasleduje teba!",
"hidden": "Skryté",
"its_you": "To si ty!",
"media": "Média",
"mention": "Spomenul",
"message": "Správa",
"mute": "Stíšiť",
"muted": "Stíšené",
"per_day": "za deň",
"remote_follow": "Nasledovanie z ďaleka",
"report": "Nahlásiť",
"statuses": "Vytvorených správ",
"subscribe": "Prihlásiť k odberu",
"unsubscribe": "Odhlásiť z odberu",
"unblock": "Odblokovať",
"unblock_progress": "Oblokováva sa…",
"block_progress": "Blokujem…",
"unmute": "Povoliť oznamy",
"unmute_progress": "Povoľujem oznamy…",
"mute_progress": "Stišujem…",
"hide_repeats": "Skry zopakovania",
"show_repeats": "Zobraz zopakovania",
"bot": "Robot",
"admin_menu": {
"moderation": "Moderovanie",
"grant_admin": "Povoliť spravovanie",
"revoke_admin": "Zakázať spravovanie",
"grant_moderator": "Povoliť moderovanie",
"revoke_moderator": "Zakázať moderovanie",
"activate_account": "Aktivovať účet",
"deactivate_account": "Deaktivovať účet",
"delete_account": "Zmazať účet",
"force_nsfw": "Označ všetky správy ako NSFW",
"strip_media": "Odstrániť média zo správy",
"force_unlisted": "Vynúť, aby správy neboli zobrazované",
"sandbox": "Vynúť, aby správy boli len pre nasledovateľov",
"disable_remote_subscription": "Odstrániť prístup k serveru nasledovnému vzdialenému užívateľovi",
"disable_any_subscription": "Zakázať nasledovanie užívateľov",
"quarantine": "Zakázať federáciu správ užívateľa",
"delete_user": "Zmazať užívateľa",
"delete_user_confirmation": "Si si úplne istý? Táto akcia sa nedá zobrať späť."
},
"highlight": {
"disabled": "Bez zvýraznenia",
"solid": "Jednoliate pozadie",
"striped": "Šrafované pozadie",
"side": "Pásik na boku"
}
},
"user_profile": {
"timeline_title": "Časová os užívateľa",
"profile_does_not_exist": "Prepáč, tento profil neexistuje.",
"profile_loading_error": "Prepáč, nastala chyba pri nahrávaní profilu."
},
"user_reporting": {
"title": "Nahlásení {0}",
"add_comment_description": "Hlásnenie bude zaslané moderátorom servera. Nižšie môžeš napísať dôvod prečo tento účet nahlasuješ:",
"additional_comments": "Ďalšie poznámky",
"forward_description": "Účet je z iného servera. Poslať kópiu tohto hlásenia aj tam?",
"forward_to": "Preposlať komu {0}",
"submit": "Odoslať",
"generic_error": "Nastala chyba pri vykonaní tvojej požiadavky."
},
"who_to_follow": {
"more": "Viac",
"who_to_follow": "Koho nasledovať"
},
"tool_tip": {
"media_upload": "Nahrať médium",
"repeat": "Zopakovať",
"reply": "Odpovedať",
"favorite": "Obľúbené",
"add_reaction": "Reagovať",
"user_settings": "Nastavenia užívateľa",
"accept_follow_request": "Prijať požiadavku nasledovníka",
"reject_follow_request": "Odmietnuť požiadavku nasledovníka",
"bookmark": "Záložka"
},
"upload": {
"error": {
"base": "Nahrávanie bolo neúspešné.",
"message": "Nahrávanie bolo neúspešné: {0}",
"file_too_big": "Súbor je príliš veľký [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Vyskúšaj opäť neskôr"
}
},
"search": {
"people": "Ľudia",
"hashtags": "Haštagy",
"person_talking": "{count} človek hovorí",
"people_talking": "{count} ľudí hovorí",
"no_results": "Žiadne výsledky"
},
"password_reset": {
"forgot_password": "Zabudol si heslo?",
"password_reset": "Obnovenie hesla",
"instruction": "Zadaj svoju emailovú adresu alebo užívateľské meno. Pošleme ti odkaz pomocou, ktorého môžeš obnoviť svoje heslo.",
"placeholder": "Tvoj email alebo užívateľské meno",
"check_email": "V novom emaile ti bol doručený odkaz na spôsob, ako obnovíš svoje heslo.",
"return_home": "Návrat na domácu stránku",
"too_many_requests": "Prekročil si limit pokusov, skús znova neskôr.",
"password_reset_disabled": "Obnova hesla je vypnutá. Kontaktuj, prosím, správcu tohto servera.",
"password_reset_required": "Musíš najskôr obnoviť heslo, ak sa chceš prihlásiť.",
"password_reset_required_but_mailer_is_disabled": "Musíš obnoviť svoje heslo, ale obnova hesla je na serveri vypnutá. Kontaktuj, prosím, správcu tohto servera."
},
"chats": {
"you": "Ty:",
"message_user": "Správa {nickname}",
"delete": "Zmazať",
"chats": "Rozhovor",
"new": "Nový rozhovor",
"empty_message_error": "Nie je možné odoslať prázdnu správu",
"more": "Viac",
"delete_confirm": "Skutočne chceš zmazať túto správu?",
"error_loading_chat": "Nastala chyba pri nahrávaní rozhovoru.",
"error_sending_message": "Nastala chyba pri odosielaní správ.",
"empty_chat_list_placeholder": "Nemáš za sebou žiadne rozhovory. Začni nový rozhovor!"
},
"file_type": {
"audio": "Audio",
"video": "Video",
"image": "Obrázok",
"file": "Súbor"
},
"display_date": {
"today": "Dnes"
}
}

@ -755,7 +755,6 @@
"deactivate_account": "Деактивувати обліковий запис",
"delete_account": "Видалити обліковий запис",
"moderation": "Модерація",
"delete_user_confirmation": "Ви абсолютно впевнені? Цю дію неможливо буде скасовувати.",
"delete_user": "Видалити обліковий запис",
"strip_media": "Вилучити медіа з дописів користувача",
"force_nsfw": "Позначити всі дописи як NSFW",

@ -772,8 +772,7 @@
"quarantine": "Không cho phép tút liên hợp",
"delete_user": "Xóa người dùng",
"revoke_moderator": "Gỡ bỏ Quản trị viên",
"force_unlisted": "Đánh dấu tất cả tút là hạn chế",
"delete_user_confirmation": "Bạn chắc chắn chưa? Hành động này không thể phục hồi."
"force_unlisted": "Đánh dấu tất cả tút là hạn chế"
},
"highlight": {
"disabled": "Không nổi bật",

@ -714,8 +714,7 @@
"disable_remote_subscription": "禁止从远程实例关注用户",
"disable_any_subscription": "完全禁止关注用户",
"quarantine": "从联合实例中禁止用户帖子",
"delete_user": "删除用户",
"delete_user_confirmation": "你确定吗?此操作无法撤销。"
"delete_user": "删除用户"
},
"hidden": "已隐藏",
"show_repeats": "显示转发",

@ -747,7 +747,6 @@
"admin_menu": {
"delete_account": "刪除賬號",
"delete_user": "刪除用戶",
"delete_user_confirmation": "你確認嗎?此操作無法撤銷。",
"moderation": "調停",
"grant_admin": "賦予管理權限",
"revoke_admin": "撤銷管理權限",

@ -9,6 +9,8 @@ const FOLLOW_IMPORT_URL = '/api/pleroma/follow_import'
const DELETE_ACCOUNT_URL = '/api/pleroma/delete_account'
const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
const MOVE_ACCOUNT_URL = '/api/pleroma/move_account'
const ALIASES_URL = '/api/pleroma/aliases'
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
@ -87,6 +89,7 @@ const PLEROMA_CHAT_URL = id => `/api/v1/pleroma/chats/by-account-id/${id}`
const PLEROMA_CHAT_MESSAGES_URL = id => `/api/v1/pleroma/chats/${id}/messages`
const PLEROMA_CHAT_READ_URL = id => `/api/v1/pleroma/chats/${id}/read`
const PLEROMA_DELETE_CHAT_MESSAGE_URL = (chatId, messageId) => `/api/v1/pleroma/chats/${chatId}/messages/${messageId}`
const PLEROMA_BACKUP_URL = '/api/v1/pleroma/backups'
const oldfetch = window.fetch
@ -789,6 +792,49 @@ const changeEmail = ({ credentials, email, password }) => {
.then((response) => response.json())
}
const moveAccount = ({ credentials, password, targetAccount }) => {
const form = new FormData()
form.append('password', password)
form.append('target_account', targetAccount)
return fetch(MOVE_ACCOUNT_URL, {
body: form,
method: 'POST',
headers: authHeaders(credentials)
})
.then((response) => response.json())
}
const addAlias = ({ credentials, alias }) => {
return promisedRequest({
url: ALIASES_URL,
method: 'PUT',
credentials,
payload: { alias }
})
}
const deleteAlias = ({ credentials, alias }) => {
return promisedRequest({
url: ALIASES_URL,
method: 'DELETE',
credentials,
payload: { alias }
})
}
const listAliases = ({ credentials }) => {
return promisedRequest({
url: ALIASES_URL,
method: 'GET',
credentials,
params: {
_cacheBooster: (new Date()).getTime()
}
})
}
const changePassword = ({ credentials, password, newPassword, newPasswordConfirmation }) => {
const form = new FormData()
@ -875,6 +921,25 @@ const fetchBlocks = ({ credentials }) => {
.then((users) => users.map(parseUser))
}
const addBackup = ({ credentials }) => {
return promisedRequest({
url: PLEROMA_BACKUP_URL,
method: 'POST',
credentials
})
}
const listBackups = ({ credentials }) => {
return promisedRequest({
url: PLEROMA_BACKUP_URL,
method: 'GET',
credentials,
params: {
_cacheBooster: (new Date()).getTime()
}
})
}
const fetchOAuthTokens = ({ credentials }) => {
const url = '/api/oauth_tokens.json'
@ -1326,12 +1391,18 @@ const apiService = {
importFollows,
deleteAccount,
changeEmail,
moveAccount,
addAlias,
deleteAlias,
listAliases,
changePassword,
settingsMFA,
mfaDisableOTP,
generateMfaBackupCodes,
mfaSetupOTP,
mfaConfirmOTP,
addBackup,
listBackups,
fetchFollowRequests,
approveUser,
denyUser,

@ -10,31 +10,29 @@ export const relativeTime = (date, nowThreshold = 1) => {
if (typeof date === 'string') date = Date.parse(date)
const round = Date.now() > date ? Math.floor : Math.ceil
const d = Math.abs(Date.now() - date)
let r = { num: round(d / YEAR), key: 'time.years' }
let r = { num: round(d / YEAR), key: 'time.unit.years' }
if (d < nowThreshold * SECOND) {
r.num = 0
r.key = 'time.now'
} else if (d < MINUTE) {
r.num = round(d / SECOND)
r.key = 'time.seconds'
r.key = 'time.unit.seconds'
} else if (d < HOUR) {
r.num = round(d / MINUTE)
r.key = 'time.minutes'
r.key = 'time.unit.minutes'
} else if (d < DAY) {
r.num = round(d / HOUR)
r.key = 'time.hours'
r.key = 'time.unit.hours'
} else if (d < WEEK) {
r.num = round(d / DAY)
r.key = 'time.days'
r.key = 'time.unit.days'
} else if (d < MONTH) {
r.num = round(d / WEEK)
r.key = 'time.weeks'
r.key = 'time.unit.weeks'
} else if (d < YEAR) {
r.num = round(d / MONTH)
r.key = 'time.months'
r.key = 'time.unit.months'
}
// Remove plural form when singular
if (r.num === 1) r.key = r.key.slice(0, -1)
return r
}

@ -11,30 +11,30 @@ describe('DateUtils', () => {
it('rounds down for past', () => {
const time = Date.now() - 1.8 * DateUtils.HOUR
expect(DateUtils.relativeTime(time)).to.eql({ num: 1, key: 'time.hour' })
expect(DateUtils.relativeTime(time)).to.eql({ num: 1, key: 'time.unit.hours' })
})
it('rounds up for future', () => {
const time = Date.now() + 1.8 * DateUtils.HOUR
expect(DateUtils.relativeTime(time)).to.eql({ num: 2, key: 'time.hours' })
expect(DateUtils.relativeTime(time)).to.eql({ num: 2, key: 'time.unit.hours' })
})
it('uses plural when necessary', () => {
const time = Date.now() - 3.8 * DateUtils.WEEK
expect(DateUtils.relativeTime(time)).to.eql({ num: 3, key: 'time.weeks' })
expect(DateUtils.relativeTime(time)).to.eql({ num: 3, key: 'time.unit.weeks' })
})
it('works with date string', () => {
const time = Date.now() - 4 * DateUtils.MONTH
const dateString = new Date(time).toISOString()
expect(DateUtils.relativeTime(dateString)).to.eql({ num: 4, key: 'time.months' })
expect(DateUtils.relativeTime(dateString)).to.eql({ num: 4, key: 'time.unit.months' })
})
})
describe('relativeTimeShort', () => {
it('returns the short version of the same relative time', () => {
const time = Date.now() + 2 * DateUtils.YEAR
expect(DateUtils.relativeTimeShort(time)).to.eql({ num: 2, key: 'time.years_short' })
expect(DateUtils.relativeTimeShort(time)).to.eql({ num: 2, key: 'time.unit.years_short' })
})
})
})

Loading…
Cancel
Save