mirror of
https://github.com/mastodon/mastodon.git
synced 2025-07-22 12:18:16 +00:00
Compare commits
101 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
be3dc5b508 | ||
![]() |
ae13063460 | ||
![]() |
1ed58aaaf2 | ||
![]() |
bf17895d19 | ||
![]() |
20b3c43dde | ||
![]() |
ee21f72211 | ||
![]() |
4de5cbd6f5 | ||
![]() |
fab95b8dae | ||
![]() |
4d2655490c | ||
![]() |
6bb4113d0a | ||
![]() |
3e76f01db4 | ||
![]() |
cf580d8c90 | ||
![]() |
dbd0c3cbd9 | ||
![]() |
3771f9e04b | ||
![]() |
a842b14c84 | ||
![]() |
138746bdcc | ||
![]() |
9e6a9efe10 | ||
![]() |
19626ad89f | ||
![]() |
7e2d92284c | ||
![]() |
20fb6bd788 | ||
![]() |
faffb73cbd | ||
![]() |
02a4e30594 | ||
![]() |
f10b522f0c | ||
![]() |
331599fa2b | ||
![]() |
558b9c90a6 | ||
![]() |
7d2dda97b3 | ||
![]() |
74fc4dbacf | ||
![]() |
07912a1cb7 | ||
![]() |
d36bf3b6fb | ||
![]() |
594976a538 | ||
![]() |
0efb889a9c | ||
![]() |
c0eabe289b | ||
![]() |
5bbc3c5ebb | ||
![]() |
d5e2cf5d3c | ||
![]() |
82a6ff091f | ||
![]() |
4b8e60682d | ||
![]() |
6c2db9b1cf | ||
![]() |
30344d6abf | ||
![]() |
1637297085 | ||
![]() |
dec1fb71f4 | ||
![]() |
7273f6c03c | ||
![]() |
a3ffd2edf8 | ||
![]() |
a2c5eace88 | ||
![]() |
a643d9d498 | ||
![]() |
3b52dca405 | ||
![]() |
853a0c466e | ||
![]() |
94bceb8683 | ||
![]() |
88b0f3a172 | ||
![]() |
b69b5ba775 | ||
![]() |
c442589593 | ||
![]() |
28633a504a | ||
![]() |
ad78701b6f | ||
![]() |
1496488771 | ||
![]() |
dd3d958e75 | ||
![]() |
b363a3651d | ||
![]() |
86645fc14c | ||
![]() |
f9beecb343 | ||
![]() |
4ecfbd3920 | ||
![]() |
a315934314 | ||
![]() |
e9170e2de1 | ||
![]() |
5cfc1fabcf | ||
![]() |
786b12e379 | ||
![]() |
e7c5c25de8 | ||
![]() |
a1e8813522 | ||
![]() |
76c1446416 | ||
![]() |
8bd2c87399 | ||
![]() |
1e2d77f2c7 | ||
![]() |
fb6c22f5c2 | ||
![]() |
f7259f625f | ||
![]() |
b628a98d32 | ||
![]() |
d8fa807998 | ||
![]() |
ef66d8379c | ||
![]() |
8ee6cee36e | ||
![]() |
71b2120e5c | ||
![]() |
b10078633c | ||
![]() |
b5eebd4d2b | ||
![]() |
fdefc4d2b4 | ||
![]() |
f6b2609353 | ||
![]() |
bdffdcb12f | ||
![]() |
1ebb87a6a8 | ||
![]() |
83660ee381 | ||
![]() |
1fa72d6c44 | ||
![]() |
5a7c0d42f7 | ||
![]() |
e8d2432e6a | ||
![]() |
2af17adc34 | ||
![]() |
e97f43399b | ||
![]() |
c66c5fd73d | ||
![]() |
3c0767f543 | ||
![]() |
70cd1fdc63 | ||
![]() |
39028dde40 | ||
![]() |
6e39b5ef04 | ||
![]() |
49db8a9662 | ||
![]() |
2cfa6cb0e0 | ||
![]() |
1ae3510ede | ||
![]() |
6f1135d763 | ||
![]() |
52bc2f64f4 | ||
![]() |
b1375328e1 | ||
![]() |
9443e2cc4b | ||
![]() |
3a533c6c8d | ||
![]() |
c047014214 | ||
![]() |
68b05e994f |
2
.github/ISSUE_TEMPLATE/1.web_bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/1.web_bug_report.yml
vendored
|
@ -1,6 +1,6 @@
|
||||||
name: Bug Report (Web Interface)
|
name: Bug Report (Web Interface)
|
||||||
description: There is a problem using Mastodon's web interface.
|
description: There is a problem using Mastodon's web interface.
|
||||||
labels: ['status/to triage', 'area/web interface']
|
labels: ['area/web interface']
|
||||||
type: Bug
|
type: Bug
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
name: Bug Report (server / API)
|
name: Bug Report (server / API)
|
||||||
description: |
|
description: |
|
||||||
There is a problem with the HTTP server, REST API, ActivityPub interaction, etc.
|
There is a problem with the HTTP server, REST API, ActivityPub interaction, etc.
|
||||||
labels: ['status/to triage']
|
|
||||||
type: 'Bug'
|
type: 'Bug'
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
|
|
1
.github/renovate.json5
vendored
1
.github/renovate.json5
vendored
|
@ -23,7 +23,6 @@
|
||||||
matchManagers: ['npm'],
|
matchManagers: ['npm'],
|
||||||
matchPackageNames: [
|
matchPackageNames: [
|
||||||
'tesseract.js', // Requires code changes
|
'tesseract.js', // Requires code changes
|
||||||
'react-hotkeys', // Requires code changes
|
|
||||||
|
|
||||||
// react-router: Requires manual upgrade
|
// react-router: Requires manual upgrade
|
||||||
'history',
|
'history',
|
||||||
|
|
4
.github/workflows/build-releases.yml
vendored
4
.github/workflows/build-releases.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
# Only tag with latest when ran against the latest stable branch
|
# Only tag with latest when ran against the latest stable branch
|
||||||
# This needs to be updated after each minor version release
|
# This needs to be updated after each minor version release
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.4.') }}
|
latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }}
|
||||||
tags: |
|
tags: |
|
||||||
type=pep440,pattern={{raw}}
|
type=pep440,pattern={{raw}}
|
||||||
type=pep440,pattern=v{{major}}.{{minor}}
|
type=pep440,pattern=v{{major}}.{{minor}}
|
||||||
|
@ -39,7 +39,7 @@ jobs:
|
||||||
# Only tag with latest when ran against the latest stable branch
|
# Only tag with latest when ran against the latest stable branch
|
||||||
# This needs to be updated after each minor version release
|
# This needs to be updated after each minor version release
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.4.') }}
|
latest=${{ startsWith(github.ref, 'refs/tags/v4.3.') }}
|
||||||
tags: |
|
tags: |
|
||||||
type=pep440,pattern={{raw}}
|
type=pep440,pattern={{raw}}
|
||||||
type=pep440,pattern=v{{major}}.{{minor}}
|
type=pep440,pattern=v{{major}}.{{minor}}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
3.4.4
|
3.4.5
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
import type { StorybookConfig } from '@storybook/react-vite';
|
import type { StorybookConfig } from '@storybook/react-vite';
|
||||||
|
|
||||||
const config: StorybookConfig = {
|
const config: StorybookConfig = {
|
||||||
|
@ -26,6 +28,12 @@ const config: StorybookConfig = {
|
||||||
'oops.png',
|
'oops.png',
|
||||||
].map((path) => ({ from: `../public/${path}`, to: `/${path}` })),
|
].map((path) => ({ from: `../public/${path}`, to: `/${path}` })),
|
||||||
],
|
],
|
||||||
|
viteFinal(config) {
|
||||||
|
// For an unknown reason, Storybook does not use the root
|
||||||
|
// from the Vite config so we need to set it manually.
|
||||||
|
config.root = resolve(__dirname, '../app/javascript');
|
||||||
|
return config;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
@ -13,7 +13,7 @@ ARG BASE_REGISTRY="docker.io"
|
||||||
|
|
||||||
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
|
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
|
||||||
# renovate: datasource=docker depName=docker.io/ruby
|
# renovate: datasource=docker depName=docker.io/ruby
|
||||||
ARG RUBY_VERSION="3.4.4"
|
ARG RUBY_VERSION="3.4.5"
|
||||||
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
||||||
# renovate: datasource=node-version depName=node
|
# renovate: datasource=node-version depName=node
|
||||||
ARG NODE_MAJOR_VERSION="22"
|
ARG NODE_MAJOR_VERSION="22"
|
||||||
|
@ -186,7 +186,7 @@ FROM build AS libvips
|
||||||
|
|
||||||
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
|
# libvips version to compile, change with [--build-arg VIPS_VERSION="8.15.2"]
|
||||||
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
|
# renovate: datasource=github-releases depName=libvips packageName=libvips/libvips
|
||||||
ARG VIPS_VERSION=8.17.0
|
ARG VIPS_VERSION=8.17.1
|
||||||
# libvips download URL, change with [--build-arg VIPS_URL="https://github.com/libvips/libvips/releases/download"]
|
# libvips download URL, change with [--build-arg VIPS_URL="https://github.com/libvips/libvips/releases/download"]
|
||||||
ARG VIPS_URL=https://github.com/libvips/libvips/releases/download
|
ARG VIPS_URL=https://github.com/libvips/libvips/releases/download
|
||||||
|
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -62,7 +62,7 @@ gem 'inline_svg'
|
||||||
gem 'irb', '~> 1.8'
|
gem 'irb', '~> 1.8'
|
||||||
gem 'kaminari', '~> 1.2'
|
gem 'kaminari', '~> 1.2'
|
||||||
gem 'link_header', '~> 0.0'
|
gem 'link_header', '~> 0.0'
|
||||||
gem 'linzer', '~> 0.7.2'
|
gem 'linzer', '~> 0.7.7'
|
||||||
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
|
||||||
gem 'mime-types', '~> 3.7.0', require: 'mime/types/columnar'
|
gem 'mime-types', '~> 3.7.0', require: 'mime/types/columnar'
|
||||||
gem 'mutex_m'
|
gem 'mutex_m'
|
||||||
|
|
104
Gemfile.lock
104
Gemfile.lock
|
@ -90,13 +90,13 @@ GEM
|
||||||
public_suffix (>= 2.0.2, < 7.0)
|
public_suffix (>= 2.0.2, < 7.0)
|
||||||
aes_key_wrap (1.1.0)
|
aes_key_wrap (1.1.0)
|
||||||
android_key_attestation (0.3.0)
|
android_key_attestation (0.3.0)
|
||||||
annotaterb (4.16.0)
|
annotaterb (4.17.0)
|
||||||
activerecord (>= 6.0.0)
|
activerecord (>= 6.0.0)
|
||||||
activesupport (>= 6.0.0)
|
activesupport (>= 6.0.0)
|
||||||
ast (2.4.3)
|
ast (2.4.3)
|
||||||
attr_required (1.0.2)
|
attr_required (1.0.2)
|
||||||
aws-eventstream (1.3.2)
|
aws-eventstream (1.4.0)
|
||||||
aws-partitions (1.1103.0)
|
aws-partitions (1.1131.0)
|
||||||
aws-sdk-core (3.215.1)
|
aws-sdk-core (3.215.1)
|
||||||
aws-eventstream (~> 1, >= 1.3.0)
|
aws-eventstream (~> 1, >= 1.3.0)
|
||||||
aws-partitions (~> 1, >= 1.992.0)
|
aws-partitions (~> 1, >= 1.992.0)
|
||||||
|
@ -109,9 +109,9 @@ GEM
|
||||||
aws-sdk-core (~> 3, >= 3.210.0)
|
aws-sdk-core (~> 3, >= 3.210.0)
|
||||||
aws-sdk-kms (~> 1)
|
aws-sdk-kms (~> 1)
|
||||||
aws-sigv4 (~> 1.5)
|
aws-sigv4 (~> 1.5)
|
||||||
aws-sigv4 (1.11.0)
|
aws-sigv4 (1.12.1)
|
||||||
aws-eventstream (~> 1, >= 1.0.2)
|
aws-eventstream (~> 1, >= 1.0.2)
|
||||||
azure-blob (0.5.8)
|
azure-blob (0.5.9.1)
|
||||||
rexml
|
rexml
|
||||||
base64 (0.3.0)
|
base64 (0.3.0)
|
||||||
bcp47_spec (0.2.1)
|
bcp47_spec (0.2.1)
|
||||||
|
@ -224,16 +224,16 @@ GEM
|
||||||
mail (~> 2.7)
|
mail (~> 2.7)
|
||||||
email_validator (2.2.4)
|
email_validator (2.2.4)
|
||||||
activemodel
|
activemodel
|
||||||
erb (5.0.1)
|
erb (5.0.2)
|
||||||
erubi (1.13.1)
|
erubi (1.13.1)
|
||||||
et-orbi (1.2.11)
|
et-orbi (1.2.11)
|
||||||
tzinfo
|
tzinfo
|
||||||
excon (1.2.5)
|
excon (1.2.8)
|
||||||
logger
|
logger
|
||||||
fabrication (3.0.0)
|
fabrication (3.0.0)
|
||||||
faker (3.5.1)
|
faker (3.5.2)
|
||||||
i18n (>= 1.8.11, < 2)
|
i18n (>= 1.8.11, < 2)
|
||||||
faraday (2.13.1)
|
faraday (2.13.2)
|
||||||
faraday-net_http (>= 2.0, < 3.5)
|
faraday-net_http (>= 2.0, < 3.5)
|
||||||
json
|
json
|
||||||
logger
|
logger
|
||||||
|
@ -241,7 +241,7 @@ GEM
|
||||||
faraday (>= 1, < 3)
|
faraday (>= 1, < 3)
|
||||||
faraday-httpclient (2.0.2)
|
faraday-httpclient (2.0.2)
|
||||||
httpclient (>= 2.2)
|
httpclient (>= 2.2)
|
||||||
faraday-net_http (3.4.0)
|
faraday-net_http (3.4.1)
|
||||||
net-http (>= 0.5.0)
|
net-http (>= 0.5.0)
|
||||||
fast_blank (1.0.1)
|
fast_blank (1.0.1)
|
||||||
fastimage (2.4.0)
|
fastimage (2.4.0)
|
||||||
|
@ -266,14 +266,14 @@ GEM
|
||||||
fog-openstack (1.1.5)
|
fog-openstack (1.1.5)
|
||||||
fog-core (~> 2.1)
|
fog-core (~> 2.1)
|
||||||
fog-json (>= 1.0)
|
fog-json (>= 1.0)
|
||||||
formatador (1.1.0)
|
formatador (1.1.1)
|
||||||
forwardable (1.3.3)
|
forwardable (1.3.3)
|
||||||
fugit (1.11.1)
|
fugit (1.11.1)
|
||||||
et-orbi (~> 1, >= 1.2.11)
|
et-orbi (~> 1, >= 1.2.11)
|
||||||
raabro (~> 1.4)
|
raabro (~> 1.4)
|
||||||
globalid (1.2.1)
|
globalid (1.2.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
google-protobuf (4.31.0)
|
google-protobuf (4.31.1)
|
||||||
bigdecimal
|
bigdecimal
|
||||||
rake (>= 13)
|
rake (>= 13)
|
||||||
googleapis-common-protos-types (1.20.0)
|
googleapis-common-protos-types (1.20.0)
|
||||||
|
@ -287,21 +287,21 @@ GEM
|
||||||
activesupport (>= 5.1)
|
activesupport (>= 5.1)
|
||||||
haml (>= 4.0.6)
|
haml (>= 4.0.6)
|
||||||
railties (>= 5.1)
|
railties (>= 5.1)
|
||||||
haml_lint (0.64.0)
|
haml_lint (0.65.0)
|
||||||
haml (>= 5.0)
|
haml (>= 5.0)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
rainbow
|
rainbow
|
||||||
rubocop (>= 1.0)
|
rubocop (>= 1.0)
|
||||||
sysexits (~> 1.1)
|
sysexits (~> 1.1)
|
||||||
hashdiff (1.1.2)
|
hashdiff (1.2.0)
|
||||||
hashie (5.0.0)
|
hashie (5.0.0)
|
||||||
hcaptcha (7.1.0)
|
hcaptcha (7.1.0)
|
||||||
json
|
json
|
||||||
highline (3.1.2)
|
highline (3.1.2)
|
||||||
reline
|
reline
|
||||||
hiredis (0.6.3)
|
hiredis (0.6.3)
|
||||||
hiredis-client (0.24.0)
|
hiredis-client (0.25.1)
|
||||||
redis-client (= 0.24.0)
|
redis-client (= 0.25.1)
|
||||||
hkdf (0.3.0)
|
hkdf (0.3.0)
|
||||||
htmlentities (4.3.4)
|
htmlentities (4.3.4)
|
||||||
http (5.3.1)
|
http (5.3.1)
|
||||||
|
@ -315,7 +315,7 @@ GEM
|
||||||
http_accept_language (2.1.1)
|
http_accept_language (2.1.1)
|
||||||
httpclient (2.9.0)
|
httpclient (2.9.0)
|
||||||
mutex_m
|
mutex_m
|
||||||
httplog (1.7.0)
|
httplog (1.7.1)
|
||||||
rack (>= 2.0)
|
rack (>= 2.0)
|
||||||
rainbow (>= 2.0.0)
|
rainbow (>= 2.0.0)
|
||||||
i18n (1.14.7)
|
i18n (1.14.7)
|
||||||
|
@ -335,7 +335,7 @@ GEM
|
||||||
inline_svg (1.10.0)
|
inline_svg (1.10.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
io-console (0.8.0)
|
io-console (0.8.1)
|
||||||
irb (1.15.2)
|
irb (1.15.2)
|
||||||
pp (>= 0.6.0)
|
pp (>= 0.6.0)
|
||||||
rdoc (>= 4.0.0)
|
rdoc (>= 4.0.0)
|
||||||
|
@ -345,7 +345,7 @@ GEM
|
||||||
azure-blob (~> 0.5.2)
|
azure-blob (~> 0.5.2)
|
||||||
hashie (~> 5.0)
|
hashie (~> 5.0)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.12.2)
|
json (2.13.0)
|
||||||
json-canonicalization (1.0.0)
|
json-canonicalization (1.0.0)
|
||||||
json-jwt (1.16.7)
|
json-jwt (1.16.7)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
|
@ -365,11 +365,11 @@ GEM
|
||||||
json-ld-preloaded (3.3.1)
|
json-ld-preloaded (3.3.1)
|
||||||
json-ld (~> 3.3)
|
json-ld (~> 3.3)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
json-schema (5.1.1)
|
json-schema (5.2.1)
|
||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
bigdecimal (~> 3.1)
|
bigdecimal (~> 3.1)
|
||||||
jsonapi-renderer (0.2.2)
|
jsonapi-renderer (0.2.2)
|
||||||
jwt (2.10.1)
|
jwt (2.10.2)
|
||||||
base64
|
base64
|
||||||
kaminari (1.2.2)
|
kaminari (1.2.2)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.1.0)
|
||||||
|
@ -403,7 +403,7 @@ GEM
|
||||||
rexml
|
rexml
|
||||||
link_header (0.0.8)
|
link_header (0.0.8)
|
||||||
lint_roller (1.1.0)
|
lint_roller (1.1.0)
|
||||||
linzer (0.7.3)
|
linzer (0.7.7)
|
||||||
cgi (~> 0.4.2)
|
cgi (~> 0.4.2)
|
||||||
forwardable (~> 1.3, >= 1.3.3)
|
forwardable (~> 1.3, >= 1.3.3)
|
||||||
logger (~> 1.7, >= 1.7.0)
|
logger (~> 1.7, >= 1.7.0)
|
||||||
|
@ -433,21 +433,21 @@ GEM
|
||||||
marcel (1.0.4)
|
marcel (1.0.4)
|
||||||
mario-redis-lock (1.2.1)
|
mario-redis-lock (1.2.1)
|
||||||
redis (>= 3.0.5)
|
redis (>= 3.0.5)
|
||||||
matrix (0.4.2)
|
matrix (0.4.3)
|
||||||
memory_profiler (1.1.0)
|
memory_profiler (1.1.0)
|
||||||
mime-types (3.7.0)
|
mime-types (3.7.0)
|
||||||
logger
|
logger
|
||||||
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
||||||
mime-types-data (3.2025.0514)
|
mime-types-data (3.2025.0715)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.9)
|
mini_portile2 (2.8.9)
|
||||||
minitest (5.25.5)
|
minitest (5.25.5)
|
||||||
msgpack (1.8.0)
|
msgpack (1.8.0)
|
||||||
multi_json (1.15.0)
|
multi_json (1.17.0)
|
||||||
mutex_m (0.3.0)
|
mutex_m (0.3.0)
|
||||||
net-http (0.6.0)
|
net-http (0.6.0)
|
||||||
uri
|
uri
|
||||||
net-imap (0.5.8)
|
net-imap (0.5.9)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.19.0)
|
net-ldap (0.19.0)
|
||||||
|
@ -458,7 +458,7 @@ GEM
|
||||||
net-smtp (0.5.1)
|
net-smtp (0.5.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.4)
|
nio4r (2.7.4)
|
||||||
nokogiri (1.18.8)
|
nokogiri (1.18.9)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.11)
|
oj (3.16.11)
|
||||||
|
@ -515,7 +515,7 @@ GEM
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-active_support (~> 0.7)
|
opentelemetry-instrumentation-active_support (~> 0.7)
|
||||||
opentelemetry-instrumentation-base (~> 0.23.0)
|
opentelemetry-instrumentation-base (~> 0.23.0)
|
||||||
opentelemetry-instrumentation-action_pack (0.12.1)
|
opentelemetry-instrumentation-action_pack (0.12.3)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.23.0)
|
opentelemetry-instrumentation-base (~> 0.23.0)
|
||||||
opentelemetry-instrumentation-rack (~> 0.21)
|
opentelemetry-instrumentation-rack (~> 0.21)
|
||||||
|
@ -553,7 +553,7 @@ GEM
|
||||||
opentelemetry-instrumentation-faraday (0.27.0)
|
opentelemetry-instrumentation-faraday (0.27.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.23.0)
|
opentelemetry-instrumentation-base (~> 0.23.0)
|
||||||
opentelemetry-instrumentation-http (0.25.0)
|
opentelemetry-instrumentation-http (0.25.1)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
opentelemetry-instrumentation-base (~> 0.23.0)
|
opentelemetry-instrumentation-base (~> 0.23.0)
|
||||||
opentelemetry-instrumentation-http_client (0.23.0)
|
opentelemetry-instrumentation-http_client (0.23.0)
|
||||||
|
@ -597,7 +597,7 @@ GEM
|
||||||
opentelemetry-semantic_conventions (1.11.0)
|
opentelemetry-semantic_conventions (1.11.0)
|
||||||
opentelemetry-api (~> 1.0)
|
opentelemetry-api (~> 1.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
ostruct (0.6.1)
|
ostruct (0.6.3)
|
||||||
ox (2.14.23)
|
ox (2.14.23)
|
||||||
bigdecimal (>= 3.0)
|
bigdecimal (>= 3.0)
|
||||||
parallel (1.27.0)
|
parallel (1.27.0)
|
||||||
|
@ -610,7 +610,7 @@ GEM
|
||||||
pg (1.5.9)
|
pg (1.5.9)
|
||||||
pghero (3.7.0)
|
pghero (3.7.0)
|
||||||
activerecord (>= 7.1)
|
activerecord (>= 7.1)
|
||||||
playwright-ruby-client (1.52.0)
|
playwright-ruby-client (1.54.0)
|
||||||
concurrent-ruby (>= 1.1.6)
|
concurrent-ruby (>= 1.1.6)
|
||||||
mime-types (>= 3.0)
|
mime-types (>= 3.0)
|
||||||
pp (0.6.2)
|
pp (0.6.2)
|
||||||
|
@ -627,11 +627,10 @@ GEM
|
||||||
prism (1.4.0)
|
prism (1.4.0)
|
||||||
prometheus_exporter (2.2.0)
|
prometheus_exporter (2.2.0)
|
||||||
webrick
|
webrick
|
||||||
propshaft (1.1.0)
|
propshaft (1.2.0)
|
||||||
actionpack (>= 7.0.0)
|
actionpack (>= 7.0.0)
|
||||||
activesupport (>= 7.0.0)
|
activesupport (>= 7.0.0)
|
||||||
rack
|
rack
|
||||||
railties (>= 7.0.0)
|
|
||||||
psych (5.2.6)
|
psych (5.2.6)
|
||||||
date
|
date
|
||||||
stringio
|
stringio
|
||||||
|
@ -682,7 +681,7 @@ GEM
|
||||||
activesupport (= 8.0.2)
|
activesupport (= 8.0.2)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 8.0.2)
|
railties (= 8.0.2)
|
||||||
rails-dom-testing (2.2.0)
|
rails-dom-testing (2.3.0)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
minitest
|
minitest
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
|
@ -702,23 +701,28 @@ GEM
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
rainbow (3.1.1)
|
rainbow (3.1.1)
|
||||||
rake (13.3.0)
|
rake (13.3.0)
|
||||||
rdf (3.3.2)
|
rdf (3.3.4)
|
||||||
bcp47_spec (~> 0.2)
|
bcp47_spec (~> 0.2)
|
||||||
bigdecimal (~> 3.1, >= 3.1.5)
|
bigdecimal (~> 3.1, >= 3.1.5)
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
|
logger (~> 1.5)
|
||||||
|
ostruct (~> 0.6)
|
||||||
|
readline (~> 0.0)
|
||||||
rdf-normalize (0.7.0)
|
rdf-normalize (0.7.0)
|
||||||
rdf (~> 3.3)
|
rdf (~> 3.3)
|
||||||
rdoc (6.14.1)
|
rdoc (6.14.2)
|
||||||
erb
|
erb
|
||||||
psych (>= 4.0.0)
|
psych (>= 4.0.0)
|
||||||
|
readline (0.0.4)
|
||||||
|
reline
|
||||||
redcarpet (3.6.1)
|
redcarpet (3.6.1)
|
||||||
redis (4.8.1)
|
redis (4.8.1)
|
||||||
redis-client (0.24.0)
|
redis-client (0.25.1)
|
||||||
connection_pool
|
connection_pool
|
||||||
redlock (1.3.2)
|
redlock (1.3.2)
|
||||||
redis (>= 3.0.0, < 6.0)
|
redis (>= 3.0.0, < 6.0)
|
||||||
regexp_parser (2.10.0)
|
regexp_parser (2.10.0)
|
||||||
reline (0.6.1)
|
reline (0.6.2)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
request_store (1.7.0)
|
request_store (1.7.0)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
|
@ -733,11 +737,11 @@ GEM
|
||||||
chunky_png (~> 1.0)
|
chunky_png (~> 1.0)
|
||||||
rqrcode_core (~> 2.0)
|
rqrcode_core (~> 2.0)
|
||||||
rqrcode_core (2.0.0)
|
rqrcode_core (2.0.0)
|
||||||
rspec (3.13.0)
|
rspec (3.13.1)
|
||||||
rspec-core (~> 3.13.0)
|
rspec-core (~> 3.13.0)
|
||||||
rspec-expectations (~> 3.13.0)
|
rspec-expectations (~> 3.13.0)
|
||||||
rspec-mocks (~> 3.13.0)
|
rspec-mocks (~> 3.13.0)
|
||||||
rspec-core (3.13.4)
|
rspec-core (3.13.5)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.13.5)
|
rspec-expectations (3.13.5)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
|
@ -761,7 +765,7 @@ GEM
|
||||||
rspec-mocks (~> 3.0)
|
rspec-mocks (~> 3.0)
|
||||||
sidekiq (>= 5, < 9)
|
sidekiq (>= 5, < 9)
|
||||||
rspec-support (3.13.4)
|
rspec-support (3.13.4)
|
||||||
rubocop (1.77.0)
|
rubocop (1.78.0)
|
||||||
json (~> 2.3)
|
json (~> 2.3)
|
||||||
language_server-protocol (~> 3.17.0.2)
|
language_server-protocol (~> 3.17.0.2)
|
||||||
lint_roller (~> 1.1.0)
|
lint_roller (~> 1.1.0)
|
||||||
|
@ -772,7 +776,7 @@ GEM
|
||||||
rubocop-ast (>= 1.45.1, < 2.0)
|
rubocop-ast (>= 1.45.1, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 4.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
rubocop-ast (1.45.1)
|
rubocop-ast (1.46.0)
|
||||||
parser (>= 3.3.7.2)
|
parser (>= 3.3.7.2)
|
||||||
prism (~> 1.4)
|
prism (~> 1.4)
|
||||||
rubocop-capybara (2.22.1)
|
rubocop-capybara (2.22.1)
|
||||||
|
@ -815,7 +819,7 @@ GEM
|
||||||
sanitize (7.0.0)
|
sanitize (7.0.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.16.8)
|
nokogiri (>= 1.16.8)
|
||||||
scenic (1.8.0)
|
scenic (1.9.0)
|
||||||
activerecord (>= 4.0.0)
|
activerecord (>= 4.0.0)
|
||||||
railties (>= 4.0.0)
|
railties (>= 4.0.0)
|
||||||
securerandom (0.4.1)
|
securerandom (0.4.1)
|
||||||
|
@ -846,7 +850,7 @@ GEM
|
||||||
docile (~> 1.1)
|
docile (~> 1.1)
|
||||||
simplecov-html (~> 0.11)
|
simplecov-html (~> 0.11)
|
||||||
simplecov_json_formatter (~> 0.1)
|
simplecov_json_formatter (~> 0.1)
|
||||||
simplecov-html (0.13.1)
|
simplecov-html (0.13.2)
|
||||||
simplecov-lcov (0.8.0)
|
simplecov-lcov (0.8.0)
|
||||||
simplecov_json_formatter (0.1.4)
|
simplecov_json_formatter (0.1.4)
|
||||||
stackprof (0.2.27)
|
stackprof (0.2.27)
|
||||||
|
@ -866,11 +870,11 @@ GEM
|
||||||
temple (0.10.3)
|
temple (0.10.3)
|
||||||
terminal-table (4.0.0)
|
terminal-table (4.0.0)
|
||||||
unicode-display_width (>= 1.1.1, < 4)
|
unicode-display_width (>= 1.1.1, < 4)
|
||||||
terrapin (1.1.0)
|
terrapin (1.1.1)
|
||||||
climate_control
|
climate_control
|
||||||
test-prof (1.4.4)
|
test-prof (1.4.4)
|
||||||
thor (1.3.2)
|
thor (1.4.0)
|
||||||
tilt (2.6.0)
|
tilt (2.6.1)
|
||||||
timeout (0.4.3)
|
timeout (0.4.3)
|
||||||
tpm-key_attestation (0.14.1)
|
tpm-key_attestation (0.14.1)
|
||||||
bindata (~> 2.4)
|
bindata (~> 2.4)
|
||||||
|
@ -932,7 +936,7 @@ GEM
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
webrick (1.9.1)
|
webrick (1.9.1)
|
||||||
websocket-driver (0.7.7)
|
websocket-driver (0.8.0)
|
||||||
base64
|
base64
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.5)
|
websocket-extensions (0.1.5)
|
||||||
|
@ -1008,7 +1012,7 @@ DEPENDENCIES
|
||||||
letter_opener (~> 1.8)
|
letter_opener (~> 1.8)
|
||||||
letter_opener_web (~> 3.0)
|
letter_opener_web (~> 3.0)
|
||||||
link_header (~> 0.0)
|
link_header (~> 0.0)
|
||||||
linzer (~> 0.7.2)
|
linzer (~> 0.7.7)
|
||||||
lograge (~> 0.12)
|
lograge (~> 0.12)
|
||||||
mail (~> 2.8)
|
mail (~> 2.8)
|
||||||
mario-redis-lock (~> 1.2)
|
mario-redis-lock (~> 1.2)
|
||||||
|
@ -1102,4 +1106,4 @@ RUBY VERSION
|
||||||
ruby 3.4.1p0
|
ruby 3.4.1p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.6.9
|
2.7.0
|
||||||
|
|
64
README.md
64
README.md
|
@ -17,71 +17,71 @@
|
||||||
<img src="https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg" alt="Crowdin" /></a>
|
<img src="https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg" alt="Crowdin" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!)
|
Mastodon is a **free, open-source social network server** based on [ActivityPub](https://www.w3.org/TR/activitypub/) where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, and video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub!)
|
||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
- [Project homepage 🐘](https://joinmastodon.org)
|
- [Project homepage 🐘](https://joinmastodon.org)
|
||||||
- [Support the development via Patreon][patreon]
|
- [Donate to support development 🎁](https://joinmastodon.org/sponsors#donate)
|
||||||
- [View sponsors](https://joinmastodon.org/sponsors)
|
- [View sponsors](https://joinmastodon.org/sponsors)
|
||||||
- [Blog](https://blog.joinmastodon.org)
|
- [Blog 📰](https://blog.joinmastodon.org)
|
||||||
- [Documentation](https://docs.joinmastodon.org)
|
- [Documentation 📚](https://docs.joinmastodon.org)
|
||||||
- [Roadmap](https://joinmastodon.org/roadmap)
|
- [Official container image 🚢](https://github.com/mastodon/mastodon/pkgs/container/mastodon)
|
||||||
- [Official Docker image](https://github.com/mastodon/mastodon/pkgs/container/mastodon)
|
|
||||||
- [Browse Mastodon servers](https://joinmastodon.org/communities)
|
|
||||||
- [Browse Mastodon apps](https://joinmastodon.org/apps)
|
|
||||||
|
|
||||||
[patreon]: https://www.patreon.com/mastodon
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
<img src="/app/javascript/images/elephant_ui_working.svg?raw=true" align="right" width="30%" />
|
<img src="./app/javascript/images/elephant_ui_working.svg?raw=true" align="right" width="30%" />
|
||||||
|
|
||||||
**No vendor lock-in: Fully interoperable with any conforming platform** - It doesn't have to be Mastodon; whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/)
|
**Part of the Fediverse. Based on open standards, with no vendor lock-in.** - the network goes beyond just Mastodon; anything that implements ActivityPub is part of a broader social network known as [the Fediverse](https://jointhefediverse.net/). You can follow and interact with users on other servers (including those running different software), and they can follow you back.
|
||||||
|
|
||||||
**Real-time, chronological timeline updates** - updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well!
|
**Real-time, chronological timeline updates** - updates of people you're following appear in real-time in the UI.
|
||||||
|
|
||||||
**Media attachments like images and short videos** - upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos loop continuously!
|
**Media attachments** - upload and view images and videos attached to the updates. Videos with no audio track are treated like animated GIFs; normal videos loop continuously.
|
||||||
|
|
||||||
**Safety and moderation tools** - Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/)
|
**Safety and moderation tools** - Mastodon includes private posts, locked accounts, phrase filtering, muting, blocking, and many other features, along with a reporting and moderation system.
|
||||||
|
|
||||||
**OAuth2 and a straightforward REST API** - Mastodon acts as an OAuth2 provider, so 3rd party apps can use the REST and Streaming APIs. This results in a rich app ecosystem with a lot of choices!
|
**OAuth2 and a straightforward REST API** - Mastodon acts as an OAuth2 provider, and third party apps can use the REST and Streaming APIs. This results in a [rich app ecosystem](https://joinmastodon.org/apps) with a variety of choices!
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
### Tech stack
|
### Tech stack
|
||||||
|
|
||||||
- **Ruby on Rails** powers the REST API and other web pages
|
- [Ruby on Rails](https://github.com/rails/rails) powers the REST API and other web pages.
|
||||||
- **React.js** and **Redux** are used for the dynamic parts of the interface
|
- [PostgreSQL](https://www.postgresql.org/) is the main database.
|
||||||
- **Node.js** powers the streaming API
|
- [Redis](https://redis.io/) and [Sidekiq](https://sidekiq.org/) are used for caching and queueing.
|
||||||
|
- [Node.js](https://nodejs.org/) powers the streaming API.
|
||||||
|
- [React.js](https://reactjs.org/) and [Redux](https://redux.js.org/) are used for the dynamic parts of the interface.
|
||||||
|
- [BrowserStack](https://www.browserstack.com/) supports testing on real devices and browsers. (This project is tested with BrowserStack)
|
||||||
|
- [Chromatic](https://www.chromatic.com/) provides visual regression testing. (This project is tested with Chromatic)
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
|
- **Ruby** 3.2+
|
||||||
- **PostgreSQL** 13+
|
- **PostgreSQL** 13+
|
||||||
- **Redis** 6.2+
|
- **Redis** 6.2+
|
||||||
- **Ruby** 3.2+
|
|
||||||
- **Node.js** 20+
|
- **Node.js** 20+
|
||||||
|
|
||||||
The repository includes deployment configurations for **Docker and docker-compose** as well as specific platforms like **Heroku**, and **Scalingo**. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). The [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation.
|
This repository includes deployment configurations for **Docker and docker-compose**, as well as for other environments like Heroku and Scalingo. For Helm charts, reference the [mastodon/chart repository](https://github.com/mastodon/chart). A [**standalone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the main documentation.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Mastodon is **free, open-source software** licensed under **AGPLv3**.
|
Mastodon is **free, open-source software** licensed under **AGPLv3**. We welcome contributions and help from anyone who wants to improve the project.
|
||||||
|
|
||||||
You can open issues for bugs you've found or features you think are missing. You
|
You should read the overall [CONTRIBUTING](https://github.com/mastodon/.github/blob/main/CONTRIBUTING.md) guide, which covers our development processes.
|
||||||
can also submit pull requests to this repository or translations via Crowdin. To
|
|
||||||
get started, look at the [CONTRIBUTING] and [DEVELOPMENT] guides. For changes
|
|
||||||
accepted into Mastodon, you can request to be paid through our [OpenCollective].
|
|
||||||
|
|
||||||
**IRC channel**: #mastodon on [`irc.libera.chat`](https://libera.chat)
|
You should also read and understand the [CODE OF CONDUCT](https://github.com/mastodon/.github/blob/main/CODE_OF_CONDUCT.md) that enables us to maintain a welcoming and inclusive community. Collaboration begins with mutual respect and understanding.
|
||||||
|
|
||||||
## License
|
You can learn about setting up a development environment in the [DEVELOPMENT](docs/DEVELOPMENT.md) documentation.
|
||||||
|
|
||||||
|
If you would like to help with translations 🌐 you can do so on [Crowdin](https://crowdin.com/project/mastodon).
|
||||||
|
|
||||||
|
## LICENSE
|
||||||
|
|
||||||
Copyright (c) 2016-2025 Eugen Rochko (+ [`mastodon authors`](AUTHORS.md))
|
Copyright (c) 2016-2025 Eugen Rochko (+ [`mastodon authors`](AUTHORS.md))
|
||||||
|
|
||||||
Licensed under GNU Affero General Public License as stated in the [LICENSE](LICENSE):
|
Licensed under GNU Affero General Public License as stated in the [LICENSE](LICENSE):
|
||||||
|
|
||||||
```
|
```text
|
||||||
Copyright (c) 2016-2025 Eugen Rochko & other Mastodon contributors
|
Copyright (c) 2016-2025 Eugen Rochko & other Mastodon contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under
|
This program is free software: you can redistribute it and/or modify it under
|
||||||
|
@ -97,7 +97,3 @@ details.
|
||||||
You should have received a copy of the GNU Affero General Public License along
|
You should have received a copy of the GNU Affero General Public License along
|
||||||
with this program. If not, see https://www.gnu.org/licenses/
|
with this program. If not, see https://www.gnu.org/licenses/
|
||||||
```
|
```
|
||||||
|
|
||||||
[CONTRIBUTING]: CONTRIBUTING.md
|
|
||||||
[DEVELOPMENT]: docs/DEVELOPMENT.md
|
|
||||||
[OpenCollective]: https://opencollective.com/mastodon
|
|
||||||
|
|
|
@ -13,27 +13,9 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
||||||
|
|
||||||
case action_from_button
|
case action_from_button
|
||||||
when 'delete', 'mark_as_sensitive'
|
when 'delete', 'mark_as_sensitive'
|
||||||
status_batch_action = Admin::StatusBatchAction.new(
|
Admin::StatusBatchAction.new(status_batch_action_params).save!
|
||||||
type: action_from_button,
|
|
||||||
status_ids: @report.status_ids,
|
|
||||||
current_account: current_account,
|
|
||||||
report_id: @report.id,
|
|
||||||
send_email_notification: !@report.spam?,
|
|
||||||
text: params[:text]
|
|
||||||
)
|
|
||||||
|
|
||||||
status_batch_action.save!
|
|
||||||
when 'silence', 'suspend'
|
when 'silence', 'suspend'
|
||||||
account_action = Admin::AccountAction.new(
|
Admin::AccountAction.new(account_action_params).save!
|
||||||
type: action_from_button,
|
|
||||||
report_id: @report.id,
|
|
||||||
target_account: @report.target_account,
|
|
||||||
current_account: current_account,
|
|
||||||
send_email_notification: !@report.spam?,
|
|
||||||
text: params[:text]
|
|
||||||
)
|
|
||||||
|
|
||||||
account_action.save!
|
|
||||||
else
|
else
|
||||||
return redirect_to admin_report_path(@report), alert: I18n.t('admin.reports.unknown_action_msg', action: action_from_button)
|
return redirect_to admin_report_path(@report), alert: I18n.t('admin.reports.unknown_action_msg', action: action_from_button)
|
||||||
end
|
end
|
||||||
|
@ -43,6 +25,26 @@ class Admin::Reports::ActionsController < Admin::BaseController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def status_batch_action_params
|
||||||
|
shared_params
|
||||||
|
.merge(status_ids: @report.status_ids)
|
||||||
|
end
|
||||||
|
|
||||||
|
def account_action_params
|
||||||
|
shared_params
|
||||||
|
.merge(target_account: @report.target_account)
|
||||||
|
end
|
||||||
|
|
||||||
|
def shared_params
|
||||||
|
{
|
||||||
|
current_account: current_account,
|
||||||
|
report_id: @report.id,
|
||||||
|
send_email_notification: !@report.spam?,
|
||||||
|
text: params[:text],
|
||||||
|
type: action_from_button,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def set_report
|
def set_report
|
||||||
@report = Report.find(params[:report_id])
|
@report = Report.find(params[:report_id])
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ class Api::V1::InvitesController < Api::BaseController
|
||||||
skip_around_action :set_locale
|
skip_around_action :set_locale
|
||||||
|
|
||||||
before_action :set_invite
|
before_action :set_invite
|
||||||
|
before_action :check_valid_usage!
|
||||||
before_action :check_enabled_registrations!
|
before_action :check_enabled_registrations!
|
||||||
|
|
||||||
# Override `current_user` to avoid reading session cookies
|
# Override `current_user` to avoid reading session cookies
|
||||||
|
@ -22,9 +23,11 @@ class Api::V1::InvitesController < Api::BaseController
|
||||||
@invite = Invite.find_by!(code: params[:invite_code])
|
@invite = Invite.find_by!(code: params[:invite_code])
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_enabled_registrations!
|
def check_valid_usage!
|
||||||
return render json: { error: I18n.t('invites.invalid') }, status: 401 unless @invite.valid_for_use?
|
render json: { error: I18n.t('invites.invalid') }, status: 401 unless @invite.valid_for_use?
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_enabled_registrations!
|
||||||
raise Mastodon::NotPermittedError unless allowed_registration?(request.remote_ip, @invite)
|
raise Mastodon::NotPermittedError unless allowed_registration?(request.remote_ip, @invite)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,8 +38,7 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
private
|
private
|
||||||
|
|
||||||
def record_login_activity
|
def record_login_activity
|
||||||
LoginActivity.create(
|
@user.login_activities.create(
|
||||||
user: @user,
|
|
||||||
success: true,
|
success: true,
|
||||||
authentication_method: :omniauth,
|
authentication_method: :omniauth,
|
||||||
provider: @provider,
|
provider: @provider,
|
||||||
|
|
|
@ -151,12 +151,11 @@ class Auth::SessionsController < Devise::SessionsController
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
flash.delete(:notice)
|
flash.delete(:notice)
|
||||||
|
|
||||||
LoginActivity.create(
|
user.login_activities.create(
|
||||||
user: user,
|
request_details.merge(
|
||||||
success: true,
|
authentication_method: security_measure,
|
||||||
authentication_method: security_measure,
|
success: true
|
||||||
ip: request.remote_ip,
|
)
|
||||||
user_agent: request.user_agent
|
|
||||||
)
|
)
|
||||||
|
|
||||||
UserMailer.suspicious_sign_in(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later! if @login_is_suspicious
|
UserMailer.suspicious_sign_in(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later! if @login_is_suspicious
|
||||||
|
@ -167,13 +166,12 @@ class Auth::SessionsController < Devise::SessionsController
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_authentication_failure(user, security_measure, failure_reason)
|
def on_authentication_failure(user, security_measure, failure_reason)
|
||||||
LoginActivity.create(
|
user.login_activities.create(
|
||||||
user: user,
|
request_details.merge(
|
||||||
success: false,
|
authentication_method: security_measure,
|
||||||
authentication_method: security_measure,
|
failure_reason: failure_reason,
|
||||||
failure_reason: failure_reason,
|
success: false
|
||||||
ip: request.remote_ip,
|
)
|
||||||
user_agent: request.user_agent
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Only send a notification email every hour at most
|
# Only send a notification email every hour at most
|
||||||
|
@ -182,6 +180,13 @@ class Auth::SessionsController < Devise::SessionsController
|
||||||
UserMailer.failed_2fa(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later!
|
UserMailer.failed_2fa(user, request.remote_ip, request.user_agent, Time.now.utc).deliver_later!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def request_details
|
||||||
|
{
|
||||||
|
ip: request.remote_ip,
|
||||||
|
user_agent: request.user_agent,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def second_factor_attempts_key(user)
|
def second_factor_attempts_key(user)
|
||||||
"2fa_auth_attempts:#{user.id}:#{Time.now.utc.hour}"
|
"2fa_auth_attempts:#{user.id}:#{Time.now.utc.hour}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,6 @@ class Settings::LoginActivitiesController < Settings::BaseController
|
||||||
skip_before_action :require_functional!
|
skip_before_action :require_functional!
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@login_activities = LoginActivity.where(user: current_user).order(id: :desc).page(params[:page])
|
@login_activities = current_user.login_activities.order(id: :desc).page(params[:page])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,7 +66,7 @@ module ApplicationHelper
|
||||||
|
|
||||||
def provider_sign_in_link(provider)
|
def provider_sign_in_link(provider)
|
||||||
label = Devise.omniauth_configs[provider]&.strategy&.display_name.presence || I18n.t("auth.providers.#{provider}", default: provider.to_s.chomp('_oauth2').capitalize)
|
label = Devise.omniauth_configs[provider]&.strategy&.display_name.presence || I18n.t("auth.providers.#{provider}", default: provider.to_s.chomp('_oauth2').capitalize)
|
||||||
link_to label, omniauth_authorize_path(:user, provider), class: "button button-#{provider}", method: :post
|
link_to label, omniauth_authorize_path(:user, provider), class: "btn button-#{provider}", method: :post
|
||||||
end
|
end
|
||||||
|
|
||||||
def locale_direction
|
def locale_direction
|
||||||
|
|
|
@ -26,6 +26,12 @@ module ContextHelper
|
||||||
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
||||||
attribution_domains: { 'toot' => 'http://joinmastodon.org/ns#', 'attributionDomains' => { '@id' => 'toot:attributionDomains', '@type' => '@id' } },
|
attribution_domains: { 'toot' => 'http://joinmastodon.org/ns#', 'attributionDomains' => { '@id' => 'toot:attributionDomains', '@type' => '@id' } },
|
||||||
quote_requests: { 'QuoteRequest' => 'https://w3id.org/fep/044f#QuoteRequest' },
|
quote_requests: { 'QuoteRequest' => 'https://w3id.org/fep/044f#QuoteRequest' },
|
||||||
|
quotes: {
|
||||||
|
'quote' => 'https://w3id.org/fep/044f#quote',
|
||||||
|
'quoteUri' => 'http://fedibird.com/ns#quoteUri',
|
||||||
|
'_misskey_quote' => 'https://misskey-hub.net/ns#_misskey_quote',
|
||||||
|
'quoteAuthorization' => { '@id' => 'https://w3id.org/fep/044f#quoteAuthorization', '@type' => '@id' },
|
||||||
|
},
|
||||||
interaction_policies: {
|
interaction_policies: {
|
||||||
'gts' => 'https://gotosocial.org/ns#',
|
'gts' => 'https://gotosocial.org/ns#',
|
||||||
'interactionPolicy' => { '@id' => 'gts:interactionPolicy', '@type' => '@id' },
|
'interactionPolicy' => { '@id' => 'gts:interactionPolicy', '@type' => '@id' },
|
||||||
|
|
|
@ -1,12 +1,30 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useLinks } from 'mastodon/hooks/useLinks';
|
import { useLinks } from 'mastodon/hooks/useLinks';
|
||||||
|
|
||||||
export const AccountBio: React.FC<{
|
interface AccountBioProps {
|
||||||
note: string;
|
note: string;
|
||||||
className: string;
|
className: string;
|
||||||
}> = ({ note, className }) => {
|
dropdownAccountId?: string;
|
||||||
const handleClick = useLinks();
|
}
|
||||||
|
|
||||||
if (note.length === 0 || note === '<p></p>') {
|
export const AccountBio: React.FC<AccountBioProps> = ({
|
||||||
|
note,
|
||||||
|
className,
|
||||||
|
dropdownAccountId,
|
||||||
|
}) => {
|
||||||
|
const handleClick = useLinks(!!dropdownAccountId);
|
||||||
|
const handleNodeChange = useCallback(
|
||||||
|
(node: HTMLDivElement | null) => {
|
||||||
|
if (!dropdownAccountId || !node || node.childNodes.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addDropdownToHashtags(node, dropdownAccountId);
|
||||||
|
},
|
||||||
|
[dropdownAccountId],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (note.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +33,28 @@ export const AccountBio: React.FC<{
|
||||||
className={`${className} translate`}
|
className={`${className} translate`}
|
||||||
dangerouslySetInnerHTML={{ __html: note }}
|
dangerouslySetInnerHTML={{ __html: note }}
|
||||||
onClickCapture={handleClick}
|
onClickCapture={handleClick}
|
||||||
|
ref={handleNodeChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function addDropdownToHashtags(node: HTMLElement | null, accountId: string) {
|
||||||
|
if (!node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const childNode of node.childNodes) {
|
||||||
|
if (!(childNode instanceof HTMLElement)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
childNode instanceof HTMLAnchorElement &&
|
||||||
|
(childNode.classList.contains('hashtag') ||
|
||||||
|
childNode.innerText.startsWith('#')) &&
|
||||||
|
!childNode.dataset.menuHashtag
|
||||||
|
) {
|
||||||
|
childNode.dataset.menuHashtag = accountId;
|
||||||
|
} else if (childNode.childNodes.length > 0) {
|
||||||
|
addDropdownToHashtags(childNode, accountId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
useCallback,
|
useCallback,
|
||||||
cloneElement,
|
cloneElement,
|
||||||
Children,
|
Children,
|
||||||
|
useId,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
@ -16,6 +17,7 @@ import Overlay from 'react-overlays/Overlay';
|
||||||
import type {
|
import type {
|
||||||
OffsetValue,
|
OffsetValue,
|
||||||
UsePopperOptions,
|
UsePopperOptions,
|
||||||
|
Placement,
|
||||||
} from 'react-overlays/esm/usePopper';
|
} from 'react-overlays/esm/usePopper';
|
||||||
|
|
||||||
import { fetchRelationships } from 'mastodon/actions/accounts';
|
import { fetchRelationships } from 'mastodon/actions/accounts';
|
||||||
|
@ -295,6 +297,11 @@ interface DropdownProps<Item = MenuItem> {
|
||||||
title?: string;
|
title?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
scrollable?: boolean;
|
scrollable?: boolean;
|
||||||
|
placement?: Placement;
|
||||||
|
/**
|
||||||
|
* Prevent the `ScrollableList` with this scrollKey
|
||||||
|
* from being scrolled while the dropdown is open
|
||||||
|
*/
|
||||||
scrollKey?: string;
|
scrollKey?: string;
|
||||||
status?: ImmutableMap<string, unknown>;
|
status?: ImmutableMap<string, unknown>;
|
||||||
forceDropdown?: boolean;
|
forceDropdown?: boolean;
|
||||||
|
@ -316,6 +323,7 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
title = 'Menu',
|
title = 'Menu',
|
||||||
disabled,
|
disabled,
|
||||||
scrollable,
|
scrollable,
|
||||||
|
placement = 'bottom',
|
||||||
status,
|
status,
|
||||||
forceDropdown = false,
|
forceDropdown = false,
|
||||||
renderItem,
|
renderItem,
|
||||||
|
@ -331,16 +339,15 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
);
|
);
|
||||||
const [currentId] = useState(id++);
|
const [currentId] = useState(id++);
|
||||||
const open = currentId === openDropdownId;
|
const open = currentId === openDropdownId;
|
||||||
const activeElement = useRef<HTMLElement | null>(null);
|
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
||||||
const targetRef = useRef<HTMLButtonElement | null>(null);
|
const menuId = useId();
|
||||||
const prefetchAccountId = status
|
const prefetchAccountId = status
|
||||||
? status.getIn(['account', 'id'])
|
? status.getIn(['account', 'id'])
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
if (activeElement.current) {
|
if (buttonRef.current) {
|
||||||
activeElement.current.focus({ preventScroll: true });
|
buttonRef.current.focus({ preventScroll: true });
|
||||||
activeElement.current = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(
|
dispatch(
|
||||||
|
@ -375,7 +382,7 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
[handleClose, onItemClick, items],
|
[handleClose, onItemClick, items],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClick = useCallback(
|
const toggleDropdown = useCallback(
|
||||||
(e: React.MouseEvent | React.KeyboardEvent) => {
|
(e: React.MouseEvent | React.KeyboardEvent) => {
|
||||||
const { type } = e;
|
const { type } = e;
|
||||||
|
|
||||||
|
@ -423,38 +430,6 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleMouseDown = useCallback(() => {
|
|
||||||
if (!open && document.activeElement instanceof HTMLElement) {
|
|
||||||
activeElement.current = document.activeElement;
|
|
||||||
}
|
|
||||||
}, [open]);
|
|
||||||
|
|
||||||
const handleButtonKeyDown = useCallback(
|
|
||||||
(e: React.KeyboardEvent) => {
|
|
||||||
switch (e.key) {
|
|
||||||
case ' ':
|
|
||||||
case 'Enter':
|
|
||||||
handleMouseDown();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[handleMouseDown],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleKeyPress = useCallback(
|
|
||||||
(e: React.KeyboardEvent) => {
|
|
||||||
switch (e.key) {
|
|
||||||
case ' ':
|
|
||||||
case 'Enter':
|
|
||||||
handleClick(e);
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[handleClick],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (currentId === openDropdownId) {
|
if (currentId === openDropdownId) {
|
||||||
|
@ -465,14 +440,16 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
|
|
||||||
let button: React.ReactElement;
|
let button: React.ReactElement;
|
||||||
|
|
||||||
|
const buttonProps = {
|
||||||
|
disabled,
|
||||||
|
onClick: toggleDropdown,
|
||||||
|
'aria-expanded': open,
|
||||||
|
'aria-controls': menuId,
|
||||||
|
ref: buttonRef,
|
||||||
|
};
|
||||||
|
|
||||||
if (children) {
|
if (children) {
|
||||||
button = cloneElement(Children.only(children), {
|
button = cloneElement(Children.only(children), buttonProps);
|
||||||
onClick: handleClick,
|
|
||||||
onMouseDown: handleMouseDown,
|
|
||||||
onKeyDown: handleButtonKeyDown,
|
|
||||||
onKeyPress: handleKeyPress,
|
|
||||||
ref: targetRef,
|
|
||||||
});
|
|
||||||
} else if (icon && iconComponent) {
|
} else if (icon && iconComponent) {
|
||||||
button = (
|
button = (
|
||||||
<IconButton
|
<IconButton
|
||||||
|
@ -480,12 +457,7 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
iconComponent={iconComponent}
|
iconComponent={iconComponent}
|
||||||
title={title}
|
title={title}
|
||||||
active={open}
|
active={open}
|
||||||
disabled={disabled}
|
{...buttonProps}
|
||||||
onClick={handleClick}
|
|
||||||
onMouseDown={handleMouseDown}
|
|
||||||
onKeyDown={handleButtonKeyDown}
|
|
||||||
onKeyPress={handleKeyPress}
|
|
||||||
ref={targetRef}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -499,13 +471,13 @@ export const Dropdown = <Item = MenuItem,>({
|
||||||
<Overlay
|
<Overlay
|
||||||
show={open}
|
show={open}
|
||||||
offset={offset}
|
offset={offset}
|
||||||
placement='bottom'
|
placement={placement}
|
||||||
flip
|
flip
|
||||||
target={targetRef}
|
target={buttonRef}
|
||||||
popperConfig={popperConfig}
|
popperConfig={popperConfig}
|
||||||
>
|
>
|
||||||
{({ props, arrowProps, placement }) => (
|
{({ props, arrowProps, placement }) => (
|
||||||
<div {...props}>
|
<div {...props} id={menuId}>
|
||||||
<div className={`dropdown-animation dropdown-menu ${placement}`}>
|
<div className={`dropdown-animation dropdown-menu ${placement}`}>
|
||||||
<div
|
<div
|
||||||
className={`dropdown-menu__arrow ${placement}`}
|
className={`dropdown-menu__arrow ${placement}`}
|
||||||
|
|
171
app/javascript/mastodon/components/hotkeys/hotkeys.stories.tsx
Normal file
171
app/javascript/mastodon/components/hotkeys/hotkeys.stories.tsx
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||||
|
import { expect } from 'storybook/test';
|
||||||
|
|
||||||
|
import type { HandlerMap } from '.';
|
||||||
|
import { Hotkeys } from '.';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Components/Hotkeys',
|
||||||
|
component: Hotkeys,
|
||||||
|
args: {
|
||||||
|
global: undefined,
|
||||||
|
focusable: undefined,
|
||||||
|
handlers: {},
|
||||||
|
},
|
||||||
|
tags: ['test'],
|
||||||
|
} satisfies Meta<typeof Hotkeys>;
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
|
||||||
|
const hotkeyTest: Story['play'] = async ({ canvas, userEvent }) => {
|
||||||
|
async function confirmHotkey(name: string, shouldFind = true) {
|
||||||
|
// 'status' is the role of the 'output' element
|
||||||
|
const output = await canvas.findByRole('status');
|
||||||
|
if (shouldFind) {
|
||||||
|
await expect(output).toHaveTextContent(name);
|
||||||
|
} else {
|
||||||
|
await expect(output).not.toHaveTextContent(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const button = await canvas.findByRole('button');
|
||||||
|
await userEvent.click(button);
|
||||||
|
|
||||||
|
await userEvent.keyboard('n');
|
||||||
|
await confirmHotkey('new');
|
||||||
|
|
||||||
|
await userEvent.keyboard('/');
|
||||||
|
await confirmHotkey('search');
|
||||||
|
|
||||||
|
await userEvent.keyboard('o');
|
||||||
|
await confirmHotkey('open');
|
||||||
|
|
||||||
|
await userEvent.keyboard('{Alt>}N{/Alt}');
|
||||||
|
await confirmHotkey('forceNew');
|
||||||
|
|
||||||
|
await userEvent.keyboard('gh');
|
||||||
|
await confirmHotkey('goToHome');
|
||||||
|
|
||||||
|
await userEvent.keyboard('gn');
|
||||||
|
await confirmHotkey('goToNotifications');
|
||||||
|
|
||||||
|
await userEvent.keyboard('gf');
|
||||||
|
await confirmHotkey('goToFavourites');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that hotkeys are not triggered when certain
|
||||||
|
* interactive elements are focused:
|
||||||
|
*/
|
||||||
|
|
||||||
|
await userEvent.keyboard('{enter}');
|
||||||
|
await confirmHotkey('open', false);
|
||||||
|
|
||||||
|
const input = await canvas.findByRole('textbox');
|
||||||
|
await userEvent.click(input);
|
||||||
|
|
||||||
|
await userEvent.keyboard('n');
|
||||||
|
await confirmHotkey('new', false);
|
||||||
|
|
||||||
|
await userEvent.keyboard('{backspace}');
|
||||||
|
await confirmHotkey('None', false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset playground:
|
||||||
|
*/
|
||||||
|
|
||||||
|
await userEvent.click(button);
|
||||||
|
await userEvent.keyboard('{backspace}');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Default = {
|
||||||
|
render: function Render() {
|
||||||
|
const [matchedHotkey, setMatchedHotkey] = useState<keyof HandlerMap | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
back: () => {
|
||||||
|
setMatchedHotkey(null);
|
||||||
|
},
|
||||||
|
new: () => {
|
||||||
|
setMatchedHotkey('new');
|
||||||
|
},
|
||||||
|
forceNew: () => {
|
||||||
|
setMatchedHotkey('forceNew');
|
||||||
|
},
|
||||||
|
search: () => {
|
||||||
|
setMatchedHotkey('search');
|
||||||
|
},
|
||||||
|
open: () => {
|
||||||
|
setMatchedHotkey('open');
|
||||||
|
},
|
||||||
|
goToHome: () => {
|
||||||
|
setMatchedHotkey('goToHome');
|
||||||
|
},
|
||||||
|
goToNotifications: () => {
|
||||||
|
setMatchedHotkey('goToNotifications');
|
||||||
|
},
|
||||||
|
goToFavourites: () => {
|
||||||
|
setMatchedHotkey('goToFavourites');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Hotkeys handlers={handlers}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: 8,
|
||||||
|
padding: '1em',
|
||||||
|
border: '1px dashed #ccc',
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#222',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h1
|
||||||
|
style={{
|
||||||
|
fontSize: 22,
|
||||||
|
marginBottom: '0.3em',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hotkey playground
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Last pressed hotkey: <output>{matchedHotkey ?? 'None'}</output>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Click within the dashed border and press the "<kbd>n</kbd>
|
||||||
|
" or "<kbd>/</kbd>" key. Press "
|
||||||
|
<kbd>Backspace</kbd>" to clear the displayed hotkey.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Try typing a sequence, like "<kbd>g</kbd>" shortly
|
||||||
|
followed by "<kbd>h</kbd>", "<kbd>n</kbd>", or
|
||||||
|
"<kbd>f</kbd>"
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Note that this playground doesn't support all hotkeys we use in
|
||||||
|
the app.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When a <button>Button</button> is focused, "
|
||||||
|
<kbd>Enter</kbd>
|
||||||
|
" should not trigger "open", but "<kbd>o</kbd>
|
||||||
|
" should.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
When an input element is focused, hotkeys should not interfere with
|
||||||
|
regular typing:
|
||||||
|
</p>
|
||||||
|
<input type='text' />
|
||||||
|
</div>
|
||||||
|
</Hotkeys>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
play: hotkeyTest,
|
||||||
|
};
|
282
app/javascript/mastodon/components/hotkeys/index.tsx
Normal file
282
app/javascript/mastodon/components/hotkeys/index.tsx
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import { normalizeKey, isKeyboardEvent } from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In case of multiple hotkeys matching the pressed key(s),
|
||||||
|
* the hotkey with a higher priority is selected. All others
|
||||||
|
* are ignored.
|
||||||
|
*/
|
||||||
|
const hotkeyPriority = {
|
||||||
|
singleKey: 0,
|
||||||
|
combo: 1,
|
||||||
|
sequence: 2,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This type of function receives a keyboard event and an array of
|
||||||
|
* previously pressed keys (within the last second), and returns
|
||||||
|
* `isMatch` (whether the pressed keys match a hotkey) and `priority`
|
||||||
|
* (a weighting used to resolve conflicts when two hotkeys match the
|
||||||
|
* pressed keys)
|
||||||
|
*/
|
||||||
|
type KeyMatcher = (
|
||||||
|
event: KeyboardEvent,
|
||||||
|
bufferedKeys?: string[],
|
||||||
|
) => {
|
||||||
|
/**
|
||||||
|
* Whether the event.key matches the hotkey
|
||||||
|
*/
|
||||||
|
isMatch: boolean;
|
||||||
|
/**
|
||||||
|
* If there are multiple matching hotkeys, the
|
||||||
|
* first one with the highest priority will be handled
|
||||||
|
*/
|
||||||
|
priority: (typeof hotkeyPriority)[keyof typeof hotkeyPriority];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a single key
|
||||||
|
*/
|
||||||
|
function just(keyName: string): KeyMatcher {
|
||||||
|
return (event) => ({
|
||||||
|
isMatch: normalizeKey(event.key) === keyName,
|
||||||
|
priority: hotkeyPriority.singleKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches any single key out of those provided
|
||||||
|
*/
|
||||||
|
function any(...keys: string[]): KeyMatcher {
|
||||||
|
return (event) => ({
|
||||||
|
isMatch: keys.some((keyName) => just(keyName)(event).isMatch),
|
||||||
|
priority: hotkeyPriority.singleKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a single key combined with the option/alt modifier
|
||||||
|
*/
|
||||||
|
function optionPlus(key: string): KeyMatcher {
|
||||||
|
return (event) => ({
|
||||||
|
// Matching against event.code here as alt combos are often
|
||||||
|
// mapped to other characters
|
||||||
|
isMatch: event.altKey && event.code === `Key${key.toUpperCase()}`,
|
||||||
|
priority: hotkeyPriority.combo,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches when all provided keys are pressed in sequence.
|
||||||
|
*/
|
||||||
|
function sequence(...sequence: string[]): KeyMatcher {
|
||||||
|
return (event, bufferedKeys) => {
|
||||||
|
const lastKeyInSequence = sequence.at(-1);
|
||||||
|
const startOfSequence = sequence.slice(0, -1);
|
||||||
|
const relevantBufferedKeys = bufferedKeys?.slice(-startOfSequence.length);
|
||||||
|
|
||||||
|
const bufferMatchesStartOfSequence =
|
||||||
|
!!relevantBufferedKeys &&
|
||||||
|
startOfSequence.join('') === relevantBufferedKeys.join('');
|
||||||
|
|
||||||
|
return {
|
||||||
|
isMatch:
|
||||||
|
bufferMatchesStartOfSequence &&
|
||||||
|
normalizeKey(event.key) === lastKeyInSequence,
|
||||||
|
priority: hotkeyPriority.sequence,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a map of all global hotkeys we support.
|
||||||
|
* To trigger a hotkey, a handler with a matching name must be
|
||||||
|
* provided to the `useHotkeys` hook or `Hotkeys` component.
|
||||||
|
*/
|
||||||
|
const hotkeyMatcherMap = {
|
||||||
|
help: just('?'),
|
||||||
|
search: any('s', '/'),
|
||||||
|
back: just('backspace'),
|
||||||
|
new: just('n'),
|
||||||
|
forceNew: optionPlus('n'),
|
||||||
|
focusColumn: any('1', '2', '3', '4', '5', '6', '7', '8', '9'),
|
||||||
|
reply: just('r'),
|
||||||
|
favourite: just('f'),
|
||||||
|
boost: just('b'),
|
||||||
|
mention: just('m'),
|
||||||
|
open: any('enter', 'o'),
|
||||||
|
openProfile: just('p'),
|
||||||
|
moveDown: any('down', 'j'),
|
||||||
|
moveUp: any('up', 'k'),
|
||||||
|
toggleHidden: just('x'),
|
||||||
|
toggleSensitive: just('h'),
|
||||||
|
toggleComposeSpoilers: optionPlus('x'),
|
||||||
|
openMedia: just('e'),
|
||||||
|
onTranslate: just('t'),
|
||||||
|
goToHome: sequence('g', 'h'),
|
||||||
|
goToNotifications: sequence('g', 'n'),
|
||||||
|
goToLocal: sequence('g', 'l'),
|
||||||
|
goToFederated: sequence('g', 't'),
|
||||||
|
goToDirect: sequence('g', 'd'),
|
||||||
|
goToStart: sequence('g', 's'),
|
||||||
|
goToFavourites: sequence('g', 'f'),
|
||||||
|
goToPinned: sequence('g', 'p'),
|
||||||
|
goToProfile: sequence('g', 'u'),
|
||||||
|
goToBlocked: sequence('g', 'b'),
|
||||||
|
goToMuted: sequence('g', 'm'),
|
||||||
|
goToRequests: sequence('g', 'r'),
|
||||||
|
cheat: sequence(
|
||||||
|
'up',
|
||||||
|
'up',
|
||||||
|
'down',
|
||||||
|
'down',
|
||||||
|
'left',
|
||||||
|
'right',
|
||||||
|
'left',
|
||||||
|
'right',
|
||||||
|
'b',
|
||||||
|
'a',
|
||||||
|
'enter',
|
||||||
|
),
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type HotkeyName = keyof typeof hotkeyMatcherMap;
|
||||||
|
|
||||||
|
export type HandlerMap = Partial<
|
||||||
|
Record<HotkeyName, (event: KeyboardEvent) => void>
|
||||||
|
>;
|
||||||
|
|
||||||
|
export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
|
||||||
|
const ref = useRef<T>(null);
|
||||||
|
const bufferedKeys = useRef<string[]>([]);
|
||||||
|
const sequenceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the latest handlers object in a ref so we don't need to
|
||||||
|
* add it as a dependency to the main event listener effect
|
||||||
|
*/
|
||||||
|
const handlersRef = useRef(handlers);
|
||||||
|
useEffect(() => {
|
||||||
|
handlersRef.current = handlers;
|
||||||
|
}, [handlers]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const element = ref.current ?? document;
|
||||||
|
|
||||||
|
function listener(event: Event) {
|
||||||
|
// Ignore key presses from input, textarea, or select elements
|
||||||
|
const tagName = (event.target as HTMLElement).tagName.toLowerCase();
|
||||||
|
const shouldHandleEvent =
|
||||||
|
isKeyboardEvent(event) &&
|
||||||
|
!event.defaultPrevented &&
|
||||||
|
!['input', 'textarea', 'select'].includes(tagName) &&
|
||||||
|
!(
|
||||||
|
['a', 'button'].includes(tagName) &&
|
||||||
|
normalizeKey(event.key) === 'enter'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (shouldHandleEvent) {
|
||||||
|
const matchCandidates: {
|
||||||
|
handler: (event: KeyboardEvent) => void;
|
||||||
|
priority: number;
|
||||||
|
}[] = [];
|
||||||
|
|
||||||
|
(Object.keys(hotkeyMatcherMap) as HotkeyName[]).forEach(
|
||||||
|
(handlerName) => {
|
||||||
|
const handler = handlersRef.current[handlerName];
|
||||||
|
|
||||||
|
if (handler) {
|
||||||
|
const hotkeyMatcher = hotkeyMatcherMap[handlerName];
|
||||||
|
|
||||||
|
const { isMatch, priority } = hotkeyMatcher(
|
||||||
|
event,
|
||||||
|
bufferedKeys.current,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isMatch) {
|
||||||
|
matchCandidates.push({ handler, priority });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sort all matches by priority
|
||||||
|
matchCandidates.sort((a, b) => b.priority - a.priority);
|
||||||
|
|
||||||
|
const bestMatchingHandler = matchCandidates.at(0)?.handler;
|
||||||
|
if (bestMatchingHandler) {
|
||||||
|
bestMatchingHandler(event);
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add last keypress to buffer
|
||||||
|
bufferedKeys.current.push(normalizeKey(event.key));
|
||||||
|
|
||||||
|
// Reset the timeout
|
||||||
|
if (sequenceTimer.current) {
|
||||||
|
clearTimeout(sequenceTimer.current);
|
||||||
|
}
|
||||||
|
sequenceTimer.current = setTimeout(() => {
|
||||||
|
bufferedKeys.current = [];
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.addEventListener('keydown', listener);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
element.removeEventListener('keydown', listener);
|
||||||
|
if (sequenceTimer.current) {
|
||||||
|
clearTimeout(sequenceTimer.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Hotkeys component allows us to globally register keyboard combinations
|
||||||
|
* under a name and assign actions to them, either globally or scoped to a portion
|
||||||
|
* of the app.
|
||||||
|
*
|
||||||
|
* ### How to use
|
||||||
|
*
|
||||||
|
* To add a new hotkey, add its key combination to the `hotkeyMatcherMap` object
|
||||||
|
* and give it a name.
|
||||||
|
*
|
||||||
|
* Use the `<Hotkeys>` component or the `useHotkeys` hook in the part of of the app
|
||||||
|
* where you want to handle the action, and pass in a handlers object.
|
||||||
|
*
|
||||||
|
* ```tsx
|
||||||
|
* <Hotkeys handlers={{open: openStatus}} />
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Now this function will be called when the 'open' hotkey is pressed by the user.
|
||||||
|
*/
|
||||||
|
export const Hotkeys: React.FC<{
|
||||||
|
/**
|
||||||
|
* An object containing functions to be run when a hotkey is pressed.
|
||||||
|
* The key must be the name of a registered hotkey, e.g. "help" or "search"
|
||||||
|
*/
|
||||||
|
handlers: HandlerMap;
|
||||||
|
/**
|
||||||
|
* When enabled, hotkeys will be matched against the document root
|
||||||
|
* rather than only inside of this component's DOM node.
|
||||||
|
*/
|
||||||
|
global?: boolean;
|
||||||
|
/**
|
||||||
|
* Allow the rendered `div` to be focused
|
||||||
|
*/
|
||||||
|
focusable?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}> = ({ handlers, global, focusable = true, children }) => {
|
||||||
|
const ref = useHotkeys<HTMLDivElement>(handlers);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={global ? undefined : ref} tabIndex={focusable ? -1 : undefined}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
29
app/javascript/mastodon/components/hotkeys/utils.ts
Normal file
29
app/javascript/mastodon/components/hotkeys/utils.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
export function isKeyboardEvent(event: Event): event is KeyboardEvent {
|
||||||
|
return 'key' in event;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeKey(key: string): string {
|
||||||
|
const lowerKey = key.toLowerCase();
|
||||||
|
|
||||||
|
switch (lowerKey) {
|
||||||
|
case ' ':
|
||||||
|
case 'spacebar': // for older browsers
|
||||||
|
return 'space';
|
||||||
|
|
||||||
|
case 'arrowup':
|
||||||
|
return 'up';
|
||||||
|
case 'arrowdown':
|
||||||
|
return 'down';
|
||||||
|
case 'arrowleft':
|
||||||
|
return 'left';
|
||||||
|
case 'arrowright':
|
||||||
|
return 'right';
|
||||||
|
|
||||||
|
case 'esc':
|
||||||
|
case 'escape':
|
||||||
|
return 'escape';
|
||||||
|
|
||||||
|
default:
|
||||||
|
return lowerKey;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,6 @@ interface Props {
|
||||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
|
onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
|
||||||
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
|
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
|
||||||
onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>;
|
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
expanded?: boolean;
|
expanded?: boolean;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
|
@ -45,7 +44,6 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(
|
||||||
activeStyle,
|
activeStyle,
|
||||||
onClick,
|
onClick,
|
||||||
onKeyDown,
|
onKeyDown,
|
||||||
onKeyPress,
|
|
||||||
onMouseDown,
|
onMouseDown,
|
||||||
active = false,
|
active = false,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
|
@ -85,16 +83,6 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(
|
||||||
[disabled, onClick],
|
[disabled, onClick],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleKeyPress: React.KeyboardEventHandler<HTMLButtonElement> =
|
|
||||||
useCallback(
|
|
||||||
(e) => {
|
|
||||||
if (!disabled) {
|
|
||||||
onKeyPress?.(e);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[disabled, onKeyPress],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleMouseDown: React.MouseEventHandler<HTMLButtonElement> =
|
const handleMouseDown: React.MouseEventHandler<HTMLButtonElement> =
|
||||||
useCallback(
|
useCallback(
|
||||||
(e) => {
|
(e) => {
|
||||||
|
@ -161,7 +149,6 @@ export const IconButton = forwardRef<HTMLButtonElement, Props>(
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
onKeyPress={handleKeyPress} // eslint-disable-line @typescript-eslint/no-deprecated
|
|
||||||
style={buttonStyle}
|
style={buttonStyle}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
|
@ -8,10 +8,9 @@ import { Link } from 'react-router-dom';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||||
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import { ContentWarning } from 'mastodon/components/content_warning';
|
import { ContentWarning } from 'mastodon/components/content_warning';
|
||||||
import { FilterWarning } from 'mastodon/components/filter_warning';
|
import { FilterWarning } from 'mastodon/components/filter_warning';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
|
@ -35,7 +34,6 @@ import StatusActionBar from './status_action_bar';
|
||||||
import StatusContent from './status_content';
|
import StatusContent from './status_content';
|
||||||
import { StatusThreadLabel } from './status_thread_label';
|
import { StatusThreadLabel } from './status_thread_label';
|
||||||
import { VisibilityIcon } from './visibility_icon';
|
import { VisibilityIcon } from './visibility_icon';
|
||||||
|
|
||||||
const domParser = new DOMParser();
|
const domParser = new DOMParser();
|
||||||
|
|
||||||
export const textForScreenReader = (intl, status, rebloggedByText = false) => {
|
export const textForScreenReader = (intl, status, rebloggedByText = false) => {
|
||||||
|
@ -325,11 +323,11 @@ class Status extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyMoveUp = e => {
|
handleHotkeyMoveUp = e => {
|
||||||
this.props.onMoveUp(this.props.status.get('id'), e.target.getAttribute('data-featured'));
|
this.props.onMoveUp?.(this.props.status.get('id'), this.node.getAttribute('data-featured'));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyMoveDown = e => {
|
handleHotkeyMoveDown = e => {
|
||||||
this.props.onMoveDown(this.props.status.get('id'), e.target.getAttribute('data-featured'));
|
this.props.onMoveDown?.(this.props.status.get('id'), this.node.getAttribute('data-featured'));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyToggleHidden = () => {
|
handleHotkeyToggleHidden = () => {
|
||||||
|
@ -437,13 +435,13 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
<Hotkeys handlers={handlers} focusable={!unfocusable}>
|
||||||
<div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={unfocusable ? null : 0}>
|
<div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={unfocusable ? null : 0}>
|
||||||
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
||||||
{status.get('spoiler_text').length > 0 && (<span>{status.get('spoiler_text')}</span>)}
|
{status.get('spoiler_text').length > 0 && (<span>{status.get('spoiler_text')}</span>)}
|
||||||
{expanded && <span>{status.get('content')}</span>}
|
{expanded && <span>{status.get('content')}</span>}
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +541,7 @@ class Status extends ImmutablePureComponent {
|
||||||
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
<Hotkeys handlers={handlers} focusable={!unfocusable}>
|
||||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted || unfocusable ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
|
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted || unfocusable ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
|
||||||
{!skipPrepend && prepend}
|
{!skipPrepend && prepend}
|
||||||
|
|
||||||
|
@ -604,7 +602,7 @@ class Status extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default class StatusList extends ImmutablePureComponent {
|
||||||
const elementIndex = this.getCurrentStatusIndex(id, featured) - 1;
|
const elementIndex = this.getCurrentStatusIndex(id, featured) - 1;
|
||||||
this._selectChild(elementIndex, true);
|
this._selectChild(elementIndex, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleMoveDown = (id, featured) => {
|
handleMoveDown = (id, featured) => {
|
||||||
const elementIndex = this.getCurrentStatusIndex(id, featured) + 1;
|
const elementIndex = this.getCurrentStatusIndex(id, featured) + 1;
|
||||||
this._selectChild(elementIndex, false);
|
this._selectChild(elementIndex, false);
|
||||||
|
@ -69,6 +69,7 @@ export default class StatusList extends ImmutablePureComponent {
|
||||||
|
|
||||||
_selectChild (index, align_top) {
|
_selectChild (index, align_top) {
|
||||||
const container = this.node.node;
|
const container = this.node.node;
|
||||||
|
// TODO: This breaks at the inline-follow-suggestions container
|
||||||
const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
|
const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`);
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import classNames from 'classnames';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { AccountBio } from '@/mastodon/components/account_bio';
|
||||||
import CheckIcon from '@/material-icons/400-24px/check.svg?react';
|
import CheckIcon from '@/material-icons/400-24px/check.svg?react';
|
||||||
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
|
@ -773,7 +774,6 @@ export const AccountHeader: React.FC<{
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = { __html: account.note_emojified };
|
|
||||||
const displayNameHtml = { __html: account.display_name_html };
|
const displayNameHtml = { __html: account.display_name_html };
|
||||||
const fields = account.fields;
|
const fields = account.fields;
|
||||||
const isLocal = !account.acct.includes('@');
|
const isLocal = !account.acct.includes('@');
|
||||||
|
@ -897,12 +897,11 @@ export const AccountHeader: React.FC<{
|
||||||
<AccountNote accountId={accountId} />
|
<AccountNote accountId={accountId} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{account.note.length > 0 && account.note !== '<p></p>' && (
|
<AccountBio
|
||||||
<div
|
note={account.note_emojified}
|
||||||
className='account__header__content translate'
|
dropdownAccountId={accountId}
|
||||||
dangerouslySetInnerHTML={content}
|
className='account__header__content'
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
|
|
||||||
<div className='account__header__fields'>
|
<div className='account__header__fields'>
|
||||||
<dl>
|
<dl>
|
||||||
|
|
|
@ -261,7 +261,9 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
|
||||||
);
|
);
|
||||||
const lang = useAppSelector(
|
const lang = useAppSelector(
|
||||||
(state) =>
|
(state) =>
|
||||||
(state.compose as ImmutableMap<string, unknown>).get('lang') as string,
|
(state.compose as ImmutableMap<string, unknown>).get(
|
||||||
|
'language',
|
||||||
|
) as string,
|
||||||
);
|
);
|
||||||
const focusX =
|
const focusX =
|
||||||
(media?.getIn(['meta', 'focus', 'x'], 0) as number | undefined) ?? 0;
|
(media?.getIn(['meta', 'focus', 'x'], 0) as number | undefined) ?? 0;
|
||||||
|
|
|
@ -92,10 +92,29 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
this.props.onChange(e.target.value);
|
this.props.onChange(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleKeyDown = (e) => {
|
blurOnEscape = (e) => {
|
||||||
if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) {
|
if (['esc', 'escape'].includes(e.key.toLowerCase())) {
|
||||||
this.handleSubmit();
|
e.target.blur();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDownPost = (e) => {
|
||||||
|
if (e.key.toLowerCase() === 'enter' && (e.ctrlKey || e.metaKey)) {
|
||||||
|
this.handleSubmit();
|
||||||
|
}
|
||||||
|
this.blurOnEscape(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleKeyDownSpoiler = (e) => {
|
||||||
|
if (e.key.toLowerCase() === 'enter') {
|
||||||
|
if (e.ctrlKey || e.metaKey) {
|
||||||
|
this.handleSubmit();
|
||||||
|
} else {
|
||||||
|
e.preventDefault();
|
||||||
|
this.textareaRef.current?.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.blurOnEscape(e);
|
||||||
};
|
};
|
||||||
|
|
||||||
getFulltextForCharacterCounting = () => {
|
getFulltextForCharacterCounting = () => {
|
||||||
|
@ -248,7 +267,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
value={this.props.spoilerText}
|
value={this.props.spoilerText}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
onChange={this.handleChangeSpoilerText}
|
onChange={this.handleChangeSpoilerText}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDownSpoiler}
|
||||||
ref={this.setSpoilerText}
|
ref={this.setSpoilerText}
|
||||||
suggestions={this.props.suggestions}
|
suggestions={this.props.suggestions}
|
||||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||||
|
@ -273,7 +292,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
onChange={this.handleChange}
|
onChange={this.handleChange}
|
||||||
suggestions={this.props.suggestions}
|
suggestions={this.props.suggestions}
|
||||||
onFocus={this.handleFocus}
|
onFocus={this.handleFocus}
|
||||||
onKeyDown={this.handleKeyDown}
|
onKeyDown={this.handleKeyDownPost}
|
||||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
onSuggestionSelected={this.onSuggestionSelected}
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
|
|
|
@ -10,15 +10,13 @@ import { createSelector } from '@reduxjs/toolkit';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
|
||||||
import { replyCompose } from 'mastodon/actions/compose';
|
import { replyCompose } from 'mastodon/actions/compose';
|
||||||
import { markConversationRead, deleteConversation } from 'mastodon/actions/conversations';
|
import { markConversationRead, deleteConversation } from 'mastodon/actions/conversations';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
import { muteStatus, unmuteStatus, toggleStatusSpoilers } from 'mastodon/actions/statuses';
|
import { muteStatus, unmuteStatus, toggleStatusSpoilers } from 'mastodon/actions/statuses';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import AttachmentList from 'mastodon/components/attachment_list';
|
import AttachmentList from 'mastodon/components/attachment_list';
|
||||||
import AvatarComposite from 'mastodon/components/avatar_composite';
|
import AvatarComposite from 'mastodon/components/avatar_composite';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
|
@ -169,7 +167,7 @@ export const Conversation = ({ conversation, scrollKey, onMoveUp, onMoveDown })
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<Hotkeys handlers={handlers}>
|
||||||
<div className={classNames('conversation focusable muted', { unread })} tabIndex={0}>
|
<div className={classNames('conversation focusable muted', { unread })} tabIndex={0}>
|
||||||
<div className='conversation__avatar' onClick={handleClick} role='presentation'>
|
<div className='conversation__avatar' onClick={handleClick} role='presentation'>
|
||||||
<AvatarComposite accounts={accounts} size={48} />
|
<AvatarComposite accounts={accounts} size={48} />
|
||||||
|
@ -219,7 +217,7 @@ export const Conversation = ({ conversation, scrollKey, onMoveUp, onMoveDown })
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
110
app/javascript/mastodon/features/emoji/constants.ts
Normal file
110
app/javascript/mastodon/features/emoji/constants.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
// Utility codes
|
||||||
|
export const VARIATION_SELECTOR_CODE = 0xfe0f;
|
||||||
|
export const KEYCAP_CODE = 0x20e3;
|
||||||
|
|
||||||
|
// Gender codes
|
||||||
|
export const GENDER_FEMALE_CODE = 0x2640;
|
||||||
|
export const GENDER_MALE_CODE = 0x2642;
|
||||||
|
|
||||||
|
// Skin tone codes
|
||||||
|
export const SKIN_TONE_CODES = [
|
||||||
|
0x1f3fb, // Light skin tone
|
||||||
|
0x1f3fc, // Medium-light skin tone
|
||||||
|
0x1f3fd, // Medium skin tone
|
||||||
|
0x1f3fe, // Medium-dark skin tone
|
||||||
|
0x1f3ff, // Dark skin tone
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export const EMOJIS_WITH_DARK_BORDER = [
|
||||||
|
'🎱', // 1F3B1
|
||||||
|
'🐜', // 1F41C
|
||||||
|
'⚫', // 26AB
|
||||||
|
'🖤', // 1F5A4
|
||||||
|
'⬛', // 2B1B
|
||||||
|
'◼️', // 25FC-FE0F
|
||||||
|
'◾', // 25FE
|
||||||
|
'◼️', // 25FC-FE0F
|
||||||
|
'✒️', // 2712-FE0F
|
||||||
|
'▪️', // 25AA-FE0F
|
||||||
|
'💣', // 1F4A3
|
||||||
|
'🎳', // 1F3B3
|
||||||
|
'📷', // 1F4F7
|
||||||
|
'📸', // 1F4F8
|
||||||
|
'♣️', // 2663-FE0F
|
||||||
|
'🕶️', // 1F576-FE0F
|
||||||
|
'✴️', // 2734-FE0F
|
||||||
|
'🔌', // 1F50C
|
||||||
|
'💂♀️', // 1F482-200D-2640-FE0F
|
||||||
|
'📽️', // 1F4FD-FE0F
|
||||||
|
'🍳', // 1F373
|
||||||
|
'🦍', // 1F98D
|
||||||
|
'💂', // 1F482
|
||||||
|
'🔪', // 1F52A
|
||||||
|
'🕳️', // 1F573-FE0F
|
||||||
|
'🕹️', // 1F579-FE0F
|
||||||
|
'🕋', // 1F54B
|
||||||
|
'🖊️', // 1F58A-FE0F
|
||||||
|
'🖋️', // 1F58B-FE0F
|
||||||
|
'💂♂️', // 1F482-200D-2642-FE0F
|
||||||
|
'🎤', // 1F3A4
|
||||||
|
'🎓', // 1F393
|
||||||
|
'🎥', // 1F3A5
|
||||||
|
'🎼', // 1F3BC
|
||||||
|
'♠️', // 2660-FE0F
|
||||||
|
'🎩', // 1F3A9
|
||||||
|
'🦃', // 1F983
|
||||||
|
'📼', // 1F4FC
|
||||||
|
'📹', // 1F4F9
|
||||||
|
'🎮', // 1F3AE
|
||||||
|
'🐃', // 1F403
|
||||||
|
'🏴', // 1F3F4
|
||||||
|
'🐞', // 1F41E
|
||||||
|
'🕺', // 1F57A
|
||||||
|
'📱', // 1F4F1
|
||||||
|
'📲', // 1F4F2
|
||||||
|
'🚲', // 1F6B2
|
||||||
|
'🪮', // 1FAA6
|
||||||
|
'🐦⬛', // 1F426-200D-2B1B
|
||||||
|
];
|
||||||
|
|
||||||
|
export const EMOJIS_WITH_LIGHT_BORDER = [
|
||||||
|
'👽', // 1F47D
|
||||||
|
'⚾', // 26BE
|
||||||
|
'🐔', // 1F414
|
||||||
|
'☁️', // 2601-FE0F
|
||||||
|
'💨', // 1F4A8
|
||||||
|
'🕊️', // 1F54A-FE0F
|
||||||
|
'👀', // 1F440
|
||||||
|
'🍥', // 1F365
|
||||||
|
'👻', // 1F47B
|
||||||
|
'🐐', // 1F410
|
||||||
|
'❕', // 2755
|
||||||
|
'❔', // 2754
|
||||||
|
'⛸️', // 26F8-FE0F
|
||||||
|
'🌩️', // 1F329-FE0F
|
||||||
|
'🔊', // 1F50A
|
||||||
|
'🔇', // 1F507
|
||||||
|
'📃', // 1F4C3
|
||||||
|
'🌧️', // 1F327-FE0F
|
||||||
|
'🐏', // 1F40F
|
||||||
|
'🍚', // 1F35A
|
||||||
|
'🍙', // 1F359
|
||||||
|
'🐓', // 1F413
|
||||||
|
'🐑', // 1F411
|
||||||
|
'💀', // 1F480
|
||||||
|
'☠️', // 2620-FE0F
|
||||||
|
'🌨️', // 1F328-FE0F
|
||||||
|
'🔉', // 1F509
|
||||||
|
'🔈', // 1F508
|
||||||
|
'💬', // 1F4AC
|
||||||
|
'💭', // 1F4AD
|
||||||
|
'🏐', // 1F3D0
|
||||||
|
'🏳️', // 1F3F3-FE0F
|
||||||
|
'⚪', // 26AA
|
||||||
|
'⬜', // 2B1C
|
||||||
|
'◽', // 25FD
|
||||||
|
'◻️', // 25FB-FE0F
|
||||||
|
'▫️', // 25AB-FE0F
|
||||||
|
'🪽', // 1FAE8
|
||||||
|
'🪿', // 1FABF
|
||||||
|
];
|
102
app/javascript/mastodon/features/emoji/database.ts
Normal file
102
app/javascript/mastodon/features/emoji/database.ts
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import { SUPPORTED_LOCALES } from 'emojibase';
|
||||||
|
import type { FlatCompactEmoji, Locale } from 'emojibase';
|
||||||
|
import type { DBSchema } from 'idb';
|
||||||
|
import { openDB } from 'idb';
|
||||||
|
|
||||||
|
import type { ApiCustomEmojiJSON } from '@/mastodon/api_types/custom_emoji';
|
||||||
|
|
||||||
|
import type { LocaleOrCustom } from './locale';
|
||||||
|
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
||||||
|
|
||||||
|
interface EmojiDB extends LocaleTables, DBSchema {
|
||||||
|
custom: {
|
||||||
|
key: string;
|
||||||
|
value: ApiCustomEmojiJSON;
|
||||||
|
indexes: {
|
||||||
|
category: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
etags: {
|
||||||
|
key: LocaleOrCustom;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LocaleTable {
|
||||||
|
key: string;
|
||||||
|
value: FlatCompactEmoji;
|
||||||
|
indexes: {
|
||||||
|
group: number;
|
||||||
|
label: string;
|
||||||
|
order: number;
|
||||||
|
tags: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
type LocaleTables = Record<Locale, LocaleTable>;
|
||||||
|
|
||||||
|
const SCHEMA_VERSION = 1;
|
||||||
|
|
||||||
|
const db = await openDB<EmojiDB>('mastodon-emoji', SCHEMA_VERSION, {
|
||||||
|
upgrade(database) {
|
||||||
|
const customTable = database.createObjectStore('custom', {
|
||||||
|
keyPath: 'shortcode',
|
||||||
|
autoIncrement: false,
|
||||||
|
});
|
||||||
|
customTable.createIndex('category', 'category');
|
||||||
|
|
||||||
|
database.createObjectStore('etags');
|
||||||
|
|
||||||
|
for (const locale of SUPPORTED_LOCALES) {
|
||||||
|
const localeTable = database.createObjectStore(locale, {
|
||||||
|
keyPath: 'hexcode',
|
||||||
|
autoIncrement: false,
|
||||||
|
});
|
||||||
|
localeTable.createIndex('group', 'group');
|
||||||
|
localeTable.createIndex('label', 'label');
|
||||||
|
localeTable.createIndex('order', 'order');
|
||||||
|
localeTable.createIndex('tags', 'tags', { multiEntry: true });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function putEmojiData(emojis: FlatCompactEmoji[], locale: Locale) {
|
||||||
|
const trx = db.transaction(locale, 'readwrite');
|
||||||
|
await Promise.all(emojis.map((emoji) => trx.store.put(emoji)));
|
||||||
|
await trx.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function putCustomEmojiData(emojis: ApiCustomEmojiJSON[]) {
|
||||||
|
const trx = db.transaction('custom', 'readwrite');
|
||||||
|
await Promise.all(emojis.map((emoji) => trx.store.put(emoji)));
|
||||||
|
await trx.done;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function putLatestEtag(etag: string, localeString: string) {
|
||||||
|
const locale = toSupportedLocaleOrCustom(localeString);
|
||||||
|
return db.put('etags', etag, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function searchEmojiByHexcode(hexcode: string, localeString: string) {
|
||||||
|
const locale = toSupportedLocale(localeString);
|
||||||
|
return db.get(locale, hexcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function searchEmojiByTag(tag: string, localeString: string) {
|
||||||
|
const locale = toSupportedLocale(localeString);
|
||||||
|
const range = IDBKeyRange.only(tag.toLowerCase());
|
||||||
|
return db.getAllFromIndex(locale, 'tags', range);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function searchCustomEmojiByShortcode(shortcode: string) {
|
||||||
|
return db.get('custom', shortcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadLatestEtag(localeString: string) {
|
||||||
|
const locale = toSupportedLocaleOrCustom(localeString);
|
||||||
|
const rowCount = await db.count(locale);
|
||||||
|
if (!rowCount) {
|
||||||
|
return null; // No data for this locale, return null even if there is an etag.
|
||||||
|
}
|
||||||
|
const etag = await db.get('etags', locale);
|
||||||
|
return etag ?? null;
|
||||||
|
}
|
38
app/javascript/mastodon/features/emoji/index.ts
Normal file
38
app/javascript/mastodon/features/emoji/index.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import initialState from '@/mastodon/initial_state';
|
||||||
|
|
||||||
|
import { toSupportedLocale } from './locale';
|
||||||
|
|
||||||
|
const serverLocale = toSupportedLocale(initialState?.meta.locale ?? 'en');
|
||||||
|
|
||||||
|
const worker =
|
||||||
|
'Worker' in window
|
||||||
|
? new Worker(new URL('./worker', import.meta.url), {
|
||||||
|
type: 'module',
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
export async function initializeEmoji() {
|
||||||
|
if (worker) {
|
||||||
|
worker.addEventListener('message', (event: MessageEvent<string>) => {
|
||||||
|
const { data: message } = event;
|
||||||
|
if (message === 'ready') {
|
||||||
|
worker.postMessage(serverLocale);
|
||||||
|
worker.postMessage('custom');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const { importCustomEmojiData, importEmojiData } = await import('./loader');
|
||||||
|
await Promise.all([importCustomEmojiData(), importEmojiData(serverLocale)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function loadEmojiLocale(localeString: string) {
|
||||||
|
const locale = toSupportedLocale(localeString);
|
||||||
|
|
||||||
|
if (worker) {
|
||||||
|
worker.postMessage(locale);
|
||||||
|
} else {
|
||||||
|
const { importEmojiData } = await import('./loader');
|
||||||
|
await importEmojiData(locale);
|
||||||
|
}
|
||||||
|
}
|
77
app/javascript/mastodon/features/emoji/loader.ts
Normal file
77
app/javascript/mastodon/features/emoji/loader.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { flattenEmojiData } from 'emojibase';
|
||||||
|
import type { CompactEmoji, FlatCompactEmoji } from 'emojibase';
|
||||||
|
|
||||||
|
import type { ApiCustomEmojiJSON } from '@/mastodon/api_types/custom_emoji';
|
||||||
|
import { isDevelopment } from '@/mastodon/utils/environment';
|
||||||
|
|
||||||
|
import {
|
||||||
|
putEmojiData,
|
||||||
|
putCustomEmojiData,
|
||||||
|
loadLatestEtag,
|
||||||
|
putLatestEtag,
|
||||||
|
} from './database';
|
||||||
|
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
||||||
|
import type { LocaleOrCustom } from './locale';
|
||||||
|
|
||||||
|
export async function importEmojiData(localeString: string) {
|
||||||
|
const locale = toSupportedLocale(localeString);
|
||||||
|
const emojis = await fetchAndCheckEtag<CompactEmoji[]>(locale);
|
||||||
|
if (!emojis) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis);
|
||||||
|
await putEmojiData(flattenedEmojis, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function importCustomEmojiData() {
|
||||||
|
const emojis = await fetchAndCheckEtag<ApiCustomEmojiJSON[]>('custom');
|
||||||
|
if (!emojis) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await putCustomEmojiData(emojis);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchAndCheckEtag<ResultType extends object[]>(
|
||||||
|
localeOrCustom: LocaleOrCustom,
|
||||||
|
): Promise<ResultType | null> {
|
||||||
|
const locale = toSupportedLocaleOrCustom(localeOrCustom);
|
||||||
|
|
||||||
|
let uri: string;
|
||||||
|
if (locale === 'custom') {
|
||||||
|
uri = '/api/v1/custom_emojis';
|
||||||
|
} else {
|
||||||
|
uri = `/packs${isDevelopment() ? '-dev' : ''}/emoji/${locale}.json`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldEtag = await loadLatestEtag(locale);
|
||||||
|
const response = await fetch(uri, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'If-None-Match': oldEtag ?? '', // Send the old ETag to check for modifications
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// If not modified, return null
|
||||||
|
if (response.status === 304) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to fetch emoji data for ${localeOrCustom}: ${response.statusText}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = (await response.json()) as ResultType;
|
||||||
|
if (!Array.isArray(data)) {
|
||||||
|
throw new Error(
|
||||||
|
`Unexpected data format for ${localeOrCustom}: expected an array`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the ETag for future requests
|
||||||
|
const etag = response.headers.get('ETag');
|
||||||
|
if (etag) {
|
||||||
|
await putLatestEtag(etag, localeOrCustom);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
29
app/javascript/mastodon/features/emoji/locale.test.ts
Normal file
29
app/javascript/mastodon/features/emoji/locale.test.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import { SUPPORTED_LOCALES } from 'emojibase';
|
||||||
|
|
||||||
|
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
||||||
|
|
||||||
|
describe('toSupportedLocale', () => {
|
||||||
|
test('returns the same locale if it is supported', () => {
|
||||||
|
for (const locale of SUPPORTED_LOCALES) {
|
||||||
|
expect(toSupportedLocale(locale)).toBe(locale);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('returns "en" for unsupported locales', () => {
|
||||||
|
const unsupportedLocales = ['xx', 'fr-CA'];
|
||||||
|
for (const locale of unsupportedLocales) {
|
||||||
|
expect(toSupportedLocale(locale)).toBe('en');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toSupportedLocaleOrCustom', () => {
|
||||||
|
test('returns custom for "custom" locale', () => {
|
||||||
|
expect(toSupportedLocaleOrCustom('custom')).toBe('custom');
|
||||||
|
});
|
||||||
|
test('returns supported locale for valid locales', () => {
|
||||||
|
for (const locale of SUPPORTED_LOCALES) {
|
||||||
|
expect(toSupportedLocaleOrCustom(locale)).toBe(locale);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
23
app/javascript/mastodon/features/emoji/locale.ts
Normal file
23
app/javascript/mastodon/features/emoji/locale.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import type { Locale } from 'emojibase';
|
||||||
|
import { SUPPORTED_LOCALES } from 'emojibase';
|
||||||
|
|
||||||
|
export type LocaleOrCustom = Locale | 'custom';
|
||||||
|
|
||||||
|
export function toSupportedLocale(localeBase: string): Locale {
|
||||||
|
const locale = localeBase.toLowerCase();
|
||||||
|
if (isSupportedLocale(locale)) {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
return 'en'; // Default to English if unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toSupportedLocaleOrCustom(locale: string): LocaleOrCustom {
|
||||||
|
if (locale.toLowerCase() === 'custom') {
|
||||||
|
return 'custom';
|
||||||
|
}
|
||||||
|
return toSupportedLocale(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSupportedLocale(locale: string): locale is Locale {
|
||||||
|
return SUPPORTED_LOCALES.includes(locale.toLowerCase() as Locale);
|
||||||
|
}
|
101
app/javascript/mastodon/features/emoji/normalize.test.ts
Normal file
101
app/javascript/mastodon/features/emoji/normalize.test.ts
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import { readdir } from 'fs/promises';
|
||||||
|
import { basename, resolve } from 'path';
|
||||||
|
|
||||||
|
import { flattenEmojiData } from 'emojibase';
|
||||||
|
import unicodeRawEmojis from 'emojibase-data/en/data.json';
|
||||||
|
|
||||||
|
import {
|
||||||
|
twemojiHasBorder,
|
||||||
|
twemojiToUnicodeInfo,
|
||||||
|
unicodeToTwemojiHex,
|
||||||
|
CODES_WITH_DARK_BORDER,
|
||||||
|
CODES_WITH_LIGHT_BORDER,
|
||||||
|
emojiToUnicodeHex,
|
||||||
|
} from './normalize';
|
||||||
|
|
||||||
|
const emojiSVGFiles = await readdir(
|
||||||
|
// This assumes tests are run from project root
|
||||||
|
resolve(process.cwd(), 'public/emoji'),
|
||||||
|
{
|
||||||
|
withFileTypes: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const svgFileNames = emojiSVGFiles
|
||||||
|
.filter((file) => file.isFile() && file.name.endsWith('.svg'))
|
||||||
|
.map((file) => basename(file.name, '.svg').toUpperCase());
|
||||||
|
const svgFileNamesWithoutBorder = svgFileNames.filter(
|
||||||
|
(fileName) => !fileName.endsWith('_BORDER'),
|
||||||
|
);
|
||||||
|
|
||||||
|
const unicodeEmojis = flattenEmojiData(unicodeRawEmojis);
|
||||||
|
|
||||||
|
describe('emojiToUnicodeHex', () => {
|
||||||
|
test.concurrent.for([
|
||||||
|
['🎱', '1F3B1'],
|
||||||
|
['🐜', '1F41C'],
|
||||||
|
['⚫', '26AB'],
|
||||||
|
['🖤', '1F5A4'],
|
||||||
|
['💀', '1F480'],
|
||||||
|
['💂♂️', '1F482-200D-2642-FE0F'],
|
||||||
|
] as const)(
|
||||||
|
'emojiToUnicodeHex converts %s to %s',
|
||||||
|
([emoji, hexcode], { expect }) => {
|
||||||
|
expect(emojiToUnicodeHex(emoji)).toBe(hexcode);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unicodeToTwemojiHex', () => {
|
||||||
|
test.concurrent.for(
|
||||||
|
unicodeEmojis
|
||||||
|
// Our version of Twemoji only supports up to version 15.1
|
||||||
|
.filter((emoji) => emoji.version < 16)
|
||||||
|
.map((emoji) => [emoji.hexcode, emoji.label] as [string, string]),
|
||||||
|
)('verifying an emoji exists for %s (%s)', ([hexcode], { expect }) => {
|
||||||
|
const result = unicodeToTwemojiHex(hexcode);
|
||||||
|
expect(svgFileNamesWithoutBorder).toContain(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('twemojiHasBorder', () => {
|
||||||
|
test.concurrent.for(
|
||||||
|
svgFileNames
|
||||||
|
.filter((file) => file.endsWith('_BORDER'))
|
||||||
|
.map((file) => {
|
||||||
|
const hexCode = file.replace('_BORDER', '');
|
||||||
|
return [
|
||||||
|
hexCode,
|
||||||
|
CODES_WITH_LIGHT_BORDER.includes(hexCode),
|
||||||
|
CODES_WITH_DARK_BORDER.includes(hexCode),
|
||||||
|
] as const;
|
||||||
|
}),
|
||||||
|
)('twemojiHasBorder for %s', ([hexCode, isLight, isDark], { expect }) => {
|
||||||
|
const result = twemojiHasBorder(hexCode);
|
||||||
|
expect(result).toHaveProperty('hexCode', hexCode);
|
||||||
|
expect(result).toHaveProperty('hasLightBorder', isLight);
|
||||||
|
expect(result).toHaveProperty('hasDarkBorder', isDark);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('twemojiToUnicodeInfo', () => {
|
||||||
|
const unicodeCodeSet = new Set(unicodeEmojis.map((emoji) => emoji.hexcode));
|
||||||
|
|
||||||
|
test.concurrent.for(svgFileNamesWithoutBorder)(
|
||||||
|
'verifying SVG file %s maps to Unicode emoji',
|
||||||
|
(svgFileName, { expect }) => {
|
||||||
|
assert(!!svgFileName);
|
||||||
|
const result = twemojiToUnicodeInfo(svgFileName);
|
||||||
|
const hexcode = typeof result === 'string' ? result : result.unqualified;
|
||||||
|
if (!hexcode) {
|
||||||
|
// No hexcode means this is a special case like the Shibuya 109 emoji
|
||||||
|
expect(result).toHaveProperty('label');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(!!hexcode);
|
||||||
|
expect(
|
||||||
|
unicodeCodeSet.has(hexcode),
|
||||||
|
`${hexcode} (${svgFileName}) not found`,
|
||||||
|
).toBeTruthy();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
173
app/javascript/mastodon/features/emoji/normalize.ts
Normal file
173
app/javascript/mastodon/features/emoji/normalize.ts
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
import {
|
||||||
|
VARIATION_SELECTOR_CODE,
|
||||||
|
KEYCAP_CODE,
|
||||||
|
GENDER_FEMALE_CODE,
|
||||||
|
GENDER_MALE_CODE,
|
||||||
|
SKIN_TONE_CODES,
|
||||||
|
EMOJIS_WITH_DARK_BORDER,
|
||||||
|
EMOJIS_WITH_LIGHT_BORDER,
|
||||||
|
} from './constants';
|
||||||
|
|
||||||
|
// Misc codes that have special handling
|
||||||
|
const SKIER_CODE = 0x26f7;
|
||||||
|
const CHRISTMAS_TREE_CODE = 0x1f384;
|
||||||
|
const MR_CLAUS_CODE = 0x1f385;
|
||||||
|
const EYE_CODE = 0x1f441;
|
||||||
|
const LEVITATING_PERSON_CODE = 0x1f574;
|
||||||
|
const SPEECH_BUBBLE_CODE = 0x1f5e8;
|
||||||
|
const MS_CLAUS_CODE = 0x1f936;
|
||||||
|
|
||||||
|
export function emojiToUnicodeHex(emoji: string): string {
|
||||||
|
const codes: number[] = [];
|
||||||
|
for (const char of emoji) {
|
||||||
|
const code = char.codePointAt(0);
|
||||||
|
if (code !== undefined) {
|
||||||
|
codes.push(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hexNumbersToString(codes);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unicodeToTwemojiHex(unicodeHex: string): string {
|
||||||
|
const codes = hexStringToNumbers(unicodeHex);
|
||||||
|
const normalizedCodes: number[] = [];
|
||||||
|
for (let i = 0; i < codes.length; i++) {
|
||||||
|
const code = codes[i];
|
||||||
|
if (!code) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Some emoji have their variation selector removed
|
||||||
|
if (code === VARIATION_SELECTOR_CODE) {
|
||||||
|
// Key emoji
|
||||||
|
if (i === 1 && codes.at(-1) === KEYCAP_CODE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Eye in speech bubble
|
||||||
|
if (codes.at(0) === EYE_CODE && codes.at(-2) === SPEECH_BUBBLE_CODE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This removes zero padding to correctly match the SVG filenames
|
||||||
|
normalizedCodes.push(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hexNumbersToString(normalizedCodes, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TwemojiBorderInfo {
|
||||||
|
hexCode: string;
|
||||||
|
hasLightBorder: boolean;
|
||||||
|
hasDarkBorder: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CODES_WITH_DARK_BORDER =
|
||||||
|
EMOJIS_WITH_DARK_BORDER.map(emojiToUnicodeHex);
|
||||||
|
|
||||||
|
export const CODES_WITH_LIGHT_BORDER =
|
||||||
|
EMOJIS_WITH_LIGHT_BORDER.map(emojiToUnicodeHex);
|
||||||
|
|
||||||
|
export function twemojiHasBorder(twemojiHex: string): TwemojiBorderInfo {
|
||||||
|
const normalizedHex = twemojiHex.toUpperCase();
|
||||||
|
let hasLightBorder = false;
|
||||||
|
let hasDarkBorder = false;
|
||||||
|
if (CODES_WITH_LIGHT_BORDER.includes(normalizedHex)) {
|
||||||
|
hasLightBorder = true;
|
||||||
|
}
|
||||||
|
if (CODES_WITH_DARK_BORDER.includes(normalizedHex)) {
|
||||||
|
hasDarkBorder = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
hexCode: normalizedHex,
|
||||||
|
hasLightBorder,
|
||||||
|
hasDarkBorder,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TwemojiSpecificEmoji {
|
||||||
|
unqualified?: string;
|
||||||
|
gender?: number;
|
||||||
|
skin?: number;
|
||||||
|
label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize man/woman to male/female
|
||||||
|
const GENDER_CODES_MAP: Record<number, number> = {
|
||||||
|
[GENDER_FEMALE_CODE]: GENDER_FEMALE_CODE,
|
||||||
|
[GENDER_MALE_CODE]: GENDER_MALE_CODE,
|
||||||
|
// These are man/woman markers, but are used for gender sometimes.
|
||||||
|
[0x1f468]: GENDER_MALE_CODE,
|
||||||
|
[0x1f469]: GENDER_FEMALE_CODE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TWEMOJI_SPECIAL_CASES: Record<string, string | TwemojiSpecificEmoji> = {
|
||||||
|
'1F441-200D-1F5E8': '1F441-FE0F-200D-1F5E8-FE0F', // Eye in speech bubble
|
||||||
|
// An emoji that was never ported to the Unicode standard.
|
||||||
|
// See: https://emojipedia.org/shibuya
|
||||||
|
E50A: { label: 'Shibuya 109' },
|
||||||
|
};
|
||||||
|
|
||||||
|
export function twemojiToUnicodeInfo(
|
||||||
|
twemojiHex: string,
|
||||||
|
): TwemojiSpecificEmoji | string {
|
||||||
|
const specialCase = TWEMOJI_SPECIAL_CASES[twemojiHex.toUpperCase()];
|
||||||
|
if (specialCase) {
|
||||||
|
return specialCase;
|
||||||
|
}
|
||||||
|
const codes = hexStringToNumbers(twemojiHex);
|
||||||
|
let gender: undefined | number;
|
||||||
|
let skin: undefined | number;
|
||||||
|
for (const code of codes) {
|
||||||
|
if (!gender && code in GENDER_CODES_MAP) {
|
||||||
|
gender = GENDER_CODES_MAP[code];
|
||||||
|
} else if (!skin && code in SKIN_TONE_CODES) {
|
||||||
|
skin = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit if we have both skin and gender
|
||||||
|
if (skin && gender) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mappedCodes: unknown[] = codes;
|
||||||
|
|
||||||
|
if (codes.at(-1) === CHRISTMAS_TREE_CODE && codes.length >= 3 && gender) {
|
||||||
|
// Twemoji uses the christmas tree with a ZWJ for Mr. and Mrs. Claus,
|
||||||
|
// but in Unicode that only works for Mx. Claus.
|
||||||
|
const START_CODE =
|
||||||
|
gender === GENDER_FEMALE_CODE ? MS_CLAUS_CODE : MR_CLAUS_CODE;
|
||||||
|
mappedCodes = [START_CODE, skin];
|
||||||
|
} else if (codes.at(-1) === KEYCAP_CODE && codes.length === 2) {
|
||||||
|
// For key emoji, insert the variation selector
|
||||||
|
mappedCodes = [codes[0], VARIATION_SELECTOR_CODE, KEYCAP_CODE];
|
||||||
|
} else if (
|
||||||
|
(codes.at(0) === SKIER_CODE || codes.at(0) === LEVITATING_PERSON_CODE) &&
|
||||||
|
codes.length > 1
|
||||||
|
) {
|
||||||
|
// Twemoji offers more gender and skin options for the skier and levitating person emoji.
|
||||||
|
return {
|
||||||
|
unqualified: hexNumbersToString([codes.at(0)]),
|
||||||
|
skin,
|
||||||
|
gender,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return hexNumbersToString(mappedCodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexStringToNumbers(hexString: string): number[] {
|
||||||
|
return hexString
|
||||||
|
.split('-')
|
||||||
|
.map((code) => Number.parseInt(code, 16))
|
||||||
|
.filter((code) => !Number.isNaN(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexNumbersToString(codes: unknown[], padding = 4): string {
|
||||||
|
return codes
|
||||||
|
.filter(
|
||||||
|
(code): code is number =>
|
||||||
|
typeof code === 'number' && code > 0 && !Number.isNaN(code),
|
||||||
|
)
|
||||||
|
.map((code) => code.toString(16).padStart(padding, '0').toUpperCase())
|
||||||
|
.join('-');
|
||||||
|
}
|
13
app/javascript/mastodon/features/emoji/worker.ts
Normal file
13
app/javascript/mastodon/features/emoji/worker.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { importEmojiData, importCustomEmojiData } from './loader';
|
||||||
|
|
||||||
|
addEventListener('message', handleMessage);
|
||||||
|
self.postMessage('ready'); // After the worker is ready, notify the main thread
|
||||||
|
|
||||||
|
function handleMessage(event: MessageEvent<string>) {
|
||||||
|
const { data: locale } = event;
|
||||||
|
if (locale !== 'custom') {
|
||||||
|
void importEmojiData(locale);
|
||||||
|
} else {
|
||||||
|
void importCustomEmojiData();
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,16 +50,22 @@ export const MoreLink: React.FC = () => {
|
||||||
|
|
||||||
const menu = useMemo(() => {
|
const menu = useMemo(() => {
|
||||||
const arr: MenuItem[] = [
|
const arr: MenuItem[] = [
|
||||||
{ text: intl.formatMessage(messages.filters), href: '/filters' },
|
|
||||||
{ text: intl.formatMessage(messages.mutes), to: '/mutes' },
|
|
||||||
{ text: intl.formatMessage(messages.blocks), to: '/blocks' },
|
|
||||||
{
|
{
|
||||||
text: intl.formatMessage(messages.domainBlocks),
|
href: '/filters',
|
||||||
to: '/domain_blocks',
|
text: intl.formatMessage(messages.filters),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/mutes',
|
||||||
|
text: intl.formatMessage(messages.mutes),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/blocks',
|
||||||
|
text: intl.formatMessage(messages.blocks),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
to: '/domain_blocks',
|
||||||
|
text: intl.formatMessage(messages.domainBlocks),
|
||||||
},
|
},
|
||||||
];
|
|
||||||
|
|
||||||
arr.push(
|
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
href: '/settings/privacy',
|
href: '/settings/privacy',
|
||||||
|
@ -77,7 +83,7 @@ export const MoreLink: React.FC = () => {
|
||||||
href: '/settings/export',
|
href: '/settings/export',
|
||||||
text: intl.formatMessage(messages.importExport),
|
text: intl.formatMessage(messages.importExport),
|
||||||
},
|
},
|
||||||
);
|
];
|
||||||
|
|
||||||
if (canManageReports(permissions)) {
|
if (canManageReports(permissions)) {
|
||||||
arr.push(null, {
|
arr.push(null, {
|
||||||
|
@ -106,7 +112,7 @@ export const MoreLink: React.FC = () => {
|
||||||
}, [intl, dispatch, permissions]);
|
}, [intl, dispatch, permissions]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown items={menu}>
|
<Dropdown items={menu} placement='bottom-start'>
|
||||||
<button className='column-link column-link--transparent'>
|
<button className='column-link column-link--transparent'>
|
||||||
<Icon id='' icon={MoreHorizIcon} className='column-link__icon' />
|
<Icon id='' icon={MoreHorizIcon} className='column-link__icon' />
|
||||||
|
|
||||||
|
|
|
@ -431,6 +431,7 @@ export const CollapsibleNavigationPanel: React.FC = () => {
|
||||||
filterTaps: true,
|
filterTaps: true,
|
||||||
bounds: isLtrDir ? { left: 0 } : { right: 0 },
|
bounds: isLtrDir ? { left: 0 } : { right: 0 },
|
||||||
rubberband: true,
|
rubberband: true,
|
||||||
|
enabled: openable,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import { Link, withRouter } from 'react-router-dom';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||||
import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react';
|
import FlagIcon from '@/material-icons/400-24px/flag-fill.svg?react';
|
||||||
|
@ -20,6 +19,7 @@ import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
|
||||||
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
||||||
import { Account } from 'mastodon/components/account';
|
import { Account } from 'mastodon/components/account';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
||||||
import { me } from 'mastodon/initial_state';
|
import { me } from 'mastodon/initial_state';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
@ -137,7 +137,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
const { intl, unread } = this.props;
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-follow focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-follow focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.follow, { name: account.get('acct') }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='user-plus' icon={PersonAddIcon} />
|
<Icon id='user-plus' icon={PersonAddIcon} />
|
||||||
|
@ -149,7 +149,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
|
|
||||||
<Account id={account.get('id')} hidden={this.props.hidden} />
|
<Account id={account.get('id')} hidden={this.props.hidden} />
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
const { intl, unread } = this.props;
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-follow-request focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.follow_request', defaultMessage: '{name} has requested to follow you' }, { name: account.get('acct') }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='user' icon={PersonIcon} />
|
<Icon id='user' icon={PersonIcon} />
|
||||||
|
@ -169,7 +169,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
|
|
||||||
<FollowRequestContainer id={account.get('id')} hidden={this.props.hidden} />
|
<FollowRequestContainer id={account.get('id')} hidden={this.props.hidden} />
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
const { intl, unread } = this.props;
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-favourite focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-favourite focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.favourite, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='star' icon={StarIcon} className='star-icon' />
|
<Icon id='star' icon={StarIcon} className='star-icon' />
|
||||||
|
@ -217,7 +217,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
cacheMediaWidth={this.props.cacheMediaWidth}
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
const { intl, unread } = this.props;
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-reblog focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-reblog focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.reblog, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='retweet' icon={RepeatIcon} />
|
<Icon id='retweet' icon={RepeatIcon} />
|
||||||
|
@ -247,7 +247,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
cacheMediaWidth={this.props.cacheMediaWidth}
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-status focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-status focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.status, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='home' icon={HomeIcon} />
|
<Icon id='home' icon={HomeIcon} />
|
||||||
|
@ -282,7 +282,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
cacheMediaWidth={this.props.cacheMediaWidth}
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-update focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-update focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.update, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='pencil' icon={EditIcon} />
|
<Icon id='pencil' icon={EditIcon} />
|
||||||
|
@ -317,7 +317,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
cacheMediaWidth={this.props.cacheMediaWidth}
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +331,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-poll focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
|
<div className={classNames('notification notification-poll focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, message, notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='tasks' icon={InsertChartIcon} />
|
<Icon id='tasks' icon={InsertChartIcon} />
|
||||||
|
@ -358,7 +358,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
cacheMediaWidth={this.props.cacheMediaWidth}
|
cacheMediaWidth={this.props.cacheMediaWidth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-severed-relationships focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.relationshipsSevered, { name: notification.getIn(['event', 'target_name']) }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-severed-relationships focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.relationshipsSevered, { name: notification.getIn(['event', 'target_name']) }), notification.get('created_at'))}>
|
||||||
<RelationshipsSeveranceEvent
|
<RelationshipsSeveranceEvent
|
||||||
type={event.get('type')}
|
type={event.get('type')}
|
||||||
|
@ -381,7 +381,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
hidden={hidden}
|
hidden={hidden}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +394,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-moderation-warning focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.moderationWarning), notification.get('created_at'))}>
|
<div className={classNames('notification notification-moderation-warning focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.moderationWarning), notification.get('created_at'))}>
|
||||||
<ModerationWarning
|
<ModerationWarning
|
||||||
action={warning.get('action')}
|
action={warning.get('action')}
|
||||||
|
@ -402,7 +402,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
hidden={hidden}
|
hidden={hidden}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,7 +410,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
const { intl, unread } = this.props;
|
const { intl, unread } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-admin-sign-up focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminSignUp, { name: account.get('acct') }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='user-plus' icon={PersonAddIcon} />
|
<Icon id='user-plus' icon={PersonAddIcon} />
|
||||||
|
@ -422,7 +422,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
|
|
||||||
<Account id={account.get('id')} hidden={this.props.hidden} />
|
<Account id={account.get('id')} hidden={this.props.hidden} />
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
const targetLink = <bdi><Link className='notification__display-name' title={targetAccount.get('acct')} data-hover-card-account={targetAccount.get('id')} to={`/@${targetAccount.get('acct')}`} dangerouslySetInnerHTML={targetDisplayNameHtml} /></bdi>;
|
const targetLink = <bdi><Link className='notification__display-name' title={targetAccount.get('acct')} data-hover-card-account={targetAccount.get('id')} to={`/@${targetAccount.get('acct')}`} dangerouslySetInnerHTML={targetDisplayNameHtml} /></bdi>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={this.getHandlers()}>
|
<Hotkeys handlers={this.getHandlers()}>
|
||||||
<div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
|
<div className={classNames('notification notification-admin-report focusable', { unread })} tabIndex={0} aria-label={notificationForScreenReader(intl, intl.formatMessage(messages.adminReport, { name: account.get('acct'), target: notification.getIn(['report', 'target_account', 'acct']) }), notification.get('created_at'))}>
|
||||||
<div className='notification__message'>
|
<div className='notification__message'>
|
||||||
<Icon id='flag' icon={FlagIcon} />
|
<Icon id='flag' icon={FlagIcon} />
|
||||||
|
@ -450,7 +450,7 @@ class Notification extends ImmutablePureComponent {
|
||||||
|
|
||||||
<Report account={account} report={notification.get('report')} hidden={this.props.hidden} />
|
<Report account={account} report={notification.get('report')} hidden={this.props.hidden} />
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,98 +122,93 @@ export const PolicyControls: React.FC = () => {
|
||||||
value={notificationPolicy.for_not_following}
|
value={notificationPolicy.for_not_following}
|
||||||
onChange={handleFilterNotFollowing}
|
onChange={handleFilterNotFollowing}
|
||||||
options={options}
|
options={options}
|
||||||
>
|
label={
|
||||||
<strong>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_not_following_title'
|
id='notifications.policy.filter_not_following_title'
|
||||||
defaultMessage="People you don't follow"
|
defaultMessage="People you don't follow"
|
||||||
/>
|
/>
|
||||||
</strong>
|
}
|
||||||
<span className='hint'>
|
hint={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_not_following_hint'
|
id='notifications.policy.filter_not_following_hint'
|
||||||
defaultMessage='Until you manually approve them'
|
defaultMessage='Until you manually approve them'
|
||||||
/>
|
/>
|
||||||
</span>
|
}
|
||||||
</SelectWithLabel>
|
/>
|
||||||
|
|
||||||
<SelectWithLabel
|
<SelectWithLabel
|
||||||
value={notificationPolicy.for_not_followers}
|
value={notificationPolicy.for_not_followers}
|
||||||
onChange={handleFilterNotFollowers}
|
onChange={handleFilterNotFollowers}
|
||||||
options={options}
|
options={options}
|
||||||
>
|
label={
|
||||||
<strong>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_not_followers_title'
|
id='notifications.policy.filter_not_followers_title'
|
||||||
defaultMessage='People not following you'
|
defaultMessage='People not following you'
|
||||||
/>
|
/>
|
||||||
</strong>
|
}
|
||||||
<span className='hint'>
|
hint={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_not_followers_hint'
|
id='notifications.policy.filter_not_followers_hint'
|
||||||
defaultMessage='Including people who have been following you fewer than {days, plural, one {one day} other {# days}}'
|
defaultMessage='Including people who have been following you fewer than {days, plural, one {one day} other {# days}}'
|
||||||
values={{ days: 3 }}
|
values={{ days: 3 }}
|
||||||
/>
|
/>
|
||||||
</span>
|
}
|
||||||
</SelectWithLabel>
|
/>
|
||||||
|
|
||||||
<SelectWithLabel
|
<SelectWithLabel
|
||||||
value={notificationPolicy.for_new_accounts}
|
value={notificationPolicy.for_new_accounts}
|
||||||
onChange={handleFilterNewAccounts}
|
onChange={handleFilterNewAccounts}
|
||||||
options={options}
|
options={options}
|
||||||
>
|
label={
|
||||||
<strong>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_new_accounts_title'
|
id='notifications.policy.filter_new_accounts_title'
|
||||||
defaultMessage='New accounts'
|
defaultMessage='New accounts'
|
||||||
/>
|
/>
|
||||||
</strong>
|
}
|
||||||
<span className='hint'>
|
hint={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_new_accounts.hint'
|
id='notifications.policy.filter_new_accounts.hint'
|
||||||
defaultMessage='Created within the past {days, plural, one {one day} other {# days}}'
|
defaultMessage='Created within the past {days, plural, one {one day} other {# days}}'
|
||||||
values={{ days: 30 }}
|
values={{ days: 30 }}
|
||||||
/>
|
/>
|
||||||
</span>
|
}
|
||||||
</SelectWithLabel>
|
/>
|
||||||
|
|
||||||
<SelectWithLabel
|
<SelectWithLabel
|
||||||
value={notificationPolicy.for_private_mentions}
|
value={notificationPolicy.for_private_mentions}
|
||||||
onChange={handleFilterPrivateMentions}
|
onChange={handleFilterPrivateMentions}
|
||||||
options={options}
|
options={options}
|
||||||
>
|
label={
|
||||||
<strong>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_private_mentions_title'
|
id='notifications.policy.filter_private_mentions_title'
|
||||||
defaultMessage='Unsolicited private mentions'
|
defaultMessage='Unsolicited private mentions'
|
||||||
/>
|
/>
|
||||||
</strong>
|
}
|
||||||
<span className='hint'>
|
hint={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_private_mentions_hint'
|
id='notifications.policy.filter_private_mentions_hint'
|
||||||
defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender"
|
defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender"
|
||||||
/>
|
/>
|
||||||
</span>
|
}
|
||||||
</SelectWithLabel>
|
/>
|
||||||
|
|
||||||
<SelectWithLabel
|
<SelectWithLabel
|
||||||
value={notificationPolicy.for_limited_accounts}
|
value={notificationPolicy.for_limited_accounts}
|
||||||
onChange={handleFilterLimitedAccounts}
|
onChange={handleFilterLimitedAccounts}
|
||||||
options={options}
|
options={options}
|
||||||
>
|
label={
|
||||||
<strong>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_limited_accounts_title'
|
id='notifications.policy.filter_limited_accounts_title'
|
||||||
defaultMessage='Moderated accounts'
|
defaultMessage='Moderated accounts'
|
||||||
/>
|
/>
|
||||||
</strong>
|
}
|
||||||
<span className='hint'>
|
hint={
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='notifications.policy.filter_limited_accounts_hint'
|
id='notifications.policy.filter_limited_accounts_hint'
|
||||||
defaultMessage='Limited by server moderators'
|
defaultMessage='Limited by server moderators'
|
||||||
/>
|
/>
|
||||||
</span>
|
}
|
||||||
</SelectWithLabel>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { PropsWithChildren } from 'react';
|
import type { PropsWithChildren } from 'react';
|
||||||
import { useCallback, useState, useRef } from 'react';
|
import { useCallback, useState, useRef, useId } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ interface DropdownProps {
|
||||||
options: SelectItem[];
|
options: SelectItem[];
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
|
'aria-labelledby': string;
|
||||||
|
'aria-describedby'?: string;
|
||||||
placement?: Placement;
|
placement?: Placement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,51 +26,33 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||||
options,
|
options,
|
||||||
disabled,
|
disabled,
|
||||||
onChange,
|
onChange,
|
||||||
|
'aria-labelledby': ariaLabelledBy,
|
||||||
|
'aria-describedby': ariaDescribedBy,
|
||||||
placement: initialPlacement = 'bottom-end',
|
placement: initialPlacement = 'bottom-end',
|
||||||
}) => {
|
}) => {
|
||||||
const activeElementRef = useRef<Element | null>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const containerRef = useRef(null);
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
const [isOpen, setOpen] = useState<boolean>(false);
|
const [isOpen, setOpen] = useState<boolean>(false);
|
||||||
const [placement, setPlacement] = useState<Placement>(initialPlacement);
|
const [placement, setPlacement] = useState<Placement>(initialPlacement);
|
||||||
|
const uniqueId = useId();
|
||||||
const handleToggle = useCallback(() => {
|
const menuId = `${uniqueId}-menu`;
|
||||||
if (
|
const buttonLabelId = `${uniqueId}-button`;
|
||||||
isOpen &&
|
|
||||||
activeElementRef.current &&
|
|
||||||
activeElementRef.current instanceof HTMLElement
|
|
||||||
) {
|
|
||||||
activeElementRef.current.focus({ preventScroll: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
setOpen(!isOpen);
|
|
||||||
}, [isOpen, setOpen]);
|
|
||||||
|
|
||||||
const handleMouseDown = useCallback(() => {
|
|
||||||
if (!isOpen) activeElementRef.current = document.activeElement;
|
|
||||||
}, [isOpen]);
|
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
|
||||||
(e: React.KeyboardEvent) => {
|
|
||||||
switch (e.key) {
|
|
||||||
case ' ':
|
|
||||||
case 'Enter':
|
|
||||||
if (!isOpen) activeElementRef.current = document.activeElement;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[isOpen],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleClose = useCallback(() => {
|
const handleClose = useCallback(() => {
|
||||||
if (
|
if (isOpen && buttonRef.current) {
|
||||||
isOpen &&
|
buttonRef.current.focus({ preventScroll: true });
|
||||||
activeElementRef.current &&
|
}
|
||||||
activeElementRef.current instanceof HTMLElement
|
|
||||||
)
|
|
||||||
activeElementRef.current.focus({ preventScroll: true });
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}, [isOpen]);
|
}, [isOpen]);
|
||||||
|
|
||||||
|
const handleToggle = useCallback(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
handleClose();
|
||||||
|
} else {
|
||||||
|
setOpen(true);
|
||||||
|
}
|
||||||
|
}, [isOpen, handleClose]);
|
||||||
|
|
||||||
const handleOverlayEnter = useCallback(
|
const handleOverlayEnter = useCallback(
|
||||||
(state: Partial<PopperState>) => {
|
(state: Partial<PopperState>) => {
|
||||||
if (state.placement) setPlacement(state.placement);
|
if (state.placement) setPlacement(state.placement);
|
||||||
|
@ -82,13 +66,18 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||||
<div ref={containerRef}>
|
<div ref={containerRef}>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
|
ref={buttonRef}
|
||||||
onClick={handleToggle}
|
onClick={handleToggle}
|
||||||
onMouseDown={handleMouseDown}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
aria-expanded={isOpen}
|
||||||
|
aria-controls={menuId}
|
||||||
|
aria-labelledby={`${ariaLabelledBy} ${buttonLabelId}`}
|
||||||
|
aria-describedby={ariaDescribedBy}
|
||||||
className={classNames('dropdown-button', { active: isOpen })}
|
className={classNames('dropdown-button', { active: isOpen })}
|
||||||
>
|
>
|
||||||
<span className='dropdown-button__label'>{valueOption?.text}</span>
|
<span id={buttonLabelId} className='dropdown-button__label'>
|
||||||
|
{valueOption?.text}
|
||||||
|
</span>
|
||||||
<Icon id='down' icon={ArrowDropDownIcon} />
|
<Icon id='down' icon={ArrowDropDownIcon} />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
@ -101,7 +90,7 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||||
popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }}
|
popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }}
|
||||||
>
|
>
|
||||||
{({ props, placement }) => (
|
{({ props, placement }) => (
|
||||||
<div {...props}>
|
<div {...props} id={menuId}>
|
||||||
<div
|
<div
|
||||||
className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}
|
className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}
|
||||||
>
|
>
|
||||||
|
@ -123,6 +112,8 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||||
interface Props {
|
interface Props {
|
||||||
value: string;
|
value: string;
|
||||||
options: SelectItem[];
|
options: SelectItem[];
|
||||||
|
label: string | React.ReactElement;
|
||||||
|
hint: string | React.ReactElement;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
@ -130,13 +121,26 @@ interface Props {
|
||||||
export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
||||||
value,
|
value,
|
||||||
options,
|
options,
|
||||||
|
label,
|
||||||
|
hint,
|
||||||
disabled,
|
disabled,
|
||||||
children,
|
|
||||||
onChange,
|
onChange,
|
||||||
}) => {
|
}) => {
|
||||||
|
const uniqueId = useId();
|
||||||
|
const labelId = `${uniqueId}-label`;
|
||||||
|
const descId = `${uniqueId}-desc`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
// This label is only used for its click-forwarding behaviour,
|
||||||
|
// accessible names are assigned manually
|
||||||
|
// eslint-disable-next-line jsx-a11y/label-has-associated-control
|
||||||
<label className='app-form__toggle'>
|
<label className='app-form__toggle'>
|
||||||
<div className='app-form__toggle__label'>{children}</div>
|
<div className='app-form__toggle__label'>
|
||||||
|
<strong id={labelId}>{label}</strong>
|
||||||
|
<span className='hint' id={descId}>
|
||||||
|
{hint}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='app-form__toggle__toggle'>
|
<div className='app-form__toggle__toggle'>
|
||||||
<div>
|
<div>
|
||||||
|
@ -144,6 +148,8 @@ export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
aria-labelledby={labelId}
|
||||||
|
aria-describedby={descId}
|
||||||
options={options}
|
options={options}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import { navigateToProfile } from 'mastodon/actions/accounts';
|
import { navigateToProfile } from 'mastodon/actions/accounts';
|
||||||
import { mentionComposeById } from 'mastodon/actions/compose';
|
import { mentionComposeById } from 'mastodon/actions/compose';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import type { NotificationGroup as NotificationGroupModel } from 'mastodon/models/notification_group';
|
import type { NotificationGroup as NotificationGroupModel } from 'mastodon/models/notification_group';
|
||||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
|
@ -156,5 +155,5 @@ export const NotificationGroup: React.FC<{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <HotKeys handlers={handlers}>{content}</HotKeys>;
|
return <Hotkeys handlers={handlers}>{content}</Hotkeys>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,12 +3,11 @@ import type { JSX } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import { replyComposeById } from 'mastodon/actions/compose';
|
import { replyComposeById } from 'mastodon/actions/compose';
|
||||||
import { navigateToStatus } from 'mastodon/actions/statuses';
|
import { navigateToStatus } from 'mastodon/actions/statuses';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import type { IconProp } from 'mastodon/components/icon';
|
import type { IconProp } from 'mastodon/components/icon';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||||
|
@ -91,7 +90,7 @@ export const NotificationGroupWithStatus: React.FC<{
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<Hotkeys handlers={handlers}>
|
||||||
<div
|
<div
|
||||||
role='button'
|
role='button'
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -149,6 +148,6 @@ export const NotificationGroupWithStatus: React.FC<{
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,14 +2,13 @@ import { useMemo } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import { replyComposeById } from 'mastodon/actions/compose';
|
import { replyComposeById } from 'mastodon/actions/compose';
|
||||||
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
||||||
import {
|
import {
|
||||||
navigateToStatus,
|
navigateToStatus,
|
||||||
toggleStatusSpoilers,
|
toggleStatusSpoilers,
|
||||||
} from 'mastodon/actions/statuses';
|
} from 'mastodon/actions/statuses';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import type { IconProp } from 'mastodon/components/icon';
|
import type { IconProp } from 'mastodon/components/icon';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
||||||
|
@ -83,7 +82,7 @@ export const NotificationWithStatus: React.FC<{
|
||||||
if (!statusId || isFiltered) return null;
|
if (!statusId || isFiltered) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys handlers={handlers}>
|
<Hotkeys handlers={handlers}>
|
||||||
<div
|
<div
|
||||||
role='button'
|
role='button'
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -111,6 +110,6 @@ export const NotificationWithStatus: React.FC<{
|
||||||
unfocusable
|
unfocusable
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,10 +10,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react';
|
import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react';
|
||||||
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
|
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import { TimelineHint } from 'mastodon/components/timeline_hint';
|
import { TimelineHint } from 'mastodon/components/timeline_hint';
|
||||||
|
@ -616,7 +615,7 @@ class Status extends ImmutablePureComponent {
|
||||||
<div className={classNames('scrollable', { fullscreen })} ref={this.setContainerRef}>
|
<div className={classNames('scrollable', { fullscreen })} ref={this.setContainerRef}>
|
||||||
{ancestors}
|
{ancestors}
|
||||||
|
|
||||||
<HotKeys handlers={handlers}>
|
<Hotkeys handlers={handlers}>
|
||||||
<div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)} ref={this.setStatusRef}>
|
<div className={classNames('focusable', 'detailed-status__wrapper', `detailed-status__wrapper-${status.get('visibility')}`)} tabIndex={0} aria-label={textForScreenReader(intl, status, false)} ref={this.setStatusRef}>
|
||||||
<DetailedStatus
|
<DetailedStatus
|
||||||
key={`details-${status.get('id')}`}
|
key={`details-${status.get('id')}`}
|
||||||
|
@ -654,7 +653,7 @@ class Status extends ImmutablePureComponent {
|
||||||
onEmbed={this.handleEmbed}
|
onEmbed={this.handleEmbed}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
|
|
||||||
{descendants}
|
{descendants}
|
||||||
{remoteHint}
|
{remoteHint}
|
||||||
|
|
|
@ -9,13 +9,13 @@ import { Redirect, Route, withRouter } from 'react-router-dom';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import { HotKeys } from 'react-hotkeys';
|
|
||||||
|
|
||||||
import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app';
|
import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app';
|
||||||
import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers';
|
import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers';
|
||||||
import { fetchNotifications } from 'mastodon/actions/notification_groups';
|
import { fetchNotifications } from 'mastodon/actions/notification_groups';
|
||||||
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
|
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
|
||||||
import { AlertsController } from 'mastodon/components/alerts_controller';
|
import { AlertsController } from 'mastodon/components/alerts_controller';
|
||||||
|
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||||
import { HoverCardController } from 'mastodon/components/hover_card_controller';
|
import { HoverCardController } from 'mastodon/components/hover_card_controller';
|
||||||
import { PictureInPicture } from 'mastodon/features/picture_in_picture';
|
import { PictureInPicture } from 'mastodon/features/picture_in_picture';
|
||||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
@ -98,40 +98,6 @@ const mapStateToProps = state => ({
|
||||||
username: state.getIn(['accounts', me, 'username']),
|
username: state.getIn(['accounts', me, 'username']),
|
||||||
});
|
});
|
||||||
|
|
||||||
const keyMap = {
|
|
||||||
help: '?',
|
|
||||||
new: 'n',
|
|
||||||
search: ['s', '/'],
|
|
||||||
forceNew: 'option+n',
|
|
||||||
toggleComposeSpoilers: 'option+x',
|
|
||||||
focusColumn: ['1', '2', '3', '4', '5', '6', '7', '8', '9'],
|
|
||||||
reply: 'r',
|
|
||||||
favourite: 'f',
|
|
||||||
boost: 'b',
|
|
||||||
mention: 'm',
|
|
||||||
open: ['enter', 'o'],
|
|
||||||
openProfile: 'p',
|
|
||||||
moveDown: ['down', 'j'],
|
|
||||||
moveUp: ['up', 'k'],
|
|
||||||
back: 'backspace',
|
|
||||||
goToHome: 'g h',
|
|
||||||
goToNotifications: 'g n',
|
|
||||||
goToLocal: 'g l',
|
|
||||||
goToFederated: 'g t',
|
|
||||||
goToDirect: 'g d',
|
|
||||||
goToStart: 'g s',
|
|
||||||
goToFavourites: 'g f',
|
|
||||||
goToPinned: 'g p',
|
|
||||||
goToProfile: 'g u',
|
|
||||||
goToBlocked: 'g b',
|
|
||||||
goToMuted: 'g m',
|
|
||||||
goToRequests: 'g r',
|
|
||||||
toggleHidden: 'x',
|
|
||||||
toggleSensitive: 'h',
|
|
||||||
openMedia: 'e',
|
|
||||||
onTranslate: 't',
|
|
||||||
};
|
|
||||||
|
|
||||||
class SwitchingColumnsArea extends PureComponent {
|
class SwitchingColumnsArea extends PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
identity: identityContextPropShape,
|
identity: identityContextPropShape,
|
||||||
|
@ -400,6 +366,10 @@ class UI extends PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleDonate = () => {
|
||||||
|
location.href = 'https://joinmastodon.org/sponsors#donate'
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { signedIn } = this.props.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
|
@ -426,10 +396,6 @@ class UI extends PureComponent {
|
||||||
|
|
||||||
setTimeout(() => this.props.dispatch(fetchServer()), 3000);
|
setTimeout(() => this.props.dispatch(fetchServer()), 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hotkeys.__mousetrap__.stopCallback = (e, element) => {
|
|
||||||
return ['TEXTAREA', 'SELECT', 'INPUT'].includes(element.tagName);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
@ -509,10 +475,6 @@ class UI extends PureComponent {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setHotkeysRef = c => {
|
|
||||||
this.hotkeys = c;
|
|
||||||
};
|
|
||||||
|
|
||||||
handleHotkeyToggleHelp = () => {
|
handleHotkeyToggleHelp = () => {
|
||||||
if (this.props.location.pathname === '/keyboard-shortcuts') {
|
if (this.props.location.pathname === '/keyboard-shortcuts') {
|
||||||
this.props.history.goBack();
|
this.props.history.goBack();
|
||||||
|
@ -593,10 +555,11 @@ class UI extends PureComponent {
|
||||||
goToBlocked: this.handleHotkeyGoToBlocked,
|
goToBlocked: this.handleHotkeyGoToBlocked,
|
||||||
goToMuted: this.handleHotkeyGoToMuted,
|
goToMuted: this.handleHotkeyGoToMuted,
|
||||||
goToRequests: this.handleHotkeyGoToRequests,
|
goToRequests: this.handleHotkeyGoToRequests,
|
||||||
|
cheat: this.handleDonate,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HotKeys keyMap={keyMap} handlers={handlers} ref={this.setHotkeysRef} attach={window} focused>
|
<Hotkeys global handlers={handlers}>
|
||||||
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef}>
|
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef}>
|
||||||
<SwitchingColumnsArea identity={this.props.identity} location={location} singleColumn={layout === 'mobile' || layout === 'single-column'} forceOnboarding={firstLaunch && newAccount}>
|
<SwitchingColumnsArea identity={this.props.identity} location={location} singleColumn={layout === 'mobile' || layout === 'single-column'} forceOnboarding={firstLaunch && newAccount}>
|
||||||
{children}
|
{children}
|
||||||
|
@ -611,7 +574,7 @@ class UI extends PureComponent {
|
||||||
<ModalContainer />
|
<ModalContainer />
|
||||||
<UploadArea active={draggingOver} onClose={this.closeUploadModal} />
|
<UploadArea active={draggingOver} onClose={this.closeUploadModal} />
|
||||||
</div>
|
</div>
|
||||||
</HotKeys>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,14 @@ import { openURL } from 'mastodon/actions/search';
|
||||||
import { useAppDispatch } from 'mastodon/store';
|
import { useAppDispatch } from 'mastodon/store';
|
||||||
|
|
||||||
const isMentionClick = (element: HTMLAnchorElement) =>
|
const isMentionClick = (element: HTMLAnchorElement) =>
|
||||||
element.classList.contains('mention');
|
element.classList.contains('mention') &&
|
||||||
|
!element.classList.contains('hashtag');
|
||||||
|
|
||||||
const isHashtagClick = (element: HTMLAnchorElement) =>
|
const isHashtagClick = (element: HTMLAnchorElement) =>
|
||||||
element.textContent?.[0] === '#' ||
|
element.textContent?.[0] === '#' ||
|
||||||
element.previousSibling?.textContent?.endsWith('#');
|
element.previousSibling?.textContent?.endsWith('#');
|
||||||
|
|
||||||
export const useLinks = () => {
|
export const useLinks = (skipHashtags?: boolean) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
@ -61,12 +62,12 @@ export const useLinks = () => {
|
||||||
if (isMentionClick(target)) {
|
if (isMentionClick(target)) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
void handleMentionClick(target);
|
void handleMentionClick(target);
|
||||||
} else if (isHashtagClick(target)) {
|
} else if (isHashtagClick(target) && !skipHashtags) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleHashtagClick(target);
|
handleHashtagClick(target);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[handleMentionClick, handleHashtagClick],
|
[skipHashtags, handleMentionClick, handleHashtagClick],
|
||||||
);
|
);
|
||||||
|
|
||||||
return handleClick;
|
return handleClick;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {[code: string, name: string, localName: string]} InitialStateLanguage
|
* @typedef {[code: string, name: string, localName: string]} InitialStateLanguage
|
||||||
*/
|
*/
|
||||||
|
@ -64,6 +63,7 @@
|
||||||
* @property {boolean=} critical_updates_pending
|
* @property {boolean=} critical_updates_pending
|
||||||
* @property {InitialStateMeta} meta
|
* @property {InitialStateMeta} meta
|
||||||
* @property {Role?} role
|
* @property {Role?} role
|
||||||
|
* @property {string[]} features
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const element = document.getElementById('initial-state');
|
const element = document.getElementById('initial-state');
|
||||||
|
@ -140,4 +140,12 @@ export function getAccessToken() {
|
||||||
return getMeta('access_token');
|
return getMeta('access_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} feature
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isFeatureEnabled(feature) {
|
||||||
|
return initialState?.features?.includes(feature) || false;
|
||||||
|
}
|
||||||
|
|
||||||
export default initialState;
|
export default initialState;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"about.blocks": "Мадэраваныя серверы",
|
"about.blocks": "Мадэраваныя серверы",
|
||||||
"about.contact": "Кантакт:",
|
"about.contact": "Кантакт:",
|
||||||
|
"about.default_locale": "Прадвызначаная",
|
||||||
"about.disclaimer": "Mastodon - свабоднае праграмнае забеспячэнне, з адкрытым зыходным кодам, і гандлёвай маркай Mastodon gGmbH.",
|
"about.disclaimer": "Mastodon - свабоднае праграмнае забеспячэнне, з адкрытым зыходным кодам, і гандлёвай маркай Mastodon gGmbH.",
|
||||||
"about.domain_blocks.no_reason_available": "Прычына недаступная",
|
"about.domain_blocks.no_reason_available": "Прычына недаступная",
|
||||||
"about.domain_blocks.preamble": "Mastodon, у асноўным, дазваляе вам праглядаць кантэнт і ўзаемадзейнічаць з карыстальнікамі з іншых сервераў у федэсвету. Гэтыя выключэнні былі зроблены дакладна на гэтым серверы.",
|
"about.domain_blocks.preamble": "Mastodon, у асноўным, дазваляе вам праглядаць кантэнт і ўзаемадзейнічаць з карыстальнікамі з іншых сервераў у федэсвету. Гэтыя выключэнні былі зроблены дакладна на гэтым серверы.",
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
"about.domain_blocks.silenced.title": "Абмежаваны",
|
"about.domain_blocks.silenced.title": "Абмежаваны",
|
||||||
"about.domain_blocks.suspended.explanation": "Ніякая інфармацыя з гэтага сервера не будзе апрацавана, захавана або абменена, узаемадзеянне або камунікацыя з карыстальнікамі гэтага сервера немагчымы.",
|
"about.domain_blocks.suspended.explanation": "Ніякая інфармацыя з гэтага сервера не будзе апрацавана, захавана або абменена, узаемадзеянне або камунікацыя з карыстальнікамі гэтага сервера немагчымы.",
|
||||||
"about.domain_blocks.suspended.title": "Прыпынены",
|
"about.domain_blocks.suspended.title": "Прыпынены",
|
||||||
|
"about.language_label": "Мова",
|
||||||
"about.not_available": "Дадзеная інфармацыя не дасяжная на гэтым серверы.",
|
"about.not_available": "Дадзеная інфармацыя не дасяжная на гэтым серверы.",
|
||||||
"about.powered_by": "Дэцэнтралізаваная сацыяльная сетка, створаная {mastodon}",
|
"about.powered_by": "Дэцэнтралізаваная сацыяльная сетка, створаная {mastodon}",
|
||||||
"about.rules": "Правілы сервера",
|
"about.rules": "Правілы сервера",
|
||||||
|
@ -19,13 +21,21 @@
|
||||||
"account.block_domain": "Заблакіраваць дамен {domain}",
|
"account.block_domain": "Заблакіраваць дамен {domain}",
|
||||||
"account.block_short": "Заблакіраваць",
|
"account.block_short": "Заблакіраваць",
|
||||||
"account.blocked": "Заблакіраваны",
|
"account.blocked": "Заблакіраваны",
|
||||||
|
"account.blocking": "Блакіраванне",
|
||||||
"account.cancel_follow_request": "Скасаваць запыт на падпіску",
|
"account.cancel_follow_request": "Скасаваць запыт на падпіску",
|
||||||
"account.copy": "Скапіраваць спасылку на профіль",
|
"account.copy": "Скапіраваць спасылку на профіль",
|
||||||
"account.direct": "Згадаць асабіста @{name}",
|
"account.direct": "Згадаць асабіста @{name}",
|
||||||
"account.disable_notifications": "Не паведамляць мне пра публікацыі @{name}",
|
"account.disable_notifications": "Не паведамляць мне пра публікацыі @{name}",
|
||||||
|
"account.domain_blocking": "Блакіраванне дамена",
|
||||||
"account.edit_profile": "Рэдагаваць профіль",
|
"account.edit_profile": "Рэдагаваць профіль",
|
||||||
"account.enable_notifications": "Апавяшчаць мяне пра допісы @{name}",
|
"account.enable_notifications": "Апавяшчаць мяне пра допісы @{name}",
|
||||||
"account.endorse": "Паказваць у профілі",
|
"account.endorse": "Паказваць у профілі",
|
||||||
|
"account.familiar_followers_many": "Мае сярод падпісчыкаў {name1}, {name2}, і {othersCount, plural, one {яшчэ # чалавека, знаёмага вам} few {яшчэ # чалавекі, знаёмыя вам} many {яшчэ # чалавек, знаёмых вам} other {яшчэ # чалавекі, знаёмыя вам}}",
|
||||||
|
"account.familiar_followers_one": "Мае сярод падпісчыкаў {name1}",
|
||||||
|
"account.familiar_followers_two": "Мае сярод падпісчыкаў {name1} і {name2}",
|
||||||
|
"account.featured": "Рэкамендаванае",
|
||||||
|
"account.featured.accounts": "Профілі",
|
||||||
|
"account.featured.hashtags": "Хэштэгі",
|
||||||
"account.featured_tags.last_status_at": "Апошні допіс ад {date}",
|
"account.featured_tags.last_status_at": "Апошні допіс ад {date}",
|
||||||
"account.featured_tags.last_status_never": "Няма допісаў",
|
"account.featured_tags.last_status_never": "Няма допісаў",
|
||||||
"account.follow": "Падпісацца",
|
"account.follow": "Падпісацца",
|
||||||
|
@ -33,9 +43,11 @@
|
||||||
"account.followers": "Падпісчыкі",
|
"account.followers": "Падпісчыкі",
|
||||||
"account.followers.empty": "Ніхто пакуль не падпісаны на гэтага карыстальніка.",
|
"account.followers.empty": "Ніхто пакуль не падпісаны на гэтага карыстальніка.",
|
||||||
"account.followers_counter": "{count, plural, one {{counter} падпісчык} few {{counter} падпісчыкі} many {{counter} падпісчыкаў} other {{counter} падпісчыка}}",
|
"account.followers_counter": "{count, plural, one {{counter} падпісчык} few {{counter} падпісчыкі} many {{counter} падпісчыкаў} other {{counter} падпісчыка}}",
|
||||||
|
"account.followers_you_know_counter": "{count, one {{counter}, знаёмы вам} other {{counter}, знаёмых вам}}",
|
||||||
"account.following": "Падпіскі",
|
"account.following": "Падпіскі",
|
||||||
"account.following_counter": "{count, plural, one {{counter} падпіска} few {{counter} падпіскі} many {{counter} падпісак} other {{counter} падпіскі}}",
|
"account.following_counter": "{count, plural, one {{counter} падпіска} few {{counter} падпіскі} many {{counter} падпісак} other {{counter} падпіскі}}",
|
||||||
"account.follows.empty": "Карыстальнік ні на каго не падпісаны.",
|
"account.follows.empty": "Карыстальнік ні на каго не падпісаны.",
|
||||||
|
"account.follows_you": "Падпісаны на вас",
|
||||||
"account.go_to_profile": "Перайсці да профілю",
|
"account.go_to_profile": "Перайсці да профілю",
|
||||||
"account.hide_reblogs": "Схаваць пашырэнні ад @{name}",
|
"account.hide_reblogs": "Схаваць пашырэнні ад @{name}",
|
||||||
"account.in_memoriam": "У памяць.",
|
"account.in_memoriam": "У памяць.",
|
||||||
|
@ -50,18 +62,22 @@
|
||||||
"account.mute_notifications_short": "Не апавяшчаць",
|
"account.mute_notifications_short": "Не апавяшчаць",
|
||||||
"account.mute_short": "Ігнараваць",
|
"account.mute_short": "Ігнараваць",
|
||||||
"account.muted": "Ігнаруецца",
|
"account.muted": "Ігнаруецца",
|
||||||
|
"account.mutual": "Вы падпісаны адно на аднаго",
|
||||||
"account.no_bio": "Апісанне адсутнічае.",
|
"account.no_bio": "Апісанне адсутнічае.",
|
||||||
"account.open_original_page": "Адкрыць арыгінальную старонку",
|
"account.open_original_page": "Адкрыць арыгінальную старонку",
|
||||||
"account.posts": "Допісы",
|
"account.posts": "Допісы",
|
||||||
"account.posts_with_replies": "Допісы і адказы",
|
"account.posts_with_replies": "Допісы і адказы",
|
||||||
|
"account.remove_from_followers": "Выдаліць карыстальніка {name} з падпісчыкаў",
|
||||||
"account.report": "Паскардзіцца на @{name}",
|
"account.report": "Паскардзіцца на @{name}",
|
||||||
"account.requested": "Чакаецца ўхваленне. Націсніце, каб скасаваць запыт на падпіску",
|
"account.requested": "Чакаецца ўхваленне. Націсніце, каб скасаваць запыт на падпіску",
|
||||||
"account.requested_follow": "{name} адправіў запыт на падпіску",
|
"account.requested_follow": "{name} адправіў запыт на падпіску",
|
||||||
|
"account.requests_to_follow_you": "Хоча падпісацца на вас",
|
||||||
"account.share": "Абагуліць профіль @{name}",
|
"account.share": "Абагуліць профіль @{name}",
|
||||||
"account.show_reblogs": "Паказаць падштурхоўванні ад @{name}",
|
"account.show_reblogs": "Паказаць падштурхоўванні ад @{name}",
|
||||||
"account.statuses_counter": "{count, plural, one {{counter} допіс} few {{counter} допісы} many {{counter} допісаў} other {{counter} допісу}}",
|
"account.statuses_counter": "{count, plural, one {{counter} допіс} few {{counter} допісы} many {{counter} допісаў} other {{counter} допісу}}",
|
||||||
"account.unblock": "Разблакіраваць @{name}",
|
"account.unblock": "Разблакіраваць @{name}",
|
||||||
"account.unblock_domain": "Разблакіраваць дамен {domain}",
|
"account.unblock_domain": "Разблакіраваць дамен {domain}",
|
||||||
|
"account.unblock_domain_short": "Разблакіраваць",
|
||||||
"account.unblock_short": "Разблакіраваць",
|
"account.unblock_short": "Разблакіраваць",
|
||||||
"account.unendorse": "Не паказваць у профілі",
|
"account.unendorse": "Не паказваць у профілі",
|
||||||
"account.unfollow": "Адпісацца",
|
"account.unfollow": "Адпісацца",
|
||||||
|
@ -83,26 +99,30 @@
|
||||||
"alert.unexpected.message": "Узнікла нечаканая памылка.",
|
"alert.unexpected.message": "Узнікла нечаканая памылка.",
|
||||||
"alert.unexpected.title": "Вой!",
|
"alert.unexpected.title": "Вой!",
|
||||||
"alt_text_badge.title": "Альтэрнатыўны тэкст",
|
"alt_text_badge.title": "Альтэрнатыўны тэкст",
|
||||||
|
"alt_text_modal.add_alt_text": "Дадаць альтэрнатыўны тэкст",
|
||||||
|
"alt_text_modal.add_text_from_image": "Дадаць тэкст з відарыса",
|
||||||
|
"alt_text_modal.cancel": "Скасаваць",
|
||||||
|
"alt_text_modal.change_thumbnail": "Змяніць мініяцюру",
|
||||||
"alt_text_modal.done": "Гатова",
|
"alt_text_modal.done": "Гатова",
|
||||||
"announcement.announcement": "Аб'ява",
|
"announcement.announcement": "Аб'ява",
|
||||||
"annual_report.summary.archetype.booster": "Трэнда-сьледнік",
|
"annual_report.summary.archetype.booster": "Паляўнічы на трэнды",
|
||||||
"annual_report.summary.archetype.lurker": "Назіральнік",
|
"annual_report.summary.archetype.lurker": "Назіральнік",
|
||||||
"annual_report.summary.archetype.oracle": "Аракул",
|
"annual_report.summary.archetype.oracle": "Аракул",
|
||||||
"annual_report.summary.archetype.pollster": "Апытвальнік",
|
"annual_report.summary.archetype.pollster": "Апытвальнік",
|
||||||
"annual_report.summary.archetype.replier": "Душа кампанійі",
|
"annual_report.summary.archetype.replier": "Душа кампаніі",
|
||||||
"annual_report.summary.followers.followers": "падпісанты",
|
"annual_report.summary.followers.followers": "падпісчыкі",
|
||||||
"annual_report.summary.followers.total": "Усяго {count}",
|
"annual_report.summary.followers.total": "Агулам {count}",
|
||||||
"annual_report.summary.here_it_is": "Вось вашыя вынікі {year} году:",
|
"annual_report.summary.here_it_is": "Вось вашы вынікі {year} за год:",
|
||||||
"annual_report.summary.highlighted_post.by_favourites": "самы ўпадабаны допіс",
|
"annual_report.summary.highlighted_post.by_favourites": "самы ўпадабаны допіс",
|
||||||
"annual_report.summary.highlighted_post.by_reblogs": "самы пашыраны допіс",
|
"annual_report.summary.highlighted_post.by_reblogs": "самы пашыраны допіс",
|
||||||
"annual_report.summary.highlighted_post.by_replies": "самы каментаваны допіс",
|
"annual_report.summary.highlighted_post.by_replies": "самы каментаваны допіс",
|
||||||
"annual_report.summary.highlighted_post.possessive": "{name}",
|
"annual_report.summary.highlighted_post.possessive": "{name}",
|
||||||
"annual_report.summary.most_used_app.most_used_app": "самая выкарыстоўваная аплікацыя",
|
"annual_report.summary.most_used_app.most_used_app": "праграма, якой карысталіся часцей",
|
||||||
"annual_report.summary.most_used_hashtag.most_used_hashtag": "самы выкарыстоўваны гэштаґ",
|
"annual_report.summary.most_used_hashtag.most_used_hashtag": "хэштэг, якім карысталіся часцей",
|
||||||
"annual_report.summary.most_used_hashtag.none": "Няма",
|
"annual_report.summary.most_used_hashtag.none": "Няма",
|
||||||
"annual_report.summary.new_posts.new_posts": "новыя допісы",
|
"annual_report.summary.new_posts.new_posts": "новыя допісы",
|
||||||
"annual_report.summary.percentile.text": "<topLabel>Мэта месьціць вас у топ</topLabel><percentage></percentage><bottomLabel> карыстальнікаў {domain}.</bottomLabel>",
|
"annual_report.summary.percentile.text": "<topLabel>З-за гэтага, вы знаходзіцеся ў топе</topLabel><percentage></percentage><bottomLabel> карыстальнікаў {domain}.</bottomLabel>",
|
||||||
"annual_report.summary.percentile.we_wont_tell_bernie": "Мы ня скажам аб гэтым Сіняпальцаму.",
|
"annual_report.summary.percentile.we_wont_tell_bernie": "КДБ пра гэта не даведаецца.",
|
||||||
"annual_report.summary.thanks": "Дзякуй за ўдзел у Mastodon!",
|
"annual_report.summary.thanks": "Дзякуй за ўдзел у Mastodon!",
|
||||||
"attachments_list.unprocessed": "(неапрацаваны)",
|
"attachments_list.unprocessed": "(неапрацаваны)",
|
||||||
"audio.hide": "Схаваць аўдыя",
|
"audio.hide": "Схаваць аўдыя",
|
||||||
|
@ -127,7 +147,7 @@
|
||||||
"bundle_column_error.routing.body": "Запытаная старонка не знойдзена. Вы ўпэўнены, што URL у адрасным радку правільны?",
|
"bundle_column_error.routing.body": "Запытаная старонка не знойдзена. Вы ўпэўнены, што URL у адрасным радку правільны?",
|
||||||
"bundle_column_error.routing.title": "404",
|
"bundle_column_error.routing.title": "404",
|
||||||
"bundle_modal_error.close": "Закрыць",
|
"bundle_modal_error.close": "Закрыць",
|
||||||
"bundle_modal_error.message": "Падчас загрузкі гэтага экрана штосьці пайшло ня так.",
|
"bundle_modal_error.message": "Падчас загрузкі гэтага экрана штосьці пайшло не так.",
|
||||||
"bundle_modal_error.retry": "Паспрабуйце зноў",
|
"bundle_modal_error.retry": "Паспрабуйце зноў",
|
||||||
"closed_registrations.other_server_instructions": "Паколькі Mastodon дэцэнтралізаваны, вы можаце стварыць уліковы запіс на іншым серверы і працягваць узаемадзейнічаць з ім.",
|
"closed_registrations.other_server_instructions": "Паколькі Mastodon дэцэнтралізаваны, вы можаце стварыць уліковы запіс на іншым серверы і працягваць узаемадзейнічаць з ім.",
|
||||||
"closed_registrations_modal.description": "Стварэнне ўліковага запісу на {domain} цяпер немагчыма. Заўважце, што няма неабходнасці мець уліковы запіс менавіта на {domain}, каб выкарыстоўваць Mastodon.",
|
"closed_registrations_modal.description": "Стварэнне ўліковага запісу на {domain} цяпер немагчыма. Заўважце, што няма неабходнасці мець уліковы запіс менавіта на {domain}, каб выкарыстоўваць Mastodon.",
|
||||||
|
@ -147,7 +167,7 @@
|
||||||
"column.firehose": "Стужкі",
|
"column.firehose": "Стужкі",
|
||||||
"column.follow_requests": "Запыты на падпіску",
|
"column.follow_requests": "Запыты на падпіску",
|
||||||
"column.home": "Галоўная",
|
"column.home": "Галоўная",
|
||||||
"column.list_members": "Кіраванне ўдзельнікамі спісу",
|
"column.list_members": "Кіраванне ўдзельнікамі спіса",
|
||||||
"column.lists": "Спісы",
|
"column.lists": "Спісы",
|
||||||
"column.mutes": "Ігнараваныя карыстальнікі",
|
"column.mutes": "Ігнараваныя карыстальнікі",
|
||||||
"column.notifications": "Апавяшчэнні",
|
"column.notifications": "Апавяшчэнні",
|
||||||
|
@ -196,19 +216,24 @@
|
||||||
"confirmations.delete_list.confirm": "Выдаліць",
|
"confirmations.delete_list.confirm": "Выдаліць",
|
||||||
"confirmations.delete_list.message": "Вы ўпэўненыя, што хочаце беззваротна выдаліць гэты чарнавік?",
|
"confirmations.delete_list.message": "Вы ўпэўненыя, што хочаце беззваротна выдаліць гэты чарнавік?",
|
||||||
"confirmations.delete_list.title": "Выдаліць спіс?",
|
"confirmations.delete_list.title": "Выдаліць спіс?",
|
||||||
|
"confirmations.discard_draft.edit.cancel": "Працягнуць рэдагаванне",
|
||||||
"confirmations.discard_edit_media.confirm": "Адмяніць",
|
"confirmations.discard_edit_media.confirm": "Адмяніць",
|
||||||
"confirmations.discard_edit_media.message": "У вас ёсць незахаваныя змены ў апісанні або прэв'ю, усе роўна скасаваць іх?",
|
"confirmations.discard_edit_media.message": "У вас ёсць незахаваныя змены ў апісанні або прэв'ю, усе роўна скасаваць іх?",
|
||||||
"confirmations.follow_to_list.confirm": "Падпісацца й дадаць у сьпіс",
|
"confirmations.follow_to_list.confirm": "Падпісацца і дадаць у спіс",
|
||||||
"confirmations.follow_to_list.message": "Вы мусіце быць падпісаныя на {name} каб дадаць яго ў сьпіс.",
|
"confirmations.follow_to_list.message": "Вам трэба падпісацца на карыстальніка {name}, каб дадаць яго ў спіс.",
|
||||||
"confirmations.follow_to_list.title": "Падпісацца на карыстальніка?",
|
"confirmations.follow_to_list.title": "Падпісацца на карыстальніка?",
|
||||||
"confirmations.logout.confirm": "Выйсці",
|
"confirmations.logout.confirm": "Выйсці",
|
||||||
"confirmations.logout.message": "Вы ўпэўненыя, што хочаце выйсці?",
|
"confirmations.logout.message": "Вы ўпэўненыя, што хочаце выйсці?",
|
||||||
"confirmations.logout.title": "Выйсці?",
|
"confirmations.logout.title": "Выйсці?",
|
||||||
"confirmations.missing_alt_text.title": "Дадаць апісаньне?",
|
"confirmations.missing_alt_text.confirm": "Дадаць альтэрнатыўны тэкст",
|
||||||
|
"confirmations.missing_alt_text.secondary": "Усё адно апублікаваць",
|
||||||
|
"confirmations.missing_alt_text.title": "Дадаць альтэрнатыўны тэкст?",
|
||||||
"confirmations.mute.confirm": "Ігнараваць",
|
"confirmations.mute.confirm": "Ігнараваць",
|
||||||
"confirmations.redraft.confirm": "Выдаліць і перапісаць",
|
"confirmations.redraft.confirm": "Выдаліць і перапісаць",
|
||||||
"confirmations.redraft.message": "Вы ўпэўнены, што хочаце выдаліць допіс і перапісаць яго? Упадабанні і пашырэнні згубяцца, а адказы да арыгінальнага допісу асірацеюць.",
|
"confirmations.redraft.message": "Вы ўпэўнены, што хочаце выдаліць допіс і перапісаць яго? Упадабанні і пашырэнні згубяцца, а адказы да арыгінальнага допісу асірацеюць.",
|
||||||
"confirmations.redraft.title": "Выдаліць і перапісаць допіс?",
|
"confirmations.redraft.title": "Выдаліць і перапісаць допіс?",
|
||||||
|
"confirmations.remove_from_followers.confirm": "Выдаліць падпісчыка",
|
||||||
|
"confirmations.remove_from_followers.title": "Выдаліць падпісчыка?",
|
||||||
"confirmations.unfollow.confirm": "Адпісацца",
|
"confirmations.unfollow.confirm": "Адпісацца",
|
||||||
"confirmations.unfollow.message": "Вы ўпэўненыя, што хочаце адпісацца ад {name}?",
|
"confirmations.unfollow.message": "Вы ўпэўненыя, што хочаце адпісацца ад {name}?",
|
||||||
"confirmations.unfollow.title": "Адпісацца ад карыстальніка?",
|
"confirmations.unfollow.title": "Адпісацца ад карыстальніка?",
|
||||||
|
@ -221,7 +246,7 @@
|
||||||
"conversation.with": "З {names}",
|
"conversation.with": "З {names}",
|
||||||
"copy_icon_button.copied": "Скапіявана ў буфер абмену",
|
"copy_icon_button.copied": "Скапіявана ў буфер абмену",
|
||||||
"copypaste.copied": "Скапіравана",
|
"copypaste.copied": "Скапіравана",
|
||||||
"copypaste.copy_to_clipboard": "Капіраваць у буфер абмену",
|
"copypaste.copy_to_clipboard": "Скапіяваць у буфер абмену",
|
||||||
"directory.federated": "З вядомага федэсвету",
|
"directory.federated": "З вядомага федэсвету",
|
||||||
"directory.local": "Толькі з {domain}",
|
"directory.local": "Толькі з {domain}",
|
||||||
"directory.new_arrivals": "Новыя карыстальнікі",
|
"directory.new_arrivals": "Новыя карыстальнікі",
|
||||||
|
@ -230,7 +255,7 @@
|
||||||
"disabled_account_banner.text": "Ваш уліковы запіс {disabledAccount} часова адключаны.",
|
"disabled_account_banner.text": "Ваш уліковы запіс {disabledAccount} часова адключаны.",
|
||||||
"dismissable_banner.community_timeline": "Гэта самыя апошнія допісы ад людзей, уліковыя запісы якіх размяшчаюцца на {domain}.",
|
"dismissable_banner.community_timeline": "Гэта самыя апошнія допісы ад людзей, уліковыя запісы якіх размяшчаюцца на {domain}.",
|
||||||
"dismissable_banner.dismiss": "Адхіліць",
|
"dismissable_banner.dismiss": "Адхіліць",
|
||||||
"dismissable_banner.public_timeline": "Гэта самыя новыя публічныя допісы ад карыстальнікаў фэдывёрсу на якіх падпісаныя карыстальнікі {domain}.",
|
"dismissable_banner.public_timeline": "Вось апошнія публічныя допісы ад карыстальнікаў fediverse на якіх падпісаны карыстальнікі {domain}.",
|
||||||
"domain_block_modal.block": "Заблакіраваць сервер",
|
"domain_block_modal.block": "Заблакіраваць сервер",
|
||||||
"domain_block_modal.block_account_instead": "Заблакіраваць @{name} замест гэтага",
|
"domain_block_modal.block_account_instead": "Заблакіраваць @{name} замест гэтага",
|
||||||
"domain_block_modal.they_can_interact_with_old_posts": "Людзі з гэтага сервера змогуць узаемадзейнічаць з вашымі старымі допісамі.",
|
"domain_block_modal.they_can_interact_with_old_posts": "Людзі з гэтага сервера змогуць узаемадзейнічаць з вашымі старымі допісамі.",
|
||||||
|
@ -275,15 +300,15 @@
|
||||||
"empty_column.account_timeline": "Тут няма допісаў!",
|
"empty_column.account_timeline": "Тут няма допісаў!",
|
||||||
"empty_column.account_unavailable": "Профіль недаступны",
|
"empty_column.account_unavailable": "Профіль недаступны",
|
||||||
"empty_column.blocks": "Вы яшчэ нікога не заблакіравалі.",
|
"empty_column.blocks": "Вы яшчэ нікога не заблакіравалі.",
|
||||||
"empty_column.bookmarked_statuses": "У вас яшчэ няма паведамленняў з закладкамі. Калі вы дадасце закладку, яна з'явіцца тут.",
|
"empty_column.bookmarked_statuses": "У вашых закладках яшчэ няма допісаў. Калі вы дадасце закладку, яна з’явіцца тут.",
|
||||||
"empty_column.community": "Мясцовая стужка пустая. Напішыце што-небудзь публічна, каб зрушыць з месца!",
|
"empty_column.community": "Мясцовая стужка пустая. Напішыце нешта публічнае, каб разварушыць справу!",
|
||||||
"empty_column.direct": "Пакуль у вас няма асабістых згадак. Калі вы дашляце або атрымаеце штось, яно з'явіцца тут.",
|
"empty_column.direct": "Пакуль у вас няма асабістых згадванняў. Калі вы дашляце або атрымаеце штосьці, яно з’явіцца тут.",
|
||||||
"empty_column.domain_blocks": "Заблакіраваных даменаў пакуль няма.",
|
"empty_column.domain_blocks": "Заблакіраваных даменаў пакуль няма.",
|
||||||
"empty_column.explore_statuses": "Зараз не ў трэндзе. Праверце пазней",
|
"empty_column.explore_statuses": "Зараз не ў трэндзе. Праверце пазней",
|
||||||
"empty_column.favourited_statuses": "Вы яшчэ не ўпадабалі ніводны допіс. Калі гэта адбудзецца, вы ўбачыце яго тут.",
|
"empty_column.favourited_statuses": "Вы яшчэ не ўпадабалі ніводны допіс. Калі гэта адбудзецца, вы ўбачыце яго тут.",
|
||||||
"empty_column.favourites": "Ніхто яшчэ не ўпадабаў гэты допіс. Калі гэта адбудзецца, вы ўбачыце гэтых людзей тут.",
|
"empty_column.favourites": "Ніхто яшчэ не ўпадабаў гэты допіс. Калі гэта адбудзецца, вы ўбачыце гэтых людзей тут.",
|
||||||
"empty_column.follow_requests": "У вас яшчэ няма запытаў на падпіскуі. Калі вы атрымаеце запыт, ён з'явяцца тут.",
|
"empty_column.follow_requests": "У вас яшчэ няма запытаў на падпіску. Калі вы атрымаеце запыт, ён з’явіцца тут.",
|
||||||
"empty_column.followed_tags": "Вы пакуль не падпісаны ні на адзін хэштэг. Калі падпішацеся, яны з'явяцца тут.",
|
"empty_column.followed_tags": "Вы пакуль не падпісаны ні на адзін хэштэг. Калі падпішацеся, яны з’явяцца тут.",
|
||||||
"empty_column.hashtag": "Па гэтаму хэштэгу пакуль што нічога няма.",
|
"empty_column.hashtag": "Па гэтаму хэштэгу пакуль што нічога няма.",
|
||||||
"empty_column.home": "Галоўная стужка пустая! Падпішыцеся на іншых людзей, каб запоўніць яе. {suggestions}",
|
"empty_column.home": "Галоўная стужка пустая! Падпішыцеся на іншых людзей, каб запоўніць яе. {suggestions}",
|
||||||
"empty_column.list": "У гэтым спісе пакуль што нічога няма. Калі члены лісту апублікуюць новыя запісы, яны з'явяцца тут.",
|
"empty_column.list": "У гэтым спісе пакуль што нічога няма. Калі члены лісту апублікуюць новыя запісы, яны з'явяцца тут.",
|
||||||
|
@ -294,13 +319,18 @@
|
||||||
"error.unexpected_crash.explanation": "Гэта старонка не можа быць адлюстравана карэктна з-за памылкі ў нашым кодзе, або праблемы з сумяшчальнасцю браўзера.",
|
"error.unexpected_crash.explanation": "Гэта старонка не можа быць адлюстравана карэктна з-за памылкі ў нашым кодзе, або праблемы з сумяшчальнасцю браўзера.",
|
||||||
"error.unexpected_crash.explanation_addons": "Гэтая старонка не можа быць адлюстравана карэктна. Верагодна, гэтая памылка выклікана дадатковым кампанентам браўзера або інструментамі аўтаматычнага перакладу",
|
"error.unexpected_crash.explanation_addons": "Гэтая старонка не можа быць адлюстравана карэктна. Верагодна, гэтая памылка выклікана дадатковым кампанентам браўзера або інструментамі аўтаматычнага перакладу",
|
||||||
"error.unexpected_crash.next_steps": "Паспрабуйце абнавіць старонку. Калі гэта не дапаможа, вы можаце паспрабаваць іншы браўзер, альбо выкарыстаць усталяваную праграму.",
|
"error.unexpected_crash.next_steps": "Паспрабуйце абнавіць старонку. Калі гэта не дапаможа, вы можаце паспрабаваць іншы браўзер, альбо выкарыстаць усталяваную праграму.",
|
||||||
"error.unexpected_crash.next_steps_addons": "Паспрабуйце выключыць іх і аднавіць старонку. Калі гэта не дапаможа, вы можаце карыстацца Мастадонт праз другі браўзер ці аплікацыю.",
|
"error.unexpected_crash.next_steps_addons": "Паспрабуйце выключыць іх і абнавіць старонку. Калі гэта не дапамагае, вы ўсё яшчэ можаце карыстацца Mastodon праз іншы браўзер ці натыўную праграму.",
|
||||||
"errors.unexpected_crash.copy_stacktrace": "Дадаць дыягнастычны стэк у буфер абмену",
|
"errors.unexpected_crash.copy_stacktrace": "Дадаць дыягнастычны стэк у буфер абмену",
|
||||||
"errors.unexpected_crash.report_issue": "Паведаміць аб праблеме",
|
"errors.unexpected_crash.report_issue": "Паведаміць аб праблеме",
|
||||||
"explore.suggested_follows": "Людзі",
|
"explore.suggested_follows": "Людзі",
|
||||||
|
"explore.title": "Трэндавае",
|
||||||
"explore.trending_links": "Навіны",
|
"explore.trending_links": "Навіны",
|
||||||
"explore.trending_statuses": "Допісы",
|
"explore.trending_statuses": "Допісы",
|
||||||
"explore.trending_tags": "Хэштэгі",
|
"explore.trending_tags": "Хэштэгі",
|
||||||
|
"featured_carousel.next": "Далей",
|
||||||
|
"featured_carousel.post": "Допіс",
|
||||||
|
"featured_carousel.previous": "Назад",
|
||||||
|
"featured_carousel.slide": "{index} з {total}",
|
||||||
"filter_modal.added.context_mismatch_explanation": "Гэтая катэгорыя фільтра не прымяняецца да кантэксту, у якім вы адкрылі гэты пост. Калі вы хочаце, каб паведамленне таксама было адфільтравана ў гэтым кантэксце, вам трэба будзе адрэдагаваць фільтр",
|
"filter_modal.added.context_mismatch_explanation": "Гэтая катэгорыя фільтра не прымяняецца да кантэксту, у якім вы адкрылі гэты пост. Калі вы хочаце, каб паведамленне таксама было адфільтравана ў гэтым кантэксце, вам трэба будзе адрэдагаваць фільтр",
|
||||||
"filter_modal.added.context_mismatch_title": "Неадпаведны кантэкст!",
|
"filter_modal.added.context_mismatch_title": "Неадпаведны кантэкст!",
|
||||||
"filter_modal.added.expired_explanation": "Тэрмін дзеяння гэтай катэгорыі фільтраў скончыўся, вам трэба будзе змяніць дату заканчэння тэрміну дзеяння, каб яна прымянялася",
|
"filter_modal.added.expired_explanation": "Тэрмін дзеяння гэтай катэгорыі фільтраў скончыўся, вам трэба будзе змяніць дату заканчэння тэрміну дзеяння, каб яна прымянялася",
|
||||||
|
@ -349,10 +379,10 @@
|
||||||
"footer.privacy_policy": "Палітыка прыватнасці",
|
"footer.privacy_policy": "Палітыка прыватнасці",
|
||||||
"footer.source_code": "Прагледзець зыходны код",
|
"footer.source_code": "Прагледзець зыходны код",
|
||||||
"footer.status": "Статус",
|
"footer.status": "Статус",
|
||||||
"footer.terms_of_service": "Умовы абслугоўваньня",
|
"footer.terms_of_service": "Умовы выкарыстання",
|
||||||
"generic.saved": "Захавана",
|
"generic.saved": "Захавана",
|
||||||
"getting_started.heading": "Пачатак працы",
|
"getting_started.heading": "Пачатак працы",
|
||||||
"hashtag.admin_moderation": "Адкрыць інтэрфэйс мадаратара для #{name}",
|
"hashtag.admin_moderation": "Адкрыць інтэрфейс мадэратара для #{name}",
|
||||||
"hashtag.column_header.tag_mode.all": "і {additional}",
|
"hashtag.column_header.tag_mode.all": "і {additional}",
|
||||||
"hashtag.column_header.tag_mode.any": "або {additional}",
|
"hashtag.column_header.tag_mode.any": "або {additional}",
|
||||||
"hashtag.column_header.tag_mode.none": "без {additional}",
|
"hashtag.column_header.tag_mode.none": "без {additional}",
|
||||||
|
@ -374,35 +404,39 @@
|
||||||
"hints.profiles.see_more_followers": "Глядзець больш падпісаных на {domain}",
|
"hints.profiles.see_more_followers": "Глядзець больш падпісаных на {domain}",
|
||||||
"hints.profiles.see_more_follows": "Глядзець больш падпісак на {domain}",
|
"hints.profiles.see_more_follows": "Глядзець больш падпісак на {domain}",
|
||||||
"hints.profiles.see_more_posts": "Глядзець больш допісаў на {domain}",
|
"hints.profiles.see_more_posts": "Глядзець больш допісаў на {domain}",
|
||||||
"hints.threads.replies_may_be_missing": "Адказы зь іншых сэрвэраў могуць адсутнічаць.",
|
"hints.threads.replies_may_be_missing": "Адказы з іншых сервераў могуць адсутнічаць.",
|
||||||
"hints.threads.see_more": "Глядзіце больш адказаў на {domain}",
|
"hints.threads.see_more": "Глядзіце больш адказаў на {domain}",
|
||||||
|
"home.column_settings.show_quotes": "Паказаць цытаты",
|
||||||
"home.column_settings.show_reblogs": "Паказваць пашырэнні",
|
"home.column_settings.show_reblogs": "Паказваць пашырэнні",
|
||||||
"home.column_settings.show_replies": "Паказваць адказы",
|
"home.column_settings.show_replies": "Паказваць адказы",
|
||||||
"home.hide_announcements": "Схаваць аб'явы",
|
"home.hide_announcements": "Схаваць аб'явы",
|
||||||
"home.pending_critical_update.body": "Калі ласка, абнавіце свой сервер Mastodon як мага хутчэй!",
|
"home.pending_critical_update.body": "Абнавіце свой сервер Mastodon як мага хутчэй!",
|
||||||
"home.pending_critical_update.link": "Прагледзець абнаўленні",
|
"home.pending_critical_update.link": "Прагледзець абнаўленні",
|
||||||
"home.pending_critical_update.title": "Даступна крытычнае абнаўленне бяспекі!",
|
"home.pending_critical_update.title": "Даступна крытычнае абнаўленне бяспекі!",
|
||||||
"home.show_announcements": "Паказаць аб'явы",
|
"home.show_announcements": "Паказаць аб'явы",
|
||||||
"ignore_notifications_modal.disclaimer": "Mastodon ня можа йнфармаваць карыстальнікаў аб тым, што вы прайігнаравалі йх паведамленьні. Ігнараваньне паведамленьняў не спыніць іх адпраўку.",
|
"ignore_notifications_modal.disclaimer": "Mastodon не можа паведамляць карыстальнікам, што вы праігнаравалі апавяшчэнні ад іх. Ігнараванне апавяшчэнняў не спыніць адпраўку саміх паведамленняў.",
|
||||||
"ignore_notifications_modal.filter_instead": "Замест гэтага адфільтраваць",
|
"ignore_notifications_modal.filter_instead": "Замест гэтага адфільтраваць",
|
||||||
"ignore_notifications_modal.filter_to_act_users": "Вы па-ранейшаму зможаце прымаць, адхіляць ці скардзіцца на карыстальнікаў",
|
"ignore_notifications_modal.filter_to_act_users": "Вы па-ранейшаму зможаце прымаць, адхіляць ці скардзіцца на карыстальнікаў",
|
||||||
"ignore_notifications_modal.filter_to_avoid_confusion": "Фільтраваньне дапамагае пазьбегнуць патэнцыйнай блытаніны",
|
"ignore_notifications_modal.filter_to_avoid_confusion": "Выкарыстанне фільтраў дапамагае пазбягаць патэнцыйнай блытаніны",
|
||||||
"ignore_notifications_modal.filter_to_review_separately": "Вы можаце прагледзець адфільтраваныя паведамленьні асобна",
|
"ignore_notifications_modal.filter_to_review_separately": "Вы можаце прагледзець адфільтраваныя апавяшчэнні асобна",
|
||||||
"ignore_notifications_modal.ignore": "Ігнараваць паведамленьні",
|
"ignore_notifications_modal.ignore": "Ігнараваць апавяшчэнні",
|
||||||
"ignore_notifications_modal.limited_accounts_title": "Ігнараваць паведамленьні ад абмежаваных уліковых запісаў?",
|
"ignore_notifications_modal.limited_accounts_title": "Ігнараваць апавяшчэнні ад уліковых запісаў пад мадэрацыяй?",
|
||||||
"ignore_notifications_modal.new_accounts_title": "Ігнараваць паведамленьні ад новых уліковых запісаў?",
|
"ignore_notifications_modal.new_accounts_title": "Ігнараваць апавяшчэнні ад новых уліковых запісаў?",
|
||||||
"ignore_notifications_modal.not_followers_title": "Ігнараваць паведамленьні ад людзей, якія ня падпісаныя на вас?",
|
"ignore_notifications_modal.not_followers_title": "Ігнараваць апавяшчэнні ад людзей, якія не падпісаныя на вас?",
|
||||||
"ignore_notifications_modal.not_following_title": "Ігнараваць апавяшчэнні ад людзей на якіх вы не падпісаны?",
|
"ignore_notifications_modal.not_following_title": "Ігнараваць апавяшчэнні ад людзей на якіх вы не падпісаны?",
|
||||||
"ignore_notifications_modal.private_mentions_title": "Ігнараваць паведамленьні аб непажаданых прыватных згадках?",
|
"ignore_notifications_modal.private_mentions_title": "Ігнараваць апавяшчэнні пра непажаданыя асабістыя згадванні?",
|
||||||
"info_button.label": "Даведка",
|
"info_button.label": "Даведка",
|
||||||
"interaction_modal.action.favourite": "Каб працягнуць, вы мусіце ўпадабаць з вашага ўліковага запісу.",
|
"interaction_modal.action.favourite": "Каб працягнуць, вы мусіце ўпадабаць нешта са свайго ўліковага запісу.",
|
||||||
"interaction_modal.action.follow": "Каб працягнуць, вы мусіце падпісацца з вашага ўліковага запісу.",
|
"interaction_modal.action.follow": "Каб працягнуць, вы мусіце падпісацца на некага са свайго ўліковага запісу.",
|
||||||
|
"interaction_modal.go": "Перайсці",
|
||||||
|
"interaction_modal.no_account_yet": "Не маеце ўліковага запісу?",
|
||||||
"interaction_modal.on_another_server": "На іншым серверы",
|
"interaction_modal.on_another_server": "На іншым серверы",
|
||||||
"interaction_modal.on_this_server": "На гэтым серверы",
|
"interaction_modal.on_this_server": "На гэтым серверы",
|
||||||
"interaction_modal.title.favourite": "Упадабаць допіс {name}",
|
"interaction_modal.title.favourite": "Упадабаць допіс {name}",
|
||||||
"interaction_modal.title.follow": "Падпісацца на {name}",
|
"interaction_modal.title.follow": "Падпісацца на {name}",
|
||||||
"interaction_modal.title.reblog": "Пашырыць допіс ад {name}",
|
"interaction_modal.title.reblog": "Пашырыць допіс ад {name}",
|
||||||
"interaction_modal.title.reply": "Адказаць на допіс {name}",
|
"interaction_modal.title.reply": "Адказаць на допіс {name}",
|
||||||
|
"interaction_modal.username_prompt": "Напр., {example}",
|
||||||
"intervals.full.days": "{number, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}}",
|
"intervals.full.days": "{number, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# гадзіна} few {# гадзіны} many {# гадзін} other {# гадзіны}}",
|
"intervals.full.hours": "{number, plural, one {# гадзіна} few {# гадзіны} many {# гадзін} other {# гадзіны}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# хвіліна} few {# хвіліны} many {# хвілін} other {# хвіліны}}",
|
"intervals.full.minutes": "{number, plural, one {# хвіліна} few {# хвіліны} many {# хвілін} other {# хвіліны}}",
|
||||||
|
@ -438,21 +472,32 @@
|
||||||
"keyboard_shortcuts.toggle_hidden": "Паказаць/схаваць тэкст за папярэджаннем пра кантэнт",
|
"keyboard_shortcuts.toggle_hidden": "Паказаць/схаваць тэкст за папярэджаннем пра кантэнт",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Паказаць/схаваць медыя",
|
"keyboard_shortcuts.toggle_sensitivity": "Паказаць/схаваць медыя",
|
||||||
"keyboard_shortcuts.toot": "Стварыць новы допіс",
|
"keyboard_shortcuts.toot": "Стварыць новы допіс",
|
||||||
|
"keyboard_shortcuts.translate": "каб перакласці допіс",
|
||||||
"keyboard_shortcuts.unfocus": "Расфакусаваць тэкставую вобласць/пошукавы радок",
|
"keyboard_shortcuts.unfocus": "Расфакусаваць тэкставую вобласць/пошукавы радок",
|
||||||
"keyboard_shortcuts.up": "Перамясціцца ўверх па спісе",
|
"keyboard_shortcuts.up": "Перамясціцца ўверх па спісе",
|
||||||
"lightbox.close": "Закрыць",
|
"lightbox.close": "Закрыць",
|
||||||
"lightbox.next": "Далей",
|
"lightbox.next": "Далей",
|
||||||
"lightbox.previous": "Назад",
|
"lightbox.previous": "Назад",
|
||||||
|
"lightbox.zoom_in": "Маштабаваць да фактычнага памеру",
|
||||||
|
"lightbox.zoom_out": "Дапасаваць усё змесціва пад памеры экрана",
|
||||||
"limited_account_hint.action": "Усе роўна паказваць профіль",
|
"limited_account_hint.action": "Усе роўна паказваць профіль",
|
||||||
"limited_account_hint.title": "Гэты профіль быў схаваны мадэратарамі",
|
"limited_account_hint.title": "Гэты профіль быў схаваны мадэратарамі",
|
||||||
"link_preview.author": "Ад {name}",
|
"link_preview.author": "Ад {name}",
|
||||||
"link_preview.more_from_author": "Больш ад {name}",
|
"link_preview.more_from_author": "Больш ад {name}",
|
||||||
"link_preview.shares": "{count, plural, one {{counter} допіс} few {{counter} допісы} many {{counter} допісаў} other {{counter} допісу}}",
|
"link_preview.shares": "{count, plural, one {{counter} допіс} few {{counter} допісы} many {{counter} допісаў} other {{counter} допісу}}",
|
||||||
"lists.add_member": "Дадаць",
|
"lists.add_member": "Дадаць",
|
||||||
|
"lists.add_to_list": "Дадаць у спіс",
|
||||||
|
"lists.add_to_lists": "Дадаць {name} у спісы",
|
||||||
"lists.create": "Стварыць",
|
"lists.create": "Стварыць",
|
||||||
"lists.create_list": "Стварыць спіс",
|
"lists.create_list": "Стварыць спіс",
|
||||||
"lists.delete": "Выдаліць спіс",
|
"lists.delete": "Выдаліць спіс",
|
||||||
|
"lists.done": "Гатова",
|
||||||
"lists.edit": "Рэдагаваць спіс",
|
"lists.edit": "Рэдагаваць спіс",
|
||||||
|
"lists.list_name": "Назва спіса",
|
||||||
|
"lists.new_list_name": "Назва новага спіса",
|
||||||
|
"lists.no_lists_yet": "Пакуль няма спісаў.",
|
||||||
|
"lists.no_members_yet": "Пакуль няма ўдзельнікаў.",
|
||||||
|
"lists.no_results_found": "Нічога не знойдзена.",
|
||||||
"lists.remove_member": "Выдаліць",
|
"lists.remove_member": "Выдаліць",
|
||||||
"lists.replies_policy.followed": "Любы карыстальнік, на якога вы падпісаліся",
|
"lists.replies_policy.followed": "Любы карыстальнік, на якога вы падпісаліся",
|
||||||
"lists.replies_policy.list": "Удзельнікі гэтага спісу",
|
"lists.replies_policy.list": "Удзельнікі гэтага спісу",
|
||||||
|
@ -460,7 +505,7 @@
|
||||||
"lists.save": "Захаваць",
|
"lists.save": "Захаваць",
|
||||||
"lists.search": "Пошук",
|
"lists.search": "Пошук",
|
||||||
"load_pending": "{count, plural, one {# новы элемент} few {# новыя элементы} many {# новых элементаў} other {# новых элементаў}}",
|
"load_pending": "{count, plural, one {# новы элемент} few {# новыя элементы} many {# новых элементаў} other {# новых элементаў}}",
|
||||||
"loading_indicator.label": "Загрузка…",
|
"loading_indicator.label": "Ідзе загрузка…",
|
||||||
"media_gallery.hide": "Схаваць",
|
"media_gallery.hide": "Схаваць",
|
||||||
"moved_to_account_banner.text": "Ваш уліковы запіс {disabledAccount} зараз адключаны таму што вы перанесены на {movedToAccount}.",
|
"moved_to_account_banner.text": "Ваш уліковы запіс {disabledAccount} зараз адключаны таму што вы перанесены на {movedToAccount}.",
|
||||||
"mute_modal.hide_from_notifications": "Схаваць з апавяшчэнняў",
|
"mute_modal.hide_from_notifications": "Схаваць з апавяшчэнняў",
|
||||||
|
@ -473,7 +518,10 @@
|
||||||
"mute_modal.you_wont_see_mentions": "Вы не ўбачыце паведамленняў са згадваннем карыстальніка.",
|
"mute_modal.you_wont_see_mentions": "Вы не ўбачыце паведамленняў са згадваннем карыстальніка.",
|
||||||
"mute_modal.you_wont_see_posts": "Карыстальнік па-ранейшаму будзе бачыць вашыя паведамленні, але вы не будзеце паведамленні карыстальніка.",
|
"mute_modal.you_wont_see_posts": "Карыстальнік па-ранейшаму будзе бачыць вашыя паведамленні, але вы не будзеце паведамленні карыстальніка.",
|
||||||
"navigation_bar.about": "Пра нас",
|
"navigation_bar.about": "Пра нас",
|
||||||
|
"navigation_bar.account_settings": "Пароль і бяспека",
|
||||||
|
"navigation_bar.administration": "Адміністрацыя",
|
||||||
"navigation_bar.advanced_interface": "Адкрыць у пашыраным вэб-інтэрфейсе",
|
"navigation_bar.advanced_interface": "Адкрыць у пашыраным вэб-інтэрфейсе",
|
||||||
|
"navigation_bar.automated_deletion": "Аўтаматычнае выдаленне допісаў",
|
||||||
"navigation_bar.blocks": "Заблакіраваныя карыстальнікі",
|
"navigation_bar.blocks": "Заблакіраваныя карыстальнікі",
|
||||||
"navigation_bar.bookmarks": "Закладкі",
|
"navigation_bar.bookmarks": "Закладкі",
|
||||||
"navigation_bar.direct": "Асабістыя згадванні",
|
"navigation_bar.direct": "Асабістыя згадванні",
|
||||||
|
@ -483,13 +531,21 @@
|
||||||
"navigation_bar.follow_requests": "Запыты на падпіску",
|
"navigation_bar.follow_requests": "Запыты на падпіску",
|
||||||
"navigation_bar.followed_tags": "Падпіскі",
|
"navigation_bar.followed_tags": "Падпіскі",
|
||||||
"navigation_bar.follows_and_followers": "Падпіскі і падпісчыкі",
|
"navigation_bar.follows_and_followers": "Падпіскі і падпісчыкі",
|
||||||
|
"navigation_bar.import_export": "Імпарт і экспарт",
|
||||||
"navigation_bar.lists": "Спісы",
|
"navigation_bar.lists": "Спісы",
|
||||||
|
"navigation_bar.live_feed_local": "Жывая стужка (лакальная)",
|
||||||
|
"navigation_bar.live_feed_public": "Жывая стужка (публічная)",
|
||||||
"navigation_bar.logout": "Выйсці",
|
"navigation_bar.logout": "Выйсці",
|
||||||
"navigation_bar.moderation": "Мадэрацыя",
|
"navigation_bar.moderation": "Мадэрацыя",
|
||||||
|
"navigation_bar.more": "Больш",
|
||||||
"navigation_bar.mutes": "Ігнараваныя карыстальнікі",
|
"navigation_bar.mutes": "Ігнараваныя карыстальнікі",
|
||||||
"navigation_bar.opened_in_classic_interface": "Допісы, уліковыя запісы і іншыя спецыфічныя старонкі па змоўчанні адчыняюцца ў класічным вэб-інтэрфейсе.",
|
"navigation_bar.opened_in_classic_interface": "Допісы, уліковыя запісы і іншыя спецыфічныя старонкі па змоўчанні адчыняюцца ў класічным вэб-інтэрфейсе.",
|
||||||
"navigation_bar.preferences": "Налады",
|
"navigation_bar.preferences": "Налады",
|
||||||
|
"navigation_bar.privacy_and_reach": "Прыватнасць і пошук",
|
||||||
"navigation_bar.search": "Пошук",
|
"navigation_bar.search": "Пошук",
|
||||||
|
"navigation_bar.search_trends": "Пошук / Трэндавае",
|
||||||
|
"navigation_panel.collapse_followed_tags": "Згарнуць меню падпісак на хэштэгі",
|
||||||
|
"navigation_panel.collapse_lists": "Згарнуць меню спісаў",
|
||||||
"not_signed_in_indicator.not_signed_in": "Вам трэба ўвайсці каб атрымаць доступ да гэтага рэсурсу.",
|
"not_signed_in_indicator.not_signed_in": "Вам трэба ўвайсці каб атрымаць доступ да гэтага рэсурсу.",
|
||||||
"notification.admin.report": "{name} паскардзіўся на {target}",
|
"notification.admin.report": "{name} паскардзіўся на {target}",
|
||||||
"notification.admin.report_account": "{name} паскардзіўся на {count, plural, one {# допіс} many {# допісаў} other {# допіса}} ад {target} з прычыны {category}",
|
"notification.admin.report_account": "{name} паскардзіўся на {count, plural, one {# допіс} many {# допісаў} other {# допіса}} ад {target} з прычыны {category}",
|
||||||
|
@ -497,7 +553,10 @@
|
||||||
"notification.admin.report_statuses": "{name} паскардзіўся на {target} з прычыны {category}",
|
"notification.admin.report_statuses": "{name} паскардзіўся на {target} з прычыны {category}",
|
||||||
"notification.admin.report_statuses_other": "{name} паскардзіўся на {target}",
|
"notification.admin.report_statuses_other": "{name} паскардзіўся на {target}",
|
||||||
"notification.admin.sign_up": "{name} зарэгістраваўся",
|
"notification.admin.sign_up": "{name} зарэгістраваўся",
|
||||||
|
"notification.annual_report.view": "Перайсці да #Wrapstodon",
|
||||||
"notification.favourite": "Ваш допіс упадабаны {name}",
|
"notification.favourite": "Ваш допіс упадабаны {name}",
|
||||||
|
"notification.favourite_pm": "Ваша асабістае згадванне ўпадабана {name}",
|
||||||
|
"notification.favourite_pm.name_and_others_with_link": "{name} і <a>{count, plural, one {# іншы} few {# іншыя} many {# іншых} other {# іншых}}</a> ўпадабалі ваша асабістае згадванне",
|
||||||
"notification.follow": "{name} падпісаўся на вас",
|
"notification.follow": "{name} падпісаўся на вас",
|
||||||
"notification.follow_request": "{name} адправіў запыт на падпіску",
|
"notification.follow_request": "{name} адправіў запыт на падпіску",
|
||||||
"notification.follow_request.name_and_others": "{name} і {count, plural, one {# іншы} many {# іншых} other {# іншых}} запыталіся падпісацца на вас",
|
"notification.follow_request.name_and_others": "{name} і {count, plural, one {# іншы} many {# іншых} other {# іншых}} запыталіся падпісацца на вас",
|
||||||
|
@ -508,7 +567,7 @@
|
||||||
"notification.mention": "Згадванне",
|
"notification.mention": "Згадванне",
|
||||||
"notification.mentioned_you": "{name} згадаў вас",
|
"notification.mentioned_you": "{name} згадаў вас",
|
||||||
"notification.moderation-warning.learn_more": "Даведацца больш",
|
"notification.moderation-warning.learn_more": "Даведацца больш",
|
||||||
"notification.moderation_warning": "Вы атрымалі папярэджанне аб мадэрацыі",
|
"notification.moderation_warning": "Вы атрымалі папярэджанне ад мадэратараў",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Некаторыя вашыя допісы былі выдаленыя.",
|
"notification.moderation_warning.action_delete_statuses": "Некаторыя вашыя допісы былі выдаленыя.",
|
||||||
"notification.moderation_warning.action_disable": "Ваш уліковы запіс быў адключаны.",
|
"notification.moderation_warning.action_disable": "Ваш уліковы запіс быў адключаны.",
|
||||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Некаторыя з вашых допісаў былі пазначаныя як далікатныя.",
|
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Некаторыя з вашых допісаў былі пазначаныя як далікатныя.",
|
||||||
|
@ -539,7 +598,7 @@
|
||||||
"notification_requests.title": "Адфільтраваныя апавяшчэнні",
|
"notification_requests.title": "Адфільтраваныя апавяшчэнні",
|
||||||
"notification_requests.view": "Прагляд апавяшчэнняў",
|
"notification_requests.view": "Прагляд апавяшчэнняў",
|
||||||
"notifications.clear": "Ачысціць апавяшчэнні",
|
"notifications.clear": "Ачысціць апавяшчэнні",
|
||||||
"notifications.clear_confirmation": "Вы ўпэўнены, што жадаеце назаўсёды сцерці ўсё паведамленні?",
|
"notifications.clear_confirmation": "Вы ўпэўнены, што хочаце назаўсёды сцерці ўсе свае паведамленні?",
|
||||||
"notifications.clear_title": "Ачысціць апавяшчэнні?",
|
"notifications.clear_title": "Ачысціць апавяшчэнні?",
|
||||||
"notifications.column_settings.admin.report": "Новыя скаргі:",
|
"notifications.column_settings.admin.report": "Новыя скаргі:",
|
||||||
"notifications.column_settings.admin.sign_up": "Новыя ўваходы:",
|
"notifications.column_settings.admin.sign_up": "Новыя ўваходы:",
|
||||||
|
@ -549,7 +608,7 @@
|
||||||
"notifications.column_settings.filter_bar.category": "Панэль хуткай фільтрацыі",
|
"notifications.column_settings.filter_bar.category": "Панэль хуткай фільтрацыі",
|
||||||
"notifications.column_settings.follow": "Новыя падпісчыкі:",
|
"notifications.column_settings.follow": "Новыя падпісчыкі:",
|
||||||
"notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
|
"notifications.column_settings.follow_request": "Новыя запыты на падпіску:",
|
||||||
"notifications.column_settings.group": "Аб'яднаць апавяшчэнні ад падпісчыкаў",
|
"notifications.column_settings.group": "Аб’яднаць апавяшчэнні ад падпісчыкаў",
|
||||||
"notifications.column_settings.mention": "Згадванні:",
|
"notifications.column_settings.mention": "Згадванні:",
|
||||||
"notifications.column_settings.poll": "Вынікі апытання:",
|
"notifications.column_settings.poll": "Вынікі апытання:",
|
||||||
"notifications.column_settings.push": "Push-апавяшчэнні",
|
"notifications.column_settings.push": "Push-апавяшчэнні",
|
||||||
|
@ -571,13 +630,13 @@
|
||||||
"notifications.group": "{count} Апавяшчэнняў",
|
"notifications.group": "{count} Апавяшчэнняў",
|
||||||
"notifications.mark_as_read": "Пазначыць усе апавяшчэнні як прачытаныя",
|
"notifications.mark_as_read": "Пазначыць усе апавяшчэнні як прачытаныя",
|
||||||
"notifications.permission_denied": "Апавяшчэнні на працоўным стале недаступныя з-за папярэдне адхіленага запыта праў браўзера",
|
"notifications.permission_denied": "Апавяшчэнні на працоўным стале недаступныя з-за папярэдне адхіленага запыта праў браўзера",
|
||||||
"notifications.permission_denied_alert": "Апавяшчэнні на працоўным стале не могуць быць уключаныя, з-за таго што запыт браўзера быў адхілены",
|
"notifications.permission_denied_alert": "З-за таго, што запыт браўзера быў раней адхілены, немагчыма ўключыць апавяшчэнні на працоўным стале",
|
||||||
"notifications.permission_required": "Апавяшчэнні на працоўным стале недаступныя, з-за таго што неабходны дазвол не быў дадзены.",
|
"notifications.permission_required": "Апавяшчэнні на працоўным стале недаступныя, з-за таго што неабходны дазвол не быў дадзены.",
|
||||||
"notifications.policy.accept": "Прыняць",
|
"notifications.policy.accept": "Прыняць",
|
||||||
"notifications.policy.accept_hint": "Паказваць у апавяшчэннях",
|
"notifications.policy.accept_hint": "Паказваць у апавяшчэннях",
|
||||||
"notifications.policy.drop": "Iгнараваць",
|
"notifications.policy.drop": "Iгнараваць",
|
||||||
"notifications.policy.filter": "Фільтраваць",
|
"notifications.policy.filter": "Фільтраваць",
|
||||||
"notifications.policy.filter_limited_accounts_title": "Абмежаваныя ўліковыя запісы",
|
"notifications.policy.filter_limited_accounts_title": "Уліковыя запісы пад мадэрацыяй",
|
||||||
"notifications.policy.filter_new_accounts.hint": "Створаныя на працягу {days, plural, one {апошняга # дня} few {апошніх # дзён} many {апошніх # дзён} other {апошняй # дня}}",
|
"notifications.policy.filter_new_accounts.hint": "Створаныя на працягу {days, plural, one {апошняга # дня} few {апошніх # дзён} many {апошніх # дзён} other {апошняй # дня}}",
|
||||||
"notifications.policy.filter_new_accounts_title": "Новыя ўліковыя запісы",
|
"notifications.policy.filter_new_accounts_title": "Новыя ўліковыя запісы",
|
||||||
"notifications.policy.filter_not_followers_hint": "Уключаючы людзей, якія падпісаны на вас менш, чым {days, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}}",
|
"notifications.policy.filter_not_followers_hint": "Уключаючы людзей, якія падпісаны на вас менш, чым {days, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}}",
|
||||||
|
@ -594,13 +653,13 @@
|
||||||
"onboarding.follows.done": "Гатова",
|
"onboarding.follows.done": "Гатова",
|
||||||
"onboarding.follows.empty": "На жаль, зараз немагчыма паказаць вынікі. Вы можаце паспрабаваць выкарыстоўваць пошук і праглядзець старонку агляду, каб знайсці людзей, на якіх можна падпісацца, або паўтарыце спробу пазней.",
|
"onboarding.follows.empty": "На жаль, зараз немагчыма паказаць вынікі. Вы можаце паспрабаваць выкарыстоўваць пошук і праглядзець старонку агляду, каб знайсці людзей, на якіх можна падпісацца, або паўтарыце спробу пазней.",
|
||||||
"onboarding.follows.search": "Пошук",
|
"onboarding.follows.search": "Пошук",
|
||||||
"onboarding.follows.title": "Падпішыцеся каб пачаць",
|
"onboarding.follows.title": "Падпішыцеся на некага, каб пачаць",
|
||||||
"onboarding.profile.discoverable": "Зрабіць мой профіль бачным",
|
"onboarding.profile.discoverable": "Зрабіць мой профіль бачным",
|
||||||
"onboarding.profile.discoverable_hint": "Калі вы звяртаецеся да адкрытасці на Mastodon, вашы паведамленні могуць з'яўляцца ў выніках пошуку і тэндэнцый, а ваш профіль можа быць прапанаваны людзям з такімі ж інтарэсамі.",
|
"onboarding.profile.discoverable_hint": "Калі вы звяртаецеся да адкрытасці на Mastodon, вашы паведамленні могуць з'яўляцца ў выніках пошуку і тэндэнцый, а ваш профіль можа быць прапанаваны людзям з такімі ж інтарэсамі.",
|
||||||
"onboarding.profile.display_name": "Бачнае імя",
|
"onboarding.profile.display_name": "Бачнае імя",
|
||||||
"onboarding.profile.display_name_hint": "Ваша поўнае імя або ваш псеўданім…",
|
"onboarding.profile.display_name_hint": "Ваша поўнае імя або ваш псеўданім…",
|
||||||
"onboarding.profile.note": "Біяграфія",
|
"onboarding.profile.note": "Біяграфія",
|
||||||
"onboarding.profile.note_hint": "Вы можаце @згадаць іншых людзей або выкарыстоўваць #хэштэгі…",
|
"onboarding.profile.note_hint": "Вы можаце @згадваць іншых людзей або выкарыстоўваць #хэштэгі…",
|
||||||
"onboarding.profile.save_and_continue": "Захаваць і працягнуць",
|
"onboarding.profile.save_and_continue": "Захаваць і працягнуць",
|
||||||
"onboarding.profile.title": "Налады профілю",
|
"onboarding.profile.title": "Налады профілю",
|
||||||
"onboarding.profile.upload_avatar": "Загрузіць фота профілю",
|
"onboarding.profile.upload_avatar": "Загрузіць фота профілю",
|
||||||
|
@ -620,6 +679,7 @@
|
||||||
"poll_button.remove_poll": "Выдаліць апытанне",
|
"poll_button.remove_poll": "Выдаліць апытанне",
|
||||||
"privacy.change": "Змяніць прыватнасць допісу",
|
"privacy.change": "Змяніць прыватнасць допісу",
|
||||||
"privacy.direct.long": "Усе згаданыя ў допісе",
|
"privacy.direct.long": "Усе згаданыя ў допісе",
|
||||||
|
"privacy.direct.short": "Асабістае згадванне",
|
||||||
"privacy.private.long": "Толькі вашыя падпісчыкі",
|
"privacy.private.long": "Толькі вашыя падпісчыкі",
|
||||||
"privacy.private.short": "Падпісчыкі",
|
"privacy.private.short": "Падпісчыкі",
|
||||||
"privacy.public.long": "Усе, хто ёсць і каго няма ў Mastodon",
|
"privacy.public.long": "Усе, хто ёсць і каго няма ў Mastodon",
|
||||||
|
@ -629,10 +689,10 @@
|
||||||
"privacy.unlisted.short": "Ціхі публічны",
|
"privacy.unlisted.short": "Ціхі публічны",
|
||||||
"privacy_policy.last_updated": "Адноўлена {date}",
|
"privacy_policy.last_updated": "Адноўлена {date}",
|
||||||
"privacy_policy.title": "Палітыка канфідэнцыйнасці",
|
"privacy_policy.title": "Палітыка канфідэнцыйнасці",
|
||||||
"recommended": "Рэкамендуем",
|
"recommended": "Рэкамендаванае",
|
||||||
"refresh": "Абнавiць",
|
"refresh": "Абнавiць",
|
||||||
"regeneration_indicator.please_stand_by": "Калі ласка, пачакайце.",
|
"regeneration_indicator.please_stand_by": "Пачакайце.",
|
||||||
"regeneration_indicator.preparing_your_home_feed": "Рыхтуем вашую стужку…",
|
"regeneration_indicator.preparing_your_home_feed": "Рыхтуем вашу галоўную стужку…",
|
||||||
"relative_time.days": "{number} д",
|
"relative_time.days": "{number} д",
|
||||||
"relative_time.full.days": "{number, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}} таму",
|
"relative_time.full.days": "{number, plural, one {# дзень} few {# дні} many {# дзён} other {# дня}} таму",
|
||||||
"relative_time.full.hours": "{number, plural, one {# гадзіна} few {# гадзіны} many {# гадзін} other {# гадзіны}} таму",
|
"relative_time.full.hours": "{number, plural, one {# гадзіна} few {# гадзіны} many {# гадзін} other {# гадзіны}} таму",
|
||||||
|
@ -649,7 +709,7 @@
|
||||||
"reply_indicator.poll": "Апытанне",
|
"reply_indicator.poll": "Апытанне",
|
||||||
"report.block": "Заблакіраваць",
|
"report.block": "Заблакіраваць",
|
||||||
"report.block_explanation": "Вы перастанеце бачыць допісы гэтага карыстальніка. Ён не зможа сачыць за вамі і бачыць вашы допісы. Ён зможа зразумець, што яго заблакіравалі.",
|
"report.block_explanation": "Вы перастанеце бачыць допісы гэтага карыстальніка. Ён не зможа сачыць за вамі і бачыць вашы допісы. Ён зможа зразумець, што яго заблакіравалі.",
|
||||||
"report.categories.legal": "Права",
|
"report.categories.legal": "Звязанае з правам",
|
||||||
"report.categories.other": "Іншае",
|
"report.categories.other": "Іншае",
|
||||||
"report.categories.spam": "Спам",
|
"report.categories.spam": "Спам",
|
||||||
"report.categories.violation": "Змест парушае адно ці некалькі правілаў сервера",
|
"report.categories.violation": "Змест парушае адно ці некалькі правілаў сервера",
|
||||||
|
@ -716,8 +776,8 @@
|
||||||
"search_results.accounts": "Профілі",
|
"search_results.accounts": "Профілі",
|
||||||
"search_results.all": "Усё",
|
"search_results.all": "Усё",
|
||||||
"search_results.hashtags": "Хэштэгі",
|
"search_results.hashtags": "Хэштэгі",
|
||||||
"search_results.no_results": "Анічога ня знойдзена.",
|
"search_results.no_results": "Няма вынікаў.",
|
||||||
"search_results.no_search_yet": "Паспрабуйце пашукаць допісы, профілі або гэштаґі.",
|
"search_results.no_search_yet": "Паспрабуйце пашукаць допісы, профілі або хэштэгі.",
|
||||||
"search_results.see_all": "Праглядзець усе",
|
"search_results.see_all": "Праглядзець усе",
|
||||||
"search_results.statuses": "Допісы",
|
"search_results.statuses": "Допісы",
|
||||||
"search_results.title": "Шукаць \"{q}\"",
|
"search_results.title": "Шукаць \"{q}\"",
|
||||||
|
@ -738,7 +798,7 @@
|
||||||
"status.bookmark": "Дадаць закладку",
|
"status.bookmark": "Дадаць закладку",
|
||||||
"status.cancel_reblog_private": "Прыбраць",
|
"status.cancel_reblog_private": "Прыбраць",
|
||||||
"status.cannot_reblog": "Гэты пост нельга пашырыць",
|
"status.cannot_reblog": "Гэты пост нельга пашырыць",
|
||||||
"status.continued_thread": "Працяг тэмы",
|
"status.continued_thread": "Працяг ланцужка",
|
||||||
"status.copy": "Скапіраваць спасылку на допіс",
|
"status.copy": "Скапіраваць спасылку на допіс",
|
||||||
"status.delete": "Выдаліць",
|
"status.delete": "Выдаліць",
|
||||||
"status.detailed_status": "Дэтальны агляд размовы",
|
"status.detailed_status": "Дэтальны агляд размовы",
|
||||||
|
@ -763,6 +823,7 @@
|
||||||
"status.mute_conversation": "Ігнараваць размову",
|
"status.mute_conversation": "Ігнараваць размову",
|
||||||
"status.open": "Разгарнуць гэты допіс",
|
"status.open": "Разгарнуць гэты допіс",
|
||||||
"status.pin": "Замацаваць у профілі",
|
"status.pin": "Замацаваць у профілі",
|
||||||
|
"status.quote_post_author": "Допіс карыстальніка @{name}",
|
||||||
"status.read_more": "Чытаць болей",
|
"status.read_more": "Чытаць болей",
|
||||||
"status.reblog": "Пашырыць",
|
"status.reblog": "Пашырыць",
|
||||||
"status.reblog_private": "Пашырыць з першапачатковай бачнасцю",
|
"status.reblog_private": "Пашырыць з першапачатковай бачнасцю",
|
||||||
|
@ -771,7 +832,7 @@
|
||||||
"status.reblogs.empty": "Гэты допіс яшчэ ніхто не пашырыў. Калі гэта адбудзецца, гэтых людзей будзе бачна тут.",
|
"status.reblogs.empty": "Гэты допіс яшчэ ніхто не пашырыў. Калі гэта адбудзецца, гэтых людзей будзе бачна тут.",
|
||||||
"status.redraft": "Выдаліць і паправіць",
|
"status.redraft": "Выдаліць і паправіць",
|
||||||
"status.remove_bookmark": "Выдаліць закладку",
|
"status.remove_bookmark": "Выдаліць закладку",
|
||||||
"status.replied_in_thread": "Адказаў у тэме",
|
"status.replied_in_thread": "Адказаў у ланцужку",
|
||||||
"status.replied_to": "Адказаў {name}",
|
"status.replied_to": "Адказаў {name}",
|
||||||
"status.reply": "Адказаць",
|
"status.reply": "Адказаць",
|
||||||
"status.replyAll": "Адказаць у ланцугу",
|
"status.replyAll": "Адказаць у ланцугу",
|
||||||
|
@ -791,8 +852,11 @@
|
||||||
"subscribed_languages.save": "Захаваць змены",
|
"subscribed_languages.save": "Захаваць змены",
|
||||||
"subscribed_languages.target": "Змяніць мовы падпіскі для {target}",
|
"subscribed_languages.target": "Змяніць мовы падпіскі для {target}",
|
||||||
"tabs_bar.home": "Галоўная",
|
"tabs_bar.home": "Галоўная",
|
||||||
|
"tabs_bar.menu": "Меню",
|
||||||
"tabs_bar.notifications": "Апавяшчэнні",
|
"tabs_bar.notifications": "Апавяшчэнні",
|
||||||
"terms_of_service.title": "Умовы абслугоўваньня",
|
"tabs_bar.publish": "Новы допіс",
|
||||||
|
"tabs_bar.search": "Пошук",
|
||||||
|
"terms_of_service.title": "Умовы выкарыстання",
|
||||||
"time_remaining.days": "{number, plural, one {застаўся # дзень} few {засталося # дні} many {засталося # дзён} other {засталося # дня}}",
|
"time_remaining.days": "{number, plural, one {застаўся # дзень} few {засталося # дні} many {засталося # дзён} other {засталося # дня}}",
|
||||||
"time_remaining.hours": "{number, plural, one {засталася # гадзіна} few {засталося # гадзіны} many {засталося # гадзін} other {засталося # гадзіны}}",
|
"time_remaining.hours": "{number, plural, one {засталася # гадзіна} few {засталося # гадзіны} many {засталося # гадзін} other {засталося # гадзіны}}",
|
||||||
"time_remaining.minutes": "{number, plural, one {засталася # хвіліна} few {засталося # хвіліны} many {засталося # хвілін} other {засталося # хвіліны}}",
|
"time_remaining.minutes": "{number, plural, one {засталася # хвіліна} few {засталося # хвіліны} many {засталося # хвілін} other {засталося # хвіліны}}",
|
||||||
|
@ -818,6 +882,12 @@
|
||||||
"video.expand": "Разгарнуць відэа",
|
"video.expand": "Разгарнуць відэа",
|
||||||
"video.fullscreen": "Увесь экран",
|
"video.fullscreen": "Увесь экран",
|
||||||
"video.hide": "Схаваць відэа",
|
"video.hide": "Схаваць відэа",
|
||||||
|
"video.mute": "Выключыць гук",
|
||||||
"video.pause": "Паўза",
|
"video.pause": "Паўза",
|
||||||
"video.play": "Прайграць"
|
"video.play": "Прайграць",
|
||||||
|
"video.skip_backward": "Праматаць назад",
|
||||||
|
"video.skip_forward": "Праматаць уперад",
|
||||||
|
"video.unmute": "Уключыць гук",
|
||||||
|
"video.volume_down": "Паменшыць гучнасць",
|
||||||
|
"video.volume_up": "Павялічыць гучнасць"
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,7 +188,7 @@
|
||||||
"community.column_settings.remote_only": "Само отдалечено",
|
"community.column_settings.remote_only": "Само отдалечено",
|
||||||
"compose.language.change": "Смяна на езика",
|
"compose.language.change": "Смяна на езика",
|
||||||
"compose.language.search": "Търсене на езици...",
|
"compose.language.search": "Търсене на езици...",
|
||||||
"compose.published.body": "Публикувана публикация.",
|
"compose.published.body": "Публикувано.",
|
||||||
"compose.published.open": "Отваряне",
|
"compose.published.open": "Отваряне",
|
||||||
"compose.saved.body": "Запазена публикация.",
|
"compose.saved.body": "Запазена публикация.",
|
||||||
"compose_form.direct_message_warning_learn_more": "Още информация",
|
"compose_form.direct_message_warning_learn_more": "Още информация",
|
||||||
|
|
|
@ -219,6 +219,13 @@
|
||||||
"confirmations.delete_list.confirm": "Elimina",
|
"confirmations.delete_list.confirm": "Elimina",
|
||||||
"confirmations.delete_list.message": "Segur que vols suprimir permanentment aquesta llista?",
|
"confirmations.delete_list.message": "Segur que vols suprimir permanentment aquesta llista?",
|
||||||
"confirmations.delete_list.title": "Eliminar la llista?",
|
"confirmations.delete_list.title": "Eliminar la llista?",
|
||||||
|
"confirmations.discard_draft.confirm": "Descarta i continua",
|
||||||
|
"confirmations.discard_draft.edit.cancel": "Continua l'edició",
|
||||||
|
"confirmations.discard_draft.edit.message": "Continuar descartarà tots els canvis que hàgiu fet a la publicació que editeu.",
|
||||||
|
"confirmations.discard_draft.edit.title": "Descartar els canvis a la publicació?",
|
||||||
|
"confirmations.discard_draft.post.cancel": "Reprendre l'esborrany",
|
||||||
|
"confirmations.discard_draft.post.message": "Continuar descartarà la publicació que escriviu.",
|
||||||
|
"confirmations.discard_draft.post.title": "Descartar l'esborrany?",
|
||||||
"confirmations.discard_edit_media.confirm": "Descarta",
|
"confirmations.discard_edit_media.confirm": "Descarta",
|
||||||
"confirmations.discard_edit_media.message": "Tens canvis no desats en la descripció del contingut o en la previsualització, els vols descartar?",
|
"confirmations.discard_edit_media.message": "Tens canvis no desats en la descripció del contingut o en la previsualització, els vols descartar?",
|
||||||
"confirmations.follow_to_list.confirm": "Seguir i afegir a una llista",
|
"confirmations.follow_to_list.confirm": "Seguir i afegir a una llista",
|
||||||
|
@ -556,6 +563,8 @@
|
||||||
"navigation_bar.follows_and_followers": "Seguint i seguidors",
|
"navigation_bar.follows_and_followers": "Seguint i seguidors",
|
||||||
"navigation_bar.import_export": "Importació i exportació",
|
"navigation_bar.import_export": "Importació i exportació",
|
||||||
"navigation_bar.lists": "Llistes",
|
"navigation_bar.lists": "Llistes",
|
||||||
|
"navigation_bar.live_feed_local": "Canal en directe (local)",
|
||||||
|
"navigation_bar.live_feed_public": "Canal en directe (públic)",
|
||||||
"navigation_bar.logout": "Tanca la sessió",
|
"navigation_bar.logout": "Tanca la sessió",
|
||||||
"navigation_bar.moderation": "Moderació",
|
"navigation_bar.moderation": "Moderació",
|
||||||
"navigation_bar.more": "Més",
|
"navigation_bar.more": "Més",
|
||||||
|
@ -564,7 +573,10 @@
|
||||||
"navigation_bar.preferences": "Preferències",
|
"navigation_bar.preferences": "Preferències",
|
||||||
"navigation_bar.privacy_and_reach": "Privacitat i abast",
|
"navigation_bar.privacy_and_reach": "Privacitat i abast",
|
||||||
"navigation_bar.search": "Cerca",
|
"navigation_bar.search": "Cerca",
|
||||||
|
"navigation_bar.search_trends": "Cerca / En tendència",
|
||||||
|
"navigation_panel.collapse_followed_tags": "Comprimeix el menú d'etiquetes seguides",
|
||||||
"navigation_panel.collapse_lists": "Tanca el menú",
|
"navigation_panel.collapse_lists": "Tanca el menú",
|
||||||
|
"navigation_panel.expand_followed_tags": "Expandeix el menú d'etiquetes seguides",
|
||||||
"navigation_panel.expand_lists": "Expandeix el menú",
|
"navigation_panel.expand_lists": "Expandeix el menú",
|
||||||
"not_signed_in_indicator.not_signed_in": "Cal que iniciïs la sessió per a accedir a aquest recurs.",
|
"not_signed_in_indicator.not_signed_in": "Cal que iniciïs la sessió per a accedir a aquest recurs.",
|
||||||
"notification.admin.report": "{name} ha reportat {target}",
|
"notification.admin.report": "{name} ha reportat {target}",
|
||||||
|
@ -792,6 +804,7 @@
|
||||||
"report_notification.categories.violation": "Violació de norma",
|
"report_notification.categories.violation": "Violació de norma",
|
||||||
"report_notification.categories.violation_sentence": "violació de normes",
|
"report_notification.categories.violation_sentence": "violació de normes",
|
||||||
"report_notification.open": "Obre l'informe",
|
"report_notification.open": "Obre l'informe",
|
||||||
|
"search.clear": "Esborra la cerca",
|
||||||
"search.no_recent_searches": "No hi ha cerques recents",
|
"search.no_recent_searches": "No hi ha cerques recents",
|
||||||
"search.placeholder": "Cerca",
|
"search.placeholder": "Cerca",
|
||||||
"search.quick_action.account_search": "Perfils coincidint amb {x}",
|
"search.quick_action.account_search": "Perfils coincidint amb {x}",
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"account.mute_notifications_short": "Sluk for notifikationer",
|
"account.mute_notifications_short": "Sluk for notifikationer",
|
||||||
"account.mute_short": "Skjul",
|
"account.mute_short": "Skjul",
|
||||||
"account.muted": "Skjult",
|
"account.muted": "Skjult",
|
||||||
"account.muting": "Tavsgørelse",
|
"account.muting": "Skjuler",
|
||||||
"account.mutual": "I følger hinanden",
|
"account.mutual": "I følger hinanden",
|
||||||
"account.no_bio": "Ingen beskrivelse til rådighed.",
|
"account.no_bio": "Ingen beskrivelse til rådighed.",
|
||||||
"account.open_original_page": "Åbn oprindelig side",
|
"account.open_original_page": "Åbn oprindelig side",
|
||||||
|
@ -350,7 +350,7 @@
|
||||||
"filter_modal.added.context_mismatch_title": "Kontekstmisforhold!",
|
"filter_modal.added.context_mismatch_title": "Kontekstmisforhold!",
|
||||||
"filter_modal.added.expired_explanation": "Denne filterkategori er udløbet. Ændr dens udløbsdato, for at anvende den.",
|
"filter_modal.added.expired_explanation": "Denne filterkategori er udløbet. Ændr dens udløbsdato, for at anvende den.",
|
||||||
"filter_modal.added.expired_title": "Udløbet filter!",
|
"filter_modal.added.expired_title": "Udløbet filter!",
|
||||||
"filter_modal.added.review_and_configure": "Gå til {settings_link} for at gennemse og yderligere opsætte denne filterkategori.",
|
"filter_modal.added.review_and_configure": "Gå til {settings_link} for at gennemgå og konfigurere denne filterkategori yderligere.",
|
||||||
"filter_modal.added.review_and_configure_title": "Filterindstillinger",
|
"filter_modal.added.review_and_configure_title": "Filterindstillinger",
|
||||||
"filter_modal.added.settings_link": "indstillingsside",
|
"filter_modal.added.settings_link": "indstillingsside",
|
||||||
"filter_modal.added.short_explanation": "Dette indlæg er nu føjet til følgende filterkategori: {title}.",
|
"filter_modal.added.short_explanation": "Dette indlæg er nu føjet til følgende filterkategori: {title}.",
|
||||||
|
@ -386,7 +386,7 @@
|
||||||
"follow_suggestions.similar_to_recently_followed_longer": "Minder om profiler, du har fulgt for nylig",
|
"follow_suggestions.similar_to_recently_followed_longer": "Minder om profiler, du har fulgt for nylig",
|
||||||
"follow_suggestions.view_all": "Vis alle",
|
"follow_suggestions.view_all": "Vis alle",
|
||||||
"follow_suggestions.who_to_follow": "Hvem, som skal følges",
|
"follow_suggestions.who_to_follow": "Hvem, som skal følges",
|
||||||
"followed_tags": "Hashtag, som følges",
|
"followed_tags": "Hashtags, som følges",
|
||||||
"footer.about": "Om",
|
"footer.about": "Om",
|
||||||
"footer.directory": "Profiloversigt",
|
"footer.directory": "Profiloversigt",
|
||||||
"footer.get_app": "Hent appen",
|
"footer.get_app": "Hent appen",
|
||||||
|
@ -560,7 +560,7 @@
|
||||||
"navigation_bar.favourites": "Favoritter",
|
"navigation_bar.favourites": "Favoritter",
|
||||||
"navigation_bar.filters": "Skjulte ord",
|
"navigation_bar.filters": "Skjulte ord",
|
||||||
"navigation_bar.follow_requests": "Følgeanmodninger",
|
"navigation_bar.follow_requests": "Følgeanmodninger",
|
||||||
"navigation_bar.followed_tags": "Hashtag, som følges",
|
"navigation_bar.followed_tags": "Hashtags, som følges",
|
||||||
"navigation_bar.follows_and_followers": "Følges og følgere",
|
"navigation_bar.follows_and_followers": "Følges og følgere",
|
||||||
"navigation_bar.import_export": "Import og eksport",
|
"navigation_bar.import_export": "Import og eksport",
|
||||||
"navigation_bar.lists": "Lister",
|
"navigation_bar.lists": "Lister",
|
||||||
|
@ -572,7 +572,7 @@
|
||||||
"navigation_bar.mutes": "Skjulte brugere",
|
"navigation_bar.mutes": "Skjulte brugere",
|
||||||
"navigation_bar.opened_in_classic_interface": "Indlæg, konti og visse andre sider åbnes som standard i den klassiske webgrænseflade.",
|
"navigation_bar.opened_in_classic_interface": "Indlæg, konti og visse andre sider åbnes som standard i den klassiske webgrænseflade.",
|
||||||
"navigation_bar.preferences": "Præferencer",
|
"navigation_bar.preferences": "Præferencer",
|
||||||
"navigation_bar.privacy_and_reach": "Fortrolighed og udbredelse",
|
"navigation_bar.privacy_and_reach": "Fortrolighed og rækkevidde",
|
||||||
"navigation_bar.search": "Søg",
|
"navigation_bar.search": "Søg",
|
||||||
"navigation_bar.search_trends": "Søg/Trender",
|
"navigation_bar.search_trends": "Søg/Trender",
|
||||||
"navigation_panel.collapse_followed_tags": "Sammenfold menuen Fulgte hashtags",
|
"navigation_panel.collapse_followed_tags": "Sammenfold menuen Fulgte hashtags",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"about.default_locale": "Προεπιλογή",
|
"about.default_locale": "Προεπιλογή",
|
||||||
"about.disclaimer": "Το Mastodon είναι ελεύθερο λογισμικό ανοιχτού κώδικα και εμπορικό σήμα της Mastodon gGmbH.",
|
"about.disclaimer": "Το Mastodon είναι ελεύθερο λογισμικό ανοιχτού κώδικα και εμπορικό σήμα της Mastodon gGmbH.",
|
||||||
"about.domain_blocks.no_reason_available": "Αιτιολογία μη διαθέσιμη",
|
"about.domain_blocks.no_reason_available": "Αιτιολογία μη διαθέσιμη",
|
||||||
"about.domain_blocks.preamble": "Σε γενικές γραμμές το Mastodon σού επιτρέπει να βλέπεις περιεχόμενο και να αλληλεπιδράς με χρήστες από οποιονδήποτε άλλο διακομιστή σε ένα διασυνδεδεμένο σύμπαν διακομιστών (fediverse). Ακολουθούν οι εξαιρέσεις που ισχύουν για τον συγκεκριμένο διακομιστή.",
|
"about.domain_blocks.preamble": "Σε γενικές γραμμές το Mastodon σου επιτρέπει να βλέπεις περιεχόμενο και να αλληλεπιδράς με χρήστες από οποιονδήποτε άλλο διακομιστή σε ένα διασυνδεδεμένο σύμπαν διακομιστών (fediverse). Ακολουθούν οι εξαιρέσεις που ισχύουν για τον συγκεκριμένο διακομιστή.",
|
||||||
"about.domain_blocks.silenced.explanation": "Συνήθως δε θα βλέπεις προφίλ και περιεχόμενο απ' αυτόν τον διακομιστή, εκτός αν κάνεις συγκεκριμένη αναζήτηση ή επιλέξεις να τον ακολουθήσεις.",
|
"about.domain_blocks.silenced.explanation": "Συνήθως δε θα βλέπεις προφίλ και περιεχόμενο απ' αυτόν τον διακομιστή, εκτός αν κάνεις συγκεκριμένη αναζήτηση ή επιλέξεις να τον ακολουθήσεις.",
|
||||||
"about.domain_blocks.silenced.title": "Περιορισμένος",
|
"about.domain_blocks.silenced.title": "Περιορισμένος",
|
||||||
"about.domain_blocks.suspended.explanation": "Τα δεδομένα αυτού του διακομιστή, δε θα επεξεργάζονται, δε θα αποθηκεύονται και δε θα ανταλλάσσονται, καθιστώντας οποιαδήποτε αλληλεπίδραση ή επικοινωνία με χρήστες από αυτόν το διακομιστή αδύνατη.",
|
"about.domain_blocks.suspended.explanation": "Τα δεδομένα αυτού του διακομιστή, δε θα επεξεργάζονται, δε θα αποθηκεύονται και δε θα ανταλλάσσονται, καθιστώντας οποιαδήποτε αλληλεπίδραση ή επικοινωνία με χρήστες από αυτόν το διακομιστή αδύνατη.",
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
"account.muting": "Σίγαση",
|
"account.muting": "Σίγαση",
|
||||||
"account.mutual": "Ακολουθείτε ο ένας τον άλλο",
|
"account.mutual": "Ακολουθείτε ο ένας τον άλλο",
|
||||||
"account.no_bio": "Δεν υπάρχει περιγραφή.",
|
"account.no_bio": "Δεν υπάρχει περιγραφή.",
|
||||||
"account.open_original_page": "Ανοικτό",
|
"account.open_original_page": "Άνοιγμα αυθεντικής σελίδας",
|
||||||
"account.posts": "Τουτ",
|
"account.posts": "Τουτ",
|
||||||
"account.posts_with_replies": "Τουτ και απαντήσεις",
|
"account.posts_with_replies": "Τουτ και απαντήσεις",
|
||||||
"account.remove_from_followers": "Κατάργηση {name} από τους ακόλουθους",
|
"account.remove_from_followers": "Κατάργηση {name} από τους ακόλουθους",
|
||||||
|
@ -194,9 +194,9 @@
|
||||||
"compose.saved.body": "Η ανάρτηση αποθηκεύτηκε.",
|
"compose.saved.body": "Η ανάρτηση αποθηκεύτηκε.",
|
||||||
"compose_form.direct_message_warning_learn_more": "Μάθε περισσότερα",
|
"compose_form.direct_message_warning_learn_more": "Μάθε περισσότερα",
|
||||||
"compose_form.encryption_warning": "Οι δημοσιεύσεις στο Mastodon δεν είναι κρυπτογραφημένες από άκρο σε άκρο. Μη μοιράζεσαι ευαίσθητες πληροφορίες μέσω του Mastodon.",
|
"compose_form.encryption_warning": "Οι δημοσιεύσεις στο Mastodon δεν είναι κρυπτογραφημένες από άκρο σε άκρο. Μη μοιράζεσαι ευαίσθητες πληροφορίες μέσω του Mastodon.",
|
||||||
"compose_form.hashtag_warning": "Αυτή η δημοσίευση δεν θα εμφανίζεται κάτω από οποιαδήποτε ετικέτα καθώς δεν είναι δημόσια. Μόνο οι δημόσιες δημοσιεύσεις μπορούν να αναζητηθούν με ετικέτα.",
|
"compose_form.hashtag_warning": "Αυτή η ανάρτηση δεν θα εμφανίζεται κάτω από οποιαδήποτε ετικέτα καθώς δεν είναι δημόσια. Μόνο οι δημόσιες αναρτήσεις μπορούν να αναζητηθούν με ετικέτα.",
|
||||||
"compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σου προς τους ακολούθους σου.",
|
"compose_form.lock_disclaimer": "Ο λογαριασμός σου δεν είναι {locked}. Οποιοσδήποτε μπορεί να σε ακολουθήσει για να δει τις δημοσιεύσεις σου προς τους ακολούθους σου.",
|
||||||
"compose_form.lock_disclaimer.lock": "κλειδωμένο",
|
"compose_form.lock_disclaimer.lock": "κλειδωμένος",
|
||||||
"compose_form.placeholder": "Τι σκέφτεσαι;",
|
"compose_form.placeholder": "Τι σκέφτεσαι;",
|
||||||
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
"compose_form.poll.duration": "Διάρκεια δημοσκόπησης",
|
||||||
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
"compose_form.poll.multiple": "Πολλαπλή επιλογή",
|
||||||
|
@ -214,13 +214,18 @@
|
||||||
"confirmation_modal.cancel": "Άκυρο",
|
"confirmation_modal.cancel": "Άκυρο",
|
||||||
"confirmations.block.confirm": "Αποκλεισμός",
|
"confirmations.block.confirm": "Αποκλεισμός",
|
||||||
"confirmations.delete.confirm": "Διαγραφή",
|
"confirmations.delete.confirm": "Διαγραφή",
|
||||||
"confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή τη δημοσίευση;",
|
"confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή την ανάρτηση;",
|
||||||
"confirmations.delete.title": "Διαγραφή ανάρτησης;",
|
"confirmations.delete.title": "Διαγραφή ανάρτησης;",
|
||||||
"confirmations.delete_list.confirm": "Διαγραφή",
|
"confirmations.delete_list.confirm": "Διαγραφή",
|
||||||
"confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;",
|
"confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;",
|
||||||
"confirmations.delete_list.title": "Διαγραφή λίστας;",
|
"confirmations.delete_list.title": "Διαγραφή λίστας;",
|
||||||
"confirmations.discard_draft.confirm": "Απόρριψη και συνέχεια",
|
"confirmations.discard_draft.confirm": "Απόρριψη και συνέχεια",
|
||||||
"confirmations.discard_draft.edit.cancel": "Συνέχιση επεξεργασίας",
|
"confirmations.discard_draft.edit.cancel": "Συνέχιση επεξεργασίας",
|
||||||
|
"confirmations.discard_draft.edit.message": "Συνεχίζοντας θα απορρίψει τυχόν αλλαγές που έχετε κάνει στην ανάρτηση που επεξεργάζεστε.",
|
||||||
|
"confirmations.discard_draft.edit.title": "Απόρριψη αλλαγών στην ανάρτηση σας;",
|
||||||
|
"confirmations.discard_draft.post.cancel": "Συνέχιση προχείρου",
|
||||||
|
"confirmations.discard_draft.post.message": "Συνεχίζοντας θα απορρίψει την ανάρτηση που συνθέτετε.",
|
||||||
|
"confirmations.discard_draft.post.title": "Απόρριψη της πρόχειρης ανάρτησης σας;",
|
||||||
"confirmations.discard_edit_media.confirm": "Απόρριψη",
|
"confirmations.discard_edit_media.confirm": "Απόρριψη",
|
||||||
"confirmations.discard_edit_media.message": "Έχεις μη αποθηκευμένες αλλαγές στην περιγραφή πολυμέσων ή στην προεπισκόπηση, απόρριψη ούτως ή άλλως;",
|
"confirmations.discard_edit_media.message": "Έχεις μη αποθηκευμένες αλλαγές στην περιγραφή πολυμέσων ή στην προεπισκόπηση, απόρριψη ούτως ή άλλως;",
|
||||||
"confirmations.follow_to_list.confirm": "Ακολούθησε και πρόσθεσε στη λίστα",
|
"confirmations.follow_to_list.confirm": "Ακολούθησε και πρόσθεσε στη λίστα",
|
||||||
|
@ -232,7 +237,7 @@
|
||||||
"confirmations.missing_alt_text.confirm": "Προσθήκη εναλ κειμένου",
|
"confirmations.missing_alt_text.confirm": "Προσθήκη εναλ κειμένου",
|
||||||
"confirmations.missing_alt_text.message": "Η ανάρτησή σου περιέχει πολυμέσα χωρίς εναλλακτικό κείμενο. Η προσθήκη περιγραφών βοηθά να γίνει το περιεχόμενό σου προσβάσιμο σε περισσότερους ανθρώπους.",
|
"confirmations.missing_alt_text.message": "Η ανάρτησή σου περιέχει πολυμέσα χωρίς εναλλακτικό κείμενο. Η προσθήκη περιγραφών βοηθά να γίνει το περιεχόμενό σου προσβάσιμο σε περισσότερους ανθρώπους.",
|
||||||
"confirmations.missing_alt_text.secondary": "Δημοσίευση όπως και να ΄χει",
|
"confirmations.missing_alt_text.secondary": "Δημοσίευση όπως και να ΄χει",
|
||||||
"confirmations.missing_alt_text.title": "Προσθήκη alt κειμένου;",
|
"confirmations.missing_alt_text.title": "Προσθήκη εναλλακτικού κειμένου;",
|
||||||
"confirmations.mute.confirm": "Αποσιώπηση",
|
"confirmations.mute.confirm": "Αποσιώπηση",
|
||||||
"confirmations.redraft.confirm": "Διαγραφή & ξαναγράψιμο",
|
"confirmations.redraft.confirm": "Διαγραφή & ξαναγράψιμο",
|
||||||
"confirmations.redraft.message": "Σίγουρα θέλεις να σβήσεις αυτή την ανάρτηση και να την ξαναγράψεις; Οι προτιμήσεις και προωθήσεις θα χαθούν και οι απαντήσεις στην αρχική ανάρτηση θα μείνουν ορφανές.",
|
"confirmations.redraft.message": "Σίγουρα θέλεις να σβήσεις αυτή την ανάρτηση και να την ξαναγράψεις; Οι προτιμήσεις και προωθήσεις θα χαθούν και οι απαντήσεις στην αρχική ανάρτηση θα μείνουν ορφανές.",
|
||||||
|
@ -271,7 +276,7 @@
|
||||||
"domain_block_modal.you_will_lose_num_followers": "Θα χάσετε {followersCount, plural, one {{followersCountDisplay} ακόλουθο} other {{followersCountDisplay} ακόλουθους}} και {followingCount, plural, one {{followingCountDisplay} άτομο που ακολουθείτε} other {{followingCountDisplay} άτομα που ακολουθείτε}}.",
|
"domain_block_modal.you_will_lose_num_followers": "Θα χάσετε {followersCount, plural, one {{followersCountDisplay} ακόλουθο} other {{followersCountDisplay} ακόλουθους}} και {followingCount, plural, one {{followingCountDisplay} άτομο που ακολουθείτε} other {{followingCountDisplay} άτομα που ακολουθείτε}}.",
|
||||||
"domain_block_modal.you_will_lose_relationships": "Θα χάσετε όλους τους ακόλουθους και τα άτομα που ακολουθείτε από αυτόν τον διακομιστή.",
|
"domain_block_modal.you_will_lose_relationships": "Θα χάσετε όλους τους ακόλουθους και τα άτομα που ακολουθείτε από αυτόν τον διακομιστή.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Δεν θα βλέπεις αναρτήσεις ή ειδοποιήσεις από χρήστες σε αυτόν το διακομιστή.",
|
"domain_block_modal.you_wont_see_posts": "Δεν θα βλέπεις αναρτήσεις ή ειδοποιήσεις από χρήστες σε αυτόν το διακομιστή.",
|
||||||
"domain_pill.activitypub_lets_connect": "Σού επιτρέπει να συνδεθείς και να αλληλεπιδράσεις με τους ανθρώπους όχι μόνο στο Mastodon, αλλά και σε διαφορετικές κοινωνικές εφαρμογές.",
|
"domain_pill.activitypub_lets_connect": "Σου επιτρέπει να συνδεθείς και να αλληλεπιδράσεις με τους ανθρώπους όχι μόνο στο Mastodon, αλλά και σε διαφορετικές κοινωνικές εφαρμογές.",
|
||||||
"domain_pill.activitypub_like_language": "Το ActivityPub είναι σαν τη γλώσσα Mastodon μιλάει με άλλα κοινωνικά δίκτυα.",
|
"domain_pill.activitypub_like_language": "Το ActivityPub είναι σαν τη γλώσσα Mastodon μιλάει με άλλα κοινωνικά δίκτυα.",
|
||||||
"domain_pill.server": "Διακομιστής",
|
"domain_pill.server": "Διακομιστής",
|
||||||
"domain_pill.their_handle": "Το πλήρες όνομα χρήστη:",
|
"domain_pill.their_handle": "Το πλήρες όνομα χρήστη:",
|
||||||
|
@ -317,7 +322,7 @@
|
||||||
"empty_column.favourited_statuses": "Δεν έχεις καμία αγαπημένη ανάρτηση ακόμα. Μόλις αγαπήσεις κάποια, θα εμφανιστεί εδώ.",
|
"empty_column.favourited_statuses": "Δεν έχεις καμία αγαπημένη ανάρτηση ακόμα. Μόλις αγαπήσεις κάποια, θα εμφανιστεί εδώ.",
|
||||||
"empty_column.favourites": "Κανείς δεν έχει αγαπήσει αυτή την ανάρτηση ακόμα. Μόλις το κάνει κάποιος, θα εμφανιστεί εδώ.",
|
"empty_column.favourites": "Κανείς δεν έχει αγαπήσει αυτή την ανάρτηση ακόμα. Μόλις το κάνει κάποιος, θα εμφανιστεί εδώ.",
|
||||||
"empty_column.follow_requests": "Δεν έχεις κανένα αίτημα παρακολούθησης ακόμα. Μόλις λάβεις κάποιο, θα εμφανιστεί εδώ.",
|
"empty_column.follow_requests": "Δεν έχεις κανένα αίτημα παρακολούθησης ακόμα. Μόλις λάβεις κάποιο, θα εμφανιστεί εδώ.",
|
||||||
"empty_column.followed_tags": "Δεν έχετε παρακολουθήσει ακόμα καμία ετικέτα. Όταν το κάνετε, θα εμφανιστούν εδώ.",
|
"empty_column.followed_tags": "Δεν έχετε ακολουθήσει ακόμα καμία ετικέτα. Όταν το κάνετε, θα εμφανιστούν εδώ.",
|
||||||
"empty_column.hashtag": "Δεν υπάρχει ακόμα κάτι για αυτή την ετικέτα.",
|
"empty_column.hashtag": "Δεν υπάρχει ακόμα κάτι για αυτή την ετικέτα.",
|
||||||
"empty_column.home": "Η τοπική σου ροή είναι κενή! Πήγαινε στο {public} ή κάνε αναζήτηση για να ξεκινήσεις και να γνωρίσεις άλλους χρήστες.",
|
"empty_column.home": "Η τοπική σου ροή είναι κενή! Πήγαινε στο {public} ή κάνε αναζήτηση για να ξεκινήσεις και να γνωρίσεις άλλους χρήστες.",
|
||||||
"empty_column.list": "Δεν υπάρχει τίποτα σε αυτή τη λίστα ακόμα. Όταν τα μέλη της δημοσιεύσουν νέες καταστάσεις, θα εμφανιστούν εδώ.",
|
"empty_column.list": "Δεν υπάρχει τίποτα σε αυτή τη λίστα ακόμα. Όταν τα μέλη της δημοσιεύσουν νέες καταστάσεις, θα εμφανιστούν εδώ.",
|
||||||
|
@ -381,7 +386,7 @@
|
||||||
"follow_suggestions.similar_to_recently_followed_longer": "Παρόμοια με προφίλ που ακολούθησες πρόσφατα",
|
"follow_suggestions.similar_to_recently_followed_longer": "Παρόμοια με προφίλ που ακολούθησες πρόσφατα",
|
||||||
"follow_suggestions.view_all": "Εμφάνιση όλων",
|
"follow_suggestions.view_all": "Εμφάνιση όλων",
|
||||||
"follow_suggestions.who_to_follow": "Ποιον να ακολουθήσεις",
|
"follow_suggestions.who_to_follow": "Ποιον να ακολουθήσεις",
|
||||||
"followed_tags": "Ετικέτες που ακολουθούνται",
|
"followed_tags": "Ακολουθούμενες ετικέτες",
|
||||||
"footer.about": "Σχετικά με",
|
"footer.about": "Σχετικά με",
|
||||||
"footer.directory": "Κατάλογος προφίλ",
|
"footer.directory": "Κατάλογος προφίλ",
|
||||||
"footer.get_app": "Αποκτήστε την εφαρμογή",
|
"footer.get_app": "Αποκτήστε την εφαρμογή",
|
||||||
|
@ -412,7 +417,7 @@
|
||||||
"hashtag.mute": "Σίγαση #{hashtag}",
|
"hashtag.mute": "Σίγαση #{hashtag}",
|
||||||
"hashtag.unfeature": "Να μην αναδεικνύεται στο προφίλ",
|
"hashtag.unfeature": "Να μην αναδεικνύεται στο προφίλ",
|
||||||
"hashtag.unfollow": "Διακοπή παρακολούθησης ετικέτας",
|
"hashtag.unfollow": "Διακοπή παρακολούθησης ετικέτας",
|
||||||
"hashtags.and_other": "…και {count, plural, one {}other {# ακόμη}}",
|
"hashtags.and_other": "…και {count, plural, other {# ακόμη}}",
|
||||||
"hints.profiles.followers_may_be_missing": "Μπορεί να λείπουν ακόλουθοι για αυτό το προφίλ.",
|
"hints.profiles.followers_may_be_missing": "Μπορεί να λείπουν ακόλουθοι για αυτό το προφίλ.",
|
||||||
"hints.profiles.follows_may_be_missing": "Άτομα που ακολουθούνται μπορεί να λείπουν απ' αυτό το προφίλ.",
|
"hints.profiles.follows_may_be_missing": "Άτομα που ακολουθούνται μπορεί να λείπουν απ' αυτό το προφίλ.",
|
||||||
"hints.profiles.posts_may_be_missing": "Κάποιες αναρτήσεις από αυτό το προφίλ μπορεί να λείπουν.",
|
"hints.profiles.posts_may_be_missing": "Κάποιες αναρτήσεις από αυτό το προφίλ μπορεί να λείπουν.",
|
||||||
|
@ -420,7 +425,7 @@
|
||||||
"hints.profiles.see_more_follows": "Δες περισσότερα άτομα που ακολουθούνται στο {domain}",
|
"hints.profiles.see_more_follows": "Δες περισσότερα άτομα που ακολουθούνται στο {domain}",
|
||||||
"hints.profiles.see_more_posts": "Δες περισσότερες αναρτήσεις στο {domain}",
|
"hints.profiles.see_more_posts": "Δες περισσότερες αναρτήσεις στο {domain}",
|
||||||
"hints.threads.replies_may_be_missing": "Απαντήσεις από άλλους διακομιστές μπορεί να λείπουν.",
|
"hints.threads.replies_may_be_missing": "Απαντήσεις από άλλους διακομιστές μπορεί να λείπουν.",
|
||||||
"hints.threads.see_more": "Δες περισσότερες αναρτήσεις στο {domain}",
|
"hints.threads.see_more": "Δες περισσότερες απαντήσεις στο {domain}",
|
||||||
"home.column_settings.show_quotes": "Εμφάνιση παραθεμάτων",
|
"home.column_settings.show_quotes": "Εμφάνιση παραθεμάτων",
|
||||||
"home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
|
"home.column_settings.show_reblogs": "Εμφάνιση προωθήσεων",
|
||||||
"home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
|
"home.column_settings.show_replies": "Εμφάνιση απαντήσεων",
|
||||||
|
@ -451,7 +456,7 @@
|
||||||
"interaction_modal.no_account_yet": "Δεν έχεις ακόμη λογαριασμό;",
|
"interaction_modal.no_account_yet": "Δεν έχεις ακόμη λογαριασμό;",
|
||||||
"interaction_modal.on_another_server": "Σε διαφορετικό διακομιστή",
|
"interaction_modal.on_another_server": "Σε διαφορετικό διακομιστή",
|
||||||
"interaction_modal.on_this_server": "Σε αυτόν τον διακομιστή",
|
"interaction_modal.on_this_server": "Σε αυτόν τον διακομιστή",
|
||||||
"interaction_modal.title.favourite": "Favorite {name}'s post\nΠροτίμησε την ανάρτηση της/του {name}",
|
"interaction_modal.title.favourite": "Αγάπησε την ανάρτηση του χρήστη {name}",
|
||||||
"interaction_modal.title.follow": "Ακολούθησε {name}",
|
"interaction_modal.title.follow": "Ακολούθησε {name}",
|
||||||
"interaction_modal.title.reblog": "Ενίσχυσε την ανάρτηση του {name}",
|
"interaction_modal.title.reblog": "Ενίσχυσε την ανάρτηση του {name}",
|
||||||
"interaction_modal.title.reply": "Απάντηση στην ανάρτηση του {name}",
|
"interaction_modal.title.reply": "Απάντηση στην ανάρτηση του {name}",
|
||||||
|
@ -463,13 +468,13 @@
|
||||||
"keyboard_shortcuts.back": "Μετάβαση πίσω",
|
"keyboard_shortcuts.back": "Μετάβαση πίσω",
|
||||||
"keyboard_shortcuts.blocked": "Άνοιγμα λίστας αποκλεισμένων χρηστών",
|
"keyboard_shortcuts.blocked": "Άνοιγμα λίστας αποκλεισμένων χρηστών",
|
||||||
"keyboard_shortcuts.boost": "Ενίσχυση ανάρτησης",
|
"keyboard_shortcuts.boost": "Ενίσχυση ανάρτησης",
|
||||||
"keyboard_shortcuts.column": "Στήλη εστίασης",
|
"keyboard_shortcuts.column": "Εστίαση στη στήλη",
|
||||||
"keyboard_shortcuts.compose": "Περιοχή συγγραφής κειμένου εστίασης",
|
"keyboard_shortcuts.compose": "Εστίαση στην περιοχή συγγραφής κειμένου",
|
||||||
"keyboard_shortcuts.description": "Περιγραφή",
|
"keyboard_shortcuts.description": "Περιγραφή",
|
||||||
"keyboard_shortcuts.direct": "για το άνοιγμα της στήλης ιδιωτικών επισημάνσεων",
|
"keyboard_shortcuts.direct": "για το άνοιγμα της στήλης ιδιωτικών επισημάνσεων",
|
||||||
"keyboard_shortcuts.down": "κίνηση προς τα κάτω στη λίστα",
|
"keyboard_shortcuts.down": "Μετακίνηση προς τα κάτω στη λίστα",
|
||||||
"keyboard_shortcuts.enter": "Εμφάνιση ανάρτησης",
|
"keyboard_shortcuts.enter": "Άνοιγμα ανάρτησης",
|
||||||
"keyboard_shortcuts.favourite": "Αγαπημένη δημοσίευση",
|
"keyboard_shortcuts.favourite": "Αγάπησε την ανάρτηση",
|
||||||
"keyboard_shortcuts.favourites": "Άνοιγμα λίστας αγαπημένων",
|
"keyboard_shortcuts.favourites": "Άνοιγμα λίστας αγαπημένων",
|
||||||
"keyboard_shortcuts.federated": "Άνοιγμα ροής συναλλαγών",
|
"keyboard_shortcuts.federated": "Άνοιγμα ροής συναλλαγών",
|
||||||
"keyboard_shortcuts.heading": "Συντομεύσεις πληκτρολογίου",
|
"keyboard_shortcuts.heading": "Συντομεύσεις πληκτρολογίου",
|
||||||
|
@ -486,13 +491,13 @@
|
||||||
"keyboard_shortcuts.profile": "Άνοιγμα προφίλ συγγραφέα",
|
"keyboard_shortcuts.profile": "Άνοιγμα προφίλ συγγραφέα",
|
||||||
"keyboard_shortcuts.reply": "Απάντηση στην ανάρτηση",
|
"keyboard_shortcuts.reply": "Απάντηση στην ανάρτηση",
|
||||||
"keyboard_shortcuts.requests": "Άνοιγμα λίστας αιτημάτων ακολούθησης",
|
"keyboard_shortcuts.requests": "Άνοιγμα λίστας αιτημάτων ακολούθησης",
|
||||||
"keyboard_shortcuts.search": "Γραμμή αναζήτησης εστίασης",
|
"keyboard_shortcuts.search": "Εστίαση στη γραμμή αναζήτησης",
|
||||||
"keyboard_shortcuts.spoilers": "Εμφάνιση/απόκρυψη πεδίου CW",
|
"keyboard_shortcuts.spoilers": "Εμφάνιση/απόκρυψη πεδίου CW",
|
||||||
"keyboard_shortcuts.start": "Άνοιγμα της στήλης \"Ας ξεκινήσουμε\"",
|
"keyboard_shortcuts.start": "Άνοιγμα της στήλης \"Ας ξεκινήσουμε\"",
|
||||||
"keyboard_shortcuts.toggle_hidden": "Εμφάνιση/απόκρυψη κειμένου πίσω από το CW",
|
"keyboard_shortcuts.toggle_hidden": "Εμφάνιση/απόκρυψη κειμένου πίσω από το CW",
|
||||||
"keyboard_shortcuts.toggle_sensitivity": "Εμφάνιση/απόκρυψη πολυμέσων",
|
"keyboard_shortcuts.toggle_sensitivity": "Εμφάνιση/απόκρυψη πολυμέσων",
|
||||||
"keyboard_shortcuts.toot": "Δημιουργία νέας ανάρτησης",
|
"keyboard_shortcuts.toot": "Δημιουργία νέας ανάρτησης",
|
||||||
"keyboard_shortcuts.translate": "να μεταφράσει μια δημοσίευση",
|
"keyboard_shortcuts.translate": "για να μεταφραστεί μια ανάρτηση",
|
||||||
"keyboard_shortcuts.unfocus": "Αποεστίαση του πεδίου σύνθεσης/αναζήτησης",
|
"keyboard_shortcuts.unfocus": "Αποεστίαση του πεδίου σύνθεσης/αναζήτησης",
|
||||||
"keyboard_shortcuts.up": "Μετακίνηση προς τα πάνω στη λίστα",
|
"keyboard_shortcuts.up": "Μετακίνηση προς τα πάνω στη λίστα",
|
||||||
"lightbox.close": "Κλείσιμο",
|
"lightbox.close": "Κλείσιμο",
|
||||||
|
@ -555,10 +560,12 @@
|
||||||
"navigation_bar.favourites": "Αγαπημένα",
|
"navigation_bar.favourites": "Αγαπημένα",
|
||||||
"navigation_bar.filters": "Αποσιωπημένες λέξεις",
|
"navigation_bar.filters": "Αποσιωπημένες λέξεις",
|
||||||
"navigation_bar.follow_requests": "Αιτήματα ακολούθησης",
|
"navigation_bar.follow_requests": "Αιτήματα ακολούθησης",
|
||||||
"navigation_bar.followed_tags": "Ετικέτες που ακολουθούνται",
|
"navigation_bar.followed_tags": "Ακολουθούμενες ετικέτες",
|
||||||
"navigation_bar.follows_and_followers": "Ακολουθείς και σε ακολουθούν",
|
"navigation_bar.follows_and_followers": "Ακολουθείς και σε ακολουθούν",
|
||||||
"navigation_bar.import_export": "Εισαγωγή και εξαγωγή",
|
"navigation_bar.import_export": "Εισαγωγή και εξαγωγή",
|
||||||
"navigation_bar.lists": "Λίστες",
|
"navigation_bar.lists": "Λίστες",
|
||||||
|
"navigation_bar.live_feed_local": "Ζωντανή ροή (τοπική)",
|
||||||
|
"navigation_bar.live_feed_public": "Ζωντανή ροή (δημόσια)",
|
||||||
"navigation_bar.logout": "Αποσύνδεση",
|
"navigation_bar.logout": "Αποσύνδεση",
|
||||||
"navigation_bar.moderation": "Συντονισμός",
|
"navigation_bar.moderation": "Συντονισμός",
|
||||||
"navigation_bar.more": "Περισσότερα",
|
"navigation_bar.more": "Περισσότερα",
|
||||||
|
@ -568,9 +575,9 @@
|
||||||
"navigation_bar.privacy_and_reach": "Ιδιωτικότητα και προσιτότητα",
|
"navigation_bar.privacy_and_reach": "Ιδιωτικότητα και προσιτότητα",
|
||||||
"navigation_bar.search": "Αναζήτηση",
|
"navigation_bar.search": "Αναζήτηση",
|
||||||
"navigation_bar.search_trends": "Αναζήτηση / Τάσεις",
|
"navigation_bar.search_trends": "Αναζήτηση / Τάσεις",
|
||||||
"navigation_panel.collapse_followed_tags": "Σύμπτυξη μενού ετικετών που ακολουθούνται",
|
"navigation_panel.collapse_followed_tags": "Σύμπτυξη μενού ετικετών που ακολουθείτε",
|
||||||
"navigation_panel.collapse_lists": "Σύμπτυξη μενού λίστας",
|
"navigation_panel.collapse_lists": "Σύμπτυξη μενού λίστας",
|
||||||
"navigation_panel.expand_followed_tags": "Επέκταση μενού ετικετών που ακολουθούνται",
|
"navigation_panel.expand_followed_tags": "Επέκταση μενού ετικετών που ακολουθείτε",
|
||||||
"navigation_panel.expand_lists": "Επέκταση μενού λίστας",
|
"navigation_panel.expand_lists": "Επέκταση μενού λίστας",
|
||||||
"not_signed_in_indicator.not_signed_in": "Πρέπει να συνδεθείς για να αποκτήσεις πρόσβαση σε αυτόν τον πόρο.",
|
"not_signed_in_indicator.not_signed_in": "Πρέπει να συνδεθείς για να αποκτήσεις πρόσβαση σε αυτόν τον πόρο.",
|
||||||
"notification.admin.report": "Ο/Η {name} ανέφερε τον {target}",
|
"notification.admin.report": "Ο/Η {name} ανέφερε τον {target}",
|
||||||
|
@ -582,11 +589,11 @@
|
||||||
"notification.admin.sign_up.name_and_others": "{name} και {count, plural, one {# ακόμη} other {# ακόμη}} έχουν εγγραφεί",
|
"notification.admin.sign_up.name_and_others": "{name} και {count, plural, one {# ακόμη} other {# ακόμη}} έχουν εγγραφεί",
|
||||||
"notification.annual_report.message": "Το #Wrapstodon {year} σε περιμένει! Αποκάλυψε τα στιγμιότυπα της χρονιάς και αξέχαστες στιγμές σου στο Mastodon!",
|
"notification.annual_report.message": "Το #Wrapstodon {year} σε περιμένει! Αποκάλυψε τα στιγμιότυπα της χρονιάς και αξέχαστες στιγμές σου στο Mastodon!",
|
||||||
"notification.annual_report.view": "Προβολή #Wrapstodon",
|
"notification.annual_report.view": "Προβολή #Wrapstodon",
|
||||||
"notification.favourite": "{name} favorited your post\n{name} προτίμησε την ανάρτηση σου",
|
"notification.favourite": "{name} αγάπησε την ανάρτηση σου",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
"notification.favourite.name_and_others_with_link": "{name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ανάρτησή σου",
|
||||||
"notification.favourite_pm": "Ο χρήστης {name} αγάπησε την ιδιωτική σου επισήμανση",
|
"notification.favourite_pm": "Ο χρήστης {name} αγάπησε την ιδιωτική σου επισήμανση",
|
||||||
"notification.favourite_pm.name_and_others_with_link": "Ο χρήστης {name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ιδωτική σου επισήμανση",
|
"notification.favourite_pm.name_and_others_with_link": "Ο χρήστης {name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> αγάπησαν την ιδωτική σου επισήμανση",
|
||||||
"notification.follow": "Ο/Η {name} σε ακολούθησε",
|
"notification.follow": "Ο χρήστης {name} σε ακολούθησε",
|
||||||
"notification.follow.name_and_others": "Ο χρήστης {name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> σε ακολούθησαν",
|
"notification.follow.name_and_others": "Ο χρήστης {name} και <a>{count, plural, one {# ακόμη} other {# ακόμη}}</a> σε ακολούθησαν",
|
||||||
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
"notification.follow_request": "Ο/H {name} ζήτησε να σε ακολουθήσει",
|
||||||
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
"notification.follow_request.name_and_others": "{name} και {count, plural, one {# άλλος} other {# άλλοι}} ζήτησαν να σε ακολουθήσουν",
|
||||||
|
@ -719,7 +726,7 @@
|
||||||
"poll_button.add_poll": "Προσθήκη δημοσκόπησης",
|
"poll_button.add_poll": "Προσθήκη δημοσκόπησης",
|
||||||
"poll_button.remove_poll": "Αφαίρεση δημοσκόπησης",
|
"poll_button.remove_poll": "Αφαίρεση δημοσκόπησης",
|
||||||
"privacy.change": "Προσαρμογή ιδιωτικότητας ανάρτησης",
|
"privacy.change": "Προσαρμογή ιδιωτικότητας ανάρτησης",
|
||||||
"privacy.direct.long": "Όλοι όσοι αναφέρθηκαν στη δημοσίευση",
|
"privacy.direct.long": "Όλοι όσοι αναφέρθηκαν στην ανάρτηση",
|
||||||
"privacy.direct.short": "Ιδιωτική επισήμανση",
|
"privacy.direct.short": "Ιδιωτική επισήμανση",
|
||||||
"privacy.private.long": "Μόνο οι ακόλουθοί σας",
|
"privacy.private.long": "Μόνο οι ακόλουθοί σας",
|
||||||
"privacy.private.short": "Ακόλουθοι",
|
"privacy.private.short": "Ακόλουθοι",
|
||||||
|
@ -797,7 +804,7 @@
|
||||||
"report_notification.categories.spam_sentence": "ανεπιθύμητα",
|
"report_notification.categories.spam_sentence": "ανεπιθύμητα",
|
||||||
"report_notification.categories.violation": "Παραβίαση κανόνα",
|
"report_notification.categories.violation": "Παραβίαση κανόνα",
|
||||||
"report_notification.categories.violation_sentence": "παραβίαση κανόνα",
|
"report_notification.categories.violation_sentence": "παραβίαση κανόνα",
|
||||||
"report_notification.open": "Ανοιχτή αναφορά",
|
"report_notification.open": "Άνοιγμα αναφοράς",
|
||||||
"search.clear": "Εκκαθάριση αναζήτησης",
|
"search.clear": "Εκκαθάριση αναζήτησης",
|
||||||
"search.no_recent_searches": "Καμία πρόσφατη αναζήτηση",
|
"search.no_recent_searches": "Καμία πρόσφατη αναζήτηση",
|
||||||
"search.placeholder": "Αναζήτηση",
|
"search.placeholder": "Αναζήτηση",
|
||||||
|
@ -851,7 +858,7 @@
|
||||||
"status.edited_x_times": "Επεξεργάστηκε {count, plural, one {{count} φορά} other {{count} φορές}}",
|
"status.edited_x_times": "Επεξεργάστηκε {count, plural, one {{count} φορά} other {{count} φορές}}",
|
||||||
"status.embed": "Απόκτηση κώδικα ενσωμάτωσης",
|
"status.embed": "Απόκτηση κώδικα ενσωμάτωσης",
|
||||||
"status.favourite": "Αγαπημένα",
|
"status.favourite": "Αγαπημένα",
|
||||||
"status.favourites": "{count, plural, one {# αγαπημένο} other {# αγαπημένα}}",
|
"status.favourites": "{count, plural, one {αγαπημένο} other {αγαπημένα}}",
|
||||||
"status.filter": "Φιλτράρισμα αυτής της ανάρτησης",
|
"status.filter": "Φιλτράρισμα αυτής της ανάρτησης",
|
||||||
"status.history.created": "{name} δημιούργησε στις {date}",
|
"status.history.created": "{name} δημιούργησε στις {date}",
|
||||||
"status.history.edited": "{name} επεξεργάστηκε στις {date}",
|
"status.history.edited": "{name} επεξεργάστηκε στις {date}",
|
||||||
|
@ -876,7 +883,7 @@
|
||||||
"status.reblog": "Ενίσχυση",
|
"status.reblog": "Ενίσχυση",
|
||||||
"status.reblog_private": "Ενίσχυση με αρχική ορατότητα",
|
"status.reblog_private": "Ενίσχυση με αρχική ορατότητα",
|
||||||
"status.reblogged_by": "{name} προώθησε",
|
"status.reblogged_by": "{name} προώθησε",
|
||||||
"status.reblogs": "{count, plural, one {# ενίσχυση} other {# ενισχύσεις}}",
|
"status.reblogs": "{count, plural, one {ενίσχυση} other {ενισχύσεις}}",
|
||||||
"status.reblogs.empty": "Κανείς δεν ενίσχυσε αυτή την ανάρτηση ακόμα. Μόλις το κάνει κάποιος, θα εμφανιστεί εδώ.",
|
"status.reblogs.empty": "Κανείς δεν ενίσχυσε αυτή την ανάρτηση ακόμα. Μόλις το κάνει κάποιος, θα εμφανιστεί εδώ.",
|
||||||
"status.redraft": "Σβήσε & ξαναγράψε",
|
"status.redraft": "Σβήσε & ξαναγράψε",
|
||||||
"status.remove_bookmark": "Αφαίρεση σελιδοδείκτη",
|
"status.remove_bookmark": "Αφαίρεση σελιδοδείκτη",
|
||||||
|
@ -888,8 +895,8 @@
|
||||||
"status.report": "Αναφορά @{name}",
|
"status.report": "Αναφορά @{name}",
|
||||||
"status.sensitive_warning": "Ευαίσθητο περιεχόμενο",
|
"status.sensitive_warning": "Ευαίσθητο περιεχόμενο",
|
||||||
"status.share": "Κοινοποίηση",
|
"status.share": "Κοινοποίηση",
|
||||||
"status.show_less_all": "Δείξε λιγότερα για όλα",
|
"status.show_less_all": "Δείξε λιγότερο για όλες",
|
||||||
"status.show_more_all": "Δείξε περισσότερα για όλα",
|
"status.show_more_all": "Δείξε περισσότερο για όλες",
|
||||||
"status.show_original": "Εμφάνιση αρχικού",
|
"status.show_original": "Εμφάνιση αρχικού",
|
||||||
"status.title.with_attachments": "{user} δημοσίευσε {attachmentCount, plural, one {ένα συνημμένο} other {{attachmentCount} συνημμένα}}",
|
"status.title.with_attachments": "{user} δημοσίευσε {attachmentCount, plural, one {ένα συνημμένο} other {{attachmentCount} συνημμένα}}",
|
||||||
"status.translate": "Μετάφραση",
|
"status.translate": "Μετάφραση",
|
||||||
|
|
|
@ -219,6 +219,13 @@
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||||
"confirmations.delete_list.title": "Delete list?",
|
"confirmations.delete_list.title": "Delete list?",
|
||||||
|
"confirmations.discard_draft.confirm": "Discard and continue",
|
||||||
|
"confirmations.discard_draft.edit.cancel": "Resume editing",
|
||||||
|
"confirmations.discard_draft.edit.message": "Continuing will discard any changes you have made to the post you are currently editing.",
|
||||||
|
"confirmations.discard_draft.edit.title": "Discard changes to your post?",
|
||||||
|
"confirmations.discard_draft.post.cancel": "Resume draft",
|
||||||
|
"confirmations.discard_draft.post.message": "Continuing will discard the post you are currently composing.",
|
||||||
|
"confirmations.discard_draft.post.title": "Discard your draft post?",
|
||||||
"confirmations.discard_edit_media.confirm": "Discard",
|
"confirmations.discard_edit_media.confirm": "Discard",
|
||||||
"confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
|
"confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
|
||||||
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
||||||
|
@ -330,6 +337,7 @@
|
||||||
"errors.unexpected_crash.copy_stacktrace": "Copy stacktrace to clipboard",
|
"errors.unexpected_crash.copy_stacktrace": "Copy stacktrace to clipboard",
|
||||||
"errors.unexpected_crash.report_issue": "Report issue",
|
"errors.unexpected_crash.report_issue": "Report issue",
|
||||||
"explore.suggested_follows": "People",
|
"explore.suggested_follows": "People",
|
||||||
|
"explore.title": "Trending",
|
||||||
"explore.trending_links": "News",
|
"explore.trending_links": "News",
|
||||||
"explore.trending_statuses": "Posts",
|
"explore.trending_statuses": "Posts",
|
||||||
"explore.trending_tags": "Hashtags",
|
"explore.trending_tags": "Hashtags",
|
||||||
|
@ -541,8 +549,10 @@
|
||||||
"mute_modal.you_wont_see_mentions": "You won't see posts that mention them.",
|
"mute_modal.you_wont_see_mentions": "You won't see posts that mention them.",
|
||||||
"mute_modal.you_wont_see_posts": "They can still see your posts, but you won't see theirs.",
|
"mute_modal.you_wont_see_posts": "They can still see your posts, but you won't see theirs.",
|
||||||
"navigation_bar.about": "About",
|
"navigation_bar.about": "About",
|
||||||
|
"navigation_bar.account_settings": "Password and security",
|
||||||
"navigation_bar.administration": "Administration",
|
"navigation_bar.administration": "Administration",
|
||||||
"navigation_bar.advanced_interface": "Open in advanced web interface",
|
"navigation_bar.advanced_interface": "Open in advanced web interface",
|
||||||
|
"navigation_bar.automated_deletion": "Automated post deletion",
|
||||||
"navigation_bar.blocks": "Blocked users",
|
"navigation_bar.blocks": "Blocked users",
|
||||||
"navigation_bar.bookmarks": "Bookmarks",
|
"navigation_bar.bookmarks": "Bookmarks",
|
||||||
"navigation_bar.direct": "Private mentions",
|
"navigation_bar.direct": "Private mentions",
|
||||||
|
@ -552,13 +562,23 @@
|
||||||
"navigation_bar.follow_requests": "Follow requests",
|
"navigation_bar.follow_requests": "Follow requests",
|
||||||
"navigation_bar.followed_tags": "Followed hashtags",
|
"navigation_bar.followed_tags": "Followed hashtags",
|
||||||
"navigation_bar.follows_and_followers": "Follows and followers",
|
"navigation_bar.follows_and_followers": "Follows and followers",
|
||||||
|
"navigation_bar.import_export": "Import and export",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "Lists",
|
||||||
|
"navigation_bar.live_feed_local": "Live feed (local)",
|
||||||
|
"navigation_bar.live_feed_public": "Live feed (public)",
|
||||||
"navigation_bar.logout": "Logout",
|
"navigation_bar.logout": "Logout",
|
||||||
"navigation_bar.moderation": "Moderation",
|
"navigation_bar.moderation": "Moderation",
|
||||||
|
"navigation_bar.more": "More",
|
||||||
"navigation_bar.mutes": "Muted users",
|
"navigation_bar.mutes": "Muted users",
|
||||||
"navigation_bar.opened_in_classic_interface": "Posts, accounts, and other specific pages are opened by default in the classic web interface.",
|
"navigation_bar.opened_in_classic_interface": "Posts, accounts, and other specific pages are opened by default in the classic web interface.",
|
||||||
"navigation_bar.preferences": "Preferences",
|
"navigation_bar.preferences": "Preferences",
|
||||||
|
"navigation_bar.privacy_and_reach": "Privacy and reach",
|
||||||
"navigation_bar.search": "Search",
|
"navigation_bar.search": "Search",
|
||||||
|
"navigation_bar.search_trends": "Search / Trending",
|
||||||
|
"navigation_panel.collapse_followed_tags": "Collapse followed hashtags menu",
|
||||||
|
"navigation_panel.collapse_lists": "Collapse list menu",
|
||||||
|
"navigation_panel.expand_followed_tags": "Expand followed hashtags menu",
|
||||||
|
"navigation_panel.expand_lists": "Expand list menu",
|
||||||
"not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
|
"not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
|
||||||
"notification.admin.report": "{name} reported {target}",
|
"notification.admin.report": "{name} reported {target}",
|
||||||
"notification.admin.report_account": "{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}",
|
"notification.admin.report_account": "{name} reported {count, plural, one {one post} other {# posts}} from {target} for {category}",
|
||||||
|
@ -785,6 +805,7 @@
|
||||||
"report_notification.categories.violation": "Rule violation",
|
"report_notification.categories.violation": "Rule violation",
|
||||||
"report_notification.categories.violation_sentence": "rule violation",
|
"report_notification.categories.violation_sentence": "rule violation",
|
||||||
"report_notification.open": "Open report",
|
"report_notification.open": "Open report",
|
||||||
|
"search.clear": "Clear search",
|
||||||
"search.no_recent_searches": "No recent searches",
|
"search.no_recent_searches": "No recent searches",
|
||||||
"search.placeholder": "Search",
|
"search.placeholder": "Search",
|
||||||
"search.quick_action.account_search": "Profiles matching {x}",
|
"search.quick_action.account_search": "Profiles matching {x}",
|
||||||
|
@ -887,7 +908,10 @@
|
||||||
"subscribed_languages.save": "Save changes",
|
"subscribed_languages.save": "Save changes",
|
||||||
"subscribed_languages.target": "Change subscribed languages for {target}",
|
"subscribed_languages.target": "Change subscribed languages for {target}",
|
||||||
"tabs_bar.home": "Home",
|
"tabs_bar.home": "Home",
|
||||||
|
"tabs_bar.menu": "Menu",
|
||||||
"tabs_bar.notifications": "Notifications",
|
"tabs_bar.notifications": "Notifications",
|
||||||
|
"tabs_bar.publish": "New Post",
|
||||||
|
"tabs_bar.search": "Search",
|
||||||
"terms_of_service.effective_as_of": "Effective as of {date}",
|
"terms_of_service.effective_as_of": "Effective as of {date}",
|
||||||
"terms_of_service.title": "Terms of Service",
|
"terms_of_service.title": "Terms of Service",
|
||||||
"terms_of_service.upcoming_changes_on": "Upcoming changes on {date}",
|
"terms_of_service.upcoming_changes_on": "Upcoming changes on {date}",
|
||||||
|
|
|
@ -564,8 +564,8 @@
|
||||||
"navigation_bar.follows_and_followers": "Cuentas seguidas y seguidores",
|
"navigation_bar.follows_and_followers": "Cuentas seguidas y seguidores",
|
||||||
"navigation_bar.import_export": "Importación y exportación",
|
"navigation_bar.import_export": "Importación y exportación",
|
||||||
"navigation_bar.lists": "Listas",
|
"navigation_bar.lists": "Listas",
|
||||||
"navigation_bar.live_feed_local": "Cronología local",
|
"navigation_bar.live_feed_local": "Línea temporal (local)",
|
||||||
"navigation_bar.live_feed_public": "Cronología pública",
|
"navigation_bar.live_feed_public": "Línea temporal (federada)",
|
||||||
"navigation_bar.logout": "Cerrar sesión",
|
"navigation_bar.logout": "Cerrar sesión",
|
||||||
"navigation_bar.moderation": "Moderación",
|
"navigation_bar.moderation": "Moderación",
|
||||||
"navigation_bar.more": "Más",
|
"navigation_bar.more": "Más",
|
||||||
|
@ -858,7 +858,7 @@
|
||||||
"status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
|
"status.edited_x_times": "Editado {count, plural, one {{count} vez} other {{count} veces}}",
|
||||||
"status.embed": "Obtener código para insertar",
|
"status.embed": "Obtener código para insertar",
|
||||||
"status.favourite": "Marcar como favorito",
|
"status.favourite": "Marcar como favorito",
|
||||||
"status.favourites": "{count, plural, one {# vez marcado como favorito} other {# veces marcado como favorito}}",
|
"status.favourites": "{count, plural, one {vez marcado como favorito} other {veces marcado como favorito}}",
|
||||||
"status.filter": "Filtrar este mensaje",
|
"status.filter": "Filtrar este mensaje",
|
||||||
"status.history.created": "Creado por {name}, {date}",
|
"status.history.created": "Creado por {name}, {date}",
|
||||||
"status.history.edited": "Editado por {name}, {date}",
|
"status.history.edited": "Editado por {name}, {date}",
|
||||||
|
|
|
@ -795,7 +795,7 @@
|
||||||
"report.thanks.title_actionable": "Gracias por informar, estudiaremos esto.",
|
"report.thanks.title_actionable": "Gracias por informar, estudiaremos esto.",
|
||||||
"report.unfollow": "Dejar de seguir a @{name}",
|
"report.unfollow": "Dejar de seguir a @{name}",
|
||||||
"report.unfollow_explanation": "Estás siguiendo esta cuenta. Para dejar de ver sus publicaciones en tu página de inicio, deja de seguirla.",
|
"report.unfollow_explanation": "Estás siguiendo esta cuenta. Para dejar de ver sus publicaciones en tu página de inicio, deja de seguirla.",
|
||||||
"report_notification.attached_statuses": "{count, plural, one {{count} publicación} other {{count} publicaciones}} adjunta(s)",
|
"report_notification.attached_statuses": "{count, plural, one {{count} publicación adjunta} other {{count} publicaciones adjuntas}}",
|
||||||
"report_notification.categories.legal": "Legal",
|
"report_notification.categories.legal": "Legal",
|
||||||
"report_notification.categories.legal_sentence": "contenido ilegal",
|
"report_notification.categories.legal_sentence": "contenido ilegal",
|
||||||
"report_notification.categories.other": "Otros",
|
"report_notification.categories.other": "Otros",
|
||||||
|
|
|
@ -569,6 +569,7 @@
|
||||||
"notification.admin.sign_up.name_and_others": "{name} eta {count, plural, one {erabiltzaile # gehiago} other {# erabiltzaile gehiago}} erregistratu dira",
|
"notification.admin.sign_up.name_and_others": "{name} eta {count, plural, one {erabiltzaile # gehiago} other {# erabiltzaile gehiago}} erregistratu dira",
|
||||||
"notification.favourite": "{name}(e)k zure bidalketa gogoko du",
|
"notification.favourite": "{name}(e)k zure bidalketa gogoko du",
|
||||||
"notification.favourite.name_and_others_with_link": "{name} eta <a>{count, plural, one {erabiltzaile # gehiagok} other {# erabiltzaile gehiagok}}</a> zure bidalketa gogoko dute",
|
"notification.favourite.name_and_others_with_link": "{name} eta <a>{count, plural, one {erabiltzaile # gehiagok} other {# erabiltzaile gehiagok}}</a> zure bidalketa gogoko dute",
|
||||||
|
"notification.favourite_pm": "{name}-ek zure aipamen pribatua gogokoetan jarri du",
|
||||||
"notification.follow": "{name}(e)k jarraitzen dizu",
|
"notification.follow": "{name}(e)k jarraitzen dizu",
|
||||||
"notification.follow_request": "{name}(e)k zu jarraitzeko eskaera egin du",
|
"notification.follow_request": "{name}(e)k zu jarraitzeko eskaera egin du",
|
||||||
"notification.follow_request.name_and_others": "{name} eta {count, plural, one {erabiltzaile # gehiagok} other {# erabiltzaile gehiagok}} zu jarraitzeko eskaera egin dute",
|
"notification.follow_request.name_and_others": "{name} eta {count, plural, one {erabiltzaile # gehiagok} other {# erabiltzaile gehiagok}} zu jarraitzeko eskaera egin dute",
|
||||||
|
@ -902,5 +903,7 @@
|
||||||
"video.hide": "Ezkutatu bideoa",
|
"video.hide": "Ezkutatu bideoa",
|
||||||
"video.pause": "Pausatu",
|
"video.pause": "Pausatu",
|
||||||
"video.play": "Jo",
|
"video.play": "Jo",
|
||||||
|
"video.unmute": "Soinua ezarri",
|
||||||
|
"video.volume_down": "Bolumena jaitsi",
|
||||||
"video.volume_up": "Bolumena Igo"
|
"video.volume_up": "Bolumena Igo"
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
"account.mute_notifications_short": "خموشی آگاهیها",
|
"account.mute_notifications_short": "خموشی آگاهیها",
|
||||||
"account.mute_short": "خموشی",
|
"account.mute_short": "خموشی",
|
||||||
"account.muted": "خموش",
|
"account.muted": "خموش",
|
||||||
"account.muting": "خموش کرده",
|
"account.muting": "خموشش کردهاید",
|
||||||
"account.mutual": "یکدیگر را پی میگیرید",
|
"account.mutual": "یکدیگر را پی میگیرید",
|
||||||
"account.no_bio": "شرحی فراهم نشده.",
|
"account.no_bio": "شرحی فراهم نشده.",
|
||||||
"account.open_original_page": "گشودن صفحهٔ اصلی",
|
"account.open_original_page": "گشودن صفحهٔ اصلی",
|
||||||
|
@ -129,14 +129,14 @@
|
||||||
"annual_report.summary.thanks": "سپاس که بخشی از ماستودون هستید!",
|
"annual_report.summary.thanks": "سپاس که بخشی از ماستودون هستید!",
|
||||||
"attachments_list.unprocessed": "(پردازش نشده)",
|
"attachments_list.unprocessed": "(پردازش نشده)",
|
||||||
"audio.hide": "نهفتن صدا",
|
"audio.hide": "نهفتن صدا",
|
||||||
"block_modal.remote_users_caveat": "ما از کارساز {domain} خواهیم خواست که به تصمیم شما احترام بگذارد. با این حال، تضمینی برای رعایت آن وجود ندارد زیرا برخی کارسازها ممکن است بلوکها را بهطور متفاوتی مدیریت کنند. فرستههای عمومی ممکن است همچنان برای کاربران که وارد نشده قابل مشاهده باشند.",
|
"block_modal.remote_users_caveat": "از کارساز {domain} خواهیم خواست که به تصمیمتان احترام بگذارد. با این حال تضمینی برای رعایتش وجود ندارد؛ زیرا برخی کارسازها ممکن است مسدودی را متفاوت مدیریت کنند. ممکن است فرستههای عمومی همچنان برای کاربران وارد نشده نمایان باشند.",
|
||||||
"block_modal.show_less": "نمایش کمتر",
|
"block_modal.show_less": "نمایش کمتر",
|
||||||
"block_modal.show_more": "نمایش بیشتر",
|
"block_modal.show_more": "نمایش بیشتر",
|
||||||
"block_modal.they_cant_mention": "نمیتوانند نامتان را برده یا پیتان بگیرند.",
|
"block_modal.they_cant_mention": "نمیتواند نامتان را برده یا پیتان بگیرد.",
|
||||||
"block_modal.they_cant_see_posts": "نمیتوانند فرستههایتان را دیده و فرستههایشان را نمیبینید.",
|
"block_modal.they_cant_see_posts": "نمیتواند فرستههایتان را ببیند و فرستههایش را نمیبینید.",
|
||||||
"block_modal.they_will_know": "میتوانند ببینند که مسدود شدهاند.",
|
"block_modal.they_will_know": "میتواند ببینند که مسدود شده.",
|
||||||
"block_modal.title": "انسداد کاربر؟",
|
"block_modal.title": "انسداد کاربر؟",
|
||||||
"block_modal.you_wont_see_mentions": "فرستههایی که از اون نام برده را نخواهید دید.",
|
"block_modal.you_wont_see_mentions": "فرستههایی که به او اشاره کردهاند را نخواهید دید.",
|
||||||
"boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید",
|
"boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید",
|
||||||
"boost_modal.reblog": "تقویت فرسته؟",
|
"boost_modal.reblog": "تقویت فرسته؟",
|
||||||
"boost_modal.undo_reblog": "ناتقویت فرسته؟",
|
"boost_modal.undo_reblog": "ناتقویت فرسته؟",
|
||||||
|
@ -269,9 +269,9 @@
|
||||||
"dismissable_banner.public_timeline": "اینها جدیدترین فرستههای عمومی از افرادی روی وب اجتماعیند که اعضای {domain} پی میگیرندشان.",
|
"dismissable_banner.public_timeline": "اینها جدیدترین فرستههای عمومی از افرادی روی وب اجتماعیند که اعضای {domain} پی میگیرندشان.",
|
||||||
"domain_block_modal.block": "انسداد کارساز",
|
"domain_block_modal.block": "انسداد کارساز",
|
||||||
"domain_block_modal.block_account_instead": "انسداد @{name} به جایش",
|
"domain_block_modal.block_account_instead": "انسداد @{name} به جایش",
|
||||||
"domain_block_modal.they_can_interact_with_old_posts": "افزارد روی این کراساز میتوانند با فرستههای قدیمیتان تعامل داشته باشند.",
|
"domain_block_modal.they_can_interact_with_old_posts": "افزارد روی این کارساز میتوانند با فرستههای قدیمیتان تعامل داشته باشند.",
|
||||||
"domain_block_modal.they_cant_follow": "هیچکسی از این کارساز نمیتواند پیتان بگیرد.",
|
"domain_block_modal.they_cant_follow": "هیچکسی از این کارساز نمیتواند پیتان بگیرد.",
|
||||||
"domain_block_modal.they_wont_know": "نخواهند دانست که مسدود شدهاند.",
|
"domain_block_modal.they_wont_know": "نخواهد دانست که مسدود شده.",
|
||||||
"domain_block_modal.title": "انسداد دامنه؟",
|
"domain_block_modal.title": "انسداد دامنه؟",
|
||||||
"domain_block_modal.you_will_lose_num_followers": "شما {followersCount, plural, one {{followersCountDisplay} پیگیرنده} other {{followersCountDisplay} پیگیرنده}} و {followingCount, plural, one {{followingCountDisplay} فرد پیگرفتهشده} other {{followingCountDisplay} فرد پیگرفتهشده}} را از دست خواهید داد.",
|
"domain_block_modal.you_will_lose_num_followers": "شما {followersCount, plural, one {{followersCountDisplay} پیگیرنده} other {{followersCountDisplay} پیگیرنده}} و {followingCount, plural, one {{followingCountDisplay} فرد پیگرفتهشده} other {{followingCountDisplay} فرد پیگرفتهشده}} را از دست خواهید داد.",
|
||||||
"domain_block_modal.you_will_lose_relationships": "شما تمام پیگیرکنندگان و افرادی که از این کارساز پیگیری میکنید را از دست خواهید داد.",
|
"domain_block_modal.you_will_lose_relationships": "شما تمام پیگیرکنندگان و افرادی که از این کارساز پیگیری میکنید را از دست خواهید داد.",
|
||||||
|
@ -543,11 +543,11 @@
|
||||||
"mute_modal.hide_options": "گزینههای نهفتن",
|
"mute_modal.hide_options": "گزینههای نهفتن",
|
||||||
"mute_modal.indefinite": "تا وقتی ناخموشش کنم",
|
"mute_modal.indefinite": "تا وقتی ناخموشش کنم",
|
||||||
"mute_modal.show_options": "نمایش گزینهها",
|
"mute_modal.show_options": "نمایش گزینهها",
|
||||||
"mute_modal.they_can_mention_and_follow": "میتوانند به شما اشاره کرده و پیتان بگیرند، ولی نخواهید دیدشان.",
|
"mute_modal.they_can_mention_and_follow": "میتواند به شما اشاره کرده و پیتان بگیرد؛ ولی نخواهید دیدش.",
|
||||||
"mute_modal.they_wont_know": "نخواهند دانست که خموش شدهاند.",
|
"mute_modal.they_wont_know": "نخواهد دانست که خموش شده.",
|
||||||
"mute_modal.title": "خموشی کاربر؟",
|
"mute_modal.title": "خموشی کاربر؟",
|
||||||
"mute_modal.you_wont_see_mentions": "فرستههایی که به او اشاره کردهاند را نخواهید دید.",
|
"mute_modal.you_wont_see_mentions": "فرستههایی که به او اشاره کردهاند را نخواهید دید.",
|
||||||
"mute_modal.you_wont_see_posts": "هنوز میتوانند فرستههایتان را ببینند، ولی فرستههایشان را نمیبینید.",
|
"mute_modal.you_wont_see_posts": "همچنان میتواند فرستههایتان را ببینند؛ ولی فرستههایش را نمیبینید.",
|
||||||
"navigation_bar.about": "درباره",
|
"navigation_bar.about": "درباره",
|
||||||
"navigation_bar.account_settings": "گذرواژه و امنیت",
|
"navigation_bar.account_settings": "گذرواژه و امنیت",
|
||||||
"navigation_bar.administration": "مدیریت",
|
"navigation_bar.administration": "مدیریت",
|
||||||
|
@ -687,7 +687,7 @@
|
||||||
"notifications.policy.filter_limited_accounts_title": "حسابهای مدیریت شده",
|
"notifications.policy.filter_limited_accounts_title": "حسابهای مدیریت شده",
|
||||||
"notifications.policy.filter_new_accounts.hint": "ساخته شده در {days, plural, one {یک} other {#}} روز اخیر",
|
"notifications.policy.filter_new_accounts.hint": "ساخته شده در {days, plural, one {یک} other {#}} روز اخیر",
|
||||||
"notifications.policy.filter_new_accounts_title": "حسابهای جدید",
|
"notifications.policy.filter_new_accounts_title": "حسابهای جدید",
|
||||||
"notifications.policy.filter_not_followers_hint": "از جمله کسانی که کمتر از {days, plural, one {یک} other {#}} روز است پیتان میگیرند",
|
"notifications.policy.filter_not_followers_hint": "از جمله کسانی که کمتر از {days, plural, one {یک} other {#}} روز است پیتان میگیرند",
|
||||||
"notifications.policy.filter_not_followers_title": "کسانی که شما را دنبال میکنند",
|
"notifications.policy.filter_not_followers_title": "کسانی که شما را دنبال میکنند",
|
||||||
"notifications.policy.filter_not_following_hint": "تا به صورت دستی تأییدشان کنید",
|
"notifications.policy.filter_not_following_hint": "تا به صورت دستی تأییدشان کنید",
|
||||||
"notifications.policy.filter_not_following_title": "کسانی که پی نمیگیرید",
|
"notifications.policy.filter_not_following_title": "کسانی که پی نمیگیرید",
|
||||||
|
@ -756,7 +756,7 @@
|
||||||
"reply_indicator.cancel": "لغو",
|
"reply_indicator.cancel": "لغو",
|
||||||
"reply_indicator.poll": "نظرسنجی",
|
"reply_indicator.poll": "نظرسنجی",
|
||||||
"report.block": "انسداد",
|
"report.block": "انسداد",
|
||||||
"report.block_explanation": "شما فرستههایشان را نخواهید دید. آنها نمیتوانند فرستههایتان را ببینند یا شما را پیبگیرند. آنها میتوانند بگویند که مسدود شدهاند.",
|
"report.block_explanation": "فرستههایش را نخواهید دید. نخواهد توانست فرستههایتان را دیده یا پیتان بگیرد. قادر است تشخیص دهد مسدود شده.",
|
||||||
"report.categories.legal": "حقوقی",
|
"report.categories.legal": "حقوقی",
|
||||||
"report.categories.other": "غیره",
|
"report.categories.other": "غیره",
|
||||||
"report.categories.spam": "هرزنامه",
|
"report.categories.spam": "هرزنامه",
|
||||||
|
@ -770,7 +770,7 @@
|
||||||
"report.forward": "فرستادن به {target}",
|
"report.forward": "فرستادن به {target}",
|
||||||
"report.forward_hint": "این حساب در کارساز دیگری ثبت شده. آیا میخواهید رونوشتی ناشناس از این گزارش به آنجا هم فرستاده شود؟",
|
"report.forward_hint": "این حساب در کارساز دیگری ثبت شده. آیا میخواهید رونوشتی ناشناس از این گزارش به آنجا هم فرستاده شود؟",
|
||||||
"report.mute": "خموش",
|
"report.mute": "خموش",
|
||||||
"report.mute_explanation": "شما فرستههای آنها را نخواهید دید. آنها همچنان میتوانند شما را پیبگیرند و فرستههایتان را ببینند و نمیدانند که خموش شدهاند.",
|
"report.mute_explanation": "فرستههایش را نخواهید دید. همچنان خواهد توانست پیتان گرفته و فرستههایتان را ببیند. نخواهد دانست که خموش شده.",
|
||||||
"report.next": "بعدی",
|
"report.next": "بعدی",
|
||||||
"report.placeholder": "توضیحات اضافه",
|
"report.placeholder": "توضیحات اضافه",
|
||||||
"report.reasons.dislike": "من آن را دوست ندارم",
|
"report.reasons.dislike": "من آن را دوست ندارم",
|
||||||
|
|
|
@ -564,6 +564,8 @@
|
||||||
"navigation_bar.follows_and_followers": "Folgers en folgjenden",
|
"navigation_bar.follows_and_followers": "Folgers en folgjenden",
|
||||||
"navigation_bar.import_export": "Ymportearje en eksportearje",
|
"navigation_bar.import_export": "Ymportearje en eksportearje",
|
||||||
"navigation_bar.lists": "Listen",
|
"navigation_bar.lists": "Listen",
|
||||||
|
"navigation_bar.live_feed_local": "Livefeed (lokaal)",
|
||||||
|
"navigation_bar.live_feed_public": "Livefeed (iepenbier)",
|
||||||
"navigation_bar.logout": "Ofmelde",
|
"navigation_bar.logout": "Ofmelde",
|
||||||
"navigation_bar.moderation": "Moderaasje",
|
"navigation_bar.moderation": "Moderaasje",
|
||||||
"navigation_bar.more": "Mear",
|
"navigation_bar.more": "Mear",
|
||||||
|
@ -803,6 +805,7 @@
|
||||||
"report_notification.categories.violation": "Skeinde regels",
|
"report_notification.categories.violation": "Skeinde regels",
|
||||||
"report_notification.categories.violation_sentence": "skeinde regels",
|
"report_notification.categories.violation_sentence": "skeinde regels",
|
||||||
"report_notification.open": "Rapport iepenje",
|
"report_notification.open": "Rapport iepenje",
|
||||||
|
"search.clear": "Sykopdracht wiskje",
|
||||||
"search.no_recent_searches": "Gjin resinte sykopdrachten",
|
"search.no_recent_searches": "Gjin resinte sykopdrachten",
|
||||||
"search.placeholder": "Sykje",
|
"search.placeholder": "Sykje",
|
||||||
"search.quick_action.account_search": "Accounts dy’t oerienkomme mei {x}",
|
"search.quick_action.account_search": "Accounts dy’t oerienkomme mei {x}",
|
||||||
|
|
|
@ -219,6 +219,13 @@
|
||||||
"confirmations.delete_list.confirm": "削除",
|
"confirmations.delete_list.confirm": "削除",
|
||||||
"confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
|
"confirmations.delete_list.message": "本当にこのリストを完全に削除しますか?",
|
||||||
"confirmations.delete_list.title": "リストを削除しようとしています",
|
"confirmations.delete_list.title": "リストを削除しようとしています",
|
||||||
|
"confirmations.discard_draft.confirm": "破棄して続ける",
|
||||||
|
"confirmations.discard_draft.edit.cancel": "編集を再開",
|
||||||
|
"confirmations.discard_draft.edit.message": "続行すると、現在編集している投稿に加えた変更は破棄されます。",
|
||||||
|
"confirmations.discard_draft.edit.title": "投稿の変更を破棄しますか?",
|
||||||
|
"confirmations.discard_draft.post.cancel": "下書きを再開",
|
||||||
|
"confirmations.discard_draft.post.message": "続行すると、現在作成中の投稿が破棄されます。",
|
||||||
|
"confirmations.discard_draft.post.title": "下書きを破棄しますか?",
|
||||||
"confirmations.discard_edit_media.confirm": "破棄",
|
"confirmations.discard_edit_media.confirm": "破棄",
|
||||||
"confirmations.discard_edit_media.message": "メディアの説明またはプレビューに保存されていない変更があります。それでも破棄しますか?",
|
"confirmations.discard_edit_media.message": "メディアの説明またはプレビューに保存されていない変更があります。それでも破棄しますか?",
|
||||||
"confirmations.follow_to_list.confirm": "フォローしてリストに追加",
|
"confirmations.follow_to_list.confirm": "フォローしてリストに追加",
|
||||||
|
@ -330,6 +337,7 @@
|
||||||
"errors.unexpected_crash.copy_stacktrace": "スタックトレースをクリップボードにコピー",
|
"errors.unexpected_crash.copy_stacktrace": "スタックトレースをクリップボードにコピー",
|
||||||
"errors.unexpected_crash.report_issue": "問題を報告",
|
"errors.unexpected_crash.report_issue": "問題を報告",
|
||||||
"explore.suggested_follows": "ユーザー",
|
"explore.suggested_follows": "ユーザー",
|
||||||
|
"explore.title": "トレンド",
|
||||||
"explore.trending_links": "ニュース",
|
"explore.trending_links": "ニュース",
|
||||||
"explore.trending_statuses": "投稿",
|
"explore.trending_statuses": "投稿",
|
||||||
"explore.trending_tags": "ハッシュタグ",
|
"explore.trending_tags": "ハッシュタグ",
|
||||||
|
@ -417,6 +425,7 @@
|
||||||
"hints.profiles.see_more_posts": "{domain} でその他の投稿を見る",
|
"hints.profiles.see_more_posts": "{domain} でその他の投稿を見る",
|
||||||
"hints.threads.replies_may_be_missing": "リモートの返信は表示されない場合があります。",
|
"hints.threads.replies_may_be_missing": "リモートの返信は表示されない場合があります。",
|
||||||
"hints.threads.see_more": "{domain} でその他の返信を見る",
|
"hints.threads.see_more": "{domain} でその他の返信を見る",
|
||||||
|
"home.column_settings.show_quotes": "引用を表示",
|
||||||
"home.column_settings.show_reblogs": "ブースト表示",
|
"home.column_settings.show_reblogs": "ブースト表示",
|
||||||
"home.column_settings.show_replies": "返信表示",
|
"home.column_settings.show_replies": "返信表示",
|
||||||
"home.hide_announcements": "お知らせを隠す",
|
"home.hide_announcements": "お知らせを隠す",
|
||||||
|
@ -539,8 +548,10 @@
|
||||||
"mute_modal.you_wont_see_mentions": "宛先に相手が入っている投稿も閲覧できなくなります。",
|
"mute_modal.you_wont_see_mentions": "宛先に相手が入っている投稿も閲覧できなくなります。",
|
||||||
"mute_modal.you_wont_see_posts": "相手はあなたの投稿を今までどおり閲覧できますが、あなたは相手の投稿を閲覧できなくなります。",
|
"mute_modal.you_wont_see_posts": "相手はあなたの投稿を今までどおり閲覧できますが、あなたは相手の投稿を閲覧できなくなります。",
|
||||||
"navigation_bar.about": "概要",
|
"navigation_bar.about": "概要",
|
||||||
|
"navigation_bar.account_settings": "パスワードとセキュリティ",
|
||||||
"navigation_bar.administration": "管理",
|
"navigation_bar.administration": "管理",
|
||||||
"navigation_bar.advanced_interface": "上級者向けUIに戻る",
|
"navigation_bar.advanced_interface": "上級者向けUIに戻る",
|
||||||
|
"navigation_bar.automated_deletion": "投稿の自動削除",
|
||||||
"navigation_bar.blocks": "ブロックしたユーザー",
|
"navigation_bar.blocks": "ブロックしたユーザー",
|
||||||
"navigation_bar.bookmarks": "ブックマーク",
|
"navigation_bar.bookmarks": "ブックマーク",
|
||||||
"navigation_bar.direct": "非公開の返信",
|
"navigation_bar.direct": "非公開の返信",
|
||||||
|
@ -550,13 +561,21 @@
|
||||||
"navigation_bar.follow_requests": "フォローリクエスト",
|
"navigation_bar.follow_requests": "フォローリクエスト",
|
||||||
"navigation_bar.followed_tags": "フォロー中のハッシュタグ",
|
"navigation_bar.followed_tags": "フォロー中のハッシュタグ",
|
||||||
"navigation_bar.follows_and_followers": "フォロー・フォロワー",
|
"navigation_bar.follows_and_followers": "フォロー・フォロワー",
|
||||||
|
"navigation_bar.import_export": "インポートとエクスポート",
|
||||||
"navigation_bar.lists": "リスト",
|
"navigation_bar.lists": "リスト",
|
||||||
"navigation_bar.logout": "ログアウト",
|
"navigation_bar.logout": "ログアウト",
|
||||||
"navigation_bar.moderation": "モデレーション",
|
"navigation_bar.moderation": "モデレーション",
|
||||||
|
"navigation_bar.more": "もっと見る",
|
||||||
"navigation_bar.mutes": "ミュートしたユーザー",
|
"navigation_bar.mutes": "ミュートしたユーザー",
|
||||||
"navigation_bar.opened_in_classic_interface": "投稿やプロフィールを直接開いた場合は一時的に標準UIで表示されます。",
|
"navigation_bar.opened_in_classic_interface": "投稿やプロフィールを直接開いた場合は一時的に標準UIで表示されます。",
|
||||||
"navigation_bar.preferences": "ユーザー設定",
|
"navigation_bar.preferences": "ユーザー設定",
|
||||||
|
"navigation_bar.privacy_and_reach": "プライバシーとつながりやすさ",
|
||||||
"navigation_bar.search": "検索",
|
"navigation_bar.search": "検索",
|
||||||
|
"navigation_bar.search_trends": "検索 / トレンド",
|
||||||
|
"navigation_panel.collapse_followed_tags": "フォロー中のハッシュタグメニューを閉じる",
|
||||||
|
"navigation_panel.collapse_lists": "リストメニューを閉じる",
|
||||||
|
"navigation_panel.expand_followed_tags": "フォロー中のハッシュタグメニューを展開",
|
||||||
|
"navigation_panel.expand_lists": "リストメニューを展開",
|
||||||
"not_signed_in_indicator.not_signed_in": "この機能を使うにはログインする必要があります。",
|
"not_signed_in_indicator.not_signed_in": "この機能を使うにはログインする必要があります。",
|
||||||
"notification.admin.report": "{name}さんが{target}さんを通報しました",
|
"notification.admin.report": "{name}さんが{target}さんを通報しました",
|
||||||
"notification.admin.report_account": "{name}さんが{target}さんの投稿{count, plural, other {#件}}を「{category}」として通報しました",
|
"notification.admin.report_account": "{name}さんが{target}さんの投稿{count, plural, other {#件}}を「{category}」として通報しました",
|
||||||
|
@ -783,6 +802,7 @@
|
||||||
"report_notification.categories.violation": "ルール違反",
|
"report_notification.categories.violation": "ルール違反",
|
||||||
"report_notification.categories.violation_sentence": "ルール違反",
|
"report_notification.categories.violation_sentence": "ルール違反",
|
||||||
"report_notification.open": "通報を開く",
|
"report_notification.open": "通報を開く",
|
||||||
|
"search.clear": "検索をクリア",
|
||||||
"search.no_recent_searches": "検索履歴はありません",
|
"search.no_recent_searches": "検索履歴はありません",
|
||||||
"search.placeholder": "検索",
|
"search.placeholder": "検索",
|
||||||
"search.quick_action.account_search": "{x}に該当するプロフィール",
|
"search.quick_action.account_search": "{x}に該当するプロフィール",
|
||||||
|
@ -885,7 +905,10 @@
|
||||||
"subscribed_languages.save": "変更を保存",
|
"subscribed_languages.save": "変更を保存",
|
||||||
"subscribed_languages.target": "{target}さんの購読言語を変更します",
|
"subscribed_languages.target": "{target}さんの購読言語を変更します",
|
||||||
"tabs_bar.home": "ホーム",
|
"tabs_bar.home": "ホーム",
|
||||||
|
"tabs_bar.menu": "メニュー",
|
||||||
"tabs_bar.notifications": "通知",
|
"tabs_bar.notifications": "通知",
|
||||||
|
"tabs_bar.publish": "新しい投稿",
|
||||||
|
"tabs_bar.search": "検索",
|
||||||
"terms_of_service.effective_as_of": "{date}より有効",
|
"terms_of_service.effective_as_of": "{date}より有効",
|
||||||
"terms_of_service.title": "サービス利用規約",
|
"terms_of_service.title": "サービス利用規約",
|
||||||
"terms_of_service.upcoming_changes_on": "{date}から適用される変更",
|
"terms_of_service.upcoming_changes_on": "{date}から適用される変更",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"about.domain_blocks.preamble": "Maṣṭudun s umata yeḍmen-ak ad teẓreḍ agbur, ad tesdemreḍ akked yimseqdacen-nniḍen seg yal aqeddac deg fedivers. Ha-tent-an ɣur-k tsuraf i yellan deg uqeddac-agi.",
|
"about.domain_blocks.preamble": "Maṣṭudun s umata yeḍmen-ak ad teẓreḍ agbur, ad tesdemreḍ akked yimseqdacen-nniḍen seg yal aqeddac deg fedivers. Ha-tent-an ɣur-k tsuraf i yellan deg uqeddac-agi.",
|
||||||
"about.domain_blocks.silenced.title": "Ɣur-s talast",
|
"about.domain_blocks.silenced.title": "Ɣur-s talast",
|
||||||
"about.domain_blocks.suspended.title": "Yettwaḥbes",
|
"about.domain_blocks.suspended.title": "Yettwaḥbes",
|
||||||
|
"about.language_label": "Tutlayt",
|
||||||
"about.not_available": "Talɣut-a ur tettwabder ara deg uqeddac-a.",
|
"about.not_available": "Talɣut-a ur tettwabder ara deg uqeddac-a.",
|
||||||
"about.powered_by": "Azeṭṭa inmetti yettwasɣelsen sɣur {mastodon}",
|
"about.powered_by": "Azeṭṭa inmetti yettwasɣelsen sɣur {mastodon}",
|
||||||
"about.rules": "Ilugan n uqeddac",
|
"about.rules": "Ilugan n uqeddac",
|
||||||
|
@ -115,6 +116,7 @@
|
||||||
"column.domain_blocks": "Taɣulin yeffren",
|
"column.domain_blocks": "Taɣulin yeffren",
|
||||||
"column.edit_list": "Ẓreg tabdart",
|
"column.edit_list": "Ẓreg tabdart",
|
||||||
"column.favourites": "Imenyafen",
|
"column.favourites": "Imenyafen",
|
||||||
|
"column.firehose": "Isuddam usriden",
|
||||||
"column.follow_requests": "Isuturen n teḍfeṛt",
|
"column.follow_requests": "Isuturen n teḍfeṛt",
|
||||||
"column.home": "Agejdan",
|
"column.home": "Agejdan",
|
||||||
"column.lists": "Tibdarin",
|
"column.lists": "Tibdarin",
|
||||||
|
@ -223,6 +225,7 @@
|
||||||
"empty_column.bookmarked_statuses": "Ulac kra n tsuffeɣt i terniḍ ɣer yismenyifen-ik·im ar tura. Ticki terniḍ yiwet, ad d-tettwasken da.",
|
"empty_column.bookmarked_statuses": "Ulac kra n tsuffeɣt i terniḍ ɣer yismenyifen-ik·im ar tura. Ticki terniḍ yiwet, ad d-tettwasken da.",
|
||||||
"empty_column.community": "Tasuddemt tazayezt tadigant n yisallen d tilemt. Aru ihi kra akken ad tt-teččareḍ!",
|
"empty_column.community": "Tasuddemt tazayezt tadigant n yisallen d tilemt. Aru ihi kra akken ad tt-teččareḍ!",
|
||||||
"empty_column.domain_blocks": "Ulac kra n taɣult yettwaffren ar tura.",
|
"empty_column.domain_blocks": "Ulac kra n taɣult yettwaffren ar tura.",
|
||||||
|
"empty_column.explore_statuses": "Ulac ayen yellan d anezzuɣ akka tura. Uɣal-d ticki!",
|
||||||
"empty_column.follow_requests": "Ulac ɣur-k·m ula yiwen n usuter n teḍfeṛt. Ticki teṭṭfeḍ-d yiwen ad d-yettwasken da.",
|
"empty_column.follow_requests": "Ulac ɣur-k·m ula yiwen n usuter n teḍfeṛt. Ticki teṭṭfeḍ-d yiwen ad d-yettwasken da.",
|
||||||
"empty_column.hashtag": "Ar tura ulac kra n ugbur yesɛan assaɣ ɣer uhacṭag-agi.",
|
"empty_column.hashtag": "Ar tura ulac kra n ugbur yesɛan assaɣ ɣer uhacṭag-agi.",
|
||||||
"empty_column.home": "Tasuddemt tagejdant n yisallen d tilemt! Ẓer {public} neɣ nadi ad tafeḍ imseqdacen-nniḍen ad ten-ḍefṛeḍ.",
|
"empty_column.home": "Tasuddemt tagejdant n yisallen d tilemt! Ẓer {public} neɣ nadi ad tafeḍ imseqdacen-nniḍen ad ten-ḍefṛeḍ.",
|
||||||
|
@ -234,9 +237,14 @@
|
||||||
"errors.unexpected_crash.copy_stacktrace": "Nɣel stacktrace ɣef wafus",
|
"errors.unexpected_crash.copy_stacktrace": "Nɣel stacktrace ɣef wafus",
|
||||||
"errors.unexpected_crash.report_issue": "Mmel ugur",
|
"errors.unexpected_crash.report_issue": "Mmel ugur",
|
||||||
"explore.suggested_follows": "Imdanen",
|
"explore.suggested_follows": "Imdanen",
|
||||||
|
"explore.title": "Inezzaɣ",
|
||||||
"explore.trending_links": "Isallen",
|
"explore.trending_links": "Isallen",
|
||||||
"explore.trending_statuses": "Tisuffaɣ",
|
"explore.trending_statuses": "Tisuffaɣ",
|
||||||
"explore.trending_tags": "Ihacṭagen",
|
"explore.trending_tags": "Ihacṭagen",
|
||||||
|
"featured_carousel.next": "Uḍfiṛ",
|
||||||
|
"featured_carousel.post": "Tasuffeɣt",
|
||||||
|
"featured_carousel.previous": "Uzwir",
|
||||||
|
"featured_carousel.slide": "{index} ɣef {total}",
|
||||||
"filter_modal.added.review_and_configure_title": "Iɣewwaṛen n imzizdig",
|
"filter_modal.added.review_and_configure_title": "Iɣewwaṛen n imzizdig",
|
||||||
"filter_modal.added.settings_link": "asebter n yiɣewwaṛen",
|
"filter_modal.added.settings_link": "asebter n yiɣewwaṛen",
|
||||||
"filter_modal.added.short_explanation": "Tasuffeɣt-a tettwarna ɣer taggayt-a n yimsizdegen: {title}.",
|
"filter_modal.added.short_explanation": "Tasuffeɣt-a tettwarna ɣer taggayt-a n yimsizdegen: {title}.",
|
||||||
|
@ -357,6 +365,7 @@
|
||||||
"lists.add_to_list": "Rnu ɣer tebdart",
|
"lists.add_to_list": "Rnu ɣer tebdart",
|
||||||
"lists.add_to_lists": "Rnu {name} ɣer tebdarin",
|
"lists.add_to_lists": "Rnu {name} ɣer tebdarin",
|
||||||
"lists.create": "Snulfu-d",
|
"lists.create": "Snulfu-d",
|
||||||
|
"lists.create_list": "Snulfu-d tabdart",
|
||||||
"lists.delete": "Kkes tabdart",
|
"lists.delete": "Kkes tabdart",
|
||||||
"lists.done": "Immed",
|
"lists.done": "Immed",
|
||||||
"lists.edit": "Ẓreg tabdart",
|
"lists.edit": "Ẓreg tabdart",
|
||||||
|
@ -395,12 +404,16 @@
|
||||||
"navigation_bar.followed_tags": "Ihacṭagen yettwaḍfaren",
|
"navigation_bar.followed_tags": "Ihacṭagen yettwaḍfaren",
|
||||||
"navigation_bar.follows_and_followers": "Imeḍfaṛen akked wid i teṭṭafaṛeḍ",
|
"navigation_bar.follows_and_followers": "Imeḍfaṛen akked wid i teṭṭafaṛeḍ",
|
||||||
"navigation_bar.lists": "Tibdarin",
|
"navigation_bar.lists": "Tibdarin",
|
||||||
|
"navigation_bar.live_feed_local": "Asuddem usrid (adigan)",
|
||||||
|
"navigation_bar.live_feed_public": "Asuddem usrid (azayaz)",
|
||||||
"navigation_bar.logout": "Ffeɣ",
|
"navigation_bar.logout": "Ffeɣ",
|
||||||
"navigation_bar.moderation": "Aseɣyed",
|
"navigation_bar.moderation": "Aseɣyed",
|
||||||
|
"navigation_bar.more": "Ugar",
|
||||||
"navigation_bar.mutes": "Iseqdacen yettwasusmen",
|
"navigation_bar.mutes": "Iseqdacen yettwasusmen",
|
||||||
"navigation_bar.opened_in_classic_interface": "Tisuffaɣ, imiḍanen akked isebtar-nniḍen igejdanen ldin-d s wudem amezwer deg ugrudem web aklasiki.",
|
"navigation_bar.opened_in_classic_interface": "Tisuffaɣ, imiḍanen akked isebtar-nniḍen igejdanen ldin-d s wudem amezwer deg ugrudem web aklasiki.",
|
||||||
"navigation_bar.preferences": "Imenyafen",
|
"navigation_bar.preferences": "Imenyafen",
|
||||||
"navigation_bar.search": "Nadi",
|
"navigation_bar.search": "Nadi",
|
||||||
|
"navigation_bar.search_trends": "Anadi / Anezzuɣ",
|
||||||
"not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
|
"not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
|
||||||
"notification.admin.report": "Yemla-t-id {name} {target}",
|
"notification.admin.report": "Yemla-t-id {name} {target}",
|
||||||
"notification.admin.sign_up": "Ijerred {name}",
|
"notification.admin.sign_up": "Ijerred {name}",
|
||||||
|
@ -505,6 +518,7 @@
|
||||||
"recommended": "Yettuwelleh",
|
"recommended": "Yettuwelleh",
|
||||||
"refresh": "Smiren",
|
"refresh": "Smiren",
|
||||||
"regeneration_indicator.please_stand_by": "Ttxil rǧu.",
|
"regeneration_indicator.please_stand_by": "Ttxil rǧu.",
|
||||||
|
"regeneration_indicator.preparing_your_home_feed": "Ha-tt-an tsuddemt-ik·im tagejdant tettwaheggay…",
|
||||||
"relative_time.days": "{number}u",
|
"relative_time.days": "{number}u",
|
||||||
"relative_time.full.just_now": "tura kan",
|
"relative_time.full.just_now": "tura kan",
|
||||||
"relative_time.hours": "{number}isr",
|
"relative_time.hours": "{number}isr",
|
||||||
|
@ -545,6 +559,7 @@
|
||||||
"report.thanks.title": "Ur tebɣiḍ ara ad twaliḍ aya?",
|
"report.thanks.title": "Ur tebɣiḍ ara ad twaliḍ aya?",
|
||||||
"report.thanks.title_actionable": "Tanemmirt ɣef uneqqis, ad nwali deg waya.",
|
"report.thanks.title_actionable": "Tanemmirt ɣef uneqqis, ad nwali deg waya.",
|
||||||
"report.unfollow": "Seḥbes aḍfar n @{name}",
|
"report.unfollow": "Seḥbes aḍfar n @{name}",
|
||||||
|
"report.unfollow_explanation": "Aql-ik·ikem teṭṭafareḍ amiḍan-a. I wakken ur tettwaliḍ ara akk, akka d asawen, tisuffaɣ-is deg tsuddemt-ik·im tagejdant, ur teṭṭafar ara.",
|
||||||
"report_notification.attached_statuses": "{count, plural, one {{count} n tsuffeɣt} other {{count} n tsuffiɣin}} ttwaqnent",
|
"report_notification.attached_statuses": "{count, plural, one {{count} n tsuffeɣt} other {{count} n tsuffiɣin}} ttwaqnent",
|
||||||
"report_notification.categories.legal": "Azerfan",
|
"report_notification.categories.legal": "Azerfan",
|
||||||
"report_notification.categories.other": "Ayen nniḍen",
|
"report_notification.categories.other": "Ayen nniḍen",
|
||||||
|
@ -610,6 +625,7 @@
|
||||||
"status.mute_conversation": "Sgugem adiwenni",
|
"status.mute_conversation": "Sgugem adiwenni",
|
||||||
"status.open": "Semɣeṛ tasuffeɣt-ayi",
|
"status.open": "Semɣeṛ tasuffeɣt-ayi",
|
||||||
"status.pin": "Senteḍ-itt deg umaɣnu",
|
"status.pin": "Senteḍ-itt deg umaɣnu",
|
||||||
|
"status.quote_post_author": "Izen sɣur {name}",
|
||||||
"status.read_more": "Issin ugar",
|
"status.read_more": "Issin ugar",
|
||||||
"status.reblog": "Bḍu",
|
"status.reblog": "Bḍu",
|
||||||
"status.reblogged_by": "Yebḍa-tt {name}",
|
"status.reblogged_by": "Yebḍa-tt {name}",
|
||||||
|
@ -635,7 +651,10 @@
|
||||||
"status.unpin": "Kkes asenteḍ seg umaɣnu",
|
"status.unpin": "Kkes asenteḍ seg umaɣnu",
|
||||||
"subscribed_languages.save": "Sekles ibeddilen",
|
"subscribed_languages.save": "Sekles ibeddilen",
|
||||||
"tabs_bar.home": "Agejdan",
|
"tabs_bar.home": "Agejdan",
|
||||||
|
"tabs_bar.menu": "Umuɣ",
|
||||||
"tabs_bar.notifications": "Ilɣa",
|
"tabs_bar.notifications": "Ilɣa",
|
||||||
|
"tabs_bar.publish": "Tasuffeɣt tamaynut",
|
||||||
|
"tabs_bar.search": "Nadi",
|
||||||
"terms_of_service.title": "Tiwtilin n useqdec",
|
"terms_of_service.title": "Tiwtilin n useqdec",
|
||||||
"time_remaining.days": "Mazal {number, plural, one {# wass} other {# wussan}}",
|
"time_remaining.days": "Mazal {number, plural, one {# wass} other {# wussan}}",
|
||||||
"time_remaining.hours": "Mazal {number, plural, one {# usarag} other {# yisragen}}",
|
"time_remaining.hours": "Mazal {number, plural, one {# usarag} other {# yisragen}}",
|
||||||
|
@ -643,7 +662,7 @@
|
||||||
"time_remaining.moments": "Akuden i d-yeqqimen",
|
"time_remaining.moments": "Akuden i d-yeqqimen",
|
||||||
"time_remaining.seconds": "Mazal {number, plural, one {# n tasint} other {# n tsinin}} id yugran",
|
"time_remaining.seconds": "Mazal {number, plural, one {# n tasint} other {# n tsinin}} id yugran",
|
||||||
"trends.counter_by_accounts": "{count, plural, one {{counter} wemdan} other {{counter} medden}} deg {days, plural, one {ass} other {{days} wussan}} iɛeddan",
|
"trends.counter_by_accounts": "{count, plural, one {{counter} wemdan} other {{counter} medden}} deg {days, plural, one {ass} other {{days} wussan}} iɛeddan",
|
||||||
"trends.trending_now": "Ayen mucaɛen tura",
|
"trends.trending_now": "Anezzuɣ tura",
|
||||||
"ui.beforeunload": "Arewway-ik·im ad iruḥ ma yella tefeɣ-d deg Maṣṭudun.",
|
"ui.beforeunload": "Arewway-ik·im ad iruḥ ma yella tefeɣ-d deg Maṣṭudun.",
|
||||||
"units.short.billion": "{count}B",
|
"units.short.billion": "{count}B",
|
||||||
"units.short.million": "{count}M",
|
"units.short.million": "{count}M",
|
||||||
|
|
|
@ -356,6 +356,7 @@
|
||||||
"hashtag.counter_by_accounts": "{count, plural, one {{counter} partisipante} other {{counter} partisipantes}}",
|
"hashtag.counter_by_accounts": "{count, plural, one {{counter} partisipante} other {{counter} partisipantes}}",
|
||||||
"hashtag.counter_by_uses": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}}",
|
"hashtag.counter_by_uses": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}}",
|
||||||
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}} oy",
|
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} publikasyon} other {{counter} publikasyones}} oy",
|
||||||
|
"hashtag.feature": "Avalia en profil",
|
||||||
"hashtag.follow": "Sige etiketa",
|
"hashtag.follow": "Sige etiketa",
|
||||||
"hashtag.mute": "Silensia #{hashtag}",
|
"hashtag.mute": "Silensia #{hashtag}",
|
||||||
"hashtag.unfeature": "No avalia en profil",
|
"hashtag.unfeature": "No avalia en profil",
|
||||||
|
@ -390,6 +391,7 @@
|
||||||
"interaction_modal.title.reblog": "Repartaja publikasyon de {name}",
|
"interaction_modal.title.reblog": "Repartaja publikasyon de {name}",
|
||||||
"interaction_modal.title.reply": "Arisponde a publikasyon de {name}",
|
"interaction_modal.title.reply": "Arisponde a publikasyon de {name}",
|
||||||
"interaction_modal.title.vote": "Vota en la anketa de {name}",
|
"interaction_modal.title.vote": "Vota en la anketa de {name}",
|
||||||
|
"interaction_modal.username_prompt": "Por enshemplo {example}",
|
||||||
"intervals.full.days": "{number, plural, one {# diya} other {# diyas}}",
|
"intervals.full.days": "{number, plural, one {# diya} other {# diyas}}",
|
||||||
"intervals.full.hours": "{number, plural, one {# ora} other {# oras}}",
|
"intervals.full.hours": "{number, plural, one {# ora} other {# oras}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
|
"intervals.full.minutes": "{number, plural, one {# minuto} other {# minutos}}",
|
||||||
|
@ -442,6 +444,7 @@
|
||||||
"lists.delete": "Efasa lista",
|
"lists.delete": "Efasa lista",
|
||||||
"lists.done": "Fecho",
|
"lists.done": "Fecho",
|
||||||
"lists.edit": "Edita lista",
|
"lists.edit": "Edita lista",
|
||||||
|
"lists.list_name": "Nombre de lista",
|
||||||
"lists.new_list_name": "Nombre de mueva lista",
|
"lists.new_list_name": "Nombre de mueva lista",
|
||||||
"lists.replies_policy.followed": "Kualseker utilizador segido",
|
"lists.replies_policy.followed": "Kualseker utilizador segido",
|
||||||
"lists.replies_policy.list": "Miembros de la lista",
|
"lists.replies_policy.list": "Miembros de la lista",
|
||||||
|
@ -738,6 +741,7 @@
|
||||||
"status.reblogs.empty": "Ainda nadie tiene repartajado esta publikasyon. Kuando algien lo aga, se amostrara aki.",
|
"status.reblogs.empty": "Ainda nadie tiene repartajado esta publikasyon. Kuando algien lo aga, se amostrara aki.",
|
||||||
"status.redraft": "Efasa i eskrive de muevo",
|
"status.redraft": "Efasa i eskrive de muevo",
|
||||||
"status.remove_bookmark": "Kita markador",
|
"status.remove_bookmark": "Kita markador",
|
||||||
|
"status.remove_favourite": "Kita de los favoritos",
|
||||||
"status.replied_in_thread": "Arispondo en filo",
|
"status.replied_in_thread": "Arispondo en filo",
|
||||||
"status.replied_to": "Arispondio a {name}",
|
"status.replied_to": "Arispondio a {name}",
|
||||||
"status.reply": "Arisponde",
|
"status.reply": "Arisponde",
|
||||||
|
@ -758,6 +762,7 @@
|
||||||
"subscribed_languages.save": "Guadra trokamientos",
|
"subscribed_languages.save": "Guadra trokamientos",
|
||||||
"subscribed_languages.target": "Troka linguas abonadas para {target}",
|
"subscribed_languages.target": "Troka linguas abonadas para {target}",
|
||||||
"tabs_bar.home": "Linya prinsipala",
|
"tabs_bar.home": "Linya prinsipala",
|
||||||
|
"tabs_bar.menu": "Menu",
|
||||||
"tabs_bar.notifications": "Avizos",
|
"tabs_bar.notifications": "Avizos",
|
||||||
"tabs_bar.publish": "Mueva publikasyon",
|
"tabs_bar.publish": "Mueva publikasyon",
|
||||||
"tabs_bar.search": "Bushkeda",
|
"tabs_bar.search": "Bushkeda",
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
{
|
{
|
||||||
"about.contact": "ਸੰਪਰਕ:",
|
"about.contact": "ਸੰਪਰਕ:",
|
||||||
|
"about.default_locale": "ਮੂਲ",
|
||||||
|
"about.disclaimer": "ਮਸਟੋਡੋਨ ਇੱਕ ਆਜ਼ਾਦ, ਖੁੱਲ੍ਹੇ ਸਰੋਤ ਵਾਲਾ ਸਾਫਟਵੇਅਰ ਹੈ ਅਤੇ Mastodon gGmbH ਦਾ ਮਾਰਕਾ ਹੈ।",
|
||||||
"about.domain_blocks.no_reason_available": "ਕਾਰਨ ਮੌਜੂਦ ਨਹੀਂ ਹੈ",
|
"about.domain_blocks.no_reason_available": "ਕਾਰਨ ਮੌਜੂਦ ਨਹੀਂ ਹੈ",
|
||||||
"about.domain_blocks.silenced.title": "ਸੀਮਿਤ",
|
"about.domain_blocks.silenced.title": "ਸੀਮਿਤ",
|
||||||
"about.domain_blocks.suspended.title": "ਮੁਅੱਤਲ ਕੀਤੀ",
|
"about.domain_blocks.suspended.title": "ਸਸਪੈਂਡ ਕੀਤਾ",
|
||||||
|
"about.language_label": "ਭਾਸ਼ਾ",
|
||||||
|
"about.not_available": "ਇਹ ਜਾਣਕਾਰੀ ਨੂੰ ਇਸ ਸਰਵਰ ਉੱਤੇ ਉਪਲੱਬਧ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ।",
|
||||||
"about.rules": "ਸਰਵਰ ਨਿਯਮ",
|
"about.rules": "ਸਰਵਰ ਨਿਯਮ",
|
||||||
"account.account_note_header": "ਨਿੱਜੀ ਨੋਟ",
|
"account.account_note_header": "ਨਿੱਜੀ ਨੋਟ",
|
||||||
"account.add_or_remove_from_list": "ਸੂਚੀ ਵਿੱਚ ਜੋੜੋ ਜਾਂ ਹਟਾਓ",
|
"account.add_or_remove_from_list": "ਸੂਚੀ ਵਿੱਚ ਜੋੜੋ ਜਾਂ ਹਟਾਓ",
|
||||||
|
@ -12,21 +16,33 @@
|
||||||
"account.block_domain": "{domain} ਡੋਮੇਨ ਉੱਤੇ ਪਾਬੰਦੀ ਲਾਓ",
|
"account.block_domain": "{domain} ਡੋਮੇਨ ਉੱਤੇ ਪਾਬੰਦੀ ਲਾਓ",
|
||||||
"account.block_short": "ਪਾਬੰਦੀ",
|
"account.block_short": "ਪਾਬੰਦੀ",
|
||||||
"account.blocked": "ਪਾਬੰਦੀਸ਼ੁਦਾ",
|
"account.blocked": "ਪਾਬੰਦੀਸ਼ੁਦਾ",
|
||||||
|
"account.blocking": "ਪਾਬੰਦੀ ਲਾਉਣੀ",
|
||||||
"account.cancel_follow_request": "ਫ਼ਾਲੋ ਕਰਨ ਨੂੰ ਰੱਦ ਕਰੋ",
|
"account.cancel_follow_request": "ਫ਼ਾਲੋ ਕਰਨ ਨੂੰ ਰੱਦ ਕਰੋ",
|
||||||
"account.copy": "ਪਰੋਫਾਇਲ ਲਈ ਲਿੰਕ ਕਾਪੀ ਕਰੋ",
|
"account.copy": "ਪਰੋਫਾਇਲ ਲਈ ਲਿੰਕ ਕਾਪੀ ਕਰੋ",
|
||||||
"account.direct": "ਨਿੱਜੀ ਜ਼ਿਕਰ @{name}",
|
"account.direct": "ਨਿੱਜੀ ਜ਼ਿਕਰ @{name}",
|
||||||
|
"account.disable_notifications": "ਜਦੋਂ {name} ਕੋਈ ਪੋਸਟ ਕਰੇ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਨਾ ਦਿਓ",
|
||||||
|
"account.domain_blocking": "ਡੋਮੇਨ ਉੱਤੇ ਪਾਬੰਦੀ",
|
||||||
"account.edit_profile": "ਪਰੋਫਾਈਲ ਨੂੰ ਸੋਧੋ",
|
"account.edit_profile": "ਪਰੋਫਾਈਲ ਨੂੰ ਸੋਧੋ",
|
||||||
"account.enable_notifications": "ਜਦੋਂ {name} ਪੋਸਟ ਕਰੇ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦਿਓ",
|
"account.enable_notifications": "ਜਦੋਂ {name} ਪੋਸਟ ਕਰੇ ਤਾਂ ਮੈਨੂੰ ਸੂਚਨਾ ਦਿਓ",
|
||||||
"account.endorse": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਫ਼ੀਚਰ",
|
"account.endorse": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਫ਼ੀਚਰ",
|
||||||
|
"account.familiar_followers_one": "{name1} ਵਲੋਂ ਫ਼ਾਲੋ ਕੀਤਾ",
|
||||||
|
"account.familiar_followers_two": "{name1} ਅਤੇ {name2} ਵਲੋਂ ਫ਼ਾਲੋ ਕੀਤਾ",
|
||||||
|
"account.featured": "ਫ਼ੀਚਰ",
|
||||||
|
"account.featured.accounts": "ਪਰੋਫਾਈਲ",
|
||||||
|
"account.featured.hashtags": "ਹੈਸ਼ਟੈਗ",
|
||||||
"account.featured_tags.last_status_at": "{date} ਨੂੰ ਆਖਰੀ ਪੋਸਟ",
|
"account.featured_tags.last_status_at": "{date} ਨੂੰ ਆਖਰੀ ਪੋਸਟ",
|
||||||
"account.featured_tags.last_status_never": "ਕੋਈ ਪੋਸਟ ਨਹੀਂ",
|
"account.featured_tags.last_status_never": "ਕੋਈ ਪੋਸਟ ਨਹੀਂ",
|
||||||
"account.follow": "ਫ਼ਾਲੋ",
|
"account.follow": "ਫ਼ਾਲੋ",
|
||||||
"account.follow_back": "ਵਾਪਸ ਫਾਲ਼ੋ ਕਰੋ",
|
"account.follow_back": "ਵਾਪਸ ਫਾਲ਼ੋ ਕਰੋ",
|
||||||
"account.followers": "ਫ਼ਾਲੋਅਰ",
|
"account.followers": "ਫ਼ਾਲੋਅਰ",
|
||||||
"account.followers.empty": "ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਾਲੇ ਕੋਈ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।",
|
"account.followers.empty": "ਇਸ ਵਰਤੋਂਕਾਰ ਨੂੰ ਹਾਲੇ ਕੋਈ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।",
|
||||||
|
"account.followers_counter": "{count, plural, one {{counter} ਫ਼ਾਲੋਅਰ} other {{counter} ਫ਼ਾਲੋਅਰ}}",
|
||||||
|
"account.followers_you_know_counter": "{counter} ਤੁਸੀਂ ਜਾਣਦੇ ਹੋ",
|
||||||
"account.following": "ਫ਼ਾਲੋ ਕੀਤਾ",
|
"account.following": "ਫ਼ਾਲੋ ਕੀਤਾ",
|
||||||
"account.follows.empty": "ਇਹ ਵਰਤੋਂਕਾਰ ਹਾਲੇ ਕਿਸੇ ਨੂੰ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।",
|
"account.follows.empty": "ਇਹ ਵਰਤੋਂਕਾਰ ਹਾਲੇ ਕਿਸੇ ਨੂੰ ਫ਼ਾਲੋ ਨਹੀਂ ਕਰਦਾ ਹੈ।",
|
||||||
|
"account.follows_you": "ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਦੇ ਹਨ",
|
||||||
"account.go_to_profile": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਜਾਓ",
|
"account.go_to_profile": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਜਾਓ",
|
||||||
|
"account.hide_reblogs": "{name} ਵਲੋਂ ਬੂਸਟ ਨੂੰ ਲੁਕਾਓ",
|
||||||
"account.joined_short": "ਜੁਆਇਨ ਕੀਤਾ",
|
"account.joined_short": "ਜੁਆਇਨ ਕੀਤਾ",
|
||||||
"account.media": "ਮੀਡੀਆ",
|
"account.media": "ਮੀਡੀਆ",
|
||||||
"account.mention": "@{name} ਦਾ ਜ਼ਿਕਰ",
|
"account.mention": "@{name} ਦਾ ਜ਼ਿਕਰ",
|
||||||
|
@ -34,6 +50,7 @@
|
||||||
"account.mute_notifications_short": "ਨੋਟਫਿਕੇਸ਼ਨਾਂ ਨੂੰ ਮੌਨ ਕਰੋ",
|
"account.mute_notifications_short": "ਨੋਟਫਿਕੇਸ਼ਨਾਂ ਨੂੰ ਮੌਨ ਕਰੋ",
|
||||||
"account.mute_short": "ਮੌਨ ਕਰੋ",
|
"account.mute_short": "ਮੌਨ ਕਰੋ",
|
||||||
"account.muted": "ਮੌਨ ਕੀਤੀਆਂ",
|
"account.muted": "ਮੌਨ ਕੀਤੀਆਂ",
|
||||||
|
"account.mutual": "ਤੁਸੀਂ ਇੱਕ ਦੂਜੇ ਨੂੰ ਫ਼ਾਲੋ ਕਰਦੇ ਹੋ",
|
||||||
"account.no_bio": "ਕੋਈ ਵਰਣਨ ਨਹੀਂ ਦਿੱਤਾ।",
|
"account.no_bio": "ਕੋਈ ਵਰਣਨ ਨਹੀਂ ਦਿੱਤਾ।",
|
||||||
"account.open_original_page": "ਅਸਲ ਸਫ਼ੇ ਨੂੰ ਖੋਲ੍ਹੋ",
|
"account.open_original_page": "ਅਸਲ ਸਫ਼ੇ ਨੂੰ ਖੋਲ੍ਹੋ",
|
||||||
"account.posts": "ਪੋਸਟਾਂ",
|
"account.posts": "ਪੋਸਟਾਂ",
|
||||||
|
@ -42,8 +59,10 @@
|
||||||
"account.requested": "ਮਨਜ਼ੂਰੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ। ਫ਼ਾਲੋ ਬੇਨਤੀਆਂ ਨੂੰ ਰੱਦ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ",
|
"account.requested": "ਮਨਜ਼ੂਰੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ। ਫ਼ਾਲੋ ਬੇਨਤੀਆਂ ਨੂੰ ਰੱਦ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ",
|
||||||
"account.requested_follow": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ",
|
"account.requested_follow": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ",
|
||||||
"account.share": "{name} ਦਾ ਪਰੋਫ਼ਾਇਲ ਸਾਂਝਾ ਕਰੋ",
|
"account.share": "{name} ਦਾ ਪਰੋਫ਼ਾਇਲ ਸਾਂਝਾ ਕਰੋ",
|
||||||
|
"account.statuses_counter": "{count, plural, one {{counter} ਪੋਸਟ} other {{counter} ਪੋਸਟਾਂ}}",
|
||||||
"account.unblock": "@{name} ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ",
|
"account.unblock": "@{name} ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ",
|
||||||
"account.unblock_domain": "{domain} ਡੋਮੇਨ ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ",
|
"account.unblock_domain": "{domain} ਡੋਮੇਨ ਤੋਂ ਪਾਬੰਦੀ ਹਟਾਓ",
|
||||||
|
"account.unblock_domain_short": "ਪਾਬੰਦੀ ਹਟਾਓ",
|
||||||
"account.unblock_short": "ਪਾਬੰਦੀ ਹਟਾਓ",
|
"account.unblock_short": "ਪਾਬੰਦੀ ਹਟਾਓ",
|
||||||
"account.unendorse": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਫ਼ੀਚਰ ਨਾ ਕਰੋ",
|
"account.unendorse": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਫ਼ੀਚਰ ਨਾ ਕਰੋ",
|
||||||
"account.unfollow": "ਅਣ-ਫ਼ਾਲੋ",
|
"account.unfollow": "ਅਣ-ਫ਼ਾਲੋ",
|
||||||
|
@ -148,6 +167,8 @@
|
||||||
"confirmations.missing_alt_text.secondary": "ਕਿਵੇਂ ਵੀ ਪੋਸਟ ਕਰੋ",
|
"confirmations.missing_alt_text.secondary": "ਕਿਵੇਂ ਵੀ ਪੋਸਟ ਕਰੋ",
|
||||||
"confirmations.mute.confirm": "ਮੌਨ ਕਰੋ",
|
"confirmations.mute.confirm": "ਮੌਨ ਕਰੋ",
|
||||||
"confirmations.redraft.confirm": "ਹਟਾਓ ਤੇ ਮੁੜ-ਡਰਾਫਟ",
|
"confirmations.redraft.confirm": "ਹਟਾਓ ਤੇ ਮੁੜ-ਡਰਾਫਟ",
|
||||||
|
"confirmations.remove_from_followers.confirm": "ਫ਼ਾਲੋਅਰ ਨੂੰ ਹਟਾਓ",
|
||||||
|
"confirmations.remove_from_followers.title": "ਫ਼ਾਲੋਅਰ ਨੂੰ ਹਟਾਉਣਾ ਹੈ?",
|
||||||
"confirmations.unfollow.confirm": "ਅਣ-ਫ਼ਾਲੋ",
|
"confirmations.unfollow.confirm": "ਅਣ-ਫ਼ਾਲੋ",
|
||||||
"confirmations.unfollow.message": "ਕੀ ਤੁਸੀਂ {name} ਨੂੰ ਅਣ-ਫ਼ਾਲੋ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
|
"confirmations.unfollow.message": "ਕੀ ਤੁਸੀਂ {name} ਨੂੰ ਅਣ-ਫ਼ਾਲੋ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?",
|
||||||
"confirmations.unfollow.title": "ਵਰਤੋਂਕਾਰ ਨੂੰ ਅਣ-ਫ਼ਾਲੋ ਕਰਨਾ ਹੈ?",
|
"confirmations.unfollow.title": "ਵਰਤੋਂਕਾਰ ਨੂੰ ਅਣ-ਫ਼ਾਲੋ ਕਰਨਾ ਹੈ?",
|
||||||
|
@ -182,7 +203,9 @@
|
||||||
"emoji_button.custom": "ਕਸਟਮ",
|
"emoji_button.custom": "ਕਸਟਮ",
|
||||||
"emoji_button.flags": "ਝੰਡੀਆਂ",
|
"emoji_button.flags": "ਝੰਡੀਆਂ",
|
||||||
"emoji_button.food": "ਖਾਣਾ-ਪੀਣਾ",
|
"emoji_button.food": "ਖਾਣਾ-ਪੀਣਾ",
|
||||||
|
"emoji_button.label": "ਇਮੋਜੀ ਪਾਓ",
|
||||||
"emoji_button.nature": "ਕੁਦਰਤ",
|
"emoji_button.nature": "ਕੁਦਰਤ",
|
||||||
|
"emoji_button.not_found": "ਕੋਈ ਮਿਲਦਾ ਇਮੋਜ਼ੀ ਨਹੀਂ ਲੱਭਿਆ",
|
||||||
"emoji_button.objects": "ਇਕਾਈ",
|
"emoji_button.objects": "ਇਕਾਈ",
|
||||||
"emoji_button.people": "ਲੋਕ",
|
"emoji_button.people": "ਲੋਕ",
|
||||||
"emoji_button.recent": "ਅਕਸਰ ਵਰਤੇ",
|
"emoji_button.recent": "ਅਕਸਰ ਵਰਤੇ",
|
||||||
|
@ -199,9 +222,15 @@
|
||||||
"empty_column.list": "ਇਸ ਸੂਚੀ ਵਿੱਚ ਹਾਲੇ ਕੁਝ ਵੀ ਨਹੀਂ ਹੈ। ਜਦੋਂ ਇਸ ਸੂਚੀ ਦੇ ਮੈਂਬਰ ਨਵੀਆਂ ਪੋਸਟਾਂ ਪਾਉਂਦੇ ਹਨ ਤਾਂ ਉਹ ਇੱਥੇ ਦਿਖਾਈ ਦੇਣਗੀਆਂ।",
|
"empty_column.list": "ਇਸ ਸੂਚੀ ਵਿੱਚ ਹਾਲੇ ਕੁਝ ਵੀ ਨਹੀਂ ਹੈ। ਜਦੋਂ ਇਸ ਸੂਚੀ ਦੇ ਮੈਂਬਰ ਨਵੀਆਂ ਪੋਸਟਾਂ ਪਾਉਂਦੇ ਹਨ ਤਾਂ ਉਹ ਇੱਥੇ ਦਿਖਾਈ ਦੇਣਗੀਆਂ।",
|
||||||
"errors.unexpected_crash.report_issue": "ਮੁੱਦੇ ਦੀ ਰਿਪੋਰਟ ਕਰੋ",
|
"errors.unexpected_crash.report_issue": "ਮੁੱਦੇ ਦੀ ਰਿਪੋਰਟ ਕਰੋ",
|
||||||
"explore.suggested_follows": "ਲੋਕ",
|
"explore.suggested_follows": "ਲੋਕ",
|
||||||
|
"explore.title": "ਰੁਝਾਨ",
|
||||||
"explore.trending_links": "ਖ਼ਬਰਾਂ",
|
"explore.trending_links": "ਖ਼ਬਰਾਂ",
|
||||||
"explore.trending_statuses": "ਪੋਸਟਾਂ",
|
"explore.trending_statuses": "ਪੋਸਟਾਂ",
|
||||||
"explore.trending_tags": "ਹੈਸ਼ਟੈਗ",
|
"explore.trending_tags": "ਹੈਸ਼ਟੈਗ",
|
||||||
|
"featured_carousel.header": "{count, plural, one {ਟੰਗੀ ਹੋਈ ਪੋਸਟ} other {ਟੰਗੀਆਂ ਹੋਈਆਂ ਪੋਸਟਾਂ}}",
|
||||||
|
"featured_carousel.next": "ਅੱਗੇ",
|
||||||
|
"featured_carousel.post": "ਪੋਸਟ",
|
||||||
|
"featured_carousel.previous": "ਪਿੱਛੇ",
|
||||||
|
"featured_carousel.slide": "{total} ਵਿੱਚੋਂ {index}",
|
||||||
"filter_modal.added.expired_title": "ਫਿਲਟਰ ਦੀ ਮਿਆਦ ਪੁੱਗੀ!",
|
"filter_modal.added.expired_title": "ਫਿਲਟਰ ਦੀ ਮਿਆਦ ਪੁੱਗੀ!",
|
||||||
"filter_modal.added.review_and_configure_title": "ਫਿਲਟਰ ਸੈਟਿੰਗਾਂ",
|
"filter_modal.added.review_and_configure_title": "ਫਿਲਟਰ ਸੈਟਿੰਗਾਂ",
|
||||||
"filter_modal.added.settings_link": "ਸੈਟਿੰਗਾਂ ਸਫ਼ਾ",
|
"filter_modal.added.settings_link": "ਸੈਟਿੰਗਾਂ ਸਫ਼ਾ",
|
||||||
|
@ -252,6 +281,8 @@
|
||||||
"home.column_settings.show_replies": "ਜਵਾਬਾਂ ਨੂੰ ਵੇਖੋ",
|
"home.column_settings.show_replies": "ਜਵਾਬਾਂ ਨੂੰ ਵੇਖੋ",
|
||||||
"home.hide_announcements": "ਐਲਾਨਾਂ ਨੂੰ ਓਹਲੇ ਕਰੋ",
|
"home.hide_announcements": "ਐਲਾਨਾਂ ਨੂੰ ਓਹਲੇ ਕਰੋ",
|
||||||
"home.pending_critical_update.link": "ਅੱਪਡੇਟ ਵੇਖੋ",
|
"home.pending_critical_update.link": "ਅੱਪਡੇਟ ਵੇਖੋ",
|
||||||
|
"home.pending_critical_update.title": "ਗੰਭੀਰ ਸੁਰੱਖਿਆ ਅੱਪਡੇਟ ਮੌਜੂਦ ਹੈ!",
|
||||||
|
"home.show_announcements": "ਐਲਾਨਾਂ ਨੂੰ ਵੇਖਾਓ",
|
||||||
"ignore_notifications_modal.ignore": "ਨੋਟਫਿਕੇਸ਼ਨਾਂ ਨੂੰ ਅਣਡਿੱਠਾ ਕਰੋ",
|
"ignore_notifications_modal.ignore": "ਨੋਟਫਿਕੇਸ਼ਨਾਂ ਨੂੰ ਅਣਡਿੱਠਾ ਕਰੋ",
|
||||||
"info_button.label": "ਮਦਦ",
|
"info_button.label": "ਮਦਦ",
|
||||||
"interaction_modal.go": "ਜਾਓ",
|
"interaction_modal.go": "ਜਾਓ",
|
||||||
|
@ -332,9 +363,12 @@
|
||||||
"media_gallery.hide": "ਲੁਕਾਓ",
|
"media_gallery.hide": "ਲੁਕਾਓ",
|
||||||
"mute_modal.hide_from_notifications": "ਨੋਟੀਫਿਕੇਸ਼ਨਾਂ ਵਿੱਚੋਂ ਲੁਕਾਓ",
|
"mute_modal.hide_from_notifications": "ਨੋਟੀਫਿਕੇਸ਼ਨਾਂ ਵਿੱਚੋਂ ਲੁਕਾਓ",
|
||||||
"mute_modal.show_options": "ਚੋਣਾਂ ਨੂੰ ਵੇਖਾਓ",
|
"mute_modal.show_options": "ਚੋਣਾਂ ਨੂੰ ਵੇਖਾਓ",
|
||||||
|
"mute_modal.title": "ਵਰਤੋਂਕਾਰ ਨੂੰ ਮੌਨ ਕਰਨਾ ਹੈ?",
|
||||||
"navigation_bar.about": "ਇਸ ਬਾਰੇ",
|
"navigation_bar.about": "ਇਸ ਬਾਰੇ",
|
||||||
|
"navigation_bar.account_settings": "ਪਾਸਵਰਡ ਅਤੇ ਸੁਰੱਖਿਆ",
|
||||||
"navigation_bar.administration": "ਪਰਸ਼ਾਸ਼ਨ",
|
"navigation_bar.administration": "ਪਰਸ਼ਾਸ਼ਨ",
|
||||||
"navigation_bar.advanced_interface": "ਤਕਨੀਕੀ ਵੈੱਬ ਇੰਟਰਫੇਸ ਵਿੱਚ ਖੋਲ੍ਹੋ",
|
"navigation_bar.advanced_interface": "ਤਕਨੀਕੀ ਵੈੱਬ ਇੰਟਰਫੇਸ ਵਿੱਚ ਖੋਲ੍ਹੋ",
|
||||||
|
"navigation_bar.automated_deletion": "ਆਪਣੇ-ਆਪ ਹਟਾਈ ਪੋਸਟ",
|
||||||
"navigation_bar.blocks": "ਪਾਬੰਦੀ ਲਾਏ ਵਰਤੋਂਕਾਰ",
|
"navigation_bar.blocks": "ਪਾਬੰਦੀ ਲਾਏ ਵਰਤੋਂਕਾਰ",
|
||||||
"navigation_bar.bookmarks": "ਬੁੱਕਮਾਰਕ",
|
"navigation_bar.bookmarks": "ਬੁੱਕਮਾਰਕ",
|
||||||
"navigation_bar.direct": "ਨਿੱਜੀ ਜ਼ਿਕਰ",
|
"navigation_bar.direct": "ਨਿੱਜੀ ਜ਼ਿਕਰ",
|
||||||
|
@ -346,11 +380,16 @@
|
||||||
"navigation_bar.follows_and_followers": "ਫ਼ਾਲੋ ਅਤੇ ਫ਼ਾਲੋ ਕਰਨ ਵਾਲੇ",
|
"navigation_bar.follows_and_followers": "ਫ਼ਾਲੋ ਅਤੇ ਫ਼ਾਲੋ ਕਰਨ ਵਾਲੇ",
|
||||||
"navigation_bar.lists": "ਸੂਚੀਆਂ",
|
"navigation_bar.lists": "ਸੂਚੀਆਂ",
|
||||||
"navigation_bar.logout": "ਲਾਗ ਆਉਟ",
|
"navigation_bar.logout": "ਲਾਗ ਆਉਟ",
|
||||||
|
"navigation_bar.more": "ਹੋਰ",
|
||||||
"navigation_bar.mutes": "ਮੌਨ ਕੀਤੇ ਵਰਤੋਂਕਾਰ",
|
"navigation_bar.mutes": "ਮੌਨ ਕੀਤੇ ਵਰਤੋਂਕਾਰ",
|
||||||
"navigation_bar.preferences": "ਪਸੰਦਾਂ",
|
"navigation_bar.preferences": "ਪਸੰਦਾਂ",
|
||||||
|
"navigation_bar.privacy_and_reach": "ਪਰਦੇਦਾਰੀ ਅਤੇ ਪਹੁੰਚ",
|
||||||
"navigation_bar.search": "ਖੋਜੋ",
|
"navigation_bar.search": "ਖੋਜੋ",
|
||||||
|
"navigation_bar.search_trends": "ਖੋਜ / ਰੁਝਾਨ",
|
||||||
"not_signed_in_indicator.not_signed_in": "ਇਹ ਸਰੋਤ ਵਰਤਣ ਲਈ ਤੁਹਾਨੂੰ ਲਾਗਇਨ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।",
|
"not_signed_in_indicator.not_signed_in": "ਇਹ ਸਰੋਤ ਵਰਤਣ ਲਈ ਤੁਹਾਨੂੰ ਲਾਗਇਨ ਕਰਨ ਦੀ ਲੋੜ ਹੈ।",
|
||||||
"notification.admin.sign_up": "{name} ਨੇ ਸਾਈਨ ਅੱਪ ਕੀਤਾ",
|
"notification.admin.sign_up": "{name} ਨੇ ਸਾਈਨ ਅੱਪ ਕੀਤਾ",
|
||||||
|
"notification.favourite": "{name} ਨੇ ਤੁਹਾਡੀ ਪੋਸਟ ਨੂੰ ਪਸੰਦ ਕੀਤਾ",
|
||||||
|
"notification.favourite_pm": "{name} ਨੇ ਤੁਹਾਡੇ ਨਿੱਜੀ ਜ਼ਿਕਰ ਨੂੰ ਪਸੰਦ ਕੀਤਾ",
|
||||||
"notification.follow": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕੀਤਾ",
|
"notification.follow": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕੀਤਾ",
|
||||||
"notification.follow.name_and_others": "{name} ਅਤੇ <a>{count, plural, one {# ਹੋਰ} other {# ਹੋਰਾਂ}}</a> ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕੀਤਾ",
|
"notification.follow.name_and_others": "{name} ਅਤੇ <a>{count, plural, one {# ਹੋਰ} other {# ਹੋਰਾਂ}}</a> ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕੀਤਾ",
|
||||||
"notification.follow_request": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ",
|
"notification.follow_request": "{name} ਨੇ ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕੀਤੀ ਹੈ",
|
||||||
|
@ -365,6 +404,7 @@
|
||||||
"notification.moderation_warning.action_silence": "ਤੁਹਾਡੇ ਖਾਤੇ ਨੂੰ ਸੀਮਿਤ ਕੀਤਾ ਗਿਆ ਹੈ।",
|
"notification.moderation_warning.action_silence": "ਤੁਹਾਡੇ ਖਾਤੇ ਨੂੰ ਸੀਮਿਤ ਕੀਤਾ ਗਿਆ ਹੈ।",
|
||||||
"notification.moderation_warning.action_suspend": "ਤੁਹਾਡੇ ਖਾਤੇ ਨੂੰ ਮੁਅੱਤਲ ਕੀਤਾ ਗਿਆ ਹੈ।",
|
"notification.moderation_warning.action_suspend": "ਤੁਹਾਡੇ ਖਾਤੇ ਨੂੰ ਮੁਅੱਤਲ ਕੀਤਾ ਗਿਆ ਹੈ।",
|
||||||
"notification.reblog": "{name} boosted your status",
|
"notification.reblog": "{name} boosted your status",
|
||||||
|
"notification.relationships_severance_event": "{name} ਨਾਲ ਕਨੈਕਸ਼ਨ ਗੁਆਚੇ",
|
||||||
"notification.relationships_severance_event.learn_more": "ਹੋਰ ਜਾਣੋ",
|
"notification.relationships_severance_event.learn_more": "ਹੋਰ ਜਾਣੋ",
|
||||||
"notification.status": "{name} ਨੇ ਹੁਣੇ ਪੋਸਟ ਕੀਤਾ",
|
"notification.status": "{name} ਨੇ ਹੁਣੇ ਪੋਸਟ ਕੀਤਾ",
|
||||||
"notification.update": "{name} ਨੋ ਪੋਸਟ ਨੂੰ ਸੋਧਿਆ",
|
"notification.update": "{name} ਨੋ ਪੋਸਟ ਨੂੰ ਸੋਧਿਆ",
|
||||||
|
@ -540,7 +580,10 @@
|
||||||
"status.unpin": "ਪਰੋਫਾਈਲ ਤੋਂ ਲਾਹੋ",
|
"status.unpin": "ਪਰੋਫਾਈਲ ਤੋਂ ਲਾਹੋ",
|
||||||
"subscribed_languages.save": "ਤਬਦੀਲੀਆਂ ਸੰਭਾਲੋ",
|
"subscribed_languages.save": "ਤਬਦੀਲੀਆਂ ਸੰਭਾਲੋ",
|
||||||
"tabs_bar.home": "ਘਰ",
|
"tabs_bar.home": "ਘਰ",
|
||||||
|
"tabs_bar.menu": "ਮੇਨੂ",
|
||||||
"tabs_bar.notifications": "ਸੂਚਨਾਵਾਂ",
|
"tabs_bar.notifications": "ਸੂਚਨਾਵਾਂ",
|
||||||
|
"tabs_bar.publish": "ਨਵੀਂ ਪੋਸਟ",
|
||||||
|
"tabs_bar.search": "ਖੋਜੋ",
|
||||||
"terms_of_service.title": "ਸੇਵਾ ਦੀਆਂ ਸ਼ਰਤਾਂ",
|
"terms_of_service.title": "ਸੇਵਾ ਦੀਆਂ ਸ਼ਰਤਾਂ",
|
||||||
"time_remaining.days": "{number, plural, one {# ਦਿਨ} other {# ਦਿਨ}} ਬਾਕੀ",
|
"time_remaining.days": "{number, plural, one {# ਦਿਨ} other {# ਦਿਨ}} ਬਾਕੀ",
|
||||||
"time_remaining.hours": "{number, plural, one {# ਘੰਟਾ} other {# ਘੰਟੇ}} ਬਾਕੀ",
|
"time_remaining.hours": "{number, plural, one {# ਘੰਟਾ} other {# ਘੰਟੇ}} ਬਾਕੀ",
|
||||||
|
@ -561,6 +604,9 @@
|
||||||
"video.expand": "ਵੀਡੀਓ ਨੂੰ ਫੈਲਾਓ",
|
"video.expand": "ਵੀਡੀਓ ਨੂੰ ਫੈਲਾਓ",
|
||||||
"video.fullscreen": "ਪੂਰੀ ਸਕਰੀਨ",
|
"video.fullscreen": "ਪੂਰੀ ਸਕਰੀਨ",
|
||||||
"video.hide": "ਵੀਡੀਓ ਨੂੰ ਲੁਕਾਓ",
|
"video.hide": "ਵੀਡੀਓ ਨੂੰ ਲੁਕਾਓ",
|
||||||
|
"video.mute": "ਮੌਨ",
|
||||||
"video.pause": "ਠਹਿਰੋ",
|
"video.pause": "ਠਹਿਰੋ",
|
||||||
"video.play": "ਚਲਾਓ"
|
"video.play": "ਚਲਾਓ",
|
||||||
|
"video.volume_down": "ਅਵਾਜ਼ ਘਟਾਓ",
|
||||||
|
"video.volume_up": "ਅਵਾਜ਼ ਵਧਾਓ"
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,8 +205,8 @@
|
||||||
"compose_form.poll.switch_to_multiple": "Permitir múltiplas escolhas",
|
"compose_form.poll.switch_to_multiple": "Permitir múltiplas escolhas",
|
||||||
"compose_form.poll.switch_to_single": "Opção única",
|
"compose_form.poll.switch_to_single": "Opção única",
|
||||||
"compose_form.poll.type": "Estilo",
|
"compose_form.poll.type": "Estilo",
|
||||||
"compose_form.publish": "Publicação",
|
"compose_form.publish": "Publicar",
|
||||||
"compose_form.reply": "Resposta",
|
"compose_form.reply": "Responder",
|
||||||
"compose_form.save_changes": "Atualização",
|
"compose_form.save_changes": "Atualização",
|
||||||
"compose_form.spoiler.marked": "Com Aviso de Conteúdo",
|
"compose_form.spoiler.marked": "Com Aviso de Conteúdo",
|
||||||
"compose_form.spoiler.unmarked": "Sem Aviso de Conteúdo",
|
"compose_form.spoiler.unmarked": "Sem Aviso de Conteúdo",
|
||||||
|
|
|
@ -4,17 +4,17 @@
|
||||||
"about.default_locale": "по умолчанию",
|
"about.default_locale": "по умолчанию",
|
||||||
"about.disclaimer": "Mastodon — свободное программное обеспечение с открытым исходным кодом и торговая марка Mastodon gGmbH.",
|
"about.disclaimer": "Mastodon — свободное программное обеспечение с открытым исходным кодом и торговая марка Mastodon gGmbH.",
|
||||||
"about.domain_blocks.no_reason_available": "Причина не указана",
|
"about.domain_blocks.no_reason_available": "Причина не указана",
|
||||||
"about.domain_blocks.preamble": "Mastodon обычно позволяет просматривать содержимое и взаимодействовать с пользователями любых других серверов в федивёрсе. Вот исключения, сделанные конкретно для этого сервера.",
|
"about.domain_blocks.preamble": "Обычно Mastodon даёт вам возможность просматривать содержимое с любых других серверов в федивёрсе и взаимодействовать с их пользователями. Вот исключения, сделанные конкретно для этого сервера:",
|
||||||
"about.domain_blocks.silenced.explanation": "Как правило, вы не увидите профили и контент с этого сервера, если специально не будете их искать или не подпишетесь на них.",
|
"about.domain_blocks.silenced.explanation": "Как правило, вы не увидите профили и содержимое с этого сервера, если только вы не запросите их с помощью поиска или не подпишетесь на пользователя с этого сервера.",
|
||||||
"about.domain_blocks.silenced.title": "Ограничивается",
|
"about.domain_blocks.silenced.title": "Ограничивается",
|
||||||
"about.domain_blocks.suspended.explanation": "Никакие данные с этого сервера не будут обрабатываться, храниться или обмениваться, что делает невозможным любое взаимодействие или связь с пользователями с этого сервера.",
|
"about.domain_blocks.suspended.explanation": "Никакие данные с этого сервера не будут обрабатываться, храниться и обмениваться, что делает невозможным любое взаимодействие и связь с пользователями на этом сервере.",
|
||||||
"about.domain_blocks.suspended.title": "Заблокирован",
|
"about.domain_blocks.suspended.title": "Заблокирован",
|
||||||
"about.language_label": "Язык",
|
"about.language_label": "Язык",
|
||||||
"about.not_available": "Эта информация не указана на данном сервере.",
|
"about.not_available": "Администраторы сервера предпочли не раскрывать эту информацию.",
|
||||||
"about.powered_by": "Децентрализованная социальная сеть на базе {mastodon}",
|
"about.powered_by": "Децентрализованная социальная сеть на базе {mastodon}",
|
||||||
"about.rules": "Правила сервера",
|
"about.rules": "Правила сервера",
|
||||||
"account.account_note_header": "Личная заметка",
|
"account.account_note_header": "Личная заметка",
|
||||||
"account.add_or_remove_from_list": "Управление списками",
|
"account.add_or_remove_from_list": "Добавить в списки",
|
||||||
"account.badges.bot": "Бот",
|
"account.badges.bot": "Бот",
|
||||||
"account.badges.group": "Группа",
|
"account.badges.group": "Группа",
|
||||||
"account.block": "Заблокировать @{name}",
|
"account.block": "Заблокировать @{name}",
|
||||||
|
@ -25,10 +25,10 @@
|
||||||
"account.cancel_follow_request": "Отозвать запрос на подписку",
|
"account.cancel_follow_request": "Отозвать запрос на подписку",
|
||||||
"account.copy": "Копировать ссылку на профиль",
|
"account.copy": "Копировать ссылку на профиль",
|
||||||
"account.direct": "Упомянуть @{name} лично",
|
"account.direct": "Упомянуть @{name} лично",
|
||||||
"account.disable_notifications": "Не уведомлять о постах от @{name}",
|
"account.disable_notifications": "Не уведомлять о постах пользователя @{name}",
|
||||||
"account.domain_blocking": "Домен заблокирован",
|
"account.domain_blocking": "Домен заблокирован",
|
||||||
"account.edit_profile": "Редактировать",
|
"account.edit_profile": "Редактировать",
|
||||||
"account.enable_notifications": "Уведомлять о постах от @{name}",
|
"account.enable_notifications": "Уведомлять о постах пользователя @{name}",
|
||||||
"account.endorse": "Рекомендовать в профиле",
|
"account.endorse": "Рекомендовать в профиле",
|
||||||
"account.familiar_followers_many": "В подписках у {name1}, {name2}, и ещё {othersCount, plural, one {# человека, которого вы знаете} other {# человек, которых вы знаете}}",
|
"account.familiar_followers_many": "В подписках у {name1}, {name2}, и ещё {othersCount, plural, one {# человека, которого вы знаете} other {# человек, которых вы знаете}}",
|
||||||
"account.familiar_followers_one": "В подписках у {name1}",
|
"account.familiar_followers_one": "В подписках у {name1}",
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
"account.featured": "Рекомендации",
|
"account.featured": "Рекомендации",
|
||||||
"account.featured.accounts": "Профили",
|
"account.featured.accounts": "Профили",
|
||||||
"account.featured.hashtags": "Хештеги",
|
"account.featured.hashtags": "Хештеги",
|
||||||
"account.featured_tags.last_status_at": "Последний пост {date}",
|
"account.featured_tags.last_status_at": "Последний пост опубликован {date}",
|
||||||
"account.featured_tags.last_status_never": "Нет постов",
|
"account.featured_tags.last_status_never": "Нет постов",
|
||||||
"account.follow": "Подписаться",
|
"account.follow": "Подписаться",
|
||||||
"account.follow_back": "Подписаться в ответ",
|
"account.follow_back": "Подписаться в ответ",
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
"account.mention": "Упомянуть @{name}",
|
"account.mention": "Упомянуть @{name}",
|
||||||
"account.moved_to": "У {name} теперь новая учётная запись:",
|
"account.moved_to": "У {name} теперь новая учётная запись:",
|
||||||
"account.mute": "Игнорировать @{name}",
|
"account.mute": "Игнорировать @{name}",
|
||||||
"account.mute_notifications_short": "Отключить уведомления",
|
"account.mute_notifications_short": "Скрыть уведомления",
|
||||||
"account.mute_short": "Игнорировать",
|
"account.mute_short": "Игнорировать",
|
||||||
"account.muted": "Игнорируется",
|
"account.muted": "Игнорируется",
|
||||||
"account.muting": "Игнорируется",
|
"account.muting": "Игнорируется",
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
"account.unendorse": "Не рекомендовать в профиле",
|
"account.unendorse": "Не рекомендовать в профиле",
|
||||||
"account.unfollow": "Отписаться",
|
"account.unfollow": "Отписаться",
|
||||||
"account.unmute": "Не игнорировать @{name}",
|
"account.unmute": "Не игнорировать @{name}",
|
||||||
"account.unmute_notifications_short": "Включить уведомления",
|
"account.unmute_notifications_short": "Показать уведомления",
|
||||||
"account.unmute_short": "Не игнорировать",
|
"account.unmute_short": "Не игнорировать",
|
||||||
"account_note.placeholder": "Текст заметки",
|
"account_note.placeholder": "Текст заметки",
|
||||||
"admin.dashboard.daily_retention": "Уровень удержания пользователей после регистрации, в днях",
|
"admin.dashboard.daily_retention": "Уровень удержания пользователей после регистрации, в днях",
|
||||||
|
@ -129,10 +129,10 @@
|
||||||
"annual_report.summary.thanks": "Спасибо за то, что были вместе с Mastodon!",
|
"annual_report.summary.thanks": "Спасибо за то, что были вместе с Mastodon!",
|
||||||
"attachments_list.unprocessed": "(не обработан)",
|
"attachments_list.unprocessed": "(не обработан)",
|
||||||
"audio.hide": "Скрыть аудио",
|
"audio.hide": "Скрыть аудио",
|
||||||
"block_modal.remote_users_caveat": "Мы попросим сервер {domain} уважать ваше решение, однако соблюдение им блокировки не гарантировано, поскольку некоторые серверы могут по-разному обрабатывать запросы. Публичные посты по-прежнему могут быть видны неавторизованным пользователям.",
|
"block_modal.remote_users_caveat": "Мы попросим сервер {domain} уважать ваше решение, однако нельзя гарантировать, что он будет соблюдать блокировку, поскольку некоторые серверы могут по-разному обрабатывать запросы. Публичные посты по-прежнему могут быть видны неавторизованным пользователям.",
|
||||||
"block_modal.show_less": "Показать меньше",
|
"block_modal.show_less": "Показать меньше",
|
||||||
"block_modal.show_more": "Показать больше",
|
"block_modal.show_more": "Показать больше",
|
||||||
"block_modal.they_cant_mention": "Он не сможет упоминать вас или подписаться на вас.",
|
"block_modal.they_cant_mention": "Он не сможет ни упоминать вас, ни подписаться на вас.",
|
||||||
"block_modal.they_cant_see_posts": "Он не сможет видеть ваши посты, а вы не будете видеть его посты.",
|
"block_modal.they_cant_see_posts": "Он не сможет видеть ваши посты, а вы не будете видеть его посты.",
|
||||||
"block_modal.they_will_know": "Он будет знать, что вы его блокируете.",
|
"block_modal.they_will_know": "Он будет знать, что вы его блокируете.",
|
||||||
"block_modal.title": "Заблокировать пользователя?",
|
"block_modal.title": "Заблокировать пользователя?",
|
||||||
|
@ -141,21 +141,21 @@
|
||||||
"boost_modal.reblog": "Продвинуть пост?",
|
"boost_modal.reblog": "Продвинуть пост?",
|
||||||
"boost_modal.undo_reblog": "Отменить продвижение?",
|
"boost_modal.undo_reblog": "Отменить продвижение?",
|
||||||
"bundle_column_error.copy_stacktrace": "Копировать отчёт об ошибке",
|
"bundle_column_error.copy_stacktrace": "Копировать отчёт об ошибке",
|
||||||
"bundle_column_error.error.body": "Запрошенная страница не может быть отображена. Это может быть вызвано ошибкой в нашем коде или проблемой совместимости браузера.",
|
"bundle_column_error.error.body": "Запрошенная страница не может быть отображена. Это могло произойти из-за ошибки в нашем коде или из-за проблемы совместимости браузера.",
|
||||||
"bundle_column_error.error.title": "О нет!",
|
"bundle_column_error.error.title": "О нет!",
|
||||||
"bundle_column_error.network.body": "При загрузке этой страницы произошла ошибка. Это может быть вызвано временными проблемами с вашим подключением к интернету или ошибкой на сервере.",
|
"bundle_column_error.network.body": "При загрузке этой страницы произошла ошибка. Она могла быть вызвана временными проблемами либо с вашим подключением к интернету, либо с этим сервером.",
|
||||||
"bundle_column_error.network.title": "Ошибка сети",
|
"bundle_column_error.network.title": "Ошибка сети",
|
||||||
"bundle_column_error.retry": "Попробовать снова",
|
"bundle_column_error.retry": "Попробовать снова",
|
||||||
"bundle_column_error.return": "Вернуться на главную",
|
"bundle_column_error.return": "Вернуться на главную",
|
||||||
"bundle_column_error.routing.body": "Запрошенная страница не найдена. Вы уверены, что в адресной строке указан правильный URL?",
|
"bundle_column_error.routing.body": "Запрошенная страница не найдена. Вы уверены, что в адресной строке указан правильный URL?",
|
||||||
"bundle_column_error.routing.title": "404",
|
"bundle_column_error.routing.title": "404",
|
||||||
"bundle_modal_error.close": "Закрыть",
|
"bundle_modal_error.close": "Закрыть",
|
||||||
"bundle_modal_error.message": "Что-то пошло не так при загрузке этой страницы.",
|
"bundle_modal_error.message": "Кое-что пошло не так при загрузке этой страницы.",
|
||||||
"bundle_modal_error.retry": "Попробовать снова",
|
"bundle_modal_error.retry": "Попробовать снова",
|
||||||
"closed_registrations.other_server_instructions": "Поскольку Mastodon децентрализован, вы можете зарегистрироваться на другом сервере и всё равно взаимодействовать с этим сервером.",
|
"closed_registrations.other_server_instructions": "Благодаря тому что Mastodon децентрализован, вы можете взаимодействовать с этим сервером, даже если зарегистрируетесь на другом сервере.",
|
||||||
"closed_registrations_modal.description": "Зарегистрироваться на {domain} сейчас не выйдет, но имейте в виду, что вам не нужна учётная запись именно на {domain}, чтобы использовать Mastodon.",
|
"closed_registrations_modal.description": "Зарегистрироваться на {domain} сейчас не выйдет, но имейте в виду, что вам не нужна учётная запись именно на {domain}, чтобы использовать Mastodon.",
|
||||||
"closed_registrations_modal.find_another_server": "Найти другой сервер",
|
"closed_registrations_modal.find_another_server": "Найти другой сервер",
|
||||||
"closed_registrations_modal.preamble": "Mastodon децентрализован, поэтому независимо от того, где именно вы зарегистрируетесь, вы сможете подписываться и взаимодействовать с кем угодно на этом сервере. Вы даже можете создать свой собственный сервер!",
|
"closed_registrations_modal.preamble": "Mastodon децентрализован, поэтому независимо от того, где именно вы зарегистрируетесь, вы сможете подписываться на кого угодно и взаимодействовать с кем угодно на этом сервере. Вы даже можете создать свой собственный сервер!",
|
||||||
"closed_registrations_modal.title": "Регистрация в Mastodon",
|
"closed_registrations_modal.title": "Регистрация в Mastodon",
|
||||||
"column.about": "О проекте",
|
"column.about": "О проекте",
|
||||||
"column.blocks": "Заблокированные пользователи",
|
"column.blocks": "Заблокированные пользователи",
|
||||||
|
@ -163,14 +163,14 @@
|
||||||
"column.community": "Локальная лента",
|
"column.community": "Локальная лента",
|
||||||
"column.create_list": "Создать список",
|
"column.create_list": "Создать список",
|
||||||
"column.direct": "Личные упоминания",
|
"column.direct": "Личные упоминания",
|
||||||
"column.directory": "Просмотр профилей",
|
"column.directory": "Каталог профилей",
|
||||||
"column.domain_blocks": "Заблокированные домены",
|
"column.domain_blocks": "Заблокированные домены",
|
||||||
"column.edit_list": "Редактировать список",
|
"column.edit_list": "Редактировать список",
|
||||||
"column.favourites": "Избранное",
|
"column.favourites": "Избранное",
|
||||||
"column.firehose": "Живая лента",
|
"column.firehose": "Живая лента",
|
||||||
"column.follow_requests": "Запросы на подписку",
|
"column.follow_requests": "Запросы на подписку",
|
||||||
"column.home": "Главная",
|
"column.home": "Главная",
|
||||||
"column.list_members": "Добавить или удалить из списка",
|
"column.list_members": "Пользователи в списке",
|
||||||
"column.lists": "Списки",
|
"column.lists": "Списки",
|
||||||
"column.mutes": "Игнорируемые пользователи",
|
"column.mutes": "Игнорируемые пользователи",
|
||||||
"column.notifications": "Уведомления",
|
"column.notifications": "Уведомления",
|
||||||
|
@ -240,7 +240,7 @@
|
||||||
"confirmations.missing_alt_text.title": "Добавить альтернативный текст?",
|
"confirmations.missing_alt_text.title": "Добавить альтернативный текст?",
|
||||||
"confirmations.mute.confirm": "Игнорировать",
|
"confirmations.mute.confirm": "Игнорировать",
|
||||||
"confirmations.redraft.confirm": "Удалить и исправить",
|
"confirmations.redraft.confirm": "Удалить и исправить",
|
||||||
"confirmations.redraft.message": "Вы уверены, что хотите удалить этот пост и создать его заново? Взаимодействия, такие как добавление в избранное или продвижение, будут потеряны, а ответы к оригинальному посту перестанут на него ссылаться.",
|
"confirmations.redraft.message": "Вы уверены, что хотите удалить этот пост и создать его заново? Взаимодействия, такие как добавление в избранное и продвижение, будут потеряны, а ответы к оригинальному посту перестанут на него ссылаться.",
|
||||||
"confirmations.redraft.title": "Удалить и создать пост заново?",
|
"confirmations.redraft.title": "Удалить и создать пост заново?",
|
||||||
"confirmations.remove_from_followers.confirm": "Убрать подписчика",
|
"confirmations.remove_from_followers.confirm": "Убрать подписчика",
|
||||||
"confirmations.remove_from_followers.message": "Пользователь {name} перестанет быть подписан на вас. Продолжить?",
|
"confirmations.remove_from_followers.message": "Пользователь {name} перестанет быть подписан на вас. Продолжить?",
|
||||||
|
@ -275,9 +275,9 @@
|
||||||
"domain_block_modal.title": "Заблокировать домен?",
|
"domain_block_modal.title": "Заблокировать домен?",
|
||||||
"domain_block_modal.you_will_lose_num_followers": "Вы потеряете {followersCount, plural, one {{followersCountDisplay} подписчика} few {{followersCountDisplay} подписчика} other {{followersCountDisplay} подписчиков}} и {followingCount, plural, one {{followingCountDisplay} подписку} few {{followingCountDisplay} подписки} other {{followingCountDisplay} подписок}}.",
|
"domain_block_modal.you_will_lose_num_followers": "Вы потеряете {followersCount, plural, one {{followersCountDisplay} подписчика} few {{followersCountDisplay} подписчика} other {{followersCountDisplay} подписчиков}} и {followingCount, plural, one {{followingCountDisplay} подписку} few {{followingCountDisplay} подписки} other {{followingCountDisplay} подписок}}.",
|
||||||
"domain_block_modal.you_will_lose_relationships": "Вы потеряете все подписки и всех подписчиков с этого сервера.",
|
"domain_block_modal.you_will_lose_relationships": "Вы потеряете все подписки и всех подписчиков с этого сервера.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Вы не будете видеть посты или уведомления от пользователей с этого сервера.",
|
"domain_block_modal.you_wont_see_posts": "Вы не будете видеть посты и уведомления от пользователей с этого сервера.",
|
||||||
"domain_pill.activitypub_lets_connect": "Благодаря ему вы можете связываться и взаимодействовать не только с пользователями Mastodon, но и с пользователями других платформ.",
|
"domain_pill.activitypub_lets_connect": "Благодаря ему вы можете связываться и взаимодействовать не только с пользователями Mastodon, но и с пользователями других платформ.",
|
||||||
"domain_pill.activitypub_like_language": "ActivityPub это язык, на котором Mastodon говорит с другими социальными сетями.",
|
"domain_pill.activitypub_like_language": "ActivityPub — это язык, на котором Mastodon говорит с другими социальными сетями.",
|
||||||
"domain_pill.server": "Сервер",
|
"domain_pill.server": "Сервер",
|
||||||
"domain_pill.their_handle": "Адрес пользователя:",
|
"domain_pill.their_handle": "Адрес пользователя:",
|
||||||
"domain_pill.their_server": "Цифровой дом пользователя, где находятся все его посты.",
|
"domain_pill.their_server": "Цифровой дом пользователя, где находятся все его посты.",
|
||||||
|
@ -319,8 +319,8 @@
|
||||||
"empty_column.direct": "Вы ещё не упоминали кого-либо и сами не были ни разу упомянуты лично. Все личные упоминания будут показаны здесь.",
|
"empty_column.direct": "Вы ещё не упоминали кого-либо и сами не были ни разу упомянуты лично. Все личные упоминания будут показаны здесь.",
|
||||||
"empty_column.domain_blocks": "Заблокированных доменов пока нет.",
|
"empty_column.domain_blocks": "Заблокированных доменов пока нет.",
|
||||||
"empty_column.explore_statuses": "Сейчас нет популярных постов. Проверьте позже!",
|
"empty_column.explore_statuses": "Сейчас нет популярных постов. Проверьте позже!",
|
||||||
"empty_column.favourited_statuses": "Вы ещё не добавили ни один пост в избранное. Все добавленные вами в избранное посты будут показаны здесь.",
|
"empty_column.favourited_statuses": "Вы ещё не добавили ни одного поста в избранное. Все добавленные вами в избранное посты будут показаны здесь.",
|
||||||
"empty_column.favourites": "Никто ещё не добавил этот пост в избранное. Все пользователи, добавившие этот пост в избранное, будут показаны здесь.",
|
"empty_column.favourites": "Никто ещё не добавил этот пост в избранное. Все пользователи, которые добавят этот пост в избранное, будут показаны здесь.",
|
||||||
"empty_column.follow_requests": "Вам ещё не приходили запросы на подписку. Все новые запросы будут показаны здесь.",
|
"empty_column.follow_requests": "Вам ещё не приходили запросы на подписку. Все новые запросы будут показаны здесь.",
|
||||||
"empty_column.followed_tags": "Вы ещё не подписались ни на один хештег. Все хештеги, на которые вы подписаны, будут показаны здесь.",
|
"empty_column.followed_tags": "Вы ещё не подписались ни на один хештег. Все хештеги, на которые вы подписаны, будут показаны здесь.",
|
||||||
"empty_column.hashtag": "С этим хештегом пока ещё никто ничего не опубликовал.",
|
"empty_column.hashtag": "С этим хештегом пока ещё никто ничего не опубликовал.",
|
||||||
|
@ -346,7 +346,7 @@
|
||||||
"featured_carousel.post": "Пост",
|
"featured_carousel.post": "Пост",
|
||||||
"featured_carousel.previous": "Предыдущий",
|
"featured_carousel.previous": "Предыдущий",
|
||||||
"featured_carousel.slide": "{index} из {total}",
|
"featured_carousel.slide": "{index} из {total}",
|
||||||
"filter_modal.added.context_mismatch_explanation": "Этот фильтр не применяется в том контексте, в котором вы видели этот пост. Если вы хотите, чтобы пост был отфильтрован в этом контексте, необходимо редактировать фильтр.",
|
"filter_modal.added.context_mismatch_explanation": "Этот фильтр не применяется в том контексте, в котором вы видели этот пост. Если вы хотите, чтобы пост был отфильтрован в текущем контексте, необходимо редактировать фильтр.",
|
||||||
"filter_modal.added.context_mismatch_title": "Несоответствие контекста!",
|
"filter_modal.added.context_mismatch_title": "Несоответствие контекста!",
|
||||||
"filter_modal.added.expired_explanation": "Этот фильтр истёк. Чтобы он был применён, вам нужно изменить срок действия фильтра.",
|
"filter_modal.added.expired_explanation": "Этот фильтр истёк. Чтобы он был применён, вам нужно изменить срок действия фильтра.",
|
||||||
"filter_modal.added.expired_title": "Истёкший фильтр!",
|
"filter_modal.added.expired_title": "Истёкший фильтр!",
|
||||||
|
@ -358,7 +358,7 @@
|
||||||
"filter_modal.select_filter.context_mismatch": "не применяется в этом контексте",
|
"filter_modal.select_filter.context_mismatch": "не применяется в этом контексте",
|
||||||
"filter_modal.select_filter.expired": "истёкший",
|
"filter_modal.select_filter.expired": "истёкший",
|
||||||
"filter_modal.select_filter.prompt_new": "Новый фильтр: {name}",
|
"filter_modal.select_filter.prompt_new": "Новый фильтр: {name}",
|
||||||
"filter_modal.select_filter.search": "Поиск или название нового фильтра",
|
"filter_modal.select_filter.search": "Поиск (или введите название нового фильтра)",
|
||||||
"filter_modal.select_filter.subtitle": "Используйте существующий фильтр или создайте новый",
|
"filter_modal.select_filter.subtitle": "Используйте существующий фильтр или создайте новый",
|
||||||
"filter_modal.select_filter.title": "Фильтровать этот пост",
|
"filter_modal.select_filter.title": "Фильтровать этот пост",
|
||||||
"filter_modal.title.status": "Фильтровать пост",
|
"filter_modal.title.status": "Фильтровать пост",
|
||||||
|
@ -413,18 +413,18 @@
|
||||||
"hashtag.counter_by_uses": "{count, plural, one {{counter} пост} few {{counter} поста} other {{counter} постов}}",
|
"hashtag.counter_by_uses": "{count, plural, one {{counter} пост} few {{counter} поста} other {{counter} постов}}",
|
||||||
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} пост} few {{counter} поста} other {{counter} постов}} сегодня",
|
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} пост} few {{counter} поста} other {{counter} постов}} сегодня",
|
||||||
"hashtag.feature": "Рекомендовать в профиле",
|
"hashtag.feature": "Рекомендовать в профиле",
|
||||||
"hashtag.follow": "Подписаться на новые посты",
|
"hashtag.follow": "Подписаться на хештег",
|
||||||
"hashtag.mute": "Игнорировать #{hashtag}",
|
"hashtag.mute": "Игнорировать #{hashtag}",
|
||||||
"hashtag.unfeature": "Не рекомендовать в профиле",
|
"hashtag.unfeature": "Не рекомендовать в профиле",
|
||||||
"hashtag.unfollow": "Отписаться от новых постов",
|
"hashtag.unfollow": "Отписаться от хештега",
|
||||||
"hashtags.and_other": "…и {count, plural, other {ещё #}}",
|
"hashtags.and_other": "…и {count, plural, other {ещё #}}",
|
||||||
"hints.profiles.followers_may_be_missing": "Некоторые подписчики этого профиля могут отсутствовать.",
|
"hints.profiles.followers_may_be_missing": "Некоторые подписчики этого профиля могут здесь отсутствовать.",
|
||||||
"hints.profiles.follows_may_be_missing": "Некоторые подписки этого профиля могут отсутствовать.",
|
"hints.profiles.follows_may_be_missing": "Некоторые подписки этого профиля могут здесь отсутствовать.",
|
||||||
"hints.profiles.posts_may_be_missing": "Некоторые посты в этом профиле могут отсутствовать.",
|
"hints.profiles.posts_may_be_missing": "Некоторые посты в этом профиле могут здесь отсутствовать.",
|
||||||
"hints.profiles.see_more_followers": "Перейдите на {domain}, чтобы увидеть всех подписчиков",
|
"hints.profiles.see_more_followers": "Перейдите на {domain}, чтобы увидеть всех подписчиков",
|
||||||
"hints.profiles.see_more_follows": "Перейдите на {domain}, чтобы увидеть все подписки",
|
"hints.profiles.see_more_follows": "Перейдите на {domain}, чтобы увидеть все подписки",
|
||||||
"hints.profiles.see_more_posts": "Перейдите на {domain}, чтобы увидеть все посты",
|
"hints.profiles.see_more_posts": "Перейдите на {domain}, чтобы увидеть все посты",
|
||||||
"hints.threads.replies_may_be_missing": "Некоторые ответы с других серверов могут отсутствовать.",
|
"hints.threads.replies_may_be_missing": "Некоторые ответы с других серверов могут здесь отсутствовать.",
|
||||||
"hints.threads.see_more": "Перейдите на {domain}, чтобы увидеть все ответы",
|
"hints.threads.see_more": "Перейдите на {domain}, чтобы увидеть все ответы",
|
||||||
"home.column_settings.show_quotes": "Показывать цитирования",
|
"home.column_settings.show_quotes": "Показывать цитирования",
|
||||||
"home.column_settings.show_reblogs": "Показывать продвижения",
|
"home.column_settings.show_reblogs": "Показывать продвижения",
|
||||||
|
@ -466,7 +466,7 @@
|
||||||
"intervals.full.hours": "{number, plural, one {# час} few {# часа} other {# часов}}",
|
"intervals.full.hours": "{number, plural, one {# час} few {# часа} other {# часов}}",
|
||||||
"intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} other {# минут}}",
|
"intervals.full.minutes": "{number, plural, one {# минута} few {# минуты} other {# минут}}",
|
||||||
"keyboard_shortcuts.back": "перейти назад",
|
"keyboard_shortcuts.back": "перейти назад",
|
||||||
"keyboard_shortcuts.blocked": "открыть список заблокированных",
|
"keyboard_shortcuts.blocked": "открыть список заблокированных пользователей",
|
||||||
"keyboard_shortcuts.boost": "продвинуть пост",
|
"keyboard_shortcuts.boost": "продвинуть пост",
|
||||||
"keyboard_shortcuts.column": "фокус на одном из столбцов",
|
"keyboard_shortcuts.column": "фокус на одном из столбцов",
|
||||||
"keyboard_shortcuts.compose": "фокус на поле ввода",
|
"keyboard_shortcuts.compose": "фокус на поле ввода",
|
||||||
|
@ -483,7 +483,7 @@
|
||||||
"keyboard_shortcuts.legend": "показать эту справку",
|
"keyboard_shortcuts.legend": "показать эту справку",
|
||||||
"keyboard_shortcuts.local": "перейти к локальной ленте",
|
"keyboard_shortcuts.local": "перейти к локальной ленте",
|
||||||
"keyboard_shortcuts.mention": "упомянуть автора поста",
|
"keyboard_shortcuts.mention": "упомянуть автора поста",
|
||||||
"keyboard_shortcuts.muted": "открыть список игнорируемых",
|
"keyboard_shortcuts.muted": "открыть список игнорируемых пользователей",
|
||||||
"keyboard_shortcuts.my_profile": "перейти к своему профилю",
|
"keyboard_shortcuts.my_profile": "перейти к своему профилю",
|
||||||
"keyboard_shortcuts.notifications": "перейти к уведомлениям",
|
"keyboard_shortcuts.notifications": "перейти к уведомлениям",
|
||||||
"keyboard_shortcuts.open_media": "открыть медиа",
|
"keyboard_shortcuts.open_media": "открыть медиа",
|
||||||
|
@ -546,7 +546,7 @@
|
||||||
"mute_modal.they_can_mention_and_follow": "Он сможет упоминать вас и подписаться на вас, но вы этого не увидите.",
|
"mute_modal.they_can_mention_and_follow": "Он сможет упоминать вас и подписаться на вас, но вы этого не увидите.",
|
||||||
"mute_modal.they_wont_know": "Он не будет знать, что вы его игнорируете.",
|
"mute_modal.they_wont_know": "Он не будет знать, что вы его игнорируете.",
|
||||||
"mute_modal.title": "Игнорировать пользователя?",
|
"mute_modal.title": "Игнорировать пользователя?",
|
||||||
"mute_modal.you_wont_see_mentions": "Вы не увидите посты, которые его упоминают.",
|
"mute_modal.you_wont_see_mentions": "Вы не будете видеть посты, упоминающие его.",
|
||||||
"mute_modal.you_wont_see_posts": "Он по-прежнему сможет видеть ваши посты, но вы не будете видеть его посты.",
|
"mute_modal.you_wont_see_posts": "Он по-прежнему сможет видеть ваши посты, но вы не будете видеть его посты.",
|
||||||
"navigation_bar.about": "О проекте",
|
"navigation_bar.about": "О проекте",
|
||||||
"navigation_bar.account_settings": "Пароль и безопасность",
|
"navigation_bar.account_settings": "Пароль и безопасность",
|
||||||
|
@ -607,9 +607,9 @@
|
||||||
"notification.moderation_warning": "Модераторы вынесли вам предупреждение",
|
"notification.moderation_warning": "Модераторы вынесли вам предупреждение",
|
||||||
"notification.moderation_warning.action_delete_statuses": "Некоторые ваши посты были удалены.",
|
"notification.moderation_warning.action_delete_statuses": "Некоторые ваши посты были удалены.",
|
||||||
"notification.moderation_warning.action_disable": "Ваша учётная запись была отключена.",
|
"notification.moderation_warning.action_disable": "Ваша учётная запись была отключена.",
|
||||||
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Некоторые ваши посты были отмечены как контент деликатного характера.",
|
"notification.moderation_warning.action_mark_statuses_as_sensitive": "Некоторые ваши посты были отмечены как содержимое деликатного характера.",
|
||||||
"notification.moderation_warning.action_none": "Модераторы вынесли вам предупреждение.",
|
"notification.moderation_warning.action_none": "Модераторы вынесли вам предупреждение.",
|
||||||
"notification.moderation_warning.action_sensitive": "С этого момента все ваши новые посты будут отмечены как контент деликатного характера.",
|
"notification.moderation_warning.action_sensitive": "С этого момента все ваши новые посты будут отмечены как содержимое деликатного характера.",
|
||||||
"notification.moderation_warning.action_silence": "Ваша учётная запись была ограничена.",
|
"notification.moderation_warning.action_silence": "Ваша учётная запись была ограничена.",
|
||||||
"notification.moderation_warning.action_suspend": "Ваша учётная запись была заблокирована.",
|
"notification.moderation_warning.action_suspend": "Ваша учётная запись была заблокирована.",
|
||||||
"notification.own_poll": "Ваш опрос завершился",
|
"notification.own_poll": "Ваш опрос завершился",
|
||||||
|
@ -617,10 +617,10 @@
|
||||||
"notification.reblog": "{name} продвинул(а) ваш пост",
|
"notification.reblog": "{name} продвинул(а) ваш пост",
|
||||||
"notification.reblog.name_and_others_with_link": "{name} и ещё <a>{count, plural, one {# пользователь} few {# пользователя} other {# пользователей}}</a> продвинули ваш пост",
|
"notification.reblog.name_and_others_with_link": "{name} и ещё <a>{count, plural, one {# пользователь} few {# пользователя} other {# пользователей}}</a> продвинули ваш пост",
|
||||||
"notification.relationships_severance_event": "Разорвана связь с {name}",
|
"notification.relationships_severance_event": "Разорвана связь с {name}",
|
||||||
"notification.relationships_severance_event.account_suspension": "Администратор сервера {from} заблокировал сервер {target}, поэтому вы больше не сможете получать обновления от людей с этого сервера или взаимодействовать с ними.",
|
"notification.relationships_severance_event.account_suspension": "Администратор сервера {from} заблокировал сервер {target}, поэтому вы больше не сможете получать обновления от людей с этого сервера и взаимодействовать с ними.",
|
||||||
"notification.relationships_severance_event.domain_block": "Администратор сервера {from} заблокировал сервер {target}, где размещены учётные записи у {followersCount} ваших подписчиков и {followingCount, plural, one {# пользователя, на которого вы подписаны} other {# пользователей, на которых вы подписаны}}.",
|
"notification.relationships_severance_event.domain_block": "Администратор сервера {from} заблокировал сервер {target}, где размещены учётные записи {followersCount} ваших подписчиков и {followingCount, plural, one {# пользователя, на которого вы подписаны} other {# пользователей, на которых вы подписаны}}.",
|
||||||
"notification.relationships_severance_event.learn_more": "Узнать больше",
|
"notification.relationships_severance_event.learn_more": "Узнать больше",
|
||||||
"notification.relationships_severance_event.user_domain_block": "Вы заблокировали сервер {target}, где размещены учётные записи у {followersCount} ваших подписчиков и {followingCount, plural, one {# пользователя, на которого вы подписаны} other {# пользователей, на которых вы подписаны}}.",
|
"notification.relationships_severance_event.user_domain_block": "Вы заблокировали сервер {target}, где размещены учётные записи {followersCount} ваших подписчиков и {followingCount, plural, one {# пользователя, на которого вы подписаны} other {# пользователей, на которых вы подписаны}}.",
|
||||||
"notification.status": "{name} опубликовал(а) новый пост",
|
"notification.status": "{name} опубликовал(а) новый пост",
|
||||||
"notification.update": "{name} отредактировал(а) пост",
|
"notification.update": "{name} отредактировал(а) пост",
|
||||||
"notification_requests.accept": "Принять",
|
"notification_requests.accept": "Принять",
|
||||||
|
@ -691,11 +691,11 @@
|
||||||
"notifications.policy.filter_not_followers_title": "Люди, не подписанные на вас",
|
"notifications.policy.filter_not_followers_title": "Люди, не подписанные на вас",
|
||||||
"notifications.policy.filter_not_following_hint": "Пока вы не одобрите их вручную",
|
"notifications.policy.filter_not_following_hint": "Пока вы не одобрите их вручную",
|
||||||
"notifications.policy.filter_not_following_title": "Люди, на которых вы не подписаны",
|
"notifications.policy.filter_not_following_title": "Люди, на которых вы не подписаны",
|
||||||
"notifications.policy.filter_private_mentions_hint": "Фильтруются, если только это не ответ на ваше собственное упоминание или если вы подписаны на отправителя",
|
"notifications.policy.filter_private_mentions_hint": "Не фильтруются ответы на ваши собственные упоминания, а также личные упоминания от пользователей, на которых вы подписаны",
|
||||||
"notifications.policy.filter_private_mentions_title": "Нежелательные личные упоминания",
|
"notifications.policy.filter_private_mentions_title": "Нежелательные личные упоминания",
|
||||||
"notifications.policy.title": "Управление уведомлениями",
|
"notifications.policy.title": "Управление уведомлениями",
|
||||||
"notifications_permission_banner.enable": "Включить уведомления",
|
"notifications_permission_banner.enable": "Включить уведомления",
|
||||||
"notifications_permission_banner.how_to_control": "Чтобы получать уведомления, даже когда Mastodon закрыт, включите уведомления на рабочем столе. После того как вы их включите, вы сможете тонко настроить, о каких видах взаимодействий вы будете оповещены через уведомления на рабочем столе, нажав на кнопку {icon} выше.",
|
"notifications_permission_banner.how_to_control": "Чтобы получать уведомления, даже когда Mastodon закрыт, включите уведомления на рабочем столе. После того как вы их включите, вы сможете тонко настроить виды взаимодействий, о которых вы будете оповещены через уведомления на рабочем столе, нажав на кнопку {icon} выше.",
|
||||||
"notifications_permission_banner.title": "Будьте в курсе происходящего",
|
"notifications_permission_banner.title": "Будьте в курсе происходящего",
|
||||||
"onboarding.follows.back": "Назад",
|
"onboarding.follows.back": "Назад",
|
||||||
"onboarding.follows.done": "Готово",
|
"onboarding.follows.done": "Готово",
|
||||||
|
@ -707,7 +707,7 @@
|
||||||
"onboarding.profile.display_name": "Отображаемое имя",
|
"onboarding.profile.display_name": "Отображаемое имя",
|
||||||
"onboarding.profile.display_name_hint": "Ваше полное имя или псевдоним…",
|
"onboarding.profile.display_name_hint": "Ваше полное имя или псевдоним…",
|
||||||
"onboarding.profile.note": "О себе",
|
"onboarding.profile.note": "О себе",
|
||||||
"onboarding.profile.note_hint": "Вы можете @упоминать других людей или использовать #хештеги…",
|
"onboarding.profile.note_hint": "Вы можете @упоминать других людей, а также использовать #хештеги…",
|
||||||
"onboarding.profile.save_and_continue": "Сохранить и продолжить",
|
"onboarding.profile.save_and_continue": "Сохранить и продолжить",
|
||||||
"onboarding.profile.title": "Создайте свой профиль",
|
"onboarding.profile.title": "Создайте свой профиль",
|
||||||
"onboarding.profile.upload_avatar": "Загрузить фото профиля",
|
"onboarding.profile.upload_avatar": "Загрузить фото профиля",
|
||||||
|
@ -733,7 +733,7 @@
|
||||||
"privacy.public.long": "Для кого угодно в интернете",
|
"privacy.public.long": "Для кого угодно в интернете",
|
||||||
"privacy.public.short": "Публичный",
|
"privacy.public.short": "Публичный",
|
||||||
"privacy.unlisted.additional": "Похоже на «Публичный» за исключением того, что пост не появится ни в живых лентах, ни в лентах хештегов, ни в разделе «Актуальное», ни в поиске Mastodon, даже если вы разрешили поиск по своим постам в настройках профиля.",
|
"privacy.unlisted.additional": "Похоже на «Публичный» за исключением того, что пост не появится ни в живых лентах, ни в лентах хештегов, ни в разделе «Актуальное», ни в поиске Mastodon, даже если вы разрешили поиск по своим постам в настройках профиля.",
|
||||||
"privacy.unlisted.long": "Меньше алгоритмических фанфар",
|
"privacy.unlisted.long": "Без продвижения алгоритмами",
|
||||||
"privacy.unlisted.short": "Тихий публичный",
|
"privacy.unlisted.short": "Тихий публичный",
|
||||||
"privacy_policy.last_updated": "Последнее обновление: {date}",
|
"privacy_policy.last_updated": "Последнее обновление: {date}",
|
||||||
"privacy_policy.title": "Политика конфиденциальности",
|
"privacy_policy.title": "Политика конфиденциальности",
|
||||||
|
@ -741,22 +741,22 @@
|
||||||
"refresh": "Обновить",
|
"refresh": "Обновить",
|
||||||
"regeneration_indicator.please_stand_by": "Пожалуйста, подождите.",
|
"regeneration_indicator.please_stand_by": "Пожалуйста, подождите.",
|
||||||
"regeneration_indicator.preparing_your_home_feed": "Готовим вашу ленту…",
|
"regeneration_indicator.preparing_your_home_feed": "Готовим вашу ленту…",
|
||||||
"relative_time.days": "{number} д",
|
"relative_time.days": "{number} д.",
|
||||||
"relative_time.full.days": "{number, plural, one {# день} many {# дней} other {# дня}} назад",
|
"relative_time.full.days": "{number, plural, one {# день} many {# дней} other {# дня}} назад",
|
||||||
"relative_time.full.hours": "{number, plural, one {# час} many {# часов} other {# часа}} назад",
|
"relative_time.full.hours": "{number, plural, one {# час} many {# часов} other {# часа}} назад",
|
||||||
"relative_time.full.just_now": "только что",
|
"relative_time.full.just_now": "только что",
|
||||||
"relative_time.full.minutes": "{number, plural, one {# минуту} many {# минут} other {# минуты}} назад",
|
"relative_time.full.minutes": "{number, plural, one {# минуту} many {# минут} other {# минуты}} назад",
|
||||||
"relative_time.full.seconds": "{number, plural, one {# секунду} many {# секунд} other {# секунды}} назад",
|
"relative_time.full.seconds": "{number, plural, one {# секунду} many {# секунд} other {# секунды}} назад",
|
||||||
"relative_time.hours": "{number} ч",
|
"relative_time.hours": "{number} ч.",
|
||||||
"relative_time.just_now": "только что",
|
"relative_time.just_now": "только что",
|
||||||
"relative_time.minutes": "{number} мин",
|
"relative_time.minutes": "{number} мин.",
|
||||||
"relative_time.seconds": "{number} с",
|
"relative_time.seconds": "{number} с.",
|
||||||
"relative_time.today": "сегодня",
|
"relative_time.today": "сегодня",
|
||||||
"reply_indicator.attachments": "{count, plural, one {# вложение} few {# вложения} other {# вложений}}",
|
"reply_indicator.attachments": "{count, plural, one {# вложение} few {# вложения} other {# вложений}}",
|
||||||
"reply_indicator.cancel": "Отмена",
|
"reply_indicator.cancel": "Отмена",
|
||||||
"reply_indicator.poll": "Опрос",
|
"reply_indicator.poll": "Опрос",
|
||||||
"report.block": "Заблокировать",
|
"report.block": "Заблокировать",
|
||||||
"report.block_explanation": "Вы не будете видеть посты этого пользователя. Этот пользователь не сможет видеть ваши посты и не сможет подписаться на вас. Пользователь будет знать, что вы его блокируете.",
|
"report.block_explanation": "Вы не будете видеть посты этого пользователя. Этот пользователь не сможет ни видеть ваши посты, ни подписаться на вас. Пользователь будет знать, что вы его блокируете.",
|
||||||
"report.categories.legal": "Нарушение закона",
|
"report.categories.legal": "Нарушение закона",
|
||||||
"report.categories.other": "Другое",
|
"report.categories.other": "Другое",
|
||||||
"report.categories.spam": "Спам",
|
"report.categories.spam": "Спам",
|
||||||
|
@ -780,7 +780,7 @@
|
||||||
"report.reasons.other": "Другое",
|
"report.reasons.other": "Другое",
|
||||||
"report.reasons.other_description": "Проблема не соответствует ни одной категории",
|
"report.reasons.other_description": "Проблема не соответствует ни одной категории",
|
||||||
"report.reasons.spam": "Это спам",
|
"report.reasons.spam": "Это спам",
|
||||||
"report.reasons.spam_description": "Вредоносные ссылки, фальшивая активность (накрутка) или повторяющиеся однообразные ответы",
|
"report.reasons.spam_description": "Вредоносные ссылки, фальшивая активность или повторяющиеся однообразные ответы",
|
||||||
"report.reasons.violation": "Нарушаются правила сервера",
|
"report.reasons.violation": "Нарушаются правила сервера",
|
||||||
"report.reasons.violation_description": "Выберите, если знаете, что подобное нарушает определённые правила",
|
"report.reasons.violation_description": "Выберите, если знаете, что подобное нарушает определённые правила",
|
||||||
"report.rules.subtitle": "Выберите все подходящие варианты",
|
"report.rules.subtitle": "Выберите все подходящие варианты",
|
||||||
|
@ -826,7 +826,7 @@
|
||||||
"search_results.all": "Все",
|
"search_results.all": "Все",
|
||||||
"search_results.hashtags": "Хештеги",
|
"search_results.hashtags": "Хештеги",
|
||||||
"search_results.no_results": "Ничего не найдено.",
|
"search_results.no_results": "Ничего не найдено.",
|
||||||
"search_results.no_search_yet": "Попробуйте поискать посты, профили или хэштеги.",
|
"search_results.no_search_yet": "Попробуйте поискать посты, профили или хештеги.",
|
||||||
"search_results.see_all": "Показать все",
|
"search_results.see_all": "Показать все",
|
||||||
"search_results.statuses": "Посты",
|
"search_results.statuses": "Посты",
|
||||||
"search_results.title": "Поиск \"{q}\"",
|
"search_results.title": "Поиск \"{q}\"",
|
||||||
|
@ -836,7 +836,7 @@
|
||||||
"server_banner.is_one_of_many": "{domain} — это один из многих независимых серверов Mastodon, которые вы можете использовать, чтобы присоединиться к сети Fediverse.",
|
"server_banner.is_one_of_many": "{domain} — это один из многих независимых серверов Mastodon, которые вы можете использовать, чтобы присоединиться к сети Fediverse.",
|
||||||
"server_banner.server_stats": "Статистика сервера:",
|
"server_banner.server_stats": "Статистика сервера:",
|
||||||
"sign_in_banner.create_account": "Зарегистрироваться",
|
"sign_in_banner.create_account": "Зарегистрироваться",
|
||||||
"sign_in_banner.follow_anyone": "Подписывайтесь на кого угодно в федивёрсе и читайте ленту в хронологическом порядке. Никаких алгоритмов, рекламы или кликбейта.",
|
"sign_in_banner.follow_anyone": "Подписывайтесь на кого угодно в федивёрсе и читайте ленту в хронологическом порядке. Никаких алгоритмов, рекламы и кликбейта.",
|
||||||
"sign_in_banner.mastodon_is": "Mastodon — лучший способ быть в курсе всего происходящего.",
|
"sign_in_banner.mastodon_is": "Mastodon — лучший способ быть в курсе всего происходящего.",
|
||||||
"sign_in_banner.sign_in": "Войти",
|
"sign_in_banner.sign_in": "Войти",
|
||||||
"sign_in_banner.sso_redirect": "Вход/Регистрация",
|
"sign_in_banner.sso_redirect": "Вход/Регистрация",
|
||||||
|
@ -847,7 +847,7 @@
|
||||||
"status.bookmark": "Добавить в закладки",
|
"status.bookmark": "Добавить в закладки",
|
||||||
"status.cancel_reblog_private": "Отменить продвижение",
|
"status.cancel_reblog_private": "Отменить продвижение",
|
||||||
"status.cannot_reblog": "Этот пост не может быть продвинут",
|
"status.cannot_reblog": "Этот пост не может быть продвинут",
|
||||||
"status.continued_thread": "Продолжение треда",
|
"status.continued_thread": "Продолжение предыдущего поста",
|
||||||
"status.copy": "Скопировать ссылку на пост",
|
"status.copy": "Скопировать ссылку на пост",
|
||||||
"status.delete": "Удалить",
|
"status.delete": "Удалить",
|
||||||
"status.detailed_status": "Подробный просмотр обсуждения",
|
"status.detailed_status": "Подробный просмотр обсуждения",
|
||||||
|
@ -860,8 +860,8 @@
|
||||||
"status.favourite": "Добавить в избранное",
|
"status.favourite": "Добавить в избранное",
|
||||||
"status.favourites": "{count, plural, one {звёздочка} few {звёздочки} other {звёздочек}}",
|
"status.favourites": "{count, plural, one {звёздочка} few {звёздочки} other {звёздочек}}",
|
||||||
"status.filter": "Фильтровать этот пост",
|
"status.filter": "Фильтровать этот пост",
|
||||||
"status.history.created": "{name} создал(а) {date}",
|
"status.history.created": "{name} создал(а) пост {date}",
|
||||||
"status.history.edited": "{name} отредактировал(а) {date}",
|
"status.history.edited": "{name} отредактировал(а) пост {date}",
|
||||||
"status.load_more": "Загрузить ещё",
|
"status.load_more": "Загрузить ещё",
|
||||||
"status.media.open": "Нажмите, чтобы открыть.",
|
"status.media.open": "Нажмите, чтобы открыть.",
|
||||||
"status.media.show": "Нажмите, чтобы показать",
|
"status.media.show": "Нажмите, чтобы показать",
|
||||||
|
@ -874,13 +874,17 @@
|
||||||
"status.pin": "Закрепить в профиле",
|
"status.pin": "Закрепить в профиле",
|
||||||
"status.quote_error.filtered": "Скрыто одним из ваших фильтров",
|
"status.quote_error.filtered": "Скрыто одним из ваших фильтров",
|
||||||
"status.quote_error.not_found": "Пост не может быть показан.",
|
"status.quote_error.not_found": "Пост не может быть показан.",
|
||||||
|
"status.quote_error.pending_approval": "Разрешение на цитирование от автора оригинального поста пока не получено.",
|
||||||
|
"status.quote_error.rejected": "Автор оригинального поста запретил его цитировать.",
|
||||||
"status.quote_error.removed": "Пост был удалён его автором.",
|
"status.quote_error.removed": "Пост был удалён его автором.",
|
||||||
|
"status.quote_error.unauthorized": "Этот пост для вас недоступен.",
|
||||||
|
"status.quote_post_author": "Пост пользователя {name}",
|
||||||
"status.read_more": "Читать далее",
|
"status.read_more": "Читать далее",
|
||||||
"status.reblog": "Продвинуть",
|
"status.reblog": "Продвинуть",
|
||||||
"status.reblog_private": "Продвинуть для своей аудитории",
|
"status.reblog_private": "Продвинуть для своей аудитории",
|
||||||
"status.reblogged_by": "{name} продвинул(а)",
|
"status.reblogged_by": "{name} продвинул(а)",
|
||||||
"status.reblogs": "{count, plural, one {продвижение} few {продвижения} other {продвижений}}",
|
"status.reblogs": "{count, plural, one {продвижение} few {продвижения} other {продвижений}}",
|
||||||
"status.reblogs.empty": "Никто ещё не продвинул этот пост. Все пользователи, продвинувшие этот пост, будут показаны здесь.",
|
"status.reblogs.empty": "Никто ещё не продвинул этот пост. Все пользователи, которые продвинут этот пост, будут показаны здесь.",
|
||||||
"status.redraft": "Удалить и исправить",
|
"status.redraft": "Удалить и исправить",
|
||||||
"status.remove_bookmark": "Убрать из закладок",
|
"status.remove_bookmark": "Убрать из закладок",
|
||||||
"status.remove_favourite": "Убрать из избранного",
|
"status.remove_favourite": "Убрать из избранного",
|
||||||
|
@ -900,7 +904,7 @@
|
||||||
"status.uncached_media_warning": "Предварительный просмотр недоступен",
|
"status.uncached_media_warning": "Предварительный просмотр недоступен",
|
||||||
"status.unmute_conversation": "Не игнорировать обсуждение",
|
"status.unmute_conversation": "Не игнорировать обсуждение",
|
||||||
"status.unpin": "Открепить от профиля",
|
"status.unpin": "Открепить от профиля",
|
||||||
"subscribed_languages.lead": "Посты лишь на выбранных языках будут появляться в вашей домашней ленте и в списках после изменения. Снимите выбор, чтобы получать посты на всех языках.",
|
"subscribed_languages.lead": "Посты лишь на выбранных языках будут появляться в вашей домашней ленте и списках после изменения. Снимите выбор, чтобы получать посты на всех языках.",
|
||||||
"subscribed_languages.save": "Сохранить изменения",
|
"subscribed_languages.save": "Сохранить изменения",
|
||||||
"subscribed_languages.target": "Изменить языки подписки для {target}",
|
"subscribed_languages.target": "Изменить языки подписки для {target}",
|
||||||
"tabs_bar.home": "Главная",
|
"tabs_bar.home": "Главная",
|
||||||
|
|
|
@ -220,6 +220,12 @@
|
||||||
"confirmations.delete_list.message": "Är du säker på att du vill radera denna lista permanent?",
|
"confirmations.delete_list.message": "Är du säker på att du vill radera denna lista permanent?",
|
||||||
"confirmations.delete_list.title": "Ta bort listan?",
|
"confirmations.delete_list.title": "Ta bort listan?",
|
||||||
"confirmations.discard_draft.confirm": "Släng bort och fortsätt",
|
"confirmations.discard_draft.confirm": "Släng bort och fortsätt",
|
||||||
|
"confirmations.discard_draft.edit.cancel": "Fortsätt redigera",
|
||||||
|
"confirmations.discard_draft.edit.message": "Fortsätter du, kommer ändringarna till inlägget att förkastas.",
|
||||||
|
"confirmations.discard_draft.edit.title": "Vill du förkasta ändringarna i inlägget?",
|
||||||
|
"confirmations.discard_draft.post.cancel": "Återuppta utkast",
|
||||||
|
"confirmations.discard_draft.post.message": "Fortsätter du, kommer inlägget du skriver att förkastas.",
|
||||||
|
"confirmations.discard_draft.post.title": "Vill du förkasta utkastet?",
|
||||||
"confirmations.discard_edit_media.confirm": "Kasta",
|
"confirmations.discard_edit_media.confirm": "Kasta",
|
||||||
"confirmations.discard_edit_media.message": "Du har osparade ändringar till mediabeskrivningen eller förhandsgranskningen, kasta bort dem ändå?",
|
"confirmations.discard_edit_media.message": "Du har osparade ändringar till mediabeskrivningen eller förhandsgranskningen, kasta bort dem ändå?",
|
||||||
"confirmations.follow_to_list.confirm": "Följ och lägg till i listan",
|
"confirmations.follow_to_list.confirm": "Följ och lägg till i listan",
|
||||||
|
@ -558,6 +564,8 @@
|
||||||
"navigation_bar.follows_and_followers": "Följer och följare",
|
"navigation_bar.follows_and_followers": "Följer och följare",
|
||||||
"navigation_bar.import_export": "Importera och exportera",
|
"navigation_bar.import_export": "Importera och exportera",
|
||||||
"navigation_bar.lists": "Listor",
|
"navigation_bar.lists": "Listor",
|
||||||
|
"navigation_bar.live_feed_local": "Direkt flöde (lokalt)",
|
||||||
|
"navigation_bar.live_feed_public": "Direkt flöde (publikt)",
|
||||||
"navigation_bar.logout": "Logga ut",
|
"navigation_bar.logout": "Logga ut",
|
||||||
"navigation_bar.moderation": "Moderering",
|
"navigation_bar.moderation": "Moderering",
|
||||||
"navigation_bar.more": "Fler",
|
"navigation_bar.more": "Fler",
|
||||||
|
@ -797,6 +805,7 @@
|
||||||
"report_notification.categories.violation": "Regelöverträdelse",
|
"report_notification.categories.violation": "Regelöverträdelse",
|
||||||
"report_notification.categories.violation_sentence": "regelöverträdelse",
|
"report_notification.categories.violation_sentence": "regelöverträdelse",
|
||||||
"report_notification.open": "Öppna rapport",
|
"report_notification.open": "Öppna rapport",
|
||||||
|
"search.clear": "Rensa sökning",
|
||||||
"search.no_recent_searches": "Inga sökningar nyligen",
|
"search.no_recent_searches": "Inga sökningar nyligen",
|
||||||
"search.placeholder": "Sök",
|
"search.placeholder": "Sök",
|
||||||
"search.quick_action.account_search": "Profiler som matchar {x}",
|
"search.quick_action.account_search": "Profiler som matchar {x}",
|
||||||
|
|
|
@ -98,7 +98,7 @@
|
||||||
"alert.rate_limited.message": "Vui lòng thử lại sau {retry_time, time, medium}.",
|
"alert.rate_limited.message": "Vui lòng thử lại sau {retry_time, time, medium}.",
|
||||||
"alert.rate_limited.title": "Vượt giới hạn",
|
"alert.rate_limited.title": "Vượt giới hạn",
|
||||||
"alert.unexpected.message": "Đã xảy ra lỗi không mong muốn.",
|
"alert.unexpected.message": "Đã xảy ra lỗi không mong muốn.",
|
||||||
"alert.unexpected.title": "Ốiii!",
|
"alert.unexpected.title": "Ốii!",
|
||||||
"alt_text_badge.title": "Văn bản thay thế",
|
"alt_text_badge.title": "Văn bản thay thế",
|
||||||
"alt_text_modal.add_alt_text": "Thêm văn bản thay thế",
|
"alt_text_modal.add_alt_text": "Thêm văn bản thay thế",
|
||||||
"alt_text_modal.add_text_from_image": "Thêm văn bản từ ảnh",
|
"alt_text_modal.add_text_from_image": "Thêm văn bản từ ảnh",
|
||||||
|
@ -276,7 +276,7 @@
|
||||||
"domain_block_modal.you_will_lose_num_followers": "Bạn sẽ mất {followersCount, plural, other {{followersCountDisplay} người theo dõi}} và {followingCount, plural, other {{followingCountDisplay} người bạn theo dõi}}.",
|
"domain_block_modal.you_will_lose_num_followers": "Bạn sẽ mất {followersCount, plural, other {{followersCountDisplay} người theo dõi}} và {followingCount, plural, other {{followingCountDisplay} người bạn theo dõi}}.",
|
||||||
"domain_block_modal.you_will_lose_relationships": "Bạn sẽ mất tất cả người theo dõi và những người bạn theo dõi từ máy chủ này.",
|
"domain_block_modal.you_will_lose_relationships": "Bạn sẽ mất tất cả người theo dõi và những người bạn theo dõi từ máy chủ này.",
|
||||||
"domain_block_modal.you_wont_see_posts": "Bạn không còn thấy tút hoặc thông báo từ thành viên máy chủ này.",
|
"domain_block_modal.you_wont_see_posts": "Bạn không còn thấy tút hoặc thông báo từ thành viên máy chủ này.",
|
||||||
"domain_pill.activitypub_lets_connect": "Nó cho phép bạn kết nối và tương tác với mọi người không chỉ trên Mastodon mà còn trên các ứng dụng xã hội khác.",
|
"domain_pill.activitypub_lets_connect": "Nó cho phép bạn kết nối và tương tác với mọi người, không chỉ trên Mastodon mà còn trên các nền tảng khác.",
|
||||||
"domain_pill.activitypub_like_language": "ActivityPub giống như ngôn ngữ Mastodon giao tiếp với các mạng xã hội khác.",
|
"domain_pill.activitypub_like_language": "ActivityPub giống như ngôn ngữ Mastodon giao tiếp với các mạng xã hội khác.",
|
||||||
"domain_pill.server": "Máy chủ",
|
"domain_pill.server": "Máy chủ",
|
||||||
"domain_pill.their_handle": "Địa chỉ Mastodon:",
|
"domain_pill.their_handle": "Địa chỉ Mastodon:",
|
||||||
|
|
|
@ -218,6 +218,9 @@
|
||||||
"confirmations.delete_list.confirm": "删除",
|
"confirmations.delete_list.confirm": "删除",
|
||||||
"confirmations.delete_list.message": "确定要永久删除此列表吗?",
|
"confirmations.delete_list.message": "确定要永久删除此列表吗?",
|
||||||
"confirmations.delete_list.title": "确定要删除列表?",
|
"confirmations.delete_list.title": "确定要删除列表?",
|
||||||
|
"confirmations.discard_draft.confirm": "放弃并继续",
|
||||||
|
"confirmations.discard_draft.edit.cancel": "恢复编辑",
|
||||||
|
"confirmations.discard_draft.post.cancel": "恢复草稿",
|
||||||
"confirmations.discard_edit_media.confirm": "丢弃",
|
"confirmations.discard_edit_media.confirm": "丢弃",
|
||||||
"confirmations.discard_edit_media.message": "你还有未保存的媒体描述或预览修改,仍要丢弃吗?",
|
"confirmations.discard_edit_media.message": "你还有未保存的媒体描述或预览修改,仍要丢弃吗?",
|
||||||
"confirmations.follow_to_list.confirm": "关注并添加到列表",
|
"confirmations.follow_to_list.confirm": "关注并添加到列表",
|
||||||
|
@ -534,8 +537,10 @@
|
||||||
"mute_modal.you_wont_see_mentions": "你看不到提及对方的嘟文。",
|
"mute_modal.you_wont_see_mentions": "你看不到提及对方的嘟文。",
|
||||||
"mute_modal.you_wont_see_posts": "对方可以看到你的嘟文,但是你看不到对方的。",
|
"mute_modal.you_wont_see_posts": "对方可以看到你的嘟文,但是你看不到对方的。",
|
||||||
"navigation_bar.about": "关于",
|
"navigation_bar.about": "关于",
|
||||||
|
"navigation_bar.account_settings": "密码与安全",
|
||||||
"navigation_bar.administration": "管理",
|
"navigation_bar.administration": "管理",
|
||||||
"navigation_bar.advanced_interface": "在高级网页界面中打开",
|
"navigation_bar.advanced_interface": "在高级网页界面中打开",
|
||||||
|
"navigation_bar.automated_deletion": "自动删除嘟文",
|
||||||
"navigation_bar.blocks": "已屏蔽的用户",
|
"navigation_bar.blocks": "已屏蔽的用户",
|
||||||
"navigation_bar.bookmarks": "书签",
|
"navigation_bar.bookmarks": "书签",
|
||||||
"navigation_bar.direct": "私下提及",
|
"navigation_bar.direct": "私下提及",
|
||||||
|
|
|
@ -375,7 +375,7 @@
|
||||||
"follow_suggestions.dismiss": "不再顯示",
|
"follow_suggestions.dismiss": "不再顯示",
|
||||||
"follow_suggestions.featured_longer": "{domain} 團隊精選",
|
"follow_suggestions.featured_longer": "{domain} 團隊精選",
|
||||||
"follow_suggestions.friends_of_friends_longer": "受您跟隨之使用者愛戴的風雲人物",
|
"follow_suggestions.friends_of_friends_longer": "受您跟隨之使用者愛戴的風雲人物",
|
||||||
"follow_suggestions.hints.featured": "這個個人檔案是 {domain} 管理團隊精心挑選。",
|
"follow_suggestions.hints.featured": "這個個人檔案是 {domain} 管理團隊精心挑選的。",
|
||||||
"follow_suggestions.hints.friends_of_friends": "這個個人檔案於您跟隨的帳號中很受歡迎。",
|
"follow_suggestions.hints.friends_of_friends": "這個個人檔案於您跟隨的帳號中很受歡迎。",
|
||||||
"follow_suggestions.hints.most_followed": "這個個人檔案是 {domain} 中最受歡迎的帳號之一。",
|
"follow_suggestions.hints.most_followed": "這個個人檔案是 {domain} 中最受歡迎的帳號之一。",
|
||||||
"follow_suggestions.hints.most_interactions": "這個個人檔案最近於 {domain} 受到非常多關注。",
|
"follow_suggestions.hints.most_interactions": "這個個人檔案最近於 {domain} 受到非常多關注。",
|
||||||
|
|
|
@ -126,6 +126,9 @@ export function createAccountFromServerJSON(serverJSON: ApiAccountJSON) {
|
||||||
? accountJSON.username
|
? accountJSON.username
|
||||||
: accountJSON.display_name;
|
: accountJSON.display_name;
|
||||||
|
|
||||||
|
const accountNote =
|
||||||
|
accountJSON.note && accountJSON.note !== '<p></p>' ? accountJSON.note : '';
|
||||||
|
|
||||||
return AccountFactory({
|
return AccountFactory({
|
||||||
...accountJSON,
|
...accountJSON,
|
||||||
moved: moved?.id,
|
moved: moved?.id,
|
||||||
|
@ -142,8 +145,8 @@ export function createAccountFromServerJSON(serverJSON: ApiAccountJSON) {
|
||||||
escapeTextContentForBrowser(displayName),
|
escapeTextContentForBrowser(displayName),
|
||||||
emojiMap,
|
emojiMap,
|
||||||
),
|
),
|
||||||
note_emojified: emojify(accountJSON.note, emojiMap),
|
note_emojified: emojify(accountNote, emojiMap),
|
||||||
note_plain: unescapeHTML(accountJSON.note),
|
note_plain: unescapeHTML(accountNote),
|
||||||
url:
|
url:
|
||||||
accountJSON.url.startsWith('http://') ||
|
accountJSON.url.startsWith('http://') ||
|
||||||
accountJSON.url.startsWith('https://')
|
accountJSON.url.startsWith('https://')
|
||||||
|
|
|
@ -939,6 +939,7 @@ body > [data-popper-placement] {
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
letter-spacing: 0.1px;
|
letter-spacing: 0.1px;
|
||||||
color: $highlight-text-color;
|
color: $highlight-text-color;
|
||||||
|
background-color: var(--input-background-color);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -1856,7 +1857,10 @@ body > [data-popper-placement] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__quote {
|
.status__quote {
|
||||||
--quote-margin: 36px;
|
// --status-gutter-width is currently only set inside of
|
||||||
|
// .notification-ungrouped, so everywhere else this will fall back
|
||||||
|
// to the pixel values
|
||||||
|
--quote-margin: var(--status-gutter-width, 36px);
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-block-start: 16px;
|
margin-block-start: 16px;
|
||||||
|
@ -1867,7 +1871,7 @@ body > [data-popper-placement] {
|
||||||
border: var(--nested-card-border);
|
border: var(--nested-card-border);
|
||||||
|
|
||||||
@container (width > 460px) {
|
@container (width > 460px) {
|
||||||
--quote-margin: 56px;
|
--quote-margin: var(--status-gutter-width, 56px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2848,7 +2852,6 @@ a.account__display-name {
|
||||||
&__pane {
|
&__pane {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
pointer-events: none;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
min-width: 285px;
|
min-width: 285px;
|
||||||
|
@ -2860,7 +2863,6 @@ a.account__display-name {
|
||||||
&__inner {
|
&__inner {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 285px;
|
width: 285px;
|
||||||
pointer-events: auto;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3874,16 +3876,18 @@ a.account__display-name {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
padding: 12px;
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
border: 0;
|
|
||||||
background: transparent;
|
|
||||||
color: $secondary-text-color;
|
color: $secondary-text-color;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
border-left: 4px solid transparent;
|
border-left: 4px solid transparent;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus,
|
||||||
|
@ -10816,21 +10820,23 @@ noscript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status {
|
.status:not(.status--is-quote) {
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
&__avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__wrapper-direct {
|
.status__wrapper-direct {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
$icon-margin: 48px; // 40px avatar + 8px gap
|
.status {
|
||||||
|
// 40px avatar + 8px gap
|
||||||
|
--status-gutter-width: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status--is-quote {
|
||||||
|
--status-gutter-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.status__content,
|
.status__content,
|
||||||
.status__action-bar,
|
.status__action-bar,
|
||||||
|
@ -10844,16 +10850,16 @@ noscript {
|
||||||
.hashtag-bar,
|
.hashtag-bar,
|
||||||
.content-warning,
|
.content-warning,
|
||||||
.filter-warning {
|
.filter-warning {
|
||||||
margin-inline-start: $icon-margin;
|
margin-inline-start: var(--status-gutter-width);
|
||||||
width: calc(100% - $icon-margin);
|
width: calc(100% - var(--status-gutter-width));
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-from-author {
|
.more-from-author {
|
||||||
width: calc(100% - $icon-margin + 2px);
|
width: calc(100% - var(--status-gutter-width) + 2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status__content__read-more-button {
|
.status__content__read-more-button {
|
||||||
margin-inline-start: $icon-margin;
|
margin-inline-start: var(--status-gutter-width);
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification__report {
|
.notification__report {
|
||||||
|
|
|
@ -28,7 +28,7 @@ class AnnualReport::Archetype < AnnualReport::Source
|
||||||
end
|
end
|
||||||
|
|
||||||
def polls_count
|
def polls_count
|
||||||
@polls_count ||= report_statuses.where.not(poll_id: nil).count
|
@polls_count ||= report_statuses.only_polls.count
|
||||||
end
|
end
|
||||||
|
|
||||||
def reblogs_count
|
def reblogs_count
|
||||||
|
@ -36,7 +36,7 @@ class AnnualReport::Archetype < AnnualReport::Source
|
||||||
end
|
end
|
||||||
|
|
||||||
def replies_count
|
def replies_count
|
||||||
@replies_count ||= report_statuses.where.not(in_reply_to_id: nil).where.not(in_reply_to_account_id: @account.id).count
|
@replies_count ||= report_statuses.where.not(in_reply_to_id: nil).not_replying_to_account(@account).count
|
||||||
end
|
end
|
||||||
|
|
||||||
def standalone_count
|
def standalone_count
|
||||||
|
|
|
@ -18,7 +18,7 @@ class AnnualReport::CommonlyInteractedWithAccounts < AnnualReport::Source
|
||||||
private
|
private
|
||||||
|
|
||||||
def commonly_interacted_with_accounts
|
def commonly_interacted_with_accounts
|
||||||
report_statuses.where.not(in_reply_to_account_id: @account.id).group(:in_reply_to_account_id).having(minimum_interaction_count).order(count_all: :desc).limit(SET_SIZE).count
|
report_statuses.not_replying_to_account(@account).group(:in_reply_to_account_id).having(minimum_interaction_count).order(count_all: :desc).limit(SET_SIZE).count
|
||||||
end
|
end
|
||||||
|
|
||||||
def minimum_interaction_count
|
def minimum_interaction_count
|
||||||
|
|
|
@ -2,20 +2,44 @@
|
||||||
|
|
||||||
class AnnualReport::TopStatuses < AnnualReport::Source
|
class AnnualReport::TopStatuses < AnnualReport::Source
|
||||||
def generate
|
def generate
|
||||||
top_reblogs = base_scope.order(reblogs_count: :desc).first&.id
|
|
||||||
top_favourites = base_scope.where.not(id: top_reblogs).order(favourites_count: :desc).first&.id
|
|
||||||
top_replies = base_scope.where.not(id: [top_reblogs, top_favourites]).order(replies_count: :desc).first&.id
|
|
||||||
|
|
||||||
{
|
{
|
||||||
top_statuses: {
|
top_statuses: {
|
||||||
by_reblogs: top_reblogs&.to_s,
|
by_reblogs: status_identifier(most_reblogged_status),
|
||||||
by_favourites: top_favourites&.to_s,
|
by_favourites: status_identifier(most_favourited_status),
|
||||||
by_replies: top_replies&.to_s,
|
by_replies: status_identifier(most_replied_status),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def status_identifier(status)
|
||||||
|
status.id.to_s if status.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def most_reblogged_status
|
||||||
|
base_scope
|
||||||
|
.order(reblogs_count: :desc)
|
||||||
|
.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def most_favourited_status
|
||||||
|
base_scope
|
||||||
|
.excluding(most_reblogged_status)
|
||||||
|
.order(favourites_count: :desc)
|
||||||
|
.first
|
||||||
|
end
|
||||||
|
|
||||||
|
def most_replied_status
|
||||||
|
base_scope
|
||||||
|
.excluding(most_reblogged_status, most_favourited_status)
|
||||||
|
.order(replies_count: :desc)
|
||||||
|
.first
|
||||||
|
end
|
||||||
|
|
||||||
def base_scope
|
def base_scope
|
||||||
report_statuses.public_visibility.joins(:status_stat)
|
report_statuses
|
||||||
|
.public_visibility
|
||||||
|
.joins(:status_stat)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,7 @@ class AnnualReport::TypeDistribution < AnnualReport::Source
|
||||||
type_distribution: {
|
type_distribution: {
|
||||||
total: report_statuses.count,
|
total: report_statuses.count,
|
||||||
reblogs: report_statuses.only_reblogs.count,
|
reblogs: report_statuses.only_reblogs.count,
|
||||||
replies: report_statuses.where.not(in_reply_to_id: nil).where.not(in_reply_to_account_id: @account.id).count,
|
replies: report_statuses.where.not(in_reply_to_id: nil).not_replying_to_account(@account).count,
|
||||||
standalone: report_statuses.without_replies.without_reblogs.count,
|
standalone: report_statuses.without_replies.without_reblogs.count,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ class AccountStatusesCleanupPolicy < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def without_poll_scope
|
def without_poll_scope
|
||||||
Status.where(poll_id: nil)
|
Status.without_polls
|
||||||
end
|
end
|
||||||
|
|
||||||
def without_popular_scope
|
def without_popular_scope
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
module Account::AttributionDomains
|
module Account::AttributionDomains
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
ATTRIBUTION_DOMAINS_LIMIT = 100
|
||||||
|
|
||||||
included do
|
included do
|
||||||
normalizes :attribution_domains, with: ->(arr) { arr.filter_map { |str| str.to_s.strip.delete_prefix('http://').delete_prefix('https://').delete_prefix('*.').presence }.uniq }
|
normalizes :attribution_domains, with: ->(arr) { arr.filter_map { |str| str.to_s.strip.delete_prefix('http://').delete_prefix('https://').delete_prefix('*.').presence }.uniq }
|
||||||
|
|
||||||
validates :attribution_domains, domain: true, length: { maximum: 100 }, if: -> { local? && will_save_change_to_attribution_domains? }
|
validates :attribution_domains, domain: true, length: { maximum: ATTRIBUTION_DOMAINS_LIMIT }, if: -> { local? && will_save_change_to_attribution_domains? }
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_be_attributed_from?(domain)
|
def can_be_attributed_from?(domain)
|
||||||
|
|
|
@ -10,12 +10,6 @@ module DatabaseViewRecord
|
||||||
concurrently: true,
|
concurrently: true,
|
||||||
cascade: false
|
cascade: false
|
||||||
)
|
)
|
||||||
rescue ActiveRecord::StatementInvalid
|
|
||||||
Scenic.database.refresh_materialized_view(
|
|
||||||
table_name,
|
|
||||||
concurrently: false,
|
|
||||||
cascade: false
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,8 @@ module FollowLimitable
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
validates_with FollowLimitValidator, on: :create, unless: :bypass_follow_limit?
|
validates_with FollowLimitValidator, on: :create, unless: :bypass_follow_limit
|
||||||
end
|
|
||||||
|
|
||||||
def bypass_follow_limit=(value)
|
attribute :bypass_follow_limit, :boolean, default: false
|
||||||
@bypass_follow_limit = value
|
|
||||||
end
|
|
||||||
|
|
||||||
def bypass_follow_limit?
|
|
||||||
@bypass_follow_limit
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,12 +17,14 @@ class CustomFilterStatus < ApplicationRecord
|
||||||
belongs_to :custom_filter
|
belongs_to :custom_filter
|
||||||
belongs_to :status
|
belongs_to :status
|
||||||
|
|
||||||
validates :status, uniqueness: { scope: :custom_filter }
|
validates :status_id, uniqueness: { scope: :custom_filter_id }
|
||||||
validate :validate_status_access
|
validate :validate_status_access, if: [:custom_filter_account, :status]
|
||||||
|
|
||||||
|
delegate :account, to: :custom_filter, prefix: true, allow_nil: true
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def validate_status_access
|
def validate_status_access
|
||||||
errors.add(:status_id, :invalid) unless StatusPolicy.new(custom_filter.account, status).show?
|
errors.add(:status_id, :invalid) unless StatusPolicy.new(custom_filter_account, status).show?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,7 +14,7 @@ class FollowRecommendationMute < ApplicationRecord
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
belongs_to :target_account, class_name: 'Account'
|
belongs_to :target_account, class_name: 'Account'
|
||||||
|
|
||||||
validates :target_account, uniqueness: { scope: :account_id }
|
validates :target_account_id, uniqueness: { scope: :account_id }
|
||||||
|
|
||||||
after_commit :invalidate_follow_recommendations_cache
|
after_commit :invalidate_follow_recommendations_cache
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class GeneratedAnnualReport < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def view!
|
def view!
|
||||||
update!(viewed_at: Time.now.utc)
|
touch(:viewed_at)
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_ids
|
def account_ids
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Quote < ApplicationRecord
|
||||||
belongs_to :quoted_account, class_name: 'Account', optional: true
|
belongs_to :quoted_account, class_name: 'Account', optional: true
|
||||||
|
|
||||||
before_validation :set_accounts
|
before_validation :set_accounts
|
||||||
|
before_validation :set_activity_uri, only: :create, if: -> { account.local? && quoted_account&.remote? }
|
||||||
validates :activity_uri, presence: true, if: -> { account.local? && quoted_account&.remote? }
|
validates :activity_uri, presence: true, if: -> { account.local? && quoted_account&.remote? }
|
||||||
validate :validate_visibility
|
validate :validate_visibility
|
||||||
|
|
||||||
|
@ -69,4 +69,8 @@ class Quote < ApplicationRecord
|
||||||
|
|
||||||
errors.add(:quoted_status_id, :visibility_mismatch)
|
errors.add(:quoted_status_id, :visibility_mismatch)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_activity_uri
|
||||||
|
self.activity_uri = [ActivityPub::TagManager.instance.uri_for(account), '/quote_requests/', SecureRandom.uuid].join
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -121,7 +121,10 @@ class Status < ApplicationRecord
|
||||||
scope :without_replies, -> { not_reply.or(reply_to_account) }
|
scope :without_replies, -> { not_reply.or(reply_to_account) }
|
||||||
scope :not_reply, -> { where(reply: false) }
|
scope :not_reply, -> { where(reply: false) }
|
||||||
scope :only_reblogs, -> { where.not(reblog_of_id: nil) }
|
scope :only_reblogs, -> { where.not(reblog_of_id: nil) }
|
||||||
|
scope :only_polls, -> { where.not(poll_id: nil) }
|
||||||
|
scope :without_polls, -> { where(poll_id: nil) }
|
||||||
scope :reply_to_account, -> { where(arel_table[:in_reply_to_account_id].eq arel_table[:account_id]) }
|
scope :reply_to_account, -> { where(arel_table[:in_reply_to_account_id].eq arel_table[:account_id]) }
|
||||||
|
scope :not_replying_to_account, ->(account) { where.not(in_reply_to_account: account) }
|
||||||
scope :without_reblogs, -> { where(statuses: { reblog_of_id: nil }) }
|
scope :without_reblogs, -> { where(statuses: { reblog_of_id: nil }) }
|
||||||
scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) }
|
scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) }
|
||||||
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
|
scope :not_excluded_by_account, ->(account) { where.not(account_id: account.excluded_from_timeline_account_ids) }
|
||||||
|
|
|
@ -49,8 +49,8 @@ class Tag < ApplicationRecord
|
||||||
|
|
||||||
validates :name, presence: true, format: { with: HASHTAG_NAME_RE }
|
validates :name, presence: true, format: { with: HASHTAG_NAME_RE }
|
||||||
validates :display_name, format: { with: HASHTAG_NAME_RE }
|
validates :display_name, format: { with: HASHTAG_NAME_RE }
|
||||||
validate :validate_name_change, if: -> { !new_record? && name_changed? }
|
validate :validate_name_change, on: :update, if: :name_changed?
|
||||||
validate :validate_display_name_change, if: -> { !new_record? && display_name_changed? }
|
validate :validate_display_name_change, on: :update, if: :display_name_changed?
|
||||||
|
|
||||||
scope :pending_review, -> { unreviewed.where.not(requested_review_at: nil) }
|
scope :pending_review, -> { unreviewed.where.not(requested_review_at: nil) }
|
||||||
scope :usable, -> { where(usable: [true, nil]) }
|
scope :usable, -> { where(usable: [true, nil]) }
|
||||||
|
|
|
@ -90,6 +90,7 @@ class User < ApplicationRecord
|
||||||
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: nil
|
has_many :applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: nil
|
||||||
has_many :backups, inverse_of: :user, dependent: nil
|
has_many :backups, inverse_of: :user, dependent: nil
|
||||||
has_many :invites, inverse_of: :user, dependent: nil
|
has_many :invites, inverse_of: :user, dependent: nil
|
||||||
|
has_many :login_activities, inverse_of: :user, dependent: :destroy
|
||||||
has_many :markers, inverse_of: :user, dependent: :destroy
|
has_many :markers, inverse_of: :user, dependent: :destroy
|
||||||
has_many :webauthn_credentials, dependent: :destroy
|
has_many :webauthn_credentials, dependent: :destroy
|
||||||
has_many :ips, class_name: 'UserIp', inverse_of: :user, dependent: nil
|
has_many :ips, class_name: 'UserIp', inverse_of: :user, dependent: nil
|
||||||
|
|
|
@ -35,6 +35,7 @@ class UserSettings
|
||||||
setting :expand_content_warnings, default: false
|
setting :expand_content_warnings, default: false
|
||||||
setting :display_media, default: 'default', in: %w(default show_all hide_all)
|
setting :display_media, default: 'default', in: %w(default show_all hide_all)
|
||||||
setting :auto_play, default: false
|
setting :auto_play, default: false
|
||||||
|
setting :emoji_style, default: 'auto', in: %w(auto native twemoji)
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :notification_emails do
|
namespace :notification_emails do
|
||||||
|
|
|
@ -7,7 +7,7 @@ class ActivityPub::QuoteRequestSerializer < ActivityPub::Serializer
|
||||||
attribute :virtual_object, key: :object
|
attribute :virtual_object, key: :object
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object.activity_uri || [ActivityPub::TagManager.instance.uri_for(object.target_account), '#quote_requests/', object.id].join
|
object.activity_uri
|
||||||
end
|
end
|
||||||
|
|
||||||
def type
|
def type
|
||||||
|
|
|
@ -5,7 +5,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
attributes :meta, :compose, :accounts,
|
attributes :meta, :compose, :accounts,
|
||||||
:media_attachments, :settings,
|
:media_attachments, :settings,
|
||||||
:languages
|
:languages, :features
|
||||||
|
|
||||||
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
|
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
|
||||||
|
|
||||||
|
@ -85,6 +85,10 @@ class InitialStateSerializer < ActiveModel::Serializer
|
||||||
LanguagesHelper::SUPPORTED_LOCALES.map { |(key, value)| [key, value[0], value[1]] }
|
LanguagesHelper::SUPPORTED_LOCALES.map { |(key, value)| [key, value[0], value[1]] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def features
|
||||||
|
Mastodon::Feature.enabled_features
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def default_meta_store
|
def default_meta_store
|
||||||
|
|
|
@ -66,6 +66,7 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
update_interaction_policies!
|
update_interaction_policies!
|
||||||
update_poll!(allow_significant_changes: false)
|
update_poll!(allow_significant_changes: false)
|
||||||
queue_poll_notifications!
|
queue_poll_notifications!
|
||||||
|
update_quote_approval!
|
||||||
update_counts!
|
update_counts!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -270,6 +271,23 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This method is only concerned with approval and skips other meaningful changes,
|
||||||
|
# as it is used instead of `update_quote!` in implicit updates
|
||||||
|
def update_quote_approval!
|
||||||
|
quote_uri = @status_parser.quote_uri
|
||||||
|
return unless quote_uri.present? && @status.quote.present?
|
||||||
|
|
||||||
|
quote = @status.quote
|
||||||
|
return if quote.quoted_status.present? && ActivityPub::TagManager.instance.uri_for(quote.quoted_status) != quote_uri
|
||||||
|
|
||||||
|
approval_uri = @status_parser.quote_approval_uri
|
||||||
|
approval_uri = nil if unsupported_uri_scheme?(approval_uri)
|
||||||
|
|
||||||
|
quote.update(approval_uri: approval_uri, state: :pending, legacy: @status_parser.legacy_quote?) if quote.approval_uri != @status_parser.quote_approval_uri
|
||||||
|
|
||||||
|
fetch_and_verify_quote!(quote, quote_uri)
|
||||||
|
end
|
||||||
|
|
||||||
def update_quote!
|
def update_quote!
|
||||||
quote_uri = @status_parser.quote_uri
|
quote_uri = @status_parser.quote_uri
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :date_of_birth,
|
= f.input :date_of_birth,
|
||||||
as: :date_of_birth,
|
as: :date_of_birth,
|
||||||
hint: t('simple_form.hints.user.date_of_birth', count: Setting.min_age.to_i),
|
hint: t('simple_form.hints.user.date_of_birth', count: Setting.min_age.to_i, domain: site_hostname),
|
||||||
required: true,
|
required: true,
|
||||||
wrapper: :with_block_label
|
wrapper: :with_block_label
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,17 @@
|
||||||
label: I18n.t('simple_form.labels.defaults.setting_theme'),
|
label: I18n.t('simple_form.labels.defaults.setting_theme'),
|
||||||
wrapper: :with_label
|
wrapper: :with_label
|
||||||
|
|
||||||
|
- if Mastodon::Feature.modern_emojis_enabled?
|
||||||
|
.fields-group
|
||||||
|
= f.simple_fields_for :settings, current_user.settings do |ff|
|
||||||
|
= ff.input :'web.emoji_style',
|
||||||
|
collection: %w(auto twemoji native),
|
||||||
|
include_blank: false,
|
||||||
|
hint: I18n.t('simple_form.hints.defaults.setting_emoji_style'),
|
||||||
|
label: I18n.t('simple_form.labels.defaults.setting_emoji_style'),
|
||||||
|
label_method: ->(emoji_style) { I18n.t("emoji_styles.#{emoji_style}", default: emoji_style) },
|
||||||
|
wrapper: :with_label
|
||||||
|
|
||||||
- unless I18n.locale == :en
|
- unless I18n.locale == :en
|
||||||
.flash-message.translation-prompt
|
.flash-message.translation-prompt
|
||||||
#{t 'appearance.localization.body'} #{content_tag(:a, t('appearance.localization.guide_link_text'), href: t('appearance.localization.guide_link'), target: '_blank', rel: 'noopener')}
|
#{t 'appearance.localization.body'} #{content_tag(:a, t('appearance.localization.guide_link_text'), href: t('appearance.localization.guide_link'), target: '_blank', rel: 'noopener')}
|
||||||
|
|
|
@ -5,24 +5,14 @@ require 'linzer/message/adapter/http_gem/response'
|
||||||
|
|
||||||
module Linzer::Message::Adapter
|
module Linzer::Message::Adapter
|
||||||
module ActionDispatch
|
module ActionDispatch
|
||||||
class Response < Linzer::Message::Adapter::Abstract
|
class Response < Linzer::Message::Adapter::Generic::Response
|
||||||
def initialize(operation, **_options) # rubocop:disable Lint/MissingSuper
|
private
|
||||||
@operation = operation
|
|
||||||
end
|
|
||||||
|
|
||||||
def header(name)
|
|
||||||
@operation.headers[name]
|
|
||||||
end
|
|
||||||
|
|
||||||
def attach!(signature)
|
|
||||||
signature.to_h.each { |h, v| @operation.headers[h] = v }
|
|
||||||
end
|
|
||||||
|
|
||||||
# Incomplete, but sufficient for FASP
|
# Incomplete, but sufficient for FASP
|
||||||
def [](field_name)
|
def derived(name)
|
||||||
return @operation.status if field_name == '@status'
|
case name.value
|
||||||
|
when '@status' then @operation.status
|
||||||
@operation.headers[field_name]
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,9 @@ be:
|
||||||
user/invite_request:
|
user/invite_request:
|
||||||
text: Прычына
|
text: Прычына
|
||||||
errors:
|
errors:
|
||||||
|
attributes:
|
||||||
|
domain:
|
||||||
|
invalid: не з’яўляецца сапраўдным даменным імем
|
||||||
models:
|
models:
|
||||||
account:
|
account:
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -37,7 +40,7 @@ be:
|
||||||
attributes:
|
attributes:
|
||||||
account_id:
|
account_id:
|
||||||
taken: ужо ў спісе
|
taken: ужо ў спісе
|
||||||
must_be_following: мусіць быць падпісаным уліковым запісам
|
must_be_following: мусіць быць карыстальнікам у вашых падпісках
|
||||||
status:
|
status:
|
||||||
attributes:
|
attributes:
|
||||||
reblog:
|
reblog:
|
||||||
|
|
|
@ -49,8 +49,14 @@ en-GB:
|
||||||
attributes:
|
attributes:
|
||||||
reblog:
|
reblog:
|
||||||
taken: of post already exists
|
taken: of post already exists
|
||||||
|
terms_of_service:
|
||||||
|
attributes:
|
||||||
|
effective_date:
|
||||||
|
too_soon: is too soon, must be later than %{date}
|
||||||
user:
|
user:
|
||||||
attributes:
|
attributes:
|
||||||
|
date_of_birth:
|
||||||
|
below_limit: is below the age limit
|
||||||
email:
|
email:
|
||||||
blocked: uses a disallowed e-mail provider
|
blocked: uses a disallowed e-mail provider
|
||||||
unreachable: does not seem to exist
|
unreachable: does not seem to exist
|
||||||
|
|
|
@ -18,7 +18,7 @@ be:
|
||||||
link_verified_on: Права ўласнасці на гэтую спасылку праверана %{date}
|
link_verified_on: Права ўласнасці на гэтую спасылку праверана %{date}
|
||||||
nothing_here: Тут нічога няма!
|
nothing_here: Тут нічога няма!
|
||||||
pin_errors:
|
pin_errors:
|
||||||
following: Вы павінны быць падпісаны на чалавека, якога жадаеце рэкамендаваць
|
following: Трэба падпісацца на чалавека, якога вы хочаце рэкамендаваць
|
||||||
posts:
|
posts:
|
||||||
few: Допісы
|
few: Допісы
|
||||||
many: Допісаў
|
many: Допісаў
|
||||||
|
@ -28,6 +28,8 @@ be:
|
||||||
admin:
|
admin:
|
||||||
account_actions:
|
account_actions:
|
||||||
action: Выканаць дзеянне
|
action: Выканаць дзеянне
|
||||||
|
already_silenced: Гэты ўліковы запіс ужо абмежаваны.
|
||||||
|
already_suspended: Гэты ўліковы запіс ужо прыпынены.
|
||||||
title: Мадэраваць %{acct}
|
title: Мадэраваць %{acct}
|
||||||
account_moderation_notes:
|
account_moderation_notes:
|
||||||
create: Пакінуць нататку
|
create: Пакінуць нататку
|
||||||
|
@ -107,7 +109,7 @@ be:
|
||||||
no_role_assigned: Роля не прызначана
|
no_role_assigned: Роля не прызначана
|
||||||
not_subscribed: Не падпісаны
|
not_subscribed: Не падпісаны
|
||||||
pending: Чакае праверкі
|
pending: Чакае праверкі
|
||||||
perform_full_suspension: Выключыць
|
perform_full_suspension: Прыпыніць
|
||||||
previous_strikes: Ранейшыя скаргі
|
previous_strikes: Ранейшыя скаргі
|
||||||
previous_strikes_description_html:
|
previous_strikes_description_html:
|
||||||
few: Гэты ўліковы запіс мае <strong>%{count}</strong> скаргі.
|
few: Гэты ўліковы запіс мае <strong>%{count}</strong> скаргі.
|
||||||
|
@ -164,7 +166,7 @@ be:
|
||||||
unconfirmed_email: Непацверджаны адрас эл. пошты
|
unconfirmed_email: Непацверджаны адрас эл. пошты
|
||||||
undo_sensitized: Прыбраць прымусовую пазнаку далікатнасці
|
undo_sensitized: Прыбраць прымусовую пазнаку далікатнасці
|
||||||
undo_silenced: Адмяніць ліміт
|
undo_silenced: Адмяніць ліміт
|
||||||
undo_suspension: Разблакаваць карыстальніка
|
undo_suspension: Разблакіраваць карыстальніка
|
||||||
unsilenced_msg: З уліковага запісу %{username} зняты абмежаванні
|
unsilenced_msg: З уліковага запісу %{username} зняты абмежаванні
|
||||||
unsubscribe: Адпісацца
|
unsubscribe: Адпісацца
|
||||||
unsuspended_msg: Уліковы запіс %{username} адноўлены
|
unsuspended_msg: Уліковы запіс %{username} адноўлены
|
||||||
|
@ -189,7 +191,7 @@ be:
|
||||||
create_domain_block: Стварыць даменны блок
|
create_domain_block: Стварыць даменны блок
|
||||||
create_email_domain_block: Стварыць даменны блок электроннай пошты
|
create_email_domain_block: Стварыць даменны блок электроннай пошты
|
||||||
create_ip_block: Стварыць IP правіла
|
create_ip_block: Стварыць IP правіла
|
||||||
create_relay: Стварыць паўтор
|
create_relay: Стварыць рэтранслятар
|
||||||
create_unavailable_domain: Стварыць недаступны Дамен
|
create_unavailable_domain: Стварыць недаступны Дамен
|
||||||
create_user_role: Стварыць ролю
|
create_user_role: Стварыць ролю
|
||||||
demote_user: Панізіць карыстальніка
|
demote_user: Панізіць карыстальніка
|
||||||
|
@ -201,22 +203,22 @@ be:
|
||||||
destroy_email_domain_block: Выдаліць даменны блок электроннай пошты
|
destroy_email_domain_block: Выдаліць даменны блок электроннай пошты
|
||||||
destroy_instance: Вычысціць дамен
|
destroy_instance: Вычысціць дамен
|
||||||
destroy_ip_block: Выдаліць IP правіла
|
destroy_ip_block: Выдаліць IP правіла
|
||||||
destroy_relay: Выдаліць паўтор
|
destroy_relay: Выдаліць рэтранслятар
|
||||||
destroy_status: Выдаліць допіс
|
destroy_status: Выдаліць допіс
|
||||||
destroy_unavailable_domain: Выдаліць недаступны дамен
|
destroy_unavailable_domain: Выдаліць недаступны дамен
|
||||||
destroy_user_role: Выдаліць ролю
|
destroy_user_role: Выдаліць ролю
|
||||||
disable_2fa_user: Адключыць двухэтапнае спраўджанне
|
disable_2fa_user: Адключыць двухэтапнае спраўджанне
|
||||||
disable_custom_emoji: Адключыць адвольныя эмодзі
|
disable_custom_emoji: Адключыць адвольныя эмодзі
|
||||||
disable_relay: Выключыць паўтор
|
disable_relay: Выключыць рэтранслятар
|
||||||
disable_sign_in_token_auth_user: Адключыць аўтарызацыю праз электронную пошту для карыстальніка
|
disable_sign_in_token_auth_user: Адключыць аўтарызацыю праз электронную пошту для карыстальніка
|
||||||
disable_user: Адключыць карыстальніка
|
disable_user: Адключыць карыстальніка
|
||||||
enable_custom_emoji: Уключыць адвольныя эмодзі
|
enable_custom_emoji: Уключыць адвольныя эмодзі
|
||||||
enable_relay: Уключыць паўтор
|
enable_relay: Уключыць рэтранслятар
|
||||||
enable_sign_in_token_auth_user: Уключыць аўтарызацыю праз электронную пошту для карыстальніка
|
enable_sign_in_token_auth_user: Уключыць аўтарызацыю праз электронную пошту для карыстальніка
|
||||||
enable_user: Уключыць карыстальніка
|
enable_user: Уключыць карыстальніка
|
||||||
memorialize_account: Запомніць уліковы запіс
|
memorialize_account: Запомніць уліковы запіс
|
||||||
promote_user: Павысіць правы Карыстальніка
|
promote_user: Павысіць правы Карыстальніка
|
||||||
publish_terms_of_service: Апублікаваць Умовы выкарыстаньня
|
publish_terms_of_service: Апублікаваць умовы выкарыстання
|
||||||
reject_appeal: Адхіліць абскарджанне
|
reject_appeal: Адхіліць абскарджанне
|
||||||
reject_user: Адмовіць карыстальніку
|
reject_user: Адмовіць карыстальніку
|
||||||
remove_avatar_user: Выдаліць аватар
|
remove_avatar_user: Выдаліць аватар
|
||||||
|
@ -226,13 +228,13 @@ be:
|
||||||
resolve_report: Вырашыць скаргу
|
resolve_report: Вырашыць скаргу
|
||||||
sensitive_account: Уліковы запіс прымусова пазначаны як далікатны
|
sensitive_account: Уліковы запіс прымусова пазначаны як далікатны
|
||||||
silence_account: Абмежаваць уліковы запіс
|
silence_account: Абмежаваць уліковы запіс
|
||||||
suspend_account: Выключыць уліковы запіс
|
suspend_account: Прыпыніць уліковы запіс
|
||||||
unassigned_report: Прыбраць прызначэнне скаргі
|
unassigned_report: Прыбраць прызначэнне скаргі
|
||||||
unblock_email_account: Разблакіраваць электронны адрас
|
unblock_email_account: Разблакіраваць электронны адрас
|
||||||
unsensitive_account: Прымусовая пазнака далікатнасці прыбраная
|
unsensitive_account: Прымусовая пазнака далікатнасці прыбраная
|
||||||
unsilence_account: Уліковы запіс больш не абмежаваны
|
unsilence_account: Уліковы запіс больш не абмежаваны
|
||||||
unsuspend_account: Аднавіць уліковы запіс
|
unsuspend_account: Аднавіць уліковы запіс
|
||||||
update_announcement: Абнавіць аб'яву
|
update_announcement: Абнавіць аб’яву
|
||||||
update_custom_emoji: Абнавіць адвольныя эмодзі
|
update_custom_emoji: Абнавіць адвольныя эмодзі
|
||||||
update_domain_block: Актуалізаваць блакіроўку дамена
|
update_domain_block: Актуалізаваць блакіроўку дамена
|
||||||
update_ip_block: Абнавіць IP правіла
|
update_ip_block: Абнавіць IP правіла
|
||||||
|
@ -254,34 +256,34 @@ be:
|
||||||
create_domain_block_html: "%{name} заблакіраваў дамен %{target}"
|
create_domain_block_html: "%{name} заблакіраваў дамен %{target}"
|
||||||
create_email_domain_block_html: "%{name} заблакіраваў дамен эл. пошты %{target}"
|
create_email_domain_block_html: "%{name} заблакіраваў дамен эл. пошты %{target}"
|
||||||
create_ip_block_html: "%{name} стварыў правіла для IP %{target}"
|
create_ip_block_html: "%{name} стварыў правіла для IP %{target}"
|
||||||
create_relay_html: "%{name} стварыў(-а) паўтор %{target}"
|
create_relay_html: "%{name} стварыў(-ла) рэтранслятар %{target}"
|
||||||
create_unavailable_domain_html: "%{name} прыпыніў дастаўку да дамена %{target}"
|
create_unavailable_domain_html: "%{name} прыпыніў дастаўку да дамена %{target}"
|
||||||
create_user_role_html: "%{name} зрабіў ролю %{target}"
|
create_user_role_html: "%{name} зрабіў ролю %{target}"
|
||||||
demote_user_html: "%{name} прыбраў карыстальніка %{target}"
|
demote_user_html: "%{name} прыбраў карыстальніка %{target}"
|
||||||
destroy_announcement_html: "%{name} выдаліў аб'яву %{target}"
|
destroy_announcement_html: "%{name} выдаліў аб'яву %{target}"
|
||||||
destroy_canonical_email_block_html: "%{name} разблакіраваў эл. пошту з хэшам %{target}"
|
destroy_canonical_email_block_html: "%{name} разблакіраваў эл. пошту з хэшам %{target}"
|
||||||
destroy_custom_emoji_html: "%{name} выдаліў(а) эмоджі %{target}"
|
destroy_custom_emoji_html: "%{name} выдаліў(-ла) эмодзі %{target}"
|
||||||
destroy_domain_allow_html: "%{name} зняў дазвол на аб'яднанне з даменам %{target}\n"
|
destroy_domain_allow_html: "%{name} зняў(-ла) дазвол на аб’яднанне з даменам %{target}"
|
||||||
destroy_domain_block_html: "%{name} разблакаваў дамен %{target}"
|
destroy_domain_block_html: "%{name} разблакаваў дамен %{target}"
|
||||||
destroy_email_domain_block_html: "%{name} разблакіраваў дамен эл. пошты %{target}"
|
destroy_email_domain_block_html: "%{name} разблакіраваў дамен эл. пошты %{target}"
|
||||||
destroy_instance_html: "%{name} цалкам прыбраў дамен %{target}"
|
destroy_instance_html: "%{name} цалкам прыбраў дамен %{target}"
|
||||||
destroy_ip_block_html: "%{name} выдаліў правіла для IP %{target}"
|
destroy_ip_block_html: "%{name} выдаліў правіла для IP %{target}"
|
||||||
destroy_relay_html: "%{name} выдаліў(-ла) паўтор %{target}"
|
destroy_relay_html: "%{name} выдаліў(-ла) рэтранслятар %{target}"
|
||||||
destroy_status_html: "%{name} выдаліў допіс %{target}"
|
destroy_status_html: "%{name} выдаліў допіс %{target}"
|
||||||
destroy_unavailable_domain_html: "%{name} дазволіў працягнуць адпраўку на дамен %{target}"
|
destroy_unavailable_domain_html: "%{name} дазволіў працягнуць адпраўку на дамен %{target}"
|
||||||
destroy_user_role_html: "%{name} выдаліў ролю %{target}"
|
destroy_user_role_html: "%{name} выдаліў ролю %{target}"
|
||||||
disable_2fa_user_html: "%{name} амяніў абавязковую двухфактарную верыфікацыю для карыстальніка %{target}"
|
disable_2fa_user_html: "%{name} амяніў абавязковую двухфактарную верыфікацыю для карыстальніка %{target}"
|
||||||
disable_custom_emoji_html: "%{name} заблакіраваў эмодзі %{target}"
|
disable_custom_emoji_html: "%{name} заблакіраваў эмодзі %{target}"
|
||||||
disable_relay_html: "%{name} выключыў(-ла) паўтор %{target}"
|
disable_relay_html: "%{name} выключыў(-ла) рэтранслятар %{target}"
|
||||||
disable_sign_in_token_auth_user_html: "%{name} адключыў уваход праз эл. пошту для %{target}"
|
disable_sign_in_token_auth_user_html: "%{name} адключыў уваход праз эл. пошту для %{target}"
|
||||||
disable_user_html: "%{name} адключыў уваход для карыстальніка %{target}"
|
disable_user_html: "%{name} адключыў уваход для карыстальніка %{target}"
|
||||||
enable_custom_emoji_html: "%{name} уключыў эмодзі %{target}"
|
enable_custom_emoji_html: "%{name} уключыў эмодзі %{target}"
|
||||||
enable_relay_html: "%{name} уключыў(-ла) паўтор %{target}"
|
enable_relay_html: "%{name} уключыў(-ла) рэтранслятар %{target}"
|
||||||
enable_sign_in_token_auth_user_html: "%{name} уключыў уваход праз эл. пошту для %{target}"
|
enable_sign_in_token_auth_user_html: "%{name} уключыў уваход праз эл. пошту для %{target}"
|
||||||
enable_user_html: "%{name} уключыў уваход для карыстальніка %{target}"
|
enable_user_html: "%{name} уключыў уваход для карыстальніка %{target}"
|
||||||
memorialize_account_html: Карыстальнік %{name} пераключыў уліковы запіс %{target} у старонку памяці
|
memorialize_account_html: Карыстальнік %{name} пераключыў уліковы запіс %{target} у старонку памяці
|
||||||
promote_user_html: "%{name} павысіў карыстальніка %{target}"
|
promote_user_html: "%{name} павысіў карыстальніка %{target}"
|
||||||
publish_terms_of_service_html: "%{name} апублікаваў абнаўленьне ўмоваў абслугоўваньня"
|
publish_terms_of_service_html: "%{name} апублікаваў(-ла) абнаўленні ва ўмовах выкарыстання"
|
||||||
reject_appeal_html: "%{name} адхіліў запыт на абскарджанне %{target}"
|
reject_appeal_html: "%{name} адхіліў запыт на абскарджанне %{target}"
|
||||||
reject_user_html: "%{name} адхіліў рэгістрацыю з %{target}"
|
reject_user_html: "%{name} адхіліў рэгістрацыю з %{target}"
|
||||||
remove_avatar_user_html: "%{name} выдаліў аватар %{target}"
|
remove_avatar_user_html: "%{name} выдаліў аватар %{target}"
|
||||||
|
@ -291,13 +293,13 @@ be:
|
||||||
resolve_report_html: "%{name} вырашыў скаргу %{target}"
|
resolve_report_html: "%{name} вырашыў скаргу %{target}"
|
||||||
sensitive_account_html: "%{name} адзначыў медыя %{target} як далікатнае"
|
sensitive_account_html: "%{name} адзначыў медыя %{target} як далікатнае"
|
||||||
silence_account_html: "%{name} абмежаваў уліковы запіс %{target}"
|
silence_account_html: "%{name} абмежаваў уліковы запіс %{target}"
|
||||||
suspend_account_html: Уліковы запіс %{target} выключаны %{name}
|
suspend_account_html: Уліковы запіс %{target} прыпынены %{name}
|
||||||
unassigned_report_html: "%{name} знял(а) прызначэнне скаргі %{target}"
|
unassigned_report_html: "%{name} знял(а) прызначэнне скаргі %{target}"
|
||||||
unblock_email_account_html: "%{name} разблакіраваў эл. пошту %{target}"
|
unblock_email_account_html: "%{name} разблакіраваў эл. пошту %{target}"
|
||||||
unsensitive_account_html: "%{name} зняў адзнаку далікатнае з медыя %{target}"
|
unsensitive_account_html: "%{name} зняў адзнаку далікатнае з медыя %{target}"
|
||||||
unsilence_account_html: "%{name} зняў ліміт з уліковага запісу %{target}"
|
unsilence_account_html: "%{name} зняў ліміт з уліковага запісу %{target}"
|
||||||
unsuspend_account_html: Уліковы запіс %{target} адноўлены %{name}
|
unsuspend_account_html: Уліковы запіс %{target} адноўлены %{name}
|
||||||
update_announcement_html: "%{name} абнавіў аб'яву %{target}"
|
update_announcement_html: "%{name} абнавіў(-ла) аб’яву %{target}"
|
||||||
update_custom_emoji_html: "%{name} абнавіў эмодзі %{target}"
|
update_custom_emoji_html: "%{name} абнавіў эмодзі %{target}"
|
||||||
update_domain_block_html: "%{name} абнавіў блакіроўку дамена для %{target}"
|
update_domain_block_html: "%{name} абнавіў блакіроўку дамена для %{target}"
|
||||||
update_ip_block_html: "%{name} змяніў правіла для IP %{target}"
|
update_ip_block_html: "%{name} змяніў правіла для IP %{target}"
|
||||||
|
@ -311,7 +313,7 @@ be:
|
||||||
title: Аўдыт
|
title: Аўдыт
|
||||||
unavailable_instance: "(імя дамена недаступнае)"
|
unavailable_instance: "(імя дамена недаступнае)"
|
||||||
announcements:
|
announcements:
|
||||||
destroyed_msg: Аб'ява паспяхова выдалена!
|
destroyed_msg: Аб’ява выдалена!
|
||||||
edit:
|
edit:
|
||||||
title: Рэдагаваць абвестку
|
title: Рэдагаваць абвестку
|
||||||
empty: Не знайдзена ніводнай абвесткі
|
empty: Не знайдзена ніводнай абвесткі
|
||||||
|
@ -325,26 +327,26 @@ be:
|
||||||
scheduled_msg: Аб'ява запланавана да публікацыі!
|
scheduled_msg: Аб'ява запланавана да публікацыі!
|
||||||
title: Аб'явы
|
title: Аб'явы
|
||||||
unpublish: Зняць з публікацыі
|
unpublish: Зняць з публікацыі
|
||||||
unpublished_msg: Аб'ява паспяхова схована!
|
unpublished_msg: Аб’ява схавана!
|
||||||
updated_msg: Аб'ява паспяхова адноўлена!
|
updated_msg: Аб’ява абноўлена!
|
||||||
critical_update_pending: Чакаецца абнаўленне
|
critical_update_pending: Чакаецца абнаўленне
|
||||||
custom_emojis:
|
custom_emojis:
|
||||||
assign_category: Прызначыць катэгорыю
|
assign_category: Прызначыць катэгорыю
|
||||||
by_domain: Дамен
|
by_domain: Дамен
|
||||||
copied_msg: Лакальная копія эмодзі паспяхова створана
|
copied_msg: Створана лакальная копія эмодзі
|
||||||
copy: Скапіраваць
|
copy: Скапіраваць
|
||||||
copy_failed_msg: Немагчыма зрабіць лакальную копію гэтага эмодзі
|
copy_failed_msg: Немагчыма зрабіць лакальную копію гэтага эмодзі
|
||||||
create_new_category: Стварыць новую катэгорыю
|
create_new_category: Стварыць новую катэгорыю
|
||||||
created_msg: Эмодзі паспяхова створана!
|
created_msg: Эмодзі паспяхова створана!
|
||||||
delete: Выдаліць
|
delete: Выдаліць
|
||||||
destroyed_msg: Смайлік паспяхова прыбраны!
|
destroyed_msg: Уласнае эмодзі знішчана!
|
||||||
disable: Адключыць
|
disable: Адключыць
|
||||||
disabled: Адключана
|
disabled: Адключана
|
||||||
disabled_msg: Смайлік паспяхова адключаны
|
disabled_msg: Смайлік паспяхова адключаны
|
||||||
emoji: Эмодзі
|
emoji: Эмодзі
|
||||||
enable: Уключыць
|
enable: Уключыць
|
||||||
enabled: Уключана
|
enabled: Уключана
|
||||||
enabled_msg: Смайлік паспяхова ўключаны
|
enabled_msg: Эмодзі паспяхова ўключана
|
||||||
image_hint: PNG або GIF да %{size}
|
image_hint: PNG або GIF да %{size}
|
||||||
list: Паказваць
|
list: Паказваць
|
||||||
listed: Паказваецца
|
listed: Паказваецца
|
||||||
|
@ -423,7 +425,7 @@ be:
|
||||||
domain: Дамен
|
domain: Дамен
|
||||||
edit: Рэдагаваць блакіраванне дамену
|
edit: Рэдагаваць блакіраванне дамену
|
||||||
existing_domain_block: Вы ўжо налажылі стражэйшыя абмежаванні на %{name}.
|
existing_domain_block: Вы ўжо налажылі стражэйшыя абмежаванні на %{name}.
|
||||||
existing_domain_block_html: Вы ўжо налажылі стражэйшыя абмежаванні на %{name}, спачатку вам неабходна <a href="%{unblock_url}">разблакаваць гэты акаўнт</a>.
|
existing_domain_block_html: Вы ўжо наклалі больш строгія абмежаванні на %{name}, спачатку вам трэба <a href="%{unblock_url}">разблакіраваць гэты ўліковы запіс</a>.
|
||||||
export: Экспарт
|
export: Экспарт
|
||||||
import: Імпарт
|
import: Імпарт
|
||||||
new:
|
new:
|
||||||
|
@ -433,7 +435,7 @@ be:
|
||||||
desc_html: "<strong>Абмежаванне</strong> зробіць допісы людзей з гэтага дамену нябачнымі для тых, хто на іх не падпісаны. <strong>Выключэнне</strong> выдаліць усё змесціва, медыя і даныя профіляў дамену з вашага серверу. <strong>«Нічога»</strong> проста адхіліць медыя файлы."
|
desc_html: "<strong>Абмежаванне</strong> зробіць допісы людзей з гэтага дамену нябачнымі для тых, хто на іх не падпісаны. <strong>Выключэнне</strong> выдаліць усё змесціва, медыя і даныя профіляў дамену з вашага серверу. <strong>«Нічога»</strong> проста адхіліць медыя файлы."
|
||||||
noop: Пуста
|
noop: Пуста
|
||||||
silence: Абмежаваць
|
silence: Абмежаваць
|
||||||
suspend: Выключыць
|
suspend: Прыпыніць
|
||||||
title: Новы блок дамену
|
title: Новы блок дамену
|
||||||
no_domain_block_selected: Блакіроўкі даменаў не былі змененыя, таму што ні адзін з іх не быў выбраны
|
no_domain_block_selected: Блакіроўкі даменаў не былі змененыя, таму што ні адзін з іх не быў выбраны
|
||||||
not_permitted: Вам забаронена выконваць гэта дзеянне
|
not_permitted: Вам забаронена выконваць гэта дзеянне
|
||||||
|
@ -478,7 +480,7 @@ be:
|
||||||
no_file: Файл не выбраны
|
no_file: Файл не выбраны
|
||||||
export_domain_blocks:
|
export_domain_blocks:
|
||||||
import:
|
import:
|
||||||
description_html: Вы збіраецеся імпартаваць спіс даменных блокаў. Калі ласка, праглядзіце гэты спіс вельмі ўважліва, асабліва калі вы асабіста не з'яўляецеся аўтарам гэтага спісу.
|
description_html: Вы збіраецеся імпартаваць спіс даменных блокаў. Праглядзіце гэты спіс вельмі ўважліва, асабліва калі вы асабіста не з’яўляецеся аўтарам гэтага спіса.
|
||||||
existing_relationships_warning: Наяўныя зносіны
|
existing_relationships_warning: Наяўныя зносіны
|
||||||
private_comment_description_html: 'Каб дапамагчы вам адсочваць, адкуль паходзяць імпартаваныя блокі, імпартаваныя блокі будуць створаны з наступным прыватным каментарыем: <q>%{comment}</q>'
|
private_comment_description_html: 'Каб дапамагчы вам адсочваць, адкуль паходзяць імпартаваныя блокі, імпартаваныя блокі будуць створаны з наступным прыватным каментарыем: <q>%{comment}</q>'
|
||||||
private_comment_template: Імпартавана з %{source} %{date}
|
private_comment_template: Імпартавана з %{source} %{date}
|
||||||
|
@ -487,6 +489,26 @@ be:
|
||||||
new:
|
new:
|
||||||
title: Імпарт блакіровак дамену
|
title: Імпарт блакіровак дамену
|
||||||
no_file: Файл не выбраны
|
no_file: Файл не выбраны
|
||||||
|
fasp:
|
||||||
|
debug:
|
||||||
|
callbacks:
|
||||||
|
delete: Выдаліць
|
||||||
|
ip: IP-адрас
|
||||||
|
providers:
|
||||||
|
active: Актыўны
|
||||||
|
base_url: Базавы URL-адрас
|
||||||
|
delete: Выдаліць
|
||||||
|
edit: Рэдагаваць пастаўшчыка
|
||||||
|
finish_registration: Завяршыць рэгістрацыю
|
||||||
|
name: Назва
|
||||||
|
providers: Пастаўшчыкі
|
||||||
|
public_key_fingerprint: Лічбавы адбітак публічнага ключа
|
||||||
|
registrations:
|
||||||
|
confirm: Пацвердзіць
|
||||||
|
reject: Адхіліць
|
||||||
|
save: Захаваць
|
||||||
|
sign_in: Увайсці
|
||||||
|
title: FASP
|
||||||
follow_recommendations:
|
follow_recommendations:
|
||||||
description_html: "<strong>Рэкамендацыі падпісак, дапамогаюць новым карыстальнікам хутка знайсці цікавы кантэнт</strong>. Калі карыстальнік недастаткова ўзаемадзейнічаў з іншымі, каб сфарміраваць персанальныя рэкамендацыі прытрымлівацца, замест гэтага рэкамендуюцца гэтыя ўліковыя запісы. Яны штодзённа пераразлічваюцца з сумесі ўліковых запісаў з самымі апошнімі ўзаемадзеяннямі і найбольшай колькасцю мясцовых падпісчыкаў для дадзенай мовы."
|
description_html: "<strong>Рэкамендацыі падпісак, дапамогаюць новым карыстальнікам хутка знайсці цікавы кантэнт</strong>. Калі карыстальнік недастаткова ўзаемадзейнічаў з іншымі, каб сфарміраваць персанальныя рэкамендацыі прытрымлівацца, замест гэтага рэкамендуюцца гэтыя ўліковыя запісы. Яны штодзённа пераразлічваюцца з сумесі ўліковых запісаў з самымі апошнімі ўзаемадзеяннямі і найбольшай колькасцю мясцовых падпісчыкаў для дадзенай мовы."
|
||||||
language: Для мовы
|
language: Для мовы
|
||||||
|
@ -527,7 +549,7 @@ be:
|
||||||
reject_media: Адхіліць мультымедыя
|
reject_media: Адхіліць мультымедыя
|
||||||
reject_reports: Адхіліць справаздачы
|
reject_reports: Адхіліць справаздачы
|
||||||
silence: Ліміт
|
silence: Ліміт
|
||||||
suspend: Выключыць
|
suspend: Прыпыніць
|
||||||
policy: Палітыка
|
policy: Палітыка
|
||||||
reason: Публічная прычына
|
reason: Публічная прычына
|
||||||
title: Палітыкі кантэнту
|
title: Палітыкі кантэнту
|
||||||
|
@ -561,6 +583,11 @@ be:
|
||||||
all: Усе
|
all: Усе
|
||||||
limited: Абмежаваныя
|
limited: Абмежаваныя
|
||||||
title: Мадэрацыя
|
title: Мадэрацыя
|
||||||
|
moderation_notes:
|
||||||
|
create: Дадаць нататку мадэратара
|
||||||
|
created_msg: Нататка мадэратара для экзэмпляра сервера створана!
|
||||||
|
destroyed_msg: Нататка мадэратара экзэмпляра сервера выдалена!
|
||||||
|
title: Нататкі мадэратараў
|
||||||
private_comment: Прыватны каментарый
|
private_comment: Прыватны каментарый
|
||||||
public_comment: Публічны каментарый
|
public_comment: Публічны каментарый
|
||||||
purge: Ачысціць
|
purge: Ачысціць
|
||||||
|
@ -601,7 +628,7 @@ be:
|
||||||
relays:
|
relays:
|
||||||
add_new: Дадаць новы рэтранслятар
|
add_new: Дадаць новы рэтранслятар
|
||||||
delete: Выдаліць
|
delete: Выдаліць
|
||||||
description_html: "<strong>Федэрацыйны рэтранслятар</strong> - гэта прамежкавы сервер, які абменьваецца вялікімі аб'ёмамі публічных паведамленняў паміж серверамі, якія падпісваюцца і публікуюць на ім. <strong>Гэта можа дапамагчы малым і сярэднім серверам выяўляць кантэнт з fediverse</strong>, для чаго лакальным карыстальнікам у адваротным выпадку трэба было б уручную сачыць за іншымі людзьмі на аддаленых серверах."
|
description_html: "<strong>Федэрацыйны рэтранслятар</strong> - гэта прамежкавы сервер, які абменьваецца вялікімі аб’ёмамі публічных паведамленняў паміж серверамі, якія падпісваюцца і робяць публікацыі на ім. <strong>Гэта можа дапамагчы малым і сярэднім серверам выяўляць змесціва з fediverse</strong>, бо ў іншым выпадку лакальным карыстальнікам трэба было б уручную сачыць за іншымі людзьмі на аддаленых серверах."
|
||||||
disable: Адключыць
|
disable: Адключыць
|
||||||
disabled: Адключана
|
disabled: Адключана
|
||||||
enable: Уключыць
|
enable: Уключыць
|
||||||
|
@ -635,11 +662,11 @@ be:
|
||||||
suspend_description_html: Уліковы запіс і ўсё яго змесціва будзе недаступна і ў далейшым выдалены, узаемадзеянне з ім будзе немагчыма. Магчыма адмяніць на працягу 30 дзён. Закрывае ўсе скаргі на гэты ўліковы запіс.
|
suspend_description_html: Уліковы запіс і ўсё яго змесціва будзе недаступна і ў далейшым выдалены, узаемадзеянне з ім будзе немагчыма. Магчыма адмяніць на працягу 30 дзён. Закрывае ўсе скаргі на гэты ўліковы запіс.
|
||||||
actions_description_html: Вырашыце, якія дзеянні распачаць, каб вырашыць гэтую скаргу. Калі вы прымеце меры пакарання ў дачыненні да ўліковага запісу, пра які паведамляецца, ім будзе адпраўлена апавяшчэнне па электроннай пошце, за выключэннем выпадкаў, калі выбрана катэгорыя <strong>Спам</strong>.
|
actions_description_html: Вырашыце, якія дзеянні распачаць, каб вырашыць гэтую скаргу. Калі вы прымеце меры пакарання ў дачыненні да ўліковага запісу, пра які паведамляецца, ім будзе адпраўлена апавяшчэнне па электроннай пошце, за выключэннем выпадкаў, калі выбрана катэгорыя <strong>Спам</strong>.
|
||||||
actions_description_remote_html: Вырашыце як паступіць з гэтай скаргай. Гэта паўплывае толькі на тое як <strong>ваш</strong> сервер звязваецца з аддалёным уліковым запісам і апрацоўвае яго кантэнт.
|
actions_description_remote_html: Вырашыце як паступіць з гэтай скаргай. Гэта паўплывае толькі на тое як <strong>ваш</strong> сервер звязваецца з аддалёным уліковым запісам і апрацоўвае яго кантэнт.
|
||||||
actions_no_posts: У гэтай скаргі няма зьвязаных паведамленьняў для выдаленьня
|
actions_no_posts: Да гэтай скаргі не прывязаны допісы да выдалення
|
||||||
add_to_report: Дадаць яшчэ дэталяў да скаргі
|
add_to_report: Дадаць яшчэ дэталяў да скаргі
|
||||||
already_suspended_badges:
|
already_suspended_badges:
|
||||||
local: Ужо прыпынена на гэтым сэрвэры
|
local: Ужо прыпынена на гэтым серверы
|
||||||
remote: Ужо прыпынена на іх сэрвэры
|
remote: Ужо прыпынена на іх серверы
|
||||||
are_you_sure: Вы ўпэўнены?
|
are_you_sure: Вы ўпэўнены?
|
||||||
assign_to_self: Прызначыць мне
|
assign_to_self: Прызначыць мне
|
||||||
assigned: Прызначаны мадэратар
|
assigned: Прызначаны мадэратар
|
||||||
|
@ -668,7 +695,7 @@ be:
|
||||||
delete: Выдаліць
|
delete: Выдаліць
|
||||||
placeholder: Апішыце, якія дзеянні былі зроблены, або любыя іншыя звязаныя абнаўленні...
|
placeholder: Апішыце, якія дзеянні былі зроблены, або любыя іншыя звязаныя абнаўленні...
|
||||||
title: Нататкі
|
title: Нататкі
|
||||||
notes_description_html: Праглядвайце і пакідайце нататкі іншым мадэратарам і сабе ў будучыні
|
notes_description_html: Праглядайце і пакідайце нататкі для іншых мадэратараў і сябе ў будучыні
|
||||||
processed_msg: 'Скарга #%{id} паспяхова апрацавана'
|
processed_msg: 'Скарга #%{id} паспяхова апрацавана'
|
||||||
quick_actions_description_html: 'Выканайце хуткае дзеянне або пракруціце ўніз, каб убачыць змесціва, на якое пададзена скарга:'
|
quick_actions_description_html: 'Выканайце хуткае дзеянне або пракруціце ўніз, каб убачыць змесціва, на якое пададзена скарга:'
|
||||||
remote_user_placeholder: аддалены карыстальнік з %{instance}
|
remote_user_placeholder: аддалены карыстальнік з %{instance}
|
||||||
|
@ -738,12 +765,12 @@ be:
|
||||||
delete_user_data_description: Дазваляе карыстальнікам без затрымкі выдаляць даныя іншых карыстальнікаў
|
delete_user_data_description: Дазваляе карыстальнікам без затрымкі выдаляць даныя іншых карыстальнікаў
|
||||||
invite_users: Запрашэнне карыстальнікаў
|
invite_users: Запрашэнне карыстальнікаў
|
||||||
invite_users_description: Дазваляе запрашаць новых людзей на сервер
|
invite_users_description: Дазваляе запрашаць новых людзей на сервер
|
||||||
manage_announcements: Кіраванне аб'явамі
|
manage_announcements: Кіраванне аб’явамі
|
||||||
manage_announcements_description: Дазваляе кіраваць аб'явамі на серверы
|
manage_announcements_description: Дазваляе кіраваць аб’явамі на серверы
|
||||||
manage_appeals: Кіраванне апеляцыямі
|
manage_appeals: Кіраванне апеляцыямі
|
||||||
manage_appeals_description: Дазваляе карыстальнікам разглядаць апеляцыі на дзеянні мадэратара
|
manage_appeals_description: Дазваляе карыстальнікам разглядаць апеляцыі на дзеянні мадэратара
|
||||||
manage_blocks: Кіраванне блакіроўкамі
|
manage_blocks: Кіраванне блакіроўкамі
|
||||||
manage_blocks_description: Дазваляе блакаваць пэўныя паштовыя правайдэры і IP адрасы
|
manage_blocks_description: Дазваляе блакіраваць пэўных пастаўшчыкоў паслуг электроннай пошты і IP адрасы
|
||||||
manage_custom_emojis: Кіраванне адвольнымі эмодзі
|
manage_custom_emojis: Кіраванне адвольнымі эмодзі
|
||||||
manage_custom_emojis_description: Дазваляе кіраваць адвольнымі эмодзі на серверы
|
manage_custom_emojis_description: Дазваляе кіраваць адвольнымі эмодзі на серверы
|
||||||
manage_federation: Кіраваць федэрацыяй
|
manage_federation: Кіраваць федэрацыяй
|
||||||
|
@ -775,11 +802,14 @@ be:
|
||||||
title: Ролі
|
title: Ролі
|
||||||
rules:
|
rules:
|
||||||
add_new: Дадаць правіла
|
add_new: Дадаць правіла
|
||||||
|
add_translation: Дадаць пераклад
|
||||||
delete: Выдаліць
|
delete: Выдаліць
|
||||||
description_html: Большасць сцвярджаюць, што прачыталі ўмовы абслугоўвання і згаджаюцца з імі, але звычайна людзі не чытаюць іх да канца, пакуль не ўзнікне праблема. <strong>Таму зрабіце правілы вашага сервера простымі з першага погляду, прадставіўшы іх у выглядзе маркіраванага спісу.</strong> Старайцеся рабіць правілы кароткімі і простымі, але не разбіваць іх на шмат асобных пунктаў.
|
description_html: Большасць сцвярджаюць, што прачыталі ўмовы абслугоўвання і згаджаюцца з імі, але звычайна людзі не чытаюць іх да канца, пакуль не ўзнікне праблема. <strong>Таму зрабіце правілы вашага сервера простымі з першага погляду, прадставіўшы іх у выглядзе маркіраванага спісу.</strong> Старайцеся рабіць правілы кароткімі і простымі, але не разбіваць іх на шмат асобных пунктаў.
|
||||||
edit: Рэдагаваць правіла
|
edit: Рэдагаваць правіла
|
||||||
empty: Правілы сервера яшчэ не вызначаны.
|
empty: Правілы сервера яшчэ не вызначаны.
|
||||||
title: Правілы сервера
|
title: Правілы сервера
|
||||||
|
translation: Пераклад
|
||||||
|
translations: Пераклады
|
||||||
settings:
|
settings:
|
||||||
about:
|
about:
|
||||||
manage_rules: Кіраваць правіламі сервера
|
manage_rules: Кіраваць правіламі сервера
|
||||||
|
@ -793,7 +823,7 @@ be:
|
||||||
preamble: Брэндынг вашага сервера адрознівае яго ад іншых сервераў у сетцы. Гэтая інфармацыя можа адлюстроўвацца ў розных асяроддзях, напрыклад, у вэб-інтэрфейсе Mastodon, уласных праграмах, у папярэднім праглядзе спасылак на іншых вэб-сайтах і ў праграмах абмену паведамленнямі і гэтак далей. Па гэтай прычыне лепш трымаць гэтую інфармацыю яснай, кароткай і сціслай.
|
preamble: Брэндынг вашага сервера адрознівае яго ад іншых сервераў у сетцы. Гэтая інфармацыя можа адлюстроўвацца ў розных асяроддзях, напрыклад, у вэб-інтэрфейсе Mastodon, уласных праграмах, у папярэднім праглядзе спасылак на іншых вэб-сайтах і ў праграмах абмену паведамленнямі і гэтак далей. Па гэтай прычыне лепш трымаць гэтую інфармацыю яснай, кароткай і сціслай.
|
||||||
title: Брэндынг
|
title: Брэндынг
|
||||||
captcha_enabled:
|
captcha_enabled:
|
||||||
desc_html: Гэта функцыянальнасць залежыць ад знешніх скрыптоў hCaptcha, што можа быць праблемай бяспекі і прыватнасці. Акрамя таго, <strong>гэта можа зрабіць працэс рэгістрацыі значна менш даступным для некаторых людзей, асабліва інвалідаў</strong>. Па гэтых прычынах, калі ласка, разгледзьце альтэрнатыўныя меры, такія як рэгістрацыя на аснове зацвярджэння або запрашэння.
|
desc_html: Гэта функцыянальнасць залежыць ад знешніх скрыптоў hCaptcha, што можа быць праблемай бяспекі і прыватнасці. Акрамя таго, <strong>гэта можыць зменшыць даступнасць працэсу рэгістрацыі для некаторых людзей (асабліва інвалідаў)</strong>. Па гэтых прычынах, разгледзьце альтэрнатыўныя меры, такія як рэгістрацыя на аснове зацвярджэння або запрашэння.
|
||||||
title: Патрабаваць ад новых карыстальнікаў рашэння CAPTCHA для пацверджання іх уліковага запісу
|
title: Патрабаваць ад новых карыстальнікаў рашэння CAPTCHA для пацверджання іх уліковага запісу
|
||||||
content_retention:
|
content_retention:
|
||||||
danger_zone: Небяспечная зона
|
danger_zone: Небяспечная зона
|
||||||
|
@ -805,11 +835,12 @@ be:
|
||||||
discovery:
|
discovery:
|
||||||
follow_recommendations: Выконвайце рэкамендацыі
|
follow_recommendations: Выконвайце рэкамендацыі
|
||||||
preamble: Прадстаўленне цікавага кантэнту дапамагае прыцягнуць новых карыстальнікаў, якія могуць не ведаць нікога на Mastodon. Кантралюйце працу розных функцый выяўлення на вашым серверы.
|
preamble: Прадстаўленне цікавага кантэнту дапамагае прыцягнуць новых карыстальнікаў, якія могуць не ведаць нікога на Mastodon. Кантралюйце працу розных функцый выяўлення на вашым серверы.
|
||||||
|
privacy: Прыватнасць
|
||||||
profile_directory: Дырэкторыя профіляў
|
profile_directory: Дырэкторыя профіляў
|
||||||
public_timelines: Публічная паслядоўнасць публікацый
|
public_timelines: Публічная паслядоўнасць публікацый
|
||||||
publish_statistics: Апублікаваць статыстыку
|
publish_statistics: Апублікаваць статыстыку
|
||||||
title: Выяўленне
|
title: Выяўленне
|
||||||
trends: Актуальныя
|
trends: Трэнды
|
||||||
domain_blocks:
|
domain_blocks:
|
||||||
all: Для ўсіх
|
all: Для ўсіх
|
||||||
disabled: Нікому
|
disabled: Нікому
|
||||||
|
@ -854,7 +885,7 @@ be:
|
||||||
add_to_report: 'Дадаць да скаргі #%{id}'
|
add_to_report: 'Дадаць да скаргі #%{id}'
|
||||||
remove_from_report: Выдаліць са справаздачы
|
remove_from_report: Выдаліць са справаздачы
|
||||||
report: Справаздача
|
report: Справаздача
|
||||||
contents: Зьмест
|
contents: Змест
|
||||||
deleted: Выдалены
|
deleted: Выдалены
|
||||||
favourites: Упадабаныя
|
favourites: Упадабаныя
|
||||||
history: Гісторыя версій
|
history: Гісторыя версій
|
||||||
|
@ -863,7 +894,7 @@ be:
|
||||||
media:
|
media:
|
||||||
title: Медыя
|
title: Медыя
|
||||||
metadata: Метаданыя
|
metadata: Метаданыя
|
||||||
no_history: Гэты пост не рэдагаваўся
|
no_history: Гэты допіс не рэдагаваўся
|
||||||
no_status_selected: Ніводная публікацыя не была зменена, бо ніводная не была выбрана
|
no_status_selected: Ніводная публікацыя не была зменена, бо ніводная не была выбрана
|
||||||
open: Адкрыць допіс
|
open: Адкрыць допіс
|
||||||
original_status: Зыходны допіс
|
original_status: Зыходны допіс
|
||||||
|
@ -872,7 +903,7 @@ be:
|
||||||
status_changed: Допіс зменены
|
status_changed: Допіс зменены
|
||||||
status_title: Допіс карыстальніка @%{name}
|
status_title: Допіс карыстальніка @%{name}
|
||||||
title: Допісы карыстальніка - @%{name}
|
title: Допісы карыстальніка - @%{name}
|
||||||
trending: Папулярныя
|
trending: Трэндавае
|
||||||
view_publicly: Глядзець публічна
|
view_publicly: Глядзець публічна
|
||||||
visibility: Бачнасць
|
visibility: Бачнасць
|
||||||
with_media: З медыя
|
with_media: З медыя
|
||||||
|
@ -890,13 +921,13 @@ be:
|
||||||
appeal_rejected: Абскарджанне адхілена
|
appeal_rejected: Абскарджанне адхілена
|
||||||
system_checks:
|
system_checks:
|
||||||
database_schema_check:
|
database_schema_check:
|
||||||
message_html: Ёсць незавершаныя міграцыі базы дадзеных. Калі ласка, запусціце іх, каб пераканацца, што дадатак паводзіць сябе належным чынам
|
message_html: Ёсць незавершаныя міграцыі базы даных. Запусціце іх, каб пераканацца, што праграма паводзіць сябе належным чынам
|
||||||
elasticsearch_health_red:
|
elasticsearch_health_red:
|
||||||
message_html: Кластар Elasticsearch нездаровы (чырвоны статус), функцыі пошуку недаступныя
|
message_html: Кластар Elasticsearch нездаровы (чырвоны статус), функцыі пошуку недаступныя
|
||||||
elasticsearch_health_yellow:
|
elasticsearch_health_yellow:
|
||||||
message_html: Кластар Elasticsearch нездаровы (жоўты статус), магчыма, неабходна высветліць прычыну
|
message_html: Кластар Elasticsearch нездаровы (жоўты статус), магчыма, неабходна высветліць прычыну
|
||||||
elasticsearch_index_mismatch:
|
elasticsearch_index_mismatch:
|
||||||
message_html: Супастаўленне індэксаў Elasticsearch састарэла. Калі ласка, выканайце каманду <code>tootctl search deploy --only=%{value}</code>
|
message_html: Супастаўленне індэксаў Elasticsearch састарэла. Выканайце каманду <code>tootctl search deploy --only=%{value}</code>
|
||||||
elasticsearch_preset:
|
elasticsearch_preset:
|
||||||
action: Падрабязней у дакументацыі
|
action: Падрабязней у дакументацыі
|
||||||
message_html: Ваш кластар Elasticsearch мае больш за адзін вузел, але Mastodon не наладжаны на іх выкарыстанне.
|
message_html: Ваш кластар Elasticsearch мае больш за адзін вузел, але Mastodon не наладжаны на іх выкарыстанне.
|
||||||
|
@ -906,7 +937,7 @@ be:
|
||||||
elasticsearch_reset_chewy:
|
elasticsearch_reset_chewy:
|
||||||
message_html: Ваш сістэмны індэкс Elasticsearch састарэлы з-за змены налад. Для яго абнаўлення выканайце каманду <code>tootctl search deploy --reset-chewy</code>.
|
message_html: Ваш сістэмны індэкс Elasticsearch састарэлы з-за змены налад. Для яго абнаўлення выканайце каманду <code>tootctl search deploy --reset-chewy</code>.
|
||||||
elasticsearch_running_check:
|
elasticsearch_running_check:
|
||||||
message_html: Немагчыма падключыцца да Elasticsearch. Калі ласка, праверце, што ён запушчаны, або адключыце паўнатэкставы пошук
|
message_html: Немагчыма падключыцца да Elasticsearch. Праверце, што ён запушчаны, або адключыце пошук па ўсім тэксце
|
||||||
elasticsearch_version_check:
|
elasticsearch_version_check:
|
||||||
message_html: 'Несумяшчальная версія Elasticsearch: %{value}'
|
message_html: 'Несумяшчальная версія Elasticsearch: %{value}'
|
||||||
version_comparison: Elasticsearch %{running_version} выяўлены, але патрабуецца %{required_version}
|
version_comparison: Elasticsearch %{running_version} выяўлены, але патрабуецца %{required_version}
|
||||||
|
@ -916,11 +947,11 @@ be:
|
||||||
sidekiq_process_check:
|
sidekiq_process_check:
|
||||||
message_html: Не працуе працэс Sidekiq для %{value} чаргі. Калі ласка праверце вашу канфігурацыю Sidekiq
|
message_html: Не працуе працэс Sidekiq для %{value} чаргі. Калі ласка праверце вашу канфігурацыю Sidekiq
|
||||||
software_version_check:
|
software_version_check:
|
||||||
action: Праверыць наяўнасьць абнаўленьняў
|
action: Праверыць наяўнасць абнаўленняў
|
||||||
message_html: Даступна абнаўленьне Mastodon.
|
message_html: Даступна абнаўленне Mastodon.
|
||||||
software_version_critical_check:
|
software_version_critical_check:
|
||||||
action: Прагледзець даступныя абнаўленні
|
action: Прагледзець даступныя абнаўленні
|
||||||
message_html: Даступна крытычнае абнаўленне Mastodon, калі ласка, зрабіце абнаўленне як мага хутчэй.
|
message_html: Даступна крытычнае абнаўленне Mastodon, абнавіцеся як мага хутчэй.
|
||||||
software_version_patch_check:
|
software_version_patch_check:
|
||||||
action: Прагледзець даступныя абнаўленні
|
action: Прагледзець даступныя абнаўленні
|
||||||
message_html: Даступна абнаўленне Mastodon з выпраўленнем памылак.
|
message_html: Даступна абнаўленне Mastodon з выпраўленнем памылак.
|
||||||
|
@ -932,13 +963,13 @@ be:
|
||||||
message_html: "<strong>Ваша сховішча не наладжана. Прыватнасць карыстальнікаў пад пагрозай.</strong>"
|
message_html: "<strong>Ваша сховішча не наладжана. Прыватнасць карыстальнікаў пад пагрозай.</strong>"
|
||||||
tags:
|
tags:
|
||||||
moderation:
|
moderation:
|
||||||
not_trendable: Не ў трэндзе
|
not_trendable: Не можа трапіць у трэнды
|
||||||
not_usable: Непрыгодныя
|
not_usable: Непрыгодныя
|
||||||
pending_review: Чакае праверкі
|
pending_review: Чакае праверкі
|
||||||
review_requested: Патрабуюць прагледжвання
|
review_requested: Патрабуюць прагледжвання
|
||||||
reviewed: Прагледжаныя
|
reviewed: Прагледжаныя
|
||||||
title: Стан
|
title: Стан
|
||||||
trendable: У трэндзе
|
trendable: Можа трапіць у трэнды
|
||||||
unreviewed: Непрагледжаныя
|
unreviewed: Непрагледжаныя
|
||||||
usable: Прыгодныя
|
usable: Прыгодныя
|
||||||
name: Назва
|
name: Назва
|
||||||
|
@ -951,18 +982,26 @@ be:
|
||||||
title: Хэштэгі
|
title: Хэштэгі
|
||||||
updated_msg: Налады хэштэгаў паспяхова змененыя
|
updated_msg: Налады хэштэгаў паспяхова змененыя
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
back: Вернуцца да ўмоваў абслугоўваньня
|
back: Вернуцца да ўмоў выкарыстання
|
||||||
changelog: Што зьмянілася
|
changelog: Што змянілася
|
||||||
create: Выкарыстоўвайце свой уласны
|
create: Выкарыстоўвайце свой тэкст
|
||||||
current: Цякучы
|
current: Бягучыя
|
||||||
draft: Чарнавік
|
draft: Чарнавік
|
||||||
generate: Выкарыстаць шаблон
|
generate: Выкарыстаць шаблон
|
||||||
generates:
|
generates:
|
||||||
action: Зґенераваць
|
action: Згенерыраваць
|
||||||
|
history: Гісторыя
|
||||||
|
live: Дзейнічае
|
||||||
|
notify_users: Апавясціць карыстальнікаў
|
||||||
|
publish: Апублікаваць
|
||||||
|
published_on_html: Апублікавана %{date}
|
||||||
|
save_draft: Захаваць чарнавік
|
||||||
|
title: Умовы выкарыстання
|
||||||
title: Адміністрацыя
|
title: Адміністрацыя
|
||||||
trends:
|
trends:
|
||||||
allow: Дазволіць
|
allow: Дазволіць
|
||||||
approved: Пацверджаны
|
approved: Пацверджаны
|
||||||
|
confirm_allow: Вы ўпэўнены, што хочаце дазволіць выбраныя тэгі?
|
||||||
disallow: Забараніць
|
disallow: Забараніць
|
||||||
links:
|
links:
|
||||||
allow: Дазволіць спасылка
|
allow: Дазволіць спасылка
|
||||||
|
@ -978,15 +1017,15 @@ be:
|
||||||
many: Абагулілі %{count} чалавек за апошні тыдзень
|
many: Абагулілі %{count} чалавек за апошні тыдзень
|
||||||
one: Абагуліў адзін чалавек за апошні тыдзень
|
one: Абагуліў адзін чалавек за апошні тыдзень
|
||||||
other: Абагулілі %{count} чалавек за апошні тыдзень
|
other: Абагулілі %{count} чалавек за апошні тыдзень
|
||||||
title: Актуальныя спасылкі
|
title: Трэндавыя спасылкі
|
||||||
usage_comparison: Выкарыстоўвалася %{today} разоў сёння, у параўнанні з %{yesterday} учора
|
usage_comparison: Выкарыстоўвалася %{today} разоў сёння, у параўнанні з %{yesterday} учора
|
||||||
not_allowed_to_trend: Забаронена выходзіць у актуальныя
|
not_allowed_to_trend: Забаронена выходзіць у трэнды
|
||||||
only_allowed: Толькі дазволенае
|
only_allowed: Толькі дазволенае
|
||||||
pending_review: Чакае праверкі
|
pending_review: Чакае праверкі
|
||||||
preview_card_providers:
|
preview_card_providers:
|
||||||
allowed: Спасылкі ад гэтага выдаўца не будуць у трэндзе
|
allowed: Спасылкі ад гэтага выдаўца не будуць у трэндзе
|
||||||
description_html: Спасылкі з гэтых даменаў часта абагульняюцца на вашым серверы. Спасылкі не трапяць у публічныя трэнды, калі дамен спасылкі не ўхвалены. Вашае ўхваленне (ці адхіленне) распаўсюдзіцца на субдамены.
|
description_html: Спасылкі з гэтых даменаў часта абагульняюцца на вашым серверы. Спасылкі не трапяць у публічныя трэнды, калі дамен спасылкі не ўхвалены. Вашае ўхваленне (ці адхіленне) распаўсюдзіцца на субдамены.
|
||||||
rejected: Спасылкі ад гэтага выдаўца не будуць у трэнде
|
rejected: Спасылкі ад гэтага выдаўца не будуць у трэндзе
|
||||||
title: Выдаўцы
|
title: Выдаўцы
|
||||||
rejected: Адхілена
|
rejected: Адхілена
|
||||||
statuses:
|
statuses:
|
||||||
|
@ -1002,7 +1041,7 @@ be:
|
||||||
many: Пашыраны або ўпадабаны %{friendly_count} разоў
|
many: Пашыраны або ўпадабаны %{friendly_count} разоў
|
||||||
one: Пашыраны або ўпадабаны %{friendly_count} раз
|
one: Пашыраны або ўпадабаны %{friendly_count} раз
|
||||||
other: Пашыраны або ўпадабаны %{friendly_count} разоў
|
other: Пашыраны або ўпадабаны %{friendly_count} разоў
|
||||||
title: Актуальныя допісы
|
title: Трэндавыя допісы
|
||||||
tags:
|
tags:
|
||||||
current_score: Бягучы рэзультат %{score}
|
current_score: Бягучы рэзультат %{score}
|
||||||
dashboard:
|
dashboard:
|
||||||
|
@ -1015,11 +1054,11 @@ be:
|
||||||
listable: Можа быць прапанавана
|
listable: Можа быць прапанавана
|
||||||
no_tag_selected: Ніводны тэг не быў зменены, бо ніводны не быў выбраны
|
no_tag_selected: Ніводны тэг не быў зменены, бо ніводны не быў выбраны
|
||||||
not_listable: Не будзе прапанавана
|
not_listable: Не будзе прапанавана
|
||||||
not_trendable: Не з'явіцца ў трэндах
|
not_trendable: Не з’явіцца сярод трэндаў
|
||||||
not_usable: Немагчыма выкарыстаць
|
not_usable: Немагчыма выкарыстаць
|
||||||
peaked_on_and_decaying: На піку %{date}, зараз спадае
|
peaked_on_and_decaying: На піку %{date}, зараз спадае
|
||||||
title: Актуальныя хэштэгі
|
title: Актуальныя хэштэгі
|
||||||
trendable: Можа з'явіцца сярод трэндаў
|
trendable: Можа з’явіцца сярод трэндаў
|
||||||
trending_rank: 'Папулярнае #%{rank}'
|
trending_rank: 'Папулярнае #%{rank}'
|
||||||
usable: Магчыма выкарыстаць
|
usable: Магчыма выкарыстаць
|
||||||
usage_comparison: Выкарыстоўвалася %{today} разоў сёння, у параўнанні з %{yesterday} учора
|
usage_comparison: Выкарыстоўвалася %{today} разоў сёння, у параўнанні з %{yesterday} учора
|
||||||
|
@ -1029,7 +1068,7 @@ be:
|
||||||
one: Выкарыстаў адзін чалавек за апошні тыдзень
|
one: Выкарыстаў адзін чалавек за апошні тыдзень
|
||||||
other: Выкарысталі %{count} чалавек за апошні тыдзень
|
other: Выкарысталі %{count} чалавек за апошні тыдзень
|
||||||
title: Рэкамендацыі і трэнды
|
title: Рэкамендацыі і трэнды
|
||||||
trending: Папулярныя
|
trending: Трэндавае
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Дадаць новы
|
add_new: Дадаць новы
|
||||||
delete: Выдаліць
|
delete: Выдаліць
|
||||||
|
@ -1070,7 +1109,7 @@ be:
|
||||||
none: папярэджанне
|
none: папярэджанне
|
||||||
sensitive: пазначыць уліковы запіс як далікатны
|
sensitive: пазначыць уліковы запіс як далікатны
|
||||||
silence: абмежаваць уліковы запіс
|
silence: абмежаваць уліковы запіс
|
||||||
suspend: выключыць уліковы запіс
|
suspend: каб прыпыніць гэты ўліковы запіс
|
||||||
body: "%{target} абскарджвае рашэнне мадэратара %{action_taken_by} ад %{date}, якая была %{type}. Яны напісалі:"
|
body: "%{target} абскарджвае рашэнне мадэратара %{action_taken_by} ад %{date}, якая была %{type}. Яны напісалі:"
|
||||||
next_steps: Вы можаце ўхваліць апеляцыю каб адмяніць рашэнне мадэратараў ці ігнараваць яе.
|
next_steps: Вы можаце ўхваліць апеляцыю каб адмяніць рашэнне мадэратараў ці ігнараваць яе.
|
||||||
subject: "%{username} абскарджвае рашэнне мадэратараў на %{instance}"
|
subject: "%{username} абскарджвае рашэнне мадэратараў на %{instance}"
|
||||||
|
@ -1090,12 +1129,12 @@ be:
|
||||||
new_trends:
|
new_trends:
|
||||||
body: 'Гэтыя элементы трэба праверыць, перш чым публікаваць:'
|
body: 'Гэтыя элементы трэба праверыць, перш чым публікаваць:'
|
||||||
new_trending_links:
|
new_trending_links:
|
||||||
title: Папулярныя спасылкі
|
title: Трэндавыя спасылкі
|
||||||
new_trending_statuses:
|
new_trending_statuses:
|
||||||
title: Папулярныя допісы
|
title: Трэндавыя допісы
|
||||||
new_trending_tags:
|
new_trending_tags:
|
||||||
title: Папулярныя хэштэгі
|
title: Трэндавыя хэштэгі
|
||||||
subject: Новае ў папулярным для разгляду %{instance}
|
subject: Новыя трэнды да прагляду %{instance}
|
||||||
aliases:
|
aliases:
|
||||||
add_new: Стварыць псеўданім
|
add_new: Стварыць псеўданім
|
||||||
created_msg: Створаны новы псеўданім. Цяпер вы можаце пачаць пераход са старога ўліковага запісу.
|
created_msg: Створаны новы псеўданім. Цяпер вы можаце пачаць пераход са старога ўліковага запісу.
|
||||||
|
@ -1147,7 +1186,7 @@ be:
|
||||||
welcome_title: Вітаем, %{name}!
|
welcome_title: Вітаем, %{name}!
|
||||||
wrong_email_hint: Калі гэты адрас электроннай пошты памылковы, вы можаце змяніць яго ў наладах уліковага запісу.
|
wrong_email_hint: Калі гэты адрас электроннай пошты памылковы, вы можаце змяніць яго ў наладах уліковага запісу.
|
||||||
delete_account: Выдаліць уліковы запіс
|
delete_account: Выдаліць уліковы запіс
|
||||||
delete_account_html: Калі вы жадаеце выдаліць ваш уліковы запіс, можаце <a href="%{path}">працягнуць тут</a>. Ад вас будзе запатрабавана пацвярджэнне.
|
delete_account_html: Калі вы жадаеце выдаліць свой уліковы запіс, вы можаце <a href="%{path}">працягнуць тут</a>. Ад вас спатрэбіцца пацвярджэнне.
|
||||||
description:
|
description:
|
||||||
prefix_invited_by_user: "@%{name} запрашае вас далучыцца да гэтага сервера ў Mastodon!"
|
prefix_invited_by_user: "@%{name} запрашае вас далучыцца да гэтага сервера ў Mastodon!"
|
||||||
prefix_sign_up: Зарэгістравацца ў Mastodon сёння!
|
prefix_sign_up: Зарэгістравацца ў Mastodon сёння!
|
||||||
|
@ -1166,7 +1205,7 @@ be:
|
||||||
or_log_in_with: Або ўвайсці з дапамогай
|
or_log_in_with: Або ўвайсці з дапамогай
|
||||||
progress:
|
progress:
|
||||||
confirm: Пацвердзіць email
|
confirm: Пацвердзіць email
|
||||||
details: Вашы дадзеныя
|
details: Вашы даныя
|
||||||
review: Наш водгук
|
review: Наш водгук
|
||||||
rules: Прыняць правілы
|
rules: Прыняць правілы
|
||||||
providers:
|
providers:
|
||||||
|
@ -1207,6 +1246,10 @@ be:
|
||||||
view_strikes: Праглядзець мінулыя папярэджанні для вашага ўліковага запісу
|
view_strikes: Праглядзець мінулыя папярэджанні для вашага ўліковага запісу
|
||||||
too_fast: Форма адпраўлена занадта хутка, паспрабуйце яшчэ раз.
|
too_fast: Форма адпраўлена занадта хутка, паспрабуйце яшчэ раз.
|
||||||
use_security_key: Выкарыстаеце ключ бяспекі
|
use_security_key: Выкарыстаеце ключ бяспекі
|
||||||
|
author_attribution:
|
||||||
|
example_title: Прыклад тэксту
|
||||||
|
s_blog: Блог %{name}
|
||||||
|
title: Пазначэнне аўтарства
|
||||||
challenge:
|
challenge:
|
||||||
confirm: Працягнуць
|
confirm: Працягнуць
|
||||||
hint_html: "<strong>Парада:</strong> Мы не будзем запытваць ваш пароль зноўку на працягу наступнай гадзіны."
|
hint_html: "<strong>Парада:</strong> Мы не будзем запытваць ваш пароль зноўку на працягу наступнай гадзіны."
|
||||||
|
@ -1276,7 +1319,7 @@ be:
|
||||||
none: Папярэджанне
|
none: Папярэджанне
|
||||||
sensitive: Пазначэнне ўліковага запісу як далікатнага
|
sensitive: Пазначэнне ўліковага запісу як далікатнага
|
||||||
silence: Абмежаванне ўліковага запісу
|
silence: Абмежаванне ўліковага запісу
|
||||||
suspend: Выключэнне ўліковага запісу
|
suspend: Прыпыненне ўліковага запісу
|
||||||
your_appeal_approved: Ваша абскарджанне было ўхвалена
|
your_appeal_approved: Ваша абскарджанне было ўхвалена
|
||||||
your_appeal_pending: Вы адправілі апеляцыю
|
your_appeal_pending: Вы адправілі апеляцыю
|
||||||
your_appeal_rejected: Ваша абскарджанне было адхілена
|
your_appeal_rejected: Ваша абскарджанне было адхілена
|
||||||
|
@ -1284,6 +1327,10 @@ be:
|
||||||
basic_information: Асноўная інфармацыя
|
basic_information: Асноўная інфармацыя
|
||||||
hint_html: "<strong>Наладзьце тое, што людзі будуць бачыць у вашым профілі і побач з вашымі паведамленнямі.</strong> Іншыя людзі з большай верагоднасцю будуць сачыць і ўзаемадзейнічаць з вамі, калі ў вас ёсць запоўнены профіль і фота профілю."
|
hint_html: "<strong>Наладзьце тое, што людзі будуць бачыць у вашым профілі і побач з вашымі паведамленнямі.</strong> Іншыя людзі з большай верагоднасцю будуць сачыць і ўзаемадзейнічаць з вамі, калі ў вас ёсць запоўнены профіль і фота профілю."
|
||||||
other: Іншае
|
other: Іншае
|
||||||
|
emoji_styles:
|
||||||
|
auto: Аўтаматычны
|
||||||
|
native: Мясцовы
|
||||||
|
twemoji: Twemoji
|
||||||
errors:
|
errors:
|
||||||
'400': Запыт, які вы адправілі, памылковы або няправільны.
|
'400': Запыт, які вы адправілі, памылковы або няправільны.
|
||||||
'403': У вас няма дазволу на прагляд гэтай старонкі.
|
'403': У вас няма дазволу на прагляд гэтай старонкі.
|
||||||
|
@ -1398,10 +1445,10 @@ be:
|
||||||
other: Выберыце %{count} элементаў, якія адпавядаюць вашаму пошуку.
|
other: Выберыце %{count} элементаў, якія адпавядаюць вашаму пошуку.
|
||||||
today: сёння
|
today: сёння
|
||||||
validation_errors:
|
validation_errors:
|
||||||
few: Штосьці пакуль не зусім правільна! Калі ласка, праглядзіце %{count} памылкі ніжэй
|
few: Штосьці тут пакуль не сыходзіцца! Праглядзіце %{count} памылкі ніжэй
|
||||||
many: Штосьці пакуль не зусім правільна! Калі ласка, праглядзіце %{count} памылак ніжэй
|
many: Штосьці тут пакуль не сыходзіцца! Праглядзіце %{count} памылак ніжэй
|
||||||
one: Штосьці пакуль не зусім правільна! Калі ласка, праглядзіце памылку ніжэй
|
one: Штосьці тут пакуль не сыходзіцца! Праглядзіце памылку ніжэй
|
||||||
other: Штосьці пакуль не зусім правільна! Калі ласка, праглядзіце %{count} памылак ніжэй
|
other: Штосьці тут пакуль не сыходзіцца! Праглядзіце %{count} памылак ніжэй
|
||||||
imports:
|
imports:
|
||||||
errors:
|
errors:
|
||||||
empty: Пусты CSV файл
|
empty: Пусты CSV файл
|
||||||
|
@ -1413,7 +1460,7 @@ be:
|
||||||
imported: Імпартавана
|
imported: Імпартавана
|
||||||
mismatched_types_warning: Здаецца, вы выбралі няправільны тып для гэтага імпарту, праверце яшчэ раз.
|
mismatched_types_warning: Здаецца, вы выбралі няправільны тып для гэтага імпарту, праверце яшчэ раз.
|
||||||
modes:
|
modes:
|
||||||
merge: Аб'яднаць
|
merge: Аб’яднаць
|
||||||
merge_long: Захаваць існуючыя запісы і дадаць новыя
|
merge_long: Захаваць існуючыя запісы і дадаць новыя
|
||||||
overwrite: Перазапісаць
|
overwrite: Перазапісаць
|
||||||
overwrite_long: Замяніць бягучыя запісы на новыя
|
overwrite_long: Замяніць бягучыя запісы на новыя
|
||||||
|
@ -1489,7 +1536,7 @@ be:
|
||||||
unsubscribe:
|
unsubscribe:
|
||||||
action: Так, адпісацца
|
action: Так, адпісацца
|
||||||
complete: Адпісаны
|
complete: Адпісаны
|
||||||
confirmation_html: Вы ўпэўнены, што жадаеце адмовіцца ад %{type} з Mastodon на дамене %{domain} на вашу электронную пошту %{email}? Вы заўсёды можаце паўторна падпісацца у <a href="%{settings_path}">наладах апавяшчэнняў па электроннай пошце</a>.
|
confirmation_html: Вы ўпэўнены, што жадаеце адмовіцца ад атрымання %{type} з Mastodon на дамене %{domain} на сваю электронную пошту %{email}? Вы заўсёды можаце паўторна падпісацца ў <a href="%{settings_path}">наладах апавяшчэнняў па электроннай пошце</a>.
|
||||||
emails:
|
emails:
|
||||||
notification_emails:
|
notification_emails:
|
||||||
favourite: апавяшчэнні на пошту пра упадабанае
|
favourite: апавяшчэнні на пошту пра упадабанае
|
||||||
|
@ -1529,7 +1576,7 @@ be:
|
||||||
set_redirect: Задаць перанакіраванне
|
set_redirect: Задаць перанакіраванне
|
||||||
warning:
|
warning:
|
||||||
backreference_required: Спачатку трэба наладзіць зваротнае спасыланне новага ўліковага запісу на бягучы
|
backreference_required: Спачатку трэба наладзіць зваротнае спасыланне новага ўліковага запісу на бягучы
|
||||||
before: 'Перш чым працягнуць, калі ласка, уважліва прачытайце гэтыя заўвагі:'
|
before: 'Перш чым працягнуць, уважліва прачытайце гэтыя заўвагі:'
|
||||||
cooldown: Пасля «пераезду» будзе перыяд чакання, на працягу якога вы не зможаце зноў «пераехаць»
|
cooldown: Пасля «пераезду» будзе перыяд чакання, на працягу якога вы не зможаце зноў «пераехаць»
|
||||||
disabled_account: Пасля гэтага ваш бягучы ўліковы запіс не будзе цалкам даступны. Аднак у вас будзе доступ да экспарту даных, а таксама да паўторнай актывацыі.
|
disabled_account: Пасля гэтага ваш бягучы ўліковы запіс не будзе цалкам даступны. Аднак у вас будзе доступ да экспарту даных, а таксама да паўторнай актывацыі.
|
||||||
followers: Гэтае дзеянне будзе «пераносіць» усіх падпісчыкаў з бягучага ўліковага запісу на новы
|
followers: Гэтае дзеянне будзе «пераносіць» усіх падпісчыкаў з бягучага ўліковага запісу на новы
|
||||||
|
@ -1642,9 +1689,9 @@ be:
|
||||||
title: Вы пакідаеце %{instance}.
|
title: Вы пакідаеце %{instance}.
|
||||||
relationships:
|
relationships:
|
||||||
activity: Актыўнасць ул. запісу
|
activity: Актыўнасць ул. запісу
|
||||||
confirm_follow_selected_followers: Вы ўпэўнены, што жадаеце падпісацца на выбраных падпісчыкаў?
|
confirm_follow_selected_followers: Вы ўпэўнены, што хочаце падпісацца на выбраных падпісчыкаў?
|
||||||
confirm_remove_selected_followers: Вы ўпэўнены, што жадаеце выдаліць выбраных падпісчыкаў?
|
confirm_remove_selected_followers: Вы ўпэўнены, што хочаце выдаліць выбраных падпісчыкаў?
|
||||||
confirm_remove_selected_follows: Вы ўпэўнены, што жадаеце выдаліць выбраныя падпіскі?
|
confirm_remove_selected_follows: Вы ўпэўнены, што хочаце выдаліць выбраныя падпіскі?
|
||||||
dormant: Занядбаны
|
dormant: Занядбаны
|
||||||
follow_failure: Вы не можаце падпісацца на некаторыя акаўнты.
|
follow_failure: Вы не можаце падпісацца на некаторыя акаўнты.
|
||||||
follow_selected_followers: Падпісацца на выбраных падпісчыкаў
|
follow_selected_followers: Падпісацца на выбраных падпісчыкаў
|
||||||
|
@ -1674,6 +1721,7 @@ be:
|
||||||
scheduled_statuses:
|
scheduled_statuses:
|
||||||
over_daily_limit: Вы перавысілі ліміт ў %{limit} запланаваных на сёння допісаў
|
over_daily_limit: Вы перавысілі ліміт ў %{limit} запланаваных на сёння допісаў
|
||||||
over_total_limit: Вы перавысілі ліміт ў %{limit} запланаваных допісаў
|
over_total_limit: Вы перавысілі ліміт ў %{limit} запланаваных допісаў
|
||||||
|
too_soon: дата публікацыі мусіць быць у будучыні
|
||||||
self_destruct:
|
self_destruct:
|
||||||
lead_html: На жаль, дамен <strong>%{domain}</strong> зачыняецца назаўсёды. Калі ў вас быў уліковы запіс, вы не зможаце працягваць выкарыстоўваць яго, але вы ўсё яшчэ можаце запытаць рэзервовае капіраванне вашых даных.
|
lead_html: На жаль, дамен <strong>%{domain}</strong> зачыняецца назаўсёды. Калі ў вас быў уліковы запіс, вы не зможаце працягваць выкарыстоўваць яго, але вы ўсё яшчэ можаце запытаць рэзервовае капіраванне вашых даных.
|
||||||
title: Гэты сервер зачыняецца
|
title: Гэты сервер зачыняецца
|
||||||
|
@ -1789,10 +1837,14 @@ be:
|
||||||
in_reply_not_found: Здаецца, допіс, на які вы спрабуеце адказаць, не існуе.
|
in_reply_not_found: Здаецца, допіс, на які вы спрабуеце адказаць, не існуе.
|
||||||
over_character_limit: перавышаная колькасць сімвалаў у %{max}
|
over_character_limit: перавышаная колькасць сімвалаў у %{max}
|
||||||
pin_errors:
|
pin_errors:
|
||||||
direct: Допісы, бачныя толькі згаданым карыстальнікам, не могуць быць замацаваныя
|
direct: Допісы, бачныя толькі згаданым карыстальнікам, нельга замацаваць
|
||||||
limit: Вы ўжо замацавалі максімальную колькасць допісаў
|
limit: Вы ўжо замацавалі максімальную колькасць допісаў
|
||||||
ownership: Немагчыма замацаваць чужы допіс
|
ownership: Немагчыма замацаваць чужы допіс
|
||||||
reblog: Немагчыма замацаваць пашырэнне
|
reblog: Немагчыма замацаваць пашырэнне
|
||||||
|
quote_policies:
|
||||||
|
followers: Падпісчыкі і згаданыя карыстальнікі
|
||||||
|
nobody: Толькі згаданыя карыстальнікі
|
||||||
|
public: Усе
|
||||||
title: '%{name}: "%{quote}"'
|
title: '%{name}: "%{quote}"'
|
||||||
visibilities:
|
visibilities:
|
||||||
direct: Асабіста
|
direct: Асабіста
|
||||||
|
@ -1845,7 +1897,7 @@ be:
|
||||||
tags:
|
tags:
|
||||||
does_not_match_previous_name: не супадае з папярэднім імям
|
does_not_match_previous_name: не супадае з папярэднім імям
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
title: Умовы абслугоўваньня
|
title: Умовы выкарыстання
|
||||||
themes:
|
themes:
|
||||||
contrast: Mastodon (высокі кантраст)
|
contrast: Mastodon (высокі кантраст)
|
||||||
default: Mastodon (цёмная)
|
default: Mastodon (цёмная)
|
||||||
|
@ -1874,7 +1926,7 @@ be:
|
||||||
otp: Праграма аўтэнтыфікацыі
|
otp: Праграма аўтэнтыфікацыі
|
||||||
recovery_codes: Абнавіць коды аднаўлення
|
recovery_codes: Абнавіць коды аднаўлення
|
||||||
recovery_codes_regenerated: Новыя коды аднаўлення паспяхова створаныя
|
recovery_codes_regenerated: Новыя коды аднаўлення паспяхова створаныя
|
||||||
recovery_instructions_html: Калі раптам вы страціце доступ да вашага тэлефона, вы можаце скарыстацца адным з кодаў аднаўлення ніжэй каб аднавіць доступ да вашага ўліковага запісу. <strong>Захоўвайце іх у бяспечным месцы</strong>. Напрыклад, вы можаце раздрукаваць іх і захоўваць разам з іншымі важнымі дакументамі.
|
recovery_instructions_html: Калі раптам вы страціце доступ да свайго тэлефона, вы можаце скарыстаць адзін з кодаў аднаўлення ніжэй каб аднавіць доступ да свайго ўліковага запісу. <strong>Захоўвайце іх у бяспечным месцы</strong>. Напрыклад, вы можаце раздрукаваць іх і захоўваць разам з іншымі важнымі дакументамі.
|
||||||
webauthn: Ключы бяспекі
|
webauthn: Ключы бяспекі
|
||||||
user_mailer:
|
user_mailer:
|
||||||
appeal_approved:
|
appeal_approved:
|
||||||
|
@ -1895,10 +1947,10 @@ be:
|
||||||
title: Ваш архіў можна спампаваць
|
title: Ваш архіў можна спампаваць
|
||||||
failed_2fa:
|
failed_2fa:
|
||||||
details: 'Вось падрабязнасці ўваходу:'
|
details: 'Вось падрабязнасці ўваходу:'
|
||||||
explanation: Хтосьці спрабаваў увайсці ў ваш уліковы запіс, але ўвёў няправільны другі фактар аўтэнтыфікацыі.
|
explanation: Хтосьці спрабаваў увайсці ў ваш уліковы запіс, але ўвёў няправільны часовы пароль.
|
||||||
further_actions_html: Калі гэта не вы, мы рэкамендуем неадкладна %{action}, бо ён можа быць скампраметаваны.
|
further_actions_html: Калі гэта не вы, мы рэкамендуем неадкладна %{action}, бо ён можа быць скампраметаваны.
|
||||||
subject: Збой аўтэнтыфікацыі па другім фактары
|
subject: Збой двухфактарнай аўтэнтыфікацыі
|
||||||
title: Няўдалая аўтэнтыфікацыя па другім фактары
|
title: Двухфактарная аўтэнтыфікацыя не ўдалася
|
||||||
suspicious_sign_in:
|
suspicious_sign_in:
|
||||||
change_password: змяніць свой пароль
|
change_password: змяніць свой пароль
|
||||||
details: 'Вось падрабязнасці ўваходу:'
|
details: 'Вось падрабязнасці ўваходу:'
|
||||||
|
@ -1906,6 +1958,9 @@ be:
|
||||||
further_actions_html: Калі гэта былі не вы, раім вам неадкладна %{action}, а таксама ўключыць двухфактарную аўтэнтыфікацыю, каб захаваць бяспеку вашага ўліковага запісу.
|
further_actions_html: Калі гэта былі не вы, раім вам неадкладна %{action}, а таксама ўключыць двухфактарную аўтэнтыфікацыю, каб захаваць бяспеку вашага ўліковага запісу.
|
||||||
subject: У вас уліковы запіс зайшлі з новага IP-адрасу
|
subject: У вас уліковы запіс зайшлі з новага IP-адрасу
|
||||||
title: Новы ўваход
|
title: Новы ўваход
|
||||||
|
terms_of_service_changed:
|
||||||
|
sign_off: Каманда %{domain}
|
||||||
|
title: Важнае абнаўленне
|
||||||
warning:
|
warning:
|
||||||
appeal: Падаць апеляцыю
|
appeal: Падаць апеляцыю
|
||||||
appeal_description: "Калі вы лічыце гэта памылкай, вы можаце падаць апеляцыю \nсупрацоўнікам %{instance}."
|
appeal_description: "Калі вы лічыце гэта памылкай, вы можаце падаць апеляцыю \nсупрацоўнікам %{instance}."
|
||||||
|
@ -1936,7 +1991,7 @@ be:
|
||||||
none: Папярэджанне
|
none: Папярэджанне
|
||||||
sensitive: Уліковыя запісы, пазначаныя як далікатныя
|
sensitive: Уліковыя запісы, пазначаныя як далікатныя
|
||||||
silence: Уліковы запіс абмежаваны
|
silence: Уліковы запіс абмежаваны
|
||||||
suspend: Уліковы запіс выключаны
|
suspend: Уліковы запіс прыпынены
|
||||||
welcome:
|
welcome:
|
||||||
apps_android_action: Спампаваць з Google Play
|
apps_android_action: Спампаваць з Google Play
|
||||||
apps_ios_action: Спампваваць з App Store
|
apps_ios_action: Спампваваць з App Store
|
||||||
|
@ -1968,9 +2023,9 @@ be:
|
||||||
many: "%{people} чалавек за апошнія 2 дні"
|
many: "%{people} чалавек за апошнія 2 дні"
|
||||||
one: "%{people} чалавек за апошнія 2 дні"
|
one: "%{people} чалавек за апошнія 2 дні"
|
||||||
other: "%{people} чалавека за апошнія 2 дні"
|
other: "%{people} чалавека за апошнія 2 дні"
|
||||||
hashtags_subtitle: Даведайцеся што было папулярна ў апошнія 2 дні
|
hashtags_subtitle: Даведайцеся што было ў трэндзе за апошнія 2 дні
|
||||||
hashtags_title: Папулярныя хэштэгі
|
hashtags_title: Папулярныя хэштэгі
|
||||||
hashtags_view_more: Прагледзець іншыя папулярныя хэштэгі
|
hashtags_view_more: Прагледзець іншыя трэндавыя хэштэгі
|
||||||
post_action: Стварыць
|
post_action: Стварыць
|
||||||
post_step: Скажыце ўсім прывітанне з дапамогай тэксту, фатаграфій, відэа і апытанняў.
|
post_step: Скажыце ўсім прывітанне з дапамогай тэксту, фатаграфій, відэа і апытанняў.
|
||||||
post_title: Стварыце свой першы допіс
|
post_title: Стварыце свой першы допіс
|
||||||
|
@ -1983,7 +2038,7 @@ be:
|
||||||
follow_limit_reached: Вы не можаце падпісацца на большую колькасць людзей чым %{limit}
|
follow_limit_reached: Вы не можаце падпісацца на большую колькасць людзей чым %{limit}
|
||||||
go_to_sso_account_settings: Перайдзіце ў налады ідэнтыфікацыі вашага ўліковага запісу
|
go_to_sso_account_settings: Перайдзіце ў налады ідэнтыфікацыі вашага ўліковага запісу
|
||||||
invalid_otp_token: Няправільны код двухфактарнай аўтэнтыфікацыі
|
invalid_otp_token: Няправільны код двухфактарнай аўтэнтыфікацыі
|
||||||
otp_lost_help_html: Калі вы страцілі доступ да абодвух, вы можаце скарыстацца %{email}
|
otp_lost_help_html: Калі вы страцілі доступ да абодвух, вы можаце звязацца з намі праз %{email}
|
||||||
rate_limited: Занадта шмат спробаў аўтэнтыфікацыі, паспрабуйце пазней.
|
rate_limited: Занадта шмат спробаў аўтэнтыфікацыі, паспрабуйце пазней.
|
||||||
seamless_external_login: Вы ўвайшлі праз знешні сэрвіс, таму налады пароля і эл. пошты недаступныя.
|
seamless_external_login: Вы ўвайшлі праз знешні сэрвіс, таму налады пароля і эл. пошты недаступныя.
|
||||||
signed_in_as: 'Увайшлі як:'
|
signed_in_as: 'Увайшлі як:'
|
||||||
|
|
|
@ -396,6 +396,9 @@ br:
|
||||||
created_at: Deiziad
|
created_at: Deiziad
|
||||||
title_actions:
|
title_actions:
|
||||||
none: Diwall
|
none: Diwall
|
||||||
|
emoji_styles:
|
||||||
|
auto: Emgefreek
|
||||||
|
twemoji: Twemoji
|
||||||
exports:
|
exports:
|
||||||
archive_takeout:
|
archive_takeout:
|
||||||
date: Deiziad
|
date: Deiziad
|
||||||
|
|
|
@ -578,6 +578,12 @@ ca:
|
||||||
all: Totes
|
all: Totes
|
||||||
limited: Limitades
|
limited: Limitades
|
||||||
title: Moderació
|
title: Moderació
|
||||||
|
moderation_notes:
|
||||||
|
create: Afegeix una nota de moderació
|
||||||
|
created_msg: S'ha creat la nota de moderació d'instància.
|
||||||
|
description_html: Mireu i deixeu notes per als altres moderadors i per a un mateix
|
||||||
|
destroyed_msg: S'ha esborrat la nota de moderació d'instància.
|
||||||
|
title: Notes de moderació
|
||||||
private_comment: Comentari privat
|
private_comment: Comentari privat
|
||||||
public_comment: Comentari públic
|
public_comment: Comentari públic
|
||||||
purge: Purga
|
purge: Purga
|
||||||
|
@ -803,6 +809,8 @@ ca:
|
||||||
preamble: Proporciona informació detallada sobre com funciona, com es modera i com es financia el servidor.
|
preamble: Proporciona informació detallada sobre com funciona, com es modera i com es financia el servidor.
|
||||||
rules_hint: Hi ha un àrea dedicada a les normes a les que s'espera que els teus usuaris s'hi adhereixin.
|
rules_hint: Hi ha un àrea dedicada a les normes a les que s'espera que els teus usuaris s'hi adhereixin.
|
||||||
title: Quant a
|
title: Quant a
|
||||||
|
allow_referrer_origin:
|
||||||
|
title: Permeteu que llocs externs vegin el vostre servidor de Mastodon com a font de trànsit
|
||||||
appearance:
|
appearance:
|
||||||
preamble: Personalitza l'interfície web de Mastodon.
|
preamble: Personalitza l'interfície web de Mastodon.
|
||||||
title: Aparença
|
title: Aparença
|
||||||
|
@ -1339,6 +1347,10 @@ ca:
|
||||||
basic_information: Informació bàsica
|
basic_information: Informació bàsica
|
||||||
hint_html: "<strong>Personalitza el que la gent veu en el teu perfil públic i a prop dels teus tuts..</strong> És més probable que altres persones et segueixin i interaccionin amb tu quan tens emplenat el teu perfil i amb la teva imatge."
|
hint_html: "<strong>Personalitza el que la gent veu en el teu perfil públic i a prop dels teus tuts..</strong> És més probable que altres persones et segueixin i interaccionin amb tu quan tens emplenat el teu perfil i amb la teva imatge."
|
||||||
other: Altres
|
other: Altres
|
||||||
|
emoji_styles:
|
||||||
|
auto: Automàtic
|
||||||
|
native: Nadiu
|
||||||
|
twemoji: Twemoji
|
||||||
errors:
|
errors:
|
||||||
'400': La sol·licitud que vas emetre no era vàlida o no era correcta.
|
'400': La sol·licitud que vas emetre no era vàlida o no era correcta.
|
||||||
'403': No tens permís per a veure aquesta pàgina.
|
'403': No tens permís per a veure aquesta pàgina.
|
||||||
|
@ -1474,6 +1486,28 @@ ca:
|
||||||
lists_html:
|
lists_html:
|
||||||
one: Esteu a punt de <strong>reemplaçar les vostres llistes</strong> amb contactes de <strong>%{filename}</strong>. S'afegirà <strong>%{count} compte</strong> a les noves llistes.
|
one: Esteu a punt de <strong>reemplaçar les vostres llistes</strong> amb contactes de <strong>%{filename}</strong>. S'afegirà <strong>%{count} compte</strong> a les noves llistes.
|
||||||
other: Esteu a punt de <strong>reemplaçar les vostres llistes</strong> amb contactes de <strong>%{filename}</strong>. S'afegiran fins a <strong>%{count} comptes</strong> a les noves llistes.
|
other: Esteu a punt de <strong>reemplaçar les vostres llistes</strong> amb contactes de <strong>%{filename}</strong>. S'afegiran fins a <strong>%{count} comptes</strong> a les noves llistes.
|
||||||
|
muting_html:
|
||||||
|
one: Esteu a punt de <strong>reemplaçar la vostra llista de comptes silenciats</strong> amb fins a <strong>%{count} compte</strong> de <strong>%{filename}</strong>.
|
||||||
|
other: Esteu a punt de <strong>reemplaçar la vostra llista de comptes silenciats</strong> amb fins a <strong>%{count} comptes</strong> de <strong>%{filename}</strong>.
|
||||||
|
preambles:
|
||||||
|
blocking_html:
|
||||||
|
one: Esteu a punt de <strong>blocar</strong> fins a <strong>%{count} compte</strong> de <strong>%{filename}</strong>.
|
||||||
|
other: Esteu a punt de <strong>blocar</strong> fins a <strong>%{count} comptes</strong> de <strong>%{filename}</strong>.
|
||||||
|
bookmarks_html:
|
||||||
|
one: Esteu a punt d'afegir fins a <strong>%{count} publicació</strong> de <strong>%{filename}</strong> als vostres <strong>marcadors</strong>.
|
||||||
|
other: Esteu a punt d'afegir fins a <strong>%{count} publicacions</strong> de <strong>%{filename}</strong> als vostres <strong>marcadors</strong>.
|
||||||
|
domain_blocking_html:
|
||||||
|
one: Esteu a punt de <strong>blocar</strong> fins a <strong>%{count} domini</strong> de <strong>%{filename}</strong>.
|
||||||
|
other: Esteu a punt de <strong>blocar</strong> fins a <strong>%{count} dominis</strong> de <strong>%{filename}</strong>.
|
||||||
|
following_html:
|
||||||
|
one: Esteu a punt de <strong>seguir</strong> fins a <strong>%{count} compte</strong> de <strong>%{filename}</strong>.
|
||||||
|
other: Esteu a punt de <strong>seguir</strong> fins a <strong>%{count} comptes</strong> de <strong>%{filename}</strong>.
|
||||||
|
lists_html:
|
||||||
|
one: Esteu a punt d'afegir <strong>%{count} compte</strong> de <strong>%{filename}</strong> a les vostres <strong>llistes</strong>. Es crearan noves llistes si no n'hi ha cap on afegir-lo.
|
||||||
|
other: Esteu a punt d'afegir <strong>%{count} comptes</strong> de <strong>%{filename}</strong> a les vostres <strong>llistes</strong>. Es crearan noves llistes si no n'hi ha cap on afegir-los.
|
||||||
|
muting_html:
|
||||||
|
one: Esteu a punt de <strong>silenciar</strong> fins a <strong>%{count} compte</strong> de <strong>%{filename}</strong>.
|
||||||
|
other: Esteu a punt de <strong>silenciar</strong> fins a <strong>%{count} comptes</strong> de <strong>%{filename}</strong>.
|
||||||
preface: Pots importar algunes les dades que has exportat des d'un altre servidor, com ara el llistat de les persones que estàs seguint o bloquejant.
|
preface: Pots importar algunes les dades que has exportat des d'un altre servidor, com ara el llistat de les persones que estàs seguint o bloquejant.
|
||||||
recent_imports: Importacions recents
|
recent_imports: Importacions recents
|
||||||
states:
|
states:
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user