Merge branch 'main' into mk.absturztau.be

This commit is contained in:
Puniko 2023-05-06 19:54:28 +02:00
commit 3d1a991051
4 changed files with 139 additions and 49 deletions

View File

@ -12,7 +12,7 @@ password: "Kata sandi"
forgotPassword: "Lupa Kata Sandi"
fetchingAsApObject: "Mengambil data dari Fediverse..."
ok: "OK"
gotIt: "Saya mengerti"
gotIt: "Saya mengerti!"
cancel: "Batalkan"
renotedBy: "direnote oleh {user}"
noNotes: "Tidak ada catatan"
@ -24,7 +24,7 @@ otherSettings: "Pengaturan lainnya"
openInWindow: "Buka di jendela"
profile: "Profil"
timeline: "Linimasa"
noAccountDescription: "Pengguna ini belum menulis bio"
noAccountDescription: "Pengguna ini belum menulis biodata mereka."
login: "Masuk"
loggingIn: "Sedang masuk"
logout: "Keluar"
@ -62,8 +62,8 @@ files: "Berkas"
download: "Unduh"
driveFileDeleteConfirm: "Hapus {name}? Catatan dengan berkas terkait juga akan terhapus."
unfollowConfirm: "Berhenti mengikuti {name}?"
exportRequested: "Kamu telah meminta ekspor. Ini akan memakan waktu sesaat. Setelah\
\ ekspor selesai, berkas yang dihasilkan akan ditambahkan ke Drive"
exportRequested: "Anda telah meminta ekspor. Ini mungkin memerlukan waktu beberapa\
\ saat. File ini akan ditambahkan ke Drive Anda setelah selesai."
importRequested: "Kamu telah meminta impor. Ini akan memakan waktu sesaat."
lists: "Daftar"
note: "Catat"
@ -100,8 +100,8 @@ clickToShow: "Klik untuk melihat"
sensitive: "Konten sensitif"
add: "Tambahkan"
reaction: "Reaksi"
reactionSettingDescription2: "Geser untuk memindah urutkan, klik untuk menghapus,\
\ tekan \"+\" untuk menambahkan"
reactionSettingDescription2: "Seret untuk menyusun ulang, klik untuk menghapus, tekan\
\ \"+\" untuk menambahkan."
attachCancel: "Hapus lampiran"
markAsSensitive: "Tandai sebagai konten sensitif"
unmarkAsSensitive: "Hapus tanda konten sensitif"
@ -193,10 +193,10 @@ blockedUsers: "Pengguna yang diblokir"
noUsers: "Tidak ada pengguna"
editProfile: "Sunting profil"
noteDeleteConfirm: "Apakah kamu yakin ingin menghapus catatan ini?"
pinLimitExceeded: "Kamu tidak dapat menyematkan catatan lagi"
pinLimitExceeded: "Anda tidak dapat menyematkan catatan lagi."
intro: "Instalasi FoundKey telah selesai! Mohon untuk membuat pengguna admin."
done: "Selesai"
processing: "Memproses"
processing: "Pemrosesan..."
preview: "Pratinjau"
default: "Bawaan"
noCustomEmojis: "Tidak ada emoji kustom"
@ -210,7 +210,7 @@ publishing: "Sedang menyiarkan langsung"
notResponding: "Tidak ada respon"
changePassword: "Ubah kata sandi"
security: "Keamanan"
retypedNotMatch: "Input tidak sama"
retypedNotMatch: "Input tidak cocok."
currentPassword: "Kata sandi saat ini"
newPassword: "Kata sandi baru"
newPasswordRetype: "Ulangi kata sandi baru"
@ -237,7 +237,7 @@ fromUrl: "Dari URL"
uploadFromUrl: "Unggah dari URL"
uploadFromUrlDescription: "URL berkas yang ingin kamu unggah"
uploadFromUrlRequested: "Pengunggahan telah diminta"
uploadFromUrlMayTakeTime: "Membutuhkan beberapa waktu hingga pengunggahan selesai"
uploadFromUrlMayTakeTime: "Mungkin diperlukan waktu hingga unggahan selesai."
explore: "Jelajahi"
messageRead: "Telah dibaca"
noMoreHistory: "Tidak ada sejarah lagi"
@ -403,7 +403,7 @@ newMessageExists: "Kamu mendapatkan pesan baru"
onlyOneFileCanBeAttached: "Kamu hanya dapat melampirkan satu berkas ke dalam pesan"
signinRequired: "Silahkan login"
invitationCode: "Kode undangan"
checking: "Memeriksa"
checking: "Memeriksa..."
available: "Tersedia"
unavailable: "Tidak tersedia"
usernameInvalidFormat: "Hanya dapat menerima karakter a-z, A-Z dan angka 0-9."
@ -445,11 +445,10 @@ showFeaturedNotesInTimeline: "Tampilkan catatan yang diunggulkan di linimasa"
objectStorage: "Object Storage"
useObjectStorage: "Gunakan object storage"
objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "Prefix URL digunakan untuk mengkonstruksi URL ke object\
\ (media) referencing. Tentukan URL jika kamu menggunakan CDN atau Proxy, jika tidak\
\ tentukan alamat yang dapat diakses secara publik sesuai dengan panduan dari layanan\
\ yang akan kamu gunakan, contohnya. 'https://<bucket>.s3.amazonaws.com' untuk AWS\
\ S3, dan 'https://storage.googleapis.com/<bucket>' untuk GCS."
objectStorageBaseUrlDesc: "URL yang digunakan sebagai referensi. Tentukan URL CDN\
\ atau Proksi Anda jika Anda menggunakan keduanya.\nUntuk S3 gunakan 'https://<bucket>.s3.amazonaws.com'\
\ dan untuk GCS atau layanan yang setara gunakan 'https://storage.googleapis.com/<bucket>',\
\ dst."
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Mohon tentukan nama bucket yang digunakan pada layanan yang\
\ telah dikonfigurasi."
@ -647,8 +646,8 @@ contact: "Kontak"
useSystemFont: "Gunakan font bawaan sistem operasi"
clips: "Klip"
makeExplorable: "Buat akun tampil di \"Jelajahi\""
makeExplorableDescription: "Jika kamu mematikan ini, akun kamu tidak akan muncul di\
\ bagian \"Jelajahi:"
makeExplorableDescription: "Jika Anda menonaktifkannya, akun Anda tidak akan muncul\
\ di bagian \"Jelajahi\"."
showGapBetweenNotesInTimeline: "Tampilkan jarak diantara catatan pada linimasa"
duplicate: "Duplikat"
left: "Kiri"
@ -759,7 +758,7 @@ ffVisibility: "Visibilitas Mengikuti/Pengikut"
ffVisibilityDescription: "Mengatur siapa yang dapat melihat pengikutmu dan yang kamu\
\ ikuti."
continueThread: "Lihat lanjutan thread"
deleteAccountConfirm: "Akun akan dihapus. Apakah kamu yakin?"
deleteAccountConfirm: "Ini akan menghapuskan akun {handle} secara permanen. Lanjutkan?"
incorrectPassword: "Kata sandi salah."
voteConfirm: "Konfirmasi suara kamu untuk ({choice})"
hide: "Sembunyikan"
@ -1079,7 +1078,7 @@ _auth:
shareAccess: "Apakah kamu ingin mengijinkan \"{name}\" untuk mengakses akun ini?"
shareAccessAsk: "Apakah kamu ingin mengijinkan aplikasi ini untuk mengakses akun\
\ kamu?"
permissionAsk: "Aplikasi ini membutuhkan beberapa ijin, yaitu:"
permissionAsk: "Aplikasi ini meminta izin berikut ini"
pleaseGoBack: "Mohon kembali ke aplikasi kamu"
callback: "Mengembalikan kamu ke aplikasi"
denied: "Akses ditolak"
@ -1263,7 +1262,7 @@ _notification:
youWereFollowed: "Mengikuti kamu"
youReceivedFollowRequest: "Kamu menerima permintaan mengikuti"
yourFollowRequestAccepted: "Permintaan mengikuti kamu telah diterima"
youWereInvitedToGroup: "Telah diundang ke grup"
youWereInvitedToGroup: "{userName} mengundang Anda ke grup"
pollEnded: "Hasil Kuesioner telah keluar"
emptyPushNotificationMessage: "Pembaruan notifikasi dorong"
_types:

