From 07d222665b9974a97c78d2a500a55555ebedd640 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 25 Jun 2024 17:25:11 +0000 Subject: [PATCH 01/34] chore(deps): update dependency typescript to v5.5.2 (#30815) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index b6117d821e..dc73fb93b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17151,22 +17151,22 @@ __metadata: linkType: hard "typescript@npm:5, typescript@npm:^5.0.4": - version: 5.4.5 - resolution: "typescript@npm:5.4.5" + version: 5.5.2 + resolution: "typescript@npm:5.5.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/2954022ada340fd3d6a9e2b8e534f65d57c92d5f3989a263754a78aba549f7e6529acc1921913560a4b816c46dce7df4a4d29f9f11a3dc0d4213bb76d043251e + checksum: 10c0/8ca39b27b5f9bd7f32db795045933ab5247897660627251e8254180b792a395bf061ea7231947d5d7ffa5cb4cc771970fd4ef543275f9b559f08c9325cccfce3 languageName: node linkType: hard "typescript@patch:typescript@npm%3A5#optional!builtin, typescript@patch:typescript@npm%3A^5.0.4#optional!builtin": - version: 5.4.5 - resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin::version=5.4.5&hash=5adc0c" + version: 5.5.2 + resolution: "typescript@patch:typescript@npm%3A5.5.2#optional!builtin::version=5.5.2&hash=379a07" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10c0/db2ad2a16ca829f50427eeb1da155e7a45e598eec7b086d8b4e8ba44e5a235f758e606d681c66992230d3fc3b8995865e5fd0b22a2c95486d0b3200f83072ec9 + checksum: 10c0/a7b7ede75dc7fc32a76d0d0af6b91f5fbd8620890d84c906f663d8783bf3de6d7bd50f0430b8bb55eac88a38934af847ff709e7156e5138b95ae94cbd5f73e5b languageName: node linkType: hard From a40831b3636fbca1e6d6b096e3d3cdd66569baf9 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 25 Jun 2024 22:37:48 +0200 Subject: [PATCH 02/34] Fix account search results (#30803) --- app/services/account_search_service.rb | 52 ++++++++++---------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/app/services/account_search_service.rb b/app/services/account_search_service.rb index b86c9b9e7e..dab5f748bf 100644 --- a/app/services/account_search_service.rb +++ b/app/services/account_search_service.rb @@ -28,9 +28,7 @@ class AccountSearchService < BaseService }, functions: [ - reputation_score_function, followers_score_function, - time_distance_function, ], }, }, @@ -81,36 +79,12 @@ class AccountSearchService < BaseService } end - # This function deranks accounts that follow more people than follow them - def reputation_score_function - { - script_score: { - script: { - source: "(Math.max(doc['followers_count'].value, 0) + 0.0) / (Math.max(doc['followers_count'].value, 0) + Math.max(doc['following_count'].value, 0) + 1)", - }, - }, - } - end - # This function promotes accounts that have more followers def followers_score_function { script_score: { script: { - source: "(Math.max(doc['followers_count'].value, 0) / (Math.max(doc['followers_count'].value, 0) + 1))", - }, - }, - } - end - - # This function deranks accounts that haven't posted in a long time - def time_distance_function - { - gauss: { - last_status_at: { - scale: '30d', - offset: '30d', - decay: 0.3, + source: "Math.log10((Math.max(doc['followers_count'].value, 0) + 1))", }, }, } @@ -126,10 +100,24 @@ class AccountSearchService < BaseService def core_query { - multi_match: { - query: @query, - type: 'bool_prefix', - fields: %w(username^2 username.*^2 display_name display_name.*), + dis_max: { + queries: [ + { + multi_match: { + query: @query, + type: 'most_fields', + fields: %w(username username.*), + }, + }, + + { + multi_match: { + query: @query, + type: 'most_fields', + fields: %w(display_name display_name.*), + }, + }, + ], }, } end @@ -142,7 +130,7 @@ class AccountSearchService < BaseService { multi_match: { query: @query, - type: 'most_fields', + type: 'best_fields', fields: %w(username^2 display_name^2 text text.*), operator: 'and', }, From 8c0ff6498e090a2919e8f8104339796ed2d3d212 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 25 Jun 2024 23:57:22 +0200 Subject: [PATCH 03/34] Change light mode to apply CSS variables to the body (#30839) --- app/javascript/styles/mastodon-light/variables.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/styles/mastodon-light/variables.scss b/app/javascript/styles/mastodon-light/variables.scss index 09a75a834b..3cdbd9bf67 100644 --- a/app/javascript/styles/mastodon-light/variables.scss +++ b/app/javascript/styles/mastodon-light/variables.scss @@ -56,11 +56,11 @@ $account-background-color: $white !default; $emojis-requiring-inversion: 'chains'; -.theme-mastodon-light { +body { --dropdown-border-color: #d9e1e8; --dropdown-background-color: #fff; --background-border-color: #d9e1e8; --background-color: #fff; - --background-color-tint: rgba(255, 255, 255, 90%); + --background-color-tint: rgba(255, 255, 255, 80%); --background-filter: blur(10px); } From 2b43c05a6a1c38a7480119a0bd12fefa8b5589c6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:42:25 +0200 Subject: [PATCH 04/34] chore(deps): update dependency aws-sdk-s3 to v1.154.0 (#30838) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5d735eb753..e8b54ed568 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -101,16 +101,16 @@ GEM awrence (1.2.1) aws-eventstream (1.3.0) aws-partitions (1.947.0) - aws-sdk-core (3.198.0) + aws-sdk-core (3.199.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.86.0) - aws-sdk-core (~> 3, >= 3.198.0) + aws-sdk-kms (1.87.0) + aws-sdk-core (~> 3, >= 3.199.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.153.0) - aws-sdk-core (~> 3, >= 3.198.0) + aws-sdk-s3 (1.154.0) + aws-sdk-core (~> 3, >= 3.199.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) From 7a84b76bb1716b131c35d9569bfcef3b32d73e60 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 26 Jun 2024 15:44:08 +0200 Subject: [PATCH 05/34] Drop favicon.ico generation (#30375) --- app/models/site_upload.rb | 11 ++--------- app/views/layouts/application.html.haml | 2 -- config/imagemagick/policy.xml | 2 +- lib/tasks/branding.rake | 3 --- public/favicon.ico | Bin 15086 -> 0 bytes spec/requests/account_show_page_spec.rb | 2 +- 6 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 public/favicon.ico diff --git a/app/models/site_upload.rb b/app/models/site_upload.rb index 6431d1007d..273dd6de9f 100644 --- a/app/models/site_upload.rb +++ b/app/models/site_upload.rb @@ -31,17 +31,10 @@ class SiteUpload < ApplicationRecord [:"#{size}", { format: 'png', geometry: "#{size}x#{size}#", file_geometry_parser: FastGeometryParser }] end.freeze, - favicon: { - ico: { - format: 'ico', - geometry: '48x48#', - file_geometry_parser: FastGeometryParser, - }.freeze, - }.merge( + favicon: FAVICON_SIZES.to_h do |size| [:"#{size}", { format: 'png', geometry: "#{size}x#{size}#", file_geometry_parser: FastGeometryParser }] - end - ).freeze, + end.freeze, thumbnail: { '@1x': { diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index e7f1a595e5..0c0512e812 100755 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -11,8 +11,6 @@ - if storage_host? %link{ rel: 'dns-prefetch', href: storage_host }/ - %link{ rel: 'icon', href: favicon_path('ico') || '/favicon.ico', type: 'image/x-icon' }/ - - SiteUpload::FAVICON_SIZES.each do |size| %link{ rel: 'icon', sizes: "#{size}x#{size}", href: favicon_path(size.to_i) || frontend_asset_path("icons/favicon-#{size}x#{size}.png"), type: 'image/png' }/ diff --git a/config/imagemagick/policy.xml b/config/imagemagick/policy.xml index 2730a9f84e..e2aa202f27 100644 --- a/config/imagemagick/policy.xml +++ b/config/imagemagick/policy.xml @@ -23,5 +23,5 @@ - + diff --git a/lib/tasks/branding.rake b/lib/tasks/branding.rake index 608fb3af9c..be72454ce2 100644 --- a/lib/tasks/branding.rake +++ b/lib/tasks/branding.rake @@ -42,7 +42,6 @@ namespace :branding do output_dest = Rails.root.join('app', 'javascript', 'icons') rsvg_convert = Terrapin::CommandLine.new('rsvg-convert', '-w :size -h :size --keep-aspect-ratio :input -o :output') - convert = Terrapin::CommandLine.new('convert', ':input :output', environment: { 'MAGICK_CONFIGURE_PATH' => nil }) favicon_sizes = [16, 32, 48] apple_icon_sizes = [57, 60, 72, 76, 114, 120, 144, 152, 167, 180, 1024] @@ -56,8 +55,6 @@ namespace :branding do rsvg_convert.run(size: size, input: favicon_source, output: output_path) end - convert.run(input: favicons, output: Rails.public_path.join('favicon.ico')) - apple_icon_sizes.each do |size| rsvg_convert.run(size: size, input: app_icon_source, output: output_dest.join("apple-touch-icon-#{size}x#{size}.png")) end diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index b09a98bb9b0649cb67305b6663bd56b3cfb17222..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 zcmdU0d303O8Gn{m+S9sq@gI+sdfIc^b8PjTdaRg0MwkFW3;~?w&Ax;HN^k)eL`<|& z1*?|DswkUO)VePfAuIt!5wnnlY=nf607(d0XL~dAX1;#+P41gFZ{8awAyE3x`Q^L! ze(Sx-yf^RrzA(&X%oyhCs~M!@nE5|snA;eJ88a|7_j_ zWUd7WLMY0(?)eIB(B2&+W{!6?WuVfgpT5rcdXgW5Nvv` zlTXHFLx{0ee-@)$>6qAkW*kas5aj+OT;#?x%!_<3%kR)l!u!t(y#MSd%g{IC*oWwi z!BAg*hyEkHCp}$phi*K?A|0leWbuQ4F<)7cX?(OI)6j{4bWxdUXs(!GyeHXW`YRO~ z##;|hFti|GgxHn7w?xUBiAHyImLY@y6-01-AL2E{N|BLCGI zHm@ej7^%@1K^cZG@xJ`q#E27Tl^Vy@H4_bgNL)SltbVfX7qxd9dk~-uLuIW_clo(3 zjZC6eYbwTP6Q}{7VT(s*IX$fgEn9;CRb-oV_{^M&&(ufiwe0$aZ1z2*B`E)WgVuD2 zj4{R!k-xQZGW++&Y~y{6*{12WTHUYD6#;pMAI)YX2)Gbv%4QoIr?5-OGhHbbX8RP+31{H}13;Axp^xmg-RbB=jsOO6>X8m5~MLvisBXbi2>&D#(l zMOV@D(7W*+0o^OtCGezjYU8dao{Q_h@Jh0NjyZ?=Z<}HM0s&HZcYj46_rO)xCGezj zYGcoTN<{tO(dH!m_PZ^wQUC2TEC+B7Qut*4rMz^;o-cMK_)pS7pVa@UT=S7r_`OgH z-yX^SYw8ksM6T=JN8s%8X9b*jXn7LfEAbz~{Y!1f#@06K|8$=91OlY+OZ*4Xzm!MD zz8!nw`>Sn8=5LShKh)Hm#6LaL+Clwy&a!qPK#IWL`2LB1DUXc(GXF_@nSVJS=Vz(^ zuGzLh1V|CU@B8!$9;r{@5jp?Py_5~1x`t%_m%HP9{C+OAJv1Jq{=4t71rZ1MZV|p;`qDAkd$xDDo@tvn>fOUWr z-lv`w^~r#||AfB&MtGMZ?@q$npa&v&Ho_H&K)9>|Li@ggXkTA!ZRls=xyNZ@#4%Lln;^u>2`ePHG?D6Zg^m`>d{8{rHZk2=_b)ZG8*) zvT}$VsRbU-H@NDBBw4QLX$bGy1AKK2@Rd~%djCTR+*_C=C;G6t9;W^Y~z5e0>?X@7V1xllDq-Fi$4)@ zxq1;WT8O$_yTRp3_}-`FpRR$!@ng&f zpcM5HV_MN(KicIPCX3`lF-6Ka5MrJp>#_RT$ zjn}te&Z1X>GdM0QyFPT=8jaq9IV)bsTdC)~_x;UxZZ+@#%z!N`J>$&%#($cb7jdnv}%p9qE^FZ4(E5@kdb>ubrw4w z_nDNp7>*se?BPke>#(NNO=~;nq#AaQy!Iovc`@flCb4fT=Lr?_hg{tx6K2ydjjK*$ zxT$Uu8%01`m~8y`(uh131?Cz5Mr(R$Q7v1j7C*^7)=V*8UpEEM1aVYry0Knk9EbPg zYxZh1=ctUTSxvo;InzqjJgagJ)=6@y4cVqg8@22<)U8JJBBE*7;ZUcOv3s`fFo08%Dq-0Dq&__}Nh{I|uODpHBQF|C(k!H{H7LD9N!k zjoIeO=i0-usiuWZQ!!V4X(DoTn(2vDHMnCrrnSc~*L^9YIfs2x?f1|!&HVZBYx*PU z12`|8DAp3DEA8QUj=2s2{|9Iw?;-L%V7}k0mh(U9xF0$ne>MT97Cf4q`{BY+zt6!&PMe6^y zOx^wr)BDo+kIk}P+cv|3wG3q_#=mR7s=S&VwROe#50<5}@0He>+Gm)4msAIl)Lr^F zDx5#YpGs#qyxuhm=a2EHvT=HP{Ci_tuJu;h)1yTDHzmjK!}yhCN3zztHaY$P#-GyG zjQBI{)J&Te`;tHn14{Al-mfa(HSZzlU9~0w-Ajs8<@;3PSBr1W_{o+S_K zMxcg)O>c{zD?0FF{A%+3uWX`XBK7Y*pf11m4N;B`0td@gyx1MxmEnUDT;$?AhX#nF_m48_|el_`_^|>_ut~r(kU9+uNi&KVYOY->#_Uu=cAAC(A{(T43j+E1pl1?>AvBtFucY6&rG&e4Z>TiLcKniQiyffVFC|Pgg!3oWCf^ zK3U+g{_a_{MAY*vUJ5++1gKq6tmpflSsANYqrXAddJ{ukGZcIEMqIiB@0 z`uF2u?Q;gP&YlYVv1Y0HgfXcnlX|xNA~pCBe$M4r)T1m<CD;mX!Fwe3$EUg?ZEfJke)g0x#Nvy3tk!F#@%t>!1!50^TF=AKdhn&y z5UDwm7!My2dK?H(%?`J$2>7oL00aW@ZQ$Qow(Bz_uA-O_vg`k*CE{7QKVhb zeC$7pfkO%sL?t{Ta{_g-7YTLq-P Date: Wed, 26 Jun 2024 09:51:11 -0400 Subject: [PATCH 06/34] Fix `Rails/ReversibleMigration` cop for `change_column` (#30835) --- db/migrate/20160223164502_make_uris_nullable_in_statuses.rb | 6 +++++- ...170322143850_change_primary_key_to_bigint_on_statuses.rb | 6 +++++- .../20170609145826_remove_default_language_from_statuses.rb | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb b/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb index fff07093c8..ebb572bd60 100644 --- a/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb +++ b/db/migrate/20160223164502_make_uris_nullable_in_statuses.rb @@ -1,7 +1,11 @@ # frozen_string_literal: true class MakeUrisNullableInStatuses < ActiveRecord::Migration[4.2] - def change + def up change_column :statuses, :uri, :string, null: true, default: nil end + + def down + raise ActiveRecord::IrreversibleMigration + end end diff --git a/db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb b/db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb index b98fffab83..e7fcb75a44 100644 --- a/db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb +++ b/db/migrate/20170322143850_change_primary_key_to_bigint_on_statuses.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class ChangePrimaryKeyToBigintOnStatuses < ActiveRecord::Migration[5.0] - def change + def up change_table(:statuses, bulk: true) do |t| t.change :id, :bigint t.change :reblog_of_id, :bigint @@ -16,4 +16,8 @@ class ChangePrimaryKeyToBigintOnStatuses < ActiveRecord::Migration[5.0] change_column :statuses_tags, :status_id, :bigint change_column :stream_entries, :activity_id, :bigint end + + def down + raise ActiveRecord::IrreversibleMigration + end end diff --git a/db/migrate/20170609145826_remove_default_language_from_statuses.rb b/db/migrate/20170609145826_remove_default_language_from_statuses.rb index 28b4172a8c..122c322287 100644 --- a/db/migrate/20170609145826_remove_default_language_from_statuses.rb +++ b/db/migrate/20170609145826_remove_default_language_from_statuses.rb @@ -1,7 +1,11 @@ # frozen_string_literal: true class RemoveDefaultLanguageFromStatuses < ActiveRecord::Migration[5.1] - def change + def up change_column :statuses, :language, :string, default: nil, null: true end + + def down + raise ActiveRecord::IrreversibleMigration + end end From 51f581e03e1b2611eceddf5010ef736680e1f62b Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Wed, 26 Jun 2024 09:51:44 -0400 Subject: [PATCH 07/34] Fix `Rails/ReversibleMigration` cop for `remove` (#30833) --- db/migrate/20170520145338_change_language_filter_to_opt_out.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20170520145338_change_language_filter_to_opt_out.rb b/db/migrate/20170520145338_change_language_filter_to_opt_out.rb index f0a95819c3..0e91c46803 100644 --- a/db/migrate/20170520145338_change_language_filter_to_opt_out.rb +++ b/db/migrate/20170520145338_change_language_filter_to_opt_out.rb @@ -5,7 +5,7 @@ class ChangeLanguageFilterToOptOut < ActiveRecord::Migration[5.0] remove_index :users, :allowed_languages change_table(:users, bulk: true) do |t| - t.remove :allowed_languages + t.remove :allowed_languages, type: :string, array: true, default: [], null: false t.column :filtered_languages, :string, array: true, default: [], null: false end From 863c470a2bc4e13a5b8df4d66a1322f4b84e2db2 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Wed, 26 Jun 2024 20:04:50 +0200 Subject: [PATCH 08/34] Convert `` to Typescript / function component (#30829) --- app/javascript/mastodon/actions/directory.js | 62 ---- app/javascript/mastodon/actions/directory.ts | 37 +++ app/javascript/mastodon/api/directory.ts | 15 + .../directory/components/account_card.jsx | 234 --------------- .../directory/components/account_card.tsx | 269 ++++++++++++++++++ .../mastodon/features/directory/index.jsx | 181 ------------ .../mastodon/features/directory/index.tsx | 217 ++++++++++++++ .../mastodon/reducers/user_lists.js | 32 +-- 8 files changed, 553 insertions(+), 494 deletions(-) delete mode 100644 app/javascript/mastodon/actions/directory.js create mode 100644 app/javascript/mastodon/actions/directory.ts create mode 100644 app/javascript/mastodon/api/directory.ts delete mode 100644 app/javascript/mastodon/features/directory/components/account_card.jsx create mode 100644 app/javascript/mastodon/features/directory/components/account_card.tsx delete mode 100644 app/javascript/mastodon/features/directory/index.jsx create mode 100644 app/javascript/mastodon/features/directory/index.tsx diff --git a/app/javascript/mastodon/actions/directory.js b/app/javascript/mastodon/actions/directory.js deleted file mode 100644 index 7a0748029d..0000000000 --- a/app/javascript/mastodon/actions/directory.js +++ /dev/null @@ -1,62 +0,0 @@ -import api from '../api'; - -import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; - -export const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST'; -export const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS'; -export const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL'; - -export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST'; -export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS'; -export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL'; - -export const fetchDirectory = params => (dispatch) => { - dispatch(fetchDirectoryRequest()); - - api().get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => { - dispatch(importFetchedAccounts(data)); - dispatch(fetchDirectorySuccess(data)); - dispatch(fetchRelationships(data.map(x => x.id))); - }).catch(error => dispatch(fetchDirectoryFail(error))); -}; - -export const fetchDirectoryRequest = () => ({ - type: DIRECTORY_FETCH_REQUEST, -}); - -export const fetchDirectorySuccess = accounts => ({ - type: DIRECTORY_FETCH_SUCCESS, - accounts, -}); - -export const fetchDirectoryFail = error => ({ - type: DIRECTORY_FETCH_FAIL, - error, -}); - -export const expandDirectory = params => (dispatch, getState) => { - dispatch(expandDirectoryRequest()); - - const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size; - - api().get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => { - dispatch(importFetchedAccounts(data)); - dispatch(expandDirectorySuccess(data)); - dispatch(fetchRelationships(data.map(x => x.id))); - }).catch(error => dispatch(expandDirectoryFail(error))); -}; - -export const expandDirectoryRequest = () => ({ - type: DIRECTORY_EXPAND_REQUEST, -}); - -export const expandDirectorySuccess = accounts => ({ - type: DIRECTORY_EXPAND_SUCCESS, - accounts, -}); - -export const expandDirectoryFail = error => ({ - type: DIRECTORY_EXPAND_FAIL, - error, -}); diff --git a/app/javascript/mastodon/actions/directory.ts b/app/javascript/mastodon/actions/directory.ts new file mode 100644 index 0000000000..34ac309c66 --- /dev/null +++ b/app/javascript/mastodon/actions/directory.ts @@ -0,0 +1,37 @@ +import type { List as ImmutableList } from 'immutable'; + +import { apiGetDirectory } from 'mastodon/api/directory'; +import { createDataLoadingThunk } from 'mastodon/store/typed_functions'; + +import { fetchRelationships } from './accounts'; +import { importFetchedAccounts } from './importer'; + +export const fetchDirectory = createDataLoadingThunk( + 'directory/fetch', + async (params: Parameters[0]) => + apiGetDirectory(params), + (data, { dispatch }) => { + dispatch(importFetchedAccounts(data)); + dispatch(fetchRelationships(data.map((x) => x.id))); + + return { accounts: data }; + }, +); + +export const expandDirectory = createDataLoadingThunk( + 'directory/expand', + async (params: Parameters[0], { getState }) => { + const loadedItems = getState().user_lists.getIn([ + 'directory', + 'items', + ]) as ImmutableList; + + return apiGetDirectory({ ...params, offset: loadedItems.size }, 20); + }, + (data, { dispatch }) => { + dispatch(importFetchedAccounts(data)); + dispatch(fetchRelationships(data.map((x) => x.id))); + + return { accounts: data }; + }, +); diff --git a/app/javascript/mastodon/api/directory.ts b/app/javascript/mastodon/api/directory.ts new file mode 100644 index 0000000000..cd39f8f269 --- /dev/null +++ b/app/javascript/mastodon/api/directory.ts @@ -0,0 +1,15 @@ +import { apiRequestGet } from 'mastodon/api'; +import type { ApiAccountJSON } from 'mastodon/api_types/accounts'; + +export const apiGetDirectory = ( + params: { + order: string; + local: boolean; + offset?: number; + }, + limit = 20, +) => + apiRequestGet('v1/directory', { + ...params, + limit, + }); diff --git a/app/javascript/mastodon/features/directory/components/account_card.jsx b/app/javascript/mastodon/features/directory/components/account_card.jsx deleted file mode 100644 index 9c5e688120..0000000000 --- a/app/javascript/mastodon/features/directory/components/account_card.jsx +++ /dev/null @@ -1,234 +0,0 @@ -import PropTypes from 'prop-types'; - -import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; - -import classNames from 'classnames'; -import { Link } from 'react-router-dom'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { - followAccount, - unfollowAccount, - unblockAccount, - unmuteAccount, -} from 'mastodon/actions/accounts'; -import { openModal } from 'mastodon/actions/modal'; -import { Avatar } from 'mastodon/components/avatar'; -import { Button } from 'mastodon/components/button'; -import { DisplayName } from 'mastodon/components/display_name'; -import { ShortNumber } from 'mastodon/components/short_number'; -import { autoPlayGif, me } from 'mastodon/initial_state'; -import { makeGetAccount } from 'mastodon/selectors'; - -const messages = defineMessages({ - unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, - follow: { id: 'account.follow', defaultMessage: 'Follow' }, - cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, - cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' }, - requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, - unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' }, - unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' }, - unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, - edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, -}); - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, { id }) => ({ - account: getAccount(state, id), - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = (dispatch, { intl }) => ({ - onFollow(account) { - if (account.getIn(['relationship', 'following'])) { - dispatch( - openModal({ - modalType: 'CONFIRM', - modalProps: { - message: ( - @{account.get('acct')} }} - /> - ), - confirm: intl.formatMessage(messages.unfollowConfirm), - onConfirm: () => dispatch(unfollowAccount(account.get('id'))), - } }), - ); - } else if (account.getIn(['relationship', 'requested'])) { - dispatch(openModal({ - modalType: 'CONFIRM', - modalProps: { - message: @{account.get('acct')} }} />, - confirm: intl.formatMessage(messages.cancelFollowRequestConfirm), - onConfirm: () => dispatch(unfollowAccount(account.get('id'))), - }, - })); - } else { - dispatch(followAccount(account.get('id'))); - } - }, - - onBlock(account) { - if (account.getIn(['relationship', 'blocking'])) { - dispatch(unblockAccount(account.get('id'))); - } - }, - - onMute(account) { - if (account.getIn(['relationship', 'muting'])) { - dispatch(unmuteAccount(account.get('id'))); - } - }, - -}); - -class AccountCard extends ImmutablePureComponent { - - static propTypes = { - account: ImmutablePropTypes.record.isRequired, - intl: PropTypes.object.isRequired, - onFollow: PropTypes.func.isRequired, - onBlock: PropTypes.func.isRequired, - onMute: PropTypes.func.isRequired, - }; - - handleMouseEnter = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-original'); - } - }; - - handleMouseLeave = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-static'); - } - }; - - handleFollow = () => { - this.props.onFollow(this.props.account); - }; - - handleBlock = () => { - this.props.onBlock(this.props.account); - }; - - handleMute = () => { - this.props.onMute(this.props.account); - }; - - handleEditProfile = () => { - window.open('/settings/profile', '_blank'); - }; - - render() { - const { account, intl } = this.props; - - let actionBtn; - - if (me !== account.get('id')) { - if (!account.get('relationship')) { // Wait until the relationship is loaded - actionBtn = ''; - } else if (account.getIn(['relationship', 'requested'])) { - actionBtn = + ); +}; diff --git a/app/javascript/mastodon/components/hover_card_account.tsx b/app/javascript/mastodon/components/hover_card_account.tsx new file mode 100644 index 0000000000..59f9577838 --- /dev/null +++ b/app/javascript/mastodon/components/hover_card_account.tsx @@ -0,0 +1,74 @@ +import { useEffect, forwardRef } from 'react'; + +import classNames from 'classnames'; +import { Link } from 'react-router-dom'; + +import { fetchAccount } from 'mastodon/actions/accounts'; +import { AccountBio } from 'mastodon/components/account_bio'; +import { AccountFields } from 'mastodon/components/account_fields'; +import { Avatar } from 'mastodon/components/avatar'; +import { FollowersCounter } from 'mastodon/components/counters'; +import { DisplayName } from 'mastodon/components/display_name'; +import { FollowButton } from 'mastodon/components/follow_button'; +import { LoadingIndicator } from 'mastodon/components/loading_indicator'; +import { ShortNumber } from 'mastodon/components/short_number'; +import { domain } from 'mastodon/initial_state'; +import { useAppSelector, useAppDispatch } from 'mastodon/store'; + +export const HoverCardAccount = forwardRef< + HTMLDivElement, + { accountId: string } +>(({ accountId }, ref) => { + const dispatch = useAppDispatch(); + + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); + + useEffect(() => { + if (accountId && !account) { + dispatch(fetchAccount(accountId)); + } + }, [dispatch, accountId, account]); + + return ( + + ); +}); + +HoverCardAccount.displayName = 'HoverCardAccount'; diff --git a/app/javascript/mastodon/components/hover_card_controller.tsx b/app/javascript/mastodon/components/hover_card_controller.tsx new file mode 100644 index 0000000000..0130390ef8 --- /dev/null +++ b/app/javascript/mastodon/components/hover_card_controller.tsx @@ -0,0 +1,117 @@ +import { useEffect, useRef, useState, useCallback } from 'react'; + +import { useLocation } from 'react-router-dom'; + +import Overlay from 'react-overlays/Overlay'; +import type { + OffsetValue, + UsePopperOptions, +} from 'react-overlays/esm/usePopper'; + +import { useTimeout } from 'mastodon/../hooks/useTimeout'; +import { HoverCardAccount } from 'mastodon/components/hover_card_account'; + +const offset = [-12, 4] as OffsetValue; +const enterDelay = 650; +const leaveDelay = 250; +const popperConfig = { strategy: 'fixed' } as UsePopperOptions; + +const isHoverCardAnchor = (element: HTMLElement) => + element.matches('[data-hover-card-account]'); + +export const HoverCardController: React.FC = () => { + const [open, setOpen] = useState(false); + const [accountId, setAccountId] = useState(); + const [anchor, setAnchor] = useState(null); + const cardRef = useRef(null); + const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout(); + const [setEnterTimeout, cancelEnterTimeout] = useTimeout(); + const location = useLocation(); + + const handleAnchorMouseEnter = useCallback( + (e: MouseEvent) => { + const { target } = e; + + if (target instanceof HTMLElement && isHoverCardAnchor(target)) { + cancelLeaveTimeout(); + + setEnterTimeout(() => { + target.setAttribute('aria-describedby', 'hover-card'); + setAnchor(target); + setOpen(true); + setAccountId( + target.getAttribute('data-hover-card-account') ?? undefined, + ); + }, enterDelay); + } + + if (target === cardRef.current?.parentNode) { + cancelLeaveTimeout(); + } + }, + [cancelLeaveTimeout, setEnterTimeout, setOpen, setAccountId, setAnchor], + ); + + const handleAnchorMouseLeave = useCallback( + (e: MouseEvent) => { + if (e.target === anchor || e.target === cardRef.current?.parentNode) { + cancelEnterTimeout(); + + setLeaveTimeout(() => { + anchor?.removeAttribute('aria-describedby'); + setOpen(false); + setAnchor(null); + }, leaveDelay); + } + }, + [cancelEnterTimeout, setLeaveTimeout, setOpen, setAnchor, anchor], + ); + + const handleClose = useCallback(() => { + cancelEnterTimeout(); + cancelLeaveTimeout(); + setOpen(false); + setAnchor(null); + }, [cancelEnterTimeout, cancelLeaveTimeout, setOpen, setAnchor]); + + useEffect(() => { + handleClose(); + }, [handleClose, location]); + + useEffect(() => { + document.body.addEventListener('mouseenter', handleAnchorMouseEnter, { + passive: true, + capture: true, + }); + document.body.addEventListener('mouseleave', handleAnchorMouseLeave, { + passive: true, + capture: true, + }); + + return () => { + document.body.removeEventListener('mouseenter', handleAnchorMouseEnter); + document.body.removeEventListener('mouseleave', handleAnchorMouseLeave); + }; + }, [handleAnchorMouseEnter, handleAnchorMouseLeave]); + + if (!accountId) return null; + + return ( + + {({ props }) => ( +
+ +
+ )} +
+ ); +}; diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index 7b97e45766..dce48d7036 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -425,7 +425,7 @@ class Status extends ImmutablePureComponent { prepend = (
- }} /> + }} />
); @@ -446,7 +446,7 @@ class Status extends ImmutablePureComponent { prepend = (
- }} /> + }} />
); } @@ -562,7 +562,7 @@ class Status extends ImmutablePureComponent { {status.get('edited_at') && *} - +
{statusAvatar}
diff --git a/app/javascript/mastodon/components/status_content.jsx b/app/javascript/mastodon/components/status_content.jsx index 24483cf512..82135b85ca 100644 --- a/app/javascript/mastodon/components/status_content.jsx +++ b/app/javascript/mastodon/components/status_content.jsx @@ -116,8 +116,9 @@ class StatusContent extends PureComponent { if (mention) { link.addEventListener('click', this.onMentionClick.bind(this, mention), false); - link.setAttribute('title', `@${mention.get('acct')}`); + link.removeAttribute('title'); link.setAttribute('href', `/@${mention.get('acct')}`); + link.setAttribute('data-hover-card-account', mention.get('id')); } else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) { link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false); link.setAttribute('href', `/tags/${link.text.replace(/^#/, '')}`); diff --git a/app/javascript/mastodon/features/explore/components/author_link.jsx b/app/javascript/mastodon/features/explore/components/author_link.jsx index b9dec3367e..8dd9b0dabd 100644 --- a/app/javascript/mastodon/features/explore/components/author_link.jsx +++ b/app/javascript/mastodon/features/explore/components/author_link.jsx @@ -9,7 +9,7 @@ export const AuthorLink = ({ accountId }) => { const account = useAppSelector(state => state.getIn(['accounts', accountId])); return ( - + diff --git a/app/javascript/mastodon/features/explore/components/card.jsx b/app/javascript/mastodon/features/explore/components/card.jsx index 316203060a..1908648510 100644 --- a/app/javascript/mastodon/features/explore/components/card.jsx +++ b/app/javascript/mastodon/features/explore/components/card.jsx @@ -8,34 +8,21 @@ import { Link } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; -import { followAccount, unfollowAccount } from 'mastodon/actions/accounts'; import { dismissSuggestion } from 'mastodon/actions/suggestions'; import { Avatar } from 'mastodon/components/avatar'; -import { Button } from 'mastodon/components/button'; import { DisplayName } from 'mastodon/components/display_name'; +import { FollowButton } from 'mastodon/components/follow_button'; import { IconButton } from 'mastodon/components/icon_button'; import { domain } from 'mastodon/initial_state'; const messages = defineMessages({ - follow: { id: 'account.follow', defaultMessage: 'Follow' }, - unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" }, }); export const Card = ({ id, source }) => { const intl = useIntl(); const account = useSelector(state => state.getIn(['accounts', id])); - const relationship = useSelector(state => state.getIn(['relationships', id])); const dispatch = useDispatch(); - const following = relationship?.get('following') ?? relationship?.get('requested'); - - const handleFollow = useCallback(() => { - if (following) { - dispatch(unfollowAccount(id)); - } else { - dispatch(followAccount(id)); - } - }, [id, following, dispatch]); const handleDismiss = useCallback(() => { dispatch(dismissSuggestion(id)); @@ -74,7 +61,7 @@ export const Card = ({ id, source }) => {
-
diff --git a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx index c39b43bade..1b8040e55b 100644 --- a/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx +++ b/app/javascript/mastodon/features/home_timeline/components/inline_follow_suggestions.jsx @@ -12,12 +12,11 @@ import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import InfoIcon from '@/material-icons/400-24px/info.svg?react'; -import { followAccount, unfollowAccount } from 'mastodon/actions/accounts'; import { changeSetting } from 'mastodon/actions/settings'; import { fetchSuggestions, dismissSuggestion } from 'mastodon/actions/suggestions'; import { Avatar } from 'mastodon/components/avatar'; -import { Button } from 'mastodon/components/button'; import { DisplayName } from 'mastodon/components/display_name'; +import { FollowButton } from 'mastodon/components/follow_button'; import { Icon } from 'mastodon/components/icon'; import { IconButton } from 'mastodon/components/icon_button'; import { VerifiedBadge } from 'mastodon/components/verified_badge'; @@ -79,18 +78,8 @@ Source.propTypes = { const Card = ({ id, sources }) => { const intl = useIntl(); const account = useSelector(state => state.getIn(['accounts', id])); - const relationship = useSelector(state => state.getIn(['relationships', id])); const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at')); const dispatch = useDispatch(); - const following = relationship?.get('following') ?? relationship?.get('requested'); - - const handleFollow = useCallback(() => { - if (following) { - dispatch(unfollowAccount(id)); - } else { - dispatch(followAccount(id)); - } - }, [id, following, dispatch]); const handleDismiss = useCallback(() => { dispatch(dismissSuggestion(id)); @@ -109,7 +98,7 @@ const Card = ({ id, sources }) => { {firstVerifiedField ? : } -
- ); -}; - -BackButton.propTypes = { - onlyIcon: PropTypes.bool, -}; - -class ColumnHeader extends PureComponent { - static propTypes = { - identity: identityContextPropShape, - intl: PropTypes.object.isRequired, - title: PropTypes.node, - icon: PropTypes.string, - iconComponent: PropTypes.func, - active: PropTypes.bool, - multiColumn: PropTypes.bool, - extraButton: PropTypes.node, - showBackButton: PropTypes.bool, - children: PropTypes.node, - pinned: PropTypes.bool, - placeholder: PropTypes.bool, - onPin: PropTypes.func, - onMove: PropTypes.func, - onClick: PropTypes.func, - appendContent: PropTypes.node, - collapseIssues: PropTypes.bool, - ...WithRouterPropTypes, - }; - - state = { - collapsed: true, - animating: false, - }; - - handleToggleClick = (e) => { - e.stopPropagation(); - this.setState({ collapsed: !this.state.collapsed, animating: true }); - }; - - handleTitleClick = () => { - this.props.onClick?.(); - }; - - handleMoveLeft = () => { - this.props.onMove(-1); - }; - - handleMoveRight = () => { - this.props.onMove(1); - }; - - handleTransitionEnd = () => { - this.setState({ animating: false }); - }; - - handlePin = () => { - if (!this.props.pinned) { - this.props.history.replace('/'); - } - - this.props.onPin(); - }; - - render () { - const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props; - const { collapsed, animating } = this.state; - - const wrapperClassName = classNames('column-header__wrapper', { - 'active': active, - }); - - const buttonClassName = classNames('column-header', { - 'active': active, - }); - - const collapsibleClassName = classNames('column-header__collapsible', { - 'collapsed': collapsed, - 'animating': animating, - }); - - const collapsibleButtonClassName = classNames('column-header__button', { - 'active': !collapsed, - }); - - let extraContent, pinButton, moveButtons, backButton, collapseButton; - - if (children) { - extraContent = ( -
- {children} -
- ); - } - - if (multiColumn && pinned) { - pinButton = ; - - moveButtons = ( -
- - -
- ); - } else if (multiColumn && this.props.onPin) { - pinButton = ; - } - - if (history && !pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) { - backButton = ; - } - - const collapsedContent = [ - extraContent, - ]; - - if (multiColumn) { - collapsedContent.push( -
- {pinButton} - {moveButtons} -
- ); - } - - if (this.props.identity.signedIn && (children || (multiColumn && this.props.onPin))) { - collapseButton = ( - - ); - } - - const hasTitle = (icon || iconComponent) && title; - - const component = ( -
-

- {hasTitle && ( - <> - {backButton} - - - - )} - - {!hasTitle && backButton} - -
- {extraButton} - {collapseButton} -
-

- -
-
- {(!collapsed || animating) && collapsedContent} -
-
- - {appendContent} -
- ); - - if (placeholder) { - return component; - } else { - return ( - {component} - ); - } - } - -} - -export default injectIntl(withIdentity(withRouter(ColumnHeader))); diff --git a/app/javascript/mastodon/components/column_header.tsx b/app/javascript/mastodon/components/column_header.tsx new file mode 100644 index 0000000000..ec946cab3e --- /dev/null +++ b/app/javascript/mastodon/components/column_header.tsx @@ -0,0 +1,301 @@ +import { useCallback, useState } from 'react'; + +import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; + +import classNames from 'classnames'; + +import AddIcon from '@/material-icons/400-24px/add.svg?react'; +import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react'; +import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings.svg?react'; +import type { IconProp } from 'mastodon/components/icon'; +import { Icon } from 'mastodon/components/icon'; +import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context'; +import { useIdentity } from 'mastodon/identity_context'; + +import { useAppHistory } from './router'; + +const messages = defineMessages({ + show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' }, + hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' }, + moveLeft: { + id: 'column_header.moveLeft_settings', + defaultMessage: 'Move column to the left', + }, + moveRight: { + id: 'column_header.moveRight_settings', + defaultMessage: 'Move column to the right', + }, + back: { id: 'column_back_button.label', defaultMessage: 'Back' }, +}); + +const BackButton: React.FC<{ + onlyIcon: boolean; +}> = ({ onlyIcon }) => { + const history = useAppHistory(); + const intl = useIntl(); + + const handleBackClick = useCallback(() => { + if (history.location.state?.fromMastodon) { + history.goBack(); + } else { + history.push('/'); + } + }, [history]); + + return ( + + ); +}; + +export interface Props { + title?: string; + icon?: string; + iconComponent?: IconProp; + active?: boolean; + children?: React.ReactNode; + pinned?: boolean; + multiColumn?: boolean; + extraButton?: React.ReactNode; + showBackButton?: boolean; + placeholder?: boolean; + appendContent?: React.ReactNode; + collapseIssues?: boolean; + onClick?: () => void; + onMove?: (arg0: number) => void; + onPin?: () => void; +} + +export const ColumnHeader: React.FC = ({ + title, + icon, + iconComponent, + active, + children, + pinned, + multiColumn, + extraButton, + showBackButton, + placeholder, + appendContent, + collapseIssues, + onClick, + onMove, + onPin, +}) => { + const intl = useIntl(); + const { signedIn } = useIdentity(); + const history = useAppHistory(); + const [collapsed, setCollapsed] = useState(true); + const [animating, setAnimating] = useState(false); + + const handleToggleClick = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + setCollapsed((value) => !value); + setAnimating(true); + }, + [setCollapsed, setAnimating], + ); + + const handleTitleClick = useCallback(() => { + onClick?.(); + }, [onClick]); + + const handleMoveLeft = useCallback(() => { + onMove?.(-1); + }, [onMove]); + + const handleMoveRight = useCallback(() => { + onMove?.(1); + }, [onMove]); + + const handleTransitionEnd = useCallback(() => { + setAnimating(false); + }, [setAnimating]); + + const handlePin = useCallback(() => { + if (!pinned) { + history.replace('/'); + } + + onPin?.(); + }, [history, pinned, onPin]); + + const wrapperClassName = classNames('column-header__wrapper', { + active, + }); + + const buttonClassName = classNames('column-header', { + active, + }); + + const collapsibleClassName = classNames('column-header__collapsible', { + collapsed, + animating, + }); + + const collapsibleButtonClassName = classNames('column-header__button', { + active: !collapsed, + }); + + let extraContent, pinButton, moveButtons, backButton, collapseButton; + + if (children) { + extraContent = ( +
+ {children} +
+ ); + } + + if (multiColumn && pinned) { + pinButton = ( + + ); + + moveButtons = ( +
+ + +
+ ); + } else if (multiColumn && onPin) { + pinButton = ( + + ); + } + + if ( + !pinned && + ((multiColumn && history.location.state?.fromMastodon) || showBackButton) + ) { + backButton = ; + } + + const collapsedContent = [extraContent]; + + if (multiColumn) { + collapsedContent.push( +
+ {pinButton} + {moveButtons} +
, + ); + } + + if (signedIn && (children || (multiColumn && onPin))) { + collapseButton = ( + + ); + } + + const hasIcon = icon && iconComponent; + const hasTitle = hasIcon && title; + + const component = ( +
+

+ {hasTitle && ( + <> + {backButton} + + + + )} + + {!hasTitle && backButton} + +
+ {extraButton} + {collapseButton} +
+

+ +
+
+ {(!collapsed || animating) && collapsedContent} +
+
+ + {appendContent} +
+ ); + + if (placeholder) { + return component; + } else { + return {component}; + } +}; + +// eslint-disable-next-line import/no-default-export +export default ColumnHeader; diff --git a/app/javascript/mastodon/features/directory/index.tsx b/app/javascript/mastodon/features/directory/index.tsx index 482c6858f4..51d283a482 100644 --- a/app/javascript/mastodon/features/directory/index.tsx +++ b/app/javascript/mastodon/features/directory/index.tsx @@ -16,7 +16,7 @@ import { } from 'mastodon/actions/columns'; import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory'; import Column from 'mastodon/components/column'; -import ColumnHeader from 'mastodon/components/column_header'; +import { ColumnHeader } from 'mastodon/components/column_header'; import { LoadMore } from 'mastodon/components/load_more'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { RadioButton } from 'mastodon/components/radio_button'; @@ -86,7 +86,7 @@ export const Directory: React.FC<{ }, [dispatch, order, local]); const handleMove = useCallback( - (dir: string) => { + (dir: number) => { dispatch(moveColumn(columnId, dir)); }, [dispatch, columnId], @@ -185,7 +185,6 @@ export const Directory: React.FC<{ label={intl.formatMessage(messages.title)} > = (otherProps) => ( +export const ColumnLoading: React.FC = (otherProps) => (
From ad53b0ab65cd9eba6d3078a3980c467428e79371 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 27 Jun 2024 03:16:59 -0400 Subject: [PATCH 11/34] Rely on built-in ruby private IP detection (#30848) --- Gemfile | 2 -- Gemfile.lock | 2 -- app/lib/private_address_check.rb | 33 ++++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 app/lib/private_address_check.rb diff --git a/Gemfile b/Gemfile index f2d7d098d5..aa3ca8f792 100644 --- a/Gemfile +++ b/Gemfile @@ -100,8 +100,6 @@ gem 'json-ld' gem 'json-ld-preloaded', '~> 3.2' gem 'rdf-normalize', '~> 0.5' -gem 'private_address_check', '~> 0.5' - gem 'opentelemetry-api', '~> 1.2.5' group :opentelemetry do diff --git a/Gemfile.lock b/Gemfile.lock index e8b54ed568..3b1b4b1121 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -595,7 +595,6 @@ GEM actionmailer (>= 3) net-smtp premailer (~> 1.7, >= 1.7.9) - private_address_check (0.5.0) propshaft (0.9.0) actionpack (>= 7.0.0) activesupport (>= 7.0.0) @@ -994,7 +993,6 @@ DEPENDENCIES pg (~> 1.5) pghero premailer-rails - private_address_check (~> 0.5) propshaft public_suffix (~> 6.0) puma (~> 6.3) diff --git a/app/lib/private_address_check.rb b/app/lib/private_address_check.rb new file mode 100644 index 0000000000..d00b16e66b --- /dev/null +++ b/app/lib/private_address_check.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module PrivateAddressCheck + module_function + + CIDR_LIST = [ + IPAddr.new('0.0.0.0/8'), # Current network (only valid as source address) + IPAddr.new('100.64.0.0/10'), # Shared Address Space + IPAddr.new('172.16.0.0/12'), # Private network + IPAddr.new('192.0.0.0/24'), # IETF Protocol Assignments + IPAddr.new('192.0.2.0/24'), # TEST-NET-1, documentation and examples + IPAddr.new('192.88.99.0/24'), # IPv6 to IPv4 relay (includes 2002::/16) + IPAddr.new('198.18.0.0/15'), # Network benchmark tests + IPAddr.new('198.51.100.0/24'), # TEST-NET-2, documentation and examples + IPAddr.new('203.0.113.0/24'), # TEST-NET-3, documentation and examples + IPAddr.new('224.0.0.0/4'), # IP multicast (former Class D network) + IPAddr.new('240.0.0.0/4'), # Reserved (former Class E network) + IPAddr.new('255.255.255.255'), # Broadcast + IPAddr.new('64:ff9b::/96'), # IPv4/IPv6 translation (RFC 6052) + IPAddr.new('100::/64'), # Discard prefix (RFC 6666) + IPAddr.new('2001::/32'), # Teredo tunneling + IPAddr.new('2001:10::/28'), # Deprecated (previously ORCHID) + IPAddr.new('2001:20::/28'), # ORCHIDv2 + IPAddr.new('2001:db8::/32'), # Addresses used in documentation and example source code + IPAddr.new('2002::/16'), # 6to4 + IPAddr.new('fc00::/7'), # Unique local address + IPAddr.new('ff00::/8'), # Multicast + ].freeze + + def private_address?(address) + address.private? || address.loopback? || address.link_local? || CIDR_LIST.any? { |cidr| cidr.include?(address) } + end +end From f6390c3326b016e1a52057573839a5608ba317ea Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 27 Jun 2024 03:42:57 -0400 Subject: [PATCH 12/34] Use flatware to parallelize CI specs (#30284) --- .github/workflows/test-ruby.yml | 8 +++++--- Gemfile | 3 +++ Gemfile.lock | 10 ++++++++++ bin/flatware | 27 +++++++++++++++++++++++++++ spec/flatware_helper.rb | 12 ++++++++++++ 5 files changed, 57 insertions(+), 3 deletions(-) create mode 100755 bin/flatware create mode 100644 spec/flatware_helper.rb diff --git a/.github/workflows/test-ruby.yml b/.github/workflows/test-ruby.yml index dd71fd253b..ef898968d0 100644 --- a/.github/workflows/test-ruby.yml +++ b/.github/workflows/test-ruby.yml @@ -132,15 +132,17 @@ jobs: additional-system-dependencies: ffmpeg libpam-dev - name: Load database schema - run: './bin/rails db:create db:schema:load db:seed' + run: | + bin/rails db:setup + bin/flatware fan bin/rails db:test:prepare - - run: bin/rspec + - run: bin/flatware rspec -r ./spec/flatware_helper.rb - name: Upload coverage reports to Codecov if: matrix.ruby-version == '.ruby-version' uses: codecov/codecov-action@v4 with: - files: coverage/lcov/mastodon.lcov + files: coverage/lcov/*.lcov env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/Gemfile b/Gemfile index aa3ca8f792..be3f9e6f98 100644 --- a/Gemfile +++ b/Gemfile @@ -121,6 +121,9 @@ group :opentelemetry do end group :test do + # Enable usage of all available CPUs/cores during spec runs + gem 'flatware-rspec' + # Adds RSpec Error/Warning annotations to GitHub PRs on the Files tab gem 'rspec-github', '~> 2.4', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 3b1b4b1121..dd112d0189 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,6 +264,11 @@ GEM ffi-compiler (1.3.2) ffi (>= 1.15.5) rake + flatware (2.3.2) + thor (< 2.0) + flatware-rspec (2.3.2) + flatware (= 2.3.2) + rspec (>= 3.6) fog-core (2.4.0) builder excon (~> 0.71) @@ -700,6 +705,10 @@ GEM chunky_png (~> 1.0) rqrcode_core (~> 1.0) rqrcode_core (1.2.0) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) rspec-core (3.13.0) rspec-support (~> 3.13.0) rspec-expectations (3.13.1) @@ -932,6 +941,7 @@ DEPENDENCIES faker (~> 3.2) fast_blank (~> 1.0) fastimage + flatware-rspec fog-core (<= 2.4.0) fog-openstack (~> 1.0) fuubar (~> 2.5) diff --git a/bin/flatware b/bin/flatware new file mode 100755 index 0000000000..337ce9277e --- /dev/null +++ b/bin/flatware @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'flatware' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("flatware", "flatware") diff --git a/spec/flatware_helper.rb b/spec/flatware_helper.rb new file mode 100644 index 0000000000..57a7c1f56a --- /dev/null +++ b/spec/flatware_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +if defined?(Flatware) + Flatware.configure do |config| + config.after_fork do |test_env_number| + unless ENV.fetch('DISABLE_SIMPLECOV', nil) == 'true' + require 'simplecov' + SimpleCov.at_fork.call(test_env_number) # Combines parallel coverage results + end + end + end +end From 6d1c1fd684d0f20691cba552b209b15d0107dfe4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 10:00:04 +0200 Subject: [PATCH 13/34] New Crowdin Translations (automated) (#30851) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/af.json | 1 - app/javascript/mastodon/locales/an.json | 3 --- app/javascript/mastodon/locales/ar.json | 3 --- app/javascript/mastodon/locales/ast.json | 2 -- app/javascript/mastodon/locales/be.json | 3 --- app/javascript/mastodon/locales/bg.json | 3 --- app/javascript/mastodon/locales/bn.json | 3 --- app/javascript/mastodon/locales/br.json | 3 --- app/javascript/mastodon/locales/ca.json | 6 +++--- app/javascript/mastodon/locales/ckb.json | 3 --- app/javascript/mastodon/locales/co.json | 3 --- app/javascript/mastodon/locales/cs.json | 3 --- app/javascript/mastodon/locales/cy.json | 3 --- app/javascript/mastodon/locales/da.json | 4 +--- app/javascript/mastodon/locales/el.json | 3 --- app/javascript/mastodon/locales/en-GB.json | 3 --- app/javascript/mastodon/locales/eo.json | 3 --- app/javascript/mastodon/locales/es-AR.json | 2 +- app/javascript/mastodon/locales/es-MX.json | 6 +++--- app/javascript/mastodon/locales/es.json | 6 +++--- app/javascript/mastodon/locales/et.json | 3 --- app/javascript/mastodon/locales/eu.json | 3 --- app/javascript/mastodon/locales/fa.json | 3 --- app/javascript/mastodon/locales/fi.json | 2 +- app/javascript/mastodon/locales/fo.json | 3 --- app/javascript/mastodon/locales/fr-CA.json | 3 --- app/javascript/mastodon/locales/fr.json | 3 --- app/javascript/mastodon/locales/fy.json | 3 --- app/javascript/mastodon/locales/ga.json | 3 --- app/javascript/mastodon/locales/gd.json | 3 --- app/javascript/mastodon/locales/gl.json | 3 --- app/javascript/mastodon/locales/he.json | 3 --- app/javascript/mastodon/locales/hi.json | 3 --- app/javascript/mastodon/locales/hr.json | 3 --- app/javascript/mastodon/locales/hu.json | 3 --- app/javascript/mastodon/locales/hy.json | 3 --- app/javascript/mastodon/locales/ia.json | 1 + app/javascript/mastodon/locales/id.json | 3 --- app/javascript/mastodon/locales/ie.json | 3 --- app/javascript/mastodon/locales/io.json | 3 --- app/javascript/mastodon/locales/is.json | 2 +- app/javascript/mastodon/locales/it.json | 6 +++--- app/javascript/mastodon/locales/ja.json | 3 --- app/javascript/mastodon/locales/ka.json | 1 - app/javascript/mastodon/locales/kab.json | 3 --- app/javascript/mastodon/locales/kk.json | 3 --- app/javascript/mastodon/locales/kn.json | 1 - app/javascript/mastodon/locales/ko.json | 3 --- app/javascript/mastodon/locales/ku.json | 3 --- app/javascript/mastodon/locales/kw.json | 3 --- app/javascript/mastodon/locales/la.json | 3 --- app/javascript/mastodon/locales/lad.json | 3 --- app/javascript/mastodon/locales/lt.json | 3 --- app/javascript/mastodon/locales/lv.json | 3 --- app/javascript/mastodon/locales/mk.json | 1 - app/javascript/mastodon/locales/ml.json | 3 --- app/javascript/mastodon/locales/mr.json | 3 --- app/javascript/mastodon/locales/ms.json | 3 --- app/javascript/mastodon/locales/my.json | 3 --- app/javascript/mastodon/locales/ne.json | 1 - app/javascript/mastodon/locales/nn.json | 3 --- app/javascript/mastodon/locales/no.json | 3 --- app/javascript/mastodon/locales/oc.json | 3 --- app/javascript/mastodon/locales/pa.json | 3 --- app/javascript/mastodon/locales/pl.json | 3 --- app/javascript/mastodon/locales/pt-BR.json | 3 --- app/javascript/mastodon/locales/pt-PT.json | 3 --- app/javascript/mastodon/locales/ro.json | 3 --- app/javascript/mastodon/locales/ru.json | 3 --- app/javascript/mastodon/locales/sa.json | 3 --- app/javascript/mastodon/locales/sc.json | 3 --- app/javascript/mastodon/locales/sco.json | 3 --- app/javascript/mastodon/locales/si.json | 3 --- app/javascript/mastodon/locales/sk.json | 3 --- app/javascript/mastodon/locales/sl.json | 6 +++--- app/javascript/mastodon/locales/sq.json | 3 --- app/javascript/mastodon/locales/sr-Latn.json | 6 +++--- app/javascript/mastodon/locales/sr.json | 6 +++--- app/javascript/mastodon/locales/sv.json | 3 --- app/javascript/mastodon/locales/szl.json | 1 - app/javascript/mastodon/locales/ta.json | 3 --- app/javascript/mastodon/locales/tai.json | 1 - app/javascript/mastodon/locales/te.json | 1 - app/javascript/mastodon/locales/th.json | 3 --- app/javascript/mastodon/locales/tr.json | 6 +++--- app/javascript/mastodon/locales/tt.json | 3 --- app/javascript/mastodon/locales/ug.json | 1 - app/javascript/mastodon/locales/uk.json | 3 --- app/javascript/mastodon/locales/ur.json | 3 --- app/javascript/mastodon/locales/uz.json | 3 --- app/javascript/mastodon/locales/vi.json | 3 --- app/javascript/mastodon/locales/zgh.json | 1 - app/javascript/mastodon/locales/zh-CN.json | 7 ++++--- app/javascript/mastodon/locales/zh-HK.json | 3 --- app/javascript/mastodon/locales/zh-TW.json | 6 +++--- config/locales/fi.yml | 2 +- config/locales/sr-Latn.yml | 2 +- config/locales/sr.yml | 2 +- config/locales/zh-TW.yml | 2 +- 99 files changed, 40 insertions(+), 259 deletions(-) diff --git a/app/javascript/mastodon/locales/af.json b/app/javascript/mastodon/locales/af.json index e4f7f12b0e..77e15eb2c6 100644 --- a/app/javascript/mastodon/locales/af.json +++ b/app/javascript/mastodon/locales/af.json @@ -50,7 +50,6 @@ "account.requested_follow": "{name} het versoek om jou te volg", "account.share": "Deel @{name} se profiel", "account.show_reblogs": "Wys aangestuurde plasings van @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Plaas} other {{counter} Plasings}}", "account.unblock": "Deblokkeer @{name}", "account.unblock_domain": "Deblokkeer domein {domain}", "account.unblock_short": "Deblokkeer", diff --git a/app/javascript/mastodon/locales/an.json b/app/javascript/mastodon/locales/an.json index af5f8426d0..752b6c3564 100644 --- a/app/javascript/mastodon/locales/an.json +++ b/app/javascript/mastodon/locales/an.json @@ -31,9 +31,7 @@ "account.follow": "Seguir", "account.followers": "Seguidores", "account.followers.empty": "Encara no sigue dengún a este usuario.", - "account.followers_counter": "{count, plural, one {{counter} Seguidor} other {{counter} Seguidores}}", "account.following": "Seguindo", - "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Seguindo}}", "account.follows.empty": "Este usuario encara no sigue a dengún.", "account.go_to_profile": "Ir ta lo perfil", "account.hide_reblogs": "Amagar retutz de @{name}", @@ -54,7 +52,6 @@ "account.requested_follow": "{name} ha demandau seguir-te", "account.share": "Compartir lo perfil de @{name}", "account.show_reblogs": "Amostrar retutz de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Publicación} other {{counter} Publicaciones}}", "account.unblock": "Desblocar a @{name}", "account.unblock_domain": "Amostrar a {domain}", "account.unblock_short": "Desblocar", diff --git a/app/javascript/mastodon/locales/ar.json b/app/javascript/mastodon/locales/ar.json index b5ce0ae861..a9e1bdb270 100644 --- a/app/javascript/mastodon/locales/ar.json +++ b/app/javascript/mastodon/locales/ar.json @@ -35,9 +35,7 @@ "account.follow_back": "رد المتابعة", "account.followers": "مُتابِعون", "account.followers.empty": "لا أحدَ يُتابع هذا المُستخدم إلى حد الآن.", - "account.followers_counter": "{count, plural, zero{لا مُتابع} one {مُتابعٌ واحِد} two {مُتابعانِ اِثنان} few {{counter} مُتابِعين} many {{counter} مُتابِعًا} other {{counter} مُتابع}}", "account.following": "الاشتراكات", - "account.following_counter": "{count, plural, zero{لا يُتابِع أحدًا} one {يُتابِعُ واحد} two{يُتابِعُ اِثنان} few{يُتابِعُ {counter}} many{يُتابِعُ {counter}} other {يُتابِعُ {counter}}}", "account.follows.empty": "لا يُتابع هذا المُستخدمُ أيَّ أحدٍ حتى الآن.", "account.go_to_profile": "اذهب إلى الملف الشخصي", "account.hide_reblogs": "إخفاء المعاد نشرها مِن @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "لقد طلب {name} متابعتك", "account.share": "شارِك الملف التعريفي لـ @{name}", "account.show_reblogs": "اعرض إعادات نشر @{name}", - "account.statuses_counter": "{count, plural, zero {لَا منشورات} one {منشور واحد} two {منشوران إثنان} few {{counter} منشورات} many {{counter} منشورًا} other {{counter} منشور}}", "account.unblock": "إلغاء الحَظر عن @{name}", "account.unblock_domain": "إلغاء الحَظر عن النِّطاق {domain}", "account.unblock_short": "ألغ الحجب", diff --git a/app/javascript/mastodon/locales/ast.json b/app/javascript/mastodon/locales/ast.json index 80e0aa6cbf..3f32a8bf15 100644 --- a/app/javascript/mastodon/locales/ast.json +++ b/app/javascript/mastodon/locales/ast.json @@ -32,7 +32,6 @@ "account.followers": "Siguidores", "account.followers.empty": "Naide sigue a esti perfil.", "account.following": "Siguiendo", - "account.following_counter": "{count, plural,one {Sigue a {counter}} other {Sigue a {counter}}}", "account.follows.empty": "Esti perfil nun sigue a naide.", "account.go_to_profile": "Dir al perfil", "account.hide_reblogs": "Anubrir los artículos compartíos de @{name}", @@ -49,7 +48,6 @@ "account.report": "Informar de: @{name}", "account.requested_follow": "{name} solicitó siguite", "account.show_reblogs": "Amosar los artículos compartíos de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} artículu} other {{counter} artículos}}", "account.unblock": "Desbloquiar a @{name}", "account.unblock_domain": "Desbloquiar el dominiu «{domain}»", "account.unblock_short": "Desbloquiar", diff --git a/app/javascript/mastodon/locales/be.json b/app/javascript/mastodon/locales/be.json index 03164c4290..643725270c 100644 --- a/app/javascript/mastodon/locales/be.json +++ b/app/javascript/mastodon/locales/be.json @@ -35,9 +35,7 @@ "account.follow_back": "Падпісацца ў адказ", "account.followers": "Падпісчыкі", "account.followers.empty": "Ніхто пакуль не падпісаны на гэтага карыстальніка.", - "account.followers_counter": "{count, plural, one {{counter} падпісчык} few {{counter} падпісчыкі} many {{counter} падпісчыкаў} other {{counter} падпісчыка}}", "account.following": "Падпіскі", - "account.following_counter": "{count, plural, one {{counter} падпіска} few {{counter} падпіскі} many {{counter} падпісак} other {{counter} падпіскі}}", "account.follows.empty": "Карыстальнік ні на каго не падпісаны.", "account.go_to_profile": "Перайсці да профілю", "account.hide_reblogs": "Схаваць пашырэнні ад @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} адправіў запыт на падпіску", "account.share": "Абагуліць профіль @{name}", "account.show_reblogs": "Паказаць падштурхоўванні ад @{name}", - "account.statuses_counter": "{count, plural, one {{counter} допіс} few {{counter} допісы} many {{counter} допісаў} other {{counter} допісу}}", "account.unblock": "Разблакіраваць @{name}", "account.unblock_domain": "Разблакіраваць дамен {domain}", "account.unblock_short": "Разблакіраваць", diff --git a/app/javascript/mastodon/locales/bg.json b/app/javascript/mastodon/locales/bg.json index 98e84c45d7..323890ba2e 100644 --- a/app/javascript/mastodon/locales/bg.json +++ b/app/javascript/mastodon/locales/bg.json @@ -35,9 +35,7 @@ "account.follow_back": "Последване взаимно", "account.followers": "Последователи", "account.followers.empty": "Още никой не следва потребителя.", - "account.followers_counter": "{count, plural, one {{counter} последовател} other {{counter} последователи}}", "account.following": "Последвано", - "account.following_counter": "{count, plural, one {{counter} последван} other {{counter} последвани}}", "account.follows.empty": "Потребителят още никого не следва.", "account.go_to_profile": "Към профила", "account.hide_reblogs": "Скриване на подсилвания от @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} поиска да ви последва", "account.share": "Споделяне на профила на @{name}", "account.show_reblogs": "Показване на подсилвания от @{name}", - "account.statuses_counter": "{count, plural, one {{counter} публикация} other {{counter} публикации}}", "account.unblock": "Отблокиране на @{name}", "account.unblock_domain": "Отблокиране на домейн {domain}", "account.unblock_short": "Отблокиране", diff --git a/app/javascript/mastodon/locales/bn.json b/app/javascript/mastodon/locales/bn.json index 4c4138bcf1..a203c43f03 100644 --- a/app/javascript/mastodon/locales/bn.json +++ b/app/javascript/mastodon/locales/bn.json @@ -33,9 +33,7 @@ "account.follow": "অনুসরণ", "account.followers": "অনুসরণকারী", "account.followers.empty": "এই ব্যক্তিকে এখনো কেউ অনুসরণ করে না.", - "account.followers_counter": "{count, plural,one {{counter} জন অনুসরণকারী } other {{counter} জন অনুসরণকারী}}", "account.following": "অনুসরণ করা হচ্ছে", - "account.following_counter": "{count, plural,one {{counter} জনকে অনুসরণ} other {{counter} জনকে অনুসরণ}}", "account.follows.empty": "এই সদস্য কাউকে এখনো ফলো করেন না.", "account.go_to_profile": "প্রোফাইলে যান", "account.hide_reblogs": "@{name}'র সমর্থনগুলি লুকিয়ে ফেলুন", @@ -60,7 +58,6 @@ "account.requested_follow": "{name} আপনাকে অনুসরণ করার জন্য অনুরোধ করেছে", "account.share": "@{name} র প্রোফাইল অন্যদের দেখান", "account.show_reblogs": "@{name} র সমর্থনগুলো দেখান", - "account.statuses_counter": "{count, plural,one {{counter} টুট} other {{counter} টুট}}", "account.unblock": "@{name} র কার্যকলাপ দেখুন", "account.unblock_domain": "{domain} কে আবার দেখুন", "account.unblock_short": "আনব্লক করুন", diff --git a/app/javascript/mastodon/locales/br.json b/app/javascript/mastodon/locales/br.json index 7cd49ba59d..c919d2e9de 100644 --- a/app/javascript/mastodon/locales/br.json +++ b/app/javascript/mastodon/locales/br.json @@ -35,9 +35,7 @@ "account.follow_back": "Heuliañ d'ho tro", "account.followers": "Tud koumanantet", "account.followers.empty": "Den na heul an implijer·ez-mañ c'hoazh.", - "account.followers_counter": "{count, plural, other{{counter} Heulier·ez}}", "account.following": "Koumanantoù", - "account.following_counter": "{count, plural, one{{counter} C'houmanant} two{{counter} Goumanant} other {{counter} a Goumanant}}", "account.follows.empty": "An implijer·ez-mañ na heul den ebet.", "account.go_to_profile": "Gwelet ar profil", "account.hide_reblogs": "Kuzh skignadennoù gant @{name}", @@ -62,7 +60,6 @@ "account.requested_follow": "Gant {name} eo bet goulennet ho heuliañ", "account.share": "Skignañ profil @{name}", "account.show_reblogs": "Diskouez skignadennoù @{name}", - "account.statuses_counter": "{count, plural, one {{counter} C'hannad} two {{counter} Gannad} other {{counter} a Gannadoù}}", "account.unblock": "Diverzañ @{name}", "account.unblock_domain": "Diverzañ an domani {domain}", "account.unblock_short": "Distankañ", diff --git a/app/javascript/mastodon/locales/ca.json b/app/javascript/mastodon/locales/ca.json index 88dd34aff0..3123e29d8d 100644 --- a/app/javascript/mastodon/locales/ca.json +++ b/app/javascript/mastodon/locales/ca.json @@ -35,9 +35,9 @@ "account.follow_back": "Segueix tu també", "account.followers": "Seguidors", "account.followers.empty": "A aquest usuari encara no el segueix ningú.", - "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} Seguidors}}", + "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidors}}", "account.following": "Seguint", - "account.following_counter": "{count, plural, other {{counter} Seguint-ne}}", + "account.following_counter": "{count, plural, other {Seguint-ne {counter}}}", "account.follows.empty": "Aquest usuari encara no segueix ningú.", "account.go_to_profile": "Vés al perfil", "account.hide_reblogs": "Amaga els impulsos de @{name}", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} ha demanat de seguir-te", "account.share": "Comparteix el perfil de @{name}", "account.show_reblogs": "Mostra els impulsos de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Tut} other {{counter} Tuts}}", + "account.statuses_counter": "{count, plural, one {{counter} publicació} other {{counter} publicacions}}", "account.unblock": "Desbloca @{name}", "account.unblock_domain": "Desbloca el domini {domain}", "account.unblock_short": "Desbloca", diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json index c212b53a8b..3ebf9391d2 100644 --- a/app/javascript/mastodon/locales/ckb.json +++ b/app/javascript/mastodon/locales/ckb.json @@ -35,9 +35,7 @@ "account.follow_back": "فۆڵۆو بکەنەوە", "account.followers": "شوێنکەوتووان", "account.followers.empty": "کەسێک شوێن ئەم بەکارهێنەرە نەکەوتووە", - "account.followers_counter": "{count, plural, one {{counter} شوێنکەوتوو} other {{counter} شوێنکەوتوو}}", "account.following": "بەدوادا", - "account.following_counter": "{count, plural, one {{counter} شوێنکەوتوو} other {{counter} شوێنکەوتوو}}", "account.follows.empty": "ئەم بەکارهێنەرە تا ئێستا شوێن کەس نەکەوتووە.", "account.go_to_profile": "بڕۆ بۆ پڕۆفایلی", "account.hide_reblogs": "داشاردنی بووستەکان لە @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} داوای کردووە شوێنت بکەوێت", "account.share": "پرۆفایلی @{name} هاوبەش بکە", "account.show_reblogs": "پیشاندانی بەرزکردنەوەکان لە @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.unblock": "@{name} لاببە", "account.unblock_domain": "کردنەوەی دۆمەینی {domain}", "account.unblock_short": "لابردنی بەربەست", diff --git a/app/javascript/mastodon/locales/co.json b/app/javascript/mastodon/locales/co.json index be4cce2692..78f8e6fd78 100644 --- a/app/javascript/mastodon/locales/co.json +++ b/app/javascript/mastodon/locales/co.json @@ -16,8 +16,6 @@ "account.follow": "Siguità", "account.followers": "Abbunati", "account.followers.empty": "Nisunu hè abbunatu à st'utilizatore.", - "account.followers_counter": "{count, plural, one {{counter} Abbunatu} other {{counter} Abbunati}}", - "account.following_counter": "{count, plural, one {{counter} Abbunamentu} other {{counter} Abbunamenti}}", "account.follows.empty": "St'utilizatore ùn seguita nisunu.", "account.hide_reblogs": "Piattà spartere da @{name}", "account.link_verified_on": "A prupietà di stu ligame hè stata verificata u {date}", @@ -32,7 +30,6 @@ "account.requested": "In attesa d'apprubazione. Cliccate per annullà a dumanda", "account.share": "Sparte u prufile di @{name}", "account.show_reblogs": "Vede spartere da @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Statutu} other {{counter} Statuti}}", "account.unblock": "Sbluccà @{name}", "account.unblock_domain": "Ùn piattà più {domain}", "account.unendorse": "Ùn fà figurà nant'à u prufilu", diff --git a/app/javascript/mastodon/locales/cs.json b/app/javascript/mastodon/locales/cs.json index d8d83ae5fa..66aa1fe0a9 100644 --- a/app/javascript/mastodon/locales/cs.json +++ b/app/javascript/mastodon/locales/cs.json @@ -35,9 +35,7 @@ "account.follow_back": "Také sledovat", "account.followers": "Sledující", "account.followers.empty": "Tohoto uživatele zatím nikdo nesleduje.", - "account.followers_counter": "{count, plural, one {{counter} Sledující} few {{counter} Sledující} many {{counter} Sledujících} other {{counter} Sledujících}}", "account.following": "Sledujete", - "account.following_counter": "{count, plural, one {{counter} Sledovaný} few {{counter} Sledovaní} many {{counter} Sledovaných} other {{counter} Sledovaných}}", "account.follows.empty": "Tento uživatel zatím nikoho nesleduje.", "account.go_to_profile": "Přejít na profil", "account.hide_reblogs": "Skrýt boosty od @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} tě požádal o sledování", "account.share": "Sdílet profil @{name}", "account.show_reblogs": "Zobrazit boosty od @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Příspěvek} few {{counter} Příspěvky} many {{counter} Příspěvků} other {{counter} Příspěvků}}", "account.unblock": "Odblokovat @{name}", "account.unblock_domain": "Odblokovat doménu {domain}", "account.unblock_short": "Odblokovat", diff --git a/app/javascript/mastodon/locales/cy.json b/app/javascript/mastodon/locales/cy.json index 96476b1433..1c7e61832c 100644 --- a/app/javascript/mastodon/locales/cy.json +++ b/app/javascript/mastodon/locales/cy.json @@ -35,9 +35,7 @@ "account.follow_back": "Dilyn yn ôl", "account.followers": "Dilynwyr", "account.followers.empty": "Does neb yn dilyn y defnyddiwr hwn eto.", - "account.followers_counter": "{count, plural, one {Dilynwr: {counter}} other {Dilynwyr: {counter}}}", "account.following": "Yn dilyn", - "account.following_counter": "{count, plural, one {Yn dilyn: {counter}} other {Yn dilyn: {counter}}}", "account.follows.empty": "Nid yw'r defnyddiwr hwn yn dilyn unrhyw un eto.", "account.go_to_profile": "Mynd i'r proffil", "account.hide_reblogs": "Cuddio hybiau gan @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "Mae {name} wedi gwneud cais i'ch dilyn", "account.share": "Rhannwch broffil @{name}", "account.show_reblogs": "Dangos hybiau gan @{name}", - "account.statuses_counter": "{count, plural, one {Postiad: {counter}} other {Postiad: {counter}}}", "account.unblock": "Dadflocio @{name}", "account.unblock_domain": "Dadflocio parth {domain}", "account.unblock_short": "Dadflocio", diff --git a/app/javascript/mastodon/locales/da.json b/app/javascript/mastodon/locales/da.json index 5ac7128a37..d8c178d295 100644 --- a/app/javascript/mastodon/locales/da.json +++ b/app/javascript/mastodon/locales/da.json @@ -35,9 +35,8 @@ "account.follow_back": "Følg tilbage", "account.followers": "Følgere", "account.followers.empty": "Ingen følger denne bruger endnu.", - "account.followers_counter": "{count, plural, one {{counter} Følger} other {{counter} Følgere}}", + "account.followers_counter": "{count, plural, one {{counter} følger} other {{counter} følgere}}", "account.following": "Følger", - "account.following_counter": "{count, plural, one {{counter} Følges} other {{counter} Følges}}", "account.follows.empty": "Denne bruger følger ikke nogen endnu.", "account.go_to_profile": "Gå til profil", "account.hide_reblogs": "Skjul boosts fra @{name}", @@ -63,7 +62,6 @@ "account.requested_follow": "{name} har anmodet om at følge dig", "account.share": "Del @{name}s profil", "account.show_reblogs": "Vis fremhævelser fra @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Indlæg} other {{counter} Indlæg}}", "account.unblock": "Afblokér @{name}", "account.unblock_domain": "Afblokér domænet {domain}", "account.unblock_short": "Afblokér", diff --git a/app/javascript/mastodon/locales/el.json b/app/javascript/mastodon/locales/el.json index 47a8df6200..5442624b36 100644 --- a/app/javascript/mastodon/locales/el.json +++ b/app/javascript/mastodon/locales/el.json @@ -35,9 +35,7 @@ "account.follow_back": "Ακολούθησε και εσύ", "account.followers": "Ακόλουθοι", "account.followers.empty": "Κανείς δεν ακολουθεί αυτόν τον χρήστη ακόμα.", - "account.followers_counter": "{count, plural, one {{counter} Ακόλουθος} other {{counter} Ακόλουθοι}}", "account.following": "Ακολουθείτε", - "account.following_counter": "{count, plural, one {{counter} Ακολουθεί} other {{counter} Ακολουθούν}}", "account.follows.empty": "Αυτός ο χρήστης δεν ακολουθεί κανέναν ακόμα.", "account.go_to_profile": "Μετάβαση στο προφίλ", "account.hide_reblogs": "Απόκρυψη ενισχύσεων από @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "Ο/Η {name} αιτήθηκε να σε ακολουθήσει", "account.share": "Κοινοποίηση του προφίλ @{name}", "account.show_reblogs": "Εμφάνιση ενισχύσεων από @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Ανάρτηση} other {{counter} Αναρτήσεις}}", "account.unblock": "Άρση αποκλεισμού @{name}", "account.unblock_domain": "Άρση αποκλεισμού του τομέα {domain}", "account.unblock_short": "Άρση αποκλεισμού", diff --git a/app/javascript/mastodon/locales/en-GB.json b/app/javascript/mastodon/locales/en-GB.json index 108880cc97..c4f401d86d 100644 --- a/app/javascript/mastodon/locales/en-GB.json +++ b/app/javascript/mastodon/locales/en-GB.json @@ -35,9 +35,7 @@ "account.follow_back": "Follow back", "account.followers": "Followers", "account.followers.empty": "No one follows this user yet.", - "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Followers}}", "account.following": "Following", - "account.following_counter": "{count, plural, one {{counter} Following} other {{counter} Following}}", "account.follows.empty": "This user doesn't follow anyone yet.", "account.go_to_profile": "Go to profile", "account.hide_reblogs": "Hide boosts from @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} has requested to follow you", "account.share": "Share @{name}'s profile", "account.show_reblogs": "Show boosts from @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Posts}}", "account.unblock": "Unblock @{name}", "account.unblock_domain": "Unblock domain {domain}", "account.unblock_short": "Unblock", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index bab277b483..e7cfc03468 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -35,9 +35,7 @@ "account.follow_back": "Sekvu reen", "account.followers": "Sekvantoj", "account.followers.empty": "Ankoraŭ neniu sekvas ĉi tiun uzanton.", - "account.followers_counter": "{count, plural, one{{counter} Sekvanto} other {{counter} Sekvantoj}}", "account.following": "Sekvatoj", - "account.following_counter": "{count, plural, one {{counter} Sekvato} other {{counter} Sekvatoj}}", "account.follows.empty": "La uzanto ankoraŭ ne sekvas iun ajn.", "account.go_to_profile": "Iri al profilo", "account.hide_reblogs": "Kaŝi diskonigojn de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} petis sekvi vin", "account.share": "Diskonigi la profilon de @{name}", "account.show_reblogs": "Montri diskonigojn de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Afiŝo} other {{counter} Afiŝoj}}", "account.unblock": "Malbloki @{name}", "account.unblock_domain": "Malbloki la domajnon {domain}", "account.unblock_short": "Malbloki", diff --git a/app/javascript/mastodon/locales/es-AR.json b/app/javascript/mastodon/locales/es-AR.json index 7da39b88cc..28e8de9237 100644 --- a/app/javascript/mastodon/locales/es-AR.json +++ b/app/javascript/mastodon/locales/es-AR.json @@ -37,7 +37,7 @@ "account.followers.empty": "Todavía nadie sigue a este usuario.", "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.following": "Siguiendo", - "account.following_counter": "{count, plural, other {Siguiendo a {counter}}}", + "account.following_counter": "{count, plural, one {siguiendo a {counter}} other {siguiendo a {counter}}}", "account.follows.empty": "Todavía este usuario no sigue a nadie.", "account.go_to_profile": "Ir al perfil", "account.hide_reblogs": "Ocultar adhesiones de @{name}", diff --git a/app/javascript/mastodon/locales/es-MX.json b/app/javascript/mastodon/locales/es-MX.json index d3e02cd6e1..c10a161015 100644 --- a/app/javascript/mastodon/locales/es-MX.json +++ b/app/javascript/mastodon/locales/es-MX.json @@ -35,9 +35,9 @@ "account.follow_back": "Seguir también", "account.followers": "Seguidores", "account.followers.empty": "Todavía nadie sigue a este usuario.", - "account.followers_counter": "{count, plural, one {{counter} Seguidor} other {{counter} Seguidores}}", + "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.following": "Siguiendo", - "account.following_counter": "{count, plural, other {{counter} Siguiendo}}", + "account.following_counter": "{count, plural, one {{counter} siguiendo} other {{counter} siguiendo}}", "account.follows.empty": "Este usuario todavía no sigue a nadie.", "account.go_to_profile": "Ir al perfil", "account.hide_reblogs": "Ocultar retoots de @{name}", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} ha solicitado seguirte", "account.share": "Compartir el perfil de @{name}", "account.show_reblogs": "Mostrar retoots de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", + "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicaciones}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Mostrar a {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json index 849e0fa27f..259fc1795b 100644 --- a/app/javascript/mastodon/locales/es.json +++ b/app/javascript/mastodon/locales/es.json @@ -35,9 +35,9 @@ "account.follow_back": "Seguir también", "account.followers": "Seguidores", "account.followers.empty": "Todavía nadie sigue a este usuario.", - "account.followers_counter": "{count, plural, one {{counter} Seguidor} other {{counter} Seguidores}}", + "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.following": "Siguiendo", - "account.following_counter": "{count, plural, other {Siguiendo a {counter}}}", + "account.following_counter": "{count, plural, one {{counter} siguiendo} other {{counter} siguiendo}}", "account.follows.empty": "Este usuario todavía no sigue a nadie.", "account.go_to_profile": "Ir al perfil", "account.hide_reblogs": "Ocultar impulsos de @{name}", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} ha solicitado seguirte", "account.share": "Compartir el perfil de @{name}", "account.show_reblogs": "Mostrar impulsos de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Publicación} other {{counter} Publicaciones}}", + "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicaciones}}", "account.unblock": "Desbloquear a @{name}", "account.unblock_domain": "Desbloquear dominio {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/et.json b/app/javascript/mastodon/locales/et.json index 547a0fe61f..94f5ef5d9e 100644 --- a/app/javascript/mastodon/locales/et.json +++ b/app/javascript/mastodon/locales/et.json @@ -35,9 +35,7 @@ "account.follow_back": "Jälgi vastu", "account.followers": "Jälgijad", "account.followers.empty": "Keegi ei jälgi veel seda kasutajat.", - "account.followers_counter": "{count, plural, one {{counter} jälgija} other {{counter} jälgijat}}", "account.following": "Jälgib", - "account.following_counter": "{count, plural, one {{counter} jälgitav} other {{counter} jälgitavat}}", "account.follows.empty": "See kasutaja ei jälgi veel kedagi.", "account.go_to_profile": "Mine profiilile", "account.hide_reblogs": "Peida @{name} jagamised", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} on taodelnud sinu jälgimist", "account.share": "Jaga @{name} profiili", "account.show_reblogs": "Näita @{name} jagamisi", - "account.statuses_counter": "{count, plural, one {{counter} postitus} other {{counter} postitust}}", "account.unblock": "Eemalda blokeering @{name}", "account.unblock_domain": "Tee {domain} nähtavaks", "account.unblock_short": "Eemalda blokeering", diff --git a/app/javascript/mastodon/locales/eu.json b/app/javascript/mastodon/locales/eu.json index 5fbac270cf..97c4250d22 100644 --- a/app/javascript/mastodon/locales/eu.json +++ b/app/javascript/mastodon/locales/eu.json @@ -35,9 +35,7 @@ "account.follow_back": "Jarraitu bueltan", "account.followers": "Jarraitzaileak", "account.followers.empty": "Ez du inork erabiltzaile hau jarraitzen oraindik.", - "account.followers_counter": "{count, plural, one {Jarraitzaile {counter}} other {{counter} jarraitzaile}}", "account.following": "Jarraitzen", - "account.following_counter": "{count, plural, one {{counter} jarraitzen} other {{counter} jarraitzen}}", "account.follows.empty": "Erabiltzaile honek ez du inor jarraitzen oraindik.", "account.go_to_profile": "Joan profilera", "account.hide_reblogs": "Ezkutatu @{name} erabiltzailearen bultzadak", @@ -63,7 +61,6 @@ "account.requested_follow": "{name}-(e)k zu jarraitzeko eskaera egin du", "account.share": "Partekatu @{name} erabiltzailearen profila", "account.show_reblogs": "Erakutsi @{name} erabiltzailearen bultzadak", - "account.statuses_counter": "{count, plural, one {Bidalketa {counter}} other {{counter} bidalketa}}", "account.unblock": "Desblokeatu @{name}", "account.unblock_domain": "Berriz erakutsi {domain}", "account.unblock_short": "Desblokeatu", diff --git a/app/javascript/mastodon/locales/fa.json b/app/javascript/mastodon/locales/fa.json index 072a67421a..18f6466d48 100644 --- a/app/javascript/mastodon/locales/fa.json +++ b/app/javascript/mastodon/locales/fa.json @@ -35,9 +35,7 @@ "account.follow_back": "دنبال کردن متقابل", "account.followers": "پی‌گیرندگان", "account.followers.empty": "هنوز کسی پی‌گیر این کاربر نیست.", - "account.followers_counter": "{count, plural, one {{counter} پی‌گیرنده} other {{counter} پی‌گیرنده}}", "account.following": "پی می‌گیرید", - "account.following_counter": "{count, plural, one {{counter} پی‌گرفته} other {{counter} پی‌گرفته}}", "account.follows.empty": "این کاربر هنوز پی‌گیر کسی نیست.", "account.go_to_profile": "رفتن به نمایه", "account.hide_reblogs": "نهفتن تقویت‌های ‎@{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} درخواست پی‌گیریتان را داد", "account.share": "هم‌رسانی نمایهٔ ‎@{name}", "account.show_reblogs": "نمایش تقویت‌های ‎@{name}", - "account.statuses_counter": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}}", "account.unblock": "رفع مسدودیت ‎@{name}", "account.unblock_domain": "رفع مسدودیت دامنهٔ {domain}", "account.unblock_short": "رفع مسدودیت", diff --git a/app/javascript/mastodon/locales/fi.json b/app/javascript/mastodon/locales/fi.json index 67e2b72b86..0767dd5e37 100644 --- a/app/javascript/mastodon/locales/fi.json +++ b/app/javascript/mastodon/locales/fi.json @@ -699,7 +699,7 @@ "server_banner.is_one_of_many": "{domain} on yksi monista itsenäisistä Mastodon-palvelimista, joiden välityksellä voit toimia fediversumissa.", "server_banner.server_stats": "Palvelimen tilastot:", "sign_in_banner.create_account": "Luo tili", - "sign_in_banner.follow_anyone": "Seuraa kenen tahansa julkaisuja fediversumissa ja näe ne kaikki aikajärjestyksessä. Ei algoritmejä, mainoksia tai klikkikalastelua.", + "sign_in_banner.follow_anyone": "Seuraa kenen tahansa julkaisuja fediversumissa ja näe ne kaikki aikajärjestyksessä. Ei algoritmeja, mainoksia tai klikkausten kalastelua.", "sign_in_banner.mastodon_is": "Mastodon on paras tapa pysyä ajan tasalla siitä, mitä ympärillä tapahtuu.", "sign_in_banner.sign_in": "Kirjaudu", "sign_in_banner.sso_redirect": "Kirjaudu tai rekisteröidy", diff --git a/app/javascript/mastodon/locales/fo.json b/app/javascript/mastodon/locales/fo.json index 7a317820bb..e7786f388d 100644 --- a/app/javascript/mastodon/locales/fo.json +++ b/app/javascript/mastodon/locales/fo.json @@ -35,9 +35,7 @@ "account.follow_back": "Fylg aftur", "account.followers": "Fylgjarar", "account.followers.empty": "Ongar fylgjarar enn.", - "account.followers_counter": "{count, plural, one {{counter} Fylgjari} other {{counter} Fylgjarar}}", "account.following": "Fylgir", - "account.following_counter": "{count, plural, one {{counter} fylgir} other {{counter} fylgja}}", "account.follows.empty": "Hesin brúkari fylgir ongum enn.", "account.go_to_profile": "Far til vanga", "account.hide_reblogs": "Fjal lyft frá @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} hevur biðið um at fylgja tær", "account.share": "Deil vanga @{name}'s", "account.show_reblogs": "Vís lyft frá @{name}", - "account.statuses_counter": "{count, plural, one {{counter} postur} other {{counter} postar}}", "account.unblock": "Banna ikki @{name}", "account.unblock_domain": "Banna ikki økisnavnið {domain}", "account.unblock_short": "Banna ikki", diff --git a/app/javascript/mastodon/locales/fr-CA.json b/app/javascript/mastodon/locales/fr-CA.json index 50b7dcf90d..4324855003 100644 --- a/app/javascript/mastodon/locales/fr-CA.json +++ b/app/javascript/mastodon/locales/fr-CA.json @@ -35,9 +35,7 @@ "account.follow_back": "S'abonner en retour", "account.followers": "abonné·e·s", "account.followers.empty": "Personne ne suit ce compte pour l'instant.", - "account.followers_counter": "{count, plural, one {{counter} Abonné·e} other {{counter} Abonné·e·s}}", "account.following": "Abonné·e", - "account.following_counter": "{count, plural, one {{counter} Abonnement} other {{counter} Abonnements}}", "account.follows.empty": "Ce compte ne suit personne présentement.", "account.go_to_profile": "Voir ce profil", "account.hide_reblogs": "Masquer les boosts de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} a demandé à vous suivre", "account.share": "Partager le profil de @{name}", "account.show_reblogs": "Afficher les boosts de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Publication} other {{counter} Publications}}", "account.unblock": "Débloquer @{name}", "account.unblock_domain": "Débloquer le domaine {domain}", "account.unblock_short": "Débloquer", diff --git a/app/javascript/mastodon/locales/fr.json b/app/javascript/mastodon/locales/fr.json index 2e565c200f..cd67cda539 100644 --- a/app/javascript/mastodon/locales/fr.json +++ b/app/javascript/mastodon/locales/fr.json @@ -35,9 +35,7 @@ "account.follow_back": "S'abonner en retour", "account.followers": "Abonné·e·s", "account.followers.empty": "Personne ne suit cet·te utilisateur·rice pour l’instant.", - "account.followers_counter": "{count, plural, one {{counter} Abonné·e} other {{counter} Abonné·e·s}}", "account.following": "Abonnements", - "account.following_counter": "{count, plural, one {{counter} Abonnement} other {{counter} Abonnements}}", "account.follows.empty": "Cet·te utilisateur·rice ne suit personne pour l’instant.", "account.go_to_profile": "Aller au profil", "account.hide_reblogs": "Masquer les partages de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} a demandé à vous suivre", "account.share": "Partager le profil de @{name}", "account.show_reblogs": "Afficher les partages de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Message} other {{counter} Messages}}", "account.unblock": "Débloquer @{name}", "account.unblock_domain": "Débloquer le domaine {domain}", "account.unblock_short": "Débloquer", diff --git a/app/javascript/mastodon/locales/fy.json b/app/javascript/mastodon/locales/fy.json index 11b11ff819..d787c16bf3 100644 --- a/app/javascript/mastodon/locales/fy.json +++ b/app/javascript/mastodon/locales/fy.json @@ -35,9 +35,7 @@ "account.follow_back": "Weromfolgje", "account.followers": "Folgers", "account.followers.empty": "Noch net ien folget dizze brûker.", - "account.followers_counter": "{count, plural, one {{counter} folger} other {{counter} folgers}}", "account.following": "Folgjend", - "account.following_counter": "{count, plural, one {{counter} folgjend} other {{counter} folgjend}}", "account.follows.empty": "Dizze brûker folget noch net ien.", "account.go_to_profile": "Gean nei profyl", "account.hide_reblogs": "Boosts fan @{name} ferstopje", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} hat dy in folchfersyk stjoerd", "account.share": "Profyl fan @{name} diele", "account.show_reblogs": "Boosts fan @{name} toane", - "account.statuses_counter": "{count, plural, one {{counter} berjocht} other {{counter} berjochten}}", "account.unblock": "@{name} deblokkearje", "account.unblock_domain": "Domein {domain} deblokkearje", "account.unblock_short": "Deblokkearje", diff --git a/app/javascript/mastodon/locales/ga.json b/app/javascript/mastodon/locales/ga.json index 97dcc752b8..edf7618148 100644 --- a/app/javascript/mastodon/locales/ga.json +++ b/app/javascript/mastodon/locales/ga.json @@ -31,9 +31,7 @@ "account.follow": "Lean", "account.followers": "Leantóirí", "account.followers.empty": "Ní leanann éinne an t-úsáideoir seo fós.", - "account.followers_counter": "{count, plural, one {Leantóir amháin} other {{counter} Leantóir}}", "account.following": "Ag leanúint", - "account.following_counter": "{count, plural, one {Ag leanúint cúntas amháin} other {Ag leanúint {counter} cúntas}}", "account.follows.empty": "Ní leanann an t-úsáideoir seo duine ar bith fós.", "account.go_to_profile": "Téigh go dtí próifíl", "account.hide_reblogs": "Folaigh moltaí ó @{name}", @@ -55,7 +53,6 @@ "account.requested_follow": "D'iarr {name} ort do chuntas a leanúint", "account.share": "Roinn próifíl @{name}", "account.show_reblogs": "Taispeáin moltaí ó @{name}", - "account.statuses_counter": "{count, plural, one {Postáil amháin} other {{counter} Postáil}}", "account.unblock": "Bain bac de @{name}", "account.unblock_domain": "Bain bac den ainm fearainn {domain}", "account.unblock_short": "Bain bac de", diff --git a/app/javascript/mastodon/locales/gd.json b/app/javascript/mastodon/locales/gd.json index 714fa6e364..fec025045c 100644 --- a/app/javascript/mastodon/locales/gd.json +++ b/app/javascript/mastodon/locales/gd.json @@ -35,9 +35,7 @@ "account.follow_back": "Lean air ais", "account.followers": "Luchd-leantainn", "account.followers.empty": "Chan eil neach sam bith a’ leantainn air a’ chleachdaiche seo fhathast.", - "account.followers_counter": "{count, plural, one {{counter} neach-leantainn} two {{counter} neach-leantainn} few {{counter} luchd-leantainn} other {{counter} luchd-leantainn}}", "account.following": "A’ leantainn", - "account.following_counter": "{count, plural, one {A’ leantainn {counter}} two {A’ leantainn {counter}} few {A’ leantainn {counter}} other {A’ leantainn {counter}}}", "account.follows.empty": "Chan eil an cleachdaiche seo a’ leantainn neach sam bith fhathast.", "account.go_to_profile": "Tadhail air a’ phròifil", "account.hide_reblogs": "Falaich na brosnachaidhean o @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "Dh’iarr {name} ’gad leantainn", "account.share": "Co-roinn a’ phròifil aig @{name}", "account.show_reblogs": "Seall na brosnachaidhean o @{name}", - "account.statuses_counter": "{count, plural, one {{counter} phost} two {{counter} phost} few {{counter} postaichean} other {{counter} post}}", "account.unblock": "Dì-bhac @{name}", "account.unblock_domain": "Dì-bhac an àrainn {domain}", "account.unblock_short": "Dì-bhac", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 7b77f98034..156fe3ee86 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -35,9 +35,7 @@ "account.follow_back": "Seguir tamén", "account.followers": "Seguidoras", "account.followers.empty": "Aínda ninguén segue esta usuaria.", - "account.followers_counter": "{count, plural, one {{counter} Seguidora} other {{counter} Seguidoras}}", "account.following": "Seguindo", - "account.following_counter": "{count, plural, one {{counter} Seguindo} other {{counter} Seguindo}}", "account.follows.empty": "Esta usuaria aínda non segue a ninguén.", "account.go_to_profile": "Ir ao perfil", "account.hide_reblogs": "Agochar promocións de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} solicitou seguirte", "account.share": "Compartir o perfil de @{name}", "account.show_reblogs": "Amosar compartidos de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Publicación} other {{counter} Publicacións}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Amosar {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/he.json b/app/javascript/mastodon/locales/he.json index 1c50ba8e1f..e022eac110 100644 --- a/app/javascript/mastodon/locales/he.json +++ b/app/javascript/mastodon/locales/he.json @@ -35,9 +35,7 @@ "account.follow_back": "לעקוב בחזרה", "account.followers": "עוקבים", "account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.", - "account.followers_counter": "{count, plural,one {עוקב אחד} other {{counter} עוקבים}}", "account.following": "נעקבים", - "account.following_counter": "{count, plural,one {עוקב אחרי {counter}}other {עוקב אחרי {counter}}}", "account.follows.empty": "משתמש זה עדיין לא עוקב אחרי אף אחד.", "account.go_to_profile": "מעבר לפרופיל", "account.hide_reblogs": "להסתיר הידהודים מאת @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} ביקשו לעקוב אחריך", "account.share": "שתף את הפרופיל של @{name}", "account.show_reblogs": "הצג הדהודים מאת @{name}", - "account.statuses_counter": "{count, plural, one {הודעה} two {הודעותיים} many {{count} הודעות} other {{count} הודעות}}", "account.unblock": "להסיר חסימה ל- @{name}", "account.unblock_domain": "הסירי את החסימה של קהילת {domain}", "account.unblock_short": "הסר חסימה", diff --git a/app/javascript/mastodon/locales/hi.json b/app/javascript/mastodon/locales/hi.json index a2da55da85..89c71207f0 100644 --- a/app/javascript/mastodon/locales/hi.json +++ b/app/javascript/mastodon/locales/hi.json @@ -35,9 +35,7 @@ "account.follow_back": "फॉलो करें", "account.followers": "फॉलोवर", "account.followers.empty": "कोई भी इस यूज़र् को फ़ॉलो नहीं करता है", - "account.followers_counter": "{count, plural, one {{counter} अनुगामी} other {{counter} समर्थक}}", "account.following": "फॉलोइंग", - "account.following_counter": "{count, plural, one {{counter} निम्नलिखित} other {{counter} निम्नलिखित}}", "account.follows.empty": "यह यूज़र् अभी तक किसी को फॉलो नहीं करता है।", "account.go_to_profile": "प्रोफाइल में जाएँ", "account.hide_reblogs": "@{name} के बूस्ट छुपाएं", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} ने आपको फॉलो करने के लिए अनुरोध किया है", "account.share": "@{name} की प्रोफाइल शेयर करे", "account.show_reblogs": "@{name} के बूस्ट दिखाए", - "account.statuses_counter": "{count, plural, one {{counter} भोंपू} other {{counter} भोंपू}}", "account.unblock": "@{name} को अनब्लॉक करें", "account.unblock_domain": "{domain} दिखाए", "account.unblock_short": "अनब्लॉक", diff --git a/app/javascript/mastodon/locales/hr.json b/app/javascript/mastodon/locales/hr.json index d952945c46..c8f6f01862 100644 --- a/app/javascript/mastodon/locales/hr.json +++ b/app/javascript/mastodon/locales/hr.json @@ -35,9 +35,7 @@ "account.follow_back": "Slijedi natrag", "account.followers": "Pratitelji", "account.followers.empty": "Nitko još ne prati korisnika/cu.", - "account.followers_counter": "{count, plural, one {{counter} pratitelj} other {{counter} pratitelja}}", "account.following": "Pratim", - "account.following_counter": "{count, plural, one {{counter} praćeni} few{{counter} praćena} other {{counter} praćenih}}", "account.follows.empty": "Korisnik/ca još ne prati nikoga.", "account.go_to_profile": "Idi na profil", "account.hide_reblogs": "Sakrij boostove od @{name}", @@ -62,7 +60,6 @@ "account.requested_follow": "{name} zatražio/la je praćenje", "account.share": "Podijeli profil @{name}", "account.show_reblogs": "Prikaži boostove od @{name}", - "account.statuses_counter": "{count, plural, one {{counter} toot} other {{counter} toota}}", "account.unblock": "Deblokiraj @{name}", "account.unblock_domain": "Deblokiraj domenu {domain}", "account.unblock_short": "Deblokiraj", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 6164335da8..627e3cab50 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -35,9 +35,7 @@ "account.follow_back": "Viszontkövetés", "account.followers": "Követő", "account.followers.empty": "Ezt a felhasználót még senki sem követi.", - "account.followers_counter": "{count, plural, one {{counter} Követő} other {{counter} Követő}}", "account.following": "Követve", - "account.following_counter": "{count, plural, one {{counter} Követett} other {{counter} Követett}}", "account.follows.empty": "Ez a felhasználó még senkit sem követ.", "account.go_to_profile": "Ugrás a profilhoz", "account.hide_reblogs": "@{name} megtolásainak elrejtése", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} kérte, hogy követhessen", "account.share": "@{name} profiljának megosztása", "account.show_reblogs": "@{name} megtolásainak mutatása", - "account.statuses_counter": "{count, plural, one {{counter} Bejegyzés} other {{counter} Bejegyzés}}", "account.unblock": "@{name} letiltásának feloldása", "account.unblock_domain": "{domain} domain tiltásának feloldása", "account.unblock_short": "Tiltás feloldása", diff --git a/app/javascript/mastodon/locales/hy.json b/app/javascript/mastodon/locales/hy.json index cd29f441df..b4abe9bf09 100644 --- a/app/javascript/mastodon/locales/hy.json +++ b/app/javascript/mastodon/locales/hy.json @@ -28,9 +28,7 @@ "account.follow": "Հետեւել", "account.followers": "Հետեւողներ", "account.followers.empty": "Այս օգտատիրոջը դեռ ոչ մէկ չի հետեւում։", - "account.followers_counter": "{count, plural, one {{counter} Հետեւորդ} other {{counter} Հետեւորդ}}", "account.following": "Հետեւած", - "account.following_counter": "{count, plural, one {{counter} Հետեւած} other {{counter} Հետեւած}}", "account.follows.empty": "Այս օգտատէրը դեռ ոչ մէկի չի հետեւում։", "account.go_to_profile": "Գնալ անձնական հաշիւ", "account.hide_reblogs": "Թաքցնել @{name}֊ի տարածածները", @@ -52,7 +50,6 @@ "account.requested_follow": "{name}-ը ցանկանում է հետեւել քեզ", "account.share": "Կիսուել @{name}֊ի էջով", "account.show_reblogs": "Ցուցադրել @{name}֊ի տարածածները", - "account.statuses_counter": "{count, plural, one {{counter} Գրառում} other {{counter} Գրառումներ}}", "account.unblock": "Ապաարգելափակել @{name}֊ին", "account.unblock_domain": "Ցուցադրել {domain} թաքցուած տիրոյթի գրառումները", "account.unblock_short": "Արգելաբացել", diff --git a/app/javascript/mastodon/locales/ia.json b/app/javascript/mastodon/locales/ia.json index 53cc938592..a2e64c10f1 100644 --- a/app/javascript/mastodon/locales/ia.json +++ b/app/javascript/mastodon/locales/ia.json @@ -699,6 +699,7 @@ "server_banner.is_one_of_many": "{domain} es un de multe servitores independente de Mastodon que tu pote usar pro participar in le fediverso.", "server_banner.server_stats": "Statos del servitor:", "sign_in_banner.create_account": "Crear un conto", + "sign_in_banner.follow_anyone": "Seque quicunque in le fediverso, e tu videra toto in ordine chronologic. Sin algorithmo, sin publicitate, sin titulos de esca.", "sign_in_banner.mastodon_is": "Mastodon es le melior maniera de sequer lo que passa.", "sign_in_banner.sign_in": "Aperir session", "sign_in_banner.sso_redirect": "Aperir session o crear conto", diff --git a/app/javascript/mastodon/locales/id.json b/app/javascript/mastodon/locales/id.json index d86b5854f4..f4e5e1baea 100644 --- a/app/javascript/mastodon/locales/id.json +++ b/app/javascript/mastodon/locales/id.json @@ -35,9 +35,7 @@ "account.follow_back": "Ikuti balik", "account.followers": "Pengikut", "account.followers.empty": "Pengguna ini belum ada pengikut.", - "account.followers_counter": "{count, plural, other {{counter} Pengikut}}", "account.following": "Mengikuti", - "account.following_counter": "{count, plural, other {{counter} Mengikuti}}", "account.follows.empty": "Pengguna ini belum mengikuti siapa pun.", "account.go_to_profile": "Buka profil", "account.hide_reblogs": "Sembunyikan boosts dari @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} ingin mengikuti Anda", "account.share": "Bagikan profil @{name}", "account.show_reblogs": "Tampilkan boost dari @{name}", - "account.statuses_counter": "{count, plural, other {{counter} Kiriman}}", "account.unblock": "Buka blokir @{name}", "account.unblock_domain": "Buka blokir domain {domain}", "account.unblock_short": "Buka blokir", diff --git a/app/javascript/mastodon/locales/ie.json b/app/javascript/mastodon/locales/ie.json index f15b982889..c75788c430 100644 --- a/app/javascript/mastodon/locales/ie.json +++ b/app/javascript/mastodon/locales/ie.json @@ -35,9 +35,7 @@ "account.follow_back": "Sequer reciprocmen", "account.followers": "Sequitores", "account.followers.empty": "Ancor nequi seque ti-ci usator.", - "account.followers_counter": "{count, plural, one {{counter} Sequitor} other {{counter} Sequitor}}", "account.following": "Sequent", - "account.following_counter": "{count, plural, one {{counter} Sequent} other {{counter} Sequent}}", "account.follows.empty": "Ti-ci usator ancor ne seque quemcunc.", "account.go_to_profile": "Ear a profil", "account.hide_reblogs": "Celar boosts de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} ha petit sequer te", "account.share": "Distribuer li profil de @{name}", "account.show_reblogs": "Monstrar boosts de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Posta} other {{counter} Postas}}", "account.unblock": "Desbloccar @{name}", "account.unblock_domain": "Desbloccar dominia {domain}", "account.unblock_short": "Desbloccar", diff --git a/app/javascript/mastodon/locales/io.json b/app/javascript/mastodon/locales/io.json index 016a111c46..6aa954ae57 100644 --- a/app/javascript/mastodon/locales/io.json +++ b/app/javascript/mastodon/locales/io.json @@ -33,9 +33,7 @@ "account.follow": "Sequar", "account.followers": "Sequanti", "account.followers.empty": "Nulu sequas ca uzanto til nun.", - "account.followers_counter": "{count, plural, one {{counter} Sequanto} other {{counter} Sequanti}}", "account.following": "Sequata", - "account.following_counter": "{count, plural, one {{counter} Sequas} other {{counter} Sequanti}}", "account.follows.empty": "Ca uzanto ne sequa irgu til nun.", "account.go_to_profile": "Irez al profilo", "account.hide_reblogs": "Celez repeti de @{name}", @@ -60,7 +58,6 @@ "account.requested_follow": "{name} demandis sequar tu", "account.share": "Partigez profilo di @{name}", "account.show_reblogs": "Montrez repeti de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Posto} other {{counter} Posti}}", "account.unblock": "Desblokusar @{name}", "account.unblock_domain": "Desblokusar {domain}", "account.unblock_short": "Desblokusar", diff --git a/app/javascript/mastodon/locales/is.json b/app/javascript/mastodon/locales/is.json index 08605f5238..1a38591b85 100644 --- a/app/javascript/mastodon/locales/is.json +++ b/app/javascript/mastodon/locales/is.json @@ -63,7 +63,7 @@ "account.requested_follow": "{name} hefur beðið um að fylgjast með þér", "account.share": "Deila notandasniði fyrir @{name}", "account.show_reblogs": "Sýna endurbirtingar frá @{name}", - "account.statuses_counter": "{count, plural, one {Færsla: {counter}} other {Færslur: {counter}}}", + "account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}", "account.unblock": "Aflétta útilokun af @{name}", "account.unblock_domain": "Aflétta útilokun lénsins {domain}", "account.unblock_short": "Hætta að loka á", diff --git a/app/javascript/mastodon/locales/it.json b/app/javascript/mastodon/locales/it.json index 3672b5fd7a..73c4f9ba60 100644 --- a/app/javascript/mastodon/locales/it.json +++ b/app/javascript/mastodon/locales/it.json @@ -35,9 +35,9 @@ "account.follow_back": "Segui a tua volta", "account.followers": "Follower", "account.followers.empty": "Ancora nessuno segue questo utente.", - "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Follower}}", + "account.followers_counter": "{count, plural, one {{counter} seguace} other {{counter} seguaci}}", "account.following": "Seguiti", - "account.following_counter": "{count, plural, one {{counter} Seguiti} other {{counter} Seguiti}}", + "account.following_counter": "{count, plural, one {{counter} segui} other {{counter} segui}}", "account.follows.empty": "Questo utente non segue ancora nessuno.", "account.go_to_profile": "Vai al profilo", "account.hide_reblogs": "Nascondi potenziamenti da @{name}", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} ha richiesto di seguirti", "account.share": "Condividi il profilo di @{name}", "account.show_reblogs": "Mostra potenziamenti da @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Post}}", + "account.statuses_counter": "{count, plural, one {{counter} post} other {{counter} post}}", "account.unblock": "Sblocca @{name}", "account.unblock_domain": "Sblocca il dominio {domain}", "account.unblock_short": "Sblocca", diff --git a/app/javascript/mastodon/locales/ja.json b/app/javascript/mastodon/locales/ja.json index 90a46edd5b..575c68de03 100644 --- a/app/javascript/mastodon/locales/ja.json +++ b/app/javascript/mastodon/locales/ja.json @@ -35,9 +35,7 @@ "account.follow_back": "フォローバック", "account.followers": "フォロワー", "account.followers.empty": "まだ誰もフォローしていません。", - "account.followers_counter": "{counter} フォロワー", "account.following": "フォロー中", - "account.following_counter": "{counter} フォロー", "account.follows.empty": "まだ誰もフォローしていません。", "account.go_to_profile": "プロフィールページへ", "account.hide_reblogs": "@{name}さんからのブーストを非表示", @@ -63,7 +61,6 @@ "account.requested_follow": "{name}さんがあなたにフォローリクエストしました", "account.share": "@{name}さんのプロフィールを共有する", "account.show_reblogs": "@{name}さんからのブーストを表示", - "account.statuses_counter": "{counter} 投稿", "account.unblock": "@{name}さんのブロックを解除", "account.unblock_domain": "{domain}のブロックを解除", "account.unblock_short": "ブロック解除", diff --git a/app/javascript/mastodon/locales/ka.json b/app/javascript/mastodon/locales/ka.json index 7af4dccd86..b2e67e143e 100644 --- a/app/javascript/mastodon/locales/ka.json +++ b/app/javascript/mastodon/locales/ka.json @@ -26,7 +26,6 @@ "account.requested": "დამტკიცების მოლოდინში. დააწკაპუნეთ რომ უარყოთ დადევნების მოთხონვა", "account.share": "გააზიარე @{name}-ის პროფილი", "account.show_reblogs": "აჩვენე ბუსტები @{name}-სგან", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "განბლოკე @{name}", "account.unblock_domain": "გამოაჩინე {domain}", "account.unendorse": "არ გამოირჩეს პროფილზე", diff --git a/app/javascript/mastodon/locales/kab.json b/app/javascript/mastodon/locales/kab.json index 5aa46bafde..de866cc1bc 100644 --- a/app/javascript/mastodon/locales/kab.json +++ b/app/javascript/mastodon/locales/kab.json @@ -26,9 +26,7 @@ "account.follow": "Ḍfer", "account.followers": "Imeḍfaren", "account.followers.empty": "Ar tura, ulac yiwen i yeṭṭafaṛen amseqdac-agi.", - "account.followers_counter": "{count, plural, one {{count} n umeḍfar} other {{count} n imeḍfaren}}", "account.following": "Yeṭṭafaṛ", - "account.following_counter": "{count, plural, one {{counter} yettwaḍfaren} other {{counter} yettwaḍfaren}}", "account.follows.empty": "Ar tura, amseqdac-agi ur yeṭṭafaṛ yiwen.", "account.go_to_profile": "Ddu ɣer umaɣnu", "account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}", @@ -51,7 +49,6 @@ "account.requested_follow": "{name} yessuter ad k·m-yeḍfer", "account.share": "Bḍu amaɣnu n @{name}", "account.show_reblogs": "Ssken-d inebḍa n @{name}", - "account.statuses_counter": "{count, plural, one {{counter} n tsuffeɣt} other {{counter} n tsuffaɣ}}", "account.unblock": "Serreḥ i @{name}", "account.unblock_domain": "Ssken-d {domain}", "account.unblock_short": "Serreḥ", diff --git a/app/javascript/mastodon/locales/kk.json b/app/javascript/mastodon/locales/kk.json index bd0a806cdb..efeee16c65 100644 --- a/app/javascript/mastodon/locales/kk.json +++ b/app/javascript/mastodon/locales/kk.json @@ -31,9 +31,7 @@ "account.follow": "Жазылу", "account.followers": "Жазылушы", "account.followers.empty": "Бұл қолданушыға әлі ешкім жазылмаған.", - "account.followers_counter": "{count, plural, one {{counter} жазылушы} other {{counter} жазылушы}}", "account.following": "Жазылым", - "account.following_counter": "{count, plural, one {{counter} жазылым} other {{counter} жазылым}}", "account.follows.empty": "Бұл қолданушы әлі ешкімге жазылмаған.", "account.go_to_profile": "Профиліне өту", "account.hide_reblogs": "@{name} бустарын жасыру", @@ -52,7 +50,6 @@ "account.requested": "Растауын күтіңіз. Жазылудан бас тарту үшін басыңыз", "account.share": "@{name} профилін бөлісу\"", "account.show_reblogs": "@{name} бөліскендерін көрсету", - "account.statuses_counter": "{count, plural, one {{counter} Пост} other {{counter} Пост}}", "account.unblock": "Бұғаттан шығару @{name}", "account.unblock_domain": "Бұғаттан шығару {domain}", "account.unendorse": "Профильде рекомендемеу", diff --git a/app/javascript/mastodon/locales/kn.json b/app/javascript/mastodon/locales/kn.json index ceb0f8b9b6..24592e37fc 100644 --- a/app/javascript/mastodon/locales/kn.json +++ b/app/javascript/mastodon/locales/kn.json @@ -16,7 +16,6 @@ "account.posts": "ಟೂಟ್‌ಗಳು", "account.posts_with_replies": "Toots and replies", "account.requested": "Awaiting approval", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock_domain": "Unhide {domain}", "account_note.placeholder": "Click to add a note", "alert.unexpected.title": "ಅಯ್ಯೋ!", diff --git a/app/javascript/mastodon/locales/ko.json b/app/javascript/mastodon/locales/ko.json index c4c084d98e..90755666bb 100644 --- a/app/javascript/mastodon/locales/ko.json +++ b/app/javascript/mastodon/locales/ko.json @@ -35,9 +35,7 @@ "account.follow_back": "맞팔로우 하기", "account.followers": "팔로워", "account.followers.empty": "아직 아무도 이 사용자를 팔로우하고 있지 않습니다.", - "account.followers_counter": "{counter} 팔로워", "account.following": "팔로잉", - "account.following_counter": "{counter} 팔로잉", "account.follows.empty": "이 사용자는 아직 아무도 팔로우하고 있지 않습니다.", "account.go_to_profile": "프로필로 이동", "account.hide_reblogs": "@{name}의 부스트를 숨기기", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} 님이 팔로우 요청을 보냈습니다", "account.share": "@{name}의 프로필 공유", "account.show_reblogs": "@{name}의 부스트 보기", - "account.statuses_counter": "{counter} 게시물", "account.unblock": "차단 해제", "account.unblock_domain": "도메인 {domain} 차단 해제", "account.unblock_short": "차단 해제", diff --git a/app/javascript/mastodon/locales/ku.json b/app/javascript/mastodon/locales/ku.json index 83fcef26fb..5248cdfa51 100644 --- a/app/javascript/mastodon/locales/ku.json +++ b/app/javascript/mastodon/locales/ku.json @@ -32,9 +32,7 @@ "account.follow": "Bişopîne", "account.followers": "Şopîner", "account.followers.empty": "Kesekî hin ev bikarhêner neşopandiye.", - "account.followers_counter": "{count, plural, one {{counter} Şopîner} other {{counter} Şopîner}}", "account.following": "Dişopîne", - "account.following_counter": "{count, plural, one {{counter} Dişopîne} other {{counter} Dişopîne}}", "account.follows.empty": "Ev bikarhêner hin kesekî heya niha neşopandiye.", "account.go_to_profile": "Biçe bo profîlê", "account.hide_reblogs": "Bilindkirinên ji @{name} veşêre", @@ -56,7 +54,6 @@ "account.requested_follow": "{name} dixwaze te bişopîne", "account.share": "Profîla @{name} parve bike", "account.show_reblogs": "Bilindkirinên ji @{name} nîşan bike", - "account.statuses_counter": "{count, plural,one {{counter} Şandî}other {{counter} Şandî}}", "account.unblock": "Astengê li ser @{name} rake", "account.unblock_domain": "Astengê li ser navperê {domain} rake", "account.unblock_short": "Astengiyê rake", diff --git a/app/javascript/mastodon/locales/kw.json b/app/javascript/mastodon/locales/kw.json index 794cbd9ede..1afcf645cf 100644 --- a/app/javascript/mastodon/locales/kw.json +++ b/app/javascript/mastodon/locales/kw.json @@ -17,8 +17,6 @@ "account.follow": "Holya", "account.followers": "Holyoryon", "account.followers.empty": "Ny wra nagonan holya'n devnydhyer ma hwath.", - "account.followers_counter": "{count, plural, one {{counter} Holyer} other {{counter} Holyer}}", - "account.following_counter": "{count, plural, one {Ow holya {counter}} other {Ow holya {counter}}}", "account.follows.empty": "Ny wra'n devnydhyer ma holya nagonan hwath.", "account.hide_reblogs": "Kudha kenerthow a @{name}", "account.link_verified_on": "Perghenogeth an kolm ma a veu checkys dhe {date}", @@ -33,7 +31,6 @@ "account.requested": "Ow kortos komendyans. Klyckyewgh dhe hedhi govyn holya", "account.share": "Kevrenna profil @{name}", "account.show_reblogs": "Diskwedhes kenerthow a @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Tout} other {{counter} Tout}}", "account.unblock": "Anlettya @{name}", "account.unblock_domain": "Anlettya gorfarth {domain}", "account.unendorse": "Na wra diskwedhes yn profil", diff --git a/app/javascript/mastodon/locales/la.json b/app/javascript/mastodon/locales/la.json index d867034f01..aa209fcc00 100644 --- a/app/javascript/mastodon/locales/la.json +++ b/app/javascript/mastodon/locales/la.json @@ -14,12 +14,9 @@ "account.edit_profile": "Recolere notionem", "account.featured_tags.last_status_never": "Nulla contributa", "account.featured_tags.title": "Hashtag notātī {name}", - "account.followers_counter": "{count, plural, one {{counter} Sectator} other {{counter} Sectatores}}", - "account.following_counter": "{count, plural, one {{counter} Sequens} other {{counter} Sequentes}}", "account.moved_to": "{name} significavit eum suam rationem novam nunc esse:", "account.muted": "Confutatus", "account.requested_follow": "{name} postulavit ut te sequeretur", - "account.statuses_counter": "{count, plural, one {{counter} Nuntius} other {{counter} Nuntii}}", "account.unblock_short": "Solvere impedimentum", "account_note.placeholder": "Click to add a note", "admin.dashboard.retention.average": "Mediocritas", diff --git a/app/javascript/mastodon/locales/lad.json b/app/javascript/mastodon/locales/lad.json index bf676a6020..292f00818c 100644 --- a/app/javascript/mastodon/locales/lad.json +++ b/app/javascript/mastodon/locales/lad.json @@ -35,9 +35,7 @@ "account.follow_back": "Sige tamyen", "account.followers": "Suivantes", "account.followers.empty": "Por agora dingun no sige a este utilizador.", - "account.followers_counter": "{count, plural, one {{counter} suivante} other {{counter} suivantes}}", "account.following": "Sigiendo", - "account.following_counter": "{count, plural, other {Sigiendo a {counter}}}", "account.follows.empty": "Este utilizador ainda no sige a dingun.", "account.go_to_profile": "Va al profil", "account.hide_reblogs": "Eskonde repartajasyones de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} tiene solisitado segirte", "account.share": "Partaja el profil de @{name}", "account.show_reblogs": "Amostra repartajasyones de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}}", "account.unblock": "Dezbloka a @{name}", "account.unblock_domain": "Dezbloka domeno {domain}", "account.unblock_short": "Dezbloka", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index bb69b73399..6bf8f94bd9 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -35,9 +35,7 @@ "account.follow_back": "Sekti atgal", "account.followers": "Sekėjai", "account.followers.empty": "Šio naudotojo dar niekas neseka.", - "account.followers_counter": "{count, plural, one {{counter} sekėjas} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", "account.following": "Sekama", - "account.following_counter": "{count, plural, one {{counter} sekimas} few {{counter} sekimai} many {{counter} sekimo} other {{counter} sekimų}}", "account.follows.empty": "Šis naudotojas dar nieko neseka.", "account.go_to_profile": "Eiti į profilį", "account.hide_reblogs": "Slėpti pakėlimus iš @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} paprašė tave sekti", "account.share": "Bendrinti @{name} profilį", "account.show_reblogs": "Rodyti pakėlimus iš @{name}", - "account.statuses_counter": "{count, plural, one {{counter} įrašas} few {{counter} įrašai} many {{counter} įrašo} other {{counter} įrašų}}", "account.unblock": "Atblokuoti @{name}", "account.unblock_domain": "Atblokuoti domeną {domain}", "account.unblock_short": "Atblokuoti", diff --git a/app/javascript/mastodon/locales/lv.json b/app/javascript/mastodon/locales/lv.json index 13ceec21c8..041072c6ad 100644 --- a/app/javascript/mastodon/locales/lv.json +++ b/app/javascript/mastodon/locales/lv.json @@ -35,9 +35,7 @@ "account.follow_back": "Sekot atpakaļ", "account.followers": "Sekotāji", "account.followers.empty": "Šim lietotājam vēl nav sekotāju.", - "account.followers_counter": "{count, plural, zero {{counter} sekotāju} one {{counter} sekotājs} other {{counter} sekotāji}}", "account.following": "Seko", - "account.following_counter": "{count, plural, zero{{counter} sekojamo} one {{counter} sekojamais} other {{counter} sekojamie}}", "account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.", "account.go_to_profile": "Doties uz profilu", "account.hide_reblogs": "Paslēpt @{name} pastiprinātos ierakstus", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} nosūtīja Tev sekošanas pieprasījumu", "account.share": "Dalīties ar @{name} profilu", "account.show_reblogs": "Parādīt @{name} pastiprinātos ierakstus", - "account.statuses_counter": "{count, plural, zero {{counter} ierakstu} one {{counter} ieraksts} other {{counter} ieraksti}}", "account.unblock": "Atbloķēt @{name}", "account.unblock_domain": "Atbloķēt domēnu {domain}", "account.unblock_short": "Atbloķēt", diff --git a/app/javascript/mastodon/locales/mk.json b/app/javascript/mastodon/locales/mk.json index d8a470ed47..a09ad98ebf 100644 --- a/app/javascript/mastodon/locales/mk.json +++ b/app/javascript/mastodon/locales/mk.json @@ -38,7 +38,6 @@ "account.requested": "Се чека одобрување. Кликни за да одкажиш барање за следење", "account.share": "Сподели @{name} профил", "account.show_reblogs": "Прикажи бустови од @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "Одблокирај @{name}", "account.unblock_domain": "Прикажи {domain}", "account.unendorse": "Не прикажувај на профил", diff --git a/app/javascript/mastodon/locales/ml.json b/app/javascript/mastodon/locales/ml.json index 8fb4e818db..d9caccef34 100644 --- a/app/javascript/mastodon/locales/ml.json +++ b/app/javascript/mastodon/locales/ml.json @@ -22,9 +22,7 @@ "account.follow": "പിന്തുടരുക", "account.followers": "പിന്തുടരുന്നവർ", "account.followers.empty": "ഈ ഉപയോക്താവിനെ ആരും ഇതുവരെ പിന്തുടരുന്നില്ല.", - "account.followers_counter": "{count, plural, one {{counter} പിന്തുടരുന്നവർ} other {{counter} പിന്തുടരുന്നവർ}}", "account.following": "പിന്തുടരുന്നു", - "account.following_counter": "{count, plural, one {{counter} പിന്തുടരുന്നു} other {{counter} പിന്തുടരുന്നു}}", "account.follows.empty": "ഈ ഉപയോക്താവ് ആരേയും ഇതുവരെ പിന്തുടരുന്നില്ല.", "account.go_to_profile": "പ്രൊഫൈലിലേക്ക് പോകാം", "account.hide_reblogs": "@{name} ബൂസ്റ്റ് ചെയ്തവ മറയ്കുക", @@ -42,7 +40,6 @@ "account.requested": "അനുവാദത്തിനായി കാത്തിരിക്കുന്നു. പിന്തുടരാനുള്ള അപേക്ഷ റദ്ദാക്കുവാൻ ഞെക്കുക", "account.share": "@{name} ന്റെ പ്രൊഫൈൽ പങ്കിടുക", "account.show_reblogs": "@{name} ൽ നിന്നുള്ള ബൂസ്റ്റുകൾ കാണിക്കുക", - "account.statuses_counter": "{count, plural, one {{counter} ടൂട്ട്} other {{counter} ടൂട്ടുകൾ}}", "account.unblock": "@{name} തടഞ്ഞത് മാറ്റുക", "account.unblock_domain": "{domain} എന്ന മേഖല വെളിപ്പെടുത്തുക", "account.unblock_short": "അൺബ്ലോക്കു ചെയ്യുക", diff --git a/app/javascript/mastodon/locales/mr.json b/app/javascript/mastodon/locales/mr.json index c07294d90a..2757b96f94 100644 --- a/app/javascript/mastodon/locales/mr.json +++ b/app/javascript/mastodon/locales/mr.json @@ -35,9 +35,7 @@ "account.follow_back": "आपणही अनुसरण करा", "account.followers": "अनुयायी", "account.followers.empty": "ह्या वापरकर्त्याचा आतापर्यंत कोणी अनुयायी नाही.", - "account.followers_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.following": "अनुसरण", - "account.following_counter": "{count, plural, one {{counter} following} other {{counter} following}}", "account.follows.empty": "हा वापरकर्ता अजूनपर्यंत कोणाचा अनुयायी नाही.", "account.go_to_profile": "प्रोफाइल वर जा", "account.hide_reblogs": "@{name} पासून सर्व बूस्ट लपवा", @@ -59,7 +57,6 @@ "account.requested_follow": "{name} ने आपल्याला फॉलो करण्याची रिक्वेस्ट केली आहे", "account.share": "@{name} चे प्रोफाइल शेअर करा", "account.show_reblogs": "{name}चे सर्व बुस्ट्स दाखवा", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "@{name} ला ब्लॉक करा", "account.unblock_domain": "उघड करा {domain}", "account.unblock_short": "अनब्लॉक करा", diff --git a/app/javascript/mastodon/locales/ms.json b/app/javascript/mastodon/locales/ms.json index 3d7992faf7..88c093bdee 100644 --- a/app/javascript/mastodon/locales/ms.json +++ b/app/javascript/mastodon/locales/ms.json @@ -35,9 +35,7 @@ "account.follow_back": "Ikut balik", "account.followers": "Pengikut", "account.followers.empty": "Belum ada yang mengikuti pengguna ini.", - "account.followers_counter": "{count, plural, one {{counter} Pengikut} other {{counter} Pengikut}}", "account.following": "Mengikuti", - "account.following_counter": "{count, plural, one {{counter} Diikuti} other {{counter} Diikuti}}", "account.follows.empty": "Pengguna ini belum mengikuti sesiapa.", "account.go_to_profile": "Pergi ke profil", "account.hide_reblogs": "Sembunyikan galakan daripada @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} has requested to follow you", "account.share": "Kongsi profil @{name}", "account.show_reblogs": "Tunjukkan galakan daripada @{name}", - "account.statuses_counter": "{count, plural, other {{counter} kiriman}}", "account.unblock": "Nyahsekat @{name}", "account.unblock_domain": "Nyahsekat domain {domain}", "account.unblock_short": "Nyahsekat", diff --git a/app/javascript/mastodon/locales/my.json b/app/javascript/mastodon/locales/my.json index e3287f3f32..46c8d18069 100644 --- a/app/javascript/mastodon/locales/my.json +++ b/app/javascript/mastodon/locales/my.json @@ -34,9 +34,7 @@ "account.follow": "စောင့်ကြည့်", "account.followers": "စောင့်ကြည့်သူများ", "account.followers.empty": "ဤသူကို စောင့်ကြည့်သူ မရှိသေးပါ။", - "account.followers_counter": "{count, plural, one {စောင့်ကြည့်သူ {counter}} other {စောင့်ကြည့်သူများ {counter}}}", "account.following": "စောင့်ကြည့်နေသည်", - "account.following_counter": "{count, plural, one {စောင့်ကြည့်ထားသူ {counter}} other {စောင့်ကြည့်ထားသူများ {counter}}}", "account.follows.empty": "ဤသူသည် မည်သူ့ကိုမျှ စောင့်ကြည့်ခြင်း မရှိသေးပါ။", "account.go_to_profile": "ပရိုဖိုင်းသို့ သွားရန်", "account.hide_reblogs": "@{name} ၏ မျှဝေမှုကို ဝှက်ထားရန်", @@ -61,7 +59,6 @@ "account.requested_follow": "{name} က သင့်ကို စောင့်ကြည့်ရန် တောင်းဆိုထားသည်", "account.share": "{name}၏ပရိုဖိုင်ကိုမျှဝေပါ", "account.show_reblogs": "@{name} မှ မျှ၀ေမှုများကို ပြပါ\n", - "account.statuses_counter": "{count, plural, one {{counter} ပိုစ့်များ} other {{counter} ပိုစ့်များ}}", "account.unblock": "{name} ကို ဘလော့ဖြုတ်မည်", "account.unblock_domain": " {domain} ဒိုမိန်းကိုပြန်ဖွင့်မည်", "account.unblock_short": "ဘလော့ဖြုတ်ရန်", diff --git a/app/javascript/mastodon/locales/ne.json b/app/javascript/mastodon/locales/ne.json index 500261a34b..ca23a1f781 100644 --- a/app/javascript/mastodon/locales/ne.json +++ b/app/javascript/mastodon/locales/ne.json @@ -39,7 +39,6 @@ "account.requested_follow": "{name} ले तपाईंलाई फलो गर्न अनुरोध गर्नुभएको छ", "account.share": "@{name} को प्रोफाइल सेयर गर्नुहोस्", "account.show_reblogs": "@{name} को बूस्टहरू देखाउनुहोस्", - "account.statuses_counter": "{count, plural, one {{counter} पोस्ट} other {{counter} पोस्टहरू}}", "account.unblock": "@{name} लाई अनब्लक गर्नुहोस्", "account.unblock_domain": "{domain} डोमेनलाई अनब्लक गर्नुहोस्", "account.unblock_short": "अनब्लक गर्नुहोस्", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 93b44f29a1..7eca296595 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -35,9 +35,7 @@ "account.follow_back": "Fylg tilbake", "account.followers": "Fylgjarar", "account.followers.empty": "Ingen fylgjer denne brukaren enno.", - "account.followers_counter": "{count, plural, one {{counter} fylgjar} other {{counter} fylgjarar}}", "account.following": "Fylgjer", - "account.following_counter": "{count, plural, one {Fylgjer {counter}} other {Fylgjer {counter}}}", "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", "account.go_to_profile": "Gå til profil", "account.hide_reblogs": "Gøym framhevingar frå @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} har bedt om å få fylgja deg", "account.share": "Del @{name} sin profil", "account.show_reblogs": "Vis framhevingar frå @{name}", - "account.statuses_counter": "{count, plural, one {{counter} tut} other {{counter} tut}}", "account.unblock": "Stopp blokkering av @{name}", "account.unblock_domain": "Stopp blokkering av domenet {domain}", "account.unblock_short": "Stopp blokkering", diff --git a/app/javascript/mastodon/locales/no.json b/app/javascript/mastodon/locales/no.json index 213ba8af12..2bda373404 100644 --- a/app/javascript/mastodon/locales/no.json +++ b/app/javascript/mastodon/locales/no.json @@ -35,9 +35,7 @@ "account.follow_back": "Følg tilbake", "account.followers": "Følgere", "account.followers.empty": "Ingen følger denne brukeren ennå.", - "account.followers_counter": "{count, plural, one {{counter} følger} other {{counter} følgere}}", "account.following": "Følger", - "account.following_counter": "{count, plural, one {{counter} som følges} other {{counter} som følges}}", "account.follows.empty": "Denne brukeren følger ikke noen enda.", "account.go_to_profile": "Gå til profil", "account.hide_reblogs": "Skjul fremhevinger fra @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} har bedt om å få følge deg", "account.share": "Del @{name} sin profil", "account.show_reblogs": "Vis fremhevinger fra @{name}", - "account.statuses_counter": "{count, plural, one {{counter} innlegg} other {{counter} innlegg}}", "account.unblock": "Opphev blokkering av @{name}", "account.unblock_domain": "Opphev blokkering av {domain}", "account.unblock_short": "Opphev blokkering", diff --git a/app/javascript/mastodon/locales/oc.json b/app/javascript/mastodon/locales/oc.json index d8e1141588..d977eed4af 100644 --- a/app/javascript/mastodon/locales/oc.json +++ b/app/javascript/mastodon/locales/oc.json @@ -32,9 +32,7 @@ "account.follow_back": "Sègre en retorn", "account.followers": "Seguidors", "account.followers.empty": "Degun sèc pas aqueste utilizaire pel moment.", - "account.followers_counter": "{count, plural, one {{counter} Seguidor} other {{counter} Seguidors}}", "account.following": "Abonat", - "account.following_counter": "{count, plural, one {{counter} Abonaments} other {{counter} Abonaments}}", "account.follows.empty": "Aqueste utilizaire sèc pas degun pel moment.", "account.go_to_profile": "Anar al perfil", "account.hide_reblogs": "Rescondre los partatges de @{name}", @@ -60,7 +58,6 @@ "account.requested_follow": "{name} a demandat a vos sègre", "account.share": "Partejar lo perfil a @{name}", "account.show_reblogs": "Mostrar los partatges de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Tut} other {{counter} Tuts}}", "account.unblock": "Desblocar @{name}", "account.unblock_domain": "Desblocar {domain}", "account.unblock_short": "Desblocat", diff --git a/app/javascript/mastodon/locales/pa.json b/app/javascript/mastodon/locales/pa.json index 46924d737d..3828ff887e 100644 --- a/app/javascript/mastodon/locales/pa.json +++ b/app/javascript/mastodon/locales/pa.json @@ -25,9 +25,7 @@ "account.follow_back": "ਵਾਪਸ ਫਾਲ਼ੋ ਕਰੋ", "account.followers": "ਫ਼ਾਲੋਅਰ", "account.followers.empty": "ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਾਲੇ ਕੋਈ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।", - "account.followers_counter": "{count, plural, one {{counter} ਫ਼ਾਲੋਅਰ} other {{counter} ਫ਼ਾਲੋਅਰ}}", "account.following": "ਫ਼ਾਲੋ ਕੀਤਾ", - "account.following_counter": "{count, plural, one {{counter} ਨੂੰ ਫ਼ਾਲੋ} other {{counter} ਨੂੰ ਫ਼ਾਲੋ}}", "account.follows.empty": "ਇਹ ਵਰਤੋਂਕਾਰ ਹਾਲੇ ਕਿਸੇ ਨੂੰ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।", "account.go_to_profile": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਜਾਓ", "account.media": "ਮੀਡੀਆ", @@ -41,7 +39,6 @@ "account.requested": "ਮਨਜ਼ੂਰੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ। ਫ਼ਾਲੋ ਬੇਨਤੀਆਂ ਨੂੰ ਰੱਦ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ", "account.requested_follow": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ", "account.share": "{name} ਦਾ ਪਰੋਫ਼ਾਇਲ ਸਾਂਝਾ ਕਰੋ", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "@{name} ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ", "account.unblock_domain": "{domain} ਡੋਮੇਨ ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ", "account.unblock_short": "ਪਾਬੰਦੀ ਹਟਾਓ", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index ddfe1d4fbc..a3690e734b 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -35,9 +35,7 @@ "account.follow_back": "Obserwuj wzajemnie", "account.followers": "Obserwujący", "account.followers.empty": "Nikt jeszcze nie obserwuje tego użytkownika.", - "account.followers_counter": "{count, plural, one {{counter} obserwujący} few {{counter} obserwujących} many {{counter} obserwujących} other {{counter} obserwujących}}", "account.following": "Obserwowani", - "account.following_counter": "{count, plural, one {{counter} obserwowany} few {{counter} obserwowanych} many {{counter} obserwowanych} other {{counter} obserwowanych}}", "account.follows.empty": "Ten użytkownik nie obserwuje jeszcze nikogo.", "account.go_to_profile": "Przejdź do profilu", "account.hide_reblogs": "Ukryj podbicia od @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} chce zaobserwować twój profil", "account.share": "Udostępnij profil @{name}", "account.show_reblogs": "Pokazuj podbicia od @{name}", - "account.statuses_counter": "{count, plural, one {{counter} wpis} few {{counter} wpisy} many {{counter} wpisów} other {{counter} wpisów}}", "account.unblock": "Odblokuj @{name}", "account.unblock_domain": "Odblokuj domenę {domain}", "account.unblock_short": "Odblokuj", diff --git a/app/javascript/mastodon/locales/pt-BR.json b/app/javascript/mastodon/locales/pt-BR.json index 4d3bd2d280..34d0ba36e6 100644 --- a/app/javascript/mastodon/locales/pt-BR.json +++ b/app/javascript/mastodon/locales/pt-BR.json @@ -35,9 +35,7 @@ "account.follow_back": "Seguir de volta", "account.followers": "Seguidores", "account.followers.empty": "Nada aqui.", - "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.following": "Seguindo", - "account.following_counter": "{count, plural, one {segue {counter}} other {segue {counter}}}", "account.follows.empty": "Nada aqui.", "account.go_to_profile": "Ir ao perfil", "account.hide_reblogs": "Ocultar boosts de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} quer te seguir", "account.share": "Compartilhar perfil de @{name}", "account.show_reblogs": "Mostrar boosts de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear domínio {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 9446d5ee25..41112c2ca4 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -35,9 +35,7 @@ "account.follow_back": "Seguir de volta", "account.followers": "Seguidores", "account.followers.empty": "Ainda ninguém segue este utilizador.", - "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.following": "A seguir", - "account.following_counter": "{count, plural, other {A seguir {counter}}}", "account.follows.empty": "Este utilizador ainda não segue ninguém.", "account.go_to_profile": "Ir para o perfil", "account.hide_reblogs": "Esconder partilhas de @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} pediu para segui-lo", "account.share": "Partilhar o perfil @{name}", "account.show_reblogs": "Mostrar partilhas de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear o domínio {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/ro.json b/app/javascript/mastodon/locales/ro.json index 3a2fab9056..35abf1b021 100644 --- a/app/javascript/mastodon/locales/ro.json +++ b/app/javascript/mastodon/locales/ro.json @@ -35,9 +35,7 @@ "account.follow_back": "Urmăreşte înapoi", "account.followers": "Urmăritori", "account.followers.empty": "Acest utilizator nu are încă urmăritori.", - "account.followers_counter": "{count, plural, one {Un abonat} few {{counter} abonați} other {{counter} de abonați}}", "account.following": "Urmăriți", - "account.following_counter": "{count, plural, one {Un abonament} few {{counter} abonamente} other {{counter} de abonamente}}", "account.follows.empty": "Momentan acest utilizator nu are niciun abonament.", "account.go_to_profile": "Mergi la profil", "account.hide_reblogs": "Ascunde distribuirile de la @{name}", @@ -62,7 +60,6 @@ "account.requested_follow": "{name} A cerut să vă urmărească", "account.share": "Distribuie profilul lui @{name}", "account.show_reblogs": "Afișează distribuirile de la @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "Deblochează pe @{name}", "account.unblock_domain": "Deblochează domeniul {domain}", "account.unblock_short": "Deblochează", diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 40ca848147..97a1f0b09c 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -35,9 +35,7 @@ "account.follow_back": "Подписаться в ответ", "account.followers": "Подписчики", "account.followers.empty": "На этого пользователя пока никто не подписан.", - "account.followers_counter": "{count, plural, one {{counter} подписчик} many {{counter} подписчиков} other {{counter} подписчика}}", "account.following": "Подписки", - "account.following_counter": "{count, plural, one {{counter} подписка} many {{counter} подписок} other {{counter} подписки}}", "account.follows.empty": "Этот пользователь пока ни на кого не подписался.", "account.go_to_profile": "Перейти к профилю", "account.hide_reblogs": "Скрыть продвижения от @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} отправил(а) вам запрос на подписку", "account.share": "Поделиться профилем @{name}", "account.show_reblogs": "Показывать продвижения от @{name}", - "account.statuses_counter": "{count, plural, one {{counter} пост} many {{counter} постов} other {{counter} поста}}", "account.unblock": "Разблокировать @{name}", "account.unblock_domain": "Разблокировать {domain}", "account.unblock_short": "Разблокировать", diff --git a/app/javascript/mastodon/locales/sa.json b/app/javascript/mastodon/locales/sa.json index 58654deb03..c3880a6b03 100644 --- a/app/javascript/mastodon/locales/sa.json +++ b/app/javascript/mastodon/locales/sa.json @@ -32,9 +32,7 @@ "account.follow": "अनुस्रियताम्", "account.followers": "अनुसर्तारः", "account.followers.empty": "नाऽनुसर्तारो वर्तन्ते", - "account.followers_counter": "{count, plural, one {{counter} अनुसर्ता} two {{counter} अनुसर्तारौ} other {{counter} अनुसर्तारः}}", "account.following": "अनुसरति", - "account.following_counter": "{count, plural, one {{counter} अनुसृतः} two {{counter} अनुसृतौ} other {{counter} अनुसृताः}}", "account.follows.empty": "न कोऽप्यनुसृतो वर्तते", "account.go_to_profile": "प्रोफायिलं गच्छ", "account.hide_reblogs": "@{name} मित्रस्य प्रकाशनानि छिद्यन्ताम्", @@ -56,7 +54,6 @@ "account.requested_follow": "{name} त्वामनुसर्तुमयाचीत्", "account.share": "@{name} मित्रस्य विवरणं विभाज्यताम्", "account.show_reblogs": "@{name} मित्रस्य प्रकाशनानि दृश्यन्ताम्", - "account.statuses_counter": "{count, plural, one {{counter} पत्रम्} two{{counter} पत्रे} other {{counter} पत्राणि}}", "account.unblock": "निषेधता नश्यताम् @{name}", "account.unblock_domain": "प्रदेशनिषेधता नश्यताम् {domain}", "account.unblock_short": "अनवरुन्धि", diff --git a/app/javascript/mastodon/locales/sc.json b/app/javascript/mastodon/locales/sc.json index a0b5b32711..8955573737 100644 --- a/app/javascript/mastodon/locales/sc.json +++ b/app/javascript/mastodon/locales/sc.json @@ -26,9 +26,7 @@ "account.follow": "Sighi", "account.followers": "Sighiduras", "account.followers.empty": "Nemos sighit ancora custa persone.", - "account.followers_counter": "{count, plural, one {{counter} sighidura} other {{counter} sighiduras}}", "account.following": "Sighende", - "account.following_counter": "{count, plural, one {Sighende a {counter}} other {Sighende a {counter}}}", "account.follows.empty": "Custa persone non sighit ancora a nemos.", "account.hide_reblogs": "Cua is cumpartziduras de @{name}", "account.in_memoriam": "In memoriam.", @@ -47,7 +45,6 @@ "account.requested_follow": "{name} at dimandadu de ti sighire", "account.share": "Cumpartzi su profilu de @{name}", "account.show_reblogs": "Ammustra is cumpartziduras de @{name}", - "account.statuses_counter": "{count, plural, one {{counter} publicatzione} other {{counter} publicatziones}}", "account.unblock": "Isbloca a @{name}", "account.unblock_domain": "Isbloca su domìniu {domain}", "account.unendorse": "Non cussiges in su profilu", diff --git a/app/javascript/mastodon/locales/sco.json b/app/javascript/mastodon/locales/sco.json index 53501a5937..397f63fed4 100644 --- a/app/javascript/mastodon/locales/sco.json +++ b/app/javascript/mastodon/locales/sco.json @@ -31,9 +31,7 @@ "account.follow": "Follae", "account.followers": "Follaers", "account.followers.empty": "Naebody follaes this uiser yit.", - "account.followers_counter": "{count, plural, one {{counter} Follaer} other {{counter} Follaers}}", "account.following": "Follaein", - "account.following_counter": "{count, plural, one {{counter} Follaein} other {{counter} Follaein}}", "account.follows.empty": "This uiser disnae follae oniebody yit.", "account.go_to_profile": "Gang tae profile", "account.hide_reblogs": "Dinnae shaw heezes fae @{name}", @@ -53,7 +51,6 @@ "account.requested": "Haudin fir approval. Chap tae cancel follae request", "account.share": "Share @{name}'s profile", "account.show_reblogs": "Shaw heezes frae @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Posts}}", "account.unblock": "Undingie @{name}", "account.unblock_domain": "Undingie domain {domain}", "account.unblock_short": "Undingie", diff --git a/app/javascript/mastodon/locales/si.json b/app/javascript/mastodon/locales/si.json index 22320daefc..fbfdfaa659 100644 --- a/app/javascript/mastodon/locales/si.json +++ b/app/javascript/mastodon/locales/si.json @@ -23,9 +23,7 @@ "account.follow": "අනුගමනය", "account.followers": "අනුගාමිකයින්", "account.followers.empty": "කිසිවෙක් අනුගමනය කර නැත.", - "account.followers_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}", "account.following": "අනුගමන", - "account.following_counter": "{count, plural, one {අනුගමන {counter}} other {අනුගමන {counter}}}", "account.follows.empty": "තවමත් කිසිවෙක් අනුගමනය නොකරයි.", "account.go_to_profile": "පැතිකඩට යන්න", "account.joined_short": "එක් වූ දිනය", @@ -39,7 +37,6 @@ "account.posts_with_replies": "ලිපි සහ පිළිතුරු", "account.report": "@{name} වාර්තා කරන්න", "account.share": "@{name} ගේ පැතිකඩ බෙදාගන්න", - "account.statuses_counter": "{count, plural, one {ලිපි {counter}} other {ලිපි {counter}}}", "account.unblock": "@{name} අනවහිර කරන්න", "account.unblock_domain": "{domain} වසම අනවහිර කරන්න", "account.unblock_short": "අනවහිර", diff --git a/app/javascript/mastodon/locales/sk.json b/app/javascript/mastodon/locales/sk.json index 4c152a2143..ed9c0de604 100644 --- a/app/javascript/mastodon/locales/sk.json +++ b/app/javascript/mastodon/locales/sk.json @@ -35,9 +35,7 @@ "account.follow_back": "Sledovať späť", "account.followers": "Sledovatelia", "account.followers.empty": "Tento účet ešte nikto nesleduje.", - "account.followers_counter": "{count, plural, one {{counter} sledujúci účet} few {{counter} sledujúce účty} many {{counter} sledujúcich účtov} other {{counter} sledujúcich účtov}}", "account.following": "Sledovaný účet", - "account.following_counter": "{count, plural, one {{counter} sledovaný účet} few {{counter} sledované účty} many {{counter} sledovaných účtov} other {{counter} sledovaných účtov}}", "account.follows.empty": "Tento účet ešte nikoho nesleduje.", "account.go_to_profile": "Prejsť na profil", "account.hide_reblogs": "Skryť zdieľania od @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} vás chce sledovať", "account.share": "Zdieľaj profil @{name}", "account.show_reblogs": "Zobrazovať zdieľania od @{name}", - "account.statuses_counter": "{count, plural, one {{counter} príspevok} few {{counter} príspevky} many {{counter} príspevkov} other {{counter} príspevkov}}", "account.unblock": "Odblokovať @{name}", "account.unblock_domain": "Odblokovať doménu {domain}", "account.unblock_short": "Odblokovať", diff --git a/app/javascript/mastodon/locales/sl.json b/app/javascript/mastodon/locales/sl.json index 195797143b..2a3d74a80f 100644 --- a/app/javascript/mastodon/locales/sl.json +++ b/app/javascript/mastodon/locales/sl.json @@ -35,9 +35,9 @@ "account.follow_back": "Sledi nazaj", "account.followers": "Sledilci", "account.followers.empty": "Nihče ne sledi temu uporabniku.", - "account.followers_counter": "{count, plural, one {ima {counter} sledilca} two {ima {counter} sledilca} few {ima {counter} sledilce} other {ima {counter} sledilcev}}", + "account.followers_counter": "{count, plural, one {{counter} sledilec} two {{counter} sledilca} few {{counter} sledilci} other {{counter} sledilcev}}", "account.following": "Sledim", - "account.following_counter": "{count, plural, one {sledi {count} osebi} two {sledi {count} osebama} few {sledi {count} osebam} other {sledi {count} osebam}}", + "account.following_counter": "{count, plural, one {{counter} sleden} two {{counter} sledena} few {{counter} sledeni} other {{counter} sledenih}}", "account.follows.empty": "Ta uporabnik še ne sledi nikomur.", "account.go_to_profile": "Pojdi na profil", "account.hide_reblogs": "Skrij izpostavitve od @{name}", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} vam želi slediti", "account.share": "Deli profil osebe @{name}", "account.show_reblogs": "Pokaži izpostavitve osebe @{name}", - "account.statuses_counter": "{count, plural, one {{count} objava} two {{count} objavi} few {{count} objave} other {{count} objav}}", + "account.statuses_counter": "{count, plural, one {{counter} objava} two {{counter} objavi} few {{counter} objave} other {{counter} objav}}", "account.unblock": "Odblokiraj @{name}", "account.unblock_domain": "Odblokiraj domeno {domain}", "account.unblock_short": "Odblokiraj", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 6903bceff6..6ac038c9f4 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -35,9 +35,7 @@ "account.follow_back": "Ndiqe gjithashtu", "account.followers": "Ndjekës", "account.followers.empty": "Këtë përdorues ende s’e ndjek kush.", - "account.followers_counter": "{count, plural, one {{counter} Ndjekës} other {{counter} Ndjekës}}", "account.following": "Ndjekje", - "account.following_counter": "{count, plural, one {{counter} i Ndjekur} other {{counter} të Ndjekur}}", "account.follows.empty": "Ky përdorues ende s’ndjek kënd.", "account.go_to_profile": "Kalo te profili", "account.hide_reblogs": "Fshih përforcime nga @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} ka kërkuar t’ju ndjekë", "account.share": "Ndajeni profilin e @{name} me të tjerët", "account.show_reblogs": "Shfaq përforcime nga @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Mesazh} other {{counter} Mesazhe}}", "account.unblock": "Zhbllokoje @{name}", "account.unblock_domain": "Zhblloko përkatësinë {domain}", "account.unblock_short": "Zhbllokoje", diff --git a/app/javascript/mastodon/locales/sr-Latn.json b/app/javascript/mastodon/locales/sr-Latn.json index 63b2e03c96..93c3b8fe2e 100644 --- a/app/javascript/mastodon/locales/sr-Latn.json +++ b/app/javascript/mastodon/locales/sr-Latn.json @@ -35,9 +35,7 @@ "account.follow_back": "Uzvrati praćenje", "account.followers": "Pratioci", "account.followers.empty": "Još uvek niko ne prati ovog korisnika.", - "account.followers_counter": "{count, plural, one {{counter} pratilac} few {{counter} pratioca} other {{counter} pratilaca}}", "account.following": "Prati", - "account.following_counter": "{count, plural, one {{counter} prati} few {{counter} prati} other {{counter} prati}}", "account.follows.empty": "Ovaj korisnik još uvek nikog ne prati.", "account.go_to_profile": "Idi na profil", "account.hide_reblogs": "Sakrij podržavanja @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} je zatražio da vas prati", "account.share": "Podeli profil korisnika @{name}", "account.show_reblogs": "Prikaži podržavanja od korisnika @{name}", - "account.statuses_counter": "{count, plural, one {{counter} objavio} few {{counter} objavio} other {{counter} objavio}}", "account.unblock": "Odblokiraj korisnika @{name}", "account.unblock_domain": "Odblokiraj domen {domain}", "account.unblock_short": "Odblokiraj", @@ -696,8 +693,11 @@ "server_banner.about_active_users": "Ljudi koji su koristili ovaj server u prethodnih 30 dana (mesečno aktivnih korisnika)", "server_banner.active_users": "aktivnih korisnika", "server_banner.administered_by": "Administrira:", + "server_banner.is_one_of_many": "{domain} je jedan od mnogih nezavisnih Mastodon servera koje možete koristiti za učešće u fediverzumu.", "server_banner.server_stats": "Statistike servera:", "sign_in_banner.create_account": "Napravite nalog", + "sign_in_banner.follow_anyone": "Pratite bilo koga širom fediverzuma i pogledajte sve hronološkim redom. Nema algoritama, reklama ili mamaca za klikove na vidiku.", + "sign_in_banner.mastodon_is": "Mastodon je najbolji način da budete u toku sa onim što se dešava.", "sign_in_banner.sign_in": "Prijavite se", "sign_in_banner.sso_redirect": "Prijavite se ili se registrujte", "status.admin_account": "Otvori moderatorsko okruženje za @{name}", diff --git a/app/javascript/mastodon/locales/sr.json b/app/javascript/mastodon/locales/sr.json index c6b969e982..0273002b37 100644 --- a/app/javascript/mastodon/locales/sr.json +++ b/app/javascript/mastodon/locales/sr.json @@ -35,9 +35,7 @@ "account.follow_back": "Узврати праћење", "account.followers": "Пратиоци", "account.followers.empty": "Још увек нико не прати овог корисника.", - "account.followers_counter": "{count, plural, one {{counter} пратилац} few {{counter} пратиоца} other {{counter} пратилаца}}", "account.following": "Прати", - "account.following_counter": "{count, plural, one {{counter} прати} few {{counter} прати} other {{counter} прати}}", "account.follows.empty": "Овај корисник још увек никог не прати.", "account.go_to_profile": "Иди на профил", "account.hide_reblogs": "Сакриј подржавања од @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} је затражио да вас прати", "account.share": "Подели профил корисника @{name}", "account.show_reblogs": "Прикажи подржавања од корисника @{name}", - "account.statuses_counter": "{count, plural, one {{counter} објавио} few {{counter} објавио} other {{counter} објавио}}", "account.unblock": "Одблокирај корисника @{name}", "account.unblock_domain": "Одблокирај домен {domain}", "account.unblock_short": "Одблокирај", @@ -696,8 +693,11 @@ "server_banner.about_active_users": "Људи који су користили овај сервер у претходних 30 дана (месечно активних корисника)", "server_banner.active_users": "активних корисника", "server_banner.administered_by": "Администрира:", + "server_banner.is_one_of_many": "{domain} је један од многих независних Mastodon сервера које можете користити за учешће у федиверзуму.", "server_banner.server_stats": "Статистике сервера:", "sign_in_banner.create_account": "Направите налог", + "sign_in_banner.follow_anyone": "Пратите било кога широм федиверзума и погледајте све хронолошким редом. Нема алгоритама, реклама или мамаца за кликове на видику.", + "sign_in_banner.mastodon_is": "Mastodon је најбољи начин да будете у току са оним што се дешава.", "sign_in_banner.sign_in": "Пријавите се", "sign_in_banner.sso_redirect": "Пријавите се или се региструјте", "status.admin_account": "Отвори модераторско окружење за @{name}", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index ced6c36054..7445b77bac 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -35,9 +35,7 @@ "account.follow_back": "Följ tillbaka", "account.followers": "Följare", "account.followers.empty": "Ingen följer denna användare än.", - "account.followers_counter": "{count, plural, one {{counter} följare} other {{counter} följare}}", "account.following": "Följer", - "account.following_counter": "{count, plural, one {{counter} följd} other {{counter} följda}}", "account.follows.empty": "Denna användare följer inte någon än.", "account.go_to_profile": "Gå till profilen", "account.hide_reblogs": "Dölj boostar från @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} har begärt att följa dig", "account.share": "Dela @{name}s profil", "account.show_reblogs": "Visa boostar från @{name}", - "account.statuses_counter": "{count, plural, one {{counter} inlägg} other {{counter} inlägg}}", "account.unblock": "Avblockera @{name}", "account.unblock_domain": "Avblockera {domain}", "account.unblock_short": "Avblockera", diff --git a/app/javascript/mastodon/locales/szl.json b/app/javascript/mastodon/locales/szl.json index 43cfc78d5b..34d086eb48 100644 --- a/app/javascript/mastodon/locales/szl.json +++ b/app/javascript/mastodon/locales/szl.json @@ -23,7 +23,6 @@ "account.posts": "Toots", "account.posts_with_replies": "Toots and replies", "account.requested": "Awaiting approval", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account_note.placeholder": "Click to add a note", "column.pins": "Pinned toot", "community.column_settings.media_only": "Media only", diff --git a/app/javascript/mastodon/locales/ta.json b/app/javascript/mastodon/locales/ta.json index ac0984293a..d44ac424f4 100644 --- a/app/javascript/mastodon/locales/ta.json +++ b/app/javascript/mastodon/locales/ta.json @@ -24,9 +24,7 @@ "account.follow_back": "பின்தொடரு", "account.followers": "பின்தொடர்பவர்கள்", "account.followers.empty": "இதுவரை யாரும் இந்த பயனரைப் பின்தொடரவில்லை.", - "account.followers_counter": "{count, plural, one {{counter} வாசகர்} other {{counter} வாசகர்கள்}}", "account.following": "பின்தொடரும்", - "account.following_counter": "{count, plural,one {{counter} சந்தா} other {{counter} சந்தாக்கள்}}", "account.follows.empty": "இந்த பயனர் இதுவரை யாரையும் பின்தொடரவில்லை.", "account.go_to_profile": "சுயவிவரத்திற்குச் செல்லவும்", "account.hide_reblogs": "இருந்து ஊக்கியாக மறை @{name}", @@ -45,7 +43,6 @@ "account.requested": "ஒப்புதலுக்காகக் காத்திருக்கிறது. பின்தொடரும் கோரிக்கையை நீக்க அழுத்தவும்", "account.share": "@{name} உடைய விவரத்தை பகிர்", "account.show_reblogs": "காட்டு boosts இருந்து @{name}", - "account.statuses_counter": "{count, plural, one {{counter} டூட்} other {{counter} டூட்டுகள்}}", "account.unblock": "@{name} மீது தடை நீக்குக", "account.unblock_domain": "{domain} ஐ காண்பி", "account.unblock_short": "தடையை நீக்கு", diff --git a/app/javascript/mastodon/locales/tai.json b/app/javascript/mastodon/locales/tai.json index 825cfb93bd..cad6e8eaa5 100644 --- a/app/javascript/mastodon/locales/tai.json +++ b/app/javascript/mastodon/locales/tai.json @@ -9,7 +9,6 @@ "account.posts": "Huah-siann", "account.posts_with_replies": "Huah-siann kah huê-ìng", "account.requested": "Tán-thāi phue-tsún", - "account.statuses_counter": "{count, plural, one {{counter} Huah-siann} other {{counter} Huah-siann}}", "account_note.placeholder": "Tiám tsi̍t-ē ka-thiam pī-tsù", "column.pins": "Tah thâu-tsîng ê huah-siann", "community.column_settings.media_only": "Kan-na muî-thé", diff --git a/app/javascript/mastodon/locales/te.json b/app/javascript/mastodon/locales/te.json index 284102c381..c06472561f 100644 --- a/app/javascript/mastodon/locales/te.json +++ b/app/javascript/mastodon/locales/te.json @@ -25,7 +25,6 @@ "account.requested": "ఆమోదం కోసం వేచి ఉంది. అభ్యర్థనను రద్దు చేయడానికి క్లిక్ చేయండి", "account.share": "@{name} యొక్క ప్రొఫైల్ను పంచుకోండి", "account.show_reblogs": "@{name}నుంచి బూస్ట్ లను చూపించు", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "@{name}పై బ్లాక్ ను తొలగించు", "account.unblock_domain": "{domain}ను దాచవద్దు", "account.unendorse": "ప్రొఫైల్లో చూపించవద్దు", diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json index 64abb394bf..e1d556ebf0 100644 --- a/app/javascript/mastodon/locales/th.json +++ b/app/javascript/mastodon/locales/th.json @@ -35,9 +35,7 @@ "account.follow_back": "ติดตามกลับ", "account.followers": "ผู้ติดตาม", "account.followers.empty": "ยังไม่มีใครติดตามผู้ใช้นี้", - "account.followers_counter": "{count, plural, other {{counter} ผู้ติดตาม}}", "account.following": "กำลังติดตาม", - "account.following_counter": "{count, plural, other {{counter} กำลังติดตาม}}", "account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร", "account.go_to_profile": "ไปยังโปรไฟล์", "account.hide_reblogs": "ซ่อนการดันจาก @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} ได้ขอติดตามคุณ", "account.share": "แชร์โปรไฟล์ของ @{name}", "account.show_reblogs": "แสดงการดันจาก @{name}", - "account.statuses_counter": "{count, plural, other {{counter} โพสต์}}", "account.unblock": "เลิกปิดกั้น @{name}", "account.unblock_domain": "เลิกปิดกั้นโดเมน {domain}", "account.unblock_short": "เลิกปิดกั้น", diff --git a/app/javascript/mastodon/locales/tr.json b/app/javascript/mastodon/locales/tr.json index 0bb2a0e4a6..ac39a3fd7b 100644 --- a/app/javascript/mastodon/locales/tr.json +++ b/app/javascript/mastodon/locales/tr.json @@ -35,9 +35,9 @@ "account.follow_back": "Geri takip et", "account.followers": "Takipçi", "account.followers.empty": "Henüz kimse bu kullanıcıyı takip etmiyor.", - "account.followers_counter": "{count, plural, one {{counter} Takipçi} other {{counter} Takipçi}}", + "account.followers_counter": "{count, plural, one {{counter} takipçi} other {{counter} takipçi}}", "account.following": "Takip Ediliyor", - "account.following_counter": "{count, plural, one {{counter} Takip Edilen} other {{counter} Takip Edilen}}", + "account.following_counter": "{count, plural, one {{counter} takip edilen} other {{counter} takip edilen}}", "account.follows.empty": "Bu kullanıcı henüz kimseyi takip etmiyor.", "account.go_to_profile": "Profile git", "account.hide_reblogs": "@{name} kişisinin boostlarını gizle", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} size takip isteği gönderdi", "account.share": "@{name} adlı kişinin profilini paylaş", "account.show_reblogs": "@{name} kişisinin yeniden paylaşımlarını göster", - "account.statuses_counter": "{count, plural, one {{counter} Gönderi} other {{counter} Gönderi}}", + "account.statuses_counter": "{count, plural, one {{counter} gönderi} other {{counter} gönderi}}", "account.unblock": "@{name} adlı kişinin engelini kaldır", "account.unblock_domain": "{domain} alan adının engelini kaldır", "account.unblock_short": "Engeli kaldır", diff --git a/app/javascript/mastodon/locales/tt.json b/app/javascript/mastodon/locales/tt.json index 273c1a6de7..baba3190dc 100644 --- a/app/javascript/mastodon/locales/tt.json +++ b/app/javascript/mastodon/locales/tt.json @@ -31,9 +31,7 @@ "account.follow": "Язылу", "account.followers": "Язылучы", "account.followers.empty": "Әле беркем дә язылмаган.", - "account.followers_counter": "{count, plural,one {{counter} язылучы} other {{counter} язылучы}}", "account.following": "Язылулар", - "account.following_counter": "{count, plural, one {{counter} язылу} other {{counter} язылу}}", "account.follows.empty": "Беркемгә дә язылмаган әле.", "account.go_to_profile": "Профильгә күчү", "account.hide_reblogs": "Скрывать көчен нче @{name}", @@ -55,7 +53,6 @@ "account.requested_follow": "{name} Сезгә язылу соравын җиберде", "account.share": "@{name} профиле белән уртаклашу", "account.show_reblogs": "Күрсәтергә көчәйтү нче @{name}", - "account.statuses_counter": "{count, plural, one {{counter} язма} other {{counter} язма}}", "account.unblock": "@{name} бикләвен чыгу", "account.unblock_domain": "{domain} бикләвен чыгу", "account.unblock_short": "Бикләүне чыгу", diff --git a/app/javascript/mastodon/locales/ug.json b/app/javascript/mastodon/locales/ug.json index 4120d4483b..e3dd0e6b11 100644 --- a/app/javascript/mastodon/locales/ug.json +++ b/app/javascript/mastodon/locales/ug.json @@ -6,7 +6,6 @@ "account.posts": "Toots", "account.posts_with_replies": "Toots and replies", "account.requested": "Awaiting approval", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account_note.placeholder": "Click to add a note", "column.pins": "Pinned toot", "community.column_settings.media_only": "Media only", diff --git a/app/javascript/mastodon/locales/uk.json b/app/javascript/mastodon/locales/uk.json index 22cd15bd23..338b650617 100644 --- a/app/javascript/mastodon/locales/uk.json +++ b/app/javascript/mastodon/locales/uk.json @@ -35,9 +35,7 @@ "account.follow_back": "Підписатися взаємно", "account.followers": "Підписники", "account.followers.empty": "Ніхто ще не підписаний на цього користувача.", - "account.followers_counter": "{count, plural, one {{counter} підписник} few {{counter} підписники} many {{counter} підписників} other {{counter} підписники}}", "account.following": "Ви стежите", - "account.following_counter": "{count, plural, one {{counter} підписка} few {{counter} підписки} many {{counter} підписок} other {{counter} підписки}}", "account.follows.empty": "Цей користувач ще ні на кого не підписався.", "account.go_to_profile": "Перейти до профілю", "account.hide_reblogs": "Сховати поширення від @{name}", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} надсилає запит на стеження", "account.share": "Поділитися профілем @{name}", "account.show_reblogs": "Показати поширення від @{name}", - "account.statuses_counter": "{count, plural, one {{counter} допис} few {{counter} дописи} many {{counter} дописів} other {{counter} дописи}}", "account.unblock": "Розблокувати @{name}", "account.unblock_domain": "Розблокувати {domain}", "account.unblock_short": "Розблокувати", diff --git a/app/javascript/mastodon/locales/ur.json b/app/javascript/mastodon/locales/ur.json index 1b9f8d9691..cf53eb6fe8 100644 --- a/app/javascript/mastodon/locales/ur.json +++ b/app/javascript/mastodon/locales/ur.json @@ -29,9 +29,7 @@ "account.follow_back": "اکاؤنٹ کو فالو بیک ", "account.followers": "پیروکار", "account.followers.empty": "ہنوز اس صارف کی کوئی پیروی نہیں کرتا.", - "account.followers_counter": "{count, plural,one {{counter} پیروکار} other {{counter} پیروکار}}", "account.following": "فالو کر رہے ہیں", - "account.following_counter": "{count, plural, one {{counter} پیروی کر رہے ہیں} other {{counter} پیروی کر رہے ہیں}}", "account.follows.empty": "\"یہ صارف ہنوز کسی کی پیروی نہیں کرتا ہے\".", "account.go_to_profile": "پروفائل پر جائیں", "account.hide_reblogs": "@{name} سے فروغ چھپائیں", @@ -57,7 +55,6 @@ "account.requested_follow": "{name} آپ کو فالو کرنا چھاتا ہے۔", "account.share": "@{name} کے مشخص کو بانٹیں", "account.show_reblogs": "@{name} کی افزائشات کو دکھائیں", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unblock": "@{name} کو بحال کریں", "account.unblock_domain": "{domain} کو نہ چھپائیں", "account.unblock_short": "بلاک ختم کریں", diff --git a/app/javascript/mastodon/locales/uz.json b/app/javascript/mastodon/locales/uz.json index 77892914a4..4824b1d332 100644 --- a/app/javascript/mastodon/locales/uz.json +++ b/app/javascript/mastodon/locales/uz.json @@ -31,9 +31,7 @@ "account.follow": "Obuna bo‘lish", "account.followers": "Obunachilar", "account.followers.empty": "Bu foydalanuvchini hali hech kim kuzatmaydi.", - "account.followers_counter": "{count, plural, one {{counter} Muxlis} other {{counter} Muxlislar}}", "account.following": "Kuzatish", - "account.following_counter": "{count, plural, one {{counter} ga Muxlis} other {{counter} larga muxlis}}", "account.follows.empty": "Bu foydalanuvchi hali hech kimni kuzatmagan.", "account.go_to_profile": "Profilga o'tish", "account.hide_reblogs": "@{name} dan boostlarni yashirish", @@ -54,7 +52,6 @@ "account.requested_follow": "{name} sizni kuzatishni soʻradi", "account.share": "@{name} profilini ulashing", "account.show_reblogs": "@{name} dan bootlarni ko'rsatish", - "account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Postlar}}", "account.unblock": "@{name} ni blokdan chiqarish", "account.unblock_domain": "{domain} domenini blokdan chiqarish", "account.unblock_short": "Blokdan chiqarish", diff --git a/app/javascript/mastodon/locales/vi.json b/app/javascript/mastodon/locales/vi.json index 18f0fec3c5..bbfecf2c8a 100644 --- a/app/javascript/mastodon/locales/vi.json +++ b/app/javascript/mastodon/locales/vi.json @@ -35,9 +35,7 @@ "account.follow_back": "Theo dõi lại", "account.followers": "Người theo dõi", "account.followers.empty": "Chưa có người theo dõi nào.", - "account.followers_counter": "{count, plural, one {{counter} Người theo dõi} other {{counter} Người theo dõi}}", "account.following": "Đang theo dõi", - "account.following_counter": "{count, plural, one {{counter} Theo dõi} other {{counter} Theo dõi}}", "account.follows.empty": "Người này chưa theo dõi ai.", "account.go_to_profile": "Xem hồ sơ", "account.hide_reblogs": "Ẩn tút @{name} đăng lại", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} yêu cầu theo dõi bạn", "account.share": "Chia sẻ @{name}", "account.show_reblogs": "Hiện tút do @{name} đăng lại", - "account.statuses_counter": "{count, plural, one {{counter} Tút} other {{counter} Tút}}", "account.unblock": "Bỏ chặn @{name}", "account.unblock_domain": "Bỏ ẩn {domain}", "account.unblock_short": "Bỏ chặn", diff --git a/app/javascript/mastodon/locales/zgh.json b/app/javascript/mastodon/locales/zgh.json index 1d3a22108c..b42bb7589c 100644 --- a/app/javascript/mastodon/locales/zgh.json +++ b/app/javascript/mastodon/locales/zgh.json @@ -19,7 +19,6 @@ "account.posts_with_replies": "Toots and replies", "account.requested": "Awaiting approval", "account.share": "ⴱⴹⵓ ⵉⴼⵔⵙ ⵏ @{name}", - "account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.unfollow": "ⴽⴽⵙ ⴰⴹⴼⴼⵓⵕ", "account_note.placeholder": "Click to add a note", "bundle_column_error.retry": "ⴰⵍⵙ ⴰⵔⵎ", diff --git a/app/javascript/mastodon/locales/zh-CN.json b/app/javascript/mastodon/locales/zh-CN.json index 3456f99d25..f2accae0d0 100644 --- a/app/javascript/mastodon/locales/zh-CN.json +++ b/app/javascript/mastodon/locales/zh-CN.json @@ -35,9 +35,9 @@ "account.follow_back": "回关", "account.followers": "关注者", "account.followers.empty": "目前无人关注此用户。", - "account.followers_counter": "被 {counter} 人关注", + "account.followers_counter": "{count, plural, other {{counter} 关注者}}", "account.following": "正在关注", - "account.following_counter": "正在关注 {counter} 人", + "account.following_counter": "{count, plural, other {{counter} 关注}}", "account.follows.empty": "此用户目前未关注任何人。", "account.go_to_profile": "前往个人资料页", "account.hide_reblogs": "隐藏来自 @{name} 的转嘟", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} 已经向你发送了关注请求", "account.share": "分享 @{name} 的个人资料页", "account.show_reblogs": "显示来自 @{name} 的转嘟", - "account.statuses_counter": "{counter} 条嘟文", + "account.statuses_counter": "{count, plural, other {{counter} 嘟文}}", "account.unblock": "取消屏蔽 @{name}", "account.unblock_domain": "取消屏蔽 {domain} 域名", "account.unblock_short": "取消屏蔽", @@ -699,6 +699,7 @@ "server_banner.is_one_of_many": "{domain} 是可用于参与联邦宇宙的众多独立 Mastodon 服务器之一。", "server_banner.server_stats": "服务器统计数据:", "sign_in_banner.create_account": "创建账户", + "sign_in_banner.follow_anyone": "关注联邦宇宙中的任何人,并按时间顺序查看所有内容。没有算法、广告或诱导链接。", "sign_in_banner.mastodon_is": "Mastodon 是了解最新动态的最佳途径。", "sign_in_banner.sign_in": "登录", "sign_in_banner.sso_redirect": "登录或注册", diff --git a/app/javascript/mastodon/locales/zh-HK.json b/app/javascript/mastodon/locales/zh-HK.json index 5dff466201..09a497e889 100644 --- a/app/javascript/mastodon/locales/zh-HK.json +++ b/app/javascript/mastodon/locales/zh-HK.json @@ -35,9 +35,7 @@ "account.follow_back": "追蹤對方", "account.followers": "追蹤者", "account.followers.empty": "尚未有人追蹤這位使用者。", - "account.followers_counter": "有 {count, plural,one {{counter} 個} other {{counter} 個}}追蹤者", "account.following": "正在追蹤", - "account.following_counter": "正在追蹤 {count, plural,one {{counter}}other {{counter} 人}}", "account.follows.empty": "這位使用者尚未追蹤任何人。", "account.go_to_profile": "前往個人檔案", "account.hide_reblogs": "隱藏 @{name} 的轉推", @@ -63,7 +61,6 @@ "account.requested_follow": "{name} 要求追蹤你", "account.share": "分享 @{name} 的個人檔案", "account.show_reblogs": "顯示 @{name} 的轉推", - "account.statuses_counter": "{count, plural,one {{counter} 篇}other {{counter} 篇}}帖文", "account.unblock": "解除封鎖 @{name}", "account.unblock_domain": "解除封鎖網域 {domain}", "account.unblock_short": "解除封鎖", diff --git a/app/javascript/mastodon/locales/zh-TW.json b/app/javascript/mastodon/locales/zh-TW.json index 4ab22daba5..04469a971d 100644 --- a/app/javascript/mastodon/locales/zh-TW.json +++ b/app/javascript/mastodon/locales/zh-TW.json @@ -35,9 +35,9 @@ "account.follow_back": "跟隨回去", "account.followers": "跟隨者", "account.followers.empty": "尚未有人跟隨這位使用者。", - "account.followers_counter": "被 {count, plural, other {{counter} 人}}跟隨", + "account.followers_counter": "被 {count, plural, other {{count} 人}}跟隨", "account.following": "跟隨中", - "account.following_counter": "正在跟隨 {count,plural,other {{counter} 人}}", + "account.following_counter": "正在跟隨 {count,plural,other {{count} 人}}", "account.follows.empty": "這位使用者尚未跟隨任何人。", "account.go_to_profile": "前往個人檔案", "account.hide_reblogs": "隱藏來自 @{name} 的轉嘟", @@ -63,7 +63,7 @@ "account.requested_follow": "{name} 要求跟隨您", "account.share": "分享 @{name} 的個人檔案", "account.show_reblogs": "顯示來自 @{name} 的轉嘟", - "account.statuses_counter": "{count, plural,one {{counter} 則}other {{counter} 則}}嘟文", + "account.statuses_counter": "{count, plural, other {{count} 則嘟文}}", "account.unblock": "解除封鎖 @{name}", "account.unblock_domain": "解除封鎖網域 {domain}", "account.unblock_short": "解除封鎖", diff --git a/config/locales/fi.yml b/config/locales/fi.yml index f108718e5e..be87258daf 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -293,7 +293,7 @@ fi: filter_by_action: Suodata tapahtuman mukaan filter_by_user: Suodata käyttäjän mukaan title: Auditointiloki - unavailable_instance: "(verkkotunnus ei ole saatavilla)" + unavailable_instance: "(verkkotunnus ei saatavilla)" announcements: destroyed_msg: Tiedote poistettu onnistuneesti! edit: diff --git a/config/locales/sr-Latn.yml b/config/locales/sr-Latn.yml index 776e473ee7..f6e6d4d2a6 100644 --- a/config/locales/sr-Latn.yml +++ b/config/locales/sr-Latn.yml @@ -577,7 +577,7 @@ sr-Latn: relays: add_new: Dodaj novi relej delete: Obriši - description_html: "Federalni relej je posrednički server koji razmenjuje velike količine javnih truba između servera na koji je pretplaćen i na koji objavljuje.Može pomoći malim i srednjim serverima da otkriju sadržaj iz fediversa, koji inače zahteva od lokalnih korisnika da ručno pratiti ostale ljude na udaljenim serverima." + description_html: "Federalni relej je posrednički server koji razmenjuje velike količine javnih objava između servera na koji je pretplaćen i na koji objavljuje.Može pomoći malim i srednjim serverima da otkriju sadržaj iz fediverzuma, koji inače zahteva od lokalnih korisnika da ručno pratiti ostale ljude na udaljenim serverima." disable: Isključi disabled: Isključen enable: Uključi diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 365b358d5a..9bfefde83c 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -577,7 +577,7 @@ sr: relays: add_new: Додај нови релеј delete: Обриши - description_html: "Федерални релеј је посреднички сервер који размењује велике количине јавних труба између сервера на који је претплаћен и на који објављује.Може помоћи малим и средњим серверима да открију садржај из федиверса, који иначе захтева од локалних корисника да ручно пратити остале људе на удаљеним серверима." + description_html: "Федерални релеј је посреднички сервер који размењује велике количине јавних објава између сервера на који је претплаћен и на који објављује.Може помоћи малим и средњим серверима да открију садржај из федиверзума, који иначе захтева од локалних корисника да ручно пратити остале људе на удаљеним серверима." disable: Искључи disabled: Искључен enable: Укључи diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 93de27c0b2..1317d5f707 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -525,7 +525,7 @@ zh-TW: total_followed_by_us: 被我們跟隨 total_reported: 關於他們的檢舉報告 total_storage: 多媒體附加檔案 - totals_time_period_hint_html: 以下顯示之總和包含所有時間的資料。 + totals_time_period_hint_html: 以下顯示之統計包含所有時間的資料。 unknown_instance: 此伺服器目前沒有這個網域的紀錄。 invites: deactivate_all: 全部停用 From 096057b845f27fd6090915b22c8688a6eeb22e28 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 27 Jun 2024 15:17:18 +0200 Subject: [PATCH 14/34] Change `author_account` to be `authors` in REST API (#30846) --- .../mastodon/actions/importer/index.js | 4 ++-- .../mastodon/actions/importer/normalizer.js | 11 +++++++++-- app/javascript/mastodon/actions/trends.js | 2 +- app/javascript/mastodon/api_types/statuses.ts | 7 +++++++ .../features/explore/components/author_link.jsx | 4 ++++ .../mastodon/features/explore/links.jsx | 2 +- .../mastodon/features/status/components/card.jsx | 4 ++-- app/models/preview_card.rb | 16 ++++++++++++++++ app/serializers/rest/preview_card_serializer.rb | 7 ++++++- 9 files changed, 48 insertions(+), 9 deletions(-) diff --git a/app/javascript/mastodon/actions/importer/index.js b/app/javascript/mastodon/actions/importer/index.js index d906bdfb14..516a7a7973 100644 --- a/app/javascript/mastodon/actions/importer/index.js +++ b/app/javascript/mastodon/actions/importer/index.js @@ -76,8 +76,8 @@ export function importFetchedStatuses(statuses) { pushUnique(polls, normalizePoll(status.poll, getState().getIn(['polls', status.poll.id]))); } - if (status.card?.author_account) { - pushUnique(accounts, status.card.author_account); + if (status.card) { + status.card.authors.forEach(author => author.account && pushUnique(accounts, author.account)); } } diff --git a/app/javascript/mastodon/actions/importer/normalizer.js b/app/javascript/mastodon/actions/importer/normalizer.js index be76b0f391..c09a3f442c 100644 --- a/app/javascript/mastodon/actions/importer/normalizer.js +++ b/app/javascript/mastodon/actions/importer/normalizer.js @@ -36,8 +36,15 @@ export function normalizeStatus(status, normalOldStatus) { normalStatus.poll = status.poll.id; } - if (status.card?.author_account) { - normalStatus.card = { ...status.card, author_account: status.card.author_account.id }; + if (status.card) { + normalStatus.card = { + ...status.card, + authors: status.card.authors.map(author => ({ + ...author, + accountId: author.account?.id, + account: undefined, + })), + }; } if (status.filtered) { diff --git a/app/javascript/mastodon/actions/trends.js b/app/javascript/mastodon/actions/trends.js index 01089fccbb..0bdf17a5d2 100644 --- a/app/javascript/mastodon/actions/trends.js +++ b/app/javascript/mastodon/actions/trends.js @@ -51,7 +51,7 @@ export const fetchTrendingLinks = () => (dispatch) => { api() .get('/api/v1/trends/links', { params: { limit: 20 } }) .then(({ data }) => { - dispatch(importFetchedAccounts(data.map(link => link.author_account).filter(account => !!account))); + dispatch(importFetchedAccounts(data.flatMap(link => link.authors.map(author => author.account)).filter(account => !!account))); dispatch(fetchTrendingLinksSuccess(data)); }) .catch(err => dispatch(fetchTrendingLinksFail(err))); diff --git a/app/javascript/mastodon/api_types/statuses.ts b/app/javascript/mastodon/api_types/statuses.ts index c7dd33b5da..db4e20506f 100644 --- a/app/javascript/mastodon/api_types/statuses.ts +++ b/app/javascript/mastodon/api_types/statuses.ts @@ -30,6 +30,12 @@ export interface ApiMentionJSON { acct: string; } +export interface ApiPreviewCardAuthorJSON { + name: string; + url: string; + account?: ApiAccountJSON; +} + export interface ApiPreviewCardJSON { url: string; title: string; @@ -48,6 +54,7 @@ export interface ApiPreviewCardJSON { embed_url: string; blurhash: string; published_at: string; + authors: ApiPreviewCardAuthorJSON[]; } export interface ApiStatusJSON { diff --git a/app/javascript/mastodon/features/explore/components/author_link.jsx b/app/javascript/mastodon/features/explore/components/author_link.jsx index 8dd9b0dabd..764ae75341 100644 --- a/app/javascript/mastodon/features/explore/components/author_link.jsx +++ b/app/javascript/mastodon/features/explore/components/author_link.jsx @@ -8,6 +8,10 @@ import { useAppSelector } from 'mastodon/store'; export const AuthorLink = ({ accountId }) => { const account = useAppSelector(state => state.getIn(['accounts', accountId])); + if (!account) { + return null; + } + return ( diff --git a/app/javascript/mastodon/features/explore/links.jsx b/app/javascript/mastodon/features/explore/links.jsx index 93fd1fb6dd..035e5aaad8 100644 --- a/app/javascript/mastodon/features/explore/links.jsx +++ b/app/javascript/mastodon/features/explore/links.jsx @@ -75,7 +75,7 @@ class Links extends PureComponent { publisher={link.get('provider_name')} publishedAt={link.get('published_at')} author={link.get('author_name')} - authorAccount={link.getIn(['author_account', 'id'])} + authorAccount={link.getIn(['authors', 0, 'account', 'id'])} sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1} thumbnail={link.get('image')} thumbnailDescription={link.get('image_description')} diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index f562e53f0b..f0ae40cbc4 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -138,7 +138,7 @@ export default class Card extends PureComponent { const interactive = card.get('type') === 'video'; const language = card.get('language') || ''; const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive; - const showAuthor = !!card.get('author_account'); + const showAuthor = !!card.getIn(['authors', 0, 'accountId']); const description = (
@@ -244,7 +244,7 @@ export default class Card extends PureComponent { {description} - {showAuthor && } + {showAuthor && } ); } diff --git a/app/models/preview_card.rb b/app/models/preview_card.rb index cbfc393786..eac02ac14f 100644 --- a/app/models/preview_card.rb +++ b/app/models/preview_card.rb @@ -128,6 +128,22 @@ class PreviewCard < ApplicationRecord @history ||= Trends::History.new('links', id) end + def authors + @authors ||= [PreviewCard::Author.new(self)] + end + + class Author < ActiveModelSerializers::Model + attributes :name, :url, :account + + def initialize(preview_card) + super( + name: preview_card.author_name, + url: preview_card.author_url, + account: preview_card.author_account, + ) + end + end + class << self private diff --git a/app/serializers/rest/preview_card_serializer.rb b/app/serializers/rest/preview_card_serializer.rb index 7d4c99c2d1..f73a051ac0 100644 --- a/app/serializers/rest/preview_card_serializer.rb +++ b/app/serializers/rest/preview_card_serializer.rb @@ -1,6 +1,11 @@ # frozen_string_literal: true class REST::PreviewCardSerializer < ActiveModel::Serializer + class AuthorSerializer < ActiveModel::Serializer + attributes :name, :url + has_one :account, serializer: REST::AccountSerializer + end + include RoutingHelper attributes :url, :title, :description, :language, :type, @@ -8,7 +13,7 @@ class REST::PreviewCardSerializer < ActiveModel::Serializer :provider_url, :html, :width, :height, :image, :image_description, :embed_url, :blurhash, :published_at - has_one :author_account, serializer: REST::AccountSerializer, if: -> { object.author_account.present? } + has_many :authors, serializer: AuthorSerializer def url object.original_url.presence || object.url From 42adb6eaee3250e3557403ce52513e3d31b3ab80 Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Thu, 27 Jun 2024 16:40:19 +0200 Subject: [PATCH 15/34] Add size limit for link preview URLs (#30854) --- app/services/fetch_link_card_service.rb | 5 ++++- spec/services/fetch_link_card_service_spec.rb | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 900cb9863d..9692dd21bb 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -15,6 +15,9 @@ class FetchLinkCardService < BaseService ) }iox + # URL size limit to safely store in PosgreSQL's unique indexes + BYTESIZE_LIMIT = 2692 + def call(status) @status = status @original_url = parse_urls @@ -85,7 +88,7 @@ class FetchLinkCardService < BaseService def bad_url?(uri) # Avoid local instance URLs and invalid URLs - uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme) + uri.host.blank? || TagManager.instance.local_url?(uri.to_s) || !%w(http https).include?(uri.scheme) || uri.to_s.bytesize > BYTESIZE_LIMIT end def mention_link?(anchor) diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb index 239f84fde9..4f02aba540 100644 --- a/spec/services/fetch_link_card_service_spec.rb +++ b/spec/services/fetch_link_card_service_spec.rb @@ -193,6 +193,19 @@ RSpec.describe FetchLinkCardService do end end + context 'with an URL too long for PostgreSQL unique indexes' do + let(:url) { "http://example.com/#{'a' * 2674}" } + let(:status) { Fabricate(:status, text: url) } + + it 'does not fetch the URL' do + expect(a_request(:get, url)).to_not have_been_made + end + + it 'does not create a preview card' do + expect(status.preview_card).to be_nil + end + end + context 'with a URL of a page with oEmbed support' do let(:html) { 'Hello world' } let(:status) { Fabricate(:status, text: 'http://example.com/html') } From ff08d99d4dceebd720e16e4a40118cbd6941b0ca Mon Sep 17 00:00:00 2001 From: David Roetzel Date: Thu, 27 Jun 2024 16:41:03 +0200 Subject: [PATCH 16/34] Catch encoding errors when creating link previews. (#30853) --- app/services/fetch_link_card_service.rb | 2 +- spec/fixtures/requests/redirect_with_utf8_url.txt | 5 +++++ spec/services/fetch_link_card_service_spec.rb | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/requests/redirect_with_utf8_url.txt diff --git a/app/services/fetch_link_card_service.rb b/app/services/fetch_link_card_service.rb index 9692dd21bb..8bc9f912c5 100644 --- a/app/services/fetch_link_card_service.rb +++ b/app/services/fetch_link_card_service.rb @@ -32,7 +32,7 @@ class FetchLinkCardService < BaseService end attach_card if @card&.persisted? - rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError => e + rescue HTTP::Error, OpenSSL::SSL::SSLError, Addressable::URI::InvalidURIError, Mastodon::HostValidationError, Mastodon::LengthValidationError, Encoding::UndefinedConversionError => e Rails.logger.debug { "Error fetching link #{@original_url}: #{e}" } nil end diff --git a/spec/fixtures/requests/redirect_with_utf8_url.txt b/spec/fixtures/requests/redirect_with_utf8_url.txt new file mode 100644 index 0000000000..08f99ee2ae --- /dev/null +++ b/spec/fixtures/requests/redirect_with_utf8_url.txt @@ -0,0 +1,5 @@ +HTTP/1.1 301 Moved Permanently +server: nginx +date: Thu, 27 Jun 2024 11:04:53 GMT +content-type: text/html; charset=UTF-8 +location: http://example.com/ärgerliche-umlaute.html diff --git a/spec/services/fetch_link_card_service_spec.rb b/spec/services/fetch_link_card_service_spec.rb index 4f02aba540..d83a527514 100644 --- a/spec/services/fetch_link_card_service_spec.rb +++ b/spec/services/fetch_link_card_service_spec.rb @@ -27,6 +27,7 @@ RSpec.describe FetchLinkCardService do stub_request(:get, 'http://example.com/koi8-r').to_return(request_fixture('koi8-r.txt')) stub_request(:get, 'http://example.com/windows-1251').to_return(request_fixture('windows-1251.txt')) stub_request(:get, 'http://example.com/low_confidence_latin1').to_return(request_fixture('low_confidence_latin1.txt')) + stub_request(:get, 'http://example.com/aergerliche-umlaute').to_return(request_fixture('redirect_with_utf8_url.txt')) Rails.cache.write('oembed_endpoint:example.com', oembed_cache) if oembed_cache @@ -101,6 +102,14 @@ RSpec.describe FetchLinkCardService do end end + context 'with a redirect URL with faulty encoding' do + let(:status) { Fabricate(:status, text: 'http://example.com/aergerliche-umlaute') } + + it 'does not create a preview card' do + expect(status.preview_card).to be_nil + end + end + context 'with a 404 URL' do let(:status) { Fabricate(:status, text: 'http://example.com/not-found') } From b15a3614dc7466e983e1394a12a16874a812e672 Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 27 Jun 2024 17:25:27 +0200 Subject: [PATCH 17/34] Stub `Vips::Error` when not using libvips (#30857) --- config/initializers/vips.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/initializers/vips.rb b/config/initializers/vips.rb index 25a17b2a17..8d5d5cdc91 100644 --- a/config/initializers/vips.rb +++ b/config/initializers/vips.rb @@ -25,3 +25,11 @@ if Rails.configuration.x.use_vips Vips.block_untrusted(true) end + +# In some places of the code, we rescue this exception, but we don't always +# load libvips, so it may be an undefined constant: +unless defined?(Vips) + module Vips + class Error < StandardError; end + end +end From 836c0477ac63ea61b955bfb900cf52ec29554e40 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 27 Jun 2024 12:03:26 -0400 Subject: [PATCH 18/34] Use vips setting instead of env var in media processing spec (#30859) --- spec/models/media_attachment_spec.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/models/media_attachment_spec.rb b/spec/models/media_attachment_spec.rb index 221645ac5a..a8f1ce7745 100644 --- a/spec/models/media_attachment_spec.rb +++ b/spec/models/media_attachment_spec.rb @@ -210,10 +210,14 @@ RSpec.describe MediaAttachment, :paperclip_processing do expect(media.file.meta['original']['duration']).to be_within(0.05).of(0.235102) expect(media.thumbnail.present?).to be true - # NOTE: Our libvips and ImageMagick implementations currently have different results - expect(media.file.meta['colors']['background']).to eq(ENV['MASTODON_USE_LIBVIPS'] ? '#268cd9' : '#3088d4') + expect(media.file.meta['colors']['background']).to eq(expected_background_color) expect(media.file_file_name).to_not eq 'boop.ogg' end + + def expected_background_color + # The libvips and ImageMagick implementations produce different results + Rails.configuration.x.use_vips ? '#268cd9' : '#3088d4' + end end describe 'mp3 with large cover art' do From 03bbb74b0ccc5f56bb3856efb1892ae8e0872a38 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 16:27:32 +0000 Subject: [PATCH 19/34] fix(deps): update dependency prom-client to v15.1.3 (#30852) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index dc73fb93b0..f9eaef4582 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14099,12 +14099,12 @@ __metadata: linkType: hard "prom-client@npm:^15.0.0": - version: 15.1.2 - resolution: "prom-client@npm:15.1.2" + version: 15.1.3 + resolution: "prom-client@npm:15.1.3" dependencies: "@opentelemetry/api": "npm:^1.4.0" tdigest: "npm:^0.1.1" - checksum: 10c0/a221db148fa64e29dfd4c6cdcaaae14635495a4272b68917e2b44fcfd988bc57027d275b04489ceeea4d0c4d64d058af842c1300966d2c1ffa255f1fa6af1277 + checksum: 10c0/816525572e5799a2d1d45af78512fb47d073c842dc899c446e94d17cfc343d04282a1627c488c7ca1bcd47f766446d3e49365ab7249f6d9c22c7664a5bce7021 languageName: node linkType: hard From bc3737f0c3c4cc0af500413db53fb5443ad02b69 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Thu, 27 Jun 2024 12:27:42 -0400 Subject: [PATCH 20/34] Add detail about running version on vips error failure (#30858) --- config/initializers/vips.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/initializers/vips.rb b/config/initializers/vips.rb index 8d5d5cdc91..a539d7035c 100644 --- a/config/initializers/vips.rb +++ b/config/initializers/vips.rb @@ -5,7 +5,11 @@ if Rails.configuration.x.use_vips require 'vips' - abort('Incompatible libvips version, please install libvips >= 8.13') unless Vips.at_least_libvips?(8, 13) + unless Vips.at_least_libvips?(8, 13) + abort <<~ERROR.squish + Incompatible libvips version (#{Vips.version_string}), please install libvips >= 8.13 + ERROR + end Vips.block('VipsForeign', true) From 3225954865c49ce7a336b73b2bc0c5ff2b707746 Mon Sep 17 00:00:00 2001 From: Michael Stanclift Date: Thu, 27 Jun 2024 11:46:20 -0500 Subject: [PATCH 21/34] Fix browser window color on light theme (#30861) --- app/lib/themes.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/themes.rb b/app/lib/themes.rb index b6da980733..183258d62f 100644 --- a/app/lib/themes.rb +++ b/app/lib/themes.rb @@ -8,7 +8,7 @@ class Themes THEME_COLORS = { dark: '#191b22', - light: '#f3f5f7', + light: '#ffffff', }.freeze def initialize From 0f3fef6fda5819824457b9c1cdc41cb3d5ca976e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 27 Jun 2024 23:34:34 +0200 Subject: [PATCH 22/34] Change search modifiers to be case-insensitive (#30865) --- app/lib/search_query_transformer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb index 927495eace..606819ed40 100644 --- a/app/lib/search_query_transformer.rb +++ b/app/lib/search_query_transformer.rb @@ -225,7 +225,7 @@ class SearchQueryTransformer < Parslet::Transform end rule(clause: subtree(:clause)) do - prefix = clause[:prefix][:term].to_s if clause[:prefix] + prefix = clause[:prefix][:term].to_s.downcase if clause[:prefix] operator = clause[:operator]&.to_s term = clause[:phrase] ? clause[:phrase].map { |term| term[:term].to_s }.join(' ') : clause[:term].to_s From ea6c455e81f9f01a64adf123d0a4f820c6e67f97 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 28 Jun 2024 00:01:40 +0200 Subject: [PATCH 23/34] Fix follow button in hover cards not working when signed out in web UI (#30864) --- .../mastodon/components/follow_button.tsx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/components/follow_button.tsx b/app/javascript/mastodon/components/follow_button.tsx index 4b4d278317..db59942882 100644 --- a/app/javascript/mastodon/components/follow_button.tsx +++ b/app/javascript/mastodon/components/follow_button.tsx @@ -2,11 +2,13 @@ import { useCallback, useEffect } from 'react'; import { useIntl, defineMessages } from 'react-intl'; +import { useIdentity } from '@/mastodon/identity_context'; import { fetchRelationships, followAccount, unfollowAccount, } from 'mastodon/actions/accounts'; +import { openModal } from 'mastodon/actions/modal'; import { Button } from 'mastodon/components/button'; import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { me } from 'mastodon/initial_state'; @@ -29,17 +31,37 @@ export const FollowButton: React.FC<{ }> = ({ accountId }) => { const intl = useIntl(); const dispatch = useAppDispatch(); + const { signedIn } = useIdentity(); + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); const relationship = useAppSelector((state) => state.relationships.get(accountId), ); const following = relationship?.following || relationship?.requested; useEffect(() => { - dispatch(fetchRelationships([accountId])); - }, [dispatch, accountId]); + if (accountId && signedIn) { + dispatch(fetchRelationships([accountId])); + } + }, [dispatch, accountId, signedIn]); const handleClick = useCallback(() => { + if (!signedIn) { + dispatch( + openModal({ + modalType: 'INTERACTION', + modalProps: { + type: 'follow', + accountId: accountId, + url: account?.url, + }, + }), + ); + } + if (!relationship) return; + if (accountId === me) { return; } else if (relationship.following || relationship.requested) { @@ -47,11 +69,13 @@ export const FollowButton: React.FC<{ } else { dispatch(followAccount(accountId)); } - }, [dispatch, accountId, relationship]); + }, [dispatch, accountId, relationship, account, signedIn]); let label; - if (accountId === me) { + if (!signedIn) { + label = intl.formatMessage(messages.follow); + } else if (accountId === me) { label = intl.formatMessage(messages.edit_profile); } else if (!relationship) { label = ; From a5134f2695659ccb1c40b28b1f691e2dc932a5fb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 10:33:57 +0200 Subject: [PATCH 24/34] New Crowdin Translations (automated) (#30867) Co-authored-by: GitHub Actions --- app/javascript/mastodon/locales/de.json | 2 +- app/javascript/mastodon/locales/gl.json | 3 +++ app/javascript/mastodon/locales/hu.json | 3 +++ app/javascript/mastodon/locales/lt.json | 3 +++ app/javascript/mastodon/locales/nn.json | 6 ++++++ app/javascript/mastodon/locales/pl.json | 3 +++ app/javascript/mastodon/locales/pt-PT.json | 3 +++ app/javascript/mastodon/locales/sq.json | 3 +++ app/javascript/mastodon/locales/sv.json | 2 ++ config/locales/nn.yml | 1 + 10 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/javascript/mastodon/locales/de.json b/app/javascript/mastodon/locales/de.json index 86438757a3..4a5b666d3e 100644 --- a/app/javascript/mastodon/locales/de.json +++ b/app/javascript/mastodon/locales/de.json @@ -37,7 +37,7 @@ "account.followers.empty": "Diesem Profil folgt noch niemand.", "account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Follower}}", "account.following": "Folge ich", - "account.following_counter": "{count, plural, one {{counter} Folge ich} other {{counter} Folge ich}}", + "account.following_counter": "{count, plural, one {{counter} folge ich} other {{counter} folge ich}}", "account.follows.empty": "Dieses Profil folgt noch niemandem.", "account.go_to_profile": "Profil aufrufen", "account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden", diff --git a/app/javascript/mastodon/locales/gl.json b/app/javascript/mastodon/locales/gl.json index 156fe3ee86..fae48ed06b 100644 --- a/app/javascript/mastodon/locales/gl.json +++ b/app/javascript/mastodon/locales/gl.json @@ -35,7 +35,9 @@ "account.follow_back": "Seguir tamén", "account.followers": "Seguidoras", "account.followers.empty": "Aínda ninguén segue esta usuaria.", + "account.followers_counter": "{count, plural, one {{counter} seguidora} other {{counter} seguidoras}}", "account.following": "Seguindo", + "account.following_counter": "{count, plural, one {{counter} seguimento} other {{counter} seguimentos}}", "account.follows.empty": "Esta usuaria aínda non segue a ninguén.", "account.go_to_profile": "Ir ao perfil", "account.hide_reblogs": "Agochar promocións de @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} solicitou seguirte", "account.share": "Compartir o perfil de @{name}", "account.show_reblogs": "Amosar compartidos de @{name}", + "account.statuses_counter": "{count, plural, one {{counter} publicación} other {{counter} publicacións}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Amosar {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/hu.json b/app/javascript/mastodon/locales/hu.json index 627e3cab50..1fcadc8f9c 100644 --- a/app/javascript/mastodon/locales/hu.json +++ b/app/javascript/mastodon/locales/hu.json @@ -35,7 +35,9 @@ "account.follow_back": "Viszontkövetés", "account.followers": "Követő", "account.followers.empty": "Ezt a felhasználót még senki sem követi.", + "account.followers_counter": "{count, plural, one {{counter} követő} other {{counter} követő}}", "account.following": "Követve", + "account.following_counter": "{count, plural, one {{counter} követett} other {{counter} követett}}", "account.follows.empty": "Ez a felhasználó még senkit sem követ.", "account.go_to_profile": "Ugrás a profilhoz", "account.hide_reblogs": "@{name} megtolásainak elrejtése", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} kérte, hogy követhessen", "account.share": "@{name} profiljának megosztása", "account.show_reblogs": "@{name} megtolásainak mutatása", + "account.statuses_counter": "{count, plural, one {{counter} bejegyzés} other {{counter} bejegyzés}}", "account.unblock": "@{name} letiltásának feloldása", "account.unblock_domain": "{domain} domain tiltásának feloldása", "account.unblock_short": "Tiltás feloldása", diff --git a/app/javascript/mastodon/locales/lt.json b/app/javascript/mastodon/locales/lt.json index 6bf8f94bd9..bb69b73399 100644 --- a/app/javascript/mastodon/locales/lt.json +++ b/app/javascript/mastodon/locales/lt.json @@ -35,7 +35,9 @@ "account.follow_back": "Sekti atgal", "account.followers": "Sekėjai", "account.followers.empty": "Šio naudotojo dar niekas neseka.", + "account.followers_counter": "{count, plural, one {{counter} sekėjas} few {{counter} sekėjai} many {{counter} sekėjo} other {{counter} sekėjų}}", "account.following": "Sekama", + "account.following_counter": "{count, plural, one {{counter} sekimas} few {{counter} sekimai} many {{counter} sekimo} other {{counter} sekimų}}", "account.follows.empty": "Šis naudotojas dar nieko neseka.", "account.go_to_profile": "Eiti į profilį", "account.hide_reblogs": "Slėpti pakėlimus iš @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} paprašė tave sekti", "account.share": "Bendrinti @{name} profilį", "account.show_reblogs": "Rodyti pakėlimus iš @{name}", + "account.statuses_counter": "{count, plural, one {{counter} įrašas} few {{counter} įrašai} many {{counter} įrašo} other {{counter} įrašų}}", "account.unblock": "Atblokuoti @{name}", "account.unblock_domain": "Atblokuoti domeną {domain}", "account.unblock_short": "Atblokuoti", diff --git a/app/javascript/mastodon/locales/nn.json b/app/javascript/mastodon/locales/nn.json index 7eca296595..0fb0edf0a0 100644 --- a/app/javascript/mastodon/locales/nn.json +++ b/app/javascript/mastodon/locales/nn.json @@ -35,7 +35,9 @@ "account.follow_back": "Fylg tilbake", "account.followers": "Fylgjarar", "account.followers.empty": "Ingen fylgjer denne brukaren enno.", + "account.followers_counter": "{count, plural, one {{counter} følgjar} other {{counter} følgjarar}}", "account.following": "Fylgjer", + "account.following_counter": "{count, plural, one {{counter} følgjer} other {{counter} følgjer}}", "account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.", "account.go_to_profile": "Gå til profil", "account.hide_reblogs": "Gøym framhevingar frå @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} har bedt om å få fylgja deg", "account.share": "Del @{name} sin profil", "account.show_reblogs": "Vis framhevingar frå @{name}", + "account.statuses_counter": "{count, plural, one {{counter} innlegg} other {{counter} innlegg}}", "account.unblock": "Stopp blokkering av @{name}", "account.unblock_domain": "Stopp blokkering av domenet {domain}", "account.unblock_short": "Stopp blokkering", @@ -693,8 +696,11 @@ "server_banner.about_active_users": "Personar som har brukt denne tenaren dei siste 30 dagane (Månadlege Aktive Brukarar)", "server_banner.active_users": "aktive brukarar", "server_banner.administered_by": "Administrert av:", + "server_banner.is_one_of_many": "{domain} er ein av dei mange uavhengige Mastodon-serverane du kan bruke til å delta i Fødiverset.", "server_banner.server_stats": "Tenarstatistikk:", "sign_in_banner.create_account": "Opprett konto", + "sign_in_banner.follow_anyone": "Følg kven som helst på tvers av Fødiverset og sjå alt i kronologisk rekkjefølgje. Ingen algoritmar, reklamar eller clickbait i sikte.", + "sign_in_banner.mastodon_is": "Mastodon er den beste måten å følgje med på det som skjer.", "sign_in_banner.sign_in": "Logg inn", "sign_in_banner.sso_redirect": "Logg inn eller registrer deg", "status.admin_account": "Opne moderasjonsgrensesnitt for @{name}", diff --git a/app/javascript/mastodon/locales/pl.json b/app/javascript/mastodon/locales/pl.json index a3690e734b..ddfe1d4fbc 100644 --- a/app/javascript/mastodon/locales/pl.json +++ b/app/javascript/mastodon/locales/pl.json @@ -35,7 +35,9 @@ "account.follow_back": "Obserwuj wzajemnie", "account.followers": "Obserwujący", "account.followers.empty": "Nikt jeszcze nie obserwuje tego użytkownika.", + "account.followers_counter": "{count, plural, one {{counter} obserwujący} few {{counter} obserwujących} many {{counter} obserwujących} other {{counter} obserwujących}}", "account.following": "Obserwowani", + "account.following_counter": "{count, plural, one {{counter} obserwowany} few {{counter} obserwowanych} many {{counter} obserwowanych} other {{counter} obserwowanych}}", "account.follows.empty": "Ten użytkownik nie obserwuje jeszcze nikogo.", "account.go_to_profile": "Przejdź do profilu", "account.hide_reblogs": "Ukryj podbicia od @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} chce zaobserwować twój profil", "account.share": "Udostępnij profil @{name}", "account.show_reblogs": "Pokazuj podbicia od @{name}", + "account.statuses_counter": "{count, plural, one {{counter} wpis} few {{counter} wpisy} many {{counter} wpisów} other {{counter} wpisów}}", "account.unblock": "Odblokuj @{name}", "account.unblock_domain": "Odblokuj domenę {domain}", "account.unblock_short": "Odblokuj", diff --git a/app/javascript/mastodon/locales/pt-PT.json b/app/javascript/mastodon/locales/pt-PT.json index 41112c2ca4..6a6feca309 100644 --- a/app/javascript/mastodon/locales/pt-PT.json +++ b/app/javascript/mastodon/locales/pt-PT.json @@ -35,7 +35,9 @@ "account.follow_back": "Seguir de volta", "account.followers": "Seguidores", "account.followers.empty": "Ainda ninguém segue este utilizador.", + "account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}", "account.following": "A seguir", + "account.following_counter": "{count, plural, one {A seguir {counter}} other {A seguir {counter}}}", "account.follows.empty": "Este utilizador ainda não segue ninguém.", "account.go_to_profile": "Ir para o perfil", "account.hide_reblogs": "Esconder partilhas de @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} pediu para segui-lo", "account.share": "Partilhar o perfil @{name}", "account.show_reblogs": "Mostrar partilhas de @{name}", + "account.statuses_counter": "{count, plural, one {{counter} publicação} other {{counter} publicações}}", "account.unblock": "Desbloquear @{name}", "account.unblock_domain": "Desbloquear o domínio {domain}", "account.unblock_short": "Desbloquear", diff --git a/app/javascript/mastodon/locales/sq.json b/app/javascript/mastodon/locales/sq.json index 6ac038c9f4..96b7b3fefc 100644 --- a/app/javascript/mastodon/locales/sq.json +++ b/app/javascript/mastodon/locales/sq.json @@ -35,7 +35,9 @@ "account.follow_back": "Ndiqe gjithashtu", "account.followers": "Ndjekës", "account.followers.empty": "Këtë përdorues ende s’e ndjek kush.", + "account.followers_counter": "{count, plural, one {{counter} ndjekës} other {{counter} ndjekës}}", "account.following": "Ndjekje", + "account.following_counter": "{count, plural, one {{counter} i ndjekur} other {{counter} të ndjekur}}", "account.follows.empty": "Ky përdorues ende s’ndjek kënd.", "account.go_to_profile": "Kalo te profili", "account.hide_reblogs": "Fshih përforcime nga @{name}", @@ -61,6 +63,7 @@ "account.requested_follow": "{name} ka kërkuar t’ju ndjekë", "account.share": "Ndajeni profilin e @{name} me të tjerët", "account.show_reblogs": "Shfaq përforcime nga @{name}", + "account.statuses_counter": "{count, plural, one {{counter} postim} other {{counter} postime}}", "account.unblock": "Zhbllokoje @{name}", "account.unblock_domain": "Zhblloko përkatësinë {domain}", "account.unblock_short": "Zhbllokoje", diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json index 7445b77bac..1833a2cfde 100644 --- a/app/javascript/mastodon/locales/sv.json +++ b/app/javascript/mastodon/locales/sv.json @@ -35,6 +35,7 @@ "account.follow_back": "Följ tillbaka", "account.followers": "Följare", "account.followers.empty": "Ingen följer denna användare än.", + "account.followers_counter": "{count, plural, one {{counter} följare} other {{counter} följare}}", "account.following": "Följer", "account.follows.empty": "Denna användare följer inte någon än.", "account.go_to_profile": "Gå till profilen", @@ -61,6 +62,7 @@ "account.requested_follow": "{name} har begärt att följa dig", "account.share": "Dela @{name}s profil", "account.show_reblogs": "Visa boostar från @{name}", + "account.statuses_counter": "{count, plural, one {{counter} inlägg} other {{counter} inlägg}}", "account.unblock": "Avblockera @{name}", "account.unblock_domain": "Avblockera {domain}", "account.unblock_short": "Avblockera", diff --git a/config/locales/nn.yml b/config/locales/nn.yml index d82c92c262..2da30e6627 100644 --- a/config/locales/nn.yml +++ b/config/locales/nn.yml @@ -293,6 +293,7 @@ nn: filter_by_action: Sorter etter handling filter_by_user: Sorter etter brukar title: Revisionslogg + unavailable_instance: "(domenenamn er utilgjengeleg)" announcements: destroyed_msg: Kunngjøringen er slettet! edit: From 1bccba14082f380232a363d036b6b2e92104ffc6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 13:39:32 +0200 Subject: [PATCH 25/34] chore(deps): update dependency @testing-library/react to v16 (#30533) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Renaud Chaput --- app/javascript/mastodon/test_helpers.tsx | 7 ++++- package.json | 3 ++- yarn.lock | 33 +++++++++++++----------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/app/javascript/mastodon/test_helpers.tsx b/app/javascript/mastodon/test_helpers.tsx index 93b5a8453a..f405090730 100644 --- a/app/javascript/mastodon/test_helpers.tsx +++ b/app/javascript/mastodon/test_helpers.tsx @@ -2,6 +2,7 @@ import { IntlProvider } from 'react-intl'; import { MemoryRouter } from 'react-router'; +import type { RenderOptions } from '@testing-library/react'; // eslint-disable-next-line import/no-extraneous-dependencies import { render as rtlRender } from '@testing-library/react'; @@ -9,7 +10,11 @@ import { IdentityContext } from './identity_context'; function render( ui: React.ReactElement, - { locale = 'en', signedIn = true, ...renderOptions } = {}, + { + locale = 'en', + signedIn = true, + ...renderOptions + }: RenderOptions & { locale?: string; signedIn?: boolean } = {}, ) { const fakeIdentity = { signedIn: signedIn, diff --git a/package.json b/package.json index 729482f857..3eb1ebad7e 100644 --- a/package.json +++ b/package.json @@ -138,8 +138,9 @@ }, "devDependencies": { "@formatjs/cli": "^6.1.1", + "@testing-library/dom": "^10.2.0", "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^15.0.0", + "@testing-library/react": "^16.0.0", "@types/babel__core": "^7.20.1", "@types/emoji-mart": "^3.0.9", "@types/escape-html": "^1.0.2", diff --git a/yarn.lock b/yarn.lock index f9eaef4582..0e7337328b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2768,8 +2768,9 @@ __metadata: "@rails/ujs": "npm:7.1.3" "@reduxjs/toolkit": "npm:^2.0.1" "@svgr/webpack": "npm:^5.5.0" + "@testing-library/dom": "npm:^10.2.0" "@testing-library/jest-dom": "npm:^6.0.0" - "@testing-library/react": "npm:^15.0.0" + "@testing-library/react": "npm:^16.0.0" "@types/babel__core": "npm:^7.20.1" "@types/emoji-mart": "npm:^3.0.9" "@types/escape-html": "npm:^1.0.2" @@ -3348,9 +3349,9 @@ __metadata: languageName: node linkType: hard -"@testing-library/dom@npm:^10.0.0": - version: 10.0.0 - resolution: "@testing-library/dom@npm:10.0.0" +"@testing-library/dom@npm:^10.2.0": + version: 10.2.0 + resolution: "@testing-library/dom@npm:10.2.0" dependencies: "@babel/code-frame": "npm:^7.10.4" "@babel/runtime": "npm:^7.12.5" @@ -3360,7 +3361,7 @@ __metadata: dom-accessibility-api: "npm:^0.5.9" lz-string: "npm:^1.5.0" pretty-format: "npm:^27.0.2" - checksum: 10c0/2d12d2a6018a6f1d15e91834180bc068932c699ff1fcbfb80aa21aba519a4f5329c861dfa852e06ee5615bcb92ef2a0f0e755e32684ea3dada63bc34248382ab + checksum: 10c0/de582dfbeb632436547a0ca5851b5a714a4a17f8e96ab3dc4fb4e454eef52c912b648b7cb6e9fdf477f3eeef97e698f3250f0ce50846f39d04677a44169209f2 languageName: node linkType: hard @@ -3397,21 +3398,23 @@ __metadata: languageName: node linkType: hard -"@testing-library/react@npm:^15.0.0": - version: 15.0.7 - resolution: "@testing-library/react@npm:15.0.7" +"@testing-library/react@npm:^16.0.0": + version: 16.0.0 + resolution: "@testing-library/react@npm:16.0.0" dependencies: "@babel/runtime": "npm:^7.12.5" - "@testing-library/dom": "npm:^10.0.0" - "@types/react-dom": "npm:^18.0.0" peerDependencies: + "@testing-library/dom": ^10.0.0 "@types/react": ^18.0.0 + "@types/react-dom": ^18.0.0 react: ^18.0.0 react-dom: ^18.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 10c0/ac8ee8968e81949ecb35f7ee34741c2c043f73dd7fee2247d56f6de6a30de4742af94f25264356863974e54387485b46c9448ecf3f6ca41cf4339011c369f2d4 + "@types/react-dom": + optional: true + checksum: 10c0/297f97bf4722dad05f11d9cafd47d387dbdb096fea4b79b876c7466460f0f2e345b55b81b3e37fc81ed8185c528cb53dd8455ca1b6b019b229edf6c796f11c9f languageName: node linkType: hard @@ -3430,9 +3433,9 @@ __metadata: linkType: hard "@types/aria-query@npm:^5.0.1": - version: 5.0.1 - resolution: "@types/aria-query@npm:5.0.1" - checksum: 10c0/bc9e40ce37bd3a1654948778c7829bd55aea1bc5f2cd06fcf6cd650b07bb388995799e9aab6e2d93a6cf55dcba3b85c155f7ba93adefcc7c2e152fc6057061b5 + version: 5.0.4 + resolution: "@types/aria-query@npm:5.0.4" + checksum: 10c0/dc667bc6a3acc7bba2bccf8c23d56cb1f2f4defaa704cfef595437107efaa972d3b3db9ec1d66bc2711bfc35086821edd32c302bffab36f2e79b97f312069f08 languageName: node linkType: hard @@ -3829,7 +3832,7 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18.0.0, @types/react-dom@npm:^18.2.4": +"@types/react-dom@npm:^18.2.4": version: 18.3.0 resolution: "@types/react-dom@npm:18.3.0" dependencies: From ba6a558a7088b811b63a90d20b82069eee7dfaa1 Mon Sep 17 00:00:00 2001 From: Claire Date: Sat, 29 Jun 2024 00:41:27 +0200 Subject: [PATCH 26/34] Simplify color extraction code using `bandunfold` (#30869) --- lib/paperclip/color_extractor.rb | 35 +++++++++++--------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/lib/paperclip/color_extractor.rb b/lib/paperclip/color_extractor.rb index 378af0961d..fba32ba4cb 100644 --- a/lib/paperclip/color_extractor.rb +++ b/lib/paperclip/color_extractor.rb @@ -116,34 +116,23 @@ module Paperclip # The number of occurrences of a color (r, g, b) is thus encoded in band `b` at pixel position `(r, g)` histogram = image.hist_find_ndim(bins: BINS) - # `histogram.max` returns an array of maxima with their pixel positions, but we don't know in which - # band they are + # With `bandunfold`, we get back to a (BINS*BINS)×BINS 2D image with a single band. + # The number of occurrences of a color (r, g, b) is thus encoded at pixel position `(r * BINS + b, g)` + histogram = histogram.bandunfold + _, colors = histogram.max(size: 10, out_array: true, x_array: true, y_array: true) - colors['out_array'].zip(colors['x_array'], colors['y_array']).map do |v, x, y| - rgb_from_xyv(histogram, x, y, v) - end.flatten.reverse.uniq + colors['x_array'].zip(colors['y_array']).map do |x, y| + rgb_from_hist_xy(x, y) + end.flatten.reverse end # rubocop:disable Naming/MethodParameterName - def rgb_from_xyv(image, x, y, v) - pixel = image.getpoint(x, y) - - # As we only have the first 2 dimensions for this maximum, we - # can't distinguish with different maxima with the same `r` and `g` - # values but different `b` values. - # - # Therefore, we return an array of maxima, which is always non-empty, - # but may contain multiple colors with the same values. - - pixel.filter_map.with_index do |pv, z| - next if pv != v - - r = (x + 0.5) * 256 / BINS - g = (y + 0.5) * 256 / BINS - b = (z + 0.5) * 256 / BINS - ColorDiff::Color::RGB.new(r, g, b) - end + def rgb_from_hist_xy(x, y) + r = ((x / BINS) + 0.5) * 256 / BINS + g = (y + 0.5) * 256 / BINS + b = ((x % BINS) + 0.5) * 256 / BINS + ColorDiff::Color::RGB.new(r, g, b) end def w3c_contrast(color1, color2) From 5d4dbbcc67c98007d417cbe67b5a2261889304dc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 29 Jun 2024 22:51:46 +0200 Subject: [PATCH 27/34] chore(deps): update dependency charlock_holmes to v0.7.8 (#30870) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index dd112d0189..02437eab6b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -159,7 +159,7 @@ GEM case_transform (0.2) activesupport cbor (0.5.9.8) - charlock_holmes (0.7.7) + charlock_holmes (0.7.8) chewy (7.6.0) activesupport (>= 5.2) elasticsearch (>= 7.14.0, < 8) From 1ac4e64a3ba51360dfc62f63e95c157a36c65e61 Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Tue, 25 Jun 2024 23:57:22 +0200 Subject: [PATCH 28/34] [Glitch] Change light mode to apply CSS variables to the body Port 8c0ff6498e090a2919e8f8104339796ed2d3d212 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/styles/mastodon-light/variables.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss b/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss index 09a75a834b..3cdbd9bf67 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss @@ -56,11 +56,11 @@ $account-background-color: $white !default; $emojis-requiring-inversion: 'chains'; -.theme-mastodon-light { +body { --dropdown-border-color: #d9e1e8; --dropdown-background-color: #fff; --background-border-color: #d9e1e8; --background-color: #fff; - --background-color-tint: rgba(255, 255, 255, 90%); + --background-color-tint: rgba(255, 255, 255, 80%); --background-filter: blur(10px); } From 8160a655a528856f87b8d0174bce54c78a7af4be Mon Sep 17 00:00:00 2001 From: Renaud Chaput Date: Wed, 26 Jun 2024 20:04:50 +0200 Subject: [PATCH 29/34] [Glitch] Convert `` to Typescript / function component Port 863c470a2bc4e13a5b8df4d66a1322f4b84e2db2 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/directory.js | 62 ---- .../flavours/glitch/actions/directory.ts | 37 +++ .../flavours/glitch/api/directory.ts | 15 + .../directory/components/account_card.jsx | 247 ---------------- .../directory/components/account_card.tsx | 273 ++++++++++++++++++ .../glitch/features/directory/index.jsx | 181 ------------ .../glitch/features/directory/index.tsx | 217 ++++++++++++++ .../flavours/glitch/locales/en.json | 3 +- .../flavours/glitch/reducers/user_lists.js | 32 +- 9 files changed, 558 insertions(+), 509 deletions(-) delete mode 100644 app/javascript/flavours/glitch/actions/directory.js create mode 100644 app/javascript/flavours/glitch/actions/directory.ts create mode 100644 app/javascript/flavours/glitch/api/directory.ts delete mode 100644 app/javascript/flavours/glitch/features/directory/components/account_card.jsx create mode 100644 app/javascript/flavours/glitch/features/directory/components/account_card.tsx delete mode 100644 app/javascript/flavours/glitch/features/directory/index.jsx create mode 100644 app/javascript/flavours/glitch/features/directory/index.tsx diff --git a/app/javascript/flavours/glitch/actions/directory.js b/app/javascript/flavours/glitch/actions/directory.js deleted file mode 100644 index 7a0748029d..0000000000 --- a/app/javascript/flavours/glitch/actions/directory.js +++ /dev/null @@ -1,62 +0,0 @@ -import api from '../api'; - -import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; - -export const DIRECTORY_FETCH_REQUEST = 'DIRECTORY_FETCH_REQUEST'; -export const DIRECTORY_FETCH_SUCCESS = 'DIRECTORY_FETCH_SUCCESS'; -export const DIRECTORY_FETCH_FAIL = 'DIRECTORY_FETCH_FAIL'; - -export const DIRECTORY_EXPAND_REQUEST = 'DIRECTORY_EXPAND_REQUEST'; -export const DIRECTORY_EXPAND_SUCCESS = 'DIRECTORY_EXPAND_SUCCESS'; -export const DIRECTORY_EXPAND_FAIL = 'DIRECTORY_EXPAND_FAIL'; - -export const fetchDirectory = params => (dispatch) => { - dispatch(fetchDirectoryRequest()); - - api().get('/api/v1/directory', { params: { ...params, limit: 20 } }).then(({ data }) => { - dispatch(importFetchedAccounts(data)); - dispatch(fetchDirectorySuccess(data)); - dispatch(fetchRelationships(data.map(x => x.id))); - }).catch(error => dispatch(fetchDirectoryFail(error))); -}; - -export const fetchDirectoryRequest = () => ({ - type: DIRECTORY_FETCH_REQUEST, -}); - -export const fetchDirectorySuccess = accounts => ({ - type: DIRECTORY_FETCH_SUCCESS, - accounts, -}); - -export const fetchDirectoryFail = error => ({ - type: DIRECTORY_FETCH_FAIL, - error, -}); - -export const expandDirectory = params => (dispatch, getState) => { - dispatch(expandDirectoryRequest()); - - const loadedItems = getState().getIn(['user_lists', 'directory', 'items']).size; - - api().get('/api/v1/directory', { params: { ...params, offset: loadedItems, limit: 20 } }).then(({ data }) => { - dispatch(importFetchedAccounts(data)); - dispatch(expandDirectorySuccess(data)); - dispatch(fetchRelationships(data.map(x => x.id))); - }).catch(error => dispatch(expandDirectoryFail(error))); -}; - -export const expandDirectoryRequest = () => ({ - type: DIRECTORY_EXPAND_REQUEST, -}); - -export const expandDirectorySuccess = accounts => ({ - type: DIRECTORY_EXPAND_SUCCESS, - accounts, -}); - -export const expandDirectoryFail = error => ({ - type: DIRECTORY_EXPAND_FAIL, - error, -}); diff --git a/app/javascript/flavours/glitch/actions/directory.ts b/app/javascript/flavours/glitch/actions/directory.ts new file mode 100644 index 0000000000..3e0f1356b3 --- /dev/null +++ b/app/javascript/flavours/glitch/actions/directory.ts @@ -0,0 +1,37 @@ +import type { List as ImmutableList } from 'immutable'; + +import { apiGetDirectory } from 'flavours/glitch/api/directory'; +import { createDataLoadingThunk } from 'flavours/glitch/store/typed_functions'; + +import { fetchRelationships } from './accounts'; +import { importFetchedAccounts } from './importer'; + +export const fetchDirectory = createDataLoadingThunk( + 'directory/fetch', + async (params: Parameters[0]) => + apiGetDirectory(params), + (data, { dispatch }) => { + dispatch(importFetchedAccounts(data)); + dispatch(fetchRelationships(data.map((x) => x.id))); + + return { accounts: data }; + }, +); + +export const expandDirectory = createDataLoadingThunk( + 'directory/expand', + async (params: Parameters[0], { getState }) => { + const loadedItems = getState().user_lists.getIn([ + 'directory', + 'items', + ]) as ImmutableList; + + return apiGetDirectory({ ...params, offset: loadedItems.size }, 20); + }, + (data, { dispatch }) => { + dispatch(importFetchedAccounts(data)); + dispatch(fetchRelationships(data.map((x) => x.id))); + + return { accounts: data }; + }, +); diff --git a/app/javascript/flavours/glitch/api/directory.ts b/app/javascript/flavours/glitch/api/directory.ts new file mode 100644 index 0000000000..72743a2584 --- /dev/null +++ b/app/javascript/flavours/glitch/api/directory.ts @@ -0,0 +1,15 @@ +import { apiRequestGet } from 'flavours/glitch/api'; +import type { ApiAccountJSON } from 'flavours/glitch/api_types/accounts'; + +export const apiGetDirectory = ( + params: { + order: string; + local: boolean; + offset?: number; + }, + limit = 20, +) => + apiRequestGet('v1/directory', { + ...params, + limit, + }); diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.jsx b/app/javascript/flavours/glitch/features/directory/components/account_card.jsx deleted file mode 100644 index ed4736d7e6..0000000000 --- a/app/javascript/flavours/glitch/features/directory/components/account_card.jsx +++ /dev/null @@ -1,247 +0,0 @@ -import PropTypes from 'prop-types'; - -import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; - -import classNames from 'classnames'; - -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { - followAccount, - unfollowAccount, - unblockAccount, - unmuteAccount, -} from 'flavours/glitch/actions/accounts'; -import { openModal } from 'flavours/glitch/actions/modal'; -import { Avatar } from 'flavours/glitch/components/avatar'; -import { Button } from 'flavours/glitch/components/button'; -import { DisplayName } from 'flavours/glitch/components/display_name'; -import { IconButton } from 'flavours/glitch/components/icon_button'; -import { Permalink } from 'flavours/glitch/components/permalink'; -import { ShortNumber } from 'flavours/glitch/components/short_number'; -import { autoPlayGif, me } from 'flavours/glitch/initial_state'; -import { makeGetAccount } from 'flavours/glitch/selectors'; - -const messages = defineMessages({ - unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, - follow: { id: 'account.follow', defaultMessage: 'Follow' }, - cancel_follow_request: { id: 'account.cancel_follow_request', defaultMessage: 'Withdraw follow request' }, - cancelFollowRequestConfirm: { id: 'confirmations.cancel_follow_request.confirm', defaultMessage: 'Withdraw request' }, - requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, - unblock: { id: 'account.unblock_short', defaultMessage: 'Unblock' }, - unmute: { id: 'account.unmute_short', defaultMessage: 'Unmute' }, - unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, - edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, - dismissSuggestion: { id: 'suggestions.dismiss', defaultMessage: 'Dismiss suggestion' }, -}); - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, { id }) => ({ - account: getAccount(state, id), - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = (dispatch, { intl }) => ({ - onFollow(account) { - if (account.getIn(['relationship', 'following'])) { - dispatch( - openModal({ - modalType: 'CONFIRM', - modalProps: { - message: ( - @{account.get('acct')} }} - /> - ), - confirm: intl.formatMessage(messages.unfollowConfirm), - onConfirm: () => dispatch(unfollowAccount(account.get('id'))), - } }), - ); - } else if (account.getIn(['relationship', 'requested'])) { - dispatch(openModal({ - modalType: 'CONFIRM', - modalProps: { - message: @{account.get('acct')} }} />, - confirm: intl.formatMessage(messages.cancelFollowRequestConfirm), - onConfirm: () => dispatch(unfollowAccount(account.get('id'))), - }, - })); - } else { - dispatch(followAccount(account.get('id'))); - } - }, - - onBlock(account) { - if (account.getIn(['relationship', 'blocking'])) { - dispatch(unblockAccount(account.get('id'))); - } - }, - - onMute(account) { - if (account.getIn(['relationship', 'muting'])) { - dispatch(unmuteAccount(account.get('id'))); - } - }, - -}); - -class AccountCard extends ImmutablePureComponent { - - static propTypes = { - account: ImmutablePropTypes.record.isRequired, - intl: PropTypes.object.isRequired, - onFollow: PropTypes.func.isRequired, - onBlock: PropTypes.func.isRequired, - onMute: PropTypes.func.isRequired, - onDismiss: PropTypes.func, - }; - - handleMouseEnter = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-original'); - } - }; - - handleMouseLeave = ({ currentTarget }) => { - if (autoPlayGif) { - return; - } - - const emojis = currentTarget.querySelectorAll('.custom-emoji'); - - for (var i = 0; i < emojis.length; i++) { - let emoji = emojis[i]; - emoji.src = emoji.getAttribute('data-static'); - } - }; - - handleFollow = () => { - this.props.onFollow(this.props.account); - }; - - handleBlock = () => { - this.props.onBlock(this.props.account); - }; - - handleMute = () => { - this.props.onMute(this.props.account); - }; - - handleEditProfile = () => { - window.open('/settings/profile', '_blank'); - }; - - handleDismiss = (e) => { - const { account, onDismiss } = this.props; - onDismiss(account.get('id')); - - e.preventDefault(); - e.stopPropagation(); - }; - - render() { - const { account, intl } = this.props; - - let actionBtn; - - if (me !== account.get('id')) { - if (!account.get('relationship')) { // Wait until the relationship is loaded - actionBtn = ''; - } else if (account.getIn(['relationship', 'requested'])) { - actionBtn = - ); -}; - -BackButton.propTypes = { - onlyIcon: PropTypes.bool, -}; - -class ColumnHeader extends PureComponent { - static propTypes = { - identity: identityContextPropShape, - intl: PropTypes.object.isRequired, - title: PropTypes.node, - icon: PropTypes.string, - iconComponent: PropTypes.func, - active: PropTypes.bool, - multiColumn: PropTypes.bool, - extraButton: PropTypes.node, - showBackButton: PropTypes.bool, - children: PropTypes.node, - pinned: PropTypes.bool, - placeholder: PropTypes.bool, - onPin: PropTypes.func, - onMove: PropTypes.func, - onClick: PropTypes.func, - appendContent: PropTypes.node, - collapseIssues: PropTypes.bool, - ...WithRouterPropTypes, - }; - - state = { - collapsed: true, - animating: false, - }; - - handleToggleClick = (e) => { - e.stopPropagation(); - this.setState({ collapsed: !this.state.collapsed, animating: true }); - }; - - handleTitleClick = () => { - this.props.onClick?.(); - }; - - handleMoveLeft = () => { - this.props.onMove(-1); - }; - - handleMoveRight = () => { - this.props.onMove(1); - }; - - handleTransitionEnd = () => { - this.setState({ animating: false }); - }; - - handlePin = () => { - if (!this.props.pinned) { - this.props.history.replace('/'); - } - - this.props.onPin(); - }; - - render () { - const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props; - const { collapsed, animating } = this.state; - - const wrapperClassName = classNames('column-header__wrapper', { - 'active': active, - }); - - const buttonClassName = classNames('column-header', { - 'active': active, - }); - - const collapsibleClassName = classNames('column-header__collapsible', { - 'collapsed': collapsed, - 'animating': animating, - }); - - const collapsibleButtonClassName = classNames('column-header__button', { - 'active': !collapsed, - }); - - let extraContent, pinButton, moveButtons, backButton, collapseButton; - - if (children) { - extraContent = ( -
- {children} -
- ); - } - - if (multiColumn && pinned) { - pinButton = ; - - moveButtons = ( -
- - -
- ); - } else if (multiColumn && this.props.onPin) { - pinButton = ; - } - - if (history && !pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) { - backButton = ; - } - - const collapsedContent = [ - extraContent, - ]; - - if (multiColumn) { - collapsedContent.push( -
- {pinButton} - {moveButtons} -
- ); - } - - if (this.props.identity.signedIn && (children || (multiColumn && this.props.onPin))) { - collapseButton = ( - - ); - } - - const hasTitle = (icon || iconComponent) && title; - - const component = ( -
-

- {hasTitle && ( - <> - {backButton} - - - - )} - - {!hasTitle && backButton} - -
- {extraButton} - {collapseButton} -
-

- -
-
- {(!collapsed || animating) && collapsedContent} -
-
- - {appendContent} -
- ); - - if (placeholder) { - return component; - } else { - return ( - {component} - ); - } - } - -} - -export default injectIntl(withIdentity(withRouter(ColumnHeader))); diff --git a/app/javascript/flavours/glitch/components/column_header.tsx b/app/javascript/flavours/glitch/components/column_header.tsx new file mode 100644 index 0000000000..9bd1559904 --- /dev/null +++ b/app/javascript/flavours/glitch/components/column_header.tsx @@ -0,0 +1,301 @@ +import { useCallback, useState } from 'react'; + +import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; + +import classNames from 'classnames'; + +import AddIcon from '@/material-icons/400-24px/add.svg?react'; +import ArrowBackIcon from '@/material-icons/400-24px/arrow_back.svg?react'; +import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; +import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; +import SettingsIcon from '@/material-icons/400-24px/settings.svg?react'; +import type { IconProp } from 'flavours/glitch/components/icon'; +import { Icon } from 'flavours/glitch/components/icon'; +import { ButtonInTabsBar } from 'flavours/glitch/features/ui/util/columns_context'; +import { useIdentity } from 'flavours/glitch/identity_context'; + +import { useAppHistory } from './router'; + +const messages = defineMessages({ + show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' }, + hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' }, + moveLeft: { + id: 'column_header.moveLeft_settings', + defaultMessage: 'Move column to the left', + }, + moveRight: { + id: 'column_header.moveRight_settings', + defaultMessage: 'Move column to the right', + }, + back: { id: 'column_back_button.label', defaultMessage: 'Back' }, +}); + +const BackButton: React.FC<{ + onlyIcon: boolean; +}> = ({ onlyIcon }) => { + const history = useAppHistory(); + const intl = useIntl(); + + const handleBackClick = useCallback(() => { + if (history.location.state?.fromMastodon) { + history.goBack(); + } else { + history.push('/'); + } + }, [history]); + + return ( + + ); +}; + +export interface Props { + title?: string; + icon?: string; + iconComponent?: IconProp; + active?: boolean; + children?: React.ReactNode; + pinned?: boolean; + multiColumn?: boolean; + extraButton?: React.ReactNode; + showBackButton?: boolean; + placeholder?: boolean; + appendContent?: React.ReactNode; + collapseIssues?: boolean; + onClick?: () => void; + onMove?: (arg0: number) => void; + onPin?: () => void; +} + +export const ColumnHeader: React.FC = ({ + title, + icon, + iconComponent, + active, + children, + pinned, + multiColumn, + extraButton, + showBackButton, + placeholder, + appendContent, + collapseIssues, + onClick, + onMove, + onPin, +}) => { + const intl = useIntl(); + const { signedIn } = useIdentity(); + const history = useAppHistory(); + const [collapsed, setCollapsed] = useState(true); + const [animating, setAnimating] = useState(false); + + const handleToggleClick = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + setCollapsed((value) => !value); + setAnimating(true); + }, + [setCollapsed, setAnimating], + ); + + const handleTitleClick = useCallback(() => { + onClick?.(); + }, [onClick]); + + const handleMoveLeft = useCallback(() => { + onMove?.(-1); + }, [onMove]); + + const handleMoveRight = useCallback(() => { + onMove?.(1); + }, [onMove]); + + const handleTransitionEnd = useCallback(() => { + setAnimating(false); + }, [setAnimating]); + + const handlePin = useCallback(() => { + if (!pinned) { + history.replace('/'); + } + + onPin?.(); + }, [history, pinned, onPin]); + + const wrapperClassName = classNames('column-header__wrapper', { + active, + }); + + const buttonClassName = classNames('column-header', { + active, + }); + + const collapsibleClassName = classNames('column-header__collapsible', { + collapsed, + animating, + }); + + const collapsibleButtonClassName = classNames('column-header__button', { + active: !collapsed, + }); + + let extraContent, pinButton, moveButtons, backButton, collapseButton; + + if (children) { + extraContent = ( +
+ {children} +
+ ); + } + + if (multiColumn && pinned) { + pinButton = ( + + ); + + moveButtons = ( +
+ + +
+ ); + } else if (multiColumn && onPin) { + pinButton = ( + + ); + } + + if ( + !pinned && + ((multiColumn && history.location.state?.fromMastodon) || showBackButton) + ) { + backButton = ; + } + + const collapsedContent = [extraContent]; + + if (multiColumn) { + collapsedContent.push( +
+ {pinButton} + {moveButtons} +
, + ); + } + + if (signedIn && (children || (multiColumn && onPin))) { + collapseButton = ( + + ); + } + + const hasIcon = icon && iconComponent; + const hasTitle = hasIcon && title; + + const component = ( +
+

+ {hasTitle && ( + <> + {backButton} + + + + )} + + {!hasTitle && backButton} + +
+ {extraButton} + {collapseButton} +
+

+ +
+
+ {(!collapsed || animating) && collapsedContent} +
+
+ + {appendContent} +
+ ); + + if (placeholder) { + return component; + } else { + return {component}; + } +}; + +// eslint-disable-next-line import/no-default-export +export default ColumnHeader; diff --git a/app/javascript/flavours/glitch/features/directory/index.tsx b/app/javascript/flavours/glitch/features/directory/index.tsx index ade047656e..d58ef2eab0 100644 --- a/app/javascript/flavours/glitch/features/directory/index.tsx +++ b/app/javascript/flavours/glitch/features/directory/index.tsx @@ -14,9 +14,12 @@ import { moveColumn, changeColumnParams, } from 'flavours/glitch/actions/columns'; -import { fetchDirectory, expandDirectory } from 'flavours/glitch/actions/directory'; +import { + fetchDirectory, + expandDirectory, +} from 'flavours/glitch/actions/directory'; import Column from 'flavours/glitch/components/column'; -import ColumnHeader from 'flavours/glitch/components/column_header'; +import { ColumnHeader } from 'flavours/glitch/components/column_header'; import { LoadMore } from 'flavours/glitch/components/load_more'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import { RadioButton } from 'flavours/glitch/components/radio_button'; @@ -86,7 +89,7 @@ export const Directory: React.FC<{ }, [dispatch, order, local]); const handleMove = useCallback( - (dir: string) => { + (dir: number) => { dispatch(moveColumn(columnId, dir)); }, [dispatch, columnId], @@ -185,7 +188,6 @@ export const Directory: React.FC<{ label={intl.formatMessage(messages.title)} > = (otherProps) => ( +export const ColumnLoading: React.FC = (otherProps) => (
From 4179f5fcf32a2aaa83c1eb564f60196722825669 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 27 Jun 2024 15:17:18 +0200 Subject: [PATCH 31/34] [Glitch] Change `author_account` to be `authors` in REST API Port 096057b845f27fd6090915b22c8688a6eeb22e28 to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/importer/index.js | 4 ++-- .../flavours/glitch/actions/importer/normalizer.js | 11 +++++++++-- app/javascript/flavours/glitch/actions/trends.js | 2 +- app/javascript/flavours/glitch/api_types/statuses.ts | 7 +++++++ .../features/explore/components/author_link.jsx | 4 ++++ .../flavours/glitch/features/explore/links.jsx | 2 +- .../glitch/features/status/components/card.jsx | 4 ++-- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/importer/index.js b/app/javascript/flavours/glitch/actions/importer/index.js index 63a28eb0ed..7341ba8550 100644 --- a/app/javascript/flavours/glitch/actions/importer/index.js +++ b/app/javascript/flavours/glitch/actions/importer/index.js @@ -76,8 +76,8 @@ export function importFetchedStatuses(statuses) { pushUnique(polls, normalizePoll(status.poll, getState().getIn(['polls', status.poll.id]))); } - if (status.card?.author_account) { - pushUnique(accounts, status.card.author_account); + if (status.card) { + status.card.authors.forEach(author => author.account && pushUnique(accounts, author.account)); } } diff --git a/app/javascript/flavours/glitch/actions/importer/normalizer.js b/app/javascript/flavours/glitch/actions/importer/normalizer.js index 8f5bda89b5..5f10c8d889 100644 --- a/app/javascript/flavours/glitch/actions/importer/normalizer.js +++ b/app/javascript/flavours/glitch/actions/importer/normalizer.js @@ -36,8 +36,15 @@ export function normalizeStatus(status, normalOldStatus, settings) { normalStatus.poll = status.poll.id; } - if (status.card?.author_account) { - normalStatus.card = { ...status.card, author_account: status.card.author_account.id }; + if (status.card) { + normalStatus.card = { + ...status.card, + authors: status.card.authors.map(author => ({ + ...author, + accountId: author.account?.id, + account: undefined, + })), + }; } if (status.filtered) { diff --git a/app/javascript/flavours/glitch/actions/trends.js b/app/javascript/flavours/glitch/actions/trends.js index 01089fccbb..0bdf17a5d2 100644 --- a/app/javascript/flavours/glitch/actions/trends.js +++ b/app/javascript/flavours/glitch/actions/trends.js @@ -51,7 +51,7 @@ export const fetchTrendingLinks = () => (dispatch) => { api() .get('/api/v1/trends/links', { params: { limit: 20 } }) .then(({ data }) => { - dispatch(importFetchedAccounts(data.map(link => link.author_account).filter(account => !!account))); + dispatch(importFetchedAccounts(data.flatMap(link => link.authors.map(author => author.account)).filter(account => !!account))); dispatch(fetchTrendingLinksSuccess(data)); }) .catch(err => dispatch(fetchTrendingLinksFail(err))); diff --git a/app/javascript/flavours/glitch/api_types/statuses.ts b/app/javascript/flavours/glitch/api_types/statuses.ts index d63441873d..261d600305 100644 --- a/app/javascript/flavours/glitch/api_types/statuses.ts +++ b/app/javascript/flavours/glitch/api_types/statuses.ts @@ -30,6 +30,12 @@ export interface ApiMentionJSON { acct: string; } +export interface ApiPreviewCardAuthorJSON { + name: string; + url: string; + account?: ApiAccountJSON; +} + export interface ApiPreviewCardJSON { url: string; title: string; @@ -48,6 +54,7 @@ export interface ApiPreviewCardJSON { embed_url: string; blurhash: string; published_at: string; + authors: ApiPreviewCardAuthorJSON[]; } export interface ApiStatusJSON { diff --git a/app/javascript/flavours/glitch/features/explore/components/author_link.jsx b/app/javascript/flavours/glitch/features/explore/components/author_link.jsx index 94061c0092..ae527db33c 100644 --- a/app/javascript/flavours/glitch/features/explore/components/author_link.jsx +++ b/app/javascript/flavours/glitch/features/explore/components/author_link.jsx @@ -7,6 +7,10 @@ import { useAppSelector } from 'flavours/glitch/store'; export const AuthorLink = ({ accountId }) => { const account = useAppSelector(state => state.getIn(['accounts', accountId])); + if (!account) { + return null; + } + return ( diff --git a/app/javascript/flavours/glitch/features/explore/links.jsx b/app/javascript/flavours/glitch/features/explore/links.jsx index dc15030f72..b5eb9c9d4f 100644 --- a/app/javascript/flavours/glitch/features/explore/links.jsx +++ b/app/javascript/flavours/glitch/features/explore/links.jsx @@ -75,7 +75,7 @@ class Links extends PureComponent { publisher={link.get('provider_name')} publishedAt={link.get('published_at')} author={link.get('author_name')} - authorAccount={link.getIn(['author_account', 'id'])} + authorAccount={link.getIn(['authors', 0, 'account', 'id'])} sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1} thumbnail={link.get('image')} thumbnailDescription={link.get('image_description')} diff --git a/app/javascript/flavours/glitch/features/status/components/card.jsx b/app/javascript/flavours/glitch/features/status/components/card.jsx index c9b0f7ebaf..0d315cbbf1 100644 --- a/app/javascript/flavours/glitch/features/status/components/card.jsx +++ b/app/javascript/flavours/glitch/features/status/components/card.jsx @@ -127,7 +127,7 @@ export default class Card extends PureComponent { const interactive = card.get('type') === 'video'; const language = card.get('language') || ''; const largeImage = (card.get('image')?.length > 0 && card.get('width') > card.get('height')) || interactive; - const showAuthor = !!card.get('author_account'); + const showAuthor = !!card.getIn(['authors', 0, 'accountId']); const description = (
@@ -233,7 +233,7 @@ export default class Card extends PureComponent { {description} - {showAuthor && } + {showAuthor && } ); } From 98185247b85cb2fa6b0dc9c5f5be7d22f3db7a24 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 26 Jun 2024 21:33:38 +0200 Subject: [PATCH 32/34] [Glitch] Add hover cards in web UI Port e89317d4c1da991b728b6d4a21671ed33f057cc4 Co-authored-by: Renaud Chaput Signed-off-by: Claire --- .../glitch/components/account_bio.tsx | 20 ++ .../glitch/components/account_fields.tsx | 42 +++++ .../glitch/components/follow_button.tsx | 90 +++++++++ .../glitch/components/hover_card_account.tsx | 78 ++++++++ .../components/hover_card_controller.tsx | 117 ++++++++++++ .../glitch/components/status_content.jsx | 3 +- .../glitch/components/status_header.jsx | 1 + .../glitch/components/status_prepend.jsx | 1 + .../explore/components/author_link.jsx | 2 +- .../features/explore/components/card.jsx | 17 +- .../components/inline_follow_suggestions.jsx | 15 +- .../notifications/components/notification.jsx | 2 + .../status/components/detailed_status.jsx | 2 +- .../flavours/glitch/features/ui/index.jsx | 2 + .../flavours/glitch/hooks/useLinks.ts | 61 ++++++ .../flavours/glitch/hooks/useTimeout.ts | 29 +++ .../flavours/glitch/styles/components.scss | 178 +++++++++++++++++- .../styles/mastodon-light/variables.scss | 2 + 18 files changed, 628 insertions(+), 34 deletions(-) create mode 100644 app/javascript/flavours/glitch/components/account_bio.tsx create mode 100644 app/javascript/flavours/glitch/components/account_fields.tsx create mode 100644 app/javascript/flavours/glitch/components/follow_button.tsx create mode 100644 app/javascript/flavours/glitch/components/hover_card_account.tsx create mode 100644 app/javascript/flavours/glitch/components/hover_card_controller.tsx create mode 100644 app/javascript/flavours/glitch/hooks/useLinks.ts create mode 100644 app/javascript/flavours/glitch/hooks/useTimeout.ts diff --git a/app/javascript/flavours/glitch/components/account_bio.tsx b/app/javascript/flavours/glitch/components/account_bio.tsx new file mode 100644 index 0000000000..567a2374c2 --- /dev/null +++ b/app/javascript/flavours/glitch/components/account_bio.tsx @@ -0,0 +1,20 @@ +import { useLinks } from 'flavours/glitch/hooks/useLinks'; + +export const AccountBio: React.FC<{ + note: string; + className: string; +}> = ({ note, className }) => { + const handleClick = useLinks(); + + if (note.length === 0 || note === '

') { + return null; + } + + return ( +
+ ); +}; diff --git a/app/javascript/flavours/glitch/components/account_fields.tsx b/app/javascript/flavours/glitch/components/account_fields.tsx new file mode 100644 index 0000000000..768eb1fa4b --- /dev/null +++ b/app/javascript/flavours/glitch/components/account_fields.tsx @@ -0,0 +1,42 @@ +import classNames from 'classnames'; + +import CheckIcon from '@/material-icons/400-24px/check.svg?react'; +import { Icon } from 'flavours/glitch/components/icon'; +import { useLinks } from 'flavours/glitch/hooks/useLinks'; +import type { Account } from 'flavours/glitch/models/account'; + +export const AccountFields: React.FC<{ + fields: Account['fields']; + limit: number; +}> = ({ fields, limit = -1 }) => { + const handleClick = useLinks(); + + if (fields.size === 0) { + return null; + } + + return ( +
+ {fields.take(limit).map((pair, i) => ( +
+
+ +
+ {pair.get('verified_at') && ( + + )} + +
+
+ ))} +
+ ); +}; diff --git a/app/javascript/flavours/glitch/components/follow_button.tsx b/app/javascript/flavours/glitch/components/follow_button.tsx new file mode 100644 index 0000000000..664ac86000 --- /dev/null +++ b/app/javascript/flavours/glitch/components/follow_button.tsx @@ -0,0 +1,90 @@ +import { useCallback, useEffect } from 'react'; + +import { useIntl, defineMessages } from 'react-intl'; + +import { + fetchRelationships, + followAccount, + unfollowAccount, +} from 'flavours/glitch/actions/accounts'; +import { Button } from 'flavours/glitch/components/button'; +import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; +import { me } from 'flavours/glitch/initial_state'; +import { useAppDispatch, useAppSelector } from 'flavours/glitch/store'; + +const messages = defineMessages({ + unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, + follow: { id: 'account.follow', defaultMessage: 'Follow' }, + followBack: { id: 'account.follow_back', defaultMessage: 'Follow back' }, + cancel_follow_request: { + id: 'account.cancel_follow_request', + defaultMessage: 'Withdraw follow request', + }, + edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, +}); + +export const FollowButton: React.FC<{ + accountId: string; +}> = ({ accountId }) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const relationship = useAppSelector((state) => + state.relationships.get(accountId), + ); + const following = relationship?.following || relationship?.requested; + + useEffect(() => { + dispatch(fetchRelationships([accountId])); + }, [dispatch, accountId]); + + const handleClick = useCallback(() => { + if (!relationship) return; + if (accountId === me) { + return; + } else if (relationship.following || relationship.requested) { + dispatch(unfollowAccount(accountId)); + } else { + dispatch(followAccount(accountId)); + } + }, [dispatch, accountId, relationship]); + + let label; + + if (accountId === me) { + label = intl.formatMessage(messages.edit_profile); + } else if (!relationship) { + label = ; + } else if (relationship.requested) { + label = intl.formatMessage(messages.cancel_follow_request); + } else if (!relationship.following && relationship.followed_by) { + label = intl.formatMessage(messages.followBack); + } else if (relationship.following) { + label = intl.formatMessage(messages.unfollow); + } else { + label = intl.formatMessage(messages.follow); + } + + if (accountId === me) { + return ( + + {label} + + ); + } + + return ( + + ); +}; diff --git a/app/javascript/flavours/glitch/components/hover_card_account.tsx b/app/javascript/flavours/glitch/components/hover_card_account.tsx new file mode 100644 index 0000000000..a62128e17b --- /dev/null +++ b/app/javascript/flavours/glitch/components/hover_card_account.tsx @@ -0,0 +1,78 @@ +import { useEffect, forwardRef } from 'react'; + +import classNames from 'classnames'; + +import { fetchAccount } from 'flavours/glitch/actions/accounts'; +import { AccountBio } from 'flavours/glitch/components/account_bio'; +import { AccountFields } from 'flavours/glitch/components/account_fields'; +import { Avatar } from 'flavours/glitch/components/avatar'; +import { FollowersCounter } from 'flavours/glitch/components/counters'; +import { DisplayName } from 'flavours/glitch/components/display_name'; +import { FollowButton } from 'flavours/glitch/components/follow_button'; +import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; +import { Permalink } from 'flavours/glitch/components/permalink'; +import { ShortNumber } from 'flavours/glitch/components/short_number'; +import { domain } from 'flavours/glitch/initial_state'; +import { useAppSelector, useAppDispatch } from 'flavours/glitch/store'; + +export const HoverCardAccount = forwardRef< + HTMLDivElement, + { accountId: string } +>(({ accountId }, ref) => { + const dispatch = useAppDispatch(); + + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); + + useEffect(() => { + if (accountId && !account) { + dispatch(fetchAccount(accountId)); + } + }, [dispatch, accountId, account]); + + return ( + + ); +}); + +HoverCardAccount.displayName = 'HoverCardAccount'; diff --git a/app/javascript/flavours/glitch/components/hover_card_controller.tsx b/app/javascript/flavours/glitch/components/hover_card_controller.tsx new file mode 100644 index 0000000000..6e11d28381 --- /dev/null +++ b/app/javascript/flavours/glitch/components/hover_card_controller.tsx @@ -0,0 +1,117 @@ +import { useEffect, useRef, useState, useCallback } from 'react'; + +import { useLocation } from 'react-router-dom'; + +import Overlay from 'react-overlays/Overlay'; +import type { + OffsetValue, + UsePopperOptions, +} from 'react-overlays/esm/usePopper'; + +import { HoverCardAccount } from 'flavours/glitch/components/hover_card_account'; +import { useTimeout } from 'flavours/glitch/hooks/useTimeout'; + +const offset = [-12, 4] as OffsetValue; +const enterDelay = 650; +const leaveDelay = 250; +const popperConfig = { strategy: 'fixed' } as UsePopperOptions; + +const isHoverCardAnchor = (element: HTMLElement) => + element.matches('[data-hover-card-account]'); + +export const HoverCardController: React.FC = () => { + const [open, setOpen] = useState(false); + const [accountId, setAccountId] = useState(); + const [anchor, setAnchor] = useState(null); + const cardRef = useRef(null); + const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout(); + const [setEnterTimeout, cancelEnterTimeout] = useTimeout(); + const location = useLocation(); + + const handleAnchorMouseEnter = useCallback( + (e: MouseEvent) => { + const { target } = e; + + if (target instanceof HTMLElement && isHoverCardAnchor(target)) { + cancelLeaveTimeout(); + + setEnterTimeout(() => { + target.setAttribute('aria-describedby', 'hover-card'); + setAnchor(target); + setOpen(true); + setAccountId( + target.getAttribute('data-hover-card-account') ?? undefined, + ); + }, enterDelay); + } + + if (target === cardRef.current?.parentNode) { + cancelLeaveTimeout(); + } + }, + [cancelLeaveTimeout, setEnterTimeout, setOpen, setAccountId, setAnchor], + ); + + const handleAnchorMouseLeave = useCallback( + (e: MouseEvent) => { + if (e.target === anchor || e.target === cardRef.current?.parentNode) { + cancelEnterTimeout(); + + setLeaveTimeout(() => { + anchor?.removeAttribute('aria-describedby'); + setOpen(false); + setAnchor(null); + }, leaveDelay); + } + }, + [cancelEnterTimeout, setLeaveTimeout, setOpen, setAnchor, anchor], + ); + + const handleClose = useCallback(() => { + cancelEnterTimeout(); + cancelLeaveTimeout(); + setOpen(false); + setAnchor(null); + }, [cancelEnterTimeout, cancelLeaveTimeout, setOpen, setAnchor]); + + useEffect(() => { + handleClose(); + }, [handleClose, location]); + + useEffect(() => { + document.body.addEventListener('mouseenter', handleAnchorMouseEnter, { + passive: true, + capture: true, + }); + document.body.addEventListener('mouseleave', handleAnchorMouseLeave, { + passive: true, + capture: true, + }); + + return () => { + document.body.removeEventListener('mouseenter', handleAnchorMouseEnter); + document.body.removeEventListener('mouseleave', handleAnchorMouseLeave); + }; + }, [handleAnchorMouseEnter, handleAnchorMouseLeave]); + + if (!accountId) return null; + + return ( + + {({ props }) => ( +
+ +
+ )} +
+ ); +}; diff --git a/app/javascript/flavours/glitch/components/status_content.jsx b/app/javascript/flavours/glitch/components/status_content.jsx index 24da69cdf2..c28f85eb72 100644 --- a/app/javascript/flavours/glitch/components/status_content.jsx +++ b/app/javascript/flavours/glitch/components/status_content.jsx @@ -181,7 +181,8 @@ class StatusContent extends PureComponent { if (mention) { link.addEventListener('click', this.onMentionClick.bind(this, mention), false); - link.setAttribute('title', `@${mention.get('acct')}`); + link.removeAttribute('title'); + link.setAttribute('data-hover-card-account', mention.get('id')); if (rewriteMentions !== 'no') { while (link.firstChild) link.removeChild(link.firstChild); link.appendChild(document.createTextNode('@')); diff --git a/app/javascript/flavours/glitch/components/status_header.jsx b/app/javascript/flavours/glitch/components/status_header.jsx index 692dca5c7b..ee4573659c 100644 --- a/app/javascript/flavours/glitch/components/status_header.jsx +++ b/app/javascript/flavours/glitch/components/status_header.jsx @@ -51,6 +51,7 @@ export default class StatusHeader extends PureComponent { target='_blank' onClick={this.handleAccountClick} rel='noopener noreferrer' + data-hover-card-account={status.getIn(['account', 'id'])} >
{statusAvatar} diff --git a/app/javascript/flavours/glitch/components/status_prepend.jsx b/app/javascript/flavours/glitch/components/status_prepend.jsx index 41902e60ba..e3bb554e2a 100644 --- a/app/javascript/flavours/glitch/components/status_prepend.jsx +++ b/app/javascript/flavours/glitch/components/status_prepend.jsx @@ -38,6 +38,7 @@ export default class StatusPrepend extends PureComponent { onClick={this.handleClick} href={account.get('url')} className='status__display-name' + data-hover-card-account={account.get('id')} > { } return ( - + diff --git a/app/javascript/flavours/glitch/features/explore/components/card.jsx b/app/javascript/flavours/glitch/features/explore/components/card.jsx index 85faa92e57..4612d25e21 100644 --- a/app/javascript/flavours/glitch/features/explore/components/card.jsx +++ b/app/javascript/flavours/glitch/features/explore/components/card.jsx @@ -8,34 +8,21 @@ import { Link } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; -import { followAccount, unfollowAccount } from 'flavours/glitch/actions/accounts'; import { dismissSuggestion } from 'flavours/glitch/actions/suggestions'; import { Avatar } from 'flavours/glitch/components/avatar'; -import { Button } from 'flavours/glitch/components/button'; import { DisplayName } from 'flavours/glitch/components/display_name'; +import { FollowButton } from 'flavours/glitch/components/follow_button'; import { IconButton } from 'flavours/glitch/components/icon_button'; import { domain } from 'flavours/glitch/initial_state'; const messages = defineMessages({ - follow: { id: 'account.follow', defaultMessage: 'Follow' }, - unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" }, }); export const Card = ({ id, source }) => { const intl = useIntl(); const account = useSelector(state => state.getIn(['accounts', id])); - const relationship = useSelector(state => state.getIn(['relationships', id])); const dispatch = useDispatch(); - const following = relationship?.get('following') ?? relationship?.get('requested'); - - const handleFollow = useCallback(() => { - if (following) { - dispatch(unfollowAccount(id)); - } else { - dispatch(followAccount(id)); - } - }, [id, following, dispatch]); const handleDismiss = useCallback(() => { dispatch(dismissSuggestion(id)); @@ -74,7 +61,7 @@ export const Card = ({ id, source }) => {
-
diff --git a/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.jsx b/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.jsx index 97b64a09b1..4e727a63ed 100644 --- a/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.jsx +++ b/app/javascript/flavours/glitch/features/home_timeline/components/inline_follow_suggestions.jsx @@ -12,12 +12,11 @@ import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react'; import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import CloseIcon from '@/material-icons/400-24px/close.svg?react'; import InfoIcon from '@/material-icons/400-24px/info.svg?react'; -import { followAccount, unfollowAccount } from 'flavours/glitch/actions/accounts'; import { changeSetting } from 'flavours/glitch/actions/settings'; import { fetchSuggestions, dismissSuggestion } from 'flavours/glitch/actions/suggestions'; import { Avatar } from 'flavours/glitch/components/avatar'; -import { Button } from 'flavours/glitch/components/button'; import { DisplayName } from 'flavours/glitch/components/display_name'; +import { FollowButton } from 'flavours/glitch/components/follow_button'; import { Icon } from 'flavours/glitch/components/icon'; import { IconButton } from 'flavours/glitch/components/icon_button'; import { VerifiedBadge } from 'flavours/glitch/components/verified_badge'; @@ -79,18 +78,8 @@ Source.propTypes = { const Card = ({ id, sources }) => { const intl = useIntl(); const account = useSelector(state => state.getIn(['accounts', id])); - const relationship = useSelector(state => state.getIn(['relationships', id])); const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at')); const dispatch = useDispatch(); - const following = relationship?.get('following') ?? relationship?.get('requested'); - - const handleFollow = useCallback(() => { - if (following) { - dispatch(unfollowAccount(id)); - } else { - dispatch(followAccount(id)); - } - }, [id, following, dispatch]); const handleDismiss = useCallback(() => { dispatch(dismissSuggestion(id)); @@ -109,7 +98,7 @@ const Card = ({ id, sources }) => { {firstVerifiedField ? : }
-
); }; diff --git a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx index 29593c06d8..0751258be9 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/notification.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/notification.jsx @@ -389,6 +389,7 @@ class Notification extends ImmutablePureComponent { title={targetAccount.get('acct')} to={`/@${targetAccount.get('acct')}`} dangerouslySetInnerHTML={targetDisplayNameHtml} + data-hover-card-account={targetAccount.get('id')} /> ); @@ -423,6 +424,7 @@ class Notification extends ImmutablePureComponent { title={account.get('acct')} to={`/@${account.get('acct')}`} dangerouslySetInnerHTML={displayNameHtml} + data-hover-card-account={account.get('id')} /> ); diff --git a/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx b/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx index a5704665fd..2db9fa6d3a 100644 --- a/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx +++ b/app/javascript/flavours/glitch/features/status/components/detailed_status.jsx @@ -285,7 +285,7 @@ class DetailedStatus extends ImmutablePureComponent { return (
- +
diff --git a/app/javascript/flavours/glitch/features/ui/index.jsx b/app/javascript/flavours/glitch/features/ui/index.jsx index 4a7b9ebfde..2f0bfd3355 100644 --- a/app/javascript/flavours/glitch/features/ui/index.jsx +++ b/app/javascript/flavours/glitch/features/ui/index.jsx @@ -15,6 +15,7 @@ import { HotKeys } from 'react-hotkeys'; import { changeLayout } from 'flavours/glitch/actions/app'; import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers'; import { INTRODUCTION_VERSION } from 'flavours/glitch/actions/onboarding'; +import { HoverCardController } from 'flavours/glitch/components/hover_card_controller'; import { Permalink } from 'flavours/glitch/components/permalink'; import { PictureInPicture } from 'flavours/glitch/features/picture_in_picture'; import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; @@ -648,6 +649,7 @@ class UI extends PureComponent { {layout !== 'mobile' && } + diff --git a/app/javascript/flavours/glitch/hooks/useLinks.ts b/app/javascript/flavours/glitch/hooks/useLinks.ts new file mode 100644 index 0000000000..bb988665fd --- /dev/null +++ b/app/javascript/flavours/glitch/hooks/useLinks.ts @@ -0,0 +1,61 @@ +import { useCallback } from 'react'; + +import { useHistory } from 'react-router-dom'; + +import { openURL } from 'flavours/glitch/actions/search'; +import { useAppDispatch } from 'flavours/glitch/store'; + +const isMentionClick = (element: HTMLAnchorElement) => + element.classList.contains('mention'); + +const isHashtagClick = (element: HTMLAnchorElement) => + element.textContent?.[0] === '#' || + element.previousSibling?.textContent?.endsWith('#'); + +export const useLinks = () => { + const history = useHistory(); + const dispatch = useAppDispatch(); + + const handleHashtagClick = useCallback( + (element: HTMLAnchorElement) => { + const { textContent } = element; + + if (!textContent) return; + + history.push(`/tags/${textContent.replace(/^#/, '')}`); + }, + [history], + ); + + const handleMentionClick = useCallback( + (element: HTMLAnchorElement) => { + dispatch( + openURL(element.href, history, () => { + window.location.href = element.href; + }), + ); + }, + [dispatch, history], + ); + + const handleClick = useCallback( + (e: React.MouseEvent) => { + const target = (e.target as HTMLElement).closest('a'); + + if (!target || e.button !== 0 || e.ctrlKey || e.metaKey) { + return; + } + + if (isMentionClick(target)) { + e.preventDefault(); + handleMentionClick(target); + } else if (isHashtagClick(target)) { + e.preventDefault(); + handleHashtagClick(target); + } + }, + [handleMentionClick, handleHashtagClick], + ); + + return handleClick; +}; diff --git a/app/javascript/flavours/glitch/hooks/useTimeout.ts b/app/javascript/flavours/glitch/hooks/useTimeout.ts new file mode 100644 index 0000000000..f1814ae8e3 --- /dev/null +++ b/app/javascript/flavours/glitch/hooks/useTimeout.ts @@ -0,0 +1,29 @@ +import { useRef, useCallback, useEffect } from 'react'; + +export const useTimeout = () => { + const timeoutRef = useRef>(); + + const set = useCallback((callback: () => void, delay: number) => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + timeoutRef.current = setTimeout(callback, delay); + }, []); + + const cancel = useCallback(() => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = undefined; + } + }, []); + + useEffect( + () => () => { + cancel(); + }, + [cancel], + ); + + return [set, cancel] as const; +}; diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index 9980f87adc..11f06dd010 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -120,8 +120,27 @@ text-decoration: none; } - &:disabled { - opacity: 0.5; + &.button--destructive { + &:active, + &:focus, + &:hover { + border-color: $ui-button-destructive-focus-background-color; + color: $ui-button-destructive-focus-background-color; + } + } + + &:disabled, + &.disabled { + opacity: 0.7; + border-color: $ui-primary-color; + color: $ui-primary-color; + + &:active, + &:focus, + &:hover { + border-color: $ui-primary-color; + color: $ui-primary-color; + } } } @@ -2629,7 +2648,7 @@ a.account__display-name { } .dropdown-animation { - animation: dropdown 150ms cubic-bezier(0.1, 0.7, 0.1, 1); + animation: dropdown 250ms cubic-bezier(0.1, 0.7, 0.1, 1); @keyframes dropdown { from { @@ -10908,3 +10927,156 @@ noscript { } } } + +.hover-card-controller[data-popper-reference-hidden='true'] { + opacity: 0; + pointer-events: none; +} + +.hover-card { + box-shadow: var(--dropdown-shadow); + background: var(--modal-background-color); + backdrop-filter: var(--background-filter); + border: 1px solid var(--modal-border-color); + border-radius: 8px; + padding: 16px; + width: 270px; + display: flex; + flex-direction: column; + gap: 12px; + + &--loading { + position: relative; + min-height: 100px; + } + + &__name { + display: flex; + gap: 12px; + text-decoration: none; + color: inherit; + } + + &__number { + font-size: 15px; + line-height: 22px; + color: $secondary-text-color; + + strong { + font-weight: 700; + } + } + + &__text-row { + display: flex; + flex-direction: column; + gap: 8px; + } + + &__bio { + color: $secondary-text-color; + font-size: 14px; + line-height: 20px; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + max-height: 2 * 20px; + overflow: hidden; + + p { + margin-bottom: 0; + } + + a { + color: inherit; + text-decoration: underline; + + &:hover, + &:focus, + &:active { + text-decoration: none; + } + } + } + + .display-name { + font-size: 15px; + line-height: 22px; + + bdi { + font-weight: 500; + color: $primary-text-color; + } + + &__account { + display: block; + color: $dark-text-color; + } + } + + .account-fields { + color: $secondary-text-color; + font-size: 14px; + line-height: 20px; + + a { + color: inherit; + text-decoration: none; + + &:focus, + &:hover, + &:active { + text-decoration: underline; + } + } + + dl { + display: flex; + align-items: center; + gap: 4px; + + dt { + flex: 0 0 auto; + color: $dark-text-color; + min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + dd { + flex: 1 1 auto; + font-weight: 500; + min-width: 0; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + + &.verified { + dd { + display: flex; + align-items: center; + gap: 4px; + overflow: hidden; + white-space: nowrap; + color: $valid-value-color; + + & > span { + overflow: hidden; + text-overflow: ellipsis; + } + + a { + font-weight: 500; + } + + .icon { + width: 16px; + height: 16px; + } + } + } + } + } +} diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss b/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss index 3cdbd9bf67..9f571b3f26 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss @@ -59,6 +59,8 @@ $emojis-requiring-inversion: 'chains'; body { --dropdown-border-color: #d9e1e8; --dropdown-background-color: #fff; + --modal-border-color: #d9e1e8; + --modal-background-color: var(--background-color-tint); --background-border-color: #d9e1e8; --background-color: #fff; --background-color-tint: rgba(255, 255, 255, 80%); From 412e5ddcbf50a5866b368623726d76e52e0102d0 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 28 Jun 2024 00:01:40 +0200 Subject: [PATCH 33/34] [Glitch] Fix follow button in hover cards not working when signed out in web UI Port ea6c455e81f9f01a64adf123d0a4f820c6e67f97 to glitch-soc Signed-off-by: Claire --- .../glitch/components/follow_button.tsx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/app/javascript/flavours/glitch/components/follow_button.tsx b/app/javascript/flavours/glitch/components/follow_button.tsx index 664ac86000..5c9cd2c067 100644 --- a/app/javascript/flavours/glitch/components/follow_button.tsx +++ b/app/javascript/flavours/glitch/components/follow_button.tsx @@ -2,11 +2,13 @@ import { useCallback, useEffect } from 'react'; import { useIntl, defineMessages } from 'react-intl'; +import { useIdentity } from '@/flavours/glitch/identity_context'; import { fetchRelationships, followAccount, unfollowAccount, } from 'flavours/glitch/actions/accounts'; +import { openModal } from 'flavours/glitch/actions/modal'; import { Button } from 'flavours/glitch/components/button'; import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator'; import { me } from 'flavours/glitch/initial_state'; @@ -28,17 +30,37 @@ export const FollowButton: React.FC<{ }> = ({ accountId }) => { const intl = useIntl(); const dispatch = useAppDispatch(); + const { signedIn } = useIdentity(); + const account = useAppSelector((state) => + accountId ? state.accounts.get(accountId) : undefined, + ); const relationship = useAppSelector((state) => state.relationships.get(accountId), ); const following = relationship?.following || relationship?.requested; useEffect(() => { - dispatch(fetchRelationships([accountId])); - }, [dispatch, accountId]); + if (accountId && signedIn) { + dispatch(fetchRelationships([accountId])); + } + }, [dispatch, accountId, signedIn]); const handleClick = useCallback(() => { + if (!signedIn) { + dispatch( + openModal({ + modalType: 'INTERACTION', + modalProps: { + type: 'follow', + accountId: accountId, + url: account?.url, + }, + }), + ); + } + if (!relationship) return; + if (accountId === me) { return; } else if (relationship.following || relationship.requested) { @@ -46,11 +68,13 @@ export const FollowButton: React.FC<{ } else { dispatch(followAccount(accountId)); } - }, [dispatch, accountId, relationship]); + }, [dispatch, accountId, relationship, account, signedIn]); let label; - if (accountId === me) { + if (!signedIn) { + label = intl.formatMessage(messages.follow); + } else if (accountId === me) { label = intl.formatMessage(messages.edit_profile); } else if (!relationship) { label = ; From 935b955b156f6313e1a4555dbb7b0661c2de1e0a Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 30 Jun 2024 21:48:30 +0200 Subject: [PATCH 34/34] Temporarily disable hover cards --- app/javascript/flavours/glitch/features/ui/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/features/ui/index.jsx b/app/javascript/flavours/glitch/features/ui/index.jsx index 2f0bfd3355..9fb4a784b3 100644 --- a/app/javascript/flavours/glitch/features/ui/index.jsx +++ b/app/javascript/flavours/glitch/features/ui/index.jsx @@ -649,7 +649,7 @@ class UI extends PureComponent { {layout !== 'mobile' && } - + {/* Temporarily disabled while upstream improves the issue */ null && }