diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx
index d8810dc644b..b9086de4242 100644
--- a/app/assets/javascripts/components/containers/mastodon.jsx
+++ b/app/assets/javascripts/components/containers/mastodon.jsx
@@ -52,8 +52,8 @@ import no from 'react-intl/locale-data/no';
import ru from 'react-intl/locale-data/ru';
import uk from 'react-intl/locale-data/uk';
import zh from 'react-intl/locale-data/zh';
+import bg from 'react-intl/locale-data/bg';
import { localeData as zh_hk } from '../locales/zh-hk';
-
import getMessagesForLocale from '../locales';
import { hydrateStore } from '../actions/store';
import createStream from '../stream';
@@ -66,7 +66,6 @@ const browserHistory = useRouterHistory(createBrowserHistory)({
basename: '/web'
});
-
addLocaleData([
...en,
...de,
@@ -82,9 +81,9 @@ addLocaleData([
...uk,
...zh,
...zh_hk,
+ ...bg,
]);
-
const Mastodon = React.createClass({
propTypes: {
diff --git a/app/assets/javascripts/components/features/community_timeline/index.jsx b/app/assets/javascripts/components/features/community_timeline/index.jsx
index 0957338cfac..acfc30b655a 100644
--- a/app/assets/javascripts/components/features/community_timeline/index.jsx
+++ b/app/assets/javascripts/components/features/community_timeline/index.jsx
@@ -14,7 +14,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import createStream from '../../stream';
const messages = defineMessages({
- title: { id: 'column.community', defaultMessage: 'Local' }
+ title: { id: 'column.community', defaultMessage: 'Local timeline' }
});
const mapStateToProps = state => ({
diff --git a/app/assets/javascripts/components/features/compose/components/compose_form.jsx b/app/assets/javascripts/components/features/compose/components/compose_form.jsx
index cb4b62f6cf1..d2e65359fb1 100644
--- a/app/assets/javascripts/components/features/compose/components/compose_form.jsx
+++ b/app/assets/javascripts/components/features/compose/components/compose_form.jsx
@@ -19,7 +19,7 @@ import TextIconButton from './text_icon_button';
const messages = defineMessages({
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Content warning' },
- publish: { id: 'compose_form.publish', defaultMessage: 'Publish' }
+ publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }
});
const ComposeForm = React.createClass({
diff --git a/app/assets/javascripts/components/features/compose/index.jsx b/app/assets/javascripts/components/features/compose/index.jsx
index 9421de3ff5e..33e16472c44 100644
--- a/app/assets/javascripts/components/features/compose/index.jsx
+++ b/app/assets/javascripts/components/features/compose/index.jsx
@@ -12,7 +12,7 @@ import SearchResultsContainer from './containers/search_results_container';
const messages = defineMessages({
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
- public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Whole Known Network' },
+ public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }
diff --git a/app/assets/javascripts/components/features/getting_started/index.jsx b/app/assets/javascripts/components/features/getting_started/index.jsx
index 0656bf69af6..05bfcc22138 100644
--- a/app/assets/javascripts/components/features/getting_started/index.jsx
+++ b/app/assets/javascripts/components/features/getting_started/index.jsx
@@ -7,11 +7,11 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
const messages = defineMessages({
heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
- public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Whole Known Network' },
+ public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
- sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Sign out' },
+ sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' }
diff --git a/app/assets/javascripts/components/features/public_timeline/index.jsx b/app/assets/javascripts/components/features/public_timeline/index.jsx
index 6d766a83b29..a7ac95ab44b 100644
--- a/app/assets/javascripts/components/features/public_timeline/index.jsx
+++ b/app/assets/javascripts/components/features/public_timeline/index.jsx
@@ -14,7 +14,7 @@ import ColumnBackButtonSlim from '../../components/column_back_button_slim';
import createStream from '../../stream';
const messages = defineMessages({
- title: { id: 'column.public', defaultMessage: 'Whole Known Network' }
+ title: { id: 'column.public', defaultMessage: 'Federated timeline' }
});
const mapStateToProps = state => ({
diff --git a/app/assets/javascripts/components/locales/bg.jsx b/app/assets/javascripts/components/locales/bg.jsx
new file mode 100644
index 00000000000..cac984aae8a
--- /dev/null
+++ b/app/assets/javascripts/components/locales/bg.jsx
@@ -0,0 +1,68 @@
+const bg = {
+ "column_back_button.label": "Назад",
+ "lightbox.close": "Затвори",
+ "loading_indicator.label": "Зареждане...",
+ "status.mention": "Споменаване",
+ "status.delete": "Изтриване",
+ "status.reply": "Отговор",
+ "status.reblog": "Споделяне",
+ "status.favourite": "Предпочитани",
+ "status.reblogged_by": "{name} сподели",
+ "status.sensitive_warning": "Деликатно съдържание",
+ "status.sensitive_toggle": "Покажи",
+ "video_player.toggle_sound": "Звук",
+ "account.mention": "Споменаване",
+ "account.edit_profile": "Редактирай профила си",
+ "account.unblock": "Не блокирай",
+ "account.unfollow": "Не следвай",
+ "account.block": "Блокирай",
+ "account.follow": "Последвай",
+ "account.posts": "Публикации",
+ "account.follows": "Следвам",
+ "account.followers": "Последователи",
+ "account.follows_you": "Твой последовател",
+ "account.requested": "В очакване на одобрение",
+ "getting_started.heading": "Първи стъпки",
+ "getting_started.about_addressing": "Можеш да последваш потребител, ако знаеш потребителското му име и домейна, на който се намира, като в полето за търсене ги въведеш по този начин: име@домейн",
+ "getting_started.about_shortcuts": "Ако с търсения потребител се намирате на един и същ домейн, достатъчно е да въведеш само името. Същото важи и за споменаване на хора в публикации.",
+ "getting_started.about_developer": "Можеш да потърсиш разработчика на този проект като: Gargron@mastodon.social",
+ "getting_started.open_source_notice": "Mastodon е софтуер с отворен код. Можеш да помогнеш или да докладваш за проблеми в Github: {github}.",
+ "column.home": "Начало",
+ "column.mentions": "Споменавания",
+ "column.public": "Публичен канал",
+ "column.notifications": "Известия",
+ "tabs_bar.compose": "Съставяне",
+ "tabs_bar.home": "Начало",
+ "tabs_bar.mentions": "Споменавания",
+ "tabs_bar.public": "Публичен канал",
+ "tabs_bar.notifications": "Известия",
+ "compose_form.placeholder": "Какво си мислиш?",
+ "compose_form.publish": "Раздумай",
+ "compose_form.sensitive": "Отбележи съдържанието като деликатно",
+ "compose_form.spoiler": "Скрий текста зад предупреждение",
+ "compose_form.private": "Отбележи като поверително",
+ "compose_form.privacy_disclaimer": "Поверителни публикации ще бъдат изпратени до споменатите потребители на {domains}. Доверяваш ли се на {domainsCount, plural, one {that server} other {those servers}}, че няма да издаде твоята публикация?",
+ "compose_form.unlisted": "Не показвай в публичния канал",
+ "navigation_bar.edit_profile": "Редактирай профил",
+ "navigation_bar.preferences": "Предпочитания",
+ "navigation_bar.public_timeline": "Публичен канал",
+ "navigation_bar.logout": "Излизане",
+ "reply_indicator.cancel": "Отказ",
+ "search.placeholder": "Търсене",
+ "search.account": "Акаунт",
+ "search.hashtag": "Хаштаг",
+ "upload_button.label": "Добави медия",
+ "upload_form.undo": "Отмяна",
+ "notification.follow": "{name} те последва",
+ "notification.favourite": "{name} хареса твоята публикация",
+ "notification.reblog": "{name} сподели твоята публикация",
+ "notification.mention": "{name} те спомена",
+ "notifications.column_settings.alert": "Десктоп известия",
+ "notifications.column_settings.show": "Покажи в колона",
+ "notifications.column_settings.follow": "Нови последователи:",
+ "notifications.column_settings.favourite": "Предпочитани:",
+ "notifications.column_settings.mention": "Споменавания:",
+ "notifications.column_settings.reblog": "Споделяния:",
+};
+
+export default en;
diff --git a/app/assets/javascripts/components/locales/en.jsx b/app/assets/javascripts/components/locales/en.jsx
index f249b196774..1834567f17b 100644
--- a/app/assets/javascripts/components/locales/en.jsx
+++ b/app/assets/javascripts/components/locales/en.jsx
@@ -1,72 +1,129 @@
+/**
+ * Note for Contributors:
+ * This file (en.jsx) serve as a template for other languages.
+ * To make other contributors' life easier, please REMEMBER:
+ * 1. to add your new string here; and
+ * 2. to remove old strings that are no longer needed; and
+ * 3. to sort the strings by the key.
+ * Thanks!
+ */
const en = {
- "column_back_button.label": "Back",
- "lightbox.close": "Close",
- "loading_indicator.label": "Loading...",
- "status.mention": "Mention @{name}",
- "status.delete": "Delete",
- "status.reply": "Reply",
- "status.reblog": "Boost",
- "status.favourite": "Favourite",
- "status.reblogged_by": "{name} boosted",
- "status.sensitive_warning": "Sensitive content",
- "status.sensitive_toggle": "Click to view",
- "status.show_more": "Show more",
- "status.show_less": "Show less",
- "status.open": "Expand this status",
- "status.report": "Report @{name}",
- "video_player.toggle_sound": "Toggle sound",
- "account.mention": "Mention @{name}",
- "account.edit_profile": "Edit profile",
- "account.unblock": "Unblock @{name}",
- "account.unfollow": "Unfollow",
"account.block": "Block @{name}",
+ "account.disclaimer": "This user is from another instance. This number may be larger.",
+ "account.edit_profile": "Edit profile",
"account.follow": "Follow",
- "account.posts": "Posts",
- "account.follows": "Follows",
"account.followers": "Followers",
"account.follows_you": "Follows you",
+ "account.follows": "Follows",
+ "account.mention": "Mention @{name}",
+ "account.mute": "Mute @{name}",
+ "account.posts": "Posts",
+ "account.report": "Report @{name}",
"account.requested": "Awaiting approval",
- "getting_started.heading": "Getting started",
- "getting_started.about_addressing": "You can follow people if you know their username and the domain they are on by entering an e-mail-esque address into the search form.",
- "getting_started.about_shortcuts": "If the target user is on the same domain as you, just the username will work. The same rule applies to mentioning people in statuses.",
- "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}. {apps}.",
- "column.home": "Home",
+ "account.unblock": "Unblock @{name}",
+ "account.unfollow": "Unfollow",
+ "account.unmute": "Unmute @{name}",
+ "boost_modal.combo": "You can press {combo} to skip this next time",
+ "column_back_button.label": "Back",
+ "column.blocks": "Blocked users",
"column.community": "Local timeline",
- "column.public": "Federated timeline",
+ "column.favourites": "Favourites",
+ "column.follow_requests": "Follow requests",
+ "column.home": "Home",
"column.notifications": "Notifications",
- "tabs_bar.compose": "Compose",
- "tabs_bar.home": "Home",
- "tabs_bar.mentions": "Mentions",
- "tabs_bar.public": "Federated timeline",
- "tabs_bar.notifications": "Notifications",
+ "column.public": "Federated timeline",
"compose_form.placeholder": "What is on your mind?",
+ "compose_form.privacy_disclaimer": "Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.",
"compose_form.publish": "Toot",
"compose_form.sensitive": "Mark media as sensitive",
+ "compose_form.spoiler_placeholder": "Content warning",
"compose_form.spoiler": "Hide text behind warning",
- "compose_form.private": "Mark as private",
- "compose_form.privacy_disclaimer": "Your private status will be delivered to mentioned users on {domains}. Do you trust {domainsCount, plural, one {that server} other {those servers}}? Post privacy only works on Mastodon instances. If {domains} {domainsCount, plural, one {is not a Mastodon instance} other {are not Mastodon instances}}, there will be no indication that your post is private, and it may be boosted or otherwise made visible to unintended recipients.",
- "compose_form.unlisted": "Do not display on public timelines",
- "navigation_bar.edit_profile": "Edit profile",
- "navigation_bar.preferences": "Preferences",
+ "emoji_button.label": "Insert emoji",
+ "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
+ "empty_column.hashtag": "There is nothing in this hashtag yet.",
+ "empty_column.home.public_timeline": "the public timeline",
+ "empty_column.home": "You aren't following anyone yet. Visit {public} or use search to get started and meet other users.",
+ "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
+ "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
+ "follow_request.authorize": "Authorize",
+ "follow_request.reject": "Rejec",
+ "getting_started.apps": "Various apps are available",
+ "getting_started.heading": "Getting started",
+ "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}. {apps}.",
+ "home.column_settings.advanced": "Advanced",
+ "home.column_settings.basic": "Basic",
+ "home.column_settings.filter_regex": "Filter out by regular expressions",
+ "home.column_settings.show_reblogs": "Show boosts",
+ "home.column_settings.show_replies": "Show replies",
+ "home.settings": "Column settings",
+ "lightbox.close": "Close",
+ "loading_indicator.label": "Loading...",
+ "media_gallery.toggle_visible": "Toggle visibility",
+ "missing_indicator.label": "Not found",
+ "navigation_bar.blocks": "Blocked users",
"navigation_bar.community_timeline": "Local timeline",
- "navigation_bar.public_timeline": "Federated timeline",
+ "navigation_bar.edit_profile": "Edit profile",
+ "navigation_bar.favourites": "Favourites",
+ "navigation_bar.follow_requests": "Follow requests",
+ "navigation_bar.info": "Extended information",
"navigation_bar.logout": "Logout",
- "reply_indicator.cancel": "Cancel",
- "search.placeholder": "Search",
- "search.account": "Account",
- "search.hashtag": "Hashtag",
- "upload_button.label": "Add media",
- "upload_form.undo": "Undo",
- "notification.follow": "{name} followed you",
+ "navigation_bar.preferences": "Preferences",
+ "navigation_bar.public_timeline": "Federated timeline",
"notification.favourite": "{name} favourited your status",
+ "notification.follow": "{name} followed you",
"notification.reblog": "{name} boosted your status",
- "notification.mention": "{name} mentioned you",
+ "notifications.clear_confirmation": "Are you sure you want to clear all your notifications?",
+ "notifications.clear": "Clear notifications",
"notifications.column_settings.alert": "Desktop notifications",
- "notifications.column_settings.show": "Show in column",
- "notifications.column_settings.follow": "New followers:",
"notifications.column_settings.favourite": "Favourites:",
+ "notifications.column_settings.follow": "New followers:",
"notifications.column_settings.mention": "Mentions:",
"notifications.column_settings.reblog": "Boosts:",
+ "notifications.column_settings.show": "Show in column",
+ "notifications.column_settings.sound": "Play sound",
+ "notifications.settings": "Column settings",
+ "privacy.change": "Adjust status privacy",
+ "privacy.direct.long": "Post to mentioned users only",
+ "privacy.direct.short": "Direct",
+ "privacy.private.long": "Post to followers only",
+ "privacy.private.short": "Private",
+ "privacy.public.long": "Post to public timelines",
+ "privacy.public.short": "Public",
+ "privacy.unlisted.long": "Do not show in public timelines",
+ "privacy.unlisted.short": "Unlisted",
+ "reply_indicator.cancel": "Cancel",
+ "report.heading": "New report",
+ "report.placeholder": "Additional comments",
+ "report.submit": "Submit",
+ "report.target": "Reporting",
+ "search_results.total": "{count} {count, plural, one {result} other {results}}",
+ "search.placeholder": "Search",
+ "search.status_by": "Status by {name}",
+ "status.delete": "Delete",
+ "status.favourite": "Favourite",
+ "status.load_more": "Load more",
+ "status.media_hidden": "Media hidden",
+ "status.mention": "Mention @{name}",
+ "status.open": "Expand this status",
+ "status.reblog": "Boost",
+ "status.reblogged_by": "{name} boosted",
+ "status.reply": "Reply",
+ "status.report": "Report @{name}",
+ "status.sensitive_toggle": "Click to view",
+ "status.sensitive_warning": "Sensitive content",
+ "status.show_less": "Show less",
+ "status.show_more": "Show more",
+ "tabs_bar.compose": "Compose",
+ "tabs_bar.federated_timeline": "Federated",
+ "tabs_bar.home": "Home",
+ "tabs_bar.local_timeline": "Local",
+ "tabs_bar.notifications": "Notifications",
+ "upload_area.title": "Drag & drop to upload",
+ "upload_button.label": "Add media",
+ "upload_form.undo": "Undo",
+ "upload_progress.label": "Uploading...",
+ "video_player.toggle_sound": "Toggle sound",
+ "video_player.toggle_visible": "Toggle visibility",
};
export default en;
diff --git a/app/assets/javascripts/components/locales/index.jsx b/app/assets/javascripts/components/locales/index.jsx
index e772c107443..f14568a3d51 100644
--- a/app/assets/javascripts/components/locales/index.jsx
+++ b/app/assets/javascripts/components/locales/index.jsx
@@ -11,7 +11,7 @@ import eo from './eo';
import ru from './ru';
import ja from './ja';
import zh_hk from './zh-hk';
-
+import bg from './bg';
const locales = {
en,
@@ -27,6 +27,7 @@ const locales = {
ru,
ja,
'zh-HK': zh_hk,
+ bg,
};
export default function getMessagesForLocale (locale) {
diff --git a/app/assets/javascripts/components/locales/ja.jsx b/app/assets/javascripts/components/locales/ja.jsx
index 25a6f7f675b..fdfc91c29ff 100644
--- a/app/assets/javascripts/components/locales/ja.jsx
+++ b/app/assets/javascripts/components/locales/ja.jsx
@@ -39,8 +39,8 @@ const ja = {
"tabs_bar.compose": "投稿",
"tabs_bar.home": "ホーム",
"tabs_bar.mentions": "返信",
- "tabs_bar.local_timeline": "ローカルTL",
- "tabs_bar.federated_timeline": "連合TL",
+ "tabs_bar.local_timeline": "ローカル",
+ "tabs_bar.federated_timeline": "連合",
"tabs_bar.notifications": "通知",
"compose_form.placeholder": "今なにしてる?",
"compose_form.publish": "トゥート",
diff --git a/app/assets/javascripts/components/locales/pt.jsx b/app/assets/javascripts/components/locales/pt.jsx
index 8d1b88c752b..cd345a585b5 100644
--- a/app/assets/javascripts/components/locales/pt.jsx
+++ b/app/assets/javascripts/components/locales/pt.jsx
@@ -14,59 +14,115 @@ const pt = {
"status.show_less": "Mostrar menos",
"status.open": "Expandir",
"status.report": "Reportar @{name}",
+ "status.load_more": "Carregar mais",
+ "status.media_hidden": "Media escondida",
"video_player.toggle_sound": "Ligar/Desligar som",
+ "video_player.toggle_visible": "Ligar/Desligar vídeo",
"account.mention": "Mencionar @{name}",
"account.edit_profile": "Editar perfil",
"account.unblock": "Não bloquear @{name}",
"account.unfollow": "Não seguir",
"account.block": "Bloquear @{name}",
+ "account.mute": "Mute",
+ "account.unmute": "Remover Mute",
"account.follow": "Seguir",
"account.posts": "Posts",
"account.follows": "Segue",
"account.followers": "Seguidores",
"account.follows_you": "É teu seguidor",
"account.requested": "A aguardar aprovação",
+ "account.report": "Denunciar",
+ "account.disclaimer": "Essa conta está localizado em outra instância. Os nomes podem ser maiores.",
"getting_started.heading": "Primeiros passos",
"getting_started.about_addressing": "Podes seguir pessoas se sabes o nome de usuário deles e o domínio em que estão colocando um endereço similar a e-mail no campo no topo da barra lateral.",
"getting_started.about_shortcuts": "Se o usuário alvo está no mesmo domínio, só o nome funcionará. A mesma regra se aplica a mencionar pessoas nas postagens.",
+ "getting_started.about_developer": "Pode seguir o developer deste projecto em Gargron@mastodon.social",
"getting_started.open_source_notice": "Mastodon é software de fonte aberta. Podes contribuir ou repostar problemas no GitHub do projecto: {github}. {apps}.",
"column.home": "Home",
"column.community": "Local",
- "column.public": "Público",
+ "column.public": "Global",
"column.notifications": "Notificações",
+ "column.blocks": "Utilizadores Bloqueados",
+ "column.favourites": "Favoritos",
+ "column.follow_requests": "Seguidores Pendentes",
+ "empty_column.notifications": "Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.",
+ "empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para ver aqui os conteúdos públicos.",
+ "empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.",
+ "empty_column.home.public_timeline": "global",
+ "empty_column.community": "Ainda não existem conteúdo local para mostrar!",
+ "empty_column.hashtag": "Não existe qualquer conteúdo com essa hashtag",
"tabs_bar.compose": "Criar",
"tabs_bar.home": "Home",
"tabs_bar.mentions": "Menções",
"tabs_bar.public": "Público",
"tabs_bar.notifications": "Notificações",
+ "tabs_bar.local_timeline": "Local",
+ "tabs_bar.federated_timeline": "Global",
"compose_form.placeholder": "Em que estás a pensar?",
"compose_form.publish": "Publicar",
- "compose_form.sensitive": "Media com conteúdo sensível",
+ "compose_form.sensitive": "Marcar media como conteúdo sensível",
"compose_form.spoiler": "Esconder texto com aviso",
+ "compose_form.spoiler_placeholder": "Aviso",
"compose_form.private": "Tornar privado",
"compose_form.privacy_disclaimer": "O teu conteúdo privado vai ser partilhado com os utilizadores do {domains}. Confias {domainsCount, plural, one {neste servidor} other {nestes servidores}}? A privacidade só funciona em instâncias do Mastodon. Se {domains} {domainsCount, plural, one {não é uma instância} other {não são instâncias}}, não existem indicadores da privacidade da tua partilha, e podem ser partilhados com outros.",
"compose_form.unlisted": "Não mostrar na listagem pública",
+ "emoji_button.label": "Inserir Emoji",
"navigation_bar.edit_profile": "Editar perfil",
"navigation_bar.preferences": "Preferências",
"navigation_bar.community_timeline": "Local",
- "navigation_bar.public_timeline": "Público",
+ "navigation_bar.public_timeline": "Global",
+ "navigation_bar.blocks": "Utilizadores bloqueados",
+ "navigation_bar.favourites": "Favoritos",
+ "navigation_bar.info": "Mais informações",
"navigation_bar.logout": "Sair",
+ "navigation_bar.follow_requests": "Seguidores pendentes",
"reply_indicator.cancel": "Cancelar",
"search.placeholder": "Pesquisar",
"search.account": "Conta",
"search.hashtag": "Hashtag",
+ "search_results.total": "{count} {count, plural, one {resultado} other {resultados}}",
+ "search.status_by": "Post de {name}",
"upload_button.label": "Adicionar media",
"upload_form.undo": "Anular",
+ "upload_progress.label": "A gravar…",
+ "upload_area.title": "Arraste e solte para enviar",
"notification.follow": "{name} seguiu-te",
"notification.favourite": "{name} adicionou o teu post aos favoritos",
"notification.reblog": "{name} partilhou o teu post",
"notification.mention": "{name} mencionou-te",
"notifications.column_settings.alert": "Notificações no computador",
"notifications.column_settings.show": "Mostrar nas colunas",
+ "notifications.column_settings.sound": "Reproduzir som",
"notifications.column_settings.follow": "Novos seguidores:",
"notifications.column_settings.favourite": "Favoritos:",
"notifications.column_settings.mention": "Menções:",
"notifications.column_settings.reblog": "Partilhas:",
+ "notifications.clear": "Limpar notificações",
+ "notifications.clear_confirmation": "Queres mesmo limpar todas as notificações?",
+ "notifications.settings": "Parâmetros da lista de Notificações",
+ "privacy.public.short": "Público",
+ "privacy.public.long": "Publicar em todos os feeds",
+ "privacy.unlisted.short": "Não listar",
+ "privacy.unlisted.long": "Não publicar nos feeds públicos",
+ "privacy.private.short": "Privado",
+ "privacy.private.long": "Apenas para os seguidores",
+ "privacy.direct.short": "Directo",
+ "privacy.direct.long": "Apenas para utilizadores mencionados",
+ "privacy.change": "Ajustar a privacidade da mensagem",
+ "media_gallery.toggle_visible": "Modificar a visibilidade",
+ "missing_indicator.label": "Não encontrado",
+ "follow_request.authorize": "Autorizar",
+ "follow_request.reject": "Rejeitar",
+ "home.settings": "Parâmetros da coluna Home",
+ "home.column_settings.basic": "Básico",
+ "home.column_settings.show_reblogs": "Mostrar as partilhas",
+ "home.column_settings.show_replies": "Mostrar as respostas",
+ "home.column_settings.advanced": "Avançadas",
+ "home.column_settings.filter_regex": "Filtrar com uma expressão regular",
+ "report.heading": "Nova denuncia",
+ "report.placeholder": "Comentários adicionais",
+ "report.submit": "Enviar",
+ "report.target": "Denunciar"
};
export default pt;
diff --git a/app/assets/javascripts/components/locales/ru.jsx b/app/assets/javascripts/components/locales/ru.jsx
index e109005a7ce..30a92df8666 100644
--- a/app/assets/javascripts/components/locales/ru.jsx
+++ b/app/assets/javascripts/components/locales/ru.jsx
@@ -10,22 +10,29 @@ const ru = {
"status.reblogged_by": "{name} продвинул(а)",
"status.sensitive_warning": "Чувствительный контент",
"status.sensitive_toggle": "Нажмите для просмотра",
+ "status.show_more": "Развернуть",
+ "status.show_less": "Свернуть",
+ "status.open": "Развернуть статус",
+ "status.report": "Пожаловаться",
+ "status.load_more": "Показать еще",
"video_player.toggle_sound": "Вкл./выкл. звук",
- "account.mention": "Упомянуть @{name}",
+ "account.mention": "Упомянуть",
"account.edit_profile": "Изменить профиль",
- "account.unblock": "Разблокировать @{name}",
+ "account.unblock": "Разблокировать",
"account.unfollow": "Отписаться",
- "account.block": "Блокировать @{name}",
+ "account.block": "Блокировать",
+ "account.mute": "Заглушить",
"account.follow": "Подписаться",
"account.posts": "Посты",
"account.follows": "Подписки",
- "account.followers": "Подписчики",
+ "account.followers": "Подписаны",
"account.follows_you": "Подписан(а) на Вас",
"account.requested": "Ожидает подтверждения",
"getting_started.heading": "Добро пожаловать",
"getting_started.about_addressing": "Вы можете подписаться на человека, зная имя пользователя и домен, на котором он находится, введя e-mail-подобный адрес в форму поиска.",
"getting_started.about_shortcuts": "Если пользователь находится на одном с Вами домене, можно использовать только имя. То же правило применимо к упоминанию пользователей в статусах.",
"getting_started.open_source_notice": "Mastodon - программа с открытым исходным кодом. Вы можете помочь проекту или сообщить о проблемах на GitHub по адресу {github}. {apps}.",
+ "getting_started.apps": "Доступны различные приложения.",
"column.home": "Главная",
"column.community": "Локальная лента",
"column.public": "Глобальная лента",
@@ -36,7 +43,7 @@ const ru = {
"tabs_bar.public": "Глобальная лента",
"tabs_bar.notifications": "Уведомления",
"compose_form.placeholder": "О чем Вы думаете?",
- "compose_form.publish": "Протрубить",
+ "compose_form.publish": "Трубить",
"compose_form.sensitive": "Отметить как чувствительный контент",
"compose_form.spoiler": "Скрыть текст за предупреждением",
"compose_form.private": "Отметить как приватное",
@@ -47,6 +54,9 @@ const ru = {
"navigation_bar.community_timeline": "Локальная лента",
"navigation_bar.public_timeline": "Глобальная лента",
"navigation_bar.logout": "Выйти",
+ "navigation_bar.info": "Об узле",
+ "navigation_bar.favourites": "Понравившееся",
+ "navigation_bar.blocks": "Список блокировки",
"reply_indicator.cancel": "Отмена",
"search.placeholder": "Поиск",
"search.account": "Аккаунт",
@@ -57,12 +67,35 @@ const ru = {
"notification.favourite": "{name} понравился Ваш статус",
"notification.reblog": "{name} продвинул(а) Ваш статус",
"notification.mention": "{name} упомянул(а) Вас",
+ "home.settings": "Настройки колонки",
+ "home.column_settings.basic": "Основные",
+ "home.column_settings.advanced": "Дополнительные",
+ "home.column_settings.filter_regex": "Отфильтровать регулярным выражением",
+ "home.column_settings.show_replies": "Показывать продвижения",
+ "home.column_settings.show_replies": "Показывать ответы",
+ "notifications.clear": "Очистить уведомления",
+ "notifications.settings": "Настройки колонки",
"notifications.column_settings.alert": "Десктопные уведомления",
"notifications.column_settings.show": "Показывать в колонке",
"notifications.column_settings.follow": "Новые подписчики:",
"notifications.column_settings.favourite": "Нравится:",
"notifications.column_settings.mention": "Упоминания:",
"notifications.column_settings.reblog": "Продвижения:",
+ "notifications.column_settings.sound": "Проигрывать звук",
+ "empty_column.notifications": "У Вас еще нет уведомлений. Заведите знакомство с другими пользователями, чтобы начать разговор.",
+ "empty_column.hashtag": "Статусов с таким хэштегом еще не существует.",
+ "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!",
+ "empty_column.public": "Здесь ничего нет! Опубликуйте что-нибудь или подпишитесь на пользователей с других узлов, чтобы заполнить ленту.",
+ "empty_column.home": "Пока Вы ни на кого не подписаны. Полистайте {public} или используйте поиск, чтобы освоиться и завести новые знакомства.",
+ "empty_column.home.public_timeline": "публичные ленты",
+ "privacy.public.short": "Публичный",
+ "privacy.public.long": "Показать в публичных лентах",
+ "privacy.unlisted.short": "Скрытый",
+ "privacy.unlisted.long": "Не показывать в лентах",
+ "privacy.private.short": "Приватный",
+ "privacy.private.long": "Показать только подписчикам",
+ "privacy.direct.short": "Направленный",
+ "privacy.direct.long": "Показать только упомянутым",
};
export default ru;
diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss
index 2e3a4f147f8..e5e8697a037 100644
--- a/app/assets/stylesheets/forms.scss
+++ b/app/assets/stylesheets/forms.scss
@@ -88,7 +88,7 @@ code {
}
}
- input[type=text], input[type=email], input[type=password], textarea {
+ input[type=text], input[type=number], input[type=email], input[type=password], textarea {
background: transparent;
box-sizing: border-box;
border: 0;
diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb
index 71cb8edd876..0e9e52f42a1 100644
--- a/app/controllers/admin/accounts_controller.rb
+++ b/app/controllers/admin/accounts_controller.rb
@@ -2,49 +2,29 @@
module Admin
class AccountsController < BaseController
- before_action :set_account, except: :index
-
def index
- @accounts = Account.alphabetic.page(params[:page])
-
- @accounts = @accounts.local if params[:local].present?
- @accounts = @accounts.remote if params[:remote].present?
- @accounts = @accounts.where(domain: params[:by_domain]) if params[:by_domain].present?
- @accounts = @accounts.silenced if params[:silenced].present?
- @accounts = @accounts.recent if params[:recent].present?
- @accounts = @accounts.suspended if params[:suspended].present?
+ @accounts = filtered_accounts.page(params[:page])
end
- def show; end
-
- def suspend
- Admin::SuspensionWorker.perform_async(@account.id)
- redirect_to admin_accounts_path
- end
-
- def unsuspend
- @account.update(suspended: false)
- redirect_to admin_accounts_path
- end
-
- def silence
- @account.update(silenced: true)
- redirect_to admin_accounts_path
- end
-
- def unsilence
- @account.update(silenced: false)
- redirect_to admin_accounts_path
+ def show
+ @account = Account.find(params[:id])
end
private
- def set_account
- @account = Account.find(params[:id])
+ def filtered_accounts
+ AccountFilter.new(filter_params).results
end
- def account_params
- params.require(:account).permit(:silenced, :suspended)
+ def filter_params
+ params.permit(
+ :local,
+ :remote,
+ :by_domain,
+ :silenced,
+ :recent,
+ :suspended
+ )
end
end
end
diff --git a/app/controllers/admin/silences_controller.rb b/app/controllers/admin/silences_controller.rb
new file mode 100644
index 00000000000..81a3008b96e
--- /dev/null
+++ b/app/controllers/admin/silences_controller.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Admin
+ class SilencesController < BaseController
+ before_action :set_account
+
+ def create
+ @account.update(silenced: true)
+ redirect_to admin_accounts_path
+ end
+
+ def destroy
+ @account.update(silenced: false)
+ redirect_to admin_accounts_path
+ end
+
+ private
+
+ def set_account
+ @account = Account.find(params[:account_id])
+ end
+ end
+end
diff --git a/app/controllers/admin/suspensions_controller.rb b/app/controllers/admin/suspensions_controller.rb
new file mode 100644
index 00000000000..5d9048d94df
--- /dev/null
+++ b/app/controllers/admin/suspensions_controller.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Admin
+ class SuspensionsController < BaseController
+ before_action :set_account
+
+ def create
+ Admin::SuspensionWorker.perform_async(@account.id)
+ redirect_to admin_accounts_path
+ end
+
+ def destroy
+ @account.update(suspended: false)
+ redirect_to admin_accounts_path
+ end
+
+ private
+
+ def set_account
+ @account = Account.find(params[:account_id])
+ end
+ end
+end
diff --git a/app/controllers/settings/exports/base_controller.rb b/app/controllers/settings/exports/base_controller.rb
index 0b790959fec..c082ed806c4 100644
--- a/app/controllers/settings/exports/base_controller.rb
+++ b/app/controllers/settings/exports/base_controller.rb
@@ -6,7 +6,7 @@ module Settings
before_action :authenticate_user!
def index
- export_data = Export.new(export_accounts).to_csv
+ @export = Export.new(current_account)
respond_to do |format|
format.csv { send_data export_data, filename: export_filename }
diff --git a/app/controllers/settings/exports/blocked_accounts_controller.rb b/app/controllers/settings/exports/blocked_accounts_controller.rb
index 9c4bcaa5320..f1115b21e31 100644
--- a/app/controllers/settings/exports/blocked_accounts_controller.rb
+++ b/app/controllers/settings/exports/blocked_accounts_controller.rb
@@ -5,8 +5,8 @@ module Settings
class BlockedAccountsController < BaseController
private
- def export_accounts
- current_account.blocking
+ def export_data
+ @export.to_blocked_accounts_csv
end
end
end
diff --git a/app/controllers/settings/exports/following_accounts_controller.rb b/app/controllers/settings/exports/following_accounts_controller.rb
index 8d06bcc9549..0011d2463a1 100644
--- a/app/controllers/settings/exports/following_accounts_controller.rb
+++ b/app/controllers/settings/exports/following_accounts_controller.rb
@@ -5,8 +5,8 @@ module Settings
class FollowingAccountsController < BaseController
private
- def export_accounts
- current_account.following
+ def export_data
+ @export.to_following_accounts_csv
end
end
end
diff --git a/app/controllers/settings/exports/muted_accounts_controller.rb b/app/controllers/settings/exports/muted_accounts_controller.rb
index a77a9af6d6a..dfe72cfcb9e 100644
--- a/app/controllers/settings/exports/muted_accounts_controller.rb
+++ b/app/controllers/settings/exports/muted_accounts_controller.rb
@@ -5,8 +5,8 @@ module Settings
class MutedAccountsController < BaseController
private
- def export_accounts
- current_account.muting
+ def export_data
+ @export.to_muted_accounts_csv
end
end
end
diff --git a/app/controllers/settings/exports_controller.rb b/app/controllers/settings/exports_controller.rb
index 77dea323164..ae62f00c1e2 100644
--- a/app/controllers/settings/exports_controller.rb
+++ b/app/controllers/settings/exports_controller.rb
@@ -6,9 +6,6 @@ class Settings::ExportsController < ApplicationController
before_action :authenticate_user!
def show
- @total_storage = current_account.media_attachments.sum(:file_file_size)
- @total_follows = current_account.following.count
- @total_blocks = current_account.blocking.count
- @total_mutes = current_account.muting.count
+ @export = Export.new(current_account)
end
end
diff --git a/app/controllers/well_known/host_meta_controller.rb b/app/controllers/well_known/host_meta_controller.rb
new file mode 100644
index 00000000000..2f0960acdb4
--- /dev/null
+++ b/app/controllers/well_known/host_meta_controller.rb
@@ -0,0 +1,13 @@
+ # frozen_string_literal: true
+
+module WellKnown
+ class HostMetaController < ApplicationController
+ def show
+ @webfinger_template = "#{webfinger_url}?resource={uri}"
+
+ respond_to do |format|
+ format.xml { render content_type: 'application/xrd+xml' }
+ end
+ end
+ end
+end
diff --git a/app/controllers/well_known/webfinger_controller.rb b/app/controllers/well_known/webfinger_controller.rb
new file mode 100644
index 00000000000..1a8ef5f90ce
--- /dev/null
+++ b/app/controllers/well_known/webfinger_controller.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module WellKnown
+ class WebfingerController < ApplicationController
+ def show
+ @account = Account.find_local!(username_from_resource)
+ @canonical_account_uri = @account.to_webfinger_s
+ @magic_key = pem_to_magic_key(@account.keypair.public_key)
+
+ respond_to do |format|
+ format.xml { render content_type: 'application/xrd+xml' }
+ format.json { render content_type: 'application/jrd+json' }
+ end
+ rescue ActiveRecord::RecordNotFound
+ head 404
+ end
+
+ private
+
+ def username_from_resource
+ WebfingerResource.new(resource_param).username
+ end
+
+ def pem_to_magic_key(public_key)
+ modulus, exponent = [public_key.n, public_key.e].map do |component|
+ result = []
+
+ until component.zero?
+ result << [component % 256].pack('C')
+ component >>= 8
+ end
+
+ result.reverse.join
+ end
+
+ (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')
+ end
+
+ def resource_param
+ params.require(:resource)
+ end
+ end
+end
diff --git a/app/controllers/xrd_controller.rb b/app/controllers/xrd_controller.rb
deleted file mode 100644
index 2886315ac03..00000000000
--- a/app/controllers/xrd_controller.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-# frozen_string_literal: true
-
-class XrdController < ApplicationController
- before_action :set_default_format_xml, only: :host_meta
-
- def host_meta
- @webfinger_template = "#{webfinger_url}?resource={uri}"
-
- respond_to do |format|
- format.xml { render content_type: 'application/xrd+xml' }
- end
- end
-
- def webfinger
- @account = Account.find_local!(username_from_resource)
- @canonical_account_uri = @account.to_webfinger_s
- @magic_key = pem_to_magic_key(@account.keypair.public_key)
-
- respond_to do |format|
- format.xml { render content_type: 'application/xrd+xml' }
- format.json { render content_type: 'application/jrd+json' }
- end
- rescue ActiveRecord::RecordNotFound
- head 404
- end
-
- private
-
- def set_default_format_xml
- request.format = 'xml' if request.headers['HTTP_ACCEPT'].nil? && params[:format].nil?
- end
-
- def username_from_resource
- WebfingerResource.new(resource_param).username
- end
-
- def pem_to_magic_key(public_key)
- modulus, exponent = [public_key.n, public_key.e].map do |component|
- result = []
-
- until component.zero?
- result << [component % 256].pack('C')
- component >>= 8
- end
-
- result.reverse.join
- end
-
- (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')
- end
-
- def resource_param
- params.require(:resource)
- end
-end
diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb
index 211b5704293..212f88c39d4 100644
--- a/app/helpers/settings_helper.rb
+++ b/app/helpers/settings_helper.rb
@@ -16,6 +16,7 @@ module SettingsHelper
ja: '日本語',
'zh-CN': '简体中文',
'zh-HK': '繁體中文(香港)',
+ bg: 'Български',
}.freeze
def human_locale(locale)
diff --git a/app/models/account_filter.rb b/app/models/account_filter.rb
new file mode 100644
index 00000000000..a8d8c883763
--- /dev/null
+++ b/app/models/account_filter.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+class AccountFilter
+ attr_reader :params
+
+ def initialize(params)
+ @params = params
+ end
+
+ def results
+ scope = Account.alphabetic
+ params.each do |key, value|
+ scope = scope.merge scope_for(key, value)
+ end
+ scope
+ end
+
+ def scope_for(key, value)
+ case key
+ when /local/
+ Account.local
+ when /remote/
+ Account.remote
+ when /by_domain/
+ Account.where(domain: value)
+ when /silenced/
+ Account.silenced
+ when /recent/
+ Account.recent
+ when /suspended/
+ Account.suspended
+ else
+ raise "Unknown filter: #{key}"
+ end
+ end
+end
diff --git a/app/models/export.rb b/app/models/export.rb
index cd1a58eb6dd..f0d5dd2557d 100644
--- a/app/models/export.rb
+++ b/app/models/export.rb
@@ -2,13 +2,43 @@
require 'csv'
class Export
- attr_reader :accounts
+ attr_reader :account
- def initialize(accounts)
- @accounts = accounts
+ def initialize(account)
+ @account = account
end
- def to_csv
+ def to_blocked_accounts_csv
+ to_csv account.blocking
+ end
+
+ def to_muted_accounts_csv
+ to_csv account.muting
+ end
+
+ def to_following_accounts_csv
+ to_csv account.following
+ end
+
+ def total_storage
+ account.media_attachments.sum(:file_file_size)
+ end
+
+ def total_follows
+ account.following.count
+ end
+
+ def total_blocks
+ account.blocking.count
+ end
+
+ def total_mutes
+ account.muting.count
+ end
+
+ private
+
+ def to_csv(accounts)
CSV.generate do |csv|
accounts.each do |account|
csv << [(account.local? ? account.local_username_and_domain : account.acct)]
diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml
index ba1c3bae7b8..22901aed1e4 100644
--- a/app/views/admin/accounts/show.html.haml
+++ b/app/views/admin/accounts/show.html.haml
@@ -62,11 +62,11 @@
= number_to_human_size @account.media_attachments.sum('file_file_size')
- if @account.silenced?
- = link_to 'Undo silence', unsilence_admin_account_path(@account.id), method: :post, class: 'button'
+ = link_to 'Undo silence', admin_account_silence_path(@account.id), method: :delete, class: 'button'
- else
- = link_to 'Silence', silence_admin_account_path(@account.id), method: :post, class: 'button'
+ = link_to 'Silence', admin_account_silence_path(@account.id), method: :post, class: 'button'
- if @account.suspended?
- = link_to 'Undo suspension', unsuspend_admin_account_path(@account.id), method: :post, class: 'button'
+ = link_to 'Undo suspension', admin_account_suspension_path(@account.id), method: :delete, class: 'button'
- else
- = link_to 'Perform full suspension', suspend_admin_account_path(@account.id), method: :post, data: { confirm: 'Are you sure?' }, class: 'button'
+ = link_to 'Perform full suspension', admin_account_suspension_path(@account.id), method: :post, data: { confirm: 'Are you sure?' }, class: 'button'
diff --git a/app/views/auth/sessions/two_factor.html.haml b/app/views/auth/sessions/two_factor.html.haml
index 8bf9985545d..1deff82b2e3 100644
--- a/app/views/auth/sessions/two_factor.html.haml
+++ b/app/views/auth/sessions/two_factor.html.haml
@@ -2,7 +2,7 @@
= t('auth.login')
= simple_form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
- = f.input :otp_attempt, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt') }, required: true, autofocus: true, autocomplete: 'off'
+ = f.input :otp_attempt, type: :number, placeholder: t('simple_form.labels.defaults.otp_attempt'), input_html: { 'aria-label' => t('simple_form.labels.defaults.otp_attempt') }, required: true, autofocus: true, autocomplete: 'off'
.actions
= f.button :button, t('auth.login'), type: :submit
diff --git a/app/views/settings/exports/show.html.haml b/app/views/settings/exports/show.html.haml
index 51be40fb623..f2f6f95563e 100644
--- a/app/views/settings/exports/show.html.haml
+++ b/app/views/settings/exports/show.html.haml
@@ -5,17 +5,17 @@
%tbody
%tr
%th= t('exports.storage')
- %td= number_to_human_size @total_storage
+ %td= number_to_human_size @export.total_storage
%td
%tr
%th= t('exports.follows')
- %td= @total_follows
+ %td= @export.total_follows
%td= table_link_to 'download', t('exports.csv'), settings_exports_follows_path(format: :csv)
%tr
%th= t('exports.blocks')
- %td= @total_blocks
+ %td= @export.total_blocks
%td= table_link_to 'download', t('exports.csv'), settings_exports_blocks_path(format: :csv)
%tr
%th= t('exports.mutes')
- %td= @total_mutes
+ %td= @export.total_mutes
%td= table_link_to 'download', t('exports.csv'), settings_exports_mutes_path(format: :csv)
diff --git a/app/views/xrd/host_meta.xml.ruby b/app/views/well_known/host_meta/show.xml.ruby
similarity index 100%
rename from app/views/xrd/host_meta.xml.ruby
rename to app/views/well_known/host_meta/show.xml.ruby
diff --git a/app/views/xrd/webfinger.json.rabl b/app/views/well_known/webfinger/show.json.rabl
similarity index 100%
rename from app/views/xrd/webfinger.json.rabl
rename to app/views/well_known/webfinger/show.json.rabl
diff --git a/app/views/xrd/webfinger.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby
similarity index 100%
rename from app/views/xrd/webfinger.xml.ruby
rename to app/views/well_known/webfinger/show.xml.ruby
diff --git a/config/application.rb b/config/application.rb
index 2c720474a09..1383d45a587 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -27,6 +27,7 @@ module Mastodon
config.i18n.available_locales = [
:en,
+ :bg,
:de,
:eo,
:es,
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
new file mode 100644
index 00000000000..a8687f3cace
--- /dev/null
+++ b/config/locales/bg.yml
@@ -0,0 +1,169 @@
+---
+bg:
+ about:
+ about_mastodon: Mastodon е безплатен сървър с отворен код за социални мрежи. Като децентрализирана алтернатива на комерсиалните платформи, той позволява избягването на риска от монополизация на твоята комуникация от единични компании. Изберете си сървър, на който се доверявате, и ще можете да контактувате с всички останали. Всеки може да пусне Mastodon и лесно да вземе участие в социалната мрежа.
+ about_this: За тази инстанция
+ apps: Приложения
+ business_email: 'Служебен e-mail:'
+ closed_registrations: В момента регистрациите за тази инстанция са затворени.
+ contact: За контакти
+ description_headline: Какво е %{domain}?
+ domain_count_after: други инстанции
+ domain_count_before: Свързани към
+ features:
+ api: Отворено API за приложения и услуги
+ blocks: Богат на инструменти за блокиране и заглушаване
+ characters: Публикации от 500 символа
+ chronology: Публикациите се показват хронологично
+ ethics: 'Етичен дизайн: без реклами и проследяване'
+ gifv: GIFV комплекти и кратки видео клипове
+ privacy: Настройване на поверителността за всяка публикация
+ public: Публични канали
+ features_headline: Какво откроява Mastodon
+ get_started: Първи стъпки
+ links: Връзки
+ other_instances: Други инстанции
+ source_code: Програмен код
+ status_count_after: публикации
+ status_count_before: Написали
+ terms: Условия
+ user_count_after: потребители
+ user_count_before: Дом на
+ accounts:
+ follow: Последвай
+ followers: Последователи
+ following: Следва
+ nothing_here: Тук няма никого!
+ people_followed_by: Хора, които %{name} следва
+ people_who_follow: Хора, които следват %{name}
+ posts: Публикации
+ remote_follow: Последвай
+ unfollow: Не следвай
+ application_mailer:
+ settings: 'Промяна на предпочитанията за e-mail: %{link}'
+ signature: Mastodon известия от %{instance}
+ view: 'Преглед:'
+ applications:
+ invalid_url: Предоставеният URL е невалиден
+ auth:
+ change_password: Идентификационни данни
+ didnt_get_confirmation: Не получих инструкции за потвърждение
+ forgot_password: Забравих си паролата
+ login: Влизане
+ logout: Излизане
+ register: Регистрация
+ resend_confirmation: Изпрати отново инструкции за потвърждение
+ reset_password: Подновяване на паролата
+ set_new_password: Задай нова парола
+ authorize_follow:
+ error: Възникна грешка в откриването на потребителя
+ follow: Последвай
+ prompt_html: '(%{self}), молбата ти беше изпратена до:'
+ title: Последвай %{acct}
+ datetime:
+ distance_in_words:
+ about_x_hours: "%{count} ч."
+ about_x_months: "%{count} м."
+ about_x_years: "%{count} г."
+ almost_x_years: "%{count} г."
+ half_a_minute: Току-що
+ less_than_x_minutes: "%{count} мин."
+ less_than_x_seconds: Току-що
+ over_x_years: "%{count} г."
+ x_days: "%{count} дни"
+ x_minutes: "%{count} мин."
+ x_months: "%{count} м."
+ x_seconds: "%{count} сек."
+ exports:
+ blocks: Вашите блокирания
+ csv: CSV
+ follows: Вашите следвания
+ storage: Съхранение на мултимедия
+ generic:
+ changes_saved_msg: Успешно запазване на промените!
+ powered_by: поддържано от %{link}
+ save_changes: Запази промените
+ validation_errors:
+ one: Нещо все още не е наред! Моля, прегледай грешката по-долу
+ other: Нещо все още не е наред! Моля, прегледай грешките по-долу
+ imports:
+ preface: Можеш да импортираш някои данни, като например всички хора, които следваш или блокираш в акаунта си на тази инстанция, от файлове, създадени чрез експорт в друга инстанция.
+ success: Твоите данни бяха успешно качени и ще бъдат обработени впоследствие.
+ types:
+ blocking: Списък на блокираните
+ following: Списък на последователите
+ upload: Качване
+ landing_strip_html: %{name} е потребител от %{domain}. Можеш да ги следваш, или да контактуваш с тях, ако имаш акаунт където и да е из федерираната вселена на Mastodon. Ако нямаш акаунт, можеш да си създадеш ето тук.
+ notification_mailer:
+ digest:
+ body: 'Ето кратко резюме на нещата, които се случиха от последното ти посещение в %{instance} на %{since}:'
+ mention: "%{name} те спомена в:"
+ new_followers_summary:
+ one: Имаш един нов последовател! Ура!
+ other: Имаш %{count} нови последователи! Изумително!
+ subject:
+ one: "1 ново известие от последното ти посещение \U0001F418"
+ other: "%{count} нови известия от последното ти посещение \U0001F418"
+ favourite:
+ body: 'Публикацията ти беше харесана от %{name}:'
+ subject: "%{name} хареса твоята публикация"
+ follow:
+ body: "%{name} те последва!"
+ subject: "%{name} те последва"
+ follow_request:
+ body: "%{name} помоли за разрешение да те последва"
+ subject: 'Чакащ последовател: %{name}'
+ mention:
+ body: '%{name} те спомена в:'
+ subject: '%{name} те спомена'
+ reblog:
+ body: 'Твоята публикация беше споделена от %{name}:'
+ subject: "%{name} сподели публикацията ти"
+ pagination:
+ next: Напред
+ prev: Назад
+ remote_follow:
+ acct: Въведи потребителско_име@домейн, от които искаш да следваш
+ missing_resource: Неуспешно търсене на нужния URL за пренасочване за твоя акаунт
+ proceed: Започни следване
+ prompt: 'Ще последваш:'
+ settings:
+ authorized_apps: Упълномощени приложения
+ back: Обратно към Mastodon
+ edit_profile: Редактирай профила си
+ export: Експортиране на данни
+ import: Импортиране
+ preferences: Предпочитания
+ settings: Настройки
+ two_factor_auth: Двустепенно удостоверяване
+ statuses:
+ open_in_web: Отвори в уеб
+ over_character_limit: прехвърлен лимит от %{max} символа
+ show_more: Покажи повече
+ visibilities:
+ private: Покажи само на последователите си
+ public: Публично
+ unlisted: Публично, но не показвай в публичния канал
+ stream_entries:
+ click_to_show: Покажи
+ reblogged: споделено
+ sensitive_content: Деликатно съдържание
+ time:
+ formats:
+ default: "%d %b, %Y, %H:%M"
+ two_factor_auth:
+ description_html: При активация на двустепенно удостоверяване, за да влезеш в приложението, ще трябва да използваш телефона си. През него ще се генерира код, който да въвеждаш при влизане.
+ disable: Деактивирай
+ enable: Активирай
+ instructions_html: "Сканирай този QR код с Google Authenticator или подобно приложение от своя телефон. Oтсега нататък, това приложение ще генерира код, който ще трябва да въвеждаш при всяко влизане."
+ plaintext_secret_html: "Тайна в обикновен текст: %{secret}"
+ warning: Ако не можеш да настроиш приложението за удостверяване сега, избери "Деактивирай". В противен случай, няма да можеш да влезеш в акаунта си.
+ users:
+ invalid_email: E-mail адресът е невалиден
+ invalid_otp_token: Невалиден код
+ will_paginate:
+ page_gap: "…"
+ media_attachments:
+ validations:
+ too_many: Не мога да прикача повече от 4 файла
+ images_and_video: Не мога да прикача видеоклип към публикация, която вече съдържа изображения
diff --git a/config/locales/devise.bg.yml b/config/locales/devise.bg.yml
new file mode 100644
index 00000000000..7485b8236c4
--- /dev/null
+++ b/config/locales/devise.bg.yml
@@ -0,0 +1,61 @@
+---
+bg:
+ devise:
+ confirmations:
+ confirmed: Твоят профил беше успешно потвърден. Влизането в профила е успешно.
+ send_instructions: Ще получиш писмо с инструкции как да потвърдиш своя профил до няколко минути.
+ send_paranoid_instructions: Ако твоят имейл адрес съществува в базата ни, ще получиш там инструкции как да потвърдиш своя профил.
+ failure:
+ already_authenticated: Вече си вътре в профила си.
+ inactive: Профилът ти все още не е активиран.
+ invalid: Невалиден имейл адрес или парола.
+ last_attempt: Разполагаш с още един опит преди профилът ти да бъде заключен.
+ locked: Профилът ти е заключен.
+ not_found_in_database: "Невалидни стойности за %{authentication_keys} или парола."
+ timeout: Сесията ти изтече, моля влез отново, за да продължиш.
+ unauthenticated: Преди да продължиш, трябва да влезеш в профила си или да се регистрираш.
+ unconfirmed: Преди да продължиш, трябва да потвърдиш регистрацията си.
+ mailer:
+ confirmation_instructions:
+ subject: 'Mastodon: Инструкции за потвърждаване'
+ password_change:
+ subject: 'Mastodon: Паролата е променена'
+ reset_password_instructions:
+ subject: 'Инструкции за смяна на паролата'
+ unlock_instructions:
+ subject: 'Инструкции за отключване'
+ omniauth_callbacks:
+ failure: "Не успяхме да те упълномощим чрез %{kind}, защото \"%{reason}\"."
+ success: "Успешно упълномощаване чрез %{kind} профил."
+ passwords:
+ no_token: Може да достъпваш тази страница само от имейл за промяна на паролата. Ако тази страница е отворена от такъв имейл, увери се, че използваш целия URL-адрес, който сме ти изпратили.
+ send_instructions: Ще получиш писмо с инструкции как да промениш паролата си до няколко минути.
+ send_paranoid_instructions: Ако твоят имейл адрес съществува в базата ни, ще получиш там инструкции за промяна на своята парола.
+ updated: Паролата ти беше променена успешно. Влизането в профила е успешно.
+ updated_not_active: Паролата ти беше променена успешно.
+ registrations:
+ destroyed: Довиждане! Твоят профил беше успешно изтрит. Надяваме се скоро да те видим отново.
+ signed_up: Привет! Регистрирацията ти е успешна.
+ signed_up_but_inactive: Регистрирацията ти е успешна. Въпреки това, не можеш да влезеш в профила си, защото той все още не е потвърден.
+ signed_up_but_locked: Регистрирацията ти е успешна. Въпреки това, не можеш да влезеш в профила си, защото той е заключен.
+ signed_up_but_unconfirmed: Писмо с връзка за потвърждаване на профила ти беше изпратено на твоя имейл адрес. Моля, отвори връзката, за да активираш своя профил.
+ update_needs_confirmation: Профилът ти е успешно променен, но ние трябва да проверим твоя нов имейл адрес. Моля, провери пощата си и отвори връзката за потвърждаване на новия адрес.
+ updated: Профилът ти е успешно променен.
+ sessions:
+ already_signed_out: Успешно излизане от профила.
+ signed_in: Успешно влизане.
+ signed_out: Успешно излизане.
+ unlocks:
+ send_instructions: Ще получиш писмо с инструкции как да отключиш профила си до няколко минути.
+ send_paranoid_instructions: Ако твоят профил съществува в базата ни, на своя имейл адрес ще получиш инструкции за отключването му до няколко минути.
+ unlocked: Твоят профил беше отключен успешно. За да продължиш, влез в него.
+ errors:
+ messages:
+ already_confirmed: е вече потвърден, моля опитай да влезеш в профила си с него
+ confirmation_period_expired: "трябва да се потвърди в рамките на %{period}, моля направи нова заявка за потвърждение"
+ expired: е изтекъл, моля заяви нов
+ not_found: не е намерен
+ not_locked: не бе заключен
+ not_saved:
+ one: "Една грешка попречи този %{resource} да бъде записан:"
+ other: "%{count} грешки попречиха този %{resource} да бъде записан:"
diff --git a/config/locales/doorkeeper.bg.yml b/config/locales/doorkeeper.bg.yml
new file mode 100644
index 00000000000..6fafdfc5549
--- /dev/null
+++ b/config/locales/doorkeeper.bg.yml
@@ -0,0 +1,113 @@
+---
+bg:
+ activerecord:
+ attributes:
+ doorkeeper/application:
+ name: Име
+ redirect_uri: URI за пренасочване
+ errors:
+ models:
+ doorkeeper/application:
+ attributes:
+ redirect_uri:
+ fragment_present: не може да съдържа фрагмент.
+ invalid_uri: трябва да е валидно URI.
+ relative_uri: трябва да е абсолютно URI.
+ secured_uri: трябва да е HTTPS/SSL URI.
+ doorkeeper:
+ applications:
+ buttons:
+ authorize: Упълномощаване
+ cancel: Отказ
+ destroy: Унищожаване
+ edit: Редакция
+ submit: Изпращане
+ confirmations:
+ destroy: Потвърждаваш ли изтриването?
+ edit:
+ title: Редактиране на приложението
+ form:
+ error: О, не! Провери формата за възможни грешки
+ help:
+ native_redirect_uri: Изполвай %{native_redirect_uri} за локални тестове
+ redirect_uri: Използвай един ред за всяко URI
+ scopes: Разделяй диапазоните с интервал. Остави празно, за да използваш диапазона по подразбиране.
+ index:
+ callback_url: URL за обратно повикване
+ name: Име
+ new: Ново приложение
+ title: Твоите приложения
+ new:
+ title: Ново приложение
+ show:
+ actions: Действия
+ application_id: Идентификатор на приложението
+ callback_urls: URL-и за обратно повикване
+ scopes: Диапазони
+ secret: Тайна
+ title: 'Приложение: %{name}'
+ authorizations:
+ buttons:
+ authorize: Упълномощаване
+ deny: Отказ
+ error:
+ title: Възникна грешка
+ new:
+ able_to: Ще е възможно
+ prompt: Приложението %{client_name} заявява достъп до твоя акаунт
+ title: Изисква се упълномощаване
+ show:
+ title: Код за упълномощаване
+ authorized_applications:
+ buttons:
+ revoke: Отмяна
+ confirmations:
+ revoke: Потвърждаваш ли отмяната?
+ index:
+ application: Приложение
+ created_at: Създадено на
+ date_format: "%Y-%m-%d %H:%M:%S"
+ scopes: Диапазони
+ title: Твоите упълномощени приложения
+ errors:
+ messages:
+ access_denied: Заявката беше отказана от собственика на ресурса или от сървъра за упълномощаване.
+ credential_flow_not_configured: Resource Owner Password Credentials предизвика грешка, заради това, че настройките за Doorkeeper.configure.resource_owner_from_credentials липсват.
+ invalid_client: Удостоверяването на клиента предизвика грешка, поради непознат клиент, липсващо клиентско удостоверяване, или заради това, че методът на удостоверяване не се поддържа.
+ invalid_grant: Предоставеното удостоверение за достъп е невалидно, изтекло, отхвърлено, не съвпада с пренасочващото URI, използвано в заявката за удостоверение, или е бил издадено от друг клиент.
+ invalid_redirect_uri: Наличното пренасочващо URI е невалидно.
+ invalid_request: Заявката е с липсващ задължителен параметър, включва стойност на параметъра, която не се поддържа, или е изкривена по друг начин.
+ invalid_resource_owner: Предоставените идентификационни данни на притежателя на ресурса са невалидни, или притежателят не може да бъде намерен.
+ invalid_scope: Заявеният диапазон е невалиден, неизвестен или изкривен.
+ invalid_token:
+ expired: Маркерът за достъп изтече
+ revoked: Маркерът за достъп беше отхвърлен
+ unknown: Маркерът за достъп е невалиден
+ resource_owner_authenticator_not_configured: Намирането на Resource Owner се провали поради липса на конфигурация на Doorkeeper.configure.resource_owner_authenticator.
+ server_error: Сървърът за удостоверяване попадна на неочаквано условие, което предотврати изпълнението на заявката.
+ temporarily_unavailable: Сървърът за удостоверяване не може да се справи със заявката в момента поради временно претоварване или профилактика на сървъра.
+ unauthorized_client: Клиентът не е удостоверен да изпълни заявката по този начин.
+ unsupported_grant_type: Типът на удостоврението за достъп не се поддържа от сървъра за удостоверяване.
+ unsupported_response_type: Удостоверяващият сървър не поддържа този тип отговор.
+ flash:
+ applications:
+ create:
+ notice: Приложението е създадено.
+ destroy:
+ notice: Приложението е изтрито.
+ update:
+ notice: Приложението е обновено.
+ authorized_applications:
+ destroy:
+ notice: Приложението е отказано.
+ layouts:
+ admin:
+ nav:
+ applications: Приложения
+ oauth2_provider: OAuth2 доставчик
+ application:
+ title: Нужно е упълномощаване по OAuth
+ scopes:
+ follow: следването, блокирането, деблокирането и отмяната на следването на акаунтите
+ read: четенето на данните от твоя акаунт
+ write: публикуването от твое име
diff --git a/config/locales/doorkeeper.ja.yml b/config/locales/doorkeeper.ja.yml
index 35592bc494e..d3ea93789cd 100644
--- a/config/locales/doorkeeper.ja.yml
+++ b/config/locales/doorkeeper.ja.yml
@@ -25,7 +25,7 @@ ja:
confirmations:
destroy: 本当に削除しますか?
edit:
- title: アプリケーションの編集
+ title: アプリの編集
form:
error: フォームにエラーが無いか確認してください。
help:
@@ -35,17 +35,17 @@ ja:
index:
callback_url: コールバックURL
name: 名前
- new: 新規アプリケーション
- title: あなたのアプリケーション
+ new: 新規アプリ
+ title: アプリ
new:
- title: 新規アプリケーション
+ title: 新規アプリ
show:
actions: アクション
application_id: アクションId
callback_urls: コールバックurl
scopes: アクセス権
secret: 非公開
- title: 'アプリケーション: %{name}'
+ title: 'アプリ: %{name}'
authorizations:
buttons:
authorize: 承認
@@ -53,8 +53,8 @@ ja:
error:
title: エラーが発生しました。
new:
- able_to: このアプリケーションは以下のことができます
- prompt: アプリケーション %{client_name} があなたのアカウントへのアクセスを要求しています。
+ able_to: このアプリは以下のことができます
+ prompt: アプリ %{client_name} があなたのアカウントへのアクセスを要求しています。
title: 認証が必要です。
show:
title: 認証コード
@@ -68,7 +68,7 @@ ja:
created_at: 許可した日時
date_format: "%Y年%m月%d日 %H時%M分%S秒"
scopes: アクセス権
- title: 認証済みアプリケーション
+ title: 認証済みアプリ
errors:
messages:
access_denied: リソースの所有者または認証サーバーが要求を拒否しました。
@@ -92,22 +92,22 @@ ja:
flash:
applications:
create:
- notice: アプリケーションが作成されました。
+ notice: アプリが作成されました。
destroy:
- notice: アプリケーションが削除されました。
+ notice: アプリが削除されました。
update:
- notice: アプリケーションが更新されました。
+ notice: アプリが更新されました。
authorized_applications:
destroy:
- notice: アプリケーションが取り消されました。
+ notice: アプリが取り消されました。
layouts:
admin:
nav:
- applications: アプリケーション
+ applications: アプリ
oauth2_provider: OAuth2プロバイダー
application:
- title: OAuth認証が必要です。
+ title: OAuth認証
scopes:
follow: アカウントのフォロー, ブロック, ブロック解除, フォロー解除
- read: アカウントへのデータの読み取り
- write: アカウントからの投稿の書き込み
+ read: アカウントからのデータの読み取り
+ write: アカウントへのデータの書き込み
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 9407c7669d4..cd6b6543dc8 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -46,7 +46,7 @@ ja:
applications:
invalid_url: URLが無効です
auth:
- change_password: 資格情報
+ change_password: ログイン情報
didnt_get_confirmation: 確認メールを受信できませんか?
forgot_password: パスワードをお忘れですか?
login: ログイン
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index fab178629e9..0c272585544 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -9,7 +9,7 @@ ru:
contact: Связаться
description_headline: Что такое %{domain}?
domain_count_after: другими узлами
- domain_count_before: Связывается с
+ domain_count_before: Связан с
features:
api: Открытый API для приложений и сервисов
blocks: Продвинутые инструменты блокирования и глушения
@@ -25,7 +25,7 @@ ru:
other_instances: Другие узлы
source_code: Исходный код
status_count_after: статусов
- status_count_before: Автор
+ status_count_before: Опубликовано
terms: Условия
user_count_after: пользователей
user_count_before: Здесь живет
@@ -42,7 +42,7 @@ ru:
application_mailer:
settings: 'Изменить настройки e-mail: %{link}'
signature: Уведомления Mastodon от %{instance}
- view: 'View:'
+ view: 'Просмотр:'
applications:
invalid_url: Введенный URL неверен
auth:
@@ -126,7 +126,7 @@ ru:
acct: Введите username@domain, откуда Вы хотите подписаться
missing_resource: Поиск требуемого перенаправления URL для Вашего аккаунта завершился неудачей
proceed: Продолжить подписку
- prompt: 'Вы ходите подписаться на:'
+ prompt: 'Вы хотите подписаться на:'
settings:
authorized_apps: Авторизованные приложения
back: Назад в Mastodon
@@ -142,8 +142,8 @@ ru:
show_more: Подробнее
visibilities:
private: Показывать только подписчикам
- public: Публичный
- unlisted: Публичный, но без отображения в публичных лентах
+ public: Показывать всем
+ unlisted: Показывать всем, но не отображать в публичных лентах
stream_entries:
click_to_show: Показать
reblogged: продвинул(а)
@@ -156,8 +156,13 @@ ru:
disable: Отключить
enable: Включить
instructions_html: "Отсканируйте этот QR-код с помощью Google Authenticator или другого подобного приложения на Вашем телефоне. С этого момента приложение будет генерировать токены, которые будет необходимо ввести для входа."
+ manual_instructions: 'Если Вы не можете отсканировать QR-код и хотите ввести его вручную, секрет представлен здесь открытым текстом:'
plaintext_secret_html: 'Секрет открытым текстом: %{secret}'
- warning: Если сейчас у Вас не получается настроить аутентификатор, нажмите "отключить", иначе Вы не сможете войти!
+ code_hint: 'Для подтверждения введите код, сгенерированный приложением аутентификатора'
+ setup: Настроить
+ warning: 'Если сейчас у Вас не получается настроить аутентификатор, нажмите "отключить", иначе Вы не сможете войти!'
users:
invalid_email: Введенный e-mail неверен
invalid_otp_token: Введен неверный код
+ will_paginate:
+ page_gap: "…"
diff --git a/config/locales/simple_form.bg.yml b/config/locales/simple_form.bg.yml
new file mode 100644
index 00000000000..55b80277d76
--- /dev/null
+++ b/config/locales/simple_form.bg.yml
@@ -0,0 +1,46 @@
+---
+bg:
+ simple_form:
+ hints:
+ defaults:
+ avatar: PNG, GIF или JPG. До 2MB. Ще бъде смалена до 120x120 пиксела
+ display_name: До 30 символа
+ header: PNG, GIF или JPG. До 2MB. Ще бъде смалена до 700x335 пиксела
+ locked: Изисква ръчно одобрение на последователите. По подразбиране, публикациите са достъпни само до последователи.
+ note: До 160 символа
+ imports:
+ data: CSV файл, експортиран от друга инстанция на Mastodon
+ labels:
+ defaults:
+ avatar: Аватар
+ confirm_new_password: Потвърди новата парола
+ confirm_password: Потвърди паролата
+ current_password: Текуща парола
+ data: Данни
+ display_name: Показвано име
+ email: E-mail адрес
+ header: Заглавен ред
+ locale: Език
+ locked: Направи акаунта поверителен
+ new_password: Нова парола
+ note: Био
+ otp_attempt: Двустепенен код
+ password: Парола
+ setting_default_privacy: Поверителност на публикациите
+ type: Тип на импортиране
+ username: Потребителско име
+ interactions:
+ must_be_follower: Блокирай известия от не-последователи
+ must_be_following: Блокирай известия от хора, които не следваш
+ notification_emails:
+ digest: Изпращай извлечения на съобщенията
+ favourite: Изпращай e-mail, когато някой хареса твоя публикация
+ follow: Изпращай e-mail, когато някой те последва
+ follow_request: Изпращай e-mail, когато някой пожелае да те последва
+ mention: Изпращай e-mail, когато някой те спомене
+ reblog: Изпращай e-mail, когато някой сподели твоя публикация
+ 'no': 'Не'
+ required:
+ mark: "*"
+ text: задължително
+ 'yes': 'Да'
diff --git a/config/locales/simple_form.ru.yml b/config/locales/simple_form.ru.yml
index 6f4873bfd2d..b7d8e4e05f5 100644
--- a/config/locales/simple_form.ru.yml
+++ b/config/locales/simple_form.ru.yml
@@ -26,7 +26,7 @@ ru:
note: О Вас
otp_attempt: Двухфакторный код
password: Пароль
- setting_default_privacy: Приватность постов
+ setting_default_privacy: Видимость постов
type: Тип импорта
username: Имя пользователя
interactions:
diff --git a/config/routes.rb b/config/routes.rb
index 78bf7870cdb..6e48d3b92b5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -1,3 +1,4 @@
+
# frozen_string_literal: true
require 'sidekiq/web'
@@ -14,8 +15,8 @@ Rails.application.routes.draw do
controllers authorizations: 'oauth/authorizations', authorized_applications: 'oauth/authorized_applications'
end
- get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta
- get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger, defaults: { format: 'json' }
+ get '.well-known/host-meta', to: 'well_known/host_meta#show', as: :host_meta, defaults: { format: 'xml' }
+ get '.well-known/webfinger', to: 'well_known/webfinger#show', as: :webfinger, defaults: { format: 'json' }
devise_for :users, path: 'auth', controllers: {
sessions: 'auth/sessions',
@@ -89,12 +90,8 @@ Rails.application.routes.draw do
end
resources :accounts, only: [:index, :show] do
- member do
- post :silence
- post :unsilence
- post :suspend
- post :unsuspend
- end
+ resource :silence, only: [:create, :destroy]
+ resource :suspension, only: [:create, :destroy]
end
end
diff --git a/spec/controllers/admin/silences_controller_spec.rb b/spec/controllers/admin/silences_controller_spec.rb
new file mode 100644
index 00000000000..7c541d7970a
--- /dev/null
+++ b/spec/controllers/admin/silences_controller_spec.rb
@@ -0,0 +1,24 @@
+require 'rails_helper'
+
+describe Admin::SilencesController do
+ let(:account) { Fabricate(:account) }
+ before do
+ sign_in Fabricate(:user, admin: true), scope: :user
+ end
+
+ describe 'POST #create' do
+ it 'redirects to admin accounts page' do
+ post :create, params: { account_id: account.id }
+
+ expect(response).to redirect_to(admin_accounts_path)
+ end
+ end
+
+ describe 'DELETE #destroy' do
+ it 'redirects to admin accounts page' do
+ delete :destroy, params: { account_id: account.id }
+
+ expect(response).to redirect_to(admin_accounts_path)
+ end
+ end
+end
diff --git a/spec/controllers/admin/suspensions_controller_spec.rb b/spec/controllers/admin/suspensions_controller_spec.rb
new file mode 100644
index 00000000000..9096f067ef2
--- /dev/null
+++ b/spec/controllers/admin/suspensions_controller_spec.rb
@@ -0,0 +1,24 @@
+require 'rails_helper'
+
+describe Admin::SuspensionsController do
+ let(:account) { Fabricate(:account) }
+ before do
+ sign_in Fabricate(:user, admin: true), scope: :user
+ end
+
+ describe 'POST #create' do
+ it 'redirects to admin accounts page' do
+ post :create, params: { account_id: account.id }
+
+ expect(response).to redirect_to(admin_accounts_path)
+ end
+ end
+
+ describe 'DELETE #destroy' do
+ it 'redirects to admin accounts page' do
+ delete :destroy, params: { account_id: account.id }
+
+ expect(response).to redirect_to(admin_accounts_path)
+ end
+ end
+end
diff --git a/spec/controllers/settings/exports_controller_spec.rb b/spec/controllers/settings/exports_controller_spec.rb
index ff98f3ad945..2be6e4744fa 100644
--- a/spec/controllers/settings/exports_controller_spec.rb
+++ b/spec/controllers/settings/exports_controller_spec.rb
@@ -1,6 +1,8 @@
require 'rails_helper'
describe Settings::ExportsController do
+ render_views
+
before do
sign_in Fabricate(:user), scope: :user
end
@@ -8,6 +10,7 @@ describe Settings::ExportsController do
describe 'GET #show' do
it 'returns http success' do
get :show
+
expect(response).to have_http_status(:success)
end
end
diff --git a/spec/controllers/well_known/host_meta_controller_spec.rb b/spec/controllers/well_known/host_meta_controller_spec.rb
new file mode 100644
index 00000000000..8a040021a6e
--- /dev/null
+++ b/spec/controllers/well_known/host_meta_controller_spec.rb
@@ -0,0 +1,13 @@
+require 'rails_helper'
+
+describe WellKnown::HostMetaController, type: :controller do
+ render_views
+
+ describe 'GET #show' do
+ it 'returns http success' do
+ get :show, format: :xml
+
+ expect(response).to have_http_status(:success)
+ end
+ end
+end
diff --git a/spec/controllers/well_known/webfinger_controller_spec.rb b/spec/controllers/well_known/webfinger_controller_spec.rb
new file mode 100644
index 00000000000..6e493b03789
--- /dev/null
+++ b/spec/controllers/well_known/webfinger_controller_spec.rb
@@ -0,0 +1,21 @@
+require 'rails_helper'
+
+describe WellKnown::WebfingerController, type: :controller do
+ render_views
+
+ describe 'GET #show' do
+ let(:alice) { Fabricate(:account, username: 'alice') }
+
+ it 'returns http success when account can be found' do
+ get :show, params: { resource: alice.to_webfinger_s }, format: :json
+
+ expect(response).to have_http_status(:success)
+ end
+
+ it 'returns http not found when account cannot be found' do
+ get :show, params: { resource: 'acct:not@existing.com' }, format: :json
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+end
diff --git a/spec/controllers/xrd_controller_spec.rb b/spec/controllers/xrd_controller_spec.rb
deleted file mode 100644
index 33b17f1523f..00000000000
--- a/spec/controllers/xrd_controller_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe XrdController, type: :controller do
- render_views
-
- describe 'GET #host_meta' do
- it 'returns http success' do
- get :host_meta
- expect(response).to have_http_status(:success)
- end
- end
-
- describe 'GET #webfinger' do
- let(:alice) { Fabricate(:account, username: 'alice') }
-
- it 'returns http success when account can be found' do
- get :webfinger, params: { resource: alice.to_webfinger_s }, format: :json
- expect(response).to have_http_status(:success)
- end
-
- it 'returns http not found when account cannot be found' do
- get :webfinger, params: { resource: 'acct:not@existing.com' }, format: :json
- expect(response).to have_http_status(:not_found)
- end
- end
-end
diff --git a/spec/models/account_filter_spec.rb b/spec/models/account_filter_spec.rb
new file mode 100644
index 00000000000..1599c5ae8b1
--- /dev/null
+++ b/spec/models/account_filter_spec.rb
@@ -0,0 +1,31 @@
+require 'rails_helper'
+
+describe AccountFilter do
+ describe 'with empty params' do
+ it 'defaults to alphabetic account list' do
+ filter = AccountFilter.new({})
+
+ expect(filter.results).to eq Account.alphabetic
+ end
+ end
+
+ describe 'with invalid params' do
+ it 'raises with key error' do
+ filter = AccountFilter.new(wrong: true)
+
+ expect { filter.results }.to raise_error(/wrong/)
+ end
+ end
+
+ describe 'with valid params' do
+ it 'combines filters on Account' do
+ filter = AccountFilter.new(by_domain: 'test.com', silenced: true)
+
+ allow(Account).to receive(:where).and_return(Account.none)
+ allow(Account).to receive(:silenced).and_return(Account.none)
+ filter.results
+ expect(Account).to have_received(:where).with(domain: 'test.com')
+ expect(Account).to have_received(:silenced)
+ end
+ end
+end
diff --git a/spec/requests/host_meta_request_spec.rb b/spec/requests/host_meta_request_spec.rb
new file mode 100644
index 00000000000..0c51b5f4843
--- /dev/null
+++ b/spec/requests/host_meta_request_spec.rb
@@ -0,0 +1,12 @@
+require "rails_helper"
+
+describe "The host_meta route" do
+ describe "requested without accepts headers" do
+ it "returns an xml response" do
+ get host_meta_url
+
+ expect(response).to have_http_status(:success)
+ expect(response.content_type).to eq "application/xrd+xml"
+ end
+ end
+end
diff --git a/spec/routing/well_known_routes_spec.rb b/spec/routing/well_known_routes_spec.rb
new file mode 100644
index 00000000000..9540c3de348
--- /dev/null
+++ b/spec/routing/well_known_routes_spec.rb
@@ -0,0 +1,15 @@
+require 'rails_helper'
+
+describe 'the host-meta route' do
+ it 'routes to correct place with xml format' do
+ expect(get('/.well-known/host-meta')).
+ to route_to('well_known/host_meta#show', format: 'xml')
+ end
+end
+
+describe 'the webfinger route' do
+ it 'routes to correct place with json format' do
+ expect(get('/.well-known/webfinger')).
+ to route_to('well_known/webfinger#show', format: 'json')
+ end
+end