View File

@ -1295,7 +1295,7 @@ _remoteInteract:
description: 今すぐにこのアクションを実行することはできません。あなたのインスタンス上で、またはログインして行う必要があるかもしれません。
movedTo: このユーザーは {handle} に引っ越しました。
uploadFailedDescription: ファイルをアップロードできませんでした。
uploadFailedSize: このファイルは大きすぎるためアップロードできません。
uploadFailedSize: ファイルサイズが大きすぎるためアップロードできません。
uploadFailed: アップロード失敗
showAttachedNotes: 添付ノートを表示
attachedToNotes: このファイルが添付されたノート

View File

@ -181,14 +181,15 @@ clearCachedFiles: "Очистить кэш"
clearCachedFilesConfirm: "Удалить все закэшированные файлы с других сайтов?"
blockedInstances: "Заблокированные инстансы"
blockedInstancesDescription: "Введите список инстансов, которые хотите заблокировать.\
\ Они больше не смогут обмениваться с вашим инстансом."
\ Они больше не смогут обмениваться с вашим инстансом. Не-ASCII доменные имена должны\
\ быть переведены в punycode. Субдомены тоже будут заблокированы"
muteAndBlock: "Скрытие и блокировка"
mutedUsers: "Скрытые пользователи"
blockedUsers: "Заблокированные пользователи"
noUsers: "Нет ни одного пользователя"
editProfile: "Редактировать профиль"
noteDeleteConfirm: "Вы хотите удалить эту заметку?"
pinLimitExceeded: "Нельзя закрепить ещё больше заметок"
pinLimitExceeded: "Нельзя закрепить ещё больше заметок."
intro: "Установка FoundKey завершена! А теперь создайте учетную запись администратора."
done: "Готово"
processing: "Обработка"
@ -722,7 +723,7 @@ misskeyUpdated: "FoundKey обновился!"
whatIsNew: "Что новенького?"
translate: "Перевод"
translatedFrom: "Перевод. Язык оригинала — {x}"
accountDeletionInProgress: "В настоящее время выполняется удаление учетной записи"
accountDeletionInProgress: "В настоящее время выполняется удаление учетной записи."
usernameInfo: "Имя, которое отличает вашу учетную запись от других на этом сервере.\
\ Вы можете использовать алфавит (a~z, A~Z), цифры (0~9) или символы подчеркивания\
\ (_). Имена пользователей не могут быть изменены позже."
@ -749,7 +750,7 @@ ffVisibility: "Видимость подписок и подписчиков"
ffVisibilityDescription: "Здесь можно настроить, кто будет видеть ваши подписки и\
\ подписчиков."
continueThread: "Показать следующие ответы"
deleteAccountConfirm: "Учётная запись будет безвозвратно удалена. Подтверждаете?"
deleteAccountConfirm: "Учётная запись {handle} будет безвозвратно удалена. Подтверждаете?"
incorrectPassword: "Пароль неверен."
voteConfirm: "Отдать голос за «{choice}»?"
hide: "Спрятать"
@ -1268,3 +1269,81 @@ _deck:
mentions: "Упоминания"
direct: "Личное"
_services: {}
botFollowRequiresApproval: Запросы на подписку от аккаунтов помеченных как бот требуют
подтверждения
showLess: Показать меньше
exportAll: Экспортировать всё
exportSelected: Экспортировать выбранное
cannotAttachFileWhenAccountSwitched: Вы не можете прикрепить файл, перейдя в другую
учетную запись.
cannotSwitchAccountWhenFileAttached: Вы не можете переключать учетные записи, пока
файлы прикреплены.
deleteAccount: Удалить аккаунт
isSystemAccount: Учетная запись, созданная системой и автоматически управляемая ею.
oneDay: Один день
cropImage: Обрезать изображение
documentation: Документация
movedTo: Этот пользователь перешел на {handle}.
typeToConfirm: Пожалуйста введите {x} чтобы подтвердить
rateLimitExceeded: Лимит превышен
numberOfPageCache: Количество кэшированных страниц
numberOfPageCacheDescription: Увеличение этого числа повысит удобство для пользователей,
но приведет к увеличению нагрузки на сервер, а также к использованию большего объема
памяти.
file: Файл
unclip: Удалить из подборки
translationSettings: Настройки перевода
translationService: Служба перевода
threadMuteNotificationsDesc: Выберите уведомления, которые вы хотите просмотреть в
этом треде. Также применяются глобальные настройки уведомлений. Отключение имеет
приоритет.
reflectMayTakeTime: Это может занять некоторое время чтобы вступило в силу.
failedToFetchAccountInformation: Не удалось получить информацию о аккаунте
instanceDefaultThemeDescription: Введите код темы в формате объекта.
tenMinutes: 10 минут
oneHour: Один час
oneWeek: Одна неделя
cropImageAsk: Вы хотите обрезать это изображение?
recentNHours: Последние {n} часов
recentNDays: Последние {n} дней
confirmToUnclipAlreadyClippedNote: Эта заметка уже является частью подборки "{name}".
Вы хотите вместо этого удалить это из этой подборки?
noEmailServerWarning: Сервер электронной почты не настроен.
setTag: Установить метку
addTag: Добавить метку
removeTag: Удалить метку
externalCssSnippets: Несколько фрагментов CSS для вашего вдохновения (не управляются
FoundKey)
oauthErrorGoBack: Произошла ошибка при попытке аутентификации стороннего приложения.
Пожалуйста, вернитесь и попробуйте еще раз.
appAuthorization: Авторизация приложения
noPermissionsRequested: (Никаких разрешений не требуется.)
selectMode: Выберите несколько
selectAll: Выбрать все
setCategory: Установить категорию
thereIsUnresolvedAbuseReportWarning: Есть нерасмотренные жалобы.
recommended: Рекомендовано
check: Проверка
unlimited: Неограниченный
mutePeriod: Длительность глушения
uploadFailed: Загрузка не удалась
uploadFailedDescription: Файл не может быть загружен.
uploadFailedSize: Файл слишком большой для загрузки.
renoteUnmute: Показать репосты
stopActivityDeliveryDescription: Локальная активнось не будет отправлена на этот сервер.
Получение активностей работает как раньше.
renoteMute: Скрыть репосты
unrenoteAllConfirm: Вы уверены что хотите отменить все репосты данной замети?
unrenoteAll: Отменить все репосты
blockThisInstanceDescription: Локальная активность не будет отправлена на этот сервер.
Активность этого сервера будет выброшена.
attachedToNotes: Заметки с этим файлом
showAttachedNotes: Показать заметки с этим файлом
signinHistoryExpires: Данные о прошлых попытках войти будут автоматически удалены
после 60 дней для соблюдения правил конфиденциальности.
deleteAllFiles: Удалить все файлы
federateBlocks: Федерировать блоки
federateBlocksDescription: Если выключено, то активности типа "блок" не будут отправлены.
regexpErrorDescription: 'Произошла ошибка в регулярном выражении на строке {line}
ваших {tab} заглушенных слов:'
reporter: Подавший жалобу

