From 01f0a6ca4fbb4d53c01f8be353a9ebfeb98f1739 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 21 Dec 2023 09:32:25 +0100 Subject: [PATCH 01/20] Fix profile setup showing default avatar in web UI (#28453) --- app/javascript/mastodon/features/onboarding/profile.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/javascript/mastodon/features/onboarding/profile.jsx b/app/javascript/mastodon/features/onboarding/profile.jsx index 09e6b2c6c6..daaef6065c 100644 --- a/app/javascript/mastodon/features/onboarding/profile.jsx +++ b/app/javascript/mastodon/features/onboarding/profile.jsx @@ -26,6 +26,8 @@ const messages = defineMessages({ uploadAvatar: { id: 'onboarding.profile.upload_avatar', defaultMessage: 'Upload profile picture' }, }); +const nullIfMissing = path => path.endsWith('missing.png') ? null : path; + export const Profile = () => { const account = useAppSelector(state => state.getIn(['accounts', me])); const [displayName, setDisplayName] = useState(account.get('display_name')); @@ -61,8 +63,8 @@ export const Profile = () => { setHeader(e.target?.files?.[0]); }, [setHeader]); - const avatarPreview = useMemo(() => avatar ? URL.createObjectURL(avatar) : account.get('avatar'), [avatar, account]); - const headerPreview = useMemo(() => header ? URL.createObjectURL(header) : account.get('header'), [header, account]); + const avatarPreview = useMemo(() => avatar ? URL.createObjectURL(avatar) : nullIfMissing(account.get('avatar')), [avatar, account]); + const headerPreview = useMemo(() => header ? URL.createObjectURL(header) : nullIfMissing(account.get('header')), [header, account]); const handleSubmit = useCallback(() => { setIsSaving(true); From 2463b53363a621c1e18223bda5c47a663707a22c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 21 Dec 2023 03:51:03 -0500 Subject: [PATCH 02/20] More duplicates in cli maintenance spec, misc bug fixes (#28449) --- lib/mastodon/cli/maintenance.rb | 40 +- spec/lib/mastodon/cli/maintenance_spec.rb | 426 +++++++++++++++++++++- 2 files changed, 443 insertions(+), 23 deletions(-) diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index 98067c6e34..7b3a9852a6 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -40,6 +40,10 @@ module Mastodon::CLI class BulkImport < ApplicationRecord; end class SoftwareUpdate < ApplicationRecord; end + class DomainBlock < ApplicationRecord + scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), domain')) } + end + class PreviewCard < ApplicationRecord self.inheritance_column = false end @@ -249,19 +253,7 @@ module Mastodon::CLI say 'Deduplicating user records…' - # Deduplicating email - ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users GROUP BY email HAVING count(*) > 1").each do |row| - users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse - ref_user = users.shift - say "Multiple users registered with e-mail address #{ref_user.email}.", :yellow - say "e-mail will be disabled for the following accounts: #{users.map { |user| user.account.acct }.join(', ')}", :yellow - say 'Please reach out to them and set another address with `tootctl account modify` or delete them.', :yellow - - users.each_with_index do |user, index| - user.update!(email: "#{index} " + user.email) - end - end - + deduplicate_users_process_email deduplicate_users_process_confirmation_token deduplicate_users_process_remember_token deduplicate_users_process_password_token @@ -280,6 +272,20 @@ module Mastodon::CLI ActiveRecord::Base.connection.execute('REINDEX INDEX index_users_on_unconfirmed_email;') if migrator_version >= 2023_07_02_151753 end + def deduplicate_users_process_email + ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users GROUP BY email HAVING count(*) > 1").each do |row| + users = User.where(id: row['ids'].split(',')).sort_by(&:updated_at).reverse + ref_user = users.shift + say "Multiple users registered with e-mail address #{ref_user.email}.", :yellow + say "e-mail will be disabled for the following accounts: #{users.map { |user| user.account.acct }.join(', ')}", :yellow + say 'Please reach out to them and set another address with `tootctl account modify` or delete them.', :yellow + + users.each_with_index do |user, index| + user.update!(email: "#{index} " + user.email) + end + end + end + def deduplicate_users_process_confirmation_token ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM users WHERE confirmation_token IS NOT NULL GROUP BY confirmation_token HAVING count(*) > 1").each do |row| users = User.where(id: row['ids'].split(',')).sort_by(&:created_at).reverse.drop(1) @@ -571,7 +577,7 @@ module Mastodon::CLI say 'Deduplicating webhooks…' ActiveRecord::Base.connection.select_all("SELECT string_agg(id::text, ',') AS ids FROM webhooks GROUP BY url HAVING count(*) > 1").each do |row| - Webhooks.where(id: row['ids'].split(',')).sort_by(&:id).reverse.drop(1).each(&:destroy) + Webhook.where(id: row['ids'].split(',')).sort_by(&:id).reverse.drop(1).each(&:destroy) end say 'Restoring webhooks indexes…' @@ -604,11 +610,7 @@ module Mastodon::CLI say 'Please chose the one to keep unchanged, other ones will be automatically renamed.' - ref_id = ask('Account to keep unchanged:') do |q| - q.required true - q.default 0 - q.convert :int - end + ref_id = ask('Account to keep unchanged:', required: true, default: 0).to_i accounts.delete_at(ref_id) diff --git a/spec/lib/mastodon/cli/maintenance_spec.rb b/spec/lib/mastodon/cli/maintenance_spec.rb index 353bf08b68..ca492bbf69 100644 --- a/spec/lib/mastodon/cli/maintenance_spec.rb +++ b/spec/lib/mastodon/cli/maintenance_spec.rb @@ -62,6 +62,7 @@ describe Mastodon::CLI::Maintenance do context 'with duplicate accounts' do before do prepare_duplicate_data + choose_local_account_to_keep end let(:duplicate_account_username) { 'username' } @@ -71,21 +72,37 @@ describe Mastodon::CLI::Maintenance do expect { subject } .to output_results( 'Deduplicating accounts', + 'Multiple local accounts were found for', 'Restoring index_accounts_on_username_and_domain_lower', 'Reindexing textual indexes on accounts…', 'Finished!' ) - .and change(duplicate_accounts, :count).from(2).to(1) + .and change(duplicate_remote_accounts, :count).from(2).to(1) + .and change(duplicate_local_accounts, :count).from(2).to(1) end - def duplicate_accounts + def duplicate_remote_accounts Account.where(username: duplicate_account_username, domain: duplicate_account_domain) end + def duplicate_local_accounts + Account.where(username: duplicate_account_username, domain: nil) + end + def prepare_duplicate_data ActiveRecord::Base.connection.remove_index :accounts, name: :index_accounts_on_username_and_domain_lower - Fabricate(:account, username: duplicate_account_username, domain: duplicate_account_domain) - Fabricate.build(:account, username: duplicate_account_username, domain: duplicate_account_domain).save(validate: false) + _remote_account = Fabricate(:account, username: duplicate_account_username, domain: duplicate_account_domain) + _remote_account_dupe = Fabricate.build(:account, username: duplicate_account_username, domain: duplicate_account_domain).save(validate: false) + _local_account = Fabricate(:account, username: duplicate_account_username, domain: nil) + _local_account_dupe = Fabricate.build(:account, username: duplicate_account_username, domain: nil).save(validate: false) + end + + def choose_local_account_to_keep + allow(cli.shell) + .to receive(:ask) + .with(/Account to keep unchanged/, anything) + .and_return('0') + .once end end @@ -175,6 +192,407 @@ describe Mastodon::CLI::Maintenance do end end + context 'with duplicate account_domain_blocks' do + before do + prepare_duplicate_data + end + + let(:duplicate_domain) { 'example.host' } + let(:account) { Fabricate(:account) } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Removing duplicate account domain blocks', + 'Restoring account domain blocks indexes', + 'Finished!' + ) + .and change(duplicate_account_domain_blocks, :count).from(2).to(1) + end + + def duplicate_account_domain_blocks + AccountDomainBlock.where(account: account, domain: duplicate_domain) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :account_domain_blocks, [:account_id, :domain] + Fabricate(:account_domain_block, account: account, domain: duplicate_domain) + Fabricate.build(:account_domain_block, account: account, domain: duplicate_domain).save(validate: false) + end + end + + context 'with duplicate announcement_reactions' do + before do + prepare_duplicate_data + end + + let(:account) { Fabricate(:account) } + let(:announcement) { Fabricate(:announcement) } + let(:name) { Fabricate(:custom_emoji).shortcode } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Removing duplicate announcement reactions', + 'Restoring announcement_reactions indexes', + 'Finished!' + ) + .and change(duplicate_announcement_reactions, :count).from(2).to(1) + end + + def duplicate_announcement_reactions + AnnouncementReaction.where(account: account, announcement: announcement, name: name) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :announcement_reactions, [:account_id, :announcement_id, :name] + Fabricate(:announcement_reaction, account: account, announcement: announcement, name: name) + Fabricate.build(:announcement_reaction, account: account, announcement: announcement, name: name).save(validate: false) + end + end + + context 'with duplicate conversations' do + before do + prepare_duplicate_data + end + + let(:uri) { 'https://example.host/path' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating conversations', + 'Restoring conversations indexes', + 'Finished!' + ) + .and change(duplicate_conversations, :count).from(2).to(1) + end + + def duplicate_conversations + Conversation.where(uri: uri) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :conversations, :uri + Fabricate(:conversation, uri: uri) + Fabricate.build(:conversation, uri: uri).save(validate: false) + end + end + + context 'with duplicate custom_emojis' do + before do + prepare_duplicate_data + end + + let(:duplicate_shortcode) { 'wowzers' } + let(:duplicate_domain) { 'example.host' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating custom_emojis', + 'Restoring custom_emojis indexes', + 'Finished!' + ) + .and change(duplicate_custom_emojis, :count).from(2).to(1) + end + + def duplicate_custom_emojis + CustomEmoji.where(shortcode: duplicate_shortcode, domain: duplicate_domain) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :custom_emojis, [:shortcode, :domain] + Fabricate(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain) + Fabricate.build(:custom_emoji, shortcode: duplicate_shortcode, domain: duplicate_domain).save(validate: false) + end + end + + context 'with duplicate custom_emoji_categories' do + before do + prepare_duplicate_data + end + + let(:duplicate_name) { 'name_value' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating custom_emoji_categories', + 'Restoring custom_emoji_categories indexes', + 'Finished!' + ) + .and change(duplicate_custom_emoji_categories, :count).from(2).to(1) + end + + def duplicate_custom_emoji_categories + CustomEmojiCategory.where(name: duplicate_name) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :custom_emoji_categories, :name + Fabricate(:custom_emoji_category, name: duplicate_name) + Fabricate.build(:custom_emoji_category, name: duplicate_name).save(validate: false) + end + end + + context 'with duplicate domain_allows' do + before do + prepare_duplicate_data + end + + let(:domain) { 'example.host' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating domain_allows', + 'Restoring domain_allows indexes', + 'Finished!' + ) + .and change(duplicate_domain_allows, :count).from(2).to(1) + end + + def duplicate_domain_allows + DomainAllow.where(domain: domain) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :domain_allows, :domain + Fabricate(:domain_allow, domain: domain) + Fabricate.build(:domain_allow, domain: domain).save(validate: false) + end + end + + context 'with duplicate domain_blocks' do + before do + prepare_duplicate_data + end + + let(:domain) { 'example.host' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating domain_blocks', + 'Restoring domain_blocks indexes', + 'Finished!' + ) + .and change(duplicate_domain_blocks, :count).from(2).to(1) + end + + def duplicate_domain_blocks + DomainBlock.where(domain: domain) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :domain_blocks, :domain + Fabricate(:domain_block, domain: domain) + Fabricate.build(:domain_block, domain: domain).save(validate: false) + end + end + + context 'with duplicate email_domain_blocks' do + before do + prepare_duplicate_data + end + + let(:domain) { 'example.host' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating email_domain_blocks', + 'Restoring email_domain_blocks indexes', + 'Finished!' + ) + .and change(duplicate_email_domain_blocks, :count).from(2).to(1) + end + + def duplicate_email_domain_blocks + EmailDomainBlock.where(domain: domain) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :email_domain_blocks, :domain + Fabricate(:email_domain_block, domain: domain) + Fabricate.build(:email_domain_block, domain: domain).save(validate: false) + end + end + + context 'with duplicate media_attachments' do + before do + prepare_duplicate_data + end + + let(:shortcode) { 'codenam' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating media_attachments', + 'Restoring media_attachments indexes', + 'Finished!' + ) + .and change(duplicate_media_attachments, :count).from(2).to(1) + end + + def duplicate_media_attachments + MediaAttachment.where(shortcode: shortcode) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :media_attachments, :shortcode + Fabricate(:media_attachment, shortcode: shortcode) + Fabricate.build(:media_attachment, shortcode: shortcode).save(validate: false) + end + end + + context 'with duplicate preview_cards' do + before do + prepare_duplicate_data + end + + let(:url) { 'https://example.host/path' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating preview_cards', + 'Restoring preview_cards indexes', + 'Finished!' + ) + .and change(duplicate_preview_cards, :count).from(2).to(1) + end + + def duplicate_preview_cards + PreviewCard.where(url: url) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :preview_cards, :url + Fabricate(:preview_card, url: url) + Fabricate.build(:preview_card, url: url).save(validate: false) + end + end + + context 'with duplicate statuses' do + before do + prepare_duplicate_data + end + + let(:uri) { 'https://example.host/path' } + let(:account) { Fabricate(:account) } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating statuses', + 'Restoring statuses indexes', + 'Finished!' + ) + .and change(duplicate_statuses, :count).from(2).to(1) + end + + def duplicate_statuses + Status.where(uri: uri) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :statuses, :uri + Fabricate(:status, account: account, uri: uri) + duplicate = Fabricate.build(:status, account: account, uri: uri) + duplicate.save(validate: false) + Fabricate(:status_pin, account: account, status: duplicate) + Fabricate(:status, in_reply_to_id: duplicate.id) + Fabricate(:status, reblog_of_id: duplicate.id) + end + end + + context 'with duplicate tags' do + before do + prepare_duplicate_data + end + + let(:name) { 'tagname' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating tags', + 'Restoring tags indexes', + 'Finished!' + ) + .and change(duplicate_tags, :count).from(2).to(1) + end + + def duplicate_tags + Tag.where(name: name) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :tags, name: 'index_tags_on_name_lower_btree' + Fabricate(:tag, name: name) + Fabricate.build(:tag, name: name).save(validate: false) + end + end + + context 'with duplicate webauthn_credentials' do + before do + prepare_duplicate_data + end + + let(:external_id) { '123_123_123' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating webauthn_credentials', + 'Restoring webauthn_credentials indexes', + 'Finished!' + ) + .and change(duplicate_webauthn_credentials, :count).from(2).to(1) + end + + def duplicate_webauthn_credentials + WebauthnCredential.where(external_id: external_id) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :webauthn_credentials, :external_id + Fabricate(:webauthn_credential, external_id: external_id) + Fabricate.build(:webauthn_credential, external_id: external_id).save(validate: false) + end + end + + context 'with duplicate webhooks' do + before do + prepare_duplicate_data + end + + let(:url) { 'https://example.host/path' } + + it 'runs the deduplication process' do + expect { subject } + .to output_results( + 'Deduplicating webhooks', + 'Restoring webhooks indexes', + 'Finished!' + ) + .and change(duplicate_webhooks, :count).from(2).to(1) + end + + def duplicate_webhooks + Webhook.where(url: url) + end + + def prepare_duplicate_data + ActiveRecord::Base.connection.remove_index :webhooks, :url + Fabricate(:webhook, url: url) + Fabricate.build(:webhook, url: url).save(validate: false) + end + end + def agree_to_backup_warning allow(cli.shell) .to receive(:yes?) From 9e5ddc1745bf729888dc2b11300955c715e95008 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:09:00 +0100 Subject: [PATCH 03/20] New Crowdin Translations (automated) (#28451) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/lad.json | 28 +++++ app/javascript/mastodon/locales/tr.json | 4 +- config/locales/devise.ie.yml | 10 ++ config/locales/ie.yml | 38 +++++++ config/locales/lad.yml | 135 +++++++++++++++++++++++ config/locales/simple_form.ie.yml | 18 +++ config/locales/simple_form.lad.yml | 9 ++ config/locales/tr.yml | 2 +- 8 files changed, 241 insertions(+), 3 deletions(-) diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index 1b501c710a..c776a91ee7 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -77,6 +77,10 @@ "admin.dashboard.retention.average": "Media", "admin.dashboard.retention.cohort": "Mez de enrejistrasyon", "admin.dashboard.retention.cohort_size": "Muevos utilizadores", + "admin.impact_report.instance_accounts": "Profiles de kuentos esto efasaria", + "admin.impact_report.instance_followers": "Suivantes a los kualos nuestros utilizadores perderian", + "admin.impact_report.instance_follows": "Suivantes a los kualos sus utilizadores perderian", + "admin.impact_report.title": "Rezumen de impakto", "alert.rate_limited.message": "Por favor aprova dempues de {retry_time, time, medium}.", "alert.rate_limited.title": "Trafiko limitado", "alert.unexpected.message": "Afito un yerro no asperado.", @@ -220,6 +224,7 @@ "emoji_button.search_results": "Rizultados de bushkeda", "emoji_button.symbols": "Simbolos", "emoji_button.travel": "Viajes i lugares", + "empty_column.account_hides_collections": "Este utilizador desidio no mostrar esta enformasyon", "empty_column.account_suspended": "Kuento suspendido", "empty_column.account_timeline": "No ay publikasyones aki!", "empty_column.account_unavailable": "Profil no desponivle", @@ -294,6 +299,8 @@ "hashtag.column_settings.tag_mode.any": "Kualsekera de estos", "hashtag.column_settings.tag_mode.none": "Dinguno de estos", "hashtag.column_settings.tag_toggle": "Inkluir etiketas adisionalas en esta kolumna", + "hashtag.counter_by_accounts": "{count, plural, one {{counter} partisipante} other {{counter} partisipantes}}", + "hashtag.counter_by_uses": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}}", "hashtag.counter_by_uses_today": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}} oy", "hashtag.follow": "Segir etiketa", "hashtag.unfollow": "Desegir etiketa", @@ -303,18 +310,23 @@ "home.column_settings.basic": "Opsyones bazikas", "home.column_settings.show_reblogs": "Amostrar repartajasyones", "home.column_settings.show_replies": "Amostrar repuestas", + "home.explore_prompt.body": "Tu linya prinsipala es una mikstura de publikasyones kon etiketas a las kualas eskojites a segir, la djente a la kuala eskojites a segir i las publikasyones ke eyos repartajan. Si esta demaziado trankila, puedes:", + "home.explore_prompt.title": "Esta es tu baza prinsipala en Mastodon.", "home.hide_announcements": "Eskonde pregones", "home.pending_critical_update.body": "Por favor aktualiza tu sirvidor de Mastodon pishin!", "home.pending_critical_update.link": "Ve aktualizasyones", + "home.pending_critical_update.title": "Aktualizasyon de seguridad kritika esta desponivle!", "home.show_announcements": "Amostra pregones", "interaction_modal.description.favourite": "Kon un kuento en Mastodon, puedes markar esta publikasyon komo favorita para ke el autor sepa ke te plaze i para guadrarla para dempues.", "interaction_modal.description.follow": "Kon un kuento en Mastodon, puedes segir a {name} para risivir sus publikasyones en tu linya temporal prinsipala.", "interaction_modal.description.reblog": "Kon un kuento en Mastodon, puedes repartajar esta publikasyon para amostrarla a tus suivantes.", "interaction_modal.description.reply": "Kon un kuento en Mastodon, puedes arispondir a esta publikasyon.", + "interaction_modal.login.action": "Va a tu sirvidor", "interaction_modal.login.prompt": "Domeno del sirvidor de tu kuento, por enshemplo mastodon.social", "interaction_modal.no_account_yet": "No tyenes kuento de Mastodon?", "interaction_modal.on_another_server": "En otro sirvidor", "interaction_modal.on_this_server": "En este sirvidor", + "interaction_modal.sign_in": "No estas konektado kon este sirvidor. Ande tyenes tu kuento?", "interaction_modal.title.favourite": "Endika ke te plaze publikasyon de {name}", "interaction_modal.title.follow": "Sige a {name}", "interaction_modal.title.reblog": "Repartaja publikasyon de {name}", @@ -369,6 +381,7 @@ "lists.delete": "Efasa lista", "lists.edit": "Edita lista", "lists.edit.submit": "Troka titolo", + "lists.exclusive": "Eskonder estas publikasyones de linya prinsipala", "lists.new.create": "Adjusta lista", "lists.new.title_placeholder": "Titolo de mueva lista", "lists.replies_policy.followed": "Kualseker utilizardo segido", @@ -403,6 +416,7 @@ "navigation_bar.lists": "Listas", "navigation_bar.logout": "Salir", "navigation_bar.mutes": "Utilizadores silensiados", + "navigation_bar.opened_in_classic_interface": "Publikasyones, kuentos i otras pajinas espesifikas se avren kon preferensyas predeterminadas en la enterfaz web klasika.", "navigation_bar.personal": "Personal", "navigation_bar.pins": "Publikasyones fiksadas", "navigation_bar.preferences": "Preferensyas", @@ -460,17 +474,24 @@ "notifications_permission_banner.title": "Nunka te piedres niente", "onboarding.action.back": "Va atras", "onboarding.actions.back": "Va atras", + "onboarding.actions.go_to_explore": "Va a los trendes", + "onboarding.actions.go_to_home": "Va a tu linya prinsipala", "onboarding.compose.template": "Ke haber, #Mastodon?", "onboarding.follows.title": "Personaliza tu linya prinsipala", "onboarding.profile.display_name": "Nombre amostrado", "onboarding.profile.display_name_hint": "Tu nombre para amostrar.", "onboarding.profile.note": "Tu deskripsyon", + "onboarding.profile.note_hint": "Puedes @enmentar a otra djente o #etiketas…", "onboarding.profile.save_and_continue": "Guadra i kontinua", "onboarding.profile.title": "Konfigurasyon de profil", "onboarding.profile.upload_avatar": "Karga imaje de profil", "onboarding.profile.upload_header": "Karga kavesera de profil", + "onboarding.share.message": "Soy {username} en #Mastodon! Segidme en {url}", + "onboarding.share.next_steps": "Posivles sigientes pasos:", "onboarding.share.title": "Partaja tu profil", "onboarding.start.skip": "No nesesitas ayudo para ampesar?", + "onboarding.start.title": "Lo logrates!", + "onboarding.steps.follow_people.body": "El buto de Mastodon es segir a djente interesante.", "onboarding.steps.follow_people.title": "Personaliza tu linya prinsipala", "onboarding.steps.publish_status.title": "Eskrive tu primera publikasyon", "onboarding.steps.setup_profile.title": "Personaliza tu profil", @@ -515,6 +536,7 @@ "reply_indicator.cancel": "Anula", "report.block": "Bloka", "report.block_explanation": "No veras sus publikasyones. No podra ver tus publikasyones ni segirte. Podra saver ke le blokates.", + "report.categories.legal": "Legal", "report.categories.other": "Otros", "report.categories.spam": "Spam", "report.categories.violation": "El kontenido viola una o mas reglas del sirvidor", @@ -552,6 +574,7 @@ "report.unfollow": "Desegir a @{name}", "report.unfollow_explanation": "Estas sigiendo este kuento. Para no ver sus publikasyones en tu linya de tiempo, puedes deshar de segirlo.", "report_notification.attached_statuses": "{count, plural, one {{count} publikasyon} other {{count} publikasyones}} atadas", + "report_notification.categories.legal": "Legal", "report_notification.categories.other": "Otros", "report_notification.categories.spam": "Spam", "report_notification.categories.violation": "Violasion de reglas", @@ -570,6 +593,7 @@ "search_popout.options": "Opsyones de bushkeda", "search_popout.quick_actions": "Aksiones rapidas", "search_popout.recent": "Bushkedas resientes", + "search_popout.specific_date": "dato espesifiko", "search_popout.user": "utilizador", "search_results.accounts": "Profiles", "search_results.all": "Todos", @@ -596,10 +620,12 @@ "status.cannot_reblog": "Esta publikasyon no se puede repartajar", "status.copy": "Kopia atadijo de publikasyon", "status.delete": "Efasa", + "status.detailed_status": "Vista de konversasyon detalyada", "status.direct": "Enmenta a @{name} en privado", "status.direct_indicator": "Enmentadura privada", "status.edit": "Edita", "status.edited": "Editado {date}", + "status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} vezes}}", "status.embed": "Inkrusta", "status.favourite": "Te plaze", "status.filter": "Filtra esta publikasyon", @@ -637,6 +663,7 @@ "status.show_more": "Amostra mas", "status.show_more_all": "Amostra mas para todo", "status.show_original": "Amostra orijinal", + "status.title.with_attachments": "{user} publiko {attachmentCount, plural, one {un anekso} other {{attachmentCount} aneksos}}", "status.translate": "Trezlada", "status.translated_from_with": "Trezladado dizde {lang} kon {provider}", "status.uncached_media_warning": "Vista previa no desponivle", @@ -685,6 +712,7 @@ "upload_modal.preview_label": "Vista previa ({ratio})", "upload_progress.label": "Kargando...", "upload_progress.processing": "Prosesando…", + "username.taken": "Akel nombre de utilizador ya esta en uzo. Aprova otruno", "video.close": "Serra video", "video.download": "Abasha dosya", "video.exit_fullscreen": "Sal de ekran kompleto", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 8eb09bb7cb..e6389b05a5 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -45,7 +45,7 @@ "account.joined_short": "Katıldı", "account.languages": "Abone olunan dilleri değiştir", "account.link_verified_on": "Bu bağlantının sahipliği {date} tarihinde denetlendi", - "account.locked_info": "Bu hesabın gizlilik durumu gizli olarak ayarlanmış. Sahibi, onu kimin takip edebileceğini manuel olarak onaylıyor.", + "account.locked_info": "Bu hesabın gizlilik durumu gizli olarak ayarlanmış. Sahibi, onu kimin takip edebileceğini elle onaylıyor.", "account.media": "Medya", "account.mention": "@{name} kişisinden bahset", "account.moved_to": "{name} yeni hesabının artık şu olduğunu belirtti:", @@ -345,7 +345,7 @@ "keyboard_shortcuts.down": "Listede aşağıya inmek için", "keyboard_shortcuts.enter": "gönderiyi aç", "keyboard_shortcuts.favourite": "Gönderiyi favorilerine ekle", - "keyboard_shortcuts.favourites": "Favoriler listeni aç", + "keyboard_shortcuts.favourites": "Gözde listeni aç", "keyboard_shortcuts.federated": "Federe akışı aç", "keyboard_shortcuts.heading": "Klavye kısayolları", "keyboard_shortcuts.home": "Ana akışı aç", diff --git a/config/locales/devise.ie.yml b/config/locales/devise.ie.yml index cee5357c24..0cf0fbe1fe 100644 --- a/config/locales/devise.ie.yml +++ b/config/locales/devise.ie.yml @@ -2,8 +2,16 @@ ie: devise: failure: + already_authenticated: Tu ha ja intrat. + inactive: Tui conto ancor ne ha esset activat. invalid: Ínvalid %{authentication_keys} o passa-parol. + last_attempt: Hay solmen un prova ante que tui conto deveni serrat. + locked: Tui conto es serrat. not_found_in_database: Ínvalid %{authentication_keys} o passa-parol. + pending: Tui conto es ancor sub revision. + timeout: Tui session ha expirat. Ples reintrar denov por continuar. + unauthenticated: Tu deve intrar o registrar te ante continuar. + unconfirmed: Tu deve confirmar tui e-posta ante continuar. mailer: email_changed: extra: Si tu ne changeat tui email-adresse, it es probabil que alqui ha ganiat accesse a tui conto. Ples changear tui passa-parol strax o contacter li administrator del servitor si tu ne posse intrar tui conto. @@ -20,6 +28,8 @@ ie: title: Reiniciar passa-parol two_factor_disabled: explanation: 2-factor autentication por tui conto ha esset desactivisat. Aperter session nu es possibil solmen per email-adresse e passa-parol. + omniauth_callbacks: + failure: Ne posset autenticar te de %{kind} pro "%{reason}". passwords: no_token: Tu ne posse accessar ti-ci págine sin venir de un email pri reiniciar li passa-parol. Si tu ha venit de un email pri reiniciar li passa-parol, ples far cert que tu usat li complet URL providet. send_instructions: Si tui email-adresse existe in nor database, tu va reciver un ligament por recuperar li passa-parol a tui email-adresse in quelc minutes. Ples vider tui spam-emails si tu ne recivet ti email. diff --git a/config/locales/ie.yml b/config/locales/ie.yml index 94df7d1454..c9eef75204 100644 --- a/config/locales/ie.yml +++ b/config/locales/ie.yml @@ -329,6 +329,7 @@ ie: title: Adjunter nov customisat emoji no_emoji_selected: Null emoji esset changeat pro que null esset selectet not_permitted: Tu ne es permisset far ti action + overwrite: Remplazzar shortcode_hint: Adminim 2 carácteres, solmen lítteres, ciffres e sublineas title: Customisat emoji uncategorized: Íncategorisat @@ -433,6 +434,7 @@ ie: title: Bloccar nov email-dominia no_email_domain_block_selected: Null email-dominia-bloccas esset changeat pro que null esset selectet not_permitted: Ne permisset + resolved_through_html: Resoluet per %{domain} title: Bloccat email-dominias export_domain_allows: new: @@ -459,6 +461,7 @@ ie: unsuppress: Restaurar seque-recomandation instances: availability: + no_failures_recorded: Null fallimentes registrat. title: Disponibilitá warning: Li ultim prova conexer a ti servitor ha esset ínsuccessosi back_to_all: Omni @@ -601,15 +604,36 @@ ie: status: Statu statuses: Contenete raportat summary: + action_preambles: + delete_html: 'Tu va remover alcun postas de @%{acct}''. To va:' + mark_as_sensitive_html: 'Tu va marcar alcun postas de @%{acct} quam sensitiv. To va:' + silence_html: 'Tu va limitar li conto de @%{acct}. To va:' + suspend_html: 'Tu va suspender li conto de @%{acct}. To va:' close_report: 'Marcar raporte #%{id} quam resoluet' title: Raportes + unassign: Ínassignar + unknown_action_msg: 'Ínconosset action: %{action}' + unresolved: Ínresoluet + updated_at: Actualisat + view_profile: Vider profil roles: + add_new: Adjunter un rol + assigned_users: + one: "%{count} usator" + other: "%{count} usatores" categories: + administration: Administration devops: DevOps invites: Invitationes moderation: Moderation special: Special delete: Deleter + description_html: Con roles por usatores, tu posse customisar li functiones e locs de Mastodon in queles tui usatores posse accesser. + edit: Modificar rol '%{name}' + everyone: Permissiones predefinit + permissions_count: + one: "%{count} permission" + other: "%{count} permissiones" privileges: administrator: Administrator delete_user_data: Deleter Data de Usator @@ -618,26 +642,39 @@ ie: manage_announcements: Tractar proclamationes manage_announcements_description: Permisse usatores tractar proclamationes sur li servitor manage_appeals: Gerer Apelles + manage_blocks: Gerer Bloccas + manage_custom_emojis: Gerer Customisat Emojis manage_federation: Gerer Federation manage_invites: Gerer Invitationes manage_reports: Gerer Raportes manage_roles: Gerer Roles + manage_rules: Gerer Regules + manage_settings: Gerer Parametres manage_taxonomies: Gerer Taxonomies manage_user_access_description: Permisse usatores desactivisar li 2-factor autentication de altri usatores, changear lor email-adresses, e reiniciar lor passa-paroles manage_users: Gerer usatores + manage_webhooks: Gerer Web-crocs + view_devops: DevOps title: Roles rules: add_new: Adjunter un regule + delete: Deleter + edit: Redacter regul + empty: Ancor null regules de servitor ha esset definit. title: Regules del servitor settings: about: + manage_rules: Gerer regules de servitor title: Pri appearance: title: Aspecte discovery: profile_directory: Profilarium public_timelines: Public témpor-lineas + title: Decovriment domain_blocks: + all: Ad omnes + disabled: A necun users: A local usatores qui ha initiat session registrations: title: Registrationes @@ -645,6 +682,7 @@ ie: modes: none: Nequi posse registrar se open: Quicunc posse registrar se + title: Parametres del servitor site_uploads: delete: Deleter cargat file destroyed_msg: Cargat file successosimen deletet! diff --git a/config/locales/lad.yml b/config/locales/lad.yml index afa6d2930c..36364feba2 100644 --- a/config/locales/lad.yml +++ b/config/locales/lad.yml @@ -306,6 +306,7 @@ lad: unpublish: Retirar publikasyon unpublished_msg: Pregon retirado kon sukseso! updated_msg: Pregon aktualizado kon sukseso! + critical_update_pending: Aktualizasyon kritika esta asperando custom_emojis: assign_category: Asinyar kategoria by_domain: Domeno @@ -331,6 +332,7 @@ lad: no_emoji_selected: No se troko dingun emoji porke no eskojites dinguno not_permitted: No tienes permiso para realizar esta aksyon overwrite: Sobreskrive + shortcode: Kodiche kurto title: Emojis personalizados uncategorized: No kategorizado unlist: No lista @@ -380,6 +382,7 @@ lad: confirm_suspension: cancel: Anula confirm: Suspende + title: Konfirma bloko de domeno para %{domain} created_msg: El bloko de domeno esta siendo prosesado destroyed_msg: El bloko de domeno se dezizo domain: Domeno @@ -702,6 +705,7 @@ lad: manage_users: Administra utilizadores manage_users_description: Permete a los utilizadores ver los peratim de otros utilizadores i realizar aksyones de moderasyon kontra eyos manage_webhooks: Administrar webhooks + view_dashboard: Ve pano view_devops: DevOps title: Rolos rules: @@ -715,10 +719,17 @@ lad: title: Sovre esto appearance: title: Aparensya + branding: + title: Marka + content_retention: + title: Retensyon de kontenido discovery: follow_recommendations: Rekomendasyones de kuentos profile_directory: Katalogo de profiles public_timelines: Linyas de tiempo publikas + publish_discovered_servers: Publika sirvidores diskuviertos + publish_statistics: Publika estatistikas + title: Diskuvrimiento trends: Trendes domain_blocks: all: A todos @@ -737,7 +748,9 @@ lad: delete: Efasa dosya kargada destroyed_msg: Dosya supremida kon sukseso! software_updates: + critical_update: Kritiko – por favor aktualiza pishin documentation_link: Ambezate mas + release_notes: Notas sovre la versyon title: Aktualizasyones desponivles type: Tipo version: Versyon @@ -795,6 +808,10 @@ lad: message_html: No tienes definido dinguna regla del sirvidor. sidekiq_process_check: message_html: No ay dingun prosedura Sidekiq en egzekusion para la(s) kola(s) %{value}. Por favor, reviza tu konfigurasyon de Sidekiq + software_version_critical_check: + action: Amostra aktualizasyones desponivles + software_version_patch_check: + action: Amostra aktualizasyones desponivles upload_check_privacy_error: message_html: "Tu sirvidor de web es mal konfigurado. La privasita de tus utilizadores esta en riziko." upload_check_privacy_error_object_storage: @@ -852,7 +869,9 @@ lad: listable: Pueden ser rekomendadas no_tag_selected: No se troko dinguna etiketa al no eskojer dinguna not_listable: No seran rekomendadas + not_trendable: No aperesera en trendes not_usable: No se pueden uzar + title: Etiketas en trend trendable: Pueden apareser en trendes trending_rank: Trend n.º %{rank} usable: Pueden uzarse @@ -901,6 +920,8 @@ lad: body: "%{target} esta apelando a una solisitasyon de moderasyon de %{action_taken_by} el %{date}, del tipo %{type}. Eyos eskrivieron:" next_steps: Puedes achetar la apelasyon para dezazer la dechizyon de moderasyon, o ignorarla. subject: "%{username} esta apelando a una dechizyon de moderasyon en %{instance}" + new_critical_software_updates: + subject: Ay aktualizasyones kritikas de Mastodon desponivles para %{instance}! new_pending_account: body: Los peratim del muevo kuento estan abashos. Puedes achetar o refuzar esta aplikasyon. subject: Muevo kuento para revizion en %{instance} (%{username}) @@ -908,6 +929,9 @@ lad: body: "%{reporter} tiene raportado a %{target}" body_remote: Alguno de %{domain} a raportado a %{target} subject: Muevo raporto para la %{instance} (#%{id}) + new_software_updates: + body: Ay mueva versyon de Mastodon, kizas keras aktualizar! + subject: Ay muevas versyones de Mastodon desponivles para %{instance}! new_trends: body: 'Los sigientes elementos nesesitan una revizion antes de ke se puedan amostrar publikamente:' new_trending_links: @@ -916,10 +940,20 @@ lad: title: Publikasyones en trend new_trending_tags: title: Etiketas en trend + aliases: + add_new: Kriya un alias + empty: No tienes aliases. + remove: Dezata alias appearance: advanced_web_interface: Enterfaz web avanzada + animations_and_accessibility: Animasyones i aksesivilita + confirmation_dialogs: Dialogos de konfirmasyon + discovery: Diskuvrimiento + localization: + guide_link_text: Todos pueden kontribuir. sensitive_content: Kontenido sensivle application_mailer: + notification_preferences: Troka preferensyas de posta salutation: "%{name}," settings: 'Troka preferensyas de posta: %{link}' unsubscribe: Dezabona @@ -936,7 +970,11 @@ lad: your_token: Tu token de akseso auth: apply_for_account: Solisita un kuento + captcha_confirmation: + title: Kontrolo de sigurita confirmations: + awaiting_review_title: Estamos revizando tu enrejistramiento + clicking_this_link: klikando en este atadijo login_link: konektate kon kuento welcome_title: Bienvenido, %{name}! wrong_email_hint: Si este adreso de posta es inkorekto, puedes trokarlo en las preferensyas del kuento. @@ -962,6 +1000,7 @@ lad: progress: confirm: Konfirma posta details: Tus detalyos + review: Muestra revizyon rules: Acheta reglas providers: cas: CAS @@ -975,10 +1014,12 @@ lad: back: Atras preamble: Estas son establesidas i aplikadas por los moderadores de %{domain}. title: Algunas reglas bazikas. + title_invited: Fuites envitado. security: Sigurita set_new_password: Establese muevo kod setup: email_below_hint_html: Mira en tu kuti de spam o solisita de muevo. Si el adreso de posta elektronika ke aparese aki es yerrado, puedes trokarlo aki. + link_not_received: No risivites un atadijo? sign_in: preamble_html: Konektate kon tus kredensiales de %{domain}. Si tu kuento esta balabayado en otruno servidor, no puedras konektarte aki. title: Konektate kon %{domain} @@ -1023,6 +1064,8 @@ lad: x_seconds: "%{count} s" deletes: proceed: Efasa kuento + warning: + username_unavailable: Tu nombre de utilizador no estara desponivle disputes: strikes: action_taken: Aksyon tomada @@ -1054,6 +1097,7 @@ lad: domain_validator: invalid_domain: no es un nombre de domeno valido edit_profile: + basic_information: Enformasyon bazika other: Otros errors: '400': La solisitasyon ke enviates no fue valida o fue malformada. @@ -1093,14 +1137,27 @@ lad: filters: contexts: account: Profiles + home: Prinsipyo i listas notifications: Avizos public: Linyas de tiempo publikas + thread: Konversasyones edit: add_keyword: Adjusta biervo yave keywords: Biervos yaves statuses: Publikasyones individualas + title: Edita filtro index: delete: Efasa + empty: No tyenes filtros. + keywords: + one: "%{count} biervo yave" + other: "%{count} biervos yave" + statuses: + one: "%{count} publikasyon" + other: "%{count} publikasyones" + statuses_long: + one: "%{count} publikasyon individuala eskondida" + other: "%{count} publikasyones individualas eskondidas" title: Filtros new: save: Guadra muevo filtro @@ -1109,17 +1166,22 @@ lad: back_to_filter: Retorna al filtro batch: remove: Kita del filtro + index: + title: Publikasyones filtradas generic: all: Todos cancel: Anula + changes_saved_msg: Trokamientos guadrados kon reusho! confirm: Konfirma copy: Kopia delete: Efasa + deselect: Deseleksyonar todo none: Dinguno save_changes: Guadra trokamientos today: oy imports: errors: + empty: Dosya CSV vaziya invalid_csv_file: 'Dosya CSV no valida. Yerro: %{error}' over_rows_processing_limit: kontiene mas de %{count} filas too_large: Dosya es mas grande @@ -1130,19 +1192,35 @@ lad: overwrite: Sobreskrive overwrite_long: Mete muevos rejistros en vez de los aktuales preface: Puedes importar siertos datos, komo todas las personas a las kualas estas sigiendo o blokando en tu kuento en esta instansya, dizde dosyas eksportadas de otra instansya. + recent_imports: Importasyones resyentes states: finished: Finalizado scheduled: Programado unconfirmed: Sin konfirmasyon status: Estado success: Tus datos se tienen kargado djustamente i seran prosesados pishin + time_started: Ampesado el + titles: + bookmarks: Importando markadores + domain_blocking: Importando domenos blokados + following: Importando kuentos segidos + lists: Importando listas + muting: Importando kuentos silensyados + type: Tipo de importasyon + type_groups: + constructive: Segidores i markadores + destructive: Blokos i silensyos types: blocking: Lista de blokos bookmarks: Markadores + domain_blocking: Lista de domenos blokados + following: Lista de segidos lists: Listas + muting: Lista de silensyados upload: Karga invites: delete: Dezaktiva + expired: Kadukado expires_in: '1800': 30 minutos '21600': 6 oras @@ -1151,6 +1229,8 @@ lad: '604800': 1 semana '86400': 1 diya expires_in_prompt: Nunkua + invalid: Esta envitasyon no es valida + invited_by: 'Fuites envitado por:' max_uses: one: 1 uzo other: "%{count} uzos" @@ -1214,12 +1294,31 @@ lad: moderation: title: Moderasyon notification_mailer: + admin: + sign_up: + subject: "%{name} se enrejistro" + favourite: + title: Muevo favorito follow: + body: "%{name} te esta sigiendo!" + subject: "%{name} te esta sigiendo" title: Muevo suivante follow_request: + subject: 'Segidor esta asperando: %{name}' title: Mueva solisitud de segimiento mention: action: Arisponde + body: 'Fuites enmentado por %{name} en:' + subject: Fuites enmentado por %{name} + title: Mueva enmentadura + reblog: + title: Mueva repartajasyon + status: + subject: "%{name} publiko algo" + update: + subject: "%{name} edito una publikasyon" + notifications: + other_settings: Otras preferensyas de avizos number: human: decimal_units: @@ -1227,7 +1326,9 @@ lad: units: billion: MM million: M + quadrillion: Ku thousand: K + trillion: T otp_authentication: enable: Kapasita instructions_html: "Eskanea este kodiche QR dizde Google Authenticator o una aplikasyon similar en tu telefon. A partir de agora, esta aplikasyon djenerara kodiches ke tendras ke ingresar kuando keras konektarte kon tu kuento." @@ -1249,6 +1350,7 @@ lad: expired: La anketa ya tiene eskapado invalid_choice: La opsyon de voto eskojida no egziste over_character_limit: no puede trespasar %{max} karakteres kada uno + self_vote: No puedes votar en tus propias anketas too_few_options: deve tener mas de un elemento too_many_options: no puede kontener mas de %{max} elementos preferences: @@ -1286,6 +1388,7 @@ lad: content_warning: 'Avertensya de kontenido:' sessions: activity: Ultima aktivita + browser: Navigador browsers: alipay: Alipay blackberry: BlackBerry @@ -1293,6 +1396,7 @@ lad: edge: Microsoft Edge electron: Electron firefox: Firefox + generic: Navigador deskonosido huawei_browser: Huawei Browser ie: Internet Explorer micro_messenger: MicroMessenger @@ -1303,6 +1407,7 @@ lad: qq: QQ Browser safari: Safari uc_browser: UC Browser + unknown_browser: Navigador deskonosido weibo: Weibo current_session: Sesyon aktuala ip: IP @@ -1374,9 +1479,30 @@ lad: limit: Ya tienes fiksado el numero maksimo de publikasyones ownership: La publikasyon de otra persona no puede fiksarse poll: + total_people: + one: "%{count} persona" + other: "%{count} personas" + total_votes: + one: "%{count} voto" + other: "%{count} votos" vote: Vota show_more: Amostra mas + show_newer: Amostra mas muevos + show_older: Amostra mas viejos + show_thread: Amostra diskusyon + title: '%{name}: "%{quote}"' + visibilities: + direct: Direkto + private: Solo suivantes + private_long: Solo amostra a tus segidores + public: Publiko + public_long: Todos pueden ver + unlisted: No listado statuses_cleanup: + enabled: Otomatikamente efasa publikasyones viejas + exceptions: Eksepsiones + ignore_favs: Ignora favoritos + ignore_reblogs: Ignora repartajasyones min_age: '1209600': 2 semanas '15778476': 6 mezes @@ -1451,14 +1577,23 @@ lad: mark_statuses_as_sensitive: Algunas de tus publikasyones an sido markados komo sensivles por los moderadores de %{instance}. Esto sinyifika ke la djente tendra ke pulsar los dosyas multimedia en las publikasyones antes de ke se amostre una vista previa. Puedes markar los dosyas multimedia komo sensivles tu mezmo kuando publikes en el avenir. sensitive: A partir de agora todas los dosyas multimedia ke subas seran markados komo sensivles i eskondidos tras una avertensya. reason: 'Razon:' + subject: + none: Avertensya para %{acct} title: + delete_statuses: Publikasyones efasadas + mark_statuses_as_sensitive: Publikasyones markadas komo sensivles none: Avertensya silence: Kuento limitado suspend: Kuento suspendido + welcome: + final_action: Ampesa a publikar + subject: Bienvenido a Mastodon users: + invalid_otp_token: Kodiche de dos pasos no valido signed_in_as: 'Konektado komo:' verification: verification: Verifikasyon + verified_links: Tus atadijos verifikados webauthn_credentials: add: Adjusta mueva yave de sigurita delete: Efasa diff --git a/config/locales/simple_form.ie.yml b/config/locales/simple_form.ie.yml index a94903b662..ff1587be8f 100644 --- a/config/locales/simple_form.ie.yml +++ b/config/locales/simple_form.ie.yml @@ -47,6 +47,7 @@ ie: setting_display_media_show_all: Sempre monstrar medie form_admin_settings: bootstrap_timeline_accounts: Ti-ci contos va esser pinglat al parte superiori del recomandationes por nov usatores. + site_contact_username: Qualmen li gente posse atinger te sur Mastodon. theme: Li dessine quel ínregistrat visitantes e nov usatores vide. timeline_preview: Ínregistrat visitantes va posser vider li max recent public postas disponibil che li servitor. trends_as_landing_page: Monstrar populari contenete a ínregistrat visitantes vice un description del servitor. Besona que tendenties es activisat. @@ -67,15 +68,32 @@ ie: starts_at: Comense del eveniment text: Proclamation defaults: + chosen_languages: Filtrar lingues confirm_new_password: Confirmar nov passa-parol confirm_password: Confirmar passa-parol + context: Filtrar contextus current_password: Actual passa-parol + data: Data + display_name: Nómine a monstrar + email: E-posta + expires_in: Expirar pos honeypot: "%{label} (ne plenar)" locale: Lingue del interfacie new_password: Nov passa-parol note: Biografie password: Passa-parol + setting_default_language: Lingue in quel postar + setting_default_privacy: Privatie de postada + setting_default_sensitive: Sempre marcar medie quam sensitiv + setting_display_media_default: Predefinitiones + setting_display_media_hide_all: Celar omno + setting_display_media_show_all: Monstrar omno + setting_theme: Tema de situ + setting_trends: Monstrar li hodial tendenties + setting_unfollow_modal: Monstrar dialog de confirmation ante dessequer alquem + setting_use_pending_items: Mode lent form_admin_settings: registrations_mode: Qui posse registrar se + theme: Predefenit tema notification_emails: follow_request: Alqui petit sequer te diff --git a/config/locales/simple_form.lad.yml b/config/locales/simple_form.lad.yml index 33fe877db1..e0b8eab876 100644 --- a/config/locales/simple_form.lad.yml +++ b/config/locales/simple_form.lad.yml @@ -168,14 +168,18 @@ lad: confirm_password: Konfirma kod context: Filtra kontekstos current_password: Kod aktual + data: Datos display_name: Nombre amostrado email: Adreso de posta elektronika expires_in: Kaduka dempues de + fields: Datos adisyonales header: Imaje de kavesera + locale: Lingua de enterfaz new_password: Muevo kod note: Deskripsyon otp_attempt: Kodiche de dos pasos password: Kod + phrase: Biervo yave o fraza setting_default_language: Lingua de publikasyones setting_default_privacy: Privasita de publikasyones setting_display_media_default: Predeterminado @@ -247,6 +251,8 @@ lad: follow_request: Alguno tiene solisitado segirte mention: Alguno te enmento reblog: Alguno repartajo tu publikasyon + software_updates: + label: Mueva version de Mastodon esta desponivle rule: text: Regla tag: @@ -259,8 +265,11 @@ lad: position: Priorita webhook: events: Evenimientos kapasitados + url: URL de Endpoint 'no': 'No' + not_recommended: No rekomendado recommended: Rekomendado required: mark: "*" + text: rekerido 'yes': Si diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 098719eb7a..568607e70d 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -1272,7 +1272,7 @@ tr: remove: Filtreden kaldır index: hint: Bu filtre diğer ölçütlerden bağımsız olarak tekil gönderileri seçmek için uygulanıyor. Web arayüzünü kullanarak bu filtreye daha fazla gönderi ekleyebilirsiniz. - title: Filtrelenmiş gönderiler + title: Süzgeçlenmiş gönderiler generic: all: Tümü all_items_on_page_selected_html: From 87e2bd02ac3accd198f43d30723bc3027fb4bffd Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 10:13:10 +0100 Subject: [PATCH 04/20] Update dependency irb to v1.11.0 (#28442) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 15bdb9b4f8..cc262f8e1a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -376,8 +376,8 @@ GEM rainbow (>= 2.2.2, < 4.0) terminal-table (>= 1.5.1) idn-ruby (0.1.5) - io-console (0.6.0) - irb (1.10.1) + io-console (0.7.1) + irb (1.11.0) rdoc reline (>= 0.3.8) jmespath (1.6.2) @@ -540,7 +540,7 @@ GEM activesupport (>= 7.0.0) rack railties (>= 7.0.0) - psych (5.1.1.1) + psych (5.1.2) stringio public_suffix (5.0.4) puma (6.4.0) @@ -614,7 +614,7 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-normalize (0.6.1) rdf (~> 3.2) - rdoc (6.6.1) + rdoc (6.6.2) psych (>= 4.0.0) redcarpet (3.6.0) redis (4.8.1) From c753b1ad35ae84c21c0474bdb052833b2bd4463a Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 21 Dec 2023 04:18:38 -0500 Subject: [PATCH 05/20] Clean up of `RSpec/LetSetup` within `spec/models` (#28444) --- .rubocop_todo.yml | 3 --- spec/models/account_spec.rb | 1 + spec/models/canonical_email_block_spec.rb | 2 +- spec/models/user_spec.rb | 2 ++ 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 030f311101..bb2715f96e 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -63,11 +63,8 @@ RSpec/LetSetup: - 'spec/lib/activitypub/activity/delete_spec.rb' - 'spec/lib/vacuum/applications_vacuum_spec.rb' - 'spec/lib/vacuum/preview_cards_vacuum_spec.rb' - - 'spec/models/account_spec.rb' - 'spec/models/account_statuses_cleanup_policy_spec.rb' - - 'spec/models/canonical_email_block_spec.rb' - 'spec/models/status_spec.rb' - - 'spec/models/user_spec.rb' - 'spec/services/account_statuses_cleanup_service_spec.rb' - 'spec/services/activitypub/fetch_featured_collection_service_spec.rb' - 'spec/services/activitypub/fetch_remote_status_service_spec.rb' diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index 522549125f..87aa8bc754 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -954,6 +954,7 @@ RSpec.describe Account do it 'returns every usable non-suspended account' do expect(described_class.searchable).to contain_exactly(silenced_local, silenced_remote, local_account, remote_account) + expect(described_class.searchable).to_not include(suspended_local, suspended_remote, unconfirmed, unapproved) end it 'does not mess with previously-applied scopes' do diff --git a/spec/models/canonical_email_block_spec.rb b/spec/models/canonical_email_block_spec.rb index 0acff82377..c63483f968 100644 --- a/spec/models/canonical_email_block_spec.rb +++ b/spec/models/canonical_email_block_spec.rb @@ -28,7 +28,7 @@ RSpec.describe CanonicalEmailBlock do end describe '.block?' do - let!(:canonical_email_block) { Fabricate(:canonical_email_block, email: 'foo@bar.com') } + before { Fabricate(:canonical_email_block, email: 'foo@bar.com') } it 'returns true for the same email' do expect(described_class.block?('foo@bar.com')).to be true diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 9111fd7c73..ab5bd39b7b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -422,6 +422,7 @@ RSpec.describe User do it 'deactivates all sessions' do expect(user.session_activations.count).to eq 0 + expect { session_activation.reload }.to raise_error(ActiveRecord::RecordNotFound) end it 'revokes all access tokens' do @@ -430,6 +431,7 @@ RSpec.describe User do it 'removes push subscriptions' do expect(Web::PushSubscription.where(user: user).or(Web::PushSubscription.where(access_token: access_token)).count).to eq 0 + expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound) end end From f32d672d2ffc33fc4b07a6e36f5d9dcbc3f26e4c Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 21 Dec 2023 04:28:41 -0500 Subject: [PATCH 06/20] Clean up of `RSpec/LetSetup` within `spec/controllers` (#28446) --- .rubocop_todo.yml | 5 ---- .../follower_accounts_controller_spec.rb | 7 +++++ .../following_accounts_controller_spec.rb | 7 +++++ ...authorized_applications_controller_spec.rb | 4 +++ .../oauth/tokens_controller_spec.rb | 4 +++ .../settings/imports_controller_spec.rb | 26 ++++++++++--------- 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index bb2715f96e..f834c55620 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -55,11 +55,6 @@ RSpec/LetSetup: - 'spec/controllers/auth/confirmations_controller_spec.rb' - 'spec/controllers/auth/passwords_controller_spec.rb' - 'spec/controllers/auth/sessions_controller_spec.rb' - - 'spec/controllers/follower_accounts_controller_spec.rb' - - 'spec/controllers/following_accounts_controller_spec.rb' - - 'spec/controllers/oauth/authorized_applications_controller_spec.rb' - - 'spec/controllers/oauth/tokens_controller_spec.rb' - - 'spec/controllers/settings/imports_controller_spec.rb' - 'spec/lib/activitypub/activity/delete_spec.rb' - 'spec/lib/vacuum/applications_vacuum_spec.rb' - 'spec/lib/vacuum/preview_cards_vacuum_spec.rb' diff --git a/spec/controllers/follower_accounts_controller_spec.rb b/spec/controllers/follower_accounts_controller_spec.rb index cb8c2a0e5b..dd78c96c05 100644 --- a/spec/controllers/follower_accounts_controller_spec.rb +++ b/spec/controllers/follower_accounts_controller_spec.rb @@ -48,6 +48,13 @@ describe FollowerAccountsController do it 'returns followers' do expect(response).to have_http_status(200) + expect(body_as_json) + .to include( + orderedItems: contain_exactly( + include(follow_from_bob.account.username), + include(follow_from_chris.account.username) + ) + ) expect(body['totalItems']).to eq 2 expect(body['partOf']).to be_present end diff --git a/spec/controllers/following_accounts_controller_spec.rb b/spec/controllers/following_accounts_controller_spec.rb index 095528ed07..7bb78fb420 100644 --- a/spec/controllers/following_accounts_controller_spec.rb +++ b/spec/controllers/following_accounts_controller_spec.rb @@ -48,6 +48,13 @@ describe FollowingAccountsController do it 'returns followers' do expect(response).to have_http_status(200) + expect(body_as_json) + .to include( + orderedItems: contain_exactly( + include(follow_of_bob.target_account.username), + include(follow_of_chris.target_account.username) + ) + ) expect(body['totalItems']).to eq 2 expect(body['partOf']).to be_present end diff --git a/spec/controllers/oauth/authorized_applications_controller_spec.rb b/spec/controllers/oauth/authorized_applications_controller_spec.rb index b54610604c..b46b944d0e 100644 --- a/spec/controllers/oauth/authorized_applications_controller_spec.rb +++ b/spec/controllers/oauth/authorized_applications_controller_spec.rb @@ -63,5 +63,9 @@ describe Oauth::AuthorizedApplicationsController do it 'removes subscriptions for the application\'s access tokens' do expect(Web::PushSubscription.where(user: user).count).to eq 0 end + + it 'removes the web_push_subscription' do + expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound) + end end end diff --git a/spec/controllers/oauth/tokens_controller_spec.rb b/spec/controllers/oauth/tokens_controller_spec.rb index 973393bcf2..dd2d8ca70c 100644 --- a/spec/controllers/oauth/tokens_controller_spec.rb +++ b/spec/controllers/oauth/tokens_controller_spec.rb @@ -20,5 +20,9 @@ RSpec.describe Oauth::TokensController do it 'removes web push subscription for token' do expect(Web::PushSubscription.where(access_token: access_token).count).to eq 0 end + + it 'removes the web_push_subscription' do + expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound) + end end end diff --git a/spec/controllers/settings/imports_controller_spec.rb b/spec/controllers/settings/imports_controller_spec.rb index 1e7b758931..89ec39e54d 100644 --- a/spec/controllers/settings/imports_controller_spec.rb +++ b/spec/controllers/settings/imports_controller_spec.rb @@ -22,6 +22,7 @@ RSpec.describe Settings::ImportsController do it 'assigns the expected imports', :aggregate_failures do expect(response).to have_http_status(200) expect(assigns(:recent_imports)).to eq [import] + expect(assigns(:recent_imports)).to_not include(other_import) expect(response.headers['Cache-Control']).to include('private, no-store') end end @@ -138,6 +139,7 @@ RSpec.describe Settings::ImportsController do let(:bulk_import) { Fabricate(:bulk_import, account: user.account, type: import_type, state: :finished) } before do + rows.each { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } bulk_import.update(total_items: bulk_import.rows.count, processed_items: bulk_import.rows.count, imported_items: 0) end @@ -152,11 +154,11 @@ RSpec.describe Settings::ImportsController do context 'with follows' do let(:import_type) { 'following' } - let!(:rows) do + let(:rows) do [ { 'acct' => 'foo@bar' }, { 'acct' => 'user@bar', 'show_reblogs' => false, 'notify' => true, 'languages' => %w(fr de) }, - ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } + ] end include_examples 'export failed rows', "Account address,Show boosts,Notify on new posts,Languages\nfoo@bar,true,false,\nuser@bar,false,true,\"fr, de\"\n" @@ -165,11 +167,11 @@ RSpec.describe Settings::ImportsController do context 'with blocks' do let(:import_type) { 'blocking' } - let!(:rows) do + let(:rows) do [ { 'acct' => 'foo@bar' }, { 'acct' => 'user@bar' }, - ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } + ] end include_examples 'export failed rows', "foo@bar\nuser@bar\n" @@ -178,11 +180,11 @@ RSpec.describe Settings::ImportsController do context 'with mutes' do let(:import_type) { 'muting' } - let!(:rows) do + let(:rows) do [ { 'acct' => 'foo@bar' }, { 'acct' => 'user@bar', 'hide_notifications' => false }, - ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } + ] end include_examples 'export failed rows', "Account address,Hide notifications\nfoo@bar,true\nuser@bar,false\n" @@ -191,11 +193,11 @@ RSpec.describe Settings::ImportsController do context 'with domain blocks' do let(:import_type) { 'domain_blocking' } - let!(:rows) do + let(:rows) do [ { 'domain' => 'bad.domain' }, { 'domain' => 'evil.domain' }, - ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } + ] end include_examples 'export failed rows', "bad.domain\nevil.domain\n" @@ -204,11 +206,11 @@ RSpec.describe Settings::ImportsController do context 'with bookmarks' do let(:import_type) { 'bookmarks' } - let!(:rows) do + let(:rows) do [ { 'uri' => 'https://foo.com/1' }, { 'uri' => 'https://foo.com/2' }, - ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } + ] end include_examples 'export failed rows', "https://foo.com/1\nhttps://foo.com/2\n" @@ -217,11 +219,11 @@ RSpec.describe Settings::ImportsController do context 'with lists' do let(:import_type) { 'lists' } - let!(:rows) do + let(:rows) do [ { 'list_name' => 'Amigos', 'acct' => 'user@example.com' }, { 'list_name' => 'Frenemies', 'acct' => 'user@org.org' }, - ].map { |data| Fabricate(:bulk_import_row, bulk_import: bulk_import, data: data) } + ] end include_examples 'export failed rows', "Amigos,user@example.com\nFrenemies,user@org.org\n" From 5976d3702ff067fb0ed972fbc5f01a0f46b01bd7 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 21 Dec 2023 10:44:09 +0100 Subject: [PATCH 07/20] Change "Follow" to "Follow back" and "Mutual" when appropriate in web UI (#28452) --- .../features/account/components/header.jsx | 20 +++++++++++++++---- app/javascript/mastodon/locales/en.json | 3 ++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index 29b46cb43d..ab9526f66a 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -35,6 +35,8 @@ import FollowRequestNoteContainer from '../containers/follow_request_note_contai const messages = defineMessages({ unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, follow: { id: 'account.follow', defaultMessage: 'Follow' }, + followBack: { id: 'account.follow_back', defaultMessage: 'Follow back' }, + mutual: { id: 'account.mutual', defaultMessage: 'Mutual' }, cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, @@ -82,6 +84,18 @@ const titleFromAccount = account => { return `${prefix} (@${acct})`; }; +const messageForFollowButton = relationship => { + if (relationship.get('following') && relationship.get('followed_by')) { + return messages.mutual; + } else if (!relationship.get('following') && relationship.get('followed_by')) { + return messages.followBack; + } else if (relationship.get('following')) { + return messages.unfollow; + } else { + return messages.follow; + } +}; + const dateFormatOptions = { month: 'short', day: 'numeric', @@ -253,9 +267,7 @@ class Header extends ImmutablePureComponent { let info = []; let menu = []; - if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) { - info.push(); - } else if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) { + if (me !== account.get('id') && account.getIn(['relationship', 'blocking'])) { info.push(); } @@ -281,7 +293,7 @@ class Header extends ImmutablePureComponent { } else if (account.getIn(['relationship', 'requested'])) { actionBtn =