Merge commit 'e8270e2807727e1cf6a47a40442b3038c5bca858' into glitch-soc/merge-upstream

Conflicts:
- `.eslintrc.js`:
  Upstream moved it to `eslint.config.mjs`.
  Ported the glitch-soc changes there.
- `yarn.lock`:
  Upstream updated dependencies close to glitch-soc-only dependencies.
  Ported upstream's changes.
This commit is contained in:
Claire
2025-04-01 20:59:34 +02:00
38 changed files with 1227 additions and 963 deletions
+1 -1
View File
@@ -68,7 +68,7 @@ function loaded() {
if (id) message = localeData[id];
if (!message) message = defaultMessage as string;
message ??= defaultMessage as string;
const messageFormat = new IntlMessageFormat(message, locale);
return messageFormat.format(values) as string;
@@ -1,4 +1,4 @@
import React from 'react';
import type React from 'react';
import { FormattedMessage } from 'react-intl';
@@ -1,5 +1,5 @@
import type { PropsWithChildren } from 'react';
import React from 'react';
import type React from 'react';
import { Router as OriginalRouter, useHistory } from 'react-router';
@@ -9,48 +9,39 @@ import { reduceMotion } from 'mastodon/initial_state';
interface UploadProgressProps {
active: boolean;
progress: number;
isProcessing: boolean;
isProcessing?: boolean;
}
export const UploadProgress: React.FC<UploadProgressProps> = ({
active,
progress,
isProcessing,
isProcessing = false,
}) => {
const styles = useSpring({
from: { width: '0%' },
to: { width: `${progress}%` },
reset: true,
immediate: reduceMotion,
immediate: reduceMotion || !active, // If this is not active, update the UI immediately.
});
if (!active) {
return null;
}
let message;
if (isProcessing) {
message = (
<FormattedMessage
id='upload_progress.processing'
defaultMessage='Processing…'
/>
);
} else {
message = (
<FormattedMessage
id='upload_progress.label'
defaultMessage='Uploading…'
/>
);
}
return (
<div className='upload-progress'>
<Icon id='upload' icon={UploadFileIcon} />
<div className='upload-progress__message'>
{message}
{isProcessing ? (
<FormattedMessage
id='upload_progress.processing'
defaultMessage='Processing…'
/>
) : (
<FormattedMessage
id='upload_progress.label'
defaultMessage='Uploading…'
/>
)}
<div className='upload-progress__backdrop'>
<animated.div className='upload-progress__tracker' style={styles} />
@@ -1,5 +1,3 @@
/* eslint-disable import/no-commonjs --
We need to use CommonJS here due to preval */
// @preval
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
// This file contains the compressed version of the emoji data from
@@ -33,11 +33,8 @@ function processEmojiMapData(
shortCode?: ShortCodesToEmojiDataKey,
) {
const [native, _filename] = emojiMapData;
let filename = emojiMapData[1];
if (!filename) {
// filename name can be derived from unicodeToFilename
filename = unicodeToFilename(native);
}
// filename name can be derived from unicodeToFilename
const filename = emojiMapData[1] ?? unicodeToFilename(native);
unicodeMapping[native] = {
shortCode,
filename,
@@ -1,6 +1,3 @@
/* eslint-disable import/no-commonjs --
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
// taken from:
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
exports.unicodeToFilename = (str) => {
@@ -1,6 +1,3 @@
/* eslint-disable import/no-commonjs --
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
function padLeft(str, num) {
while (str.length < num) {
str = '0' + str;
+2 -2
View File
@@ -911,6 +911,6 @@
"video.skip_backward": "Siirry taaksepäin",
"video.skip_forward": "Siirry eteenpäin",
"video.unmute": "Poista mykistys",
"video.volume_down": "Laske äänenvoimakkuutta",
"video.volume_up": "Nosta äänenvoimakkuutta"
"video.volume_down": "Vähennä äänenvoimakkuutta",
"video.volume_up": "Lisää äänenvoimakkuutta"
}
+7 -1
View File
@@ -905,6 +905,12 @@
"video.expand": "동영상 확장",
"video.fullscreen": "전체화면",
"video.hide": "동영상 숨기기",
"video.mute": "음소거",
"video.pause": "일시정지",
"video.play": "재생"
"video.play": "재생",
"video.skip_backward": "뒤로 건너뛰기",
"video.skip_forward": "앞으로 건너뛰기",
"video.unmute": "음소거 해제",
"video.volume_down": "음량 감소",
"video.volume_up": "음량 증가"
}
+10 -1
View File
@@ -697,6 +697,7 @@
"poll_button.remove_poll": "Remover enquete",
"privacy.change": "Alterar privacidade do toot",
"privacy.direct.long": "Todos mencionados na publicação",
"privacy.direct.short": "Menção privada",
"privacy.private.long": "Apenas seus seguidores",
"privacy.private.short": "Seguidores",
"privacy.public.long": "Qualquer um dentro ou fora do Mastodon",
@@ -871,7 +872,9 @@
"subscribed_languages.target": "Alterar idiomas inscritos para {target}",
"tabs_bar.home": "Página inicial",
"tabs_bar.notifications": "Notificações",
"terms_of_service.effective_as_of": "Em vigor a partir de {date}",
"terms_of_service.title": "Termos de serviço",
"terms_of_service.upcoming_changes_on": "Próximas mudanças em {date}",
"time_remaining.days": "{number, plural, one {# dia restante} other {# dias restantes}}",
"time_remaining.hours": "{number, plural, one {# hora restante} other {# horas restantes}}",
"time_remaining.minutes": "{number, plural, one {# minuto restante} other {# minutos restantes}}",
@@ -902,6 +905,12 @@
"video.expand": "Abrir vídeo",
"video.fullscreen": "Tela cheia",
"video.hide": "Ocultar mídia",
"video.mute": "Silenciar",
"video.pause": "Pausar",
"video.play": "Executar"
"video.play": "Executar",
"video.skip_backward": "Retroceder",
"video.skip_forward": "Avançar",
"video.unmute": "Ativar som",
"video.volume_down": "Diminuir o volume",
"video.volume_up": "Aumentar o volume"
}
+13 -12
View File
@@ -156,7 +156,7 @@
"column.firehose": "Живая лента",
"column.follow_requests": "Запросы на подписку",
"column.home": "Главная",
"column.list_members": "Управление пользователями в списке",
"column.list_members": "Добавить или удалить из списка",
"column.lists": "Списки",
"column.mutes": "Игнорируемые пользователи",
"column.notifications": "Уведомления",
@@ -173,7 +173,7 @@
"column_subheading.settings": "Настройки",
"community.column_settings.local_only": "Только локальные",
"community.column_settings.media_only": "Только с медиафайлами",
"community.column_settings.remote_only": "Только удалённые",
"community.column_settings.remote_only": "Только с других серверов",
"compose.language.change": "Изменить язык",
"compose.language.search": "Найти язык...",
"compose.published.body": "Пост опубликован.",
@@ -181,7 +181,7 @@
"compose.saved.body": "Пост отредактирован.",
"compose_form.direct_message_warning_learn_more": "Узнать больше",
"compose_form.encryption_warning": "Посты в Mastodon не защищены сквозным шифрованием. Не делитесь конфиденциальной информацией через Mastodon.",
"compose_form.hashtag_warning": "Этот пост не будет виден ни под одним из хэштегов, так как он не публичный. Только публичные посты можно найти по хэштегу.",
"compose_form.hashtag_warning": "Этот пост не появится в поиске по хэштегам, так как он не обозначен как публичный. Только публичные посты можно найти по хэштегу.",
"compose_form.lock_disclaimer": "Ваша учётная запись {locked}. Любой пользователь сможет подписаться на вас и просматривать посты для подписчиков.",
"compose_form.lock_disclaimer.lock": "не закрыта",
"compose_form.placeholder": "О чём думаете?",
@@ -189,8 +189,8 @@
"compose_form.poll.multiple": "Несколько вариантов ответа",
"compose_form.poll.option_placeholder": "Вариант {number}",
"compose_form.poll.single": "Один вариант ответа",
"compose_form.poll.switch_to_multiple": "Разрешить выбор нескольких вариантов",
"compose_form.poll.switch_to_single": "Переключить в режим выбора одного ответа",
"compose_form.poll.switch_to_multiple": "Переключить в режим выбора нескольких вариантов ответа",
"compose_form.poll.switch_to_single": "Переключить в режим выбора одного варианта ответа",
"compose_form.poll.type": "Тип",
"compose_form.publish": "Опубликовать",
"compose_form.publish_form": "Опубликовать",
@@ -208,11 +208,11 @@
"confirmations.delete_list.message": "Вы уверены, что хотите навсегда удалить этот список?",
"confirmations.delete_list.title": "Удалить список?",
"confirmations.discard_edit_media.confirm": "Сбросить",
"confirmations.discard_edit_media.message": "У вас есть несохранённые изменения в описании мультимедиа или предпросмотре, сбросить их?",
"confirmations.discard_edit_media.message": "У вас есть несохранённые изменения, касающиеся описания медиа или области предпросмотра, сбросить их?",
"confirmations.edit.confirm": "Редактировать",
"confirmations.edit.message": "Если вы начнёте редактировать сейчас, то набираемый в данный момент пост будет стёрт. Вы уверены, что хотите продолжить?",
"confirmations.edit.title": "Стереть несохранённый черновик поста?",
"confirmations.follow_to_list.confirm": "Подписаться, а затем добавить в список",
"confirmations.follow_to_list.confirm": "Подписаться и добавить",
"confirmations.follow_to_list.message": "Чтобы добавить пользователя {name} в список, вы должны быть на него подписаны.",
"confirmations.follow_to_list.title": "Подписаться на пользователя?",
"confirmations.logout.confirm": "Выйти",
@@ -224,8 +224,8 @@
"confirmations.missing_alt_text.title": "Добавить альтернативный текст?",
"confirmations.mute.confirm": "Игнорировать",
"confirmations.redraft.confirm": "Удалить и исправить",
"confirmations.redraft.message": "Вы уверены, что хотите удалить и переписать этот пост? Отметки «избранного», продвижения и ответы к оригинальному посту будут потеряны.",
"confirmations.redraft.title": "Создать пост заново?",
"confirmations.redraft.message": "Вы уверены, что хотите удалить этот пост и создать его заново? Взаимодействия, такие как добавление в избранное или продвижение, будут потеряны, а ответы к оригинальному посту перестанут на него ссылаться.",
"confirmations.redraft.title": "Удалить и создать пост заново?",
"confirmations.reply.confirm": "Ответить",
"confirmations.reply.message": "Если вы начнёте составлять ответ сейчас, то набираемый в данный момент пост будет стёрт. Вы уверены, что хотите продолжить?",
"confirmations.reply.title": "Стереть несохранённый черновик поста?",
@@ -293,7 +293,7 @@
"emoji_button.search_results": "Результаты поиска",
"emoji_button.symbols": "Символы",
"emoji_button.travel": "Путешествия и места",
"empty_column.account_hides_collections": "Данный пользователь решил не предоставлять эту информацию",
"empty_column.account_hides_collections": "Пользователь предпочёл не раскрывать эту информацию",
"empty_column.account_suspended": "Учётная запись заблокирована",
"empty_column.account_timeline": "Здесь нет постов!",
"empty_column.account_unavailable": "Профиль недоступен",
@@ -409,8 +409,9 @@
"home.show_announcements": "Показать объявления",
"ignore_notifications_modal.disclaimer": "Mastodon не может сообщить пользователям, что вы игнорируете их уведомления. Игнорирование уведомлений не остановит отправку самих сообщений.",
"ignore_notifications_modal.filter_instead": "Фильтровать",
"ignore_notifications_modal.filter_to_avoid_confusion": "Фильтрация помогает избежать потенциальной путаницы",
"ignore_notifications_modal.filter_to_review_separately": "Вы можете просматривать отфильтрованные уведомления отдельно",
"ignore_notifications_modal.filter_to_act_users": "Вы по-прежнему сможете принимать и отклонять запросы, а также отправлять жалобы на пользователей",
"ignore_notifications_modal.filter_to_avoid_confusion": "Фильтрация поможет избежать возможной путаницы",
"ignore_notifications_modal.filter_to_review_separately": "Отфильтрованные уведомления можно просматривать отдельно",
"ignore_notifications_modal.ignore": "Игнорировать уведомления",
"ignore_notifications_modal.limited_accounts_title": "Игнорировать уведомления от модерируемых учётных записей?",
"ignore_notifications_modal.new_accounts_title": "Игнорировать уведомления от новых учётных записей?",
+11 -3
View File
@@ -113,6 +113,7 @@ function clearAll(state) {
map.set('sensitive', state.get('default_sensitive'));
map.set('language', state.get('default_language'));
map.update('media_attachments', list => list.clear());
map.set('progress', 0);
map.set('poll', null);
map.set('idempotencyKey', uuid());
});
@@ -128,6 +129,7 @@ function appendMedia(state, media, file) {
map.update('media_attachments', list => list.push(media.set('unattached', true)));
map.set('is_uploading', false);
map.set('is_processing', false);
map.set('progress', 0);
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
map.set('idempotencyKey', uuid());
map.update('pending_media_attachments', n => n - 1);
@@ -296,6 +298,8 @@ const updatePoll = (state, index, value, maxOptions) => state.updateIn(['poll',
return tmp;
});
const calculateProgress = (loaded, total) => Math.min(Math.round((loaded / total) * 100), 100);
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
export const composeReducer = (state = initialState, action) => {
if (changeUploadCompose.fulfilled.match(action)) {
@@ -402,15 +406,19 @@ export const composeReducer = (state = initialState, action) => {
case COMPOSE_UPLOAD_SUCCESS:
return appendMedia(state, fromJS(action.media), action.file);
case COMPOSE_UPLOAD_FAIL:
return state.set('is_uploading', false).set('is_processing', false).update('pending_media_attachments', n => n - 1);
return state
.set('is_uploading', false)
.set('is_processing', false)
.set('progress', 0)
.update('pending_media_attachments', n => n - 1);
case COMPOSE_UPLOAD_UNDO:
return removeMedia(state, action.media_id);
case COMPOSE_UPLOAD_PROGRESS:
return state.set('progress', Math.round((action.loaded / action.total) * 100));
return state.set('progress', calculateProgress(action.loaded, action.total));
case THUMBNAIL_UPLOAD_REQUEST:
return state.set('isUploadingThumbnail', true);
case THUMBNAIL_UPLOAD_PROGRESS:
return state.set('thumbnailProgress', Math.round((action.loaded / action.total) * 100));
return state.set('thumbnailProgress', calculateProgress(action.loaded, action.total));
case THUMBNAIL_UPLOAD_FAIL:
return state.set('isUploadingThumbnail', false);
case THUMBNAIL_UPLOAD_SUCCESS:
@@ -1,6 +1,3 @@
/* eslint-disable import/no-commonjs --
We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */
/* @preval */
const fs = require('fs');