View File

@ -4,6 +4,7 @@ import config from '@/config/index.js';
import { UserProfiles } from '@/models/index.js';
import { extractMentions } from '@/misc/extract-mentions.js';
import { intersperse } from '@/prelude/array.js';
import { toPunyNullable } from '@/misc/convert-host.js';
// Transforms MFM to HTML, given the MFM text and a list of user IDs that are
// mentioned in the text. If the list of mentions is not given, all mentions
@ -14,6 +15,19 @@ export async function toHtml(mfmText: string, mentions?: string[]): Promise<stri
return null;
}
let mentionedUsers = [];
const ids = mentions ?? extractMentions(nodes);
if (ids.length > 0) {
mentionedUsers = await UserProfiles.createQueryBuilder('user_profile')
.leftJoin('user_profile.user', 'user')
.select('user.usernameLower', 'username')
.addSelect('user.host', 'host')
// links should preferably use user friendly urls, only fall back to AP ids
.addSelect('COALESCE(user_profile.url, user.uri)', 'url')
.where('"userId" IN (:...ids)', { ids })
.getRawMany();
}
const doc = new JSDOM('').window.document;
const handlers: { [K in mfm.MfmNode['type']]: (node: mfm.NodeType<K>) => Promise<Node> } = {
@ -103,30 +117,28 @@ export async function toHtml(mfmText: string, mentions?: string[]): Promise<stri
},
async mention(node): Promise<HTMLElement | Text> {
const { username, host, acct } = node.props;
const ids = mentions ?? extractMentions(nodes);
if (ids.length > 0) {
const mentionedUsers = await UserProfiles.createQueryBuilder('user_profile')
.leftJoin('user_profile.user', 'user')
.select('user.username', 'username')
.addSelect('user.host', 'host')
// links should preferably use user friendly urls, only fall back to AP ids
.addSelect('COALESCE(user_profile.url, user.uri)', 'url')
.where('"userId" IN (:...ids)', { ids })
.getRawMany();
const userInfo = mentionedUsers.find(user => user.username === username && user.host === host);
if (userInfo != null) {
// Mastodon microformat: span.h-card > a.u-url.mention
const a = doc.createElement('a');
a.href = userInfo.url ?? `${config.url}/${acct}`;
a.className = 'u-url mention';
a.textContent = acct;
let { username, host, acct } = node.props;
// normalize username and host for searching the user
username = username.toLowerCase();
host = toPunyNullable(host);
// Discard host if it is the local host. Otherwise mentions of local users where the
// hostname is not omitted are not handled correctly.
if (host == config.hostname) {
host = null;
}
const userInfo = mentionedUsers.find(user => user.username === username && user.host === host);
if (userInfo != null) {
// Mastodon microformat: span.h-card > a.u-url.mention
const a = doc.createElement('a');
// The fallback will only be used for local users, so the host part can be discarded.
a.href = userInfo.url ?? `${config.url}/@${username}`;
a.className = 'u-url mention';
a.textContent = acct;
const card = doc.createElement('span');
card.className = 'h-card';
card.appendChild(a);
return card;
}
const card = doc.createElement('span');
card.className = 'h-card';
card.appendChild(a);
return card;
}
// this user does not actually exist
return doc.createTextNode(acct);