Compare commits
393 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7658351041 | ||
![]() |
833e2869e7 | ||
![]() |
5b3a07ee9e | ||
![]() |
3dfe3aa9a4 | ||
![]() |
f68e13d905 | ||
![]() |
3157d81e95 | ||
![]() |
bd13ea3d2c | ||
![]() |
f0cb587c89 | ||
![]() |
84e2ee220b | ||
![]() |
a7977c6642 | ||
![]() |
1dfcd45704 | ||
![]() |
8013cd2e79 | ||
![]() |
9c69501404 | ||
![]() |
0c8d874e3a | ||
![]() |
0fb9c372dd | ||
![]() |
3bb7afe544 | ||
![]() |
29399e1ddc | ||
![]() |
dfc1410bb0 | ||
![]() |
9b72e02da3 | ||
![]() |
5ec07ede7c | ||
![]() |
72d4ad4c45 | ||
![]() |
a6fb6150a3 | ||
![]() |
b9ee14fe5b | ||
![]() |
6e68a78d6a | ||
![]() |
870f7608be | ||
![]() |
69869307bf | ||
![]() |
b161f38710 | ||
![]() |
a7f464147d | ||
![]() |
8eb87c8e4d | ||
![]() |
7925b130e8 | ||
![]() |
16e3cb01ca | ||
![]() |
543ba2b3b7 | ||
![]() |
beb9cd5710 | ||
![]() |
b5fa8767da | ||
![]() |
f846b207b6 | ||
![]() |
c6b07acdcc | ||
![]() |
b055f516c0 | ||
![]() |
716ffcace6 | ||
![]() |
980bf1306e | ||
![]() |
ea92254b73 | ||
![]() |
16ba1b3708 | ||
![]() |
47b6f466ec | ||
![]() |
2e76fcdf6f | ||
![]() |
7ce0f79f7f | ||
![]() |
0c59dd3da7 | ||
![]() |
2aa73fdf6c | ||
![]() |
cd5615d354 | ||
![]() |
8c883653c9 | ||
![]() |
36170a11f5 | ||
![]() |
0f546b47d1 | ||
![]() |
60df819c60 | ||
![]() |
0e1b5d6f14 | ||
![]() |
bde22208fe | ||
![]() |
d4eb1def61 | ||
![]() |
14cff15c89 | ||
![]() |
e8c5307f66 | ||
![]() |
dd52be3a01 | ||
![]() |
8f9ce23e52 | ||
![]() |
7c5fc2c423 | ||
![]() |
63df2c851e | ||
![]() |
4db787c4ee | ||
![]() |
839a626716 | ||
![]() |
ef7ad05c0b | ||
![]() |
e24b0ceb80 | ||
![]() |
71c42bef9b | ||
![]() |
8caf288ac1 | ||
![]() |
8f2049bcd2 | ||
![]() |
d0aba46ee3 | ||
![]() |
57c94a5cf0 | ||
![]() |
c1f1e0ee7c | ||
![]() |
192ea9738d | ||
![]() |
37b849ad1f | ||
![]() |
4e68126c06 | ||
![]() |
c7fbf5637f | ||
![]() |
5cf5b66696 | ||
![]() |
7436a58ea1 | ||
![]() |
b7b8fd4b59 | ||
![]() |
55d4d3418e | ||
![]() |
1c8419cea0 | ||
![]() |
e8d4f3eac3 | ||
![]() |
1b21bad202 | ||
![]() |
30f600e03e | ||
![]() |
f34f9f6ea5 | ||
![]() |
8d4c5deb8d | ||
![]() |
2f41f12aea | ||
![]() |
9f0e0dc8ce | ||
![]() |
a71682f6f0 | ||
![]() |
5d3d5cd59c | ||
![]() |
451bc0b444 | ||
![]() |
d7a2d59f41 | ||
![]() |
7deb4691fb | ||
![]() |
9965bc8f94 | ||
![]() |
317770fb23 | ||
![]() |
19c204ea03 | ||
![]() |
b9feacab85 | ||
![]() |
56c7359a0c | ||
![]() |
a7c1afffc6 | ||
![]() |
fdb745b4a8 | ||
![]() |
b3d8134c7a | ||
![]() |
0879ab50b8 | ||
![]() |
c5ef6bf38a | ||
![]() |
b427bf70a8 | ||
![]() |
c75fc266e9 | ||
![]() |
e98740c285 | ||
![]() |
56b23a64a3 | ||
![]() |
ee5b417354 | ||
![]() |
2f48d109dd | ||
![]() |
784fc7b3f5 | ||
![]() |
b55d26387b | ||
![]() |
9ddf62d8b7 | ||
![]() |
a8feed1eff | ||
![]() |
f5bfc6f0c1 | ||
![]() |
ee03ab8d2c | ||
![]() |
3c7e1ff92e | ||
![]() |
ac7e2ecb59 | ||
![]() |
f28aea9e30 | ||
![]() |
1ac7c154d7 | ||
![]() |
ef860a8f84 | ||
![]() |
f6f269194f | ||
![]() |
e1d41063cd | ||
![]() |
5d02405a98 | ||
![]() |
998c2b692a | ||
![]() |
19c0027605 | ||
![]() |
9349f72227 | ||
![]() |
5af8b77d28 | ||
![]() |
f74d9c7ed0 | ||
![]() |
7d9c273dac | ||
![]() |
f2da79ad43 | ||
![]() |
73a1372940 | ||
![]() |
0138c3b00e | ||
![]() |
6f33be6c75 | ||
![]() |
3004fe573d | ||
![]() |
040f9927dd | ||
![]() |
abc1bdf218 | ||
![]() |
e73e56be8f | ||
![]() |
b0616b52ea | ||
![]() |
6b6b767199 | ||
![]() |
e1bdecb9c1 | ||
![]() |
a32c6267be | ||
![]() |
54df243b90 | ||
![]() |
b44597d5d8 | ||
![]() |
7b70b6c3cd | ||
![]() |
5cc0219ff2 | ||
![]() |
4a0b0b135a | ||
![]() |
8bd2d6328a | ||
![]() |
9351fb9617 | ||
![]() |
7b29e36d64 | ||
![]() |
9cc36ef32d | ||
![]() |
000f876084 | ||
![]() |
2d11c558fa | ||
![]() |
ac6b02af40 | ||
![]() |
7d91912cfd | ||
![]() |
3c504b4b08 | ||
![]() |
adad4bcfe3 | ||
![]() |
b3e8671dd9 | ||
![]() |
0f8c890761 | ||
![]() |
512e451f24 | ||
![]() |
ca0d53ec5d | ||
![]() |
686a709e87 | ||
![]() |
83fb629f0b | ||
![]() |
35eeeb25e3 | ||
![]() |
19035c676c | ||
![]() |
61ffe7417c | ||
![]() |
7651353f39 | ||
![]() |
3f5b81060f | ||
![]() |
63dc66769f | ||
![]() |
e0fc8cbf8f | ||
![]() |
f9d1bc340e | ||
![]() |
0b269e79fd | ||
![]() |
6159cfd138 | ||
![]() |
6a5bbd335b | ||
![]() |
39e269db8c | ||
![]() |
70fe23a3ce | ||
![]() |
a6a8a7fb85 | ||
![]() |
6641b13b4c | ||
![]() |
5136b05c9b | ||
![]() |
803c2144f4 | ||
![]() |
b69a079514 | ||
![]() |
2aa800cd55 | ||
![]() |
6e61a36d05 | ||
![]() |
f80bf1fb1c | ||
![]() |
d465e85239 | ||
![]() |
deed25a2ff | ||
![]() |
a486716520 | ||
![]() |
2361e11e98 | ||
![]() |
cd1f2adca7 | ||
![]() |
a558767b7a | ||
![]() |
399ce9b999 | ||
![]() |
a94a0b5b0b | ||
![]() |
76faec2115 | ||
![]() |
33c4e57994 | ||
![]() |
bc23496998 | ||
![]() |
d35ad95c18 | ||
![]() |
5facd11592 | ||
![]() |
e1e885d6b2 | ||
![]() |
5b6695114f | ||
![]() |
71dd7f89e9 | ||
![]() |
21331e53fe | ||
![]() |
7afee5977f | ||
![]() |
d195b0dec7 | ||
![]() |
8a95e850ad | ||
![]() |
a4d74d7d7e | ||
![]() |
256e0db36d | ||
![]() |
d593c1358a | ||
![]() |
1ff14d81c1 | ||
![]() |
4369d12eec | ||
![]() |
91cc033eb5 | ||
![]() |
57543e6b44 | ||
![]() |
a1b8cd15c4 | ||
![]() |
73f06e591a | ||
![]() |
6f7cfa82b5 | ||
![]() |
ff97a003d1 | ||
![]() |
53c92e3e23 | ||
![]() |
13d13bc2f6 | ||
![]() |
03744a25ed | ||
![]() |
eac3bf8bff | ||
![]() |
2e1fbb5b16 | ||
![]() |
98b3517d36 | ||
![]() |
dee662705e | ||
![]() |
0da0cc80b9 | ||
![]() |
650187deaf | ||
![]() |
2e565cac2c | ||
![]() |
ac7537278c | ||
![]() |
f9a2e98831 | ||
![]() |
54f789bd55 | ||
![]() |
5ac9d13516 | ||
![]() |
2be1a39d13 | ||
![]() |
f3c5edc852 | ||
![]() |
30704e6de8 | ||
![]() |
41932ac409 | ||
![]() |
9843c596d8 | ||
![]() |
baf65bfa69 | ||
![]() |
6501f80fc7 | ||
![]() |
b037f6566b | ||
![]() |
0ec8ebeba3 | ||
![]() |
af1c9251fc | ||
![]() |
4ad399c593 | ||
![]() |
55a9646f23 | ||
![]() |
46017f5725 | ||
![]() |
c20ce12f86 | ||
![]() |
1e28db2396 | ||
![]() |
5f3640c7fd | ||
![]() |
d65e5f6794 | ||
![]() |
e67d7bc0ea | ||
![]() |
1139632f95 | ||
![]() |
b51a8c3f82 | ||
![]() |
0d7256678e | ||
![]() |
eea33d07fd | ||
![]() |
f599337320 | ||
![]() |
7df019db0e | ||
![]() |
04f92bd688 | ||
![]() |
505ecf6c1f | ||
![]() |
c9ec08704e | ||
![]() |
6a3039f7b7 | ||
![]() |
868c8fffb3 | ||
![]() |
faed3b438e | ||
![]() |
6c982629ea | ||
![]() |
110bbbc7dc | ||
![]() |
4ad0345f20 | ||
![]() |
9d84214462 | ||
![]() |
3f199c7113 | ||
![]() |
e9417fb741 | ||
![]() |
ee74df6823 | ||
![]() |
26630bae81 | ||
![]() |
9bde9edcf6 | ||
![]() |
a12f07c42b | ||
![]() |
e7334c4fb0 | ||
![]() |
38f9d1e764 | ||
![]() |
2dfed75402 | ||
![]() |
0c12e80106 | ||
![]() |
b7522f69e7 | ||
![]() |
24705a7e39 | ||
![]() |
8add8025a0 | ||
![]() |
32fa79d928 | ||
![]() |
534be6ff25 | ||
![]() |
f684c07567 | ||
![]() |
788ae2f6ca | ||
![]() |
572000f868 | ||
![]() |
57f5df2d22 | ||
![]() |
b2a67ba5ca | ||
![]() |
d78e15cc1a | ||
![]() |
ceab34f5f3 | ||
![]() |
3a62625bbc | ||
![]() |
ad6844ac4a | ||
![]() |
a8c252a613 | ||
![]() |
1d39f785f1 | ||
![]() |
4b8b29b862 | ||
![]() |
0d148bd23b | ||
![]() |
ebedb81e3f | ||
![]() |
d195406fdc | ||
![]() |
5173ed37f9 | ||
![]() |
825551d64f | ||
![]() |
449761bada | ||
![]() |
5859df389f | ||
![]() |
562b02310f | ||
![]() |
65ed702d87 | ||
![]() |
c559a9843f | ||
![]() |
88c3957085 | ||
![]() |
01778e11dc | ||
![]() |
9d9e8a3c4e | ||
![]() |
ed3e035ad6 | ||
![]() |
07f885fea8 | ||
![]() |
2cc98226ca | ||
![]() |
8a6f73c5ff | ||
![]() |
00e3453ce1 | ||
![]() |
16646dd77a | ||
![]() |
1f39d1fe26 | ||
![]() |
e8f3c587c9 | ||
![]() |
4b43745e7c | ||
![]() |
9db2f60053 | ||
![]() |
4610d8dfe3 | ||
![]() |
fa296efdf6 | ||
![]() |
d9d98f84bf | ||
![]() |
7c3143b8e5 | ||
![]() |
387fcd5c5d | ||
![]() |
ebc6437977 | ||
![]() |
dbc23b5d20 | ||
![]() |
843f1aed4f | ||
![]() |
e42938cad6 | ||
![]() |
2a41f6c383 | ||
![]() |
671d21a2c1 | ||
![]() |
515692d7a6 | ||
![]() |
00d28826b9 | ||
![]() |
5b38f76254 | ||
![]() |
ca7dbd6010 | ||
![]() |
133644e5a9 | ||
![]() |
04d60426c7 | ||
![]() |
8282bbd07c | ||
![]() |
7190bd00c9 | ||
![]() |
44b9539818 | ||
![]() |
b2ed4c9508 | ||
![]() |
c7b5c8b19e | ||
![]() |
f4bee24ccf | ||
![]() |
e9cb18c5aa | ||
![]() |
d8f33bc0af | ||
![]() |
663999556f | ||
![]() |
c5a12ca2c7 | ||
![]() |
7af0e38dd3 | ||
![]() |
7d9d1ae7c2 | ||
![]() |
cef448f0f2 | ||
![]() |
67d64c9365 | ||
![]() |
269af9d6b9 | ||
![]() |
d37a734379 | ||
![]() |
7cb13cf839 | ||
![]() |
d7dda8f6e3 | ||
![]() |
6670c72f8b | ||
![]() |
b21064ffa4 | ||
![]() |
1959cb462b | ||
![]() |
1d6767ef0c | ||
![]() |
4735ae6451 | ||
![]() |
452bd6db25 | ||
![]() |
f5d6b84381 | ||
![]() |
34f5d81d1f | ||
![]() |
aa8adc07aa | ||
![]() |
d87bb807c3 | ||
![]() |
7646d6ed47 | ||
![]() |
41a6ed0de0 | ||
![]() |
ec8074cd49 | ||
![]() |
7131eb1827 | ||
![]() |
605b0f27e4 | ||
![]() |
80d2e157f6 | ||
![]() |
1e3447bccb | ||
![]() |
5ffa106cc1 | ||
![]() |
fc641c9b96 | ||
![]() |
5f49ac1b11 | ||
![]() |
9ffecf25dc | ||
![]() |
35fd523edf | ||
![]() |
6721d4216c | ||
![]() |
e3275e916b | ||
![]() |
3ba5541a66 | ||
![]() |
945c50db1f | ||
![]() |
30dce42e03 | ||
![]() |
d4fb201d05 | ||
![]() |
2a2e8d0cf6 | ||
![]() |
520ed8cb4d | ||
![]() |
8cab16c824 | ||
![]() |
26fbb3a560 | ||
![]() |
93dd0638ad | ||
![]() |
0d44129ae3 | ||
![]() |
0cffe60abc | ||
![]() |
8a6750278e | ||
![]() |
d347f0a087 | ||
![]() |
226e0c4714 | ||
![]() |
0b2f945bb6 | ||
![]() |
2f6c45e118 | ||
![]() |
a5f54580a9 | ||
![]() |
a8b19f4aa8 | ||
![]() |
890564e1da | ||
![]() |
002f98987d | ||
![]() |
43956f3ffb | ||
![]() |
f2a9194c79 | ||
![]() |
4cd70df7f4 | ||
![]() |
21e4c3dfe9 |
@@ -114,11 +114,6 @@ id: 'aid'
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Syslog option
|
||||
#syslog:
|
||||
# host: localhost
|
||||
# port: 514
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
|
@@ -114,11 +114,6 @@ id: 'aid'
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Syslog option
|
||||
#syslog:
|
||||
# host: localhost
|
||||
# port: 514
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
@@ -135,11 +130,21 @@ proxyBypassHosts:
|
||||
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||
|
||||
# Media Proxy
|
||||
# Reference Implementation: https://github.com/misskey-dev/media-proxy
|
||||
# * Deliver a common cache between instances
|
||||
# * Perform image compression (on a different server resource than the main process)
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
# Movie Thumbnail Generation URL
|
||||
# There is no reference implementation.
|
||||
# For example, Misskey will point to the following URL:
|
||||
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
|
||||
#videoThumbnailGenerator: https://example.com
|
||||
|
||||
# Sign to ActivityPub GET request (default: true)
|
||||
signToActivityPubGet: true
|
||||
|
||||
|
1
.devcontainer/Dockerfile
Normal file
1
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM mcr.microsoft.com/devcontainers/javascript-node:0-18
|
11
.devcontainer/devcontainer.json
Normal file
11
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Misskey",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspace",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers-contrib/features/pnpm:2": {}
|
||||
},
|
||||
"forwardPorts": [3000],
|
||||
"postCreateCommand": "sudo chmod 755 .devcontainer/init.sh && .devcontainer/init.sh"
|
||||
}
|
146
.devcontainer/devcontainer.yml
Normal file
146
.devcontainer/devcontainer.yml
Normal file
@@ -0,0 +1,146 @@
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Misskey configuration
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
# ┌─────┐
|
||||
#───┘ URL └─────────────────────────────────────────────────────
|
||||
|
||||
# Final accessible URL seen by a user.
|
||||
url: http://127.0.0.1:3000/
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# URL SETTINGS AFTER THAT!
|
||||
|
||||
# ┌───────────────────────┐
|
||||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
#
|
||||
# Misskey requires a reverse proxy to support HTTPS connections.
|
||||
#
|
||||
# +----- https://example.tld/ ------------+
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
# You need to set up a reverse proxy. (e.g. nginx)
|
||||
# An encrypted connection with HTTPS is highly recommended
|
||||
# because tokens may be transferred in GET requests.
|
||||
|
||||
# The port that your Misskey server should listen on.
|
||||
port: 3000
|
||||
|
||||
# ┌──────────────────────────┐
|
||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||
|
||||
db:
|
||||
host: db
|
||||
port: 5432
|
||||
|
||||
# Database name
|
||||
db: misskey
|
||||
|
||||
# Auth
|
||||
user: postgres
|
||||
pass: postgres
|
||||
|
||||
# Whether disable Caching queries
|
||||
#disableCache: true
|
||||
|
||||
# Extra Connection options
|
||||
#extra:
|
||||
# ssl: true
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Redis configuration └─────────────────────────────────────
|
||||
|
||||
redis:
|
||||
host: redis
|
||||
port: 6379
|
||||
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||
#pass: example-pass
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
|
||||
# ┌─────────────────────────────┐
|
||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||
|
||||
#elasticsearch:
|
||||
# host: localhost
|
||||
# port: 9200
|
||||
# ssl: false
|
||||
# user:
|
||||
# pass:
|
||||
|
||||
# ┌───────────────┐
|
||||
#───┘ ID generation └───────────────────────────────────────────
|
||||
|
||||
# You can select the ID generation method.
|
||||
# You don't usually need to change this setting, but you can
|
||||
# change it according to your preferences.
|
||||
|
||||
# Available methods:
|
||||
# aid ... Short, Millisecond accuracy
|
||||
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||
# ulid ... Millisecond accuracy
|
||||
# objectid ... This is left for backward compatibility
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# ID SETTINGS AFTER THAT!
|
||||
|
||||
id: 'aid'
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Other configuration └─────────────────────────────────────
|
||||
|
||||
# Whether disable HSTS
|
||||
#disableHsts: true
|
||||
|
||||
# Number of worker processes
|
||||
#clusterLimit: 1
|
||||
|
||||
# Job concurrency per worker
|
||||
# deliverJobConcurrency: 128
|
||||
# inboxJobConcurrency: 16
|
||||
|
||||
# Job rate limiter
|
||||
# deliverJobPerSec: 128
|
||||
# inboxJobPerSec: 16
|
||||
|
||||
# Job attempts
|
||||
# deliverJobMaxAttempts: 12
|
||||
# inboxJobMaxAttempts: 8
|
||||
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
proxyBypassHosts:
|
||||
- api.deepl.com
|
||||
- api-free.deepl.com
|
||||
- www.recaptcha.net
|
||||
- hcaptcha.com
|
||||
- challenges.cloudflare.com
|
||||
|
||||
# Proxy for SMTP/SMTPS
|
||||
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||
|
||||
# Media Proxy
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
# Sign to ActivityPub GET request (default: true)
|
||||
signToActivityPubGet: true
|
||||
|
||||
allowedPrivateNetworks: [
|
||||
'127.0.0.1/32'
|
||||
]
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
53
.devcontainer/docker-compose.yml
Normal file
53
.devcontainer/docker-compose.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
|
||||
volumes:
|
||||
- ../:/workspace:cached
|
||||
|
||||
command: sleep infinity
|
||||
|
||||
networks:
|
||||
- internal_network
|
||||
- external_network
|
||||
|
||||
redis:
|
||||
restart: always
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
- internal_network
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
healthcheck:
|
||||
test: "redis-cli ping"
|
||||
interval: 5s
|
||||
retries: 20
|
||||
|
||||
db:
|
||||
restart: unless-stopped
|
||||
image: postgres:15-alpine
|
||||
networks:
|
||||
- internal_network
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: misskey
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||
interval: 5s
|
||||
retries: 20
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
redis-data:
|
||||
|
||||
networks:
|
||||
internal_network:
|
||||
internal: true
|
||||
external_network:
|
10
.devcontainer/init.sh
Executable file
10
.devcontainer/init.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
sudo chown -R node /workspace
|
||||
git submodule update --init
|
||||
pnpm install --frozen-lockfile
|
||||
cp .devcontainer/devcontainer.yml .config/default.yml
|
||||
pnpm build
|
||||
pnpm migrate
|
@@ -16,9 +16,15 @@ files/
|
||||
misskey-assets/
|
||||
fluent-emojis/
|
||||
.pnp.*
|
||||
|
||||
# .yarn関連
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
.idea/
|
||||
packages/*/.vscode/
|
||||
packages/backend/test/docker-compose.yml
|
||||
|
3
.dockleignore
Normal file
3
.dockleignore
Normal file
@@ -0,0 +1,3 @@
|
||||
DKL-DI-0005
|
||||
DKL-DI-0006
|
||||
DKL-LI-0003
|
@@ -5,6 +5,7 @@ indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
|
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -5,3 +5,4 @@
|
||||
*.glb -diff -text
|
||||
*.blend -diff -text
|
||||
*.afdesign -diff -text
|
||||
* text=auto eol=lf
|
||||
|
36
.github/workflows/check_copyright_year.yml
vendored
36
.github/workflows/check_copyright_year.yml
vendored
@@ -1,18 +1,18 @@
|
||||
name: Check copyright year
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
check_copyright_year:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.2.0
|
||||
- run: |
|
||||
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
||||
echo "Please change copyright year!"
|
||||
exit 1
|
||||
fi
|
||||
name: Check copyright year
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
check_copyright_year:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.2.0
|
||||
- run: |
|
||||
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
|
||||
echo "Please change copyright year!"
|
||||
exit 1
|
||||
fi
|
||||
|
12
.github/workflows/docker-develop.yml
vendored
12
.github/workflows/docker-develop.yml
vendored
@@ -14,6 +14,11 @@ jobs:
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v3.3.0
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2.3.0
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
@@ -25,9 +30,14 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Build and Push to Docker Hub
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
push: true
|
||||
platforms: ${{ steps.buildx.outputs.platforms }}
|
||||
provenance: false
|
||||
tags: misskey/misskey:develop
|
||||
labels: develop
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
12
.github/workflows/docker.yml
vendored
12
.github/workflows/docker.yml
vendored
@@ -13,6 +13,11 @@ jobs:
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v3.3.0
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2.3.0
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
@@ -31,9 +36,14 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Build and Push to Docker Hub
|
||||
uses: docker/build-push-action@v3
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
push: true
|
||||
platforms: ${{ steps.buildx.outputs.platforms }}
|
||||
provenance: false
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
30
.github/workflows/dockle.yml
vendored
Normal file
30
.github/workflows/dockle.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Dockle
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
dockle:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DOCKER_CONTENT_TRUST: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3.2.0
|
||||
- run: |
|
||||
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v0.4.10/dockle_0.4.10_Linux-64bit.deb"
|
||||
sudo dpkg -i dockle.deb
|
||||
- run: |
|
||||
cp .config/docker_example.env .config/docker.env
|
||||
cp ./docker-compose.yml.example ./docker-compose.yml
|
||||
- run: |
|
||||
docker compose up -d web
|
||||
docker tag "$(docker compose images web | awk 'OFS=":" {print $4}' | tail -n +2)" misskey-web:latest
|
||||
- run: |
|
||||
cmd="dockle --exit-code 1 misskey-web:latest ${image_name}"
|
||||
echo "> ${cmd}"
|
||||
eval "${cmd}"
|
110
.github/workflows/lint.yml
vendored
110
.github/workflows/lint.yml
vendored
@@ -1,54 +1,56 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
pnpm_install:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: 'pnpm'
|
||||
- run: corepack enable
|
||||
- run: pnpm i --frozen-lockfile
|
||||
|
||||
lint:
|
||||
needs: [pnpm_install]
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
workspace:
|
||||
- backend
|
||||
- frontend
|
||||
- sw
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: 'pnpm'
|
||||
- run: corepack enable
|
||||
- run: pnpm i --frozen-lockfile
|
||||
- run: pnpm --filter ${{ matrix.workspace }} run lint
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
pnpm_install:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: 'pnpm'
|
||||
- run: corepack enable
|
||||
- run: pnpm i --frozen-lockfile
|
||||
|
||||
lint:
|
||||
needs: [pnpm_install]
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
workspace:
|
||||
- backend
|
||||
- frontend
|
||||
- sw
|
||||
lint:
|
||||
- eslint
|
||||
steps:
|
||||
- uses: actions/checkout@v3.3.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
- uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 7
|
||||
run_install: false
|
||||
- uses: actions/setup-node@v3.6.0
|
||||
with:
|
||||
node-version: 18.x
|
||||
cache: 'pnpm'
|
||||
- run: corepack enable
|
||||
- run: pnpm i --frozen-lockfile
|
||||
- run: pnpm --filter ${{ matrix.workspace }} run ${{ matrix.lint }}
|
||||
|
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -109,8 +109,12 @@ jobs:
|
||||
# https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091
|
||||
- name: ALSA Env
|
||||
run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc
|
||||
# XXX: This tries reinstalling Cypress if the binary is not cached
|
||||
# Remove this when the cache issue is fixed
|
||||
- name: Cypress install
|
||||
run: pnpm exec cypress install
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v4
|
||||
uses: cypress-io/github-action@v5
|
||||
with:
|
||||
install: false
|
||||
start: pnpm start:test
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -32,6 +32,8 @@ coverage
|
||||
!/.config/example.yml
|
||||
!/.config/docker_example.yml
|
||||
!/.config/docker_example.env
|
||||
docker-compose.yml
|
||||
!/.devcontainer/docker-compose.yml
|
||||
|
||||
# misskey
|
||||
/build
|
||||
|
@@ -1 +1 @@
|
||||
v18.12.1
|
||||
v18.13.0
|
||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"search.exclude": {
|
||||
"**/node_modules": true
|
||||
}
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
193
CHANGELOG.md
193
CHANGELOG.md
@@ -8,6 +8,199 @@
|
||||
|
||||
You should also include the user name that made the change.
|
||||
-->
|
||||
## 13.7.0 (2023/02/22)
|
||||
|
||||
### Changes
|
||||
- チャット機能が削除されました
|
||||
|
||||
### Improvements
|
||||
- Server: URLプレビュー(summaly)はプロキシを通すように
|
||||
- Client: 2FA設定のUIをまともにした
|
||||
- セキュリティキーの名前を変更できるように
|
||||
- enhance(client): add quiz preset for play
|
||||
- 広告開始時期を設定できるように
|
||||
- みつけるで公開ロール一覧とそのメンバーを閲覧できるように
|
||||
- enhance(client): MFMのx3, x4が含まれていたらノートをたたむように
|
||||
- enhance(client): make possible to reload page of window
|
||||
|
||||
### Bugfixes
|
||||
- ユーザー検索ダイアログでローカルユーザーを絞って検索できない問題を修正
|
||||
- fix(client): MkHeader及びデッキのカラムでチャンネル一覧を選択したとき、最大5個までしか表示されない
|
||||
- 管理画面の広告を10個以上見えるように
|
||||
- Moderation note が保存できない
|
||||
- ユーザーのハッシュタグ検索が機能していないのを修正
|
||||
|
||||
## 13.6.1 (2023/02/12)
|
||||
|
||||
### Improvements
|
||||
- アニメーションを少なくする設定の時、MkPageHeaderのタブアニメーションを無効化
|
||||
- Backend: activitypub情報がcorsでブロックされないようヘッダーを追加
|
||||
- enhance: レートリミットを0%にできるように
|
||||
- チャンネル内Renoteを行えるように
|
||||
|
||||
### Bugfixes
|
||||
- Client: ユーザーページでアクティビティを見ることができない問題を修正
|
||||
|
||||
## 13.6.0 (2023/02/11)
|
||||
|
||||
### Improvements
|
||||
- MkPageHeaderをごっそり変えた
|
||||
* モバイルではヘッダーは上下に分割され、下段にタブが表示されるように
|
||||
* iconOnlyのタブ項目がアクティブな場合にはタブのタイトルを表示するように
|
||||
* メインタイムラインではタイトルを表示しない
|
||||
* メインタイムラインかつモバイルで表示される左上のアバターを選択するとアカウントメニューが開くように
|
||||
- ユーザーページのノート一覧をタブとして分離
|
||||
- コンディショナルロールもバッジとして表示可能に
|
||||
- enhance(client): ロールをより簡単に付与できるように
|
||||
- enhance(client): 一度見たノートのRenoteは省略して表示するように
|
||||
- enhance(client): 迷惑になる可能性のある投稿を行う前に警告を表示
|
||||
- リアクションの数が多い場合の表示を改善
|
||||
- 一部のMFM構文をopt-outに
|
||||
|
||||
### Bugfixes
|
||||
- Client: ユーザーページでタブがほとんど見れないことがないように
|
||||
|
||||
## 13.5.6 (2023/02/10)
|
||||
|
||||
### Improvements
|
||||
- 非ログイン時にMiAuthを踏んだ際にMiAuthであることを表示する
|
||||
- /auth/のUIをアップデート
|
||||
- 利用規約同意UIの調整
|
||||
- クロップ時の質問を分かりやすく
|
||||
|
||||
### Bugfixes
|
||||
- fix: prevent clipping audio plyr's tooltip
|
||||
|
||||
## 13.5.4 (2023/02/09)
|
||||
|
||||
### Improvements
|
||||
- Server: UIのHTML(ノートなどの特別なページを除く)のキャッシュ時間を15秒から30秒に
|
||||
- i/notificationsのレートリミットを緩和
|
||||
|
||||
### Bugfixes
|
||||
- fix(client): validate url to improve security
|
||||
- fix(client): dateの初期値が正常に入らない時がある
|
||||
|
||||
## 13.5.3 (2023/02/09)
|
||||
|
||||
### Improvements
|
||||
- Client: デッキにチャンネルカラムを追加
|
||||
|
||||
## 13.5.2 (2023/02/08)
|
||||
|
||||
### Changes
|
||||
- Revert: perf(client): do not render custom emojis in user names
|
||||
|
||||
### Bugfixes
|
||||
- Client: register_note_view_interruptor not working
|
||||
- Client: ログイントークンの再生成が出来ない
|
||||
|
||||
## 13.5.0 (2023/02/08)
|
||||
|
||||
### Changes
|
||||
- perf(client): do not render custom emojis in user names
|
||||
|
||||
### Improvements
|
||||
- Client: disableShowingAnimatedImagesのデフォルト値をprefers-reduced-motionにする
|
||||
- enhance(client): tweak medialist style
|
||||
|
||||
### Bugfixes
|
||||
- fix docker health check
|
||||
- Client: MkEmojiPickerでもChromeで検索ダイアログで変換確定するとそのまま検索されてしまうのを修正
|
||||
- fix(mfm): default degree not used in rotate
|
||||
- fix(server): validate urls from ap to improve security
|
||||
|
||||
## 13.4.0 (2023/02/05)
|
||||
|
||||
### Improvements
|
||||
- ロールにアイコンを設定してユーザー名の横に表示できるように
|
||||
- feat: timeline page for non-login users
|
||||
- 実績の単なるラッキーの獲得確立を調整
|
||||
- Add Thai language support
|
||||
|
||||
### Bugfixes
|
||||
- fix(server): 自分のノートをお気に入りに登録しても実績解除される問題を修正
|
||||
- fix(server): clean up file in FileServer
|
||||
- fix(server): Deny UNIX domain socket
|
||||
- fix(server): validate filename and emoji name to improve security
|
||||
- fix(client): validate input response in aiscript
|
||||
- fix(client): add webhook delete button
|
||||
- fix(client): tweak notification style
|
||||
- fix(client): インラインコードを折り返して表示する
|
||||
|
||||
## 13.3.3 (2023/02/04)
|
||||
|
||||
### Bugfixes
|
||||
- Server: improve security
|
||||
|
||||
## 13.3.2 (2023/02/04)
|
||||
|
||||
### Improvements
|
||||
- 外部メディアプロキシへの対応を強化しました
|
||||
外部メディアプロキシのFastify実装を作りました
|
||||
https://github.com/misskey-dev/media-proxy
|
||||
- Server: improve performance
|
||||
|
||||
### Bugfixes
|
||||
- Client: validate urls to improve security
|
||||
|
||||
## 13.3.1 (2023/02/04)
|
||||
|
||||
### Bugfixes
|
||||
- Client: カスタム絵文字にアニメーション画像を再生しない設定が適用されていない問題を修正
|
||||
- Client: オートコンプリートでUnicode絵文字がカスタム絵文字として表示されてしまうのを修正
|
||||
- Client: Fix Vue-plyr CORS issue
|
||||
- Client: validate urls to improve security
|
||||
|
||||
## 13.3.0 (2023/02/03)
|
||||
### Changes
|
||||
- twitter/github/discord連携機能が削除されました
|
||||
- ハッシュタグごとのチャートが削除されました
|
||||
- syslogのサポートが削除されました
|
||||
|
||||
### Improvements
|
||||
- ロールで広告の非表示が有効になっている場合は最初から広告を非表示にするように
|
||||
|
||||
## 13.2.6 (2023/02/01)
|
||||
### Changes
|
||||
- docker-compose.ymlをdocker-compose.yml.exampleにしました。docker-compose.ymlとしてコピーしてから使用してください。
|
||||
|
||||
### Improvements
|
||||
- 絵文字ピッカーのパフォーマンスを改善
|
||||
- AiScriptを0.12.4に更新
|
||||
|
||||
### Bugfixes
|
||||
- Server: リレーと通信できない問題を修正
|
||||
- Client: classicモード使用時にwindowサイズによってdefaultに変更された後に、windowサイズが元に戻ったらclassicに戻すように修正 #9669
|
||||
- Client: Chromeで検索ダイアログで変換確定するとそのまま検索されてしまう問題を修正
|
||||
|
||||
## 13.2.4 (2023/01/27)
|
||||
### Improvements
|
||||
- リモートカスタム絵文字表示時のパフォーマンスを改善
|
||||
- Default to `animation: false` when prefers-reduced-motion is set
|
||||
- リアクション履歴が公開なら、ログインしていなくても表示できるように
|
||||
- tweak blur setting
|
||||
- tweak custom emoji cache
|
||||
|
||||
### Bugfixes
|
||||
- fix aggregation of retention
|
||||
- ダッシュボードでオンラインユーザー数が表示されない問題を修正
|
||||
- フォロー申請・フォローのボタンが、通知から消えている問題を修正
|
||||
|
||||
## 13.2.3 (2023/01/26)
|
||||
### Improvements
|
||||
- カスタム絵文字の更新をリアルタイムで反映するように
|
||||
|
||||
### Bugfixes
|
||||
- turnstile-failed: missing-input-secret
|
||||
|
||||
## 13.2.2 (2023/01/25)
|
||||
### Improvements
|
||||
- サーバーのパフォーマンスを改善
|
||||
|
||||
### Bugfixes
|
||||
- サインイン時に誤ったレートリミットがかかることがある問題を修正
|
||||
- MFMのposition、rotate、scaleで小数が使えない問題を修正
|
||||
|
||||
## 13.2.1 (2023/01/24)
|
||||
### Improvements
|
||||
|
@@ -44,7 +44,7 @@ Thank you for your PR! Before creating a PR, please check the following:
|
||||
- Check if there are any documents that need to be created or updated due to this change.
|
||||
- If you have added a feature or fixed a bug, please add a test case if possible.
|
||||
- Please make sure that tests and Lint are passed in advance.
|
||||
- You can run it with `yarn test` and `yarn lint`. [See more info](#testing)
|
||||
- You can run it with `pnpm test` and `pnpm lint`. [See more info](#testing)
|
||||
- If this PR includes UI changes, please attach a screenshot in the text.
|
||||
|
||||
Thanks for your cooperation 🤗
|
||||
@@ -102,7 +102,7 @@ If your language is not listed in Crowdin, please open an issue.
|
||||
During development, it is useful to use the
|
||||
|
||||
```
|
||||
yarn dev
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
command.
|
||||
@@ -111,8 +111,28 @@ command.
|
||||
- Vite HMR (just the `vite` command) is available. The behavior may be different from production.
|
||||
- Service Worker is watched by esbuild.
|
||||
|
||||
### Dev Container
|
||||
Instead of running `pnpm` locally, you can use Dev Container to set up your development environment.
|
||||
To use Dev Container, open the project directory on VSCode with Dev Containers installed.
|
||||
**Note:** If you are using Windows, please clone the repository with WSL. Using Git for Windows will result in broken files due to the difference in how newlines are handled.
|
||||
|
||||
It will run the following command automatically inside the container.
|
||||
``` bash
|
||||
git submodule update --init
|
||||
pnpm install --frozen-lockfile
|
||||
cp .devcontainer/devcontainer.yml .config/default.yml
|
||||
pnpm build
|
||||
pnpm migrate
|
||||
```
|
||||
|
||||
After finishing the migration, run the `pnpm dev` command to start the development server.
|
||||
|
||||
``` bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Testing
|
||||
- Test codes are located in [`/test`](/test).
|
||||
- Test codes are located in [`/packages/backend/test`](/packages/backend/test).
|
||||
|
||||
### Run test
|
||||
Create a config file.
|
||||
@@ -121,18 +141,18 @@ cp .github/misskey/test.yml .config/
|
||||
```
|
||||
Prepare DB/Redis for testing.
|
||||
```
|
||||
docker-compose -f packages/backend/test/docker-compose.yml up
|
||||
docker compose -f packages/backend/test/docker-compose.yml up
|
||||
```
|
||||
Alternatively, prepare an empty (data can be erased) DB and edit `.config/test.yml`.
|
||||
|
||||
Run all test.
|
||||
```
|
||||
yarn test
|
||||
pnpm test
|
||||
```
|
||||
|
||||
#### Run specify test
|
||||
```
|
||||
yarn jest -- foo.ts
|
||||
pnpm jest -- foo.ts
|
||||
```
|
||||
|
||||
### e2e tests
|
||||
@@ -177,9 +197,9 @@ vue-routerとの最大の違いは、niraxは複数のルーターが存在す
|
||||
これにより、アプリ内ウィンドウでブラウザとは個別にルーティングすることなどが可能になります。
|
||||
|
||||
## Notes
|
||||
### How to resolve conflictions occurred at yarn.lock?
|
||||
### How to resolve conflictions occurred at pnpm-lock.yaml?
|
||||
|
||||
Just execute `yarn` to fix it.
|
||||
Just execute `pnpm` to fix it.
|
||||
|
||||
### INSERTするときにはsaveではなくinsertを使用する
|
||||
#6441
|
||||
@@ -265,7 +285,7 @@ MongoDBは`null`で返してきてたので、その感覚で`if (x === null)`
|
||||
### Migration作成方法
|
||||
packages/backendで:
|
||||
```sh
|
||||
yarn dlx typeorm migration:generate -d ormconfig.js -o <migration name>
|
||||
pnpm dlx typeorm migration:generate -d ormconfig.js -o <migration name>
|
||||
```
|
||||
|
||||
- 生成後、ファイルをmigration下に移してください
|
||||
|
41
Dockerfile
41
Dockerfile
@@ -1,43 +1,55 @@
|
||||
# syntax = docker/dockerfile:1.4
|
||||
|
||||
ARG NODE_VERSION=18.13.0-bullseye
|
||||
|
||||
FROM node:${NODE_VERSION} AS builder
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
rm -f /etc/apt/apt.conf.d/docker-clean \
|
||||
; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
|
||||
&& apt-get update \
|
||||
&& apt-get install -yqq --no-install-recommends \
|
||||
build-essential
|
||||
|
||||
RUN corepack enable
|
||||
|
||||
WORKDIR /misskey
|
||||
|
||||
COPY ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
|
||||
COPY ["scripts", "./scripts"]
|
||||
COPY ["packages/backend/package.json", "./packages/backend/"]
|
||||
COPY ["packages/frontend/package.json", "./packages/frontend/"]
|
||||
COPY ["packages/sw/package.json", "./packages/sw/"]
|
||||
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
|
||||
COPY --link ["scripts", "./scripts"]
|
||||
COPY --link ["packages/backend/package.json", "./packages/backend/"]
|
||||
COPY --link ["packages/frontend/package.json", "./packages/frontend/"]
|
||||
COPY --link ["packages/sw/package.json", "./packages/sw/"]
|
||||
|
||||
RUN pnpm i --frozen-lockfile
|
||||
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
|
||||
pnpm i --frozen-lockfile --aggregate-output
|
||||
|
||||
COPY . ./
|
||||
COPY --link . ./
|
||||
|
||||
ARG NODE_ENV=production
|
||||
|
||||
RUN git submodule update --init
|
||||
RUN pnpm build
|
||||
RUN rm -rf .git/
|
||||
|
||||
FROM node:${NODE_VERSION}-slim AS runner
|
||||
|
||||
ARG UID="991"
|
||||
ARG GID="991"
|
||||
|
||||
RUN apt-get update \
|
||||
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
||||
rm -f /etc/apt/apt.conf.d/docker-clean \
|
||||
; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
ffmpeg tini \
|
||||
&& apt-get -y clean \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
ffmpeg tini curl \
|
||||
&& corepack enable \
|
||||
&& groupadd -g "${GID}" misskey \
|
||||
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey
|
||||
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \
|
||||
&& find / -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \
|
||||
&& find / -type f -perm /g+s -ignore_readdir_race -exec chmod g-s {} \;
|
||||
|
||||
USER misskey
|
||||
WORKDIR /misskey
|
||||
@@ -51,5 +63,6 @@ COPY --chown=misskey:misskey --from=builder /misskey/fluent-emojis /misskey/flue
|
||||
COPY --chown=misskey:misskey . ./
|
||||
|
||||
ENV NODE_ENV=production
|
||||
HEALTHCHECK --interval=5s --retries=20 CMD ["/bin/bash", "/misskey/healthcheck.sh"]
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
CMD ["pnpm", "run", "migrateandstart"]
|
||||
|
@@ -24,6 +24,8 @@
|
||||
|
||||
---
|
||||
|
||||
[](https://codecov.io/gh/misskey-dev/misskey)
|
||||
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
11
ROADMAP.md
11
ROADMAP.md
@@ -5,17 +5,14 @@ Also, the later tasks are more indefinite and are subject to change as developme
|
||||
## (1) Improve maintainability \<current phase\>
|
||||
This is the phase we are at now. We need to make a high-maintenance environment that can withstand future development.
|
||||
|
||||
- Make the number of type errors zero (backend)
|
||||
- Probably need to switch some libraries to others that make it difficult to reduce type errors
|
||||
- e.g. koa to fastify https://github.com/misskey-dev/misskey/issues/7537
|
||||
- ~~Make the number of type errors zero (backend)~~ → Done ✔️
|
||||
- Improve CI
|
||||
- Fix tests
|
||||
- mocha, jest, etc. do not support the combination of `TypeScript + ESM + Path alias`, and the tests currently do not work.
|
||||
- ~~Fix tests~~ → Done ✔️
|
||||
- Fix random test failures - https://github.com/misskey-dev/misskey/issues/7985 and https://github.com/misskey-dev/misskey/issues/7986
|
||||
- Add more tests
|
||||
- May need to implement a mechanism that allows for DI
|
||||
- ~~May need to implement a mechanism that allows for DI~~ → Done ✔️
|
||||
- https://github.com/misskey-dev/misskey/pull/9085
|
||||
- Measure coverage
|
||||
- ~~Measure coverage~~ → Done ✔️
|
||||
- https://github.com/misskey-dev/misskey/pull/9081
|
||||
- Improve documentation
|
||||
- Refactoring
|
||||
|
@@ -1,3 +1,4 @@
|
||||
apiVersion: v2
|
||||
name: misskey
|
||||
version: 0.0.0
|
||||
description: This chart is created for the purpose of previewing Pull Requests. Do not use this for production use.
|
||||
|
@@ -133,11 +133,6 @@ id: "aid"
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Syslog option
|
||||
#syslog:
|
||||
# host: localhost
|
||||
# port: 514
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
|
5
codecov.yml
Normal file
5
codecov.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
only_pulls: true
|
4
healthcheck.sh
Normal file
4
healthcheck.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
PORT=$(grep '^port:' /misskey/.config/default.yml | awk 'NR==1{print $2; exit}')
|
||||
curl -s -S -o /dev/null "http://localhost:${PORT}"
|
@@ -886,56 +886,6 @@ _nsfw:
|
||||
respect: "اخف الوسائط ذات المحتوى الحساس"
|
||||
ignore: "اعرض الوسائط ذات المحتوى الحساس"
|
||||
force: "اخف كل الوسائط"
|
||||
_mfm:
|
||||
cheatSheet: "مرجع ملخص عن MFM"
|
||||
intro: "MFM هي لغة ترميزية مخصصة يمكن استخدامها في عدّة أماكن في ميسكي. يمكنك مراجعة كل تعابيرها مع كيفية استخدامها هنا."
|
||||
mention: "أشر الى"
|
||||
mentionDescription: "يمكنك الإشارة لمستخدم معيّن من خلال كتابة @ متبوعة باسم مستخدم."
|
||||
hashtag: "الوسوم"
|
||||
hashtagDescription: "يمكنك تعيين وسم من خلال كتابة # متبوعة بالنص المطلوب."
|
||||
url: "الرابط"
|
||||
urlDescription: "يمكن عرض الروابط"
|
||||
link: "رابط"
|
||||
bold: "عريض"
|
||||
boldDescription: "جعل الحروف أثخن لإبرازها."
|
||||
small: "صغير"
|
||||
smallDescription: "يعرض المحتوى صغيرًا ورفيعًا."
|
||||
center: "وسط"
|
||||
centerDescription: "يمركز المحتوى في الوَسَط."
|
||||
quote: "اقتبس"
|
||||
quoteDescription: "يعرض المحتوى كاقتباس"
|
||||
emoji: "إيموجي مخصص"
|
||||
emojiDescription: "إحاطة اسم الإيموجي بنقطتي تفسير سيستبدله بصورة الإيموجي."
|
||||
search: "البحث"
|
||||
searchDescription: "يعرض نصًا في صندوق البحث"
|
||||
flip: "اقلب"
|
||||
flipDescription: "يقلب المحتوى عموديًا أو أفقيًا"
|
||||
jelly: "تأثير (هلام)"
|
||||
jellyDescription: "يمنح المحتوى حركة هلامية."
|
||||
tada: "تأثير (تادا)"
|
||||
tadaDescription: "يمنح للمحتوى تأثير تادا"
|
||||
jump: "تأثير (قفز)"
|
||||
jumpDescription: "يمنح للمحتوى حركة قفز."
|
||||
bounce: "تأثير (ارتداد)"
|
||||
bounceDescription: "يمنح للمحتوى حركة ارتدادية"
|
||||
shake: "تأثير (اهتزاز)"
|
||||
shakeDescription: "يمنح المحتوى حركة اهتزازية."
|
||||
spin: "تأثير (دوران)"
|
||||
spinDescription: "يمنح المحتوى حركة دورانية."
|
||||
x2: "كبير"
|
||||
x2Description: "يُكبر المحتوى"
|
||||
x3: "كبير جداً"
|
||||
x3Description: "يُضخم المحتوى"
|
||||
x4: "هائل"
|
||||
x4Description: "يُضخم المحتوى أكثر مما سبق."
|
||||
blur: "طمس"
|
||||
blurDescription: "يطمس المحتوى، لكن بالتمرير فوقه سيظهر بوضوح."
|
||||
font: "الخط"
|
||||
fontDescription: "الخط المستخدم لعرض المحتوى."
|
||||
rainbow: "قوس قزح"
|
||||
rainbowDescription: "اجعل المحتوى يظهر بألوان الطيف"
|
||||
rotate: "تدوير"
|
||||
rotateDescription: "يُدير المحتوى بزاوية معيّنة."
|
||||
_instanceTicker:
|
||||
none: "لا تظهره بتاتًا"
|
||||
remote: "أظهر للمستخدمين البِعاد"
|
||||
@@ -1345,5 +1295,6 @@ _deck:
|
||||
tl: "الخيط الزمني"
|
||||
antenna: "الهوائيات"
|
||||
list: "القوائم"
|
||||
channel: "القنوات"
|
||||
mentions: "الإشارات"
|
||||
direct: "مباشرة"
|
||||
|
@@ -455,7 +455,6 @@ youHaveNoGroups: "আপনার কোন গ্রুপ নেই "
|
||||
joinOrCreateGroup: "একটি বিদ্যমান গ্রুপের আমন্ত্রণ পান বা একটি নতুন গ্রুপ তৈরি করুন৷"
|
||||
noHistory: "কোনো ইতিহাস নেই"
|
||||
signinHistory: "প্রবেশ করার ইতিহাস"
|
||||
disableAnimatedMfm: "অ্যানিমেটেড MFM অক্ষম করুন"
|
||||
doing: "প্রক্রিয়া করছে..."
|
||||
category: "বিভাগ"
|
||||
tags: "ট্যাগসমূহ"
|
||||
@@ -923,70 +922,6 @@ _nsfw:
|
||||
respect: "স্পর্শকাতর মিডিয়া লুকান"
|
||||
ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না"
|
||||
force: "সকল মিডিয়া লুকান"
|
||||
_mfm:
|
||||
cheatSheet: "MFM চিটশিট"
|
||||
intro: "MFM একটি মার্কআপ ভাষা যা Misskey-এর মধ্যে বিভিন্ন জায়গায় ব্যবহার করা যেতে পারে। এখানে আপনি MFM-এর সিনট্যাক্সগুলির একটি তালিকা দেখতে পারবেন।"
|
||||
dummy: "মিসকি ফেডিভার্সের বিশ্বকে প্রসারিত করে"
|
||||
mention: "উল্লেখ"
|
||||
mentionDescription: "@ চিহ্ন + ব্যবহারকারীর নাম একটি নির্দিষ্ট ব্যবহারকারীকে নির্দেশ করতে ব্যবহার করা যায়।"
|
||||
hashtag: "হ্যাশট্যাগ"
|
||||
hashtagDescription: "আপনি একটি # চিহ্ন + ট্যাগ সহ একটি হ্যাশট্যাগ নির্দেশ করতে পারেন।"
|
||||
url: "URL"
|
||||
urlDescription: "URL দেখানো সম্ভব।"
|
||||
link: "লিংক"
|
||||
linkDescription: "আপনি পাঠ্যের একটি নির্দিষ্ট অংশকে URL হিসাবে দেখাতে পারেন৷"
|
||||
bold: "গাঢ়"
|
||||
boldDescription: "অক্ষরগুলিকে মোটাকরে প্রদর্শন করা হবে।"
|
||||
small: "ছোট"
|
||||
smallDescription: "লেখা ছোট এবং পাতলা করে দেখানো হবে।"
|
||||
center: "সেন্টার"
|
||||
centerDescription: "লেখা মাঝ বরাবর দেখানো হবে"
|
||||
inlineCode: "কোড (ইনলাইন)"
|
||||
inlineCodeDescription: " প্রোগ্রামের কোডের জন্য ইনলাইন সিনট্যাক্স হাইলাইটিং করা হবে"
|
||||
blockCode: "কোড (ব্লক)"
|
||||
blockCodeDescription: "মাল্টি-লাইন প্রোগ্রামের কোডের জন্য সিনট্যাক্স হাইলাইট করে।"
|
||||
inlineMath: "গাণিতিক সূত্র (ইনলাইন)"
|
||||
inlineMathDescription: "গাণিতিক সূত্র প্রদর্শন করুন (KaTeX) ইনলাইন।"
|
||||
blockMath: "গাণিতিক সূত্র (ব্লক)"
|
||||
blockMathDescription: "একটি ব্লকে একাধিক লাইনের গাণিতিক সূত্র প্রদর্শন করুন (KaTeX)।"
|
||||
quote: "উদ্ধৃতি"
|
||||
quoteDescription: "বিষয়বস্তুকে একটি উদ্ধৃতি হিসাবে দেখানো হবে।"
|
||||
emoji: "স্বনির্ধারিত ইমোজিগুলি"
|
||||
emojiDescription: "আপনি একটি কাস্টম ইমোজির নাম কোলনে আবদ্ধ করে কাস্টম ইমোজিটি দেখাতে পারেন৷"
|
||||
search: "খুঁজুন"
|
||||
searchDescription: "পূর্ব-টাইপ করা পাঠ্য সহ একটি অনুসন্ধান বাক্স প্রদর্শন করে।"
|
||||
flip: "উল্টান"
|
||||
flipDescription: "বিষয়বস্তু উপরে/নীচে বা বাম/ডানে উল্টান।"
|
||||
jelly: "অ্যানিমেশন (জেলি)"
|
||||
jellyDescription: "জেলির মত অ্যানিমেশন দেখায়।"
|
||||
tada: "অ্যানিমেশন (টাডা)"
|
||||
tadaDescription: "\"টাডা!\" এর মত অ্যানিমেশন দেখায়।"
|
||||
jump: "অ্যানিমেশন (লাফ)"
|
||||
jumpDescription: "বিষয়বস্তুতে লাফ মারার মত অ্যানিমেশন দেখায়।"
|
||||
bounce: "অ্যানিমেশন (তিড়িং বিড়িং)"
|
||||
bounceDescription: "তিড়িং বিড়িং করার মত অ্যানিমেশন দেখায়।"
|
||||
shake: "অ্যানিমেশন (ঝাঁকি)"
|
||||
shakeDescription: "ঝাঁকির মত অ্যানিমেশন দেখায়।"
|
||||
twitch: "অ্যানিমেশন (মোচড়ানো)"
|
||||
twitchDescription: "মোচড়ানোর মত অ্যানিমেশন দেখায়।"
|
||||
spin: "অ্যানিমেশন (ঘুরা)"
|
||||
spinDescription: "ঘুরার মত অ্যানিমেশন দেখায়।"
|
||||
x2: "বড়"
|
||||
x2Description: "বিষয়বস্তু বড় করে দেখায়।"
|
||||
x3: "অনেক বড়"
|
||||
x3Description: "বিষয়বস্তু আরও বড় করে দেখায়।"
|
||||
x4: "অস্বাভাবিক বড়"
|
||||
x4Description: "বিষয়বস্তুকে আগের থেকেও আরও বড় করে দেখায়।"
|
||||
blur: "ব্লার"
|
||||
blurDescription: "বিষয়বস্তুকে ব্লার করতে পারেন। আপনি এর উপর মাউস কার্সার রাখলে, এটি পরিষ্কারভাবে দেখতে পাবেন।"
|
||||
font: "ফন্ট"
|
||||
fontDescription: "বিষয়বস্তুকে কোন ফন্টে দেখানো হবে তা নির্ধারণ করে।"
|
||||
rainbow: "রেইনবো"
|
||||
rainbowDescription: "বিষয়বস্তুকে রংধনুর রং গুলিতে প্রদর্শন করে।"
|
||||
sparkle: "চিক চিক"
|
||||
sparkleDescription: "বিষয়বস্তুকে একটি চিকচিকে কণা প্রভাব দেয়।"
|
||||
rotate: "ঘুরান"
|
||||
rotateDescription: "বিষয়বস্তুকে একটি নির্দিষ্ট কোনে ঘুরায়।"
|
||||
_instanceTicker:
|
||||
none: "দেখাবেন না"
|
||||
remote: "রিমোট ব্যাবহারকারীদের জন্য দেখান"
|
||||
@@ -1441,5 +1376,6 @@ _deck:
|
||||
tl: "টাইমলাইন"
|
||||
antenna: "অ্যান্টেনা"
|
||||
list: "লিস্ট"
|
||||
channel: "চ্যানেলগুলি"
|
||||
mentions: "উল্লেখসমূহ"
|
||||
direct: "ডাইরেক্ট নোটগুলি"
|
||||
|
@@ -375,11 +375,6 @@ file: "Fitxers"
|
||||
_email:
|
||||
_follow:
|
||||
title: "t'ha seguit"
|
||||
_mfm:
|
||||
mention: "Menció"
|
||||
quote: "Citar"
|
||||
emoji: "Emojis personalitzats"
|
||||
search: "Cercar"
|
||||
_instanceMute:
|
||||
instanceMuteDescription: "Silencia tots els impulsos dels servidors seleccionats, també els usuaris que responen a altres d'un servidor silenciat."
|
||||
_theme:
|
||||
|
@@ -642,19 +642,6 @@ _registry:
|
||||
_aboutMisskey:
|
||||
allContributors: "Všichni přispěvatelé"
|
||||
source: "Zdrojový kód"
|
||||
_mfm:
|
||||
mention: "Zmínění"
|
||||
hashtag: "Hashtag"
|
||||
link: "Odkaz"
|
||||
bold: "Tučně"
|
||||
quote: "Citovat"
|
||||
emoji: "Vlastní emoji"
|
||||
search: "Vyhledávání"
|
||||
flip: "Otočit"
|
||||
tada: "Animace (tadá)"
|
||||
blur: "Rozmazání"
|
||||
font: "Font"
|
||||
rainbow: "Duha"
|
||||
_channel:
|
||||
featured: "Trendy"
|
||||
_menuDisplay:
|
||||
@@ -804,4 +791,5 @@ _deck:
|
||||
tl: "Časová osa"
|
||||
antenna: "Antény"
|
||||
list: "Seznamy"
|
||||
channel: "Kanály"
|
||||
mentions: "Zmínění"
|
||||
|
@@ -68,7 +68,7 @@ export: "Export"
|
||||
files: "Dateien"
|
||||
download: "Herunterladen"
|
||||
driveFileDeleteConfirm: "Möchtest du die Datei „{name}“ wirklich löschen? Notizen mit dieser Datei werden ebenso verschwinden."
|
||||
unfollowConfirm: "Möchtest du {name} nicht mehr folgen?"
|
||||
unfollowConfirm: "Möchtest du {name} wirklich nicht mehr folgen?"
|
||||
exportRequested: "Du hast einen Export angefragt. Dies kann etwas Zeit in Anspruch nehmen. Sobald der Export abgeschlossen ist, wird er deiner Drive hinzugefügt."
|
||||
importRequested: "Du hast einen Import angefragt. Dies kann etwas Zeit in Anspruch nehmen."
|
||||
lists: "Listen"
|
||||
@@ -94,7 +94,7 @@ defaultNoteVisibility: "Standardsichtbarkeit"
|
||||
follow: "Folgen"
|
||||
followRequest: "Follow-Anfrage senden"
|
||||
followRequests: "Follow-Anfragen"
|
||||
unfollow: "Nicht mehr folgen"
|
||||
unfollow: "Entfolgen"
|
||||
followRequestPending: "Follow-Anfrage ausstehend"
|
||||
enterEmoji: "Gib ein Emoji ein"
|
||||
renote: "Renote"
|
||||
@@ -103,6 +103,8 @@ renoted: "Renote getätigt."
|
||||
cantRenote: "Renote dieses Beitrags nicht möglich."
|
||||
cantReRenote: "Renote einer Renote nicht möglich."
|
||||
quote: "Zitieren"
|
||||
inChannelRenote: "Kanal-interner Renote"
|
||||
inChannelQuote: "Kanal-internes Zitat"
|
||||
pinnedNote: "Angeheftete Notiz"
|
||||
pinned: "Angeheftet"
|
||||
you: "Du"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "Möchtest du diese Blockierung wirklich aufheben?"
|
||||
suspendConfirm: "Möchtest du diesen Benutzer wirklich sperren?"
|
||||
unsuspendConfirm: "Möchtest du diesen Benutzer wirklich entsperren?"
|
||||
selectList: "Liste auswählen"
|
||||
selectChannel: "Kanal auswählen"
|
||||
selectAntenna: "Antenne auswählen"
|
||||
selectWidget: "Widget auswählen"
|
||||
editWidgets: "Widgets bearbeiten"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "Kein weiterer Verlauf vorhanden"
|
||||
startMessaging: "Neuen Chat erstellen"
|
||||
nUsersRead: "Von {n} Benutzern gelesen"
|
||||
agreeTo: "Ich stimme {0} zu"
|
||||
agreeBelow: "Ich stimme Untenstehendem zu"
|
||||
basicNotesBeforeCreateAccount: "Wichtige Infos"
|
||||
tos: "Nutzungsbedingungen"
|
||||
start: "Anfangen"
|
||||
home: "Startseite"
|
||||
@@ -464,7 +469,8 @@ youHaveNoGroups: "Keine Gruppen vorhanden"
|
||||
joinOrCreateGroup: "Lass dich zu einer Gruppe einladen oder erstelle deine eigene."
|
||||
noHistory: "Kein Verlauf gefunden"
|
||||
signinHistory: "Anmeldungsverlauf"
|
||||
disableAnimatedMfm: "MFM, die Animationen enthalten, deaktivieren"
|
||||
enableAdvancedMfm: "Erweitertes MFM aktivieren"
|
||||
enableAnimatedMfm: "Animiertes MFM aktivieren"
|
||||
doing: "In Bearbeitung …"
|
||||
category: "Kategorie"
|
||||
tags: "Schlagwörter"
|
||||
@@ -861,6 +867,8 @@ failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgef
|
||||
rateLimitExceeded: "Versuchsanzahl überschritten"
|
||||
cropImage: "Bild zuschneiden"
|
||||
cropImageAsk: "Möchtest du das Bild zuschneiden?"
|
||||
cropYes: "Zuschneiden"
|
||||
cropNo: "Unbearbeitet verwenden"
|
||||
file: "Datei"
|
||||
recentNHours: "Letzten {n} Stunden"
|
||||
recentNDays: "Letzten {n} Tage"
|
||||
@@ -939,6 +947,16 @@ cannotPerformTemporaryDescription: "Diese Aktion ist wegen des Überschreitenes
|
||||
preset: "Vorlage"
|
||||
selectFromPresets: "Aus Vorlagen wählen"
|
||||
achievements: "Errungenschaften"
|
||||
gotInvalidResponseError: "Ungültige Antwort des Servers"
|
||||
gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
|
||||
thisPostMayBeAnnoying: "Dieser Beitrag stört eventuell andere Benutzer."
|
||||
thisPostMayBeAnnoyingHome: "Zur Startseite schicken"
|
||||
thisPostMayBeAnnoyingCancel: "Abbrechen"
|
||||
thisPostMayBeAnnoyingIgnore: "Trotzdem schicken"
|
||||
collapseRenotes: "Bereits gesehene Renotes verkürzt anzeigen"
|
||||
internalServerError: "Serverinterner Fehler"
|
||||
internalServerErrorDescription: "Im Server ist ein unerwarteter Fehler aufgetreten."
|
||||
copyErrorInfo: "Fehlerdetails kopieren"
|
||||
_achievements:
|
||||
earnedAt: "Freigeschaltet am"
|
||||
_types:
|
||||
@@ -1195,6 +1213,9 @@ _role:
|
||||
baseRole: "Rollenvorlage"
|
||||
useBaseValue: "Wert der Rollenvorlage verwenden"
|
||||
chooseRoleToAssign: "Zuzuweisende Rolle auswählen"
|
||||
iconUrl: "Icon-URL"
|
||||
asBadge: "Als Abzeichen anzeigen"
|
||||
descriptionOfAsBadge: "Ist dies aktiviert, so wird das Icon dieser Rolle an der Seite der Namen von Benutzern mit dieser Rolle angezeigt."
|
||||
canEditMembersByModerator: "Moderatoren können Benutzern diese Rolle zuweisen"
|
||||
descriptionOfCanEditMembersByModerator: "Wenn aktiviert, so können Moderatoren und Adminstratoren anderen Benutzern diese Rolle zuweisen bzw. diese Zuweisung aufheben. Wenn deaktiviert, so ist es nur Administratoren möglich, Zuweisungen dieser Rolle zu verwalten."
|
||||
priority: "Priorität"
|
||||
@@ -1320,72 +1341,6 @@ _nsfw:
|
||||
respect: "Als NSFW markierte Bilder verbergen"
|
||||
ignore: "Als NSFW markierte Bilder nicht verbergen"
|
||||
force: "Alle Medien verbergen"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Spickzettel"
|
||||
intro: "MFM ist eine Misskey-exklusive Markup-Sprache, die in Misskey an vielen Stellen verwendet werden kann. Hier kannst du eine Liste von verfügbarer MFM-Syntax einsehen."
|
||||
dummy: "Misskey erweitert die Welt des Fediverse"
|
||||
mention: "Erwähnung"
|
||||
mentionDescription: "Mit At-Zeichen und Benutzername kann ein individueller Nutzer angegeben werden."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Mit einer Raute und Text kann ein Hashtag angegeben werden."
|
||||
url: "URL"
|
||||
urlDescription: "Zeigt URLs an."
|
||||
link: "Link"
|
||||
linkDescription: "Zeigt spezifische Textabschnitte als URL an."
|
||||
bold: "Fett"
|
||||
boldDescription: "Zeichen zur Betonung dicker erscheinen lassen."
|
||||
small: "Klein"
|
||||
smallDescription: "Inhalt klein und dünn erscheinen lassen."
|
||||
center: "Zentrieren"
|
||||
centerDescription: "Inhalt zentriert anzeigen."
|
||||
inlineCode: "Code (Eingebettet)"
|
||||
inlineCodeDescription: "Syntax-Hervorhebung für (Programm-)Code eingebettet anzeigen."
|
||||
blockCode: "Code (Block)"
|
||||
blockCodeDescription: "Syntax-Hervorhebung für mehrzeiligen (Programm-)Code als Block anzeigen."
|
||||
inlineMath: "Mathe (Eingebettet)"
|
||||
inlineMathDescription: "Mathematische Formeln (KaTeX) eingebettet anzeigen."
|
||||
blockMath: "Mathe (Block)"
|
||||
blockMathDescription: "Mehrzeilige mathematische Formeln (KaTeX) als Block einbetten."
|
||||
quote: "Zitationen"
|
||||
quoteDescription: "Inhalt als Zitat anzeigen."
|
||||
emoji: "Benutzerdefinierte Emojis"
|
||||
emojiDescription: "Durch das Umschließen von Emoji-Namen durch Doppelpunkte können benutzerdefinierte Emojis angezeigt werden."
|
||||
search: "Suche"
|
||||
searchDescription: "Eine vorgefertige Suchanfragebox anzeigen."
|
||||
flip: "Spiegelung"
|
||||
flipDescription: "Inhalt horizontal oder vertikal gespiegelt anzeigen."
|
||||
jelly: "Animation (Dehnen)"
|
||||
jellyDescription: "Verleiht Inhalt eine sich dehnende Animation."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Verleiht Inhalt eine Animation mit \"Tada!\"-Gefühl"
|
||||
jump: "Animation (Sprung)"
|
||||
jumpDescription: "Verleiht Inhalt eine springende Animation."
|
||||
bounce: "Animation (Federn)"
|
||||
bounceDescription: "Verleiht Inhalt eine federnde Animation."
|
||||
shake: "Animation (Zittern)"
|
||||
shakeDescription: "Verleiht Inhalt eine zitternde Animation."
|
||||
twitch: "Animation (Zucken)"
|
||||
twitchDescription: "Verleiht Inhalt eine sehr stark zuckende Animation."
|
||||
spin: "Animation (Rotieren)"
|
||||
spinDescription: "Verleiht Inhalt eine rotierende Animation."
|
||||
x2: "Groß"
|
||||
x2Description: "Inhalte größer anzeigen."
|
||||
x3: "Sehr groß"
|
||||
x3Description: "Inhalte noch größer anzeigen."
|
||||
x4: "Unglaublich groß"
|
||||
x4Description: "Lässt Inhalte noch größer als größer als groß angezeigt werden."
|
||||
blur: "Weichzeichnen"
|
||||
blurDescription: "Inhalte durch Weihzeichnung verschwimmen lassen. Durch das Bewegen des Mauszeigers über den Inhalt wird er klar angezeigt."
|
||||
font: "Schriftart"
|
||||
fontDescription: "Setzt die Schriftart des Inhaltes fest."
|
||||
rainbow: "Regenbogen"
|
||||
rainbowDescription: "Lässt den Inhalt in Regenbogenfarben erscheinen."
|
||||
sparkle: "Glitzer"
|
||||
sparkleDescription: "Verleiht Inhalt einen glitzernden Partikeleffekt."
|
||||
rotate: "Drehen"
|
||||
rotateDescription: "Dreht den Inhalt um einen angegebenen Winkel."
|
||||
plain: "Schlicht"
|
||||
plainDescription: "Deaktiviert jegliche MFM-Syntax, die sich innerhalb dieses MFM-Effekts befindet."
|
||||
_instanceTicker:
|
||||
none: "Nie anzeigen"
|
||||
remote: "Für Benutzer fremder Instanzen anzeigen"
|
||||
@@ -1590,12 +1545,15 @@ _permissions:
|
||||
"read:gallery-likes": "Liste deiner mit \"Gefällt mir\" markierten Galerie-Beiträge lesen"
|
||||
"write:gallery-likes": "Liste deiner mit \"Gefällt mir\" markierten Galerie-Beiträge bearbeiten"
|
||||
_auth:
|
||||
shareAccessTitle: "Verteilung von App-Berechtigungen"
|
||||
shareAccess: "Möchtest du „{name}“ authorisieren, auf dieses Benutzerkonto zugreifen zu können?"
|
||||
shareAccessAsk: "Bist du dir sicher, dass du diese Anwendung authorisieren möchtest, auf dein Benutzerkonto zugreifen zu können?"
|
||||
permission: "{name} fordert folgende Berechtigungen"
|
||||
permissionAsk: "Diese Anwendung fordert folgende Berechtigungen"
|
||||
pleaseGoBack: "Bitte kehre zur Anwendung zurück"
|
||||
callback: "Es wird zur Anwendung zurückgekehrt"
|
||||
denied: "Zugriff verweigert"
|
||||
pleaseLogin: "Bitte logge dich ein, um Apps zu authorisieren."
|
||||
_antennaSources:
|
||||
all: "Alle Notizen"
|
||||
homeTimeline: "Notizen von Benutzern, denen gefolgt wird"
|
||||
@@ -1866,5 +1824,6 @@ _deck:
|
||||
tl: "Chronik"
|
||||
antenna: "Antennen"
|
||||
list: "Listen"
|
||||
channel: "Kanal"
|
||||
mentions: "Erwähnungen"
|
||||
direct: "Direktnachrichten"
|
||||
|
@@ -298,11 +298,6 @@ cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω
|
||||
_email:
|
||||
_follow:
|
||||
title: "Έχετε ένα νέο ακόλουθο"
|
||||
_mfm:
|
||||
mention: "Επισήμανση"
|
||||
quote: "Παράθεση"
|
||||
emoji: "Επιπλέον emoji"
|
||||
search: "Αναζήτηση"
|
||||
_channel:
|
||||
featured: "Δημοφιλή"
|
||||
_theme:
|
||||
|
@@ -68,7 +68,7 @@ export: "Export"
|
||||
files: "Files"
|
||||
download: "Download"
|
||||
driveFileDeleteConfirm: "Are you sure you want to delete the file \"{name}\"? Notes with this file attached will also be deleted."
|
||||
unfollowConfirm: "Are you sure that you want to unfollow {name}?"
|
||||
unfollowConfirm: "Are you sure you want to unfollow {name}?"
|
||||
exportRequested: "You've requested an export. This may take a while. It will be added to your Drive once completed."
|
||||
importRequested: "You've requested an import. This may take a while."
|
||||
lists: "Lists"
|
||||
@@ -103,6 +103,8 @@ renoted: "Renoted."
|
||||
cantRenote: "This post can't be renoted."
|
||||
cantReRenote: "A renote can't be renoted."
|
||||
quote: "Quote"
|
||||
inChannelRenote: "Channel-only Renote"
|
||||
inChannelQuote: "Channel-only Quote"
|
||||
pinnedNote: "Pinned note"
|
||||
pinned: "Pin to profile"
|
||||
you: "You"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "Are you sure that you want to unblock this account?"
|
||||
suspendConfirm: "Are you sure that you want to suspend this account?"
|
||||
unsuspendConfirm: "Are you sure that you want to unsuspend this account?"
|
||||
selectList: "Select a list"
|
||||
selectChannel: "Select a channel"
|
||||
selectAntenna: "Select an antenna"
|
||||
selectWidget: "Select a widget"
|
||||
editWidgets: "Edit widgets"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "There is no further history"
|
||||
startMessaging: "Start a new chat"
|
||||
nUsersRead: "read by {n}"
|
||||
agreeTo: "I agree to {0}"
|
||||
agreeBelow: "I agree to the below"
|
||||
basicNotesBeforeCreateAccount: "Important notes"
|
||||
tos: "Terms of Service"
|
||||
start: "Begin"
|
||||
home: "Home"
|
||||
@@ -464,7 +469,8 @@ youHaveNoGroups: "You have no groups"
|
||||
joinOrCreateGroup: "Get invited to a group or create your own."
|
||||
noHistory: "No history available"
|
||||
signinHistory: "Login history"
|
||||
disableAnimatedMfm: "Disable MFM with animation"
|
||||
enableAdvancedMfm: "Enable advanced MFM"
|
||||
enableAnimatedMfm: "Enable animated MFM"
|
||||
doing: "Processing..."
|
||||
category: "Category"
|
||||
tags: "Tags"
|
||||
@@ -861,6 +867,8 @@ failedToFetchAccountInformation: "Could not fetch account information"
|
||||
rateLimitExceeded: "Rate limit exceeded"
|
||||
cropImage: "Crop image"
|
||||
cropImageAsk: "Do you want to crop this image?"
|
||||
cropYes: "Crop"
|
||||
cropNo: "Use as-is"
|
||||
file: "File"
|
||||
recentNHours: "Last {n} hours"
|
||||
recentNDays: "Last {n} days"
|
||||
@@ -939,6 +947,16 @@ cannotPerformTemporaryDescription: "This action cannot be performed temporarily
|
||||
preset: "Preset"
|
||||
selectFromPresets: "Choose from presets"
|
||||
achievements: "Achievements"
|
||||
gotInvalidResponseError: "Invalid server response"
|
||||
gotInvalidResponseErrorDescription: "The server may be unreachable or undergoing maintenance. Please try again later."
|
||||
thisPostMayBeAnnoying: "This note may annoy others."
|
||||
thisPostMayBeAnnoyingHome: "Post to home timeline"
|
||||
thisPostMayBeAnnoyingCancel: "Cancel"
|
||||
thisPostMayBeAnnoyingIgnore: "Post anyway"
|
||||
collapseRenotes: "Collapse renotes you've already seen"
|
||||
internalServerError: "Internal Server Error"
|
||||
internalServerErrorDescription: "The server has run into an unexpected error."
|
||||
copyErrorInfo: "Copy error details"
|
||||
_achievements:
|
||||
earnedAt: "Unlocked at"
|
||||
_types:
|
||||
@@ -1195,6 +1213,9 @@ _role:
|
||||
baseRole: "Role template"
|
||||
useBaseValue: "Use role template value"
|
||||
chooseRoleToAssign: "Select the role to assign"
|
||||
iconUrl: "Icon URL"
|
||||
asBadge: "Show as badge"
|
||||
descriptionOfAsBadge: "This role's icon will be displayed next to the username of users with this role if turned on."
|
||||
canEditMembersByModerator: "Allow moderators to edit the list of members for this role"
|
||||
descriptionOfCanEditMembersByModerator: "When turned on, moderators as well as administrators will be able to assign and unassign users to this role. When turned off, only administrators will be able to assign users."
|
||||
priority: "Priority"
|
||||
@@ -1320,72 +1341,6 @@ _nsfw:
|
||||
respect: "Hide NSFW media"
|
||||
ignore: "Don't hide NSFW media"
|
||||
force: "Hide all media"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM is a Misskey-exclusive markup language that can be used in many places. Here you can view a list of all available MFM syntax."
|
||||
dummy: "Misskey expands the world of the Fediverse"
|
||||
mention: "Mention"
|
||||
mentionDescription: "You can specify a user by using an At-Symbol and a username."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "You can specify a hashtag using a number sign and text."
|
||||
url: "URL"
|
||||
urlDescription: "URLs can be displayed."
|
||||
link: "Link"
|
||||
linkDescription: "Specific parts of text can be displayed as a URL."
|
||||
bold: "Bold"
|
||||
boldDescription: "Highlights letters by making them thicker."
|
||||
small: "Small"
|
||||
smallDescription: "Displays content small and thin."
|
||||
center: "Center"
|
||||
centerDescription: "Displays content centered."
|
||||
inlineCode: "Code (Inline)"
|
||||
inlineCodeDescription: "Displays inline syntax highlighting for (program) code."
|
||||
blockCode: "Code (Block)"
|
||||
blockCodeDescription: "Displays syntax highlighting for multi-line (program) code in a block."
|
||||
inlineMath: "Math (Inline)"
|
||||
inlineMathDescription: "Display math formulas (KaTeX) in-line"
|
||||
blockMath: "Math (Block)"
|
||||
blockMathDescription: "Display multi-line math formulas (KaTeX) in a block"
|
||||
quote: "Quote"
|
||||
quoteDescription: "Displays content as a quote."
|
||||
emoji: "Custom Emoji"
|
||||
emojiDescription: "By surrounding a custom emoji name with colons, custom emoji can be displayed."
|
||||
search: "Search"
|
||||
searchDescription: "Displays a search box with pre-entered text."
|
||||
flip: "Flip"
|
||||
flipDescription: "Flips content horizontally or vertically."
|
||||
jelly: "Animation (Jelly)"
|
||||
jellyDescription: "Gives content a jelly-like animation."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Gives content a \"Tada!\"-like animation."
|
||||
jump: "Animation (Jump)"
|
||||
jumpDescription: "Gives content a jumping animation."
|
||||
bounce: "Animation (Bounce)"
|
||||
bounceDescription: "Gives content a bouncy animation."
|
||||
shake: "Animation (Shake)"
|
||||
shakeDescription: "Gives content a shaking animation."
|
||||
twitch: "Animation (Twitch)"
|
||||
twitchDescription: "Gives content a strongly twitching animation."
|
||||
spin: "Animation (Spin)"
|
||||
spinDescription: "Gives content a spinning animation."
|
||||
x2: "Big"
|
||||
x2Description: "Displays content bigger."
|
||||
x3: "Very big"
|
||||
x3Description: "Displays content even bigger."
|
||||
x4: "Unbelievably big"
|
||||
x4Description: "Displays content even bigger than bigger than big."
|
||||
blur: "Blur"
|
||||
blurDescription: "Blurs content. It will be displayed clearly when hovered over."
|
||||
font: "Font"
|
||||
fontDescription: "Sets the font to display content in."
|
||||
rainbow: "Rainbow"
|
||||
rainbowDescription: "Makes the content appear in rainbow colors."
|
||||
sparkle: "Sparkle"
|
||||
sparkleDescription: "Gives content a sparkling particle effect."
|
||||
rotate: "Rotate"
|
||||
rotateDescription: "Turns content by a specified angle."
|
||||
plain: "Plain"
|
||||
plainDescription: "Deactivates the effects of all MFM contained within this MFM effect."
|
||||
_instanceTicker:
|
||||
none: "Never show"
|
||||
remote: "Show for remote users"
|
||||
@@ -1590,12 +1545,15 @@ _permissions:
|
||||
"read:gallery-likes": "View your list of liked gallery posts"
|
||||
"write:gallery-likes": "Edit your list of liked gallery posts"
|
||||
_auth:
|
||||
shareAccessTitle: "Granting application permissions"
|
||||
shareAccess: "Would you like to authorize \"{name}\" to access this account?"
|
||||
shareAccessAsk: "Are you sure you want to authorize this application to access your account?"
|
||||
permission: "{name} requests the following permissions"
|
||||
permissionAsk: "This application requests the following permissions"
|
||||
pleaseGoBack: "Please go back to the application"
|
||||
callback: "Returning to the application"
|
||||
denied: "Access denied"
|
||||
pleaseLogin: "Please log in to authorize applications."
|
||||
_antennaSources:
|
||||
all: "All notes"
|
||||
homeTimeline: "Notes from followed users"
|
||||
@@ -1866,5 +1824,6 @@ _deck:
|
||||
tl: "Timeline"
|
||||
antenna: "Antennas"
|
||||
list: "List"
|
||||
channel: "Channel"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct notes"
|
||||
|
@@ -56,7 +56,7 @@ reply: "Responder"
|
||||
loadMore: "Ver más"
|
||||
showMore: "Ver más"
|
||||
showLess: "Cerrar"
|
||||
youGotNewFollower: "te ha seguido"
|
||||
youGotNewFollower: "ahora te sigue"
|
||||
receiveFollowRequest: "Recibiste una solicitud de seguimiento"
|
||||
followRequestAccepted: "La solicitud de seguimiento fue aceptada"
|
||||
mention: "Menciones"
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "¿Quiere dejar de bloquear esta cuenta?"
|
||||
suspendConfirm: "¿Quiere suspender esta cuenta?"
|
||||
unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
|
||||
selectList: "Seleccione una lista"
|
||||
selectChannel: "Seleccionar canal"
|
||||
selectAntenna: "Seleccionar antena"
|
||||
selectWidget: "Seleccionar widget"
|
||||
editWidgets: "Editar widgets"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "El historial se ha acabado"
|
||||
startMessaging: "Iniciar chat"
|
||||
nUsersRead: "Leído por {n} personas"
|
||||
agreeTo: "De acuerdo con {0}"
|
||||
agreeBelow: "Estoy de acuerdo con lo siguiente"
|
||||
basicNotesBeforeCreateAccount: "Notas básicas"
|
||||
tos: "Términos de uso"
|
||||
start: "Comenzar"
|
||||
home: "Inicio"
|
||||
@@ -464,7 +467,6 @@ youHaveNoGroups: "Sin grupos"
|
||||
joinOrCreateGroup: "Obtenga una invitación para unirse al grupos o puede crear su propio grupo."
|
||||
noHistory: "No hay datos en el historial"
|
||||
signinHistory: "Historial de ingresos"
|
||||
disableAnimatedMfm: "Deshabilitar MFM que tiene animaciones"
|
||||
doing: "Voy en camino"
|
||||
category: "Categoría"
|
||||
tags: "Etiqueta"
|
||||
@@ -509,7 +511,7 @@ objectStorageSetPublicRead: "Seleccionar \"public-read\" al subir "
|
||||
serverLogs: "Registros del servidor"
|
||||
deleteAll: "Eliminar todos"
|
||||
showFixedPostForm: "Mostrar el formulario de las entradas encima de la línea de tiempo"
|
||||
newNoteRecived: "Tienes una nota nuevo"
|
||||
newNoteRecived: "Tienes una nota nueva"
|
||||
sounds: "Sonidos"
|
||||
sound: "Sonidos"
|
||||
listen: "Escuchar"
|
||||
@@ -918,17 +920,328 @@ tools: "Utilidades"
|
||||
cannotLoad: "No se puede cargar."
|
||||
numberOfProfileView: "Número de vistas de perfil"
|
||||
like: "¡Muy bien!"
|
||||
unlike: "Quitar 'me gusta'"
|
||||
numberOfLikes: "Cantidad de 'Me gusta'"
|
||||
show: "Apariencia"
|
||||
neverShow: "No mostrar de nuevo"
|
||||
remindMeLater: "Recordar después"
|
||||
didYouLikeMisskey: "¿Te gusta Misskey?"
|
||||
pleaseDonate: "Misskey es software libre, y es usado por {host} . Por favor, ¡considera donar al proyecto principal para que podamos continuar!"
|
||||
roles: "Roles"
|
||||
role: "Roles"
|
||||
normalUser: "Usuario normal"
|
||||
undefined: "Indefinido"
|
||||
assign: "Asignar"
|
||||
unassign: "Quitar"
|
||||
color: "Color"
|
||||
manageCustomEmojis: "Administrar emojis personalizados"
|
||||
youCannotCreateAnymore: "Se alcanzó el límite de creación"
|
||||
cannotPerformTemporary: "Indisponible temporalmente"
|
||||
cannotPerformTemporaryDescription: "Esta acción no se puede realizar porque se excedió el límite de ejecución. Espera un poco y prueba de nuevo."
|
||||
preset: "Predefinido"
|
||||
selectFromPresets: "Escoger desde predefinidos"
|
||||
achievements: "Logros"
|
||||
gotInvalidResponseError: "Respuesta del servidor inválida"
|
||||
gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde"
|
||||
_achievements:
|
||||
earnedAt: "Desbloqueado el"
|
||||
_types:
|
||||
_notes1:
|
||||
title: "¡Hola Misskey!"
|
||||
description: "Publicaste tu primera nota"
|
||||
flavor: "¡Pasándola bien con Misskey!"
|
||||
_notes10:
|
||||
title: "Algunas notas"
|
||||
description: "10 notas publicadas"
|
||||
_notes100:
|
||||
title: "¡Muchas notas!"
|
||||
description: "100 notas publicadas"
|
||||
_notes500:
|
||||
title: "¡Cubierto de notas!"
|
||||
description: "500 notas publicadas"
|
||||
_notes1000:
|
||||
title: "¡Una montaña de notas!"
|
||||
description: "1000 notas publicadas"
|
||||
_notes5000:
|
||||
title: "¡Exceso de notas!"
|
||||
description: "5000 notas publicadas"
|
||||
_notes10000:
|
||||
title: "¡Súpernota!"
|
||||
description: "10000 notas publicadas"
|
||||
_notes20000:
|
||||
title: "Necesito... Más... ¡Notas!"
|
||||
description: "20000 notas publicadas"
|
||||
_notes30000:
|
||||
title: "¡Notas! ¡Notas! ¡Notas!"
|
||||
description: "30000 notas publicadas"
|
||||
_notes40000:
|
||||
title: "Fábrica de notas"
|
||||
description: "40000 notas publicadas"
|
||||
_notes50000:
|
||||
title: "¡Un planeta de notas!"
|
||||
description: "50000 notas publicadas"
|
||||
_notes60000:
|
||||
title: "¡Un cuásar de notas!"
|
||||
description: "60000 notas publicadas"
|
||||
_notes70000:
|
||||
title: "¡Un hoyo negro de notas!"
|
||||
description: "70000 notas publicadas"
|
||||
_notes80000:
|
||||
title: "¡Una galaxia de notas!"
|
||||
description: "80000 notas publicadas"
|
||||
_notes90000:
|
||||
title: "¡Todo un universo de notas!"
|
||||
description: "90000 notas publicadas"
|
||||
_notes100000:
|
||||
title: "ALL YOUR NOTE ARE BELONG TO US"
|
||||
description: "100000 notas publicadas"
|
||||
flavor: "¿Tienes tanto para publicar?"
|
||||
_login3:
|
||||
title: "Principiante I"
|
||||
description: "Días desde el inicio de sesión: 3"
|
||||
flavor: "Desde hoy, soy Misskero"
|
||||
_login7:
|
||||
title: "Principiante II"
|
||||
description: "Días desde el inicio de sesión: 7"
|
||||
flavor: "¿Ya te acostumbraste?"
|
||||
_login15:
|
||||
title: "Principiante III"
|
||||
description: "Días desde el inicio de sesión: 15"
|
||||
_login30:
|
||||
title: "Misskero I"
|
||||
description: "Días desde el inicio de sesión: 30"
|
||||
_login60:
|
||||
title: "Misskero II"
|
||||
description: "Días desde el inicio de sesión: 60"
|
||||
_login100:
|
||||
title: "Misskero III"
|
||||
description: "Días desde el inicio de sesión: 100"
|
||||
flavor: "Para este usuario, Misskaína"
|
||||
_login200:
|
||||
title: "Regular I"
|
||||
description: "Días desde el inicio de sesión: 200"
|
||||
_login300:
|
||||
title: "Regular II"
|
||||
description: "Días desde el inicio de sesión: 300"
|
||||
_login400:
|
||||
title: "Regular III"
|
||||
description: "Días desde el inicio de sesión: 400"
|
||||
_login500:
|
||||
title: "Veterano I"
|
||||
description: "Días desde el inicio de sesión: 500"
|
||||
flavor: "Chicos, me encantan las libretas..."
|
||||
_login600:
|
||||
title: "Veterano II"
|
||||
description: "Días desde el inicio de sesión: 600"
|
||||
_login700:
|
||||
title: "Veterano III"
|
||||
description: "Días desde el inicio de sesión: 700"
|
||||
_login800:
|
||||
title: "Maestro I"
|
||||
description: "Días desde el inicio de sesión: 800"
|
||||
_login900:
|
||||
title: "Maestro II"
|
||||
description: "Días desde el inicio de sesión: 900"
|
||||
_login1000:
|
||||
title: "Maestro III"
|
||||
description: "Días desde el inicio de sesión: 1000"
|
||||
flavor: "¡Gracias por usar Misskey!"
|
||||
_noteClipped1:
|
||||
title: "No puedo evitar clipearte..."
|
||||
description: "Hacer un clip por primera vez"
|
||||
_noteFavorited1:
|
||||
title: "Contemplando las estrellas"
|
||||
description: "Poner una nota como favorito por primera vez"
|
||||
_myNoteFavorited1:
|
||||
title: "¡Quiero una estrella!"
|
||||
description: "Tu nota ha sido marcada como favorito por primera vez"
|
||||
_profileFilled:
|
||||
title: "¡Listo!"
|
||||
description: "Perfil completado"
|
||||
_markedAsCat:
|
||||
title: "Soy un gato"
|
||||
description: "Configurar la cuenta como cuenta de un gato"
|
||||
flavor: "Aún no tengo nombre"
|
||||
_following1:
|
||||
title: "Primera vez siguiendo a alguien"
|
||||
description: "Seguir a un usuario"
|
||||
_following10:
|
||||
title: "Ahí la llevas, ahí la llevas..."
|
||||
description: "10 usuarios seguidos"
|
||||
_following50:
|
||||
title: "¡Un puñado de amigos!"
|
||||
description: "50 cuentas seguidas"
|
||||
_following100:
|
||||
title: "100 amigos"
|
||||
description: "100 cuentas seguidas"
|
||||
_following300:
|
||||
title: "¡Sobrecarga de amigos!"
|
||||
description: "300 cuentas seguidas"
|
||||
_followers1:
|
||||
title: "¡Tu primer seguidor!"
|
||||
description: "1 seguidor ganado"
|
||||
_followers10:
|
||||
title: "¡Sígueme!"
|
||||
description: "10 seguidores ganados"
|
||||
_followers50:
|
||||
title: "Viniendo en manada"
|
||||
description: "50 seguidores ganados"
|
||||
_followers100:
|
||||
title: "Popular"
|
||||
description: "100 cuentas seguidas"
|
||||
_followers300:
|
||||
title: "Por favor, hagan una fila"
|
||||
description: "300 seguidores ganados"
|
||||
_followers500:
|
||||
title: "¡Toda una torre de radio!"
|
||||
description: "500 seguidores ganados"
|
||||
_followers1000:
|
||||
title: "\"Influyente\""
|
||||
description: "1000 seguidores gandos"
|
||||
_collectAchievements30:
|
||||
title: "Coleccionista"
|
||||
description: "30 logros ganados"
|
||||
_viewAchievements3min:
|
||||
title: "¡Te gustan los logros!"
|
||||
description: "Mirando tus logros por 3 minutos"
|
||||
_iLoveMisskey:
|
||||
title: "¡AMO Misskey!"
|
||||
description: "\"I ❤ #Misskey\" Publicado"
|
||||
flavor: "El equipo de desarrollo de Misskey, en verdad, ¡aprecia tu apoyo!"
|
||||
_foundTreasure:
|
||||
title: "Búsqueda del tesoro"
|
||||
description: "Encontraste un tesoro"
|
||||
_client30min:
|
||||
title: "Un descansito"
|
||||
description: "30 minutos dedicados a Misskey"
|
||||
_noteDeletedWithin1min:
|
||||
title: "Ah... Mejor no..."
|
||||
description: "Borrar una nota antes que de pase 1 minuto"
|
||||
_postedAtLateNight:
|
||||
title: "Nocturno"
|
||||
description: "Una nota publicada por la noche"
|
||||
flavor: "¡Ya casi es hora de dormir!"
|
||||
_postedAt0min0sec:
|
||||
title: "Reloj parlante"
|
||||
description: "Publicar una nota a las 00:00 de la madrugada"
|
||||
flavor: "Tic, tic, tic ¡TUUUUUN!"
|
||||
_selfQuote:
|
||||
title: "Autoreferencia"
|
||||
description: "Citar tu propia nota"
|
||||
_htl20npm:
|
||||
title: "Línea de tiempo fluyendo"
|
||||
description: "La velocidad de tu línea de tiempo excede las 20 npm (notas por minuto)"
|
||||
_viewInstanceChart:
|
||||
title: "Analista"
|
||||
description: "Gráficas de la instancia mostradas"
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "¡Hola mundo!"
|
||||
description: "Escribir \"hello world\" en el compositor"
|
||||
_open3windows:
|
||||
title: "Multiventana"
|
||||
description: "Tener más de 3 ventanas al mismo tiempo"
|
||||
_driveFolderCircularReference:
|
||||
title: "Referencia circular"
|
||||
description: "Intento de crear carpetas recursivamente"
|
||||
_reactWithoutRead:
|
||||
title: "¡Sí lo leíste bien?"
|
||||
description: "Reaccionar a los 3 segundos de publicación de una nota con más de 100 caracteres"
|
||||
_clickedClickHere:
|
||||
title: "Pícale aquí"
|
||||
description: "Le picó ahí"
|
||||
_justPlainLucky:
|
||||
title: "Pura suerte"
|
||||
description: "Obtenido con una probabilidad del 0.01% cada 10 segundos"
|
||||
_setNameToSyuilo:
|
||||
title: "Complejo de superioridad"
|
||||
description: "Configurar el nombre como 'Syuilo'"
|
||||
_passedSinceAccountCreated1:
|
||||
title: "Primer aniversario"
|
||||
description: "Pasó un año desde la creación de la cuenta"
|
||||
_passedSinceAccountCreated2:
|
||||
title: "Segundo aniversario"
|
||||
description: "Pasaron dos años desde la creación de la cuenta"
|
||||
_passedSinceAccountCreated3:
|
||||
title: "Tercer aniversario"
|
||||
description: "Pasaron tres años desde la creación de la cuenta"
|
||||
_loggedInOnBirthday:
|
||||
title: "¡Feliz cumpleaños!"
|
||||
description: "En linea el día de tu cumpleaños"
|
||||
_loggedInOnNewYearsDay:
|
||||
title: "¡Feliz Año Nuevo!"
|
||||
description: "En linea en año nuevo"
|
||||
flavor: "¡Gracias por tu apoyo a la instancia durante todo este año!"
|
||||
_cookieClicked:
|
||||
title: "Un juego para picarle a una galleta"
|
||||
description: "Picaste una galleta"
|
||||
flavor: "¿Está mal este juego?"
|
||||
_brainDiver:
|
||||
title: "Brain Diver"
|
||||
description: "Publicaste un vínculo a \"Brain Diver\""
|
||||
flavor: "Misskey-Misskey La-Tu-Ma"
|
||||
_role:
|
||||
new: "Crear rol"
|
||||
edit: "Editar rol"
|
||||
name: "Nombre del rol"
|
||||
description: "Descripción del rol"
|
||||
permission: "Permisos del rol"
|
||||
descriptionOfPermission: "<b>Moderador</b> Te permite ejecutar acciones básicas de moderación.\n<b>Administradores</b> puede cambiar todas las configuraciones de la instancia."
|
||||
assignTarget: "Asignar objetivo"
|
||||
descriptionOfAssignTarget: "<b>Manual</b> Para cambiar manualmente lo que se incluye en este rol.\n<b>Condicional</b> configura una condición, y los usuarios que cumplan la condición serán incluídos automáticamente."
|
||||
manual: "manual"
|
||||
conditional: "condicional"
|
||||
condition: "condición"
|
||||
isConditionalRole: "Esto es un rol condicional"
|
||||
isPublic: "Publicar rol"
|
||||
descriptionOfIsPublic: "Cualquiera puede ver los usuarios asignados a este rol. También, el perfil del usuario mostrará este rol."
|
||||
options: "Opción"
|
||||
policies: "Política"
|
||||
baseRole: "Rol base"
|
||||
useBaseValue: "Usar los valores del rol base"
|
||||
chooseRoleToAssign: "Selecciona el rol para asignar"
|
||||
iconUrl: "URL del ícono"
|
||||
asBadge: "Mostrar como emblema"
|
||||
descriptionOfAsBadge: "Este ícono de rol se mostrará a lado del nombre de usuario cuando este rol se encuentre activo."
|
||||
canEditMembersByModerator: "Permitir a los moderadores editar los miembros"
|
||||
descriptionOfCanEditMembersByModerator: "Si se activa, los moderadores, al igual que los administradores, serán capaces de asignar/quitar usuarios a éste rol. Si se desactiva, sólo los administradores podrán hacerlo."
|
||||
priority: "Prioridad"
|
||||
_priority:
|
||||
low: "Baja"
|
||||
middle: "Mediano"
|
||||
high: "Alta"
|
||||
_options:
|
||||
gtlAvailable: "Explorar la línea de tiempo global"
|
||||
ltlAvailable: "Explorar la línea de tiempo local"
|
||||
canPublicNote: "Permitir la publicación"
|
||||
canInvite: "Puede crear códigos de invitación"
|
||||
canManageCustomEmojis: "Administrar emojis personalizados"
|
||||
driveCapacity: "Capacidad de almacenamiento"
|
||||
pinMax: "Máximo de notas fijadas"
|
||||
antennaMax: "Máximo de antenas"
|
||||
wordMuteMax: "Máximo de caracteres en palabras silenciadas"
|
||||
webhookMax: "Máximo de Webhooks"
|
||||
clipMax: "Máximo de clips"
|
||||
noteEachClipsMax: "Máximo de notas con clip"
|
||||
userListMax: "Máximo de listas de usuarios"
|
||||
userEachUserListsMax: "Máximo de usuarios en una lista"
|
||||
rateLimitFactor: "Limitador"
|
||||
descriptionOfRateLimitFactor: "Límites más bajos son menos restrictivos, más altos menos restrictivos"
|
||||
canHideAds: "Puede ocultar anuncios"
|
||||
_condition:
|
||||
isLocal: "Usuario local"
|
||||
isRemote: "Usuario remoto"
|
||||
createdLessThan: "Menos de X han pasado desde la creación de la cuenta"
|
||||
createdMoreThan: "Más de X han pasado desde la creación de la cuenta"
|
||||
followersLessThanOrEq: "Tiene X o menos seguidores"
|
||||
followersMoreThanOrEq: "Tiene X o más seguidores"
|
||||
followingLessThanOrEq: "Sigue X o menos cuentas"
|
||||
followingMoreThanOrEq: "Sigue X o más cuentas"
|
||||
and: "Condicional AND"
|
||||
or: "Condicional OR"
|
||||
not: "Condicional NOT"
|
||||
_sensitiveMediaDetection:
|
||||
description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
|
||||
sensitivity: "Sensibilidad de detección"
|
||||
description: "Reduce el esfuerzo de la moderación en el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
|
||||
sensitivity: "Sensibilidad de la detección"
|
||||
sensitivityDescription: "Reducir la sensibilidad puede acarrear a varios falsos positivos, mientras que incrementarla puede reducir las detecciones (falsos negativos)."
|
||||
setSensitiveFlagAutomatically: "Marcar como NSFW"
|
||||
setSensitiveFlagAutomaticallyDescription: "Los resultados de la detección interna pueden ser retenidos incluso si la opción está desactivada."
|
||||
@@ -1014,72 +1327,6 @@ _nsfw:
|
||||
respect: "Ocultar medios NSFW"
|
||||
ignore: "No esconder medios NSFW "
|
||||
force: "Ocultar todos los medios"
|
||||
_mfm:
|
||||
cheatSheet: "Hoja de referencia de MFM"
|
||||
intro: "MFM es un lenguaje de marcado dedicado que se puede usar en varios lugares dentro de Misskey. Aquí puede ver una lista de sintaxis disponibles en MFM."
|
||||
dummy: "Misskey expande el mundo de la Fediverso"
|
||||
mention: "Menciones"
|
||||
mentionDescription: "El signo @ seguido de un nombre de usuario se puede utilizar para notificar a un usuario en particular."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Puede especificar un hashtag con un numeral y el texto."
|
||||
url: "URL"
|
||||
urlDescription: "Se pueden mostrar las URL"
|
||||
link: "Vínculo"
|
||||
linkDescription: "Se pueden asociar partes de texto a la URL"
|
||||
bold: "Negrita"
|
||||
boldDescription: "Muestra el texto con las letras más gruesas"
|
||||
small: "Pequeño"
|
||||
smallDescription: "Muestra el texto más pequeño y delgado"
|
||||
center: "Centrar"
|
||||
centerDescription: "Muestra el texto centrado"
|
||||
inlineCode: "Código (insertado)"
|
||||
inlineCodeDescription: "Muestra el código de un programa resaltando su sintaxis"
|
||||
blockCode: "Código (bloque)"
|
||||
blockCodeDescription: "Código de resaltado de sintaxis, como programas de varias líneas con bloques."
|
||||
inlineMath: "Fórmula (insertado)"
|
||||
inlineMathDescription: "Muestra fórmulas (KaTeX) insertadas"
|
||||
blockMath: "Fórmula (bloque)"
|
||||
blockMathDescription: "Muestra fórmulas (KaTeX) de varias líneas en un bloque"
|
||||
quote: "Citar"
|
||||
quoteDescription: "Muestra el contenido como una cita"
|
||||
emoji: "Emojis personalizados"
|
||||
emojiDescription: "Muestra los emojis personalizados encerrados entre dos puntos."
|
||||
search: "Buscar"
|
||||
searchDescription: "Muestra una caja de búsqueda con texto pre-escrito"
|
||||
flip: "Echar de un capirotazo"
|
||||
flipDescription: "Voltea el contenido hacia arriba / abajo o hacia la izquierda / derecha."
|
||||
jelly: "Animación (gelatina)"
|
||||
jellyDescription: "Aplica un efecto de animación tipo gelatina"
|
||||
tada: "Animación (tadá)"
|
||||
tadaDescription: "Aplica un efecto de animación al estilo \"Tadá\""
|
||||
jump: "Animación (saltar)"
|
||||
jumpDescription: "Aplica un efecto de animación tipo salto"
|
||||
bounce: "Animación (rebotar)"
|
||||
bounceDescription: "Aplica un efecto de animación tipo rebote"
|
||||
shake: "Animación (temblor)"
|
||||
shakeDescription: "Aplica un efecto de animación tipo temblor"
|
||||
twitch: "Animación (sacudida)"
|
||||
twitchDescription: "Aplica un efecto de animación tipo sacudida"
|
||||
spin: "Animación (giro)"
|
||||
spinDescription: "Aplica un efecto de animación tipo rotación"
|
||||
x2: "Grande"
|
||||
x2Description: "Muestra el contenido más grande"
|
||||
x3: "Muy grande"
|
||||
x3Description: "Muestra el contenido mucho más grande"
|
||||
x4: "Totalmente grande"
|
||||
x4Description: "Muestra el contenido totalmente grande"
|
||||
blur: "Desenfoque"
|
||||
blurDescription: "Para desenfocar el contenido. Se muestra claramente al colocar el puntero encima."
|
||||
font: "Fuente"
|
||||
fontDescription: "Elegir la fuente del contenido"
|
||||
rainbow: "Arcoíris"
|
||||
rainbowDescription: "Muestra el contenido con los colores del arcoíris"
|
||||
sparkle: "Parpadeante"
|
||||
sparkleDescription: "Aplica un efecto de partículas parpadeantes"
|
||||
rotate: "Rotar"
|
||||
rotateDescription: "Rota el contenido a un ángulo especificado."
|
||||
plain: "Plano"
|
||||
plainDescription: "Desactiva los efectos de todo el contenido MFM con este efecto MFM."
|
||||
_instanceTicker:
|
||||
none: "No mostrar"
|
||||
remote: "Mostrar a usuarios remotos"
|
||||
@@ -1284,12 +1531,15 @@ _permissions:
|
||||
"read:gallery-likes": "Ver favoritos de la galería"
|
||||
"write:gallery-likes": "Editar favoritos de la galería"
|
||||
_auth:
|
||||
shareAccessTitle: "Permisos de la aplicación"
|
||||
shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?"
|
||||
shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder a su cuenta?"
|
||||
permission: "{name} solicita los siguientes permisos"
|
||||
permissionAsk: "Esta aplicación requiere los siguientes permisos"
|
||||
pleaseGoBack: "Por favor, vuelve a la aplicación"
|
||||
callback: "Volviendo a la aplicación"
|
||||
denied: "Acceso denegado"
|
||||
pleaseLogin: "Se requiere un inicio de sesión para darle permisos a la aplicación"
|
||||
_antennaSources:
|
||||
all: "Todas las notas"
|
||||
homeTimeline: "Notas de los usuarios que sigues"
|
||||
@@ -1328,10 +1578,12 @@ _widgets:
|
||||
jobQueue: "Cola de trabajos"
|
||||
serverMetric: "Estadísticas del servidor"
|
||||
aiscript: "Consola de AiScript"
|
||||
aiscriptApp: "Aplicación AiScript"
|
||||
aichan: "indigo"
|
||||
userList: "Lista de usuarios"
|
||||
_userList:
|
||||
chooseList: "Seleccione una lista"
|
||||
clicker: "Cliqueador"
|
||||
_cw:
|
||||
hide: "Ocultar"
|
||||
show: "Ver más"
|
||||
@@ -1434,7 +1686,16 @@ _timelines:
|
||||
social: "Social"
|
||||
global: "Global"
|
||||
_play:
|
||||
new: "Crear guión"
|
||||
edit: "Editar guión"
|
||||
created: "Guión creado"
|
||||
updated: "Guión editado"
|
||||
deleted: "Guión eliminado"
|
||||
pageSetting: "Configuración de guión"
|
||||
editThisPage: "Editar este guión"
|
||||
viewSource: "Ver la fuente"
|
||||
my: "Mis guiones"
|
||||
liked: "Guiones que te gustaron"
|
||||
featured: "Popular"
|
||||
title: "Título"
|
||||
script: "Script"
|
||||
@@ -1507,6 +1768,7 @@ _notification:
|
||||
pollEnded: "Estan disponibles los resultados de la encuesta"
|
||||
unreadAntennaNote: "Antena {name}"
|
||||
emptyPushNotificationMessage: "Se han actualizado las notificaciones push"
|
||||
achievementEarned: "Logro desbloqueado"
|
||||
_types:
|
||||
all: "Todo"
|
||||
follow: "Siguiendo"
|
||||
@@ -1548,5 +1810,6 @@ _deck:
|
||||
tl: "Linea de tiempo"
|
||||
antenna: "Antenas"
|
||||
list: "Listas"
|
||||
channel: "Canal"
|
||||
mentions: "Menciones"
|
||||
direct: "Mensaje directo"
|
||||
|
@@ -464,7 +464,6 @@ youHaveNoGroups: "Vous n’avez aucun groupe"
|
||||
joinOrCreateGroup: "Vous pouvez être invité·e à rejoindre des groupes existants ou créer votre propre nouveau groupe."
|
||||
noHistory: "Pas d'historique"
|
||||
signinHistory: "Historique de connexion"
|
||||
disableAnimatedMfm: "Désactiver MFM ayant des animations"
|
||||
doing: "En cours..."
|
||||
category: "Catégorie"
|
||||
tags: "Étiquettes"
|
||||
@@ -1011,72 +1010,6 @@ _nsfw:
|
||||
respect: "Cacher les médias marqués comme contenu sensible"
|
||||
ignore: "Afficher les médias sensibles"
|
||||
force: "Cacher tous les médias"
|
||||
_mfm:
|
||||
cheatSheet: "Antisèche MFM"
|
||||
intro: "MFM est un langage Markdown spécifique utilisable ici et là dans Misskey. Vous pouvez vérifier ici les structures utilisables avec MFM."
|
||||
dummy: "La Fédiverse s'agrandit avec Misskey"
|
||||
mention: "Mentionner"
|
||||
mentionDescription: "Vous pouvez afficher un utilisateur spécifique en indiquant une arobase suivie d'un nom d'utilisateur"
|
||||
hashtag: "Hashtags"
|
||||
hashtagDescription: "Vous pouvez afficher un mot-dièse en utilisant un croisillon et du texte"
|
||||
url: "URL"
|
||||
urlDescription: "L'adresse web peut être affichée."
|
||||
link: "Lien"
|
||||
linkDescription: "Une partie précise d'une phrase peut être liée à l'adresse web."
|
||||
bold: "Gras"
|
||||
boldDescription: "Il est possible de mettre le texte en exergue en le mettant en gras."
|
||||
small: "Diminuer l'emphase"
|
||||
smallDescription: "Le contenu peut être affiché en petit et fin."
|
||||
center: "Centrer"
|
||||
centerDescription: "Le contenu peut être centré"
|
||||
inlineCode: "Code (inline)"
|
||||
inlineCodeDescription: "Coloration syntaxique des lignes de code."
|
||||
blockCode: "Bloc de code"
|
||||
blockCodeDescription: "Coloration syntaxique des lignes de code pour les blocs multi-lignes."
|
||||
inlineMath: "Formule mathématique (inline)"
|
||||
inlineMathDescription: "Afficher les formules mathématiques (KaTeX)."
|
||||
blockMath: "Formule mathématique (bloc)"
|
||||
blockMathDescription: "Afficher les formules mathématiques (KaTeX) multi-lignes dans un bloc."
|
||||
quote: "Citer"
|
||||
quoteDescription: "Affiche le contenu sous forme de citation."
|
||||
emoji: "Émojis personnalisés"
|
||||
emojiDescription: "Entourez le nom de l'émoji personnalisé de deux points pour l'afficher."
|
||||
search: "Rechercher"
|
||||
searchDescription: "Affiche une boîte de recherche avec du texte pré-saisi."
|
||||
flip: "Inverser"
|
||||
flipDescription: "Rotation verticale ou horizontale du contenu"
|
||||
jelly: "Animation (Gelée)"
|
||||
jellyDescription: "Donne une animation d'étirement."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Donne une animation qui donne une impression de \"Tada !\""
|
||||
jump: "Animation (Saut)"
|
||||
jumpDescription: "Donne une animation qui saute."
|
||||
bounce: "Animation (Rebond)"
|
||||
bounceDescription: "Donne une animation de rebondissement."
|
||||
shake: "Animation (Secousse)"
|
||||
shakeDescription: "Donne une animation tremblante."
|
||||
twitch: "Animation (Tremblement)"
|
||||
twitchDescription: "Donne une animation de tremblement intense."
|
||||
spin: "Animation (Rotation)"
|
||||
spinDescription: "Donne une animation de rotation."
|
||||
x2: "Grand"
|
||||
x2Description: "Afficher le contenu en grand."
|
||||
x3: "Très grand"
|
||||
x3Description: "Afficher le contenu en très grand."
|
||||
x4: "Plus grand"
|
||||
x4Description: "Afficher le contenu en plus grand."
|
||||
blur: "Flou"
|
||||
blurDescription: "Le contenu peut être flouté ; il sera visible en le survolant avec le curseur."
|
||||
font: "Police de caractères"
|
||||
fontDescription: "Il est possible de choisir la police."
|
||||
rainbow: "Arc-en-ciel"
|
||||
rainbowDescription: "Permet d'afficher le contenu en couleurs arc-en-ciel."
|
||||
sparkle: "Paillettes"
|
||||
sparkleDescription: "Ajoute un effet scintillant au contenu."
|
||||
rotate: "Pivoter"
|
||||
rotateDescription: "Faire pivoter à un angle spécifié."
|
||||
plain: "Vu texte non formaté"
|
||||
plainDescription: "Désactive toute la syntaxe interne."
|
||||
_instanceTicker:
|
||||
none: "Cacher "
|
||||
remote: "Montrer pour les utilisateur·ice·s distant·e·s"
|
||||
@@ -1541,5 +1474,6 @@ _deck:
|
||||
tl: "Fil"
|
||||
antenna: "Antennes"
|
||||
list: "Listes"
|
||||
channel: "Canaux"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct"
|
||||
|
@@ -13,6 +13,7 @@ fetchingAsApObject: "Mengambil data dari Fediverse..."
|
||||
ok: "OK"
|
||||
gotIt: "Saya mengerti"
|
||||
cancel: "Batalkan"
|
||||
noThankYou: "Tidak sekarang."
|
||||
enterUsername: "Masukkan nama pengguna"
|
||||
renotedBy: "direnote oleh {user}"
|
||||
noNotes: "Tidak ada catatan"
|
||||
@@ -206,6 +207,7 @@ done: "Selesai"
|
||||
processing: "Memproses"
|
||||
preview: "Pratinjau"
|
||||
default: "Bawaan"
|
||||
defaultValueIs: "Bawaan: {value}"
|
||||
noCustomEmojis: "Tidak ada emoji kustom"
|
||||
noJobs: "Tidak ada kerja"
|
||||
federating: "memfederasi"
|
||||
@@ -349,6 +351,8 @@ recaptcha: "reCAPTCHA"
|
||||
enableRecaptcha: "Nyalakan reCAPTCHA"
|
||||
recaptchaSiteKey: "Site key"
|
||||
recaptchaSecretKey: "Secret Key"
|
||||
turnstile: "Turnstile"
|
||||
enableTurnstile: "Nyalakan Turnstile"
|
||||
turnstileSiteKey: "Site key"
|
||||
turnstileSecretKey: "Secret Key"
|
||||
avoidMultiCaptchaConfirm: "Menggunakan banyak Captcha dapat menyebabkan gangguan. Apakah kamu ingin untuk menonaktifkan Captcha yang lain? Kamu dapat membiarkan fitur ini tetap aktif dengan menekan tombol batal."
|
||||
@@ -454,12 +458,12 @@ uiLanguage: "Bahasa antarmuka pengguna"
|
||||
groupInvited: "Telah diundang ke grup"
|
||||
aboutX: "Tentang {x}"
|
||||
emojiStyle: "Gaya emoji"
|
||||
native: "Native"
|
||||
disableDrawer: "Jangan gunakan menu bergaya laci"
|
||||
youHaveNoGroups: "Kamu tidak memiliki grup"
|
||||
joinOrCreateGroup: "Bergabunglah dengan grup atau kamu dapat membuat grupmu sendiri."
|
||||
noHistory: "Tidak ada riwayat"
|
||||
signinHistory: "Riwayat masuk"
|
||||
disableAnimatedMfm: "Nonaktifkan MFM dengan animasi"
|
||||
doing: "Sedang berkerja..."
|
||||
category: "Kategori"
|
||||
tags: "Tandai"
|
||||
@@ -857,10 +861,21 @@ rateLimitExceeded: "Batas sudah terlampaui"
|
||||
cropImage: "potong gambar"
|
||||
cropImageAsk: "Ingin memotong gambar?"
|
||||
file: "Berkas"
|
||||
recentNHours: "{n} jam terakhir"
|
||||
recentNDays: "{n} hari terakhir"
|
||||
noEmailServerWarning: "Mail Server tidak disetel."
|
||||
thereIsUnresolvedAbuseReportWarning: "Ada laporan yang belum diselesaikan."
|
||||
recommended: "Disarankan"
|
||||
check: "Cek"
|
||||
driveCapOverrideLabel: "Ubah kapasitas drive untuk user ini"
|
||||
driveCapOverrideCaption: "Setel ulang kapasitas ke bawaan dengan memasukkan nilai 0 atau lebih rendah."
|
||||
requireAdminForView: "Kamu harus login dengan akun administrator untuk melihat ini."
|
||||
isSystemAccount: "Akun yang dibuat dan otomatis dioperasikan oleh sistem."
|
||||
typeToConfirm: "Mohon masukkan {x} untuk mengonfirmasi"
|
||||
deleteAccount: "Hapus Akun"
|
||||
document: "Dokumen"
|
||||
numberOfPageCache: "Jumlah halaman ditembolokkan"
|
||||
numberOfPageCacheDescription: "Menaikkan jumlah ini akan meningkatkan kenyamanan untuk pengguna, namun dapat menyebabkan lonjakan beban pada peladen dan juga memori yang digunakan."
|
||||
logoutConfirm: "Anda yakin ingin keluar?"
|
||||
lastActiveDate: "Terakhir digunakan"
|
||||
statusbar: "Bilah status"
|
||||
@@ -870,20 +885,189 @@ colored: "Diwarnai"
|
||||
refreshInterval: "Jeda pembaharuan"
|
||||
label: "Label"
|
||||
type: "Tipe"
|
||||
speed: "Kecepatan"
|
||||
slow: "Lambat"
|
||||
fast: "Cepat"
|
||||
sensitiveMediaDetection: "Deteksi media NSFW"
|
||||
localOnly: "Hanya lokal"
|
||||
remoteOnly: "Hanya remot"
|
||||
failedToUpload: "Gagal mengunggah"
|
||||
cannotUploadBecauseInappropriate: "Berkas ini tidak dapat diunggah karena sebagian dari berkas terdeteksi berpotensi NSFW."
|
||||
cannotUploadBecauseNoFreeSpace: "Gagal mengunggah karena kekurangan kapasitas Drive."
|
||||
beta: "Beta"
|
||||
enableAutoSensitive: "Penandaan NSFW otomatis"
|
||||
enableAutoSensitiveDescription: "Mendeteksi otomatis dan menandai media NSFW menggunakan Machine Learning jika memungkinkan. Meskipun opsi ini dimatikan, ada kemungkinan dinyalakan secara menyeluruh pada instansi peladen."
|
||||
activeEmailValidationDescription: "Membolehkan validasi alamat surel ketat dengan mengecek apakah alamat surel tersebut temporer dan bisa berkomunikasi dengan surel tersebut. Ketidak tidak dicentang, hanya format surel yang divalidasi."
|
||||
navbar: "Bilah navigasi"
|
||||
shuffle: "Acak"
|
||||
account: "Akun"
|
||||
move: "Pindah"
|
||||
pushNotification: "Pemberitahuan push"
|
||||
subscribePushNotification: "Nyalakan pemberitahuan push"
|
||||
unsubscribePushNotification: "Matikan pemberitahuan push"
|
||||
pushNotificationAlreadySubscribed: "Pemberitahuan push telah dinyalakan"
|
||||
pushNotificationNotSupported: "Browser atau instansi kamu tidak mendukung pemberitahuan push"
|
||||
sendPushNotificationReadMessage: "Hapus pemberitahuan push ketika pemberitahuan relevan atau pesan telah dibaca"
|
||||
sendPushNotificationReadMessageCaption: "Pemberitahuan berisi teks「{emptyPushNotificationMessage}」akan ditampilkan dalam waktu pendek. Ini mungkin dapat menambah pemakaian baterai pada perangkat kamu."
|
||||
windowMaximize: "Maksimalkan"
|
||||
windowRestore: "Kembalikan"
|
||||
caption: "Keterangan"
|
||||
loggedInAsBot: "Sedang login sebagai bot"
|
||||
tools: "Alat"
|
||||
cannotLoad: "Tidak dapat memuat"
|
||||
numberOfProfileView: "tayang profil"
|
||||
like: "Suka"
|
||||
unlike: "Tidak Suka"
|
||||
numberOfLikes: "Jumlah yang disukai"
|
||||
show: "Tampilkan"
|
||||
neverShow: "Jangan tampilkan lagi"
|
||||
remindMeLater: "Mungkin nanti"
|
||||
didYouLikeMisskey: "Apakah kamu mulai menyukai Misskey?"
|
||||
pleaseDonate: "{host} menggunakan perangkat lunak bebas yaitu Misskey. Kami sangat mengapresiasi sekali donasi dari kamu agar pengembangan Misskey tetap dapat berlanjut!"
|
||||
roles: "Peran"
|
||||
role: "Peran"
|
||||
color: "Warna"
|
||||
_achievements:
|
||||
_types:
|
||||
_login7:
|
||||
description: "Login selama 7 hari"
|
||||
flavor: "Sudah mulai terbiasa?"
|
||||
_login15:
|
||||
title: "Pemula III"
|
||||
description: "Login selama 15 hari"
|
||||
_login30:
|
||||
title: "Misskist I"
|
||||
description: "Login selama 30 hari"
|
||||
_login60:
|
||||
title: "Misskist II"
|
||||
description: "Login selama 60 hari"
|
||||
_login100:
|
||||
title: "Misskist III"
|
||||
description: "Login selama 100 hari"
|
||||
flavor: "Violent Misskist"
|
||||
_login200:
|
||||
title: "Reguler I"
|
||||
description: "Login selama 200 hari"
|
||||
_login300:
|
||||
title: "Reguler II"
|
||||
description: "Login selama 300 hari"
|
||||
_login400:
|
||||
title: "Reguler III"
|
||||
description: "Login selama 400 hari"
|
||||
_login500:
|
||||
title: "Veteran I"
|
||||
description: "Login selama 500 hari"
|
||||
flavor: "Kawanku, aku suka catatan."
|
||||
_login600:
|
||||
title: "Veteran II"
|
||||
description: "Login selama 600 hari"
|
||||
_login700:
|
||||
title: "Veteran III"
|
||||
description: "Login selama 700 hari"
|
||||
_login800:
|
||||
title: "Sepuh Catatan I"
|
||||
description: "Login selama 800 hari"
|
||||
_login900:
|
||||
title: "Sepuh Catatan II"
|
||||
description: "Login selama 900 hari"
|
||||
_login1000:
|
||||
title: "Sepuh Catatan III"
|
||||
description: "Login selama 1000 hari"
|
||||
flavor: "Terima kasih telah menggunakan Misskey!"
|
||||
_noteClipped1:
|
||||
title: "Harus... Ngeklip..."
|
||||
description: "Klip catatan pertamamu"
|
||||
_noteFavorited1:
|
||||
title: "Pengamat Bintang"
|
||||
description: "Favoritkan catatan pertamamu"
|
||||
_myNoteFavorited1:
|
||||
title: "Pencari Bintang"
|
||||
description: "Minta orang lain memfavoritkan salah satu catatanmu"
|
||||
_profileFilled:
|
||||
title: "Siap Sedia"
|
||||
description: "Atur profil kamu"
|
||||
_markedAsCat:
|
||||
title: "Aku Seekor Kucing"
|
||||
description: "Tandai akunmu sebagai kucing"
|
||||
flavor: "Aku beri kamu nama nanti"
|
||||
_following1:
|
||||
title: "Ikuti pengguna lain pertamamu"
|
||||
description: "Ikuti pengguna"
|
||||
_following10:
|
||||
title: "Terusin... terusin..."
|
||||
description: "Ikuti 10 pengguna lain"
|
||||
_following50:
|
||||
title: "Banyak teman"
|
||||
description: "Ikuti 50 pengguna lain"
|
||||
_following100:
|
||||
title: "100 Teman"
|
||||
description: "Ikuti 100 pengguna lain"
|
||||
_clickedClickHere:
|
||||
description: "Kamu telah mengeklik disini"
|
||||
_justPlainLucky:
|
||||
title: "Lagi Beruntung"
|
||||
description: "Mendapatkan kesempatan dengan kemungkinan 0.01% setiap 10 detik"
|
||||
_setNameToSyuilo:
|
||||
title: "God Complex"
|
||||
description: "Atur namamu jadi \"syuilo\""
|
||||
_passedSinceAccountCreated1:
|
||||
title: "Perayaan Satu Tahun"
|
||||
description: "Satu tahun telah lewat sejak akunmu dibuat"
|
||||
_passedSinceAccountCreated2:
|
||||
title: "Perayaan Dua Tahun"
|
||||
description: "Dua tahun telah lewat sejak akunmu dibuat"
|
||||
_passedSinceAccountCreated3:
|
||||
title: "Perayaan Tiga Tahun"
|
||||
description: "Tiga tahun telah lewat sejak akunmu dibuat"
|
||||
_loggedInOnBirthday:
|
||||
title: "Selamat Ulang Tahun"
|
||||
description: "Login di hari ulang tahunmu"
|
||||
_loggedInOnNewYearsDay:
|
||||
title: "Selamat Tahun Baru!"
|
||||
description: "Login di hari pertama tahun baru"
|
||||
_cookieClicked:
|
||||
title: "Permainan dimana kamu mengeklik kue"
|
||||
description: "Mengeklik kue"
|
||||
flavor: "Tunggu, apakah kamu sedang berada di website yang benar?"
|
||||
_brainDiver:
|
||||
title: "Brain Diver"
|
||||
description: "Posting tautan mengenai Brain Diver"
|
||||
flavor: "Misskey-Misskey La-Tu-Ma"
|
||||
_role:
|
||||
new: "Buat peran"
|
||||
edit: "Sunting peran"
|
||||
name: "Nama peran"
|
||||
description: "Deskripsi peran"
|
||||
permission: "Perijinan peran"
|
||||
descriptionOfPermission: "<b>Moderator</b> dapat melakukan operasi moderasi dasar.\n<b>Administrator</b> dapat mengubah seluruh pengaturan instansi."
|
||||
assignTarget: "Tipe tugas"
|
||||
descriptionOfAssignTarget: "<b>Manual</b> untuk mengganti secara manual siapa yang mendapatkan peran ini dan siapa yang tidak.\n<b>Kondisional</b> untuk pengguna secara otomatis dimasukkan atau dihapus dari peran berdasarkan kondisi yang ditentukan."
|
||||
manual: "Manual"
|
||||
conditional: "Kondisional"
|
||||
condition: "Kondisi"
|
||||
isConditionalRole: "Ini adalah peran kondisional"
|
||||
isPublic: "Publikkan Peran"
|
||||
descriptionOfIsPublic: "Siapapun dapat melihat daftar pengguna yang ditugaskan pada peran ini. Tambahan juga peran ini akan ditampilkan ke dalam profil pengguna tentang peran yang ditugaskan."
|
||||
options: "Opsi peran"
|
||||
policies: "Kebijakan"
|
||||
baseRole: "Templat peran"
|
||||
useBaseValue: "Gunakan nilai templat peran"
|
||||
chooseRoleToAssign: "Pilih peran yang ditugaskan"
|
||||
canEditMembersByModerator: "Perbolehkan moderator untuk menyunting daftar anggota untuk peran ini"
|
||||
descriptionOfCanEditMembersByModerator: "Ketika dinyalakan, moderator beserta administrator dapat menugaskan ataupun mencabut pengguna ke peran ini. Ketika dimatikan, hanya administrator saja yang dapat menugaskan pengguna ke peran ini."
|
||||
priority: "Prioritas"
|
||||
_priority:
|
||||
low: "Rendah"
|
||||
middle: "Sedang"
|
||||
high: "Tinggi"
|
||||
_options:
|
||||
gtlAvailable: "Dapat melihat linimasa global"
|
||||
ltlAvailable: "Dapat melihat linimasa lokal"
|
||||
canPublicNote: "Dapat mengirim catatan publik"
|
||||
canInvite: "Dapat membuat kode undangan instansi"
|
||||
canManageCustomEmojis: "Dapat mengelola Emoji kustom"
|
||||
driveCapacity: "Kapasitas Drive"
|
||||
pinMax: "Jumlah maksimal catatan yang disematkan"
|
||||
_emailUnavailable:
|
||||
used: "Alamat surel ini telah digunakan"
|
||||
format: "Format tidak valid."
|
||||
@@ -946,70 +1130,6 @@ _nsfw:
|
||||
respect: "Sembunyikan media NSFW"
|
||||
ignore: "Jangan sembunyikan media NSFW"
|
||||
force: "Sembunyikan semua media"
|
||||
_mfm:
|
||||
cheatSheet: "Contekan MFM"
|
||||
intro: "MFM adalah Misskey-exclusive Markup Language yang dapat digunakan di banyak tempat. Berikut kamu bisa melihat daftar dari syntax MFM yang ada."
|
||||
dummy: "Misskey membentangkan dunia Fediverse"
|
||||
mention: "Sebut"
|
||||
mentionDescription: "Kamu dapat menentukan pengguna tertentu dengan menggunakan simbol-At dan nama engguna mereka."
|
||||
hashtag: "Tagar"
|
||||
hashtagDescription: "Kamu dapat menentukan tagar dengan menggunakan angka dan teks."
|
||||
url: "URL"
|
||||
urlDescription: "URL dapat ditampilkan."
|
||||
link: "Tautan"
|
||||
linkDescription: "Bagian tertentu dari teks dapat ditampilka sebagai URL."
|
||||
bold: "Tebal"
|
||||
boldDescription: "Sorot tulisan dengan membuatnya tebal."
|
||||
small: "Kecil"
|
||||
smallDescription: "Tampilkan konten kecil dan tipis."
|
||||
center: "Tengah"
|
||||
centerDescription: "Tampilkan konten di tengah."
|
||||
inlineCode: "Kode (Dalam baris)"
|
||||
inlineCodeDescription: "Menampilkan sorotan sintaks dalam baris untuk kode(program-)."
|
||||
blockCode: "Kode (Blok)"
|
||||
blockCodeDescription: "Menampilkan sorotan sintaks untuk kode(program-) multi baris dalam sebuah blok."
|
||||
inlineMath: "Matematika (Dalam baris)"
|
||||
inlineMathDescription: "Menampilkan formula matematika (KaTeX) dalam baris."
|
||||
blockMath: "Matematika (Blok)"
|
||||
blockMathDescription: "Menampilkan formula matematika (KaTeX) multibaris dalam sebuah blok."
|
||||
quote: "Kutip"
|
||||
quoteDescription: "Menampilkan konten sebagai kutipan."
|
||||
emoji: "Emoji kustom"
|
||||
emojiDescription: "Emoji kustom dapat ditampilkan dengan mengurung nama emoji kustom menggunakan tanda titik dua."
|
||||
search: "Penelusuran"
|
||||
searchDescription: "Menampilkan kotak pencarian dengan teks yang sudah dimasukkan."
|
||||
flip: "Balik"
|
||||
flipDescription: "Balikkan konten secara horizontal atau vertikal."
|
||||
jelly: "Animasi (Jelly)"
|
||||
jellyDescription: "Menerapkan animasi seperti jelly"
|
||||
tada: "Animasi (Tada)"
|
||||
tadaDescription: "Menerapkan animasi seperti \"Kejutan!\"."
|
||||
jump: "Animasi (Loncat)"
|
||||
jumpDescription: "Menerapkan animasi melompat."
|
||||
bounce: "Animasi (Melambung)"
|
||||
bounceDescription: "Menerapkan animasi melambung."
|
||||
shake: "Animasi (Goyang)"
|
||||
shakeDescription: "Menerapkan animasi bergoyang."
|
||||
twitch: "Animasi (Cubit)"
|
||||
twitchDescription: "Terapkan animasi cubit yang kuat."
|
||||
spin: "Animasi (Putar)"
|
||||
spinDescription: "Terapkan animasi putar."
|
||||
x2: "Besar"
|
||||
x2Description: "Tampilkan konten menjadi besar."
|
||||
x3: "Lebih besar"
|
||||
x3Description: "Tampilkan konten menjadi lebih besar."
|
||||
x4: "Sangat besar"
|
||||
x4Description: "Tampilka konten menjadi sangat besar."
|
||||
blur: "Buram"
|
||||
blurDescription: "Konten dapat diburamkan dengan efek ini. Konten dapat ditampilkan dengan jelas dengan melayangkan kursor tetikus di atasnya."
|
||||
font: "Font"
|
||||
fontDescription: "Setel font yang ditampilkan untuk konten."
|
||||
rainbow: "Pelangi"
|
||||
rainbowDescription: "Membuat konten muncul dalam warna pelangi."
|
||||
sparkle: "Kelap-kelip"
|
||||
sparkleDescription: "Memberikan konten efek partikel kelap-kelip."
|
||||
rotate: "Putar"
|
||||
rotateDescription: "Putar konten sesuai sudut yang ditentukan."
|
||||
_instanceTicker:
|
||||
none: "Jangan tampilkan"
|
||||
remote: "Tampilkan untuk pengguna luar"
|
||||
@@ -1167,6 +1287,7 @@ _tutorial:
|
||||
step7_1: "Yay, Selamat! Kamu sudah menyelesaikan tutorial dasar Misskey."
|
||||
step7_2: "Jika kamu ingin mempelajari lebih lanjut tentang Misskey, cobalah berkunjung ke bagian {help}."
|
||||
step7_3: "Semoga berhasil dan bersenang-senanglah! 🚀"
|
||||
step8_3: "Kamu dapat mengganti pengaturan ini nanti."
|
||||
_2fa:
|
||||
alreadyRegistered: "Kamu telah mendaftarkan perangkat otentikasi dua faktor."
|
||||
registerDevice: "Daftarkan perangkat baru"
|
||||
@@ -1241,10 +1362,13 @@ _widgets:
|
||||
trends: "Tren"
|
||||
clock: "Jam"
|
||||
rss: "Pembaca RSS"
|
||||
rssTicker: "RSS-Ticker"
|
||||
activity: "Aktivitas"
|
||||
photos: "Foto"
|
||||
digitalClock: "Jam digital"
|
||||
unixClock: "Jam UNIX"
|
||||
federation: "Federasi"
|
||||
instanceCloud: "Instansi awan"
|
||||
postForm: "Buat catatan"
|
||||
slideshow: "Slideshow"
|
||||
button: "Tombol"
|
||||
@@ -1254,8 +1378,10 @@ _widgets:
|
||||
aiscript: "Konsol AiScript"
|
||||
aiscriptApp: "Aplikasi AiScript"
|
||||
aichan: "Ai"
|
||||
userList: "Daftar pengguna"
|
||||
_userList:
|
||||
chooseList: "Pilih daftar"
|
||||
clicker: "Pengeklik"
|
||||
_cw:
|
||||
hide: "Sembunyikan"
|
||||
show: "Lihat konten"
|
||||
@@ -1319,6 +1445,7 @@ _profile:
|
||||
changeBanner: "Ubah header"
|
||||
_exportOrImport:
|
||||
allNotes: "Semua catatan"
|
||||
favoritedNotes: "Catatan favorit"
|
||||
followingList: "Ikuti"
|
||||
muteList: "Bisukan"
|
||||
blockingList: "Blokir"
|
||||
@@ -1437,7 +1564,9 @@ _notification:
|
||||
yourFollowRequestAccepted: "Permintaan mengikuti kamu telah diterima"
|
||||
youWereInvitedToGroup: "Telah diundang ke grup"
|
||||
pollEnded: "Hasil Kuesioner telah keluar"
|
||||
unreadAntennaNote: "Antena {name}"
|
||||
emptyPushNotificationMessage: "Pembaruan notifikasi dorong"
|
||||
achievementEarned: "Pencapaian didapatkan"
|
||||
_types:
|
||||
all: "Semua"
|
||||
follow: "Ikuti"
|
||||
@@ -1459,6 +1588,7 @@ _deck:
|
||||
alwaysShowMainColumn: "Selalu tampilkan kolom utama"
|
||||
columnAlign: "Luruskan kolom"
|
||||
addColumn: "Tambahkan kolom"
|
||||
configureColumn: "Atur kolom"
|
||||
swapLeft: "Pindah ke kiri"
|
||||
swapRight: "Pindah ke kanan"
|
||||
swapUp: "Pindah ke atas"
|
||||
@@ -1466,6 +1596,11 @@ _deck:
|
||||
stackLeft: "Tumpukkan di kolom kiri"
|
||||
popRight: "Keluarkan di kanan"
|
||||
profile: "Profil"
|
||||
newProfile: "Profil baru"
|
||||
deleteProfile: "Hapus profil"
|
||||
introduction: "Buat antarmuka sempurna untukmu dengan menata kolom secara bebas!"
|
||||
introduction2: "Klik \"+\" pada kanan layar untuk menambahkan kolom baru kapanpun yang kamu mau."
|
||||
widgetsIntroduction: "Mohon pilih \"Sunting gawit\" pada menu kolom dan tambahkan gawit."
|
||||
_columns:
|
||||
main: "Utama"
|
||||
widgets: "Widget"
|
||||
@@ -1473,5 +1608,6 @@ _deck:
|
||||
tl: "Linimasa"
|
||||
antenna: "Antena"
|
||||
list: "Daftar"
|
||||
channel: "Kanal"
|
||||
mentions: "Sebutan"
|
||||
direct: "Langsung"
|
||||
|
@@ -34,6 +34,7 @@ const languages = [
|
||||
'pt-PT',
|
||||
'ru-RU',
|
||||
'sk-SK',
|
||||
'th-TH',
|
||||
'ug-CN',
|
||||
'uk-UA',
|
||||
'vi-VN',
|
||||
|
@@ -84,12 +84,12 @@ error: "Errore"
|
||||
somethingHappened: "Si è verificato un problema"
|
||||
retry: "Riprova"
|
||||
pageLoadError: "Caricamento pagina non riuscito. "
|
||||
pageLoadErrorDescription: "Questo viene normalmente causato dalla rete o dalla cache del browser. Si prega di pulire la cache, o di attendere e riprovare più tardi."
|
||||
pageLoadErrorDescription: "Questo problema viene normalmente causato da errori di rete o dalla cache del browser. Si prega di pulire la cache, o di attendere e riprovare più tardi."
|
||||
serverIsDead: "Il server non risponde. Si prega di attendere e riprovare più tardi."
|
||||
youShouldUpgradeClient: "Per visualizzare la pagina è necessario aggiornare il client alla nuova versione e ricaricare."
|
||||
enterListName: "Nome della lista"
|
||||
privacy: "Privacy"
|
||||
makeFollowManuallyApprove: "Richiedi di approvare i follower manualmente"
|
||||
makeFollowManuallyApprove: "Approva i follower manualmente"
|
||||
defaultNoteVisibility: "Privacy predefinita delle note"
|
||||
follow: "Segui"
|
||||
followRequest: "Richiesta di follow"
|
||||
@@ -103,6 +103,8 @@ renoted: "Rinotato!"
|
||||
cantRenote: "È impossibile rinotare questa nota."
|
||||
cantReRenote: "È impossibile rinotare una Rinota."
|
||||
quote: "Cita"
|
||||
inChannelRenote: "Rinota nel canale"
|
||||
inChannelQuote: "Cita nel canale"
|
||||
pinnedNote: "Nota fissata"
|
||||
pinned: "Fissa sul profilo"
|
||||
you: "Tu"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "Vuoi davvero sbloccare il profilo?"
|
||||
suspendConfirm: "Vuoi sospendere questo profilo?"
|
||||
unsuspendConfirm: "Vuoi revocare la sospensione si questo profilo?"
|
||||
selectList: "Seleziona una lista"
|
||||
selectChannel: "Seleziona canale"
|
||||
selectAntenna: "Scegli un'antenna"
|
||||
selectWidget: "Seleziona il riquadro"
|
||||
editWidgets: "Modifica i riquadri"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "Non c'è più cronologia da visualizzare"
|
||||
startMessaging: "Nuovo messaggio"
|
||||
nUsersRead: "Letto da {n} persone"
|
||||
agreeTo: "Sono d'accordo con {0}"
|
||||
agreeBelow: "Accetto quanto riportato sotto"
|
||||
basicNotesBeforeCreateAccount: "Note importanti"
|
||||
tos: "Termini di servizio"
|
||||
start: "Inizia!"
|
||||
home: "Home"
|
||||
@@ -464,7 +469,8 @@ youHaveNoGroups: "Nessun gruppo"
|
||||
joinOrCreateGroup: "Puoi creare il tuo gruppo o essere invitat@ a gruppi che già esistono."
|
||||
noHistory: "Nessuna cronologia"
|
||||
signinHistory: "Storico degli accessi al profilo"
|
||||
disableAnimatedMfm: "Disabilità i MFM animati"
|
||||
enableAdvancedMfm: "Attiva MFM avanzati"
|
||||
enableAnimatedMfm: "Attiva MFM animati"
|
||||
doing: "In corso..."
|
||||
category: "Categoria"
|
||||
tags: "Tag"
|
||||
@@ -861,6 +867,8 @@ failedToFetchAccountInformation: "Impossibile recuperare le informazioni sul pro
|
||||
rateLimitExceeded: "Superato il limite di velocità."
|
||||
cropImage: "Ritaglio dell'immagine"
|
||||
cropImageAsk: "Si desidera ritagliare l'immagine?"
|
||||
cropYes: "Ritaglia"
|
||||
cropNo: "Non ritagliare"
|
||||
file: "Allegati"
|
||||
recentNHours: "Ultime {n} ore"
|
||||
recentNDays: "Ultimi {n} giorni"
|
||||
@@ -939,6 +947,16 @@ cannotPerformTemporaryDescription: "L'attività non può essere svolta, poiché
|
||||
preset: "Preimpostato"
|
||||
selectFromPresets: "Seleziona preimpostato"
|
||||
achievements: "Obiettivi raggiunti"
|
||||
gotInvalidResponseError: "Risposta del server non valida"
|
||||
gotInvalidResponseErrorDescription: "Il server potrebbe essere irraggiungibile o in manutenzione. Riprova più tardi."
|
||||
thisPostMayBeAnnoying: "Questa nota potrebbe essere offensiva"
|
||||
thisPostMayBeAnnoyingHome: "Pubblica sulla timeline principale"
|
||||
thisPostMayBeAnnoyingCancel: "Annulla"
|
||||
thisPostMayBeAnnoyingIgnore: "Pubblica lo stesso"
|
||||
collapseRenotes: "Comprimi i Rinota già letti"
|
||||
internalServerError: "Errore interno del server"
|
||||
internalServerErrorDescription: "Si è verificato un errore imprevisto all'interno del server"
|
||||
copyErrorInfo: "Copia le informazioni sull'errore"
|
||||
_achievements:
|
||||
earnedAt: "Data di conseguimento"
|
||||
_types:
|
||||
@@ -1044,7 +1062,7 @@ _achievements:
|
||||
flavor: "Grazie per aver usato Misskey!"
|
||||
_noteClipped1:
|
||||
title: "Devo clippare!"
|
||||
description: "Ho raccolto in Clip la prima Nota"
|
||||
description: "Hai raccolto la tua prima Nota in una Clip"
|
||||
_noteFavorited1:
|
||||
title: "Guarda le stelle"
|
||||
description: "Aggiungi una Nota ai preferiti per la prima volta"
|
||||
@@ -1080,7 +1098,7 @@ _achievements:
|
||||
title: "Follow me!"
|
||||
description: "Hai ottenuto 10 profili Follower"
|
||||
_followers50:
|
||||
title: "Follower a frotte"
|
||||
title: "Un gregge di Follower"
|
||||
description: "Hai ottenuto 50 Follower"
|
||||
_followers100:
|
||||
title: "Popolare"
|
||||
@@ -1108,7 +1126,7 @@ _achievements:
|
||||
title: "Caccia al tesoro"
|
||||
description: "Hai trovato un tesoro nascosto"
|
||||
_client30min:
|
||||
title: "Piccola pausa"
|
||||
title: "Piccola grande pausa"
|
||||
description: "Hai passato più di 30 minuti su Misskey"
|
||||
_noteDeletedWithin1min:
|
||||
title: "Ooops!"
|
||||
@@ -1134,7 +1152,7 @@ _achievements:
|
||||
title: "Hello, world!"
|
||||
description: "Hai scritto «Hello world» nel blocco appunti"
|
||||
_open3windows:
|
||||
title: "Finestrato"
|
||||
title: "Apri le finestre!"
|
||||
description: "Hai aperto almeno 3 finestre contemporaneamente"
|
||||
_driveFolderCircularReference:
|
||||
title: "Riferimento circolare"
|
||||
@@ -1170,7 +1188,7 @@ _achievements:
|
||||
_cookieClicked:
|
||||
title: "Clicca il biscotto"
|
||||
description: "Hai giocato a cliccare il cookie"
|
||||
flavor: "Hai autorizzato i cookie?"
|
||||
flavor: "È il sito giusto?"
|
||||
_brainDiver:
|
||||
title: "Brain Diver"
|
||||
description: "Pubblica un link a Brain Diver"
|
||||
@@ -1195,6 +1213,9 @@ _role:
|
||||
baseRole: "Ruolo di base"
|
||||
useBaseValue: "Eredita dal ruolo base"
|
||||
chooseRoleToAssign: "Seleziona il ruolo da assegnare"
|
||||
iconUrl: "URL dell'icona"
|
||||
asBadge: "Mostra come badge"
|
||||
descriptionOfAsBadge: "Se indicato, accanto al nome utente viene visualizzata l'icona del ruolo."
|
||||
canEditMembersByModerator: "Anche i Moderatori assegnano profili a questo ruolo"
|
||||
descriptionOfCanEditMembersByModerator: "Se disattivo, potranno farlo solamente gli Amministratori."
|
||||
priority: "Priorità"
|
||||
@@ -1320,72 +1341,6 @@ _nsfw:
|
||||
respect: "Nascondere i media segnati come sensibli"
|
||||
ignore: "Visualizzare i media segnati come sensibili"
|
||||
force: "Nascondere tutti i media"
|
||||
_mfm:
|
||||
cheatSheet: "Bigliettino MFM"
|
||||
intro: "MFM è un linguaggio Markdown particolare che si può usare in diverse parti di Misskey. Qui puoi visualizzare a colpo d'occhio tutta la sintassi MFM utile."
|
||||
dummy: "Il Fediverso si espande con Misskey"
|
||||
mention: "Menzioni"
|
||||
mentionDescription: "Si può menzionare un utente specifico digitando il suo nome utente subito dopo il segno @."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Per indicare un hashtag si può usare il segno numerico + tag."
|
||||
url: "URL"
|
||||
urlDescription: "È possibile indicare gli URL"
|
||||
link: "Link"
|
||||
linkDescription: "È possibile associare specifici intervalli di testo agli URL"
|
||||
bold: "Grassetto"
|
||||
boldDescription: "Il testo può essere grassettato per enfasi"
|
||||
small: "vistosamente"
|
||||
smallDescription: "Il contenuto può essere visualizzato più piccolo e più sottile"
|
||||
center: "centratura"
|
||||
centerDescription: "Il contenuto può essere centrato"
|
||||
inlineCode: "Codice (inline)"
|
||||
inlineCodeDescription: "Evidenziazione della sintassi in linea di programmi e altro codice"
|
||||
blockCode: "Codice (blocco)"
|
||||
blockCodeDescription: "Evidenziazione della sintassi di programmi multilinea e di altro codice in blocchi"
|
||||
inlineMath: "Espressione matematica(Immersione)"
|
||||
inlineMathDescription: "Visualizza le formule (KaTeX) in linea."
|
||||
blockMath: "Formula matematica (blocco)"
|
||||
blockMathDescription: "Visualizzazione di formule multilinea (KaTeX) in blocchi."
|
||||
quote: "Cita il nota"
|
||||
quoteDescription: "Può indicare che il contenuto è una citazione."
|
||||
emoji: "Emoji personalizzati"
|
||||
emojiDescription: "Utilizzare i due punti per racchiudere il nome di un'emoji personalizzata e visualizzarla."
|
||||
search: "Cerca"
|
||||
searchDescription: "È possibile visualizzare una casella di ricerca precompilata."
|
||||
flip: "Inverti"
|
||||
flipDescription: "Capovolgere il contenuto verso l'alto o verso il basso, a sinistra o a destra."
|
||||
jelly: "Animazione (Biyon Biyon)."
|
||||
jellyDescription: "Dà un'animazione di salto."
|
||||
tada: "Animazione (jang)."
|
||||
tadaDescription: "Ta-da! dà un'animazione che assomiglia a."
|
||||
jump: "Animazione(salto)"
|
||||
jumpDescription: "Da un animazione che salta su e giù."
|
||||
bounce: "Animazione(rimbalzo)"
|
||||
bounceDescription: "Rende il testo rimbalzante"
|
||||
shake: "rimbalzante"
|
||||
shakeDescription: "Rende il testo traballante"
|
||||
twitch: "testo"
|
||||
twitchDescription: "Fa tremare il testo"
|
||||
spin: "Animazione (rotazione)"
|
||||
spinDescription: "Fornisce un'animazione rotante."
|
||||
x2: "Più grande"
|
||||
x2Description: "Mostra il contenuto ingrandito."
|
||||
x3: "Molto più grande"
|
||||
x3Description: "Mostra il contenuto molto più ingrandito."
|
||||
x4: "Estremamente più grande"
|
||||
x4Description: "Mostra il contenuto estremamente più ingrandito."
|
||||
blur: "Sfocatura"
|
||||
blurDescription: "È possibile rendere sfocato il contenuto. Spostando il cursore su di esso tornerà visibile chiaramente."
|
||||
font: "Tipo di carattere"
|
||||
fontDescription: "Puoi scegliere il tipo di carattere per il contenuto."
|
||||
rainbow: "Arcobaleno"
|
||||
rainbowDescription: "Arcobaleno il contenuto."
|
||||
sparkle: "brillantini"
|
||||
sparkleDescription: "Aggiungere effetti particellari scintillanti."
|
||||
rotate: "Ruota"
|
||||
rotateDescription: "Ruota con un angolo specificato."
|
||||
plain: "Testo semplice"
|
||||
plainDescription: "Disattiva tutta la sintassi interna."
|
||||
_instanceTicker:
|
||||
none: "Nascondi"
|
||||
remote: "Mostra solo per i profili remoti"
|
||||
@@ -1590,12 +1545,15 @@ _permissions:
|
||||
"read:gallery-likes": "Visualizza i contenuti della galleria."
|
||||
"write:gallery-likes": "Manipolazione dei \"Mi piace\" della galleria."
|
||||
_auth:
|
||||
shareAccessTitle: "Permessi dell'applicazione"
|
||||
shareAccess: "Vuoi autorizzare {name} ad accedere al tuo profilo?"
|
||||
shareAccessAsk: "Vuoi autorizzare questa App ad accedere al tuo profilo?"
|
||||
permission: "{name} richiede i permessi seguenti"
|
||||
permissionAsk: "Questa app richiede le seguenti autorizzazioni:"
|
||||
pleaseGoBack: "Si prega di ritornare sulla app"
|
||||
callback: "Ritornando sulla app"
|
||||
denied: "Accesso negato"
|
||||
pleaseLogin: "Per favore accedi al tuo account per cambiare i permessi dell'applicazione"
|
||||
_antennaSources:
|
||||
all: "Tutte le note"
|
||||
homeTimeline: "Note dagli utenti che segui"
|
||||
@@ -1866,5 +1824,6 @@ _deck:
|
||||
tl: "Timeline"
|
||||
antenna: "Antenne"
|
||||
list: "Liste"
|
||||
channel: "Canale"
|
||||
mentions: "Menzioni"
|
||||
direct: "Diretta"
|
||||
|
@@ -103,6 +103,8 @@ renoted: "Renoteしました。"
|
||||
cantRenote: "この投稿はRenoteできません。"
|
||||
cantReRenote: "RenoteをRenoteすることはできません。"
|
||||
quote: "引用"
|
||||
inChannelRenote: "チャンネル内Renote"
|
||||
inChannelQuote: "チャンネル内引用"
|
||||
pinnedNote: "ピン留めされたノート"
|
||||
pinned: "ピン留め"
|
||||
you: "あなた"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "ブロック解除しますか?"
|
||||
suspendConfirm: "凍結しますか?"
|
||||
unsuspendConfirm: "解凍しますか?"
|
||||
selectList: "リストを選択"
|
||||
selectChannel: "チャンネルを選択"
|
||||
selectAntenna: "アンテナを選択"
|
||||
selectWidget: "ウィジェットを選択"
|
||||
editWidgets: "ウィジェットを編集"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "これより過去の履歴はありません"
|
||||
startMessaging: "チャットを開始"
|
||||
nUsersRead: "{n}人が読みました"
|
||||
agreeTo: "{0}に同意"
|
||||
agreeBelow: "下記に同意する"
|
||||
basicNotesBeforeCreateAccount: "基本的な注意事項"
|
||||
tos: "利用規約"
|
||||
start: "始める"
|
||||
home: "ホーム"
|
||||
@@ -387,17 +392,20 @@ userList: "リスト"
|
||||
about: "情報"
|
||||
aboutMisskey: "Misskeyについて"
|
||||
administrator: "管理者"
|
||||
token: "トークン"
|
||||
twoStepAuthentication: "二段階認証"
|
||||
token: "確認コード"
|
||||
2fa: "二要素認証"
|
||||
totp: "認証アプリ"
|
||||
totpDescription: "認証アプリを使ってワンタイムパスワードを入力"
|
||||
moderator: "モデレーター"
|
||||
moderation: "モデレーション"
|
||||
nUsersMentioned: "{n}人が投稿"
|
||||
securityKeyAndPasskey: "セキュリティキー・パスキー"
|
||||
securityKey: "セキュリティキー"
|
||||
securityKeyName: "キーの名前"
|
||||
registerSecurityKey: "セキュリティキーを登録する"
|
||||
lastUsed: "最後の使用"
|
||||
lastUsedAt: "最後の使用: {t}"
|
||||
unregister: "登録を解除"
|
||||
passwordLessLogin: "パスワード無しログイン"
|
||||
passwordLessLogin: "パスワードレスログイン"
|
||||
passwordLessLoginDescription: "パスワードを使用せず、セキュリティキーやパスキーなどのみでログインします"
|
||||
resetPassword: "パスワードをリセット"
|
||||
newPasswordIs: "新しいパスワードは「{password}」です"
|
||||
reduceUiAnimation: "UIのアニメーションを減らす"
|
||||
@@ -412,24 +420,15 @@ markAsReadAllTalkMessages: "すべてのチャットを既読にする"
|
||||
help: "ヘルプ"
|
||||
inputMessageHere: "ここにメッセージを入力"
|
||||
close: "閉じる"
|
||||
group: "グループ"
|
||||
groups: "グループ"
|
||||
createGroup: "グループを作成"
|
||||
ownedGroups: "所有グループ"
|
||||
joinedGroups: "参加しているグループ"
|
||||
invites: "招待"
|
||||
groupName: "グループ名"
|
||||
members: "メンバー"
|
||||
transfer: "譲渡"
|
||||
messagingWithUser: "ユーザーとチャット"
|
||||
messagingWithGroup: "グループでチャット"
|
||||
title: "タイトル"
|
||||
text: "テキスト"
|
||||
enable: "有効にする"
|
||||
next: "次"
|
||||
retype: "再入力"
|
||||
noteOf: "{user}のノート"
|
||||
inviteToGroup: "グループに招待"
|
||||
quoteAttached: "引用付き"
|
||||
quoteQuestion: "引用として添付しますか?"
|
||||
noMessagesYet: "まだチャットはありません"
|
||||
@@ -451,20 +450,17 @@ passwordMatched: "一致しました"
|
||||
passwordNotMatched: "一致していません"
|
||||
signinWith: "{x}でログイン"
|
||||
signinFailed: "ログインできませんでした。ユーザー名とパスワードを確認してください。"
|
||||
tapSecurityKey: "セキュリティキーにタッチ"
|
||||
or: "もしくは"
|
||||
language: "言語"
|
||||
uiLanguage: "UIの表示言語"
|
||||
groupInvited: "グループに招待されました"
|
||||
aboutX: "{x}について"
|
||||
emojiStyle: "絵文字のスタイル"
|
||||
native: "ネイティブ"
|
||||
disableDrawer: "メニューをドロワーで表示しない"
|
||||
youHaveNoGroups: "グループがありません"
|
||||
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
|
||||
noHistory: "履歴はありません"
|
||||
signinHistory: "ログイン履歴"
|
||||
disableAnimatedMfm: "動きのあるMFMを無効にする"
|
||||
enableAdvancedMfm: "高度なMFMを有効にする"
|
||||
enableAnimatedMfm: "動きのあるMFMを有効にする"
|
||||
doing: "やっています"
|
||||
category: "カテゴリ"
|
||||
tags: "タグ"
|
||||
@@ -783,6 +779,7 @@ popularPosts: "人気の投稿"
|
||||
shareWithNote: "ノートで共有"
|
||||
ads: "広告"
|
||||
expiration: "期限"
|
||||
startingperiod: "開始期間"
|
||||
memo: "メモ"
|
||||
priority: "優先度"
|
||||
high: "高"
|
||||
@@ -834,8 +831,6 @@ deleteAccountConfirm: "アカウントが削除されます。よろしいです
|
||||
incorrectPassword: "パスワードが間違っています。"
|
||||
voteConfirm: "「{choice}」に投票しますか?"
|
||||
hide: "隠す"
|
||||
leaveGroup: "グループから抜ける"
|
||||
leaveGroupConfirm: "「{name}」から抜けますか?"
|
||||
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
|
||||
welcomeBackWithName: "おかえりなさい、{name}さん"
|
||||
clickToFinishEmailVerification: "[{ok}]を押して、メールアドレスの確認を完了してください。"
|
||||
@@ -861,6 +856,8 @@ failedToFetchAccountInformation: "アカウント情報の取得に失敗しま
|
||||
rateLimitExceeded: "レート制限を超えました"
|
||||
cropImage: "画像のクロップ"
|
||||
cropImageAsk: "画像をクロップしますか?"
|
||||
cropYes: "クロップする"
|
||||
cropNo: "そのまま使う"
|
||||
file: "ファイル"
|
||||
recentNHours: "直近{n}時間"
|
||||
recentNDays: "直近{n}日"
|
||||
@@ -939,6 +936,19 @@ cannotPerformTemporaryDescription: "操作回数が制限を超過するため
|
||||
preset: "プリセット"
|
||||
selectFromPresets: "プリセットから選択"
|
||||
achievements: "実績"
|
||||
gotInvalidResponseError: "サーバーの応答が無効です"
|
||||
gotInvalidResponseErrorDescription: "サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから再度お試しください。"
|
||||
thisPostMayBeAnnoying: "この投稿は迷惑になる可能性があります。"
|
||||
thisPostMayBeAnnoyingHome: "ホームに投稿"
|
||||
thisPostMayBeAnnoyingCancel: "やめる"
|
||||
thisPostMayBeAnnoyingIgnore: "このまま投稿"
|
||||
collapseRenotes: "見たことのあるRenoteを省略して表示"
|
||||
internalServerError: "サーバー内部エラー"
|
||||
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
|
||||
copyErrorInfo: "エラー情報をコピー"
|
||||
joinThisServer: "このサーバーに登録する"
|
||||
exploreOtherServers: "他のサーバーを探す"
|
||||
letsLookAtTimeline: "タイムラインを見てみる"
|
||||
|
||||
_achievements:
|
||||
earnedAt: "獲得日時"
|
||||
@@ -1148,7 +1158,7 @@ _achievements:
|
||||
description: "ここをクリックした"
|
||||
_justPlainLucky:
|
||||
title: "単なるラッキー"
|
||||
description: "10秒ごとに0.01%の確率で獲得"
|
||||
description: "10秒ごとに0.005%の確率で獲得"
|
||||
_setNameToSyuilo:
|
||||
title: "神様コンプレックス"
|
||||
description: "名前を syuilo に設定した"
|
||||
@@ -1184,7 +1194,7 @@ _role:
|
||||
description: "ロールの説明"
|
||||
permission: "ロールの権限"
|
||||
descriptionOfPermission: "<b>モデレーター</b>は基本的なモデレーションに関する操作を行えます。\n<b>管理者</b>はインスタンスの全ての設定を変更できます。"
|
||||
assignTarget: "アサインターゲット"
|
||||
assignTarget: "アサイン"
|
||||
descriptionOfAssignTarget: "<b>マニュアル</b>は誰がこのロールに含まれるかを手動で管理します。\n<b>コンディショナル</b>は条件を設定し、それに合致するユーザーが自動で含まれるようになります。"
|
||||
manual: "マニュアル"
|
||||
conditional: "コンディショナル"
|
||||
@@ -1197,6 +1207,9 @@ _role:
|
||||
baseRole: "ベースロール"
|
||||
useBaseValue: "ベースロールの値を使用"
|
||||
chooseRoleToAssign: "アサインするロールを選択"
|
||||
iconUrl: "アイコン画像のURL"
|
||||
asBadge: "バッジとして表示"
|
||||
descriptionOfAsBadge: "オンにすると、ユーザー名の横にロールのアイコンが表示されます。"
|
||||
canEditMembersByModerator: "モデレーターのメンバー編集を許可"
|
||||
descriptionOfCanEditMembersByModerator: "オンにすると、管理者に加えてモデレーターもこのロールへユーザーをアサイン/アサイン解除できるようになります。オフにすると管理者のみが行えます。"
|
||||
priority: "優先度"
|
||||
@@ -1337,73 +1350,6 @@ _nsfw:
|
||||
ignore: "閲覧注意のメディアを隠さない"
|
||||
force: "常にメディアを隠す"
|
||||
|
||||
_mfm:
|
||||
cheatSheet: "MFMチートシート"
|
||||
intro: "MFMは、Misskey内の様々な場所で使用できる専用のマークアップ言語です。ここでは、MFMで使用可能な構文一覧が確認できます。"
|
||||
dummy: "MisskeyでFediverseの世界が広がります"
|
||||
mention: "メンション"
|
||||
mentionDescription: "アットマーク + ユーザー名で、特定のユーザーを示すことができます。"
|
||||
hashtag: "ハッシュタグ"
|
||||
hashtagDescription: "ナンバーサイン + タグで、ハッシュタグを示すことができます。"
|
||||
url: "URL"
|
||||
urlDescription: "URLを示すことができます。"
|
||||
link: "リンク"
|
||||
linkDescription: "文章の特定の範囲を、URLに紐づけることができます。"
|
||||
bold: "太字"
|
||||
boldDescription: "文字を太く表示して強調することができます。"
|
||||
small: "目立たなく"
|
||||
smallDescription: "内容を小さく・薄く表示させることができます。"
|
||||
center: "中央寄せ"
|
||||
centerDescription: "内容を中央寄せで表示させることができます。"
|
||||
inlineCode: "コード(インライン)"
|
||||
inlineCodeDescription: "プログラムなどのコードをインラインでシンタックスハイライトします。"
|
||||
blockCode: "コード(ブロック)"
|
||||
blockCodeDescription: "複数行のプログラムなどのコードをブロックでシンタックスハイライトします。"
|
||||
inlineMath: "数式(インライン)"
|
||||
inlineMathDescription: "数式(KaTeX)をインラインで表示します。"
|
||||
blockMath: "数式(ブロック)"
|
||||
blockMathDescription: "複数行の数式(KaTeX)をブロックで表示します。"
|
||||
quote: "引用"
|
||||
quoteDescription: "内容が引用であることを示すことができます。"
|
||||
emoji: "カスタム絵文字"
|
||||
emojiDescription: "コロンでカスタム絵文字名を囲むと、カスタム絵文字を表示させることができます。"
|
||||
search: "検索"
|
||||
searchDescription: "入力済み検索ボックスを表示させることができます。"
|
||||
flip: "反転"
|
||||
flipDescription: "内容を上下または左右に反転させます。"
|
||||
jelly: "アニメーション(びよんびよん)"
|
||||
jellyDescription: "びよんびよんするアニメーションを与えます。"
|
||||
tada: "アニメーション(じゃーん)"
|
||||
tadaDescription: "ジャーン!という感じのアニメーションを与えます。"
|
||||
jump: "アニメーション(ジャンプ)"
|
||||
jumpDescription: "飛び跳ねるようなアニメーションを与えます。"
|
||||
bounce: "アニメーション(バウンド)"
|
||||
bounceDescription: "ぽよんぽよん弾むようなアニメーションを与えます。"
|
||||
shake: "アニメーション(ぶるぶる)"
|
||||
shakeDescription: "ぶるぶる震えるアニメーションを与えます。"
|
||||
twitch: "アニメーション(ブレ)"
|
||||
twitchDescription: "激しくブレるアニメーションを与えます。"
|
||||
spin: "アニメーション(回転)"
|
||||
spinDescription: "回転するアニメーションを与えます。"
|
||||
x2: "大きく"
|
||||
x2Description: "内容を大きく表示します。"
|
||||
x3: "とても大きく"
|
||||
x3Description: "内容をとても大きく表示します。"
|
||||
x4: "究極に大きく"
|
||||
x4Description: "内容を究極に大きく表示します。"
|
||||
blur: "ぼかし"
|
||||
blurDescription: "内容をぼかすことができます。ポインターを上に乗せるとはっきり見えるようになります。"
|
||||
font: "フォント"
|
||||
fontDescription: "内容のフォントを指定することができます。"
|
||||
rainbow: "レインボー"
|
||||
rainbowDescription: "内容をレインボーにします。"
|
||||
sparkle: "キラキラ"
|
||||
sparkleDescription: "キラキラしたパーティクルのエフェクトを追加します。"
|
||||
rotate: "回転"
|
||||
rotateDescription: "指定した角度で回転させます。"
|
||||
plain: "プレーン"
|
||||
plainDescription: "内側の構文を全て無効にします。"
|
||||
|
||||
_instanceTicker:
|
||||
none: "表示しない"
|
||||
remote: "リモートユーザーに表示"
|
||||
@@ -1578,14 +1524,29 @@ _tutorial:
|
||||
|
||||
_2fa:
|
||||
alreadyRegistered: "既に設定は完了しています。"
|
||||
registerDevice: "デバイスを登録"
|
||||
registerKey: "キーを登録"
|
||||
registerTOTP: "認証アプリの設定を開始"
|
||||
passwordToTOTP: "パスワードを入力してください"
|
||||
step1: "まず、{a}や{b}などの認証アプリをお使いのデバイスにインストールします。"
|
||||
step2: "次に、表示されているQRコードをアプリでスキャンします。"
|
||||
step2Url: "デスクトップアプリでは次のURLを入力します:"
|
||||
step3: "アプリに表示されているトークンを入力して完了です。"
|
||||
step4: "これからログインするときも、同じようにトークンを入力します。"
|
||||
securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキーもしくは端末の指紋認証やPINを使用してログインするように設定できます。"
|
||||
step2Click: "QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。"
|
||||
step2Url: "デスクトップアプリでは次のURIを入力します:"
|
||||
step3Title: "確認コードを入力"
|
||||
step3: "アプリに表示されている確認コード(トークン)を入力して完了です。"
|
||||
step4: "これからログインするときも、同じように確認コードを入力します。"
|
||||
securityKeyNotSupported: "お使いのブラウザはセキュリティキーに対応していません。"
|
||||
registerTOTPBeforeKey: "セキュリティキー・パスキーを登録するには、まず認証アプリの設定を行なってください。"
|
||||
securityKeyInfo: "FIDO2をサポートするハードウェアセキュリティキー、端末の生体認証やPINロック、パスキーといった、WebAuthn由来の鍵を登録します。"
|
||||
chromePasskeyNotSupported: "Chromeのパスキーは現在サポートしていません。"
|
||||
registerSecurityKey: "セキュリティキー・パスキーを登録する"
|
||||
securityKeyName: "キーの名前を入力"
|
||||
tapSecurityKey: "ブラウザの指示に従い、セキュリティキーやパスキーを登録してください"
|
||||
removeKey: "セキュリティキーを削除"
|
||||
removeKeyConfirm: "{name}を削除しますか?"
|
||||
whyTOTPOnlyRenew: "セキュリティキーが登録されている場合、認証アプリの設定は解除できません。"
|
||||
renewTOTP: "認証アプリを再設定"
|
||||
renewTOTPConfirm: "今までの認証アプリの確認コードは使用できなくなります"
|
||||
renewTOTPOk: "再設定する"
|
||||
renewTOTPCancel: "やめておく"
|
||||
|
||||
_permissions:
|
||||
"read:account": "アカウントの情報を見る"
|
||||
@@ -1622,19 +1583,21 @@ _permissions:
|
||||
"write:gallery-likes": "ギャラリーのいいねを操作する"
|
||||
|
||||
_auth:
|
||||
shareAccessTitle: "アプリへのアクセス許可"
|
||||
shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?"
|
||||
shareAccessAsk: "アカウントへのアクセスを許可しますか?"
|
||||
permission: "{name}は次の権限を要求しています"
|
||||
permissionAsk: "このアプリは次の権限を要求しています"
|
||||
pleaseGoBack: "アプリケーションに戻ってやっていってください"
|
||||
callback: "アプリケーションに戻っています"
|
||||
denied: "アクセスを拒否しました"
|
||||
pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
|
||||
|
||||
_antennaSources:
|
||||
all: "全てのノート"
|
||||
homeTimeline: "フォローしているユーザーのノート"
|
||||
users: "指定した一人または複数のユーザーのノート"
|
||||
userList: "指定したリストのユーザーのノート"
|
||||
userGroup: "指定したグループのユーザーのノート"
|
||||
|
||||
_weekday:
|
||||
sunday: "日曜日"
|
||||
@@ -1864,12 +1827,9 @@ _notification:
|
||||
youGotReply: "{name}からのリプライ"
|
||||
youGotQuote: "{name}による引用"
|
||||
youRenoted: "{name}がRenoteしました"
|
||||
youGotMessagingMessageFromUser: "{name}からのチャットがあります"
|
||||
youGotMessagingMessageFromGroup: "{name}のチャットがあります"
|
||||
youWereFollowed: "フォローされました"
|
||||
youReceivedFollowRequest: "フォローリクエストが来ました"
|
||||
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
||||
youWereInvitedToGroup: "{userName}があなたをグループに招待しました"
|
||||
pollEnded: "アンケートの結果が出ました"
|
||||
unreadAntennaNote: "アンテナ {name}"
|
||||
emptyPushNotificationMessage: "プッシュ通知の更新をしました"
|
||||
@@ -1886,7 +1846,6 @@ _notification:
|
||||
pollEnded: "アンケートが終了"
|
||||
receiveFollowRequest: "フォロー申請を受け取った"
|
||||
followRequestAccepted: "フォローが受理された"
|
||||
groupInvited: "グループに招待された"
|
||||
app: "連携アプリからの通知"
|
||||
|
||||
_actions:
|
||||
@@ -1919,5 +1878,10 @@ _deck:
|
||||
tl: "タイムライン"
|
||||
antenna: "アンテナ"
|
||||
list: "リスト"
|
||||
channel: "チャンネル"
|
||||
mentions: "あなた宛て"
|
||||
direct: "ダイレクト"
|
||||
|
||||
_dialog:
|
||||
charactersExceeded: "最大文字数を超えています! 現在 {current} / 制限 {max}"
|
||||
charactersBelow: "最小文字数を下回っています! 現在 {current} / 制限 {min}"
|
||||
|
@@ -46,7 +46,7 @@ copyContent: "内容をコピー"
|
||||
copyLink: "リンクをコピー"
|
||||
delete: "ほかす"
|
||||
deleteAndEdit: "ほかして直す"
|
||||
deleteAndEditConfirm: "このノートをほかして書き直すんか?このノートへのリアクション、Renote、返信も全部消えてまうで。"
|
||||
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Renote、返信も全部消えるんやけどそれでもええん?"
|
||||
addToList: "リストに入れたる"
|
||||
sendMessage: "メッセージを送る"
|
||||
copyRSS: "RSSをコピー"
|
||||
@@ -89,7 +89,7 @@ serverIsDead: "サーバーからの応答がないで。もうちょい待っ
|
||||
youShouldUpgradeClient: "このページを表示するには、リロードして新しいバージョンのクライアントを使ってなー。"
|
||||
enterListName: "リスト名を入れてや"
|
||||
privacy: "プライバシー"
|
||||
makeFollowManuallyApprove: "自分が認めた人だけがこのアカウントをフォローできるようにする"
|
||||
makeFollowManuallyApprove: "他人のフォローは許可してからや!"
|
||||
defaultNoteVisibility: "もとからの公開範囲"
|
||||
follow: "フォロー"
|
||||
followRequest: "フォローを頼む"
|
||||
@@ -103,6 +103,8 @@ renoted: "Renoteしたで。"
|
||||
cantRenote: "この投稿はRenoteできへんらしい。"
|
||||
cantReRenote: "Renote自体はRenoteできへんで。"
|
||||
quote: "引用"
|
||||
inChannelRenote: "チャンネル内Renote"
|
||||
inChannelQuote: "チャンネル内引用"
|
||||
pinnedNote: "ピン留めされとるノート"
|
||||
pinned: "ピン留めしとく"
|
||||
you: "あんた"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "ブロックやめたるってほんまか?"
|
||||
suspendConfirm: "凍結してしもうてええか?"
|
||||
unsuspendConfirm: "解凍するけどええか?"
|
||||
selectList: "リストを選ぶ"
|
||||
selectChannel: "チャンネルを選ぶ"
|
||||
selectAntenna: "アンテナを選ぶ"
|
||||
selectWidget: "ウィジェットを選ぶ"
|
||||
editWidgets: "ウィジェットをいじる"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "これより過去の履歴はあらへんで"
|
||||
startMessaging: "チャットやるで"
|
||||
nUsersRead: "{n}人が読んでもうた"
|
||||
agreeTo: "{0}に同意したで"
|
||||
agreeBelow: "下記に同意したる"
|
||||
basicNotesBeforeCreateAccount: "よう読んでやってや"
|
||||
tos: "利用規約"
|
||||
start: "始める"
|
||||
home: "ホーム"
|
||||
@@ -300,7 +305,7 @@ avatar: "アイコン"
|
||||
banner: "バナー"
|
||||
nsfw: "閲覧注意"
|
||||
whenServerDisconnected: "サーバーとの接続が切れたとき"
|
||||
disconnectedFromServer: "サーバーとの通信が切れたで"
|
||||
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
||||
reload: "リロード"
|
||||
doNothing: "何もせんとく"
|
||||
reloadConfirm: "リロードしてええか?"
|
||||
@@ -464,7 +469,8 @@ youHaveNoGroups: "グループがあらへんねぇ。"
|
||||
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループ作ってからやってな"
|
||||
noHistory: "履歴はあらへんねぇ。"
|
||||
signinHistory: "ログイン履歴"
|
||||
disableAnimatedMfm: "動きがやかましいMFMを止める"
|
||||
enableAdvancedMfm: "ややこしいMFMもありにする"
|
||||
enableAnimatedMfm: "動きがやかましいMFMも許したる"
|
||||
doing: "やっとるがな"
|
||||
category: "カテゴリ"
|
||||
tags: "タグ"
|
||||
@@ -673,8 +679,8 @@ sentReactionsCount: "リアクションした数やで"
|
||||
receivedReactionsCount: "リアクションされた数"
|
||||
pollVotesCount: "アンケートに投票した数"
|
||||
pollVotedCount: "アンケートに投票された数"
|
||||
yes: "はい"
|
||||
no: "いいえ"
|
||||
yes: "ええで"
|
||||
no: "あかんで"
|
||||
driveFilesCount: "ドライブのファイル数"
|
||||
driveUsage: "ドライブ使用量やで"
|
||||
noCrawle: "クローラーによるインデックスを拒否するで"
|
||||
@@ -861,6 +867,8 @@ failedToFetchAccountInformation: "アカウントの取得に失敗したみた
|
||||
rateLimitExceeded: "レート制限が超えたみたいやで"
|
||||
cropImage: "画像のクロップ"
|
||||
cropImageAsk: "画像をクロップしたってええか?"
|
||||
cropYes: "切り抜いたる"
|
||||
cropNo: "切り抜かへん"
|
||||
file: "ファイル"
|
||||
recentNHours: "直近{n}時間"
|
||||
recentNDays: "直近{n}日"
|
||||
@@ -938,6 +946,172 @@ cannotPerformTemporary: "一時的に利用できへんで"
|
||||
cannotPerformTemporaryDescription: "操作回数が制限を超えたから一時的に利用できへんくなったで。ちょっと時間置いてからもう一回やってやー。"
|
||||
preset: "プリセット"
|
||||
selectFromPresets: "プリセットから選ぶ"
|
||||
achievements: "実績"
|
||||
gotInvalidResponseError: "サーバー黙っとるわ、知らんけど"
|
||||
gotInvalidResponseErrorDescription: "サーバーいま日曜日。またきて月曜日。"
|
||||
thisPostMayBeAnnoying: "この投稿は迷惑かもしらんで。"
|
||||
thisPostMayBeAnnoyingHome: "ホームに投稿"
|
||||
thisPostMayBeAnnoyingCancel: "やめとく"
|
||||
thisPostMayBeAnnoyingIgnore: "このまま投稿"
|
||||
collapseRenotes: "見たことあるRenoteは省略やで"
|
||||
internalServerError: "サーバー内部エラー"
|
||||
internalServerErrorDescription: "サーバー内部でよう分からんエラーやわ"
|
||||
copyErrorInfo: "エラー情報をコピー"
|
||||
_achievements:
|
||||
earnedAt: "貰った日ぃ"
|
||||
_types:
|
||||
_notes1:
|
||||
title: "まいど!"
|
||||
description: "初めてノート投稿したった"
|
||||
flavor: "Misskeyを楽しんでな~"
|
||||
_notes10:
|
||||
title: "ノートの天保山"
|
||||
description: "ノートを10回投稿した"
|
||||
_notes100:
|
||||
title: "ノートの真田山"
|
||||
description: "ノートを100回投稿した"
|
||||
_notes500:
|
||||
title: "ノートの生駒山"
|
||||
description: "ノートを500回投稿した"
|
||||
_notes1000:
|
||||
title: "ノートの山"
|
||||
description: "ノートを1,000回投稿した"
|
||||
_notes5000:
|
||||
title: "箕面の滝からノート"
|
||||
description: "ノートを5,000回投稿した"
|
||||
_notes10000:
|
||||
title: "スーパーノート"
|
||||
description: "ノートを10,000回投稿した"
|
||||
_notes20000:
|
||||
title: "ニードモアノート"
|
||||
description: "ノートを20,000回投稿した"
|
||||
_notes30000:
|
||||
title: "ノートノートノート"
|
||||
description: "ノートを30,000回投稿した"
|
||||
_notes40000:
|
||||
title: "ノート工場"
|
||||
description: "ノートを40,000回投稿した"
|
||||
_notes50000:
|
||||
title: "ノートの惑星"
|
||||
description: "ノートを50,000回投稿した"
|
||||
_notes60000:
|
||||
title: "ノートクエーサー"
|
||||
description: "ノートを60,000回投稿した"
|
||||
_notes70000:
|
||||
title: "ブラックノートホール"
|
||||
description: "ノートを70,000回投稿した"
|
||||
_notes80000:
|
||||
title: "ノートギャラクシー"
|
||||
description: "ノートを80,000回投稿した"
|
||||
_notes90000:
|
||||
title: "ノートバース"
|
||||
description: "ノートを90,000回投稿した"
|
||||
_notes100000:
|
||||
title: "ALL YOUR NOTE ARE BELONG TO US"
|
||||
description: "ノートを100,000回投稿した"
|
||||
flavor: "そんなに書くことあるんか?"
|
||||
_login3:
|
||||
title: "ビギナーⅠ"
|
||||
description: "通算ログイン日数が3日"
|
||||
flavor: "今日からワシはミスキストやで"
|
||||
_login7:
|
||||
title: "ビギナーⅡ"
|
||||
description: "通算ログイン日数が7日"
|
||||
flavor: "慣れてきたんちゃう?"
|
||||
_login15:
|
||||
title: "ビギナーⅢ"
|
||||
description: "通算ログイン日数が15日"
|
||||
_login30:
|
||||
title: "ミスキストⅠ"
|
||||
description: "通算ログイン日数が30日"
|
||||
_login60:
|
||||
title: "ミスキストⅡ"
|
||||
description: "通算ログイン日数が60日"
|
||||
_login100:
|
||||
title: "ミスキストⅢ"
|
||||
description: "通算ログイン日数が100日"
|
||||
flavor: "そのユーザー、ミスキストにつき"
|
||||
_login200:
|
||||
title: "常連Ⅰ"
|
||||
_followers500:
|
||||
title: "基地局"
|
||||
description: "フォロワーが500人を超した"
|
||||
_followers1000:
|
||||
title: "インフルエンサー"
|
||||
description: "フォロワーが1,000人を超した"
|
||||
_collectAchievements30:
|
||||
title: "実績コレクター"
|
||||
description: "実績を30個以上獲得した"
|
||||
_viewAchievements3min:
|
||||
title: "実績好き"
|
||||
description: "実績一覧を3分以上眺め続けた"
|
||||
_iLoveMisskey:
|
||||
title: "Misskey好きやねん"
|
||||
description: "\"I ❤ #Misskey\"を投稿した"
|
||||
flavor: "Misskeyを使ってくれてありがとうな~ by 開発チーム"
|
||||
_foundTreasure:
|
||||
title: "なんでも鑑定団"
|
||||
description: "隠されたお宝を発見した"
|
||||
_client30min:
|
||||
title: "ねんね"
|
||||
description: "クライアントを起動してから30分以上経過した"
|
||||
_noteDeletedWithin1min:
|
||||
title: "*おおっと*"
|
||||
description: "投稿してから1分以内にその投稿を消した"
|
||||
_postedAtLateNight:
|
||||
title: "夜行性"
|
||||
description: "深夜にノートを投稿した"
|
||||
flavor: "そろそろ寝よか"
|
||||
_postedAt0min0sec:
|
||||
title: "時報"
|
||||
description: "0分0秒にノートを投稿した"
|
||||
flavor: "ポッ ポッ ポッ ピーン"
|
||||
_selfQuote:
|
||||
title: "自己言及"
|
||||
description: "自分のノートを引用した"
|
||||
_htl20npm:
|
||||
title: "流れるTL"
|
||||
description: "ホームタイムラインの流速が20npmを超す"
|
||||
_viewInstanceChart:
|
||||
title: "アナリスト"
|
||||
description: "インスタンスのチャートを表示した"
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "Hello, world!"
|
||||
description: "スクラッチパッドで hello worldを出力した"
|
||||
_open3windows:
|
||||
title: "マド開けすぎ"
|
||||
description: "ウィンドウを3つ以上開いた状態にした"
|
||||
_driveFolderCircularReference:
|
||||
title: "環状線"
|
||||
description: "ドライブのフォルダを再帰的な入れ子にしようとした"
|
||||
_reactWithoutRead:
|
||||
title: "ちゃんと読んだんか?"
|
||||
description: "100文字以上のテキストを含むノートに投稿されてから3秒以内にリアクションした"
|
||||
_clickedClickHere:
|
||||
title: "ここをクリック"
|
||||
description: "ここをクリックした"
|
||||
_justPlainLucky:
|
||||
title: "単なるラッキー"
|
||||
description: "10秒ごとに0.005%の確率で獲得"
|
||||
_setNameToSyuilo:
|
||||
title: "神様コンプレックス"
|
||||
description: "名前を syuilo に設定した"
|
||||
_passedSinceAccountCreated1:
|
||||
title: "一周年"
|
||||
description: "アカウント作成から1年経過した"
|
||||
_passedSinceAccountCreated2:
|
||||
title: "二周年"
|
||||
description: "アカウント作成から2年経過した"
|
||||
_passedSinceAccountCreated3:
|
||||
title: "三周年"
|
||||
description: "アカウント作成から3年経過した"
|
||||
_loggedInOnBirthday:
|
||||
title: "ハッピーバースデー!"
|
||||
description: "誕生日にログインした"
|
||||
_loggedInOnNewYearsDay:
|
||||
title: "あけましておめでとうございます!"
|
||||
description: "元旦にログインした"
|
||||
flavor: "今年も弊インスタンスをよろしくお願いします"
|
||||
_role:
|
||||
new: "ロールの作成"
|
||||
edit: "ロールの編集"
|
||||
@@ -1083,72 +1257,6 @@ _nsfw:
|
||||
respect: "閲覧注意のメディアは隠すで"
|
||||
ignore: "閲覧注意のメディアは隠さへんで"
|
||||
force: "常にメディアを隠すで"
|
||||
_mfm:
|
||||
cheatSheet: "MFMチートシート"
|
||||
intro: "MFMは、Misskey内の色んな所で使える専用のマークアップ言語やで。このページでMFMで使える構文一覧が確認できるで。"
|
||||
dummy: "MisskeyでFediverseの世界が広がります"
|
||||
mention: "メンション"
|
||||
mentionDescription: "アットマーク + ユーザー名で、特定のユーザーを示すことができるで。"
|
||||
hashtag: "ハッシュタグ"
|
||||
hashtagDescription: "ナンバーサイン + タグで、ハッシュタグを示すことができるで。"
|
||||
url: "URL"
|
||||
urlDescription: "URLを示すことができるで。"
|
||||
link: "リンク"
|
||||
linkDescription: "文章の特定の範囲をURLに紐づけることができるで"
|
||||
bold: "太字"
|
||||
boldDescription: "文字を太く表示して強調することができるで"
|
||||
small: "目立たなく"
|
||||
smallDescription: "内容を小さく・薄く表示することができるで"
|
||||
center: "中央寄せ"
|
||||
centerDescription: "内容を中央寄せで表示することができるで"
|
||||
inlineCode: "コード(インライン)"
|
||||
inlineCodeDescription: "プログラムとかのコードをインラインでシンタックスハイライトするで"
|
||||
blockCode: "コード(ブロック)"
|
||||
blockCodeDescription: "複数行のプログラムとかのコードをブロックでシンタックスハイライトするで"
|
||||
inlineMath: "数式(インライン)"
|
||||
inlineMathDescription: "数式(KaTeX)をインラインで表示するで"
|
||||
blockMath: "数式(ブロック)"
|
||||
blockMathDescription: "複数行の数式(KaTeX)をブロックで表示するで"
|
||||
quote: "引用"
|
||||
quoteDescription: "内容が引用ってことを示すことができるで"
|
||||
emoji: "カスタム絵文字"
|
||||
emojiDescription: "コロンでカスタム絵文字名を囲んだると、カスタム絵文字を表示させることができるで"
|
||||
search: "探す"
|
||||
searchDescription: "入力済み検索ボックスを表示することができるで"
|
||||
flip: "反転"
|
||||
flipDescription: "内容を上下または左右に反転するで"
|
||||
jelly: "アニメーション(びよんびよん)"
|
||||
jellyDescription: "びよんびよんするアニメーションやな。"
|
||||
tada: "アニメーション(じゃーん)"
|
||||
tadaDescription: "ジャーン!ってな感じのアニメーションやな。"
|
||||
jump: "アニメーション(ジャンプ)"
|
||||
jumpDescription: "飛び跳ねるようなアニメーションやな。"
|
||||
bounce: "アニメーション(バウンド)"
|
||||
bounceDescription: "ぽよんぽよん弾むようなアニメーションやな。"
|
||||
shake: "アニメーション(ぶるぶる)"
|
||||
shakeDescription: "ぶるぶる震えるアニメーションやな。"
|
||||
twitch: "アニメーション(ブレ)"
|
||||
twitchDescription: "激しくブレるアニメーションやな。"
|
||||
spin: "アニメーション(回転)"
|
||||
spinDescription: "回転するアニメーションやな。"
|
||||
x2: "大きく"
|
||||
x2Description: "内容を大きく表示するで"
|
||||
x3: "とても大きく"
|
||||
x3Description: "内容をとても大きく表示するで"
|
||||
x4: "究極に大きく"
|
||||
x4Description: "内容を究極に大きく表示するで"
|
||||
blur: "ぼかし"
|
||||
blurDescription: "内容をぼかすことができるで。ポインターを上に乗せるとはっきり見えるようになるで"
|
||||
font: "フォント"
|
||||
fontDescription: "内容のフォントを指定することができるで"
|
||||
rainbow: "レインボー"
|
||||
rainbowDescription: "内容をレインボーにするで"
|
||||
sparkle: "キラキラ"
|
||||
sparkleDescription: "キラキラしたバーティ来るのエフェクトを追加するで"
|
||||
rotate: "回転"
|
||||
rotateDescription: "指定した角度で回転させるで"
|
||||
plain: "プレーン"
|
||||
plainDescription: "内側の構文を全部無効にするで"
|
||||
_instanceTicker:
|
||||
none: "表示せん"
|
||||
remote: "リモートユーザーに表示"
|
||||
@@ -1355,10 +1463,12 @@ _permissions:
|
||||
_auth:
|
||||
shareAccess: "「{name}」がアカウントにアクセスすることを許可してええか?"
|
||||
shareAccessAsk: "アカウントのアクセスを許可してもええか?"
|
||||
permission: "{name}に次の権限つけたってやって"
|
||||
permissionAsk: "このアプリは次の権限を要求しとるで"
|
||||
pleaseGoBack: "アプリケーションに戻ってええよ"
|
||||
callback: "アプリケーションに戻っとるで"
|
||||
denied: "アクセスを拒否ったで"
|
||||
pleaseLogin: "アプリにアクセスさせるんやったら、ログインしてや。"
|
||||
_antennaSources:
|
||||
all: "みんなのノート"
|
||||
homeTimeline: "フォローしとるユーザーのノート"
|
||||
@@ -1587,6 +1697,7 @@ _notification:
|
||||
pollEnded: "アンケートの結果が出たみたいや"
|
||||
unreadAntennaNote: "アンテナ {name}"
|
||||
emptyPushNotificationMessage: "プッシュ通知の更新をしといたで"
|
||||
achievementEarned: "実績を獲得しとるで"
|
||||
_types:
|
||||
all: "すべて"
|
||||
follow: "フォロー"
|
||||
@@ -1628,5 +1739,6 @@ _deck:
|
||||
tl: "タイムライン"
|
||||
antenna: "アンテナ"
|
||||
list: "リスト"
|
||||
channel: "チャンネル"
|
||||
mentions: "あんた宛て"
|
||||
direct: "ダイレクト"
|
||||
|
@@ -61,10 +61,6 @@ account: "Imiḍan"
|
||||
_email:
|
||||
_follow:
|
||||
title: "Yeṭṭafaṛ-ik·em-id"
|
||||
_mfm:
|
||||
mention: "Bder"
|
||||
search: "Nadi"
|
||||
font: "Tasefsit"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Bder"
|
||||
|
@@ -64,8 +64,6 @@ file: "ಕಡತಗಳು"
|
||||
_email:
|
||||
_follow:
|
||||
title: "ಹಿಂಬಾಲಿಸಿದರು"
|
||||
_mfm:
|
||||
search: "ಹುಡುಕು"
|
||||
_sfx:
|
||||
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
||||
_widgets:
|
||||
|
@@ -129,6 +129,7 @@ unblockConfirm: "이 계정의 차단을 해제하시겠습니까?"
|
||||
suspendConfirm: "이 계정을 정지하시겠습니까?"
|
||||
unsuspendConfirm: "이 계정의 정지를 해제하시겠습니까?"
|
||||
selectList: "리스트 선택"
|
||||
selectChannel: "채널 선택"
|
||||
selectAntenna: "안테나 선택"
|
||||
selectWidget: "위젯 선택"
|
||||
editWidgets: "위젯 편집"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "이것보다 과거의 기록이 없습니다"
|
||||
startMessaging: "대화 시작하기"
|
||||
nUsersRead: "{n}명이 읽음"
|
||||
agreeTo: "{0}에 동의"
|
||||
agreeBelow: "아래 내용에 동의합니다"
|
||||
basicNotesBeforeCreateAccount: "기본적인 주의사항"
|
||||
tos: "이용 약관"
|
||||
start: "시작하기"
|
||||
home: "홈"
|
||||
@@ -464,7 +467,8 @@ youHaveNoGroups: "그룹이 없습니다"
|
||||
joinOrCreateGroup: "다른 그룹의 초대를 받거나, 직접 새 그룹을 만들어 보세요."
|
||||
noHistory: "기록이 없습니다"
|
||||
signinHistory: "로그인 기록"
|
||||
disableAnimatedMfm: "움직임이 있는 MFM을 비활성화"
|
||||
enableAdvancedMfm: "고급 MFM을 활성화"
|
||||
enableAnimatedMfm: "움직임이 있는 MFM을 활성화"
|
||||
doing: "잠시만요"
|
||||
category: "카테고리"
|
||||
tags: "태그"
|
||||
@@ -861,6 +865,8 @@ failedToFetchAccountInformation: "계정 정보를 가져오지 못했습니다"
|
||||
rateLimitExceeded: "요청 제한 횟수를 초과하였습니다"
|
||||
cropImage: "이미지 자르기"
|
||||
cropImageAsk: "이미지를 자르시겠습니까?"
|
||||
cropYes: "잘라내기"
|
||||
cropNo: "그대로 사용"
|
||||
file: "파일"
|
||||
recentNHours: "최근 {n}시간"
|
||||
recentNDays: "최근 {n}일"
|
||||
@@ -939,6 +945,12 @@ cannotPerformTemporaryDescription: "조작 횟수 제한을 초과하여 일시
|
||||
preset: "프리셋"
|
||||
selectFromPresets: "프리셋에서 선택"
|
||||
achievements: "도전 과제"
|
||||
gotInvalidResponseError: "서버의 응답이 올바르지 않습니다"
|
||||
gotInvalidResponseErrorDescription: " 서버가 다운되었거나 점검중일 가능성이 있습니다. 잠시후에 다시 시도해 주십시오."
|
||||
thisPostMayBeAnnoying: "이 게시물은 다른 유저에게 피해를 줄 가능성이 있습니다."
|
||||
thisPostMayBeAnnoyingHome: "홈에 게시"
|
||||
thisPostMayBeAnnoyingCancel: "그만두기"
|
||||
thisPostMayBeAnnoyingIgnore: "이대로 게시"
|
||||
_achievements:
|
||||
earnedAt: "달성 일시"
|
||||
_types:
|
||||
@@ -1195,6 +1207,9 @@ _role:
|
||||
baseRole: "기본 역할"
|
||||
useBaseValue: "기본값 사용"
|
||||
chooseRoleToAssign: "할당할 역할 선택"
|
||||
iconUrl: "아이콘 URL"
|
||||
asBadge: "뱃지로 표시"
|
||||
descriptionOfAsBadge: "활성화하면 유저명 옆에 역할의 아이콘이 표시됩니다."
|
||||
canEditMembersByModerator: "모더레이터의 역할 수정 허용"
|
||||
descriptionOfCanEditMembersByModerator: "이 옵션을 켜면 모더레이터도 이 역할에 사용자를 할당하거나 삭제할 수 있습니다. 꺼져 있으면 관리자만 할당이 가능합니다."
|
||||
priority: "우선순위"
|
||||
@@ -1320,72 +1335,6 @@ _nsfw:
|
||||
respect: "열람주의로 설정된 미디어 숨기기"
|
||||
ignore: "열람 주의 미디어 항상 표시"
|
||||
force: "미디어 항상 숨기기"
|
||||
_mfm:
|
||||
cheatSheet: "MFM 도움말"
|
||||
intro: "MFM는 Misskey의 다양한 곳에서 사용할 수 있는 전용 마크업 언어입니다. 여기에서는 MFM에서 사용할 수 있는 구문을 확인할 수 있습니다."
|
||||
dummy: "Misskey로 연합우주의 세계가 펼쳐집니다"
|
||||
mention: "멘션"
|
||||
mentionDescription: "골뱅이표(@) 뒤에 사용자명을 넣어 특정 유저를 나타낼 수 있습니다."
|
||||
hashtag: "해시태그"
|
||||
hashtagDescription: "샵 또는 우물정자(#)를 앞에 붙여서 해시태그를 나타낼 수 있습니다."
|
||||
url: "URL"
|
||||
urlDescription: "URL을 나타낼 수 있습니다."
|
||||
link: "링크"
|
||||
linkDescription: "문장의 특정 범위를 URL로 표시합니다."
|
||||
bold: "굵음/볼드체"
|
||||
boldDescription: "문자를 굵게 강조합니다."
|
||||
small: "눈에 띄지 않음"
|
||||
smallDescription: "내용을 작고 연하게 보이게 합니다."
|
||||
center: "가운데 정렬"
|
||||
centerDescription: "내용을 가운데 정렬로 보이게 합니다."
|
||||
inlineCode: "코드(인라인)"
|
||||
inlineCodeDescription: "여러 행의 코드를 문법 강조를 적용하여 인라인으로 표시합니다."
|
||||
blockCode: "코드(블록)"
|
||||
blockCodeDescription: "여러 행의 코드를 문법 강조를 적용하여 블록으로 표시합니다."
|
||||
inlineMath: "수식(인라인)"
|
||||
inlineMathDescription: "수식(KaTeX)를 인라인으로 보이게 합니다."
|
||||
blockMath: "수식(블록)"
|
||||
blockMathDescription: "여러 줄의 수식(KaTeX)를 블록으로 보이게 합니다."
|
||||
quote: "인용"
|
||||
quoteDescription: "내용을 인용문으로 표시합니다."
|
||||
emoji: "커스텀 이모지"
|
||||
emojiDescription: "커스텀 이모지의 이름을 쌍점(:)으로 감싸서 커스텀 이모지를 사용합니다."
|
||||
search: "검색"
|
||||
searchDescription: "주어진 키워드가 입력된 검색창을 보이게 합니다."
|
||||
flip: "플립"
|
||||
flipDescription: "내용을 상하 또는 좌우로 반전시킵니다."
|
||||
jelly: "애니메이션 (젤리)"
|
||||
jellyDescription: "젤리처럼 탱글탱글한 느낌의 효과를 줍니다."
|
||||
tada: "애니메이션 (짠!)"
|
||||
tadaDescription: "짠! 하는 느낌의 효과를 줍니다."
|
||||
jump: "애니메이션(점프)"
|
||||
jumpDescription: "펄쩍 뛸 듯한 느낌의 효과를 줍니다."
|
||||
bounce: "애니메이션 (바운스)"
|
||||
bounceDescription: "통통 튀는 느낌의 효과를 줍니다."
|
||||
shake: "애니메이션 (부들부들)"
|
||||
shakeDescription: "부들부들 떠는 느낌의 효과를 줍니다."
|
||||
twitch: "애니메이션 (경련)"
|
||||
twitchDescription: "격하게 흔들리는 느낌의 효과를 줍니다."
|
||||
spin: "애니메이션 (회전)"
|
||||
spinDescription: "회전 효과를 줍니다."
|
||||
x2: "크게"
|
||||
x2Description: "내용을 크게 표시합니다."
|
||||
x3: "더 크게"
|
||||
x3Description: "내용을 더 크게 표시합니다."
|
||||
x4: "매우 크게"
|
||||
x4Description: "내용을 매우 크게 표시합니다."
|
||||
blur: "흐림"
|
||||
blurDescription: "내용이 흐리게 보입니다. 마우스를 위에 올려두면 내용이 보입니다."
|
||||
font: "폰트"
|
||||
fontDescription: "내용의 글꼴을 지정할 수 있습니다."
|
||||
rainbow: "무지개"
|
||||
rainbowDescription: "내용을 무지개로 표시합니다."
|
||||
sparkle: "반짝반짝"
|
||||
sparkleDescription: "반짝이는 파티클 효과를 추가합니다."
|
||||
rotate: "회전"
|
||||
rotateDescription: "지정한 각도로 회전시킵니다."
|
||||
plain: "평문"
|
||||
plainDescription: "안에 있는 MFM 구문을 모두 무시하고 평문으로 표시합니다."
|
||||
_instanceTicker:
|
||||
none: "보이지 않음"
|
||||
remote: "리모트 유저에게만 보이기"
|
||||
@@ -1590,12 +1539,15 @@ _permissions:
|
||||
"read:gallery-likes": "갤러리의 좋아요를 확인합니다"
|
||||
"write:gallery-likes": "갤러리에 좋아요를 추가하거나 취소합니다"
|
||||
_auth:
|
||||
shareAccessTitle: "어플리케이션의 접근 허가"
|
||||
shareAccess: "\"{name}\" 이 계정에 접근하는 것을 허용하시겠습니까?"
|
||||
shareAccessAsk: "이 애플리케이션이 계정에 접근하는 것을 허용하시겠습니까?"
|
||||
permission: "{name}에서 다음 권한을 요청하였습니다"
|
||||
permissionAsk: "이 앱은 다음의 권한을 요청합니다"
|
||||
pleaseGoBack: "앱으로 돌아가서 시도해 주세요"
|
||||
callback: "앱으로 돌아갑니다"
|
||||
denied: "접근이 거부되었습니다"
|
||||
pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오."
|
||||
_antennaSources:
|
||||
all: "모든 노트"
|
||||
homeTimeline: "팔로우중인 유저의 노트"
|
||||
@@ -1866,5 +1818,6 @@ _deck:
|
||||
tl: "타임라인"
|
||||
antenna: "안테나"
|
||||
list: "리스트"
|
||||
channel: "채널"
|
||||
mentions: "받은 멘션"
|
||||
direct: "다이렉트"
|
||||
|
239
locales/lo-LA.yml
Normal file
239
locales/lo-LA.yml
Normal file
@@ -0,0 +1,239 @@
|
||||
---
|
||||
_lang_: "ພາສາລາວ"
|
||||
headlineMisskey: "ເຊື່ອມຕໍ່ເຄືອຂ່າຍໂດຍຫມາຍເຫດ"
|
||||
introMisskey: "ຍິນດີຕ້ອນຮັບ! Misskey ເປັນແຫຼ່ງເປີດ, ການບໍລິການ microblogging ກະຈາຍ\nສ້າງ \"ບັນທຶກ\" ເພື່ອແບ່ງປັນຄວາມຄິດຂອງທ່ານກັບທຸກໆຄົນທີ່ຢູ່ອ້ອມຮອບທ່ານ 📡\nດ້ວຍ \"ປະຕິກິລິຍາ\", ທ່ານຍັງສາມາດສະແດງຄວາມຮູ້ສຶກຂອງທ່ານຢ່າງໄວວາກ່ຽວກັບບັນທຶກຂອງທຸກໆຄົນ 👍\nມາສຳຫຼວດໂລກໃໝ່! 🚀"
|
||||
poweredByMisskeyDescription: "{name} ແມ່ນສ່ວນໜຶ່ງຂອງການບໍລິການທີ່ຂັບເຄື່ອນໂດຍແພລດຟອມ open source. <b>Misskey</b> (ເອີ້ນວ່າ \"Misskey instance\")"
|
||||
monthAndDay: "{ເດືອນ}/{ມື້}"
|
||||
search: "ຄົ້ນຫາ"
|
||||
notifications: "ການແຈ້ງເຕືອນ"
|
||||
username: "ຊື່ຜູ້ໃຊ້"
|
||||
password: "ລະຫັດຜ່ານ"
|
||||
forgotPassword: "ລືມລະຫັດຜ່ານ"
|
||||
fetchingAsApObject: "ກຳລັງດຶງຂໍ້ມູນຈາກ fediverse..."
|
||||
ok: "ຕົກລົງ"
|
||||
gotIt: "ເຂົ້າໃຈແລ້ວ!"
|
||||
cancel: "ຍົກເລີກ"
|
||||
noThankYou: "ບໍ່ແມ່ນຕອນນີ້"
|
||||
enterUsername: "ປ້ອນຊື່ຜູ້ໃຊ້"
|
||||
renotedBy: "Renoted ໂດຍ {ຜູ້ໃຊ້}"
|
||||
noNotes: "ບໍ່ມີຫມາຍເຫດ"
|
||||
noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
|
||||
instance: "ອີນສະແຕນ"
|
||||
settings: "ກຳນົດຄ່າ"
|
||||
basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
|
||||
otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
|
||||
openInWindow: "ເປີດຢູ່ໃນປ່ອງຢ້ຽມ"
|
||||
profile: "ໂພຼຟາຍ"
|
||||
timeline: "ເສັ້ນກຳນົດເວລາ"
|
||||
noAccountDescription: "ຜູ້ໃຊ້ນີ້ຍັງບໍ່ໄດ້ຂຽນໃນຊີວະປະຫວັດຂອງເຂົາເຈົ້າເທື່ອ"
|
||||
login: "ເຂົ້າສູ່ລະບົບ"
|
||||
loggingIn: "ກຳລັງເຂົ້າສູ່ລະບົບ..."
|
||||
logout: "ອອກຈາກລະບົບ"
|
||||
signup: "ລົງທະບຽນ"
|
||||
uploading: "ການອັບໂຫຼດ..."
|
||||
save: "ບັນທຶກ"
|
||||
users: "ຜູ້ໃຊ້ຕ່າງໆ"
|
||||
addUser: "ເພີ່ມຜູ້ໃຊ້"
|
||||
favorite: "ເພີ່ມໃສ່ລາຍການທີ່ມັກ"
|
||||
favorites: "ລາຍການທີ່ມັກ"
|
||||
unfavorite: "ລຶບອອກຈາກລາຍການທີ່ມັກ"
|
||||
favorited: "ເພີ່ມໃສ່ລາຍການທີ່ມັກແລ້ວ"
|
||||
alreadyFavorited: "ເພີ່ມເຂົ້າໃນລາຍການທີ່ມັກແລ້ວ."
|
||||
cantFavorite: "ບໍ່ສາມາດເພີ່ມໃສ່ລາຍການທີ່ມັກໄດ້."
|
||||
pin: "ປັກໝຸດໄປຫາໂປຣໄຟລ໌"
|
||||
unpin: "ຖອດປັກໝຸດອອກຈາກໂປຣໄຟລ໌"
|
||||
copyContent: "ຄັດລອກເນື້ອຫາ"
|
||||
copyLink: "ສຳເນົາລິ້ງ"
|
||||
delete: "ລຶບ"
|
||||
deleteAndEdit: "ລົບແລະແກ້ໄຂ"
|
||||
deleteAndEditConfirm: "ເຈົ້າແນ່ໃຈບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
|
||||
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
|
||||
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
|
||||
copyRSS: "ສຳເນົາ RSS"
|
||||
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
|
||||
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
|
||||
reply: "ຕອບໄປທີ"
|
||||
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
|
||||
showMore: "ໂຫຼດເພີ່ມເຕີມ"
|
||||
showLess: "ປິດ"
|
||||
youGotNewFollower: "ໄດ້ຕິດຕາມທ່ານ"
|
||||
receiveFollowRequest: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍທີ່ໄດ້ຮັບ"
|
||||
followRequestAccepted: "ຜູ້ຕິດຕາມໄດ້ຍອມຮັບຄໍາຮ້ອງຂໍຂອງທ່ານ"
|
||||
mention: "ໄດ້ກ່າວມາ"
|
||||
mentions: "ກ່າວເຖິງ"
|
||||
directNotes: "ໂດຍກົງຫມາຍເຫດ"
|
||||
importAndExport: "ນໍາເຂົ້າ / ສົ່ງອອກ"
|
||||
import: "ນຳເຂົ້າ"
|
||||
export: "ນຳອອກ"
|
||||
files: "ໄຟລ໌"
|
||||
download: "ດາວໂຫລດ"
|
||||
driveFileDeleteConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບໄຟລ໌ \"{name}\"? ບັນທຶກທີ່ມີໄຟລ໌ແນບນີ້ຈະຖືກລຶບຖິ້ມ"
|
||||
unfollowConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການເຊົາຕິດຕາມ {name}?"
|
||||
exportRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການສົ່ງອອກ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ ແລະມັນຈະຖືກເພີ່ມໃສ່ drive ຂອງທ່ານເມື່ອມັນສຳເລັດແລ້ວ"
|
||||
importRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການນໍາເຂົ້າ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ"
|
||||
lists: "ລາຍການ"
|
||||
noLists: "ທ່ານບໍ່ມີລາຍການໃດໆ"
|
||||
note: "ບັນທຶກ"
|
||||
notes: "ບັນທຶກ"
|
||||
following: "ກຳລັງຕິດຕາມ"
|
||||
followers: "ຜູ້ຕິດຕາມ"
|
||||
followsYou: "ຕິດຕາມເຈົ້າ"
|
||||
createList: "ສ້າງລາຍຊື່"
|
||||
manageLists: "ການບໍລິຫານບັນຊີລາຍການ"
|
||||
error: "ຂໍ້ຜິດພາດ"
|
||||
somethingHappened: "ອຸຍ, ມີບາງຢ່າງຜິດພາດ"
|
||||
retry: "ລອງໃຫມ່"
|
||||
pageLoadError: "ເກີດຄວາມຜິດພາດໃນການໂຫລດໜ້ານີ້"
|
||||
pageLoadErrorDescription: "ປົກກະຕິແລ້ວມັນເກີດຈາກຄວາມຜິດພາດເຄືອຂ່າຍ ຫຼື cache ຂອງຕົວທ່ອງເວັບ ລອງລຶບລ້າງແຄດແລ້ວລອງໃໝ່ພາຍຫຼັງສອງສາມນາທີ"
|
||||
serverIsDead: "ເຊີບເວີນີ້ບໍ່ຕອບສະໜອງ ກະລຸນາລໍຖ້າຈັກໜ່ອຍແລ້ວລອງໃໝ່ອີກຄັ້ງ"
|
||||
youShouldUpgradeClient: "ເພື່ອເບິ່ງໜ້ານີ້, ກະລຸນາໂຫຼດຂໍ້ມູນຄືນໃໝ່ເພື່ອອັບເດດລູກຄ້າຂອງທ່ານ"
|
||||
enterListName: "ໃສ່ຊື່ສຳລັບລາຍຊື່"
|
||||
privacy: "ຄວາມເປັນສ່ວນຕົວ"
|
||||
makeFollowManuallyApprove: "ປະຕິບັດຕາມການຮ້ອງຂໍຮຽກຮ້ອງໃຫ້ມີການອະນຸມັດ"
|
||||
defaultNoteVisibility: "ເປັນຄ່າເລີ່ມຕົ້ນ"
|
||||
follow: "ກຳລັງຕິດຕາມ"
|
||||
followRequest: "ສົ່ງການຮ້ອງຂໍປະຕິບຕາມ"
|
||||
followRequests: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍ"
|
||||
unfollow: "ເຊົາຕິດຕາມ"
|
||||
followRequestPending: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍທີ່ລໍຖ້າຢູ່"
|
||||
enterEmoji: "ປ້ອນອີໂມຈິ"
|
||||
renote: "Renote"
|
||||
unrenote: "ເລີກ Renote"
|
||||
renoted: "ເກັບບັນທຶກໄວ້"
|
||||
quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
|
||||
pinnedNote: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
|
||||
pinned: "ປັກໝຸດໄປຫາໂປຣໄຟລ໌"
|
||||
you: "ເຈົ້າ"
|
||||
clickToShow: "ກົດເພື່ອສະແດງໃຫ້ເຫັນ"
|
||||
sensitive: "NSFW"
|
||||
add: "ເພີ່ມ"
|
||||
reaction: "ປະຕິກິລິຍາ"
|
||||
reactions: "ປະຕິກິລິຍາ"
|
||||
mute: "ປີດສຽງ"
|
||||
unmute: "ເປີດສຽງ"
|
||||
block: "ບ໋ອກ"
|
||||
unblock: "ຍົກເລີກກາຮົບລັອກ"
|
||||
suspend: "ລະງັບ"
|
||||
unsuspend: "ເຊົາລະງັບ"
|
||||
selectList: "ເລືອກບັນຊີລາຍການ"
|
||||
selectWidget: "ເລືອກວິກເຈັດ"
|
||||
editWidgets: "ແກ້ໄຂ Widget"
|
||||
editWidgetsExit: "ສຳເລັດແລ້ວ"
|
||||
customEmojis: "ອີໂມຈິແບບກຳນົດເອງ"
|
||||
emoji: "ອີໂມຈິ"
|
||||
emojis: "ອີໂມຈິ"
|
||||
emojiName: "ຊື່ Emoji"
|
||||
emojiUrl: "URL ອີໂມຈິ"
|
||||
addEmoji: "ຕື່ມອີໂມຈິ"
|
||||
flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
|
||||
flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
|
||||
flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
|
||||
flagShowTimelineReplies: "ສະແດງການຕອບກັບໃນທາມລາຍ"
|
||||
flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບຂອງຜູ້ໃຊ້ຕໍ່ກັບບັນທຶກຂອງຜູ້ໃຊ້ອື່ນໃນທາມລາຍຖ້າເປີດໃຊ້ງານ"
|
||||
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
|
||||
addAccount: "ເພີ່ມບັນຊີ"
|
||||
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
|
||||
general: "ທົ່ວໄປ"
|
||||
wallpaper: "ພາບພື້ນຫລັງ"
|
||||
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
|
||||
instances: "ອີນສະແຕນ"
|
||||
instanceInfo: "ອີນສະແຕນ"
|
||||
statistics: "ສະຖິຕິ"
|
||||
clearQueue: "ລ້າງຄິວ"
|
||||
clearCachedFiles: "ລຶບລ້າງແຄສ"
|
||||
editProfile: "ແກ້ໄຂໂປຣໄຟລ໌"
|
||||
done: "ສຳເລັດ"
|
||||
processing: "ກຳລັງປະມວນຜົນ"
|
||||
preview: "ສະແດງເປັນຕົວຢ່າງ"
|
||||
default: "ຄ່າເລີ່ມຕົ້ນ"
|
||||
blocked: "ບລັອກແລ້ວ "
|
||||
all: "ທັງໝົດ"
|
||||
subscribing: "ສະໝັກສະມາຊິກແລັວ"
|
||||
publishing: "ການພິມເຜີຍແຜ່"
|
||||
notResponding: "ບໍ່ຕອບສະໜອງ"
|
||||
instanceFollowing: "ກຳລັງຕິດຕາມສຸດຕົວຢ່າງ"
|
||||
instanceFollowers: "ຜູ້ຕິດຕາມຕົວຢ່າງ"
|
||||
instanceUsers: "ຜູ້ຊົມໃຊ້ຂອງຕົວຢ່າງນີ້"
|
||||
changePassword: "ປ່ຽນລະຫັດຜ່ານ"
|
||||
featured: "ໄຮໄລທ໌"
|
||||
announcements: "ປະກາດ"
|
||||
remove: "ລຶບ"
|
||||
messaging: "ແຊ໋ດ"
|
||||
tos: "ເງື່ອນໄຂການໃຫ້ບໍລິການ"
|
||||
start: "ເລີ່ມຕົ້ນນຳໃຊ້ເລີຍ"
|
||||
home: "ໜ້າຫຼັກ"
|
||||
images: "ຮູບພາບ"
|
||||
birthday: "ວັນເກີດ"
|
||||
registeredDate: "ວັນທີ່ເປັນສະມາຊິກ"
|
||||
location: "ທີ່ຕັ້ງ"
|
||||
theme: "ແທ໋ມ"
|
||||
light: "ສະຫວ່າງ"
|
||||
dark: "ມືດ"
|
||||
lightThemes: "ຊຸດຮູບແບບສະຫວ່າງ"
|
||||
darkThemes: "ຮູບແບບສີສັນມືດ"
|
||||
fileName: "ຊື່ໄຟລ໌"
|
||||
selectFile: "ເລືອກໄຟລ໌"
|
||||
selectFiles: "ເລືອກໄຟລ໌"
|
||||
nsfw: "NSFW"
|
||||
accept: "ອະນຸຍາດ"
|
||||
pinnedNotes: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
|
||||
userList: "ລາຍການ"
|
||||
smtpUser: "ຊື່ຜູ້ໃຊ້"
|
||||
smtpPass: "ລະຫັດຜ່ານ"
|
||||
clearCache: "ລຶບລ້າງແຄສ"
|
||||
user: "ຜູ້ໃຊ້ຕ່າງໆ"
|
||||
searchByGoogle: "ຄົ້ນຫາ"
|
||||
file: "ໄຟລ໌"
|
||||
_email:
|
||||
_follow:
|
||||
title: "ໄດ້ຕິດຕາມທ່ານ"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "ໄດ້ກ່າວມາ"
|
||||
renote: "Renote"
|
||||
_sfx:
|
||||
note: "ບັນທຶກ"
|
||||
notification: "ການແຈ້ງເຕືອນ"
|
||||
chat: "ແຊ໋ດ"
|
||||
_widgets:
|
||||
profile: "ໂພຼຟາຍ"
|
||||
instanceInfo: "ອີນສະແຕນ"
|
||||
notifications: "ການແຈ້ງເຕືອນ"
|
||||
timeline: "ເສັ້ນກຳນົດເວລາ"
|
||||
_userList:
|
||||
chooseList: "ເລືອກບັນຊີລາຍການ"
|
||||
_cw:
|
||||
show: "ໂຫຼດເພີ່ມເຕີມ"
|
||||
_visibility:
|
||||
home: "ໜ້າຫຼັກ"
|
||||
followers: "ຜູ້ຕິດຕາມ"
|
||||
_profile:
|
||||
username: "ຊື່ຜູ້ໃຊ້"
|
||||
_exportOrImport:
|
||||
followingList: "ກຳລັງຕິດຕາມ"
|
||||
muteList: "ປີດສຽງ"
|
||||
blockingList: "ບ໋ອກ"
|
||||
userLists: "ລາຍການ"
|
||||
_timelines:
|
||||
home: "ໜ້າຫຼັກ"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "ຮູບພາບ"
|
||||
_notification:
|
||||
youWereFollowed: "ໄດ້ຕິດຕາມທ່ານ"
|
||||
_types:
|
||||
follow: "ກຳລັງຕິດຕາມ"
|
||||
mention: "ໄດ້ກ່າວມາ"
|
||||
renote: "Renote"
|
||||
quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
|
||||
reaction: "ປະຕິກິລິຍາ"
|
||||
_actions:
|
||||
reply: "ຕອບໄປທີ"
|
||||
renote: "Renote"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "ການແຈ້ງເຕືອນ"
|
||||
tl: "ເສັ້ນກຳນົດເວລາ"
|
||||
list: "ລາຍການ"
|
||||
channel: "ຊ່ອງ"
|
||||
mentions: "ກ່າວເຖິງ"
|
@@ -427,11 +427,6 @@ loggedInAsBot: "Momenteel als bot ingelogd"
|
||||
_email:
|
||||
_follow:
|
||||
title: "volgde jou"
|
||||
_mfm:
|
||||
mention: "Vermelding"
|
||||
quote: "Quote"
|
||||
emoji: "Maatwerk emoji"
|
||||
search: "Zoeken"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Vermelding"
|
||||
|
@@ -461,7 +461,6 @@ youHaveNoGroups: "Nie masz żadnych grup"
|
||||
joinOrCreateGroup: "Uzyskaj zaproszenie do dołączenia do grupy lub utwórz własną grupę."
|
||||
noHistory: "Brak historii"
|
||||
signinHistory: "Historia logowania"
|
||||
disableAnimatedMfm: "Wyłącz MFM z animacją"
|
||||
doing: "Przetwarzanie..."
|
||||
category: "Kategoria"
|
||||
tags: "Tagi"
|
||||
@@ -958,68 +957,6 @@ _nsfw:
|
||||
respect: "Ukrywaj media NSFW"
|
||||
ignore: "Nie ukrywaj mediów NSFW"
|
||||
force: "Ukrywaj wszystkie media"
|
||||
_mfm:
|
||||
cheatSheet: "Ściąga MFM"
|
||||
intro: "MFM to język składniowy wyjątkowy dla Misskey, który może być użyty w wielu miejscach. Tu znajdziesz listę wszystkich możliwych elementów składni MFM."
|
||||
dummy: "Misskey rozszerza świat Fediwersum"
|
||||
mention: "Wspomnij"
|
||||
mentionDescription: "Używając znaku @ i nazwy użytkownika, możesz określić danego użytkownika."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Używając kratki i tekstu, możesz określić hashtag."
|
||||
url: "Adres URL"
|
||||
urlDescription: "Adresy URL mogą być wyświetlane"
|
||||
link: "Odnośnik"
|
||||
linkDescription: "Określone części tekstu mogą być wyświetlane jako adres URL."
|
||||
bold: "Pogrubienie"
|
||||
boldDescription: "Wyróżnia litery pogrubiając je."
|
||||
small: "Małe"
|
||||
smallDescription: "Wyświetla treść jako małą i cienką."
|
||||
center: "Wyśrodkowanie"
|
||||
centerDescription: "Wyśrodkowuje zawartość."
|
||||
inlineCode: "Kod (w wierszu)"
|
||||
blockCode: "Kod (blok)"
|
||||
blockCodeDescription: "Wyświetla kod z podświetlaną składnią składający się z wielu linii."
|
||||
blockMath: "Matematyka (Blok)"
|
||||
quote: "Cytuj"
|
||||
quoteDescription: "Wyświetla treść jako cytat."
|
||||
emoji: "Niestandardowe emoji"
|
||||
emojiDescription: "Otaczając nazwę niestandardowego emoji dwukropkami, możesz użyć niestandardowego emoji."
|
||||
search: "Szukaj"
|
||||
searchDescription: "Wyświetla pole wyszukiwania z wcześniej wpisanym tekstem."
|
||||
flip: "Odwróć"
|
||||
flipDescription: "Przerzuca treść poziomo lub pionowo."
|
||||
jelly: "Animacja (Galaretka)"
|
||||
jellyDescription: "Nadaje treści galaretowatą animację."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Nadaje treści animację podobną do \"Tada!\"."
|
||||
jump: "Animacja (Skok)"
|
||||
jumpDescription: "Nadaje treści animację skakania."
|
||||
bounce: "Animacja (Odbijanie)"
|
||||
bounceDescription: "Nadaje treści animację odbijania się."
|
||||
shake: "Animacja (Wstrząsanie)"
|
||||
shakeDescription: "Nadaje treści animację wstrząsania."
|
||||
twitch: "Animacja (Drganie)"
|
||||
twitchDescription: "Nadaje treści mocno drgającą animację."
|
||||
spin: "Animacja (Obrót)"
|
||||
spinDescription: "Nadaje treści animację obracania."
|
||||
x2: "Duże"
|
||||
x2Description: "Czyni treść większą."
|
||||
x3: "Bardzo duże"
|
||||
x3Description: "Czyni treść jeszcze większą."
|
||||
x4: "Ogromne"
|
||||
x4Description: "Czyni treść jeszcze większą niż jeszcze większa."
|
||||
blur: "Rozmycie"
|
||||
blurDescription: "Rozmywa treść. Zostanie wyraźnie wyświetlona po najechaniu."
|
||||
font: "Czcionka"
|
||||
fontDescription: "Wybiera czcionkę do wyświetlania treści."
|
||||
rainbow: "Tęcza"
|
||||
rainbowDescription: "Sprawia, że zawartość pojawia się w kolorach tęczy."
|
||||
sparkle: "Blask"
|
||||
sparkleDescription: "Nadaje zawartości efekt lśniącego brokatu."
|
||||
rotate: "Obróć"
|
||||
rotateDescription: "Obraca zawartość o określony kąt."
|
||||
plain: "Zwyczajny"
|
||||
plainDescription: "Wyłącza efekty wszystkich MFM zawartych w tym efekcie MFM."
|
||||
_instanceTicker:
|
||||
none: "Nigdy nie pokazuj"
|
||||
remote: "Pokaż dla zdalnych użytkowników"
|
||||
@@ -1438,5 +1375,6 @@ _deck:
|
||||
tl: "Oś czasu"
|
||||
antenna: "Anteny"
|
||||
list: "Listy"
|
||||
channel: "Kanały"
|
||||
mentions: "Wspomnienia"
|
||||
direct: "Bezpośredni"
|
||||
|
@@ -475,11 +475,6 @@ file: "Ficheiros"
|
||||
_email:
|
||||
_follow:
|
||||
title: "Você tem um novo seguidor"
|
||||
_mfm:
|
||||
mention: "Menção"
|
||||
quote: "Citar"
|
||||
emoji: "Emoji personalizado"
|
||||
search: "Buscar"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Menção"
|
||||
|
@@ -455,7 +455,6 @@ youHaveNoGroups: "Nu ai niciun grup"
|
||||
joinOrCreateGroup: "Primește o invitație într-un grup sau creează unul nou."
|
||||
noHistory: "Nu există istoric"
|
||||
signinHistory: "Istoric autentificări"
|
||||
disableAnimatedMfm: "Dezactivează MFM cu animații"
|
||||
doing: "Se procesează..."
|
||||
category: "Categorie"
|
||||
tags: "Etichete"
|
||||
@@ -655,11 +654,6 @@ _role:
|
||||
_email:
|
||||
_follow:
|
||||
title: "te-a urmărit"
|
||||
_mfm:
|
||||
mention: "Mențiune"
|
||||
quote: "Citează"
|
||||
emoji: "Emoji personalizat"
|
||||
search: "Caută"
|
||||
_theme:
|
||||
description: "Descriere"
|
||||
keys:
|
||||
@@ -721,4 +715,5 @@ _deck:
|
||||
tl: "Cronologie"
|
||||
antenna: "Antene"
|
||||
list: "Liste"
|
||||
channel: "Canale"
|
||||
mentions: "Mențiuni"
|
||||
|
@@ -22,7 +22,7 @@ instance: "Инстанс"
|
||||
settings: "Настройки"
|
||||
basicSettings: "Основные настройки"
|
||||
otherSettings: "Прочие настройки"
|
||||
openInWindow: "Открывать в плавающих окнах"
|
||||
openInWindow: "Открыть в плавающем окне"
|
||||
profile: "Профиль"
|
||||
timeline: "Лента"
|
||||
noAccountDescription: "Пользователь ничего не написал про себя"
|
||||
@@ -273,7 +273,7 @@ light: "Светлый"
|
||||
dark: "Тёмный"
|
||||
lightThemes: "Светлые темы"
|
||||
darkThemes: "Тёмные темы"
|
||||
syncDeviceDarkMode: "Синхронизировать с темным режимом устройства"
|
||||
syncDeviceDarkMode: "Синхронизировать с тёмной темой системы"
|
||||
drive: "Диск"
|
||||
fileName: "Имя файла"
|
||||
selectFile: "Выберите файл"
|
||||
@@ -456,12 +456,12 @@ uiLanguage: "Язык интерфейса"
|
||||
groupInvited: "Приглашение в группу"
|
||||
aboutX: "Описание {x}"
|
||||
emojiStyle: "Стиль эмодзи"
|
||||
native: "Системные"
|
||||
disableDrawer: "Не использовать выдвижные меню"
|
||||
youHaveNoGroups: "У вас нет ни одной группы"
|
||||
joinOrCreateGroup: "Получайте приглашения в группы или создавайте свои собственные"
|
||||
noHistory: "История пока пуста"
|
||||
signinHistory: "Журнал посещений"
|
||||
disableAnimatedMfm: "Отключение анимированной разметки MFM"
|
||||
doing: "В процессе"
|
||||
category: "Категория"
|
||||
tags: "Метки"
|
||||
@@ -603,6 +603,7 @@ smtpSecureInfo: "Выключите при использовании STARTTLS."
|
||||
testEmail: "Проверка доставки электронной почты"
|
||||
wordMute: "Скрытие слов"
|
||||
regexpError: "Ошибка в регулярном выражении"
|
||||
regexpErrorDescription: "В списке {tab} скрытых слов, в строке {line} обнаружена синтаксическая ошибка:"
|
||||
instanceMute: "Глушение инстансов"
|
||||
userSaysSomething: "{name} что-то сообщает"
|
||||
makeActive: "Активировать"
|
||||
@@ -804,7 +805,7 @@ translate: "Перевод"
|
||||
translatedFrom: "Перевод. Язык оригинала — {x}"
|
||||
accountDeletionInProgress: "В настоящее время выполняется удаление учетной записи"
|
||||
usernameInfo: "Имя, которое отличает вашу учетную запись от других на этом сервере. Вы можете использовать алфавит (a~z, A~Z), цифры (0~9) или символы подчеркивания (_). Имена пользователей не могут быть изменены позже."
|
||||
aiChanMode: "ИИ режим"
|
||||
aiChanMode: "Режим Ай"
|
||||
keepCw: "Сохраняйте Предупреждения о содержимом"
|
||||
pubSub: "Учётные записи Pub/Sub"
|
||||
lastCommunication: "Последнее сообщение"
|
||||
@@ -821,8 +822,8 @@ manageAccounts: "Управление аккаунтом"
|
||||
makeReactionsPublic: "Опубликовать список реакций"
|
||||
makeReactionsPublicDescription: "Список сделанных вами реакций доступен для просмотра всем желающим."
|
||||
classic: "Классика"
|
||||
muteThread: "Заглушить цепочку"
|
||||
unmuteThread: "Отменить глушение цепочки"
|
||||
muteThread: "Скрыть цепочку"
|
||||
unmuteThread: "Отменить сокрытие цепочки"
|
||||
ffVisibility: "Видимость подписок и подписчиков"
|
||||
ffVisibilityDescription: "Здесь можно настроить, кто будет видеть ваши подписки и подписчиков."
|
||||
continueThread: "Показать следующие ответы"
|
||||
@@ -891,6 +892,7 @@ cannotUploadBecauseNoFreeSpace: "Файл не может быть загруж
|
||||
beta: "Бета"
|
||||
enableAutoSensitive: "Автоматическое определение NSFW"
|
||||
enableAutoSensitiveDescription: "Если доступно, используйте машинное обучение для автоматической установки флага NSFW на носителе. Даже если эта функция отключена, она может быть установлена автоматически в зависимости от инстанта."
|
||||
activeEmailValidationDescription: "Если включено, будет проводиться более строгая проверка адреса электронной почты, в том числе на то, что он действительный и не временный. Если же отключено, то проверяется только корректность написания адреса."
|
||||
navbar: "Панель навигации"
|
||||
shuffle: "Перемешать"
|
||||
account: "Учётные записи"
|
||||
@@ -1096,6 +1098,9 @@ _achievements:
|
||||
title: "Я люблю Misskey"
|
||||
description: "Написана заметка «I ❤ #Misskey»"
|
||||
flavor: "Спасибо за поддержку Misskey! Ваша команда разработчиков"
|
||||
_foundTreasure:
|
||||
title: "Охота за сокровищами"
|
||||
description: "Найдено спрятанное сокровище"
|
||||
_client30min:
|
||||
title: "Перерыв на обед"
|
||||
description: "Прошло 30 минут с момента запуска клиента"
|
||||
@@ -1116,6 +1121,9 @@ _achievements:
|
||||
_htl20npm:
|
||||
title: "В потоке"
|
||||
description: "Достигнута скорость домашней ленты в 20 з/мин (заметок минуту)"
|
||||
_viewInstanceChart:
|
||||
title: "Аналитик"
|
||||
description: "Просмотрены статистические диаграммы инстанса"
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "Привет, мир!"
|
||||
description: "Выведен текст «hello world» в Когтеточке"
|
||||
@@ -1189,7 +1197,34 @@ _role:
|
||||
middle: "Средне"
|
||||
high: "Высокий"
|
||||
_options:
|
||||
gtlAvailable: "Может просматривать глобальную ленту"
|
||||
ltlAvailable: "Может просматривать местную ленту"
|
||||
canPublicNote: "Может публиковать общедоступные заметки"
|
||||
canInvite: "Может создавать пригласительные коды"
|
||||
canManageCustomEmojis: "Управлять пользовательскими эмодзи"
|
||||
driveCapacity: "Доступное пространство на «диске»"
|
||||
pinMax: "Доступное количество закреплённых заметок"
|
||||
antennaMax: "Доступное количество антенн"
|
||||
wordMuteMax: "Доступное количество знаков в списке скрытия слов"
|
||||
clipMax: "Максимальное количество подборок"
|
||||
noteEachClipsMax: "Максимальное количество заметок в подборке"
|
||||
userListMax: "Максимальное количество списков аккаунтов"
|
||||
userEachUserListsMax: "Максимальное количество аккаунтов в списке"
|
||||
rateLimitFactor: "Ограничение активности"
|
||||
descriptionOfRateLimitFactor: "Меньшее значение — слабые ограничения, большее — сильные"
|
||||
canHideAds: "Может скрыть рекламу"
|
||||
_condition:
|
||||
isLocal: "Местный"
|
||||
isRemote: "Неместный"
|
||||
createdLessThan: "Аккаунт младше, чем..."
|
||||
createdMoreThan: "Аккаунт старше, чем..."
|
||||
followersLessThanOrEq: "Количество подписчиков не превышает…"
|
||||
followersMoreThanOrEq: "Количество подписчиков не меньше чем…"
|
||||
followingLessThanOrEq: "Количество подписок не превышает…"
|
||||
followingMoreThanOrEq: "Количество подписок не меньше чем…"
|
||||
and: "Выполнено несколько условий:.."
|
||||
or: "Выполнено любое из условий:.."
|
||||
not: "Кроме тех, у кого…"
|
||||
_sensitiveMediaDetection:
|
||||
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
|
||||
setSensitiveFlagAutomatically: "Установить флаг NSFW"
|
||||
@@ -1237,10 +1272,23 @@ _plugin:
|
||||
installWarn: "Пожалуйста, не устанавливайте расширения, которым не доверяете."
|
||||
manage: "Управление расширениями"
|
||||
_preferencesBackups:
|
||||
saveConfirm: "Сохранить бэкап как {name}?"
|
||||
deleteConfirm: "Удалить резервную копию {name}?"
|
||||
renameConfirm: "Переименовать резервную копию с \"{old}\" на \"{new}\"?"
|
||||
noBackups: "Резервной копии не существует. Вы можете создать резервную копию в настройках на этом инстансе с помощью \"Создать новую резервную копию\"."
|
||||
list: "Существующие резервные копии"
|
||||
saveNew: "Создать резервную копию"
|
||||
loadFile: "Прочесть из файла"
|
||||
apply: "Восстановить на это устройство"
|
||||
save: "Обновить из текущих настроек"
|
||||
inputName: "Введите название для резервной копии"
|
||||
cannotSave: "Сохранить не удалось"
|
||||
nameAlreadyExists: "Резервная копия под названием «{name}» уже существует. Придумайте другое."
|
||||
applyConfirm: "Правда хотите загрузить резервную копию «{name}» на это устройство? Этим будут потеряны текущие настройки."
|
||||
saveConfirm: "Сохранить резервную копию под названием «{name}»?"
|
||||
deleteConfirm: "Удалить резервную копию «{name}»?"
|
||||
renameConfirm: "Переименовать резервную копию «{old}» в «{new}»?"
|
||||
noBackups: "Здесь ещё нет резервных копий. Вы можете создать резервную копию настроек на этом сайте с помощью кнопки «Создать резервную копию»."
|
||||
createdAt: "Создана {date} в {time}"
|
||||
updatedAt: "Обновлена {date} в {time}"
|
||||
cannotLoad: "Загрузить не удалось"
|
||||
invalidFile: "Некорректный формат файла"
|
||||
_registry:
|
||||
scope: "Область"
|
||||
key: "Ключ"
|
||||
@@ -1260,70 +1308,6 @@ _nsfw:
|
||||
respect: "Скрывать содержимое не для всех"
|
||||
ignore: "Показывать содержимое не для всех"
|
||||
force: "Скрывать вообще все файлы"
|
||||
_mfm:
|
||||
cheatSheet: "Подсказка по разметке MFM"
|
||||
intro: "MFM — язык оформления текста, который придуман специально для Misskey и готов для применения во многих местах. На этой странице собраны и кратко изложены способы его использовать."
|
||||
dummy: "Misskey расширяет границы Федиверса."
|
||||
mention: "Упоминание"
|
||||
mentionDescription: "При помощи знака «собака» перед именем можно упомянуть какого-нибудь пользователя."
|
||||
hashtag: "Хэштег"
|
||||
hashtagDescription: "При помощи знака «решётка» перед словом задаётся хэштег."
|
||||
url: "Простая ссылка (URL)"
|
||||
urlDescription: "Ссылки могут отображаться непосредственно."
|
||||
link: "Ссылка с пояснением"
|
||||
linkDescription: "Можно ссылку оформить в виде произвольного текста."
|
||||
bold: "Жирный шрифт"
|
||||
boldDescription: "Выделяет текст, делая буквы жирнее."
|
||||
small: "Мелкий шрифт"
|
||||
smallDescription: "Делает текст маленьким и незаметным."
|
||||
center: "Выровнять элементы по центру"
|
||||
centerDescription: "Так можно выровнять что-то по центру."
|
||||
inlineCode: "Программа (в тексте)"
|
||||
inlineCodeDescription: "Подсвечивает фрагмент программы внутри сплошного текста."
|
||||
blockCode: "Программа (блок)"
|
||||
blockCodeDescription: "Оформляет текст программы в виде отдельного блокоа. Он может состоять из множества строк."
|
||||
inlineMath: "Математическое выражение (в тексте)"
|
||||
inlineMathDescription: "Позволяет вставлять математические выражения внутрь текста при помощи языка KaTeX."
|
||||
blockMath: "Математическое выражение (блок)"
|
||||
blockMathDescription: "Оформляет математическое выражение (KaTeX) на отдельной строке."
|
||||
quote: "Цитата"
|
||||
quoteDescription: "Так можно процитировать чей-то текст."
|
||||
emoji: "Собственные эмодзи"
|
||||
emojiDescription: "Можно вставить эмодзи в текст, окружив название двоеточиями."
|
||||
search: "Поиск"
|
||||
searchDescription: "Можно добавить форму для поиска, сразу задав, что искать."
|
||||
flip: "Переворот"
|
||||
flipDescription: "Позволяет отразить текст зеркально по вертикали или горизонтали."
|
||||
jelly: "Анимация желе (шлёп-плёп)"
|
||||
jellyDescription: "Напоминает горку джема, дёргающуюся от шлепков."
|
||||
tada: "Анимация (та-дам!)"
|
||||
tadaDescription: "Получается нечто выпрыгивающее, как бы крича: «а вот и я!»"
|
||||
jump: "Анимация прыжков (прыг-скок)"
|
||||
jumpDescription: "Побуждает радостно подпрыгивать."
|
||||
bounce: "Анимация отскоков (бум-бум)"
|
||||
bounceDescription: "Это будет скакать как мяч."
|
||||
shake: "Анимация дрожи (б-р-р-р)"
|
||||
shakeDescription: "Такое дрожит, словно от холода. Или от страха."
|
||||
twitch: "Анимация тряски"
|
||||
twitchDescription: "Заставляет трястись как одержимого"
|
||||
spin: "Вращение"
|
||||
spinDescription: "Так можно крутить содержимое в разных направлениях."
|
||||
x2: "Крупный шрифт"
|
||||
x2Description: "Увеличивает содержимое."
|
||||
x3: "Ещё крупнее"
|
||||
x3Description: "Сильнее увеличивает содержимое."
|
||||
x4: "Совсем крупно"
|
||||
x4Description: "Увеличивает содержимое совсем сильно."
|
||||
blur: "Размытие"
|
||||
blurDescription: "Размывает текст до нечитаемости, будто его поместили за матовое стекло. Наведение указателя мыши на размытый текст возвращает чёткость."
|
||||
font: "Шрифт"
|
||||
fontDescription: "Так можно писать произвольным шрифтом."
|
||||
rainbow: "Радуга"
|
||||
rainbowDescription: "Заставлять содержимое отображаться в цветах радуги."
|
||||
sparkle: "Искры"
|
||||
sparkleDescription: "Добавляет эффект искрящихся частиц."
|
||||
rotate: "Повернуть"
|
||||
rotateDescription: "Поворачивает на заданный угол."
|
||||
_instanceTicker:
|
||||
none: "Не показывать"
|
||||
remote: "Только для других сайтов"
|
||||
@@ -1353,12 +1337,14 @@ _wordMute:
|
||||
muteWordsDescription2: "Здесь можно использовать регулярные выражения — просто заключите их между двумя дробными чертами (/)."
|
||||
softDescription: "Соответствующие условиям заметки будут спрятаны из вашей ленты."
|
||||
hardDescription: "Соответстующие условиям заметки вообще не будут попадать в вашу ленту. Даже если вы поменяете условия, отсеенные таким образом заметки уже не появятся."
|
||||
soft: "Мягкий"
|
||||
hard: "Жёсткий"
|
||||
soft: "Мягко"
|
||||
hard: "Жёстко"
|
||||
mutedNotes: "Скрытые заметки"
|
||||
_instanceMute:
|
||||
instanceMuteDescription: "Заметки и репосты с указанных здесь инстансов, а также ответы пользователям оттуда же не будут отображаться."
|
||||
instanceMuteDescription2: "Пишите каждый инстанс на отдельной строке"
|
||||
title: "Скрывает заметки с заданных инстансов."
|
||||
heading: "Список заглушенных инстансов"
|
||||
heading: "Список скрытых инстансов"
|
||||
_theme:
|
||||
explore: "Обзор"
|
||||
install: "Установить тему"
|
||||
@@ -1479,12 +1465,16 @@ _tutorial:
|
||||
step7_1: "На этом вводный урок по использованию Misskey закончен. Спасибо, что прошли его до конца!"
|
||||
step7_2: "Хотите изучить Misskey глубже — добро пожаловать в раздел «{help}»."
|
||||
step7_3: "Приятно вам провести время с Misskey🚀"
|
||||
step8_1: "Ах, да, не хотите ли включить push-уведомления?"
|
||||
step8_2: "С push-уведомлениями вы будете в курсе репостов, ответов, реакций и всего такого, даже когда закрыли Misskey."
|
||||
step8_3: "Эту настройку вы всегда сможете поменять"
|
||||
_2fa:
|
||||
alreadyRegistered: "Двухфакторная аутентификация уже настроена."
|
||||
registerDevice: "Зарегистрируйте ваше устройство"
|
||||
registerKey: "Зарегистрировать ключ"
|
||||
step1: "Прежде всего, установите на устройство приложение для аутентификации, например, {a} или {b}."
|
||||
step2: "Далее отсканируйте отображаемый QR-код при помощи приложения."
|
||||
step2Url: "Если пользуетесь приложением на компьютере, можете ввести в него эту строку (URL):"
|
||||
step3: "И наконец, введите код, который покажет приложение."
|
||||
step4: "Теперь при каждом входе на сайт вам нужно будет вводить код из приложения аналогичным образом."
|
||||
securityKeyInfo: "Вы можете настроить вход с помощью аппаратного ключа безопасности, поддерживающего FIDO2, или отпечатка пальца или PIN-кода на устройстве."
|
||||
@@ -1501,7 +1491,7 @@ _permissions:
|
||||
"write:following": "Изменять спискок подписок"
|
||||
"read:messaging": "Смотреть сообщения"
|
||||
"write:messaging": "Писать и удалять сообщения"
|
||||
"read:mutes": "Смотреть спискок скрытых пользователей"
|
||||
"read:mutes": "Смотреть список скрытых пользователей"
|
||||
"write:mutes": "Изменять список скрытых пользователей"
|
||||
"write:notes": "Писать и удалять заметки"
|
||||
"read:notifications": "Смотреть уведомления"
|
||||
@@ -1552,10 +1542,13 @@ _widgets:
|
||||
trends: "Актуальное"
|
||||
clock: "Часы"
|
||||
rss: "Просмотр RSS"
|
||||
rssTicker: "Бегущая строка RSS"
|
||||
activity: "Активность"
|
||||
photos: "Фото"
|
||||
digitalClock: "Цифровые часы"
|
||||
unixClock: "Часы UNIX"
|
||||
federation: "Федерация"
|
||||
instanceCloud: "Облако инстансов"
|
||||
postForm: "Форма отправки"
|
||||
slideshow: "Показ слайдов"
|
||||
button: "Кнопка"
|
||||
@@ -1563,9 +1556,12 @@ _widgets:
|
||||
jobQueue: "Очередь заданий"
|
||||
serverMetric: "Показатели сервера"
|
||||
aiscript: "Консоль AiScript"
|
||||
aiscriptApp: "Приложение на AiScript"
|
||||
aichan: "Ай"
|
||||
userList: "Список аккаунтов"
|
||||
_userList:
|
||||
chooseList: "Выберите список"
|
||||
clicker: "Счётчик щелчков"
|
||||
_cw:
|
||||
hide: "Спрятать"
|
||||
show: "Показать еще"
|
||||
@@ -1628,12 +1624,13 @@ _profile:
|
||||
changeAvatar: "Поменять аватар"
|
||||
changeBanner: "Поменять изображение в шапке"
|
||||
_exportOrImport:
|
||||
allNotes: "Все записи\n"
|
||||
allNotes: "Все заметки\n"
|
||||
favoritedNotes: "Избранное"
|
||||
followingList: "Подписки"
|
||||
muteList: "Скрытые"
|
||||
blockingList: "Заблокированные"
|
||||
userLists: "Списки"
|
||||
excludeMutingUsers: "За исключением заглушенных пользователей"
|
||||
excludeMutingUsers: "За исключением скрытых пользователей"
|
||||
excludeInactiveUsers: "Без неактивных учётных записей"
|
||||
_charts:
|
||||
federation: "Федерация"
|
||||
@@ -1737,6 +1734,8 @@ _notification:
|
||||
youReceivedFollowRequest: "У вас новый запрос на подписку."
|
||||
yourFollowRequestAccepted: "Ваш запрос на подписку одобрен."
|
||||
youWereInvitedToGroup: "Вы приглашены в группу."
|
||||
pollEnded: "Подведены окончательные итоги опроса"
|
||||
emptyPushNotificationMessage: "Обновлены push-уведомления"
|
||||
achievementEarned: "Получено достижение"
|
||||
_types:
|
||||
all: "Все"
|
||||
@@ -1746,11 +1745,13 @@ _notification:
|
||||
renote: "Репосты"
|
||||
quote: "Цитаты"
|
||||
reaction: "Реакции"
|
||||
pollEnded: "Окончания опросов"
|
||||
receiveFollowRequest: "Получен запрос на подписку"
|
||||
followRequestAccepted: "Запрос на подписку одобрен"
|
||||
groupInvited: "Приглашение в группы"
|
||||
app: "Уведомления из приложений"
|
||||
_actions:
|
||||
followBack: "отвечает взаимной подпиской"
|
||||
reply: "Ответить"
|
||||
renote: "Репост"
|
||||
_deck:
|
||||
@@ -1764,7 +1765,12 @@ _deck:
|
||||
swapDown: "Переставить ниже"
|
||||
stackLeft: "В столбик влево"
|
||||
popRight: "Из столбика вправо"
|
||||
profile: "Профиль"
|
||||
profile: "Расстановка"
|
||||
newProfile: "Новая расстановка"
|
||||
deleteProfile: "Удаление расстановки"
|
||||
introduction: "Создайте идеальный интерфейс расставляя колонки как угодно"
|
||||
introduction2: "Чтобы добавлять колонки в любом месте, жмите «+» справа экрана."
|
||||
widgetsIntroduction: "Чтобы добавлять виджеты, выбирайте «Редактировать виджеты» в меню колонки."
|
||||
_columns:
|
||||
main: "Основная"
|
||||
widgets: "Виджеты"
|
||||
@@ -1772,5 +1778,6 @@ _deck:
|
||||
tl: "Лента"
|
||||
antenna: "Антенны"
|
||||
list: "Списки"
|
||||
channel: "Каналы"
|
||||
mentions: "Упоминания"
|
||||
direct: "Личное"
|
||||
|
@@ -464,7 +464,6 @@ youHaveNoGroups: "Nemáte žiadne skupiny"
|
||||
joinOrCreateGroup: "Požiadajte o pozvanie do existujúcej skupiny alebo vytvorte novú."
|
||||
noHistory: "Žiadna história"
|
||||
signinHistory: "História prihlásení"
|
||||
disableAnimatedMfm: "Vypnúť MFM s animáciou"
|
||||
doing: "Pracujem..."
|
||||
category: "Kategórie"
|
||||
tags: "Značky"
|
||||
@@ -1013,72 +1012,6 @@ _nsfw:
|
||||
respect: "Skryť NSFW médiá"
|
||||
ignore: "Neskrývať NSFW médiá"
|
||||
force: "Skryť všetky médiá"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM je Misskey exkluzívny značkovací jazyk, ktorý sa dá používať na viacerých miestach. Tu môžete vidieť zoznam všetkej dostupnej MFM syntaxe."
|
||||
dummy: "Misskey rozširuje svet Fediverza"
|
||||
mention: "Zmienka"
|
||||
mentionDescription: "Používateľa spomeniete použítím zavináča a mena používateľa"
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Môžete zadať hashtag použitím mriežky a textu"
|
||||
url: "URL"
|
||||
urlDescription: "URL sa dajú zobraziť."
|
||||
link: "Odkaz"
|
||||
linkDescription: "Jednotlivé časti texty sa dajú zobraziť ako URL."
|
||||
bold: "Tučné"
|
||||
boldDescription: "Zvýrazní písmená tým, že budú tučnejšie."
|
||||
small: "Malé"
|
||||
smallDescription: "Zobrazí obsah malý a tenký."
|
||||
center: "Vystrediť prvky"
|
||||
centerDescription: "Zobrazí obsah v strede"
|
||||
inlineCode: "Kód (inline)"
|
||||
inlineCodeDescription: "Zobrazí kód so zvýraznením syntaxe."
|
||||
blockCode: "Kód (blok)"
|
||||
blockCodeDescription: "Zobrazí viacriadkový kód so zvýraznením syntaxe v bloku."
|
||||
inlineMath: "Vzorec (inline)"
|
||||
inlineMathDescription: "Zobrazí matematický vzorec (KaTeX) v riadku."
|
||||
blockMath: "Vzorec (blok)"
|
||||
blockMathDescription: "Zobrazí viacriadkový matematický vzorec (KaTeX) v bloku"
|
||||
quote: "Citovať"
|
||||
quoteDescription: "Zobrazí obsah ako citát."
|
||||
emoji: "Vlastné emoji"
|
||||
emojiDescription: "Pridaním dvojbodiek pred a za názov vlastnej emoji, sa dá zobraziť vlastná emoji."
|
||||
search: "Hľadať"
|
||||
searchDescription: "Zobrazí vyhľadávacie pole so zadaným textom."
|
||||
flip: "Preklopiť"
|
||||
flipDescription: "Preklopí obsah horizontálne alebo vertikálne"
|
||||
jelly: "Animácia (želé)"
|
||||
jellyDescription: "Obsah sa bude hýbať ako želé."
|
||||
tada: "Animácia (tadá)"
|
||||
tadaDescription: "Obsah sa bude hýbať ako Tada!"
|
||||
jump: "Animácia (skok)"
|
||||
jumpDescription: "Obsah skočí."
|
||||
bounce: "Animácia (odraz)"
|
||||
bounceDescription: "Obsah sa bude odrážať."
|
||||
shake: "Animácia (trasenie)"
|
||||
shakeDescription: "Obsah sa bude triasť."
|
||||
twitch: "Animácia (myknutie)"
|
||||
twitchDescription: "Obsahu dá animáciu silného trasenia."
|
||||
spin: "Animácia (rotácia)"
|
||||
spinDescription: "Obsahu pridá otáčajúcu animáciu."
|
||||
x2: "Veľký"
|
||||
x2Description: "Zobrazí obsah väčší."
|
||||
x3: "Veľmi veľký"
|
||||
x3Description: "Zobrazí obsah ešte väčší."
|
||||
x4: "Neuveriteľne veľký"
|
||||
x4Description: "Zobrazí obsah ešte viac veľký než veľmi veľký."
|
||||
blur: "Rozmazanie"
|
||||
blurDescription: "Týmto efektom môže byť obsah rozmazaný. Zaostrí sa keď ned neho príde kurzor."
|
||||
font: "Písmo"
|
||||
fontDescription: "Nastaví písmo, ktorým sa zobrazí text."
|
||||
rainbow: "Dúha"
|
||||
rainbowDescription: "Zobrazí obsah vo farbách dúhy."
|
||||
sparkle: "Trblietky"
|
||||
sparkleDescription: "Obsahu dodá trblietajúci efekt."
|
||||
rotate: "Otáčať"
|
||||
rotateDescription: "Otočí obsah o určitý uhol."
|
||||
plain: "Obyčajné"
|
||||
plainDescription: "Bez akejkoľvej syntaxe"
|
||||
_instanceTicker:
|
||||
none: "Nikdy nezobrazovať"
|
||||
remote: "Zobraziť pre vzdialených používateľov"
|
||||
@@ -1545,5 +1478,6 @@ _deck:
|
||||
tl: "Časová os"
|
||||
antenna: "Antény"
|
||||
list: "Zoznam"
|
||||
channel: "Kanály"
|
||||
mentions: "Zmienky"
|
||||
direct: "Priame poznámky"
|
||||
|
@@ -371,11 +371,6 @@ pushNotificationNotSupported: "Din webbläsare eller instans har inte stöd för
|
||||
_email:
|
||||
_follow:
|
||||
title: "följde dig"
|
||||
_mfm:
|
||||
mention: "Nämn"
|
||||
quote: "Citat"
|
||||
emoji: "Anpassa emoji"
|
||||
search: "Sök"
|
||||
_channel:
|
||||
setBanner: "Välj banner"
|
||||
removeBanner: "Ta bort banner"
|
||||
|
@@ -129,6 +129,7 @@ unblockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต
|
||||
suspendConfirm: "นายแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
|
||||
unsuspendConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการยกเลิกการระงับบัญชีนี้"
|
||||
selectList: "เลือกรายการ"
|
||||
selectChannel: "เลือกแชนแนล"
|
||||
selectAntenna: "เลือกเสาอากาศ"
|
||||
selectWidget: "เลือกวิดเจ็ต"
|
||||
editWidgets: "แก้ไขวิดเจ็ต"
|
||||
@@ -464,7 +465,6 @@ youHaveNoGroups: "คุณยังไม่มีกลุ่ม"
|
||||
joinOrCreateGroup: "รับเชิญเข้าร่วมกลุ่มหรือสร้างกลุ่มของคุณเองเลยนะ"
|
||||
noHistory: "ไม่มีรายการ"
|
||||
signinHistory: "ประวัติการเข้าสู่ระบบ"
|
||||
disableAnimatedMfm: "ปิดการใช้งาน MFM ด้วยแอนิเมชั่น"
|
||||
doing: "กำลังประมวลผล......"
|
||||
category: "หมวดหมู่"
|
||||
tags: "แท็ก"
|
||||
@@ -939,53 +939,243 @@ cannotPerformTemporaryDescription: "การดําเนินการน
|
||||
preset: "พรีเซ็ต"
|
||||
selectFromPresets: "เลือกจากการพรีเซ็ต"
|
||||
achievements: "ความสำเร็จ"
|
||||
gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
|
||||
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
|
||||
_achievements:
|
||||
earnedAt: "ได้รับเมื่อ"
|
||||
_types:
|
||||
_notes1:
|
||||
title: "เพียงแค่ตั้งค่า msky ของฉัน"
|
||||
description: "โพสต์โน้ตครั้งแรกของคุณ"
|
||||
flavor: "ขอให้มีช่วงเวลาที่ดีกับ Misskey นะคะ!"
|
||||
_notes10:
|
||||
title: "โน้ตบางอย่าง"
|
||||
description: "โพสต์ 10 โน้ต"
|
||||
_notes100:
|
||||
title: "โน้ตจำนวนมาก"
|
||||
description: "โพสต์ 100 โน้ต"
|
||||
_notes500:
|
||||
title: "ครอบคลุมในโน้ต"
|
||||
description: "โพสต์ 500 โน้ต"
|
||||
_notes1000:
|
||||
title: "ภูเขาแห่งโน้ต"
|
||||
description: "โพสต์ 1,000 โน้ต"
|
||||
_notes5000:
|
||||
title: "โน้ตล้น"
|
||||
description: "โพสต์ 5,000 โน้ต"
|
||||
_notes10000:
|
||||
title: "ซุปเปอร์โน้ต"
|
||||
description: "โพสต์ 10,000 โน้ต"
|
||||
_notes20000:
|
||||
title: "ต้องการ... เพิ่มเติม... โน้ต..."
|
||||
description: "โพสต์ 20,000 โน้ต"
|
||||
_notes30000:
|
||||
title: "โน้ต โน้ต โน้ต!"
|
||||
description: "โพสต์ 30,000 โน้ต"
|
||||
_notes40000:
|
||||
title: "โน้ตโรงงาน"
|
||||
description: "โพสต์ 40,000 โน้ต"
|
||||
_notes50000:
|
||||
title: "ดาวเคราะห์แห่งโน้ต"
|
||||
description: "โพสต์ 50,000 โน้ต"
|
||||
_notes60000:
|
||||
title: "โน้ตควอซาร์"
|
||||
description: "โพสต์ 60,000 โน้ต"
|
||||
_notes70000:
|
||||
title: "โน้ตหลุมดำ"
|
||||
description: "โพสต์ 70,000 โน้ต"
|
||||
_notes80000:
|
||||
title: "โน้ต กาแล็กซี่"
|
||||
description: "โพสต์ 80,000 โน้ต"
|
||||
_notes90000:
|
||||
title: "โน้ต จักรวาล"
|
||||
description: "โพสต์ 90,000 โน้ต"
|
||||
_notes100000:
|
||||
title: "ALL YOUR NOTE ARE BELONG TO US"
|
||||
description: "โพสต์ 100,000 โน้ต"
|
||||
flavor: "นายแน่ใจล่ะก็ มีอะไรพูดมาได้นะ"
|
||||
_login3:
|
||||
title: "มือใหม่ I"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 3 วัน"
|
||||
flavor: "เริ่มตั้งแต่วันนี้ เรียกฉันว่ามิสคิสต์"
|
||||
_login7:
|
||||
title: "มือใหม่ II"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 7 วัน"
|
||||
flavor: "รู้สึกเหมือนคุณได้แขวนของสิ่งต่างๆ หรือยังคะ?"
|
||||
_login15:
|
||||
title: "มือใหม่ III"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 15 วัน"
|
||||
_login30:
|
||||
title: "มิสคิสท์ I"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 30 วัน"
|
||||
_login60:
|
||||
title: "มิสคิสท์ II"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 60 วัน"
|
||||
_login100:
|
||||
title: "มิสคิสท์ III"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 100 วัน"
|
||||
flavor: "ความรุนแรง Misskist"
|
||||
_login200:
|
||||
title: "ลูกค้าประจำ I"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 200 วัน"
|
||||
_login300:
|
||||
title: "ลูกค้าประจำ II"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 300 วัน"
|
||||
_login400:
|
||||
title: "ลูกค้าประจำ III"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 400 วัน"
|
||||
_login500:
|
||||
title: "ผู้เชี่ยวชาญ I"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 500 วัน"
|
||||
flavor: "เพื่อนของผมนะมักจะกล่าวว่าผมนะชอบจดโน้ต"
|
||||
_login600:
|
||||
title: "ผู้เชี่ยวชาญ II"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 600 วัน"
|
||||
_login700:
|
||||
title: "ผู้เชี่ยวชาญ III"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 700 วัน"
|
||||
_login800:
|
||||
title: "ปรมาจารย์ด้านโน้ต I"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 800 วัน"
|
||||
_login900:
|
||||
title: "ปรมาจารย์ด้านโน้ต II"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 900 วัน"
|
||||
_login1000:
|
||||
title: "ปรมาจารย์ด้านโน้ต III"
|
||||
description: "เข้าสู่ระบบเป็นเวลารวม 1,000 วัน"
|
||||
flavor: "ขอบคุณที่ใช้ Misskey นะ !"
|
||||
_noteClipped1:
|
||||
title: "จะต้อง... คลิป..."
|
||||
description: "คลิปโน้ตตัวแรกของคุณ"
|
||||
_noteFavorited1:
|
||||
title: "สตาร์เกเซอร์"
|
||||
description: "ชื่นชอบโน้ตแรกของคุณ"
|
||||
_myNoteFavorited1:
|
||||
title: "แสวงหาดวงดาว"
|
||||
description: "มีคนอื่นๆที่ชื่นชอบหนึ่งในโน้ตของคุณ"
|
||||
_profileFilled:
|
||||
title: "เตรียมไว้อย่างดี"
|
||||
description: "ตั้งค่าโปรไฟล์ของคุณ"
|
||||
_markedAsCat:
|
||||
title: "ฉันเป็นแมว"
|
||||
description: "ทำเครื่องหมายบัญชีของคุณว่าเป็นแมว"
|
||||
flavor: "ฉันจะให้ชื่อคุณภายหลังนะ"
|
||||
_following1:
|
||||
title: "กำลังติดตามผู้ใช้คนแรกของคุณ"
|
||||
description: "ติดตามผู้ใช้"
|
||||
_following10:
|
||||
title: "ทำต่อไป... ทำต่อไป..."
|
||||
description: "ติดตาม 10 บัญชีผู้ใช้"
|
||||
_following50:
|
||||
title: "มีเพื่อนมากมาย"
|
||||
description: "ติดตาม 50 บัญชี"
|
||||
_following100:
|
||||
title: "เพื่อน 100 คน"
|
||||
description: "ติดตาม 100 บัญชี"
|
||||
_following300:
|
||||
title: "เพื่อนโอเวอร์โหลด"
|
||||
description: "ติดตาม 300 บัญชี"
|
||||
_followers1:
|
||||
title: "ผู้ติดตามคนแรก"
|
||||
description: "ได้รับ 1 ผู้ติดตาม"
|
||||
_followers10:
|
||||
title: "ติดตามฉัน!"
|
||||
description: "ได้รับ 10 คนผู้ติดตาม"
|
||||
_followers50:
|
||||
title: "มากันเป็นฝูง"
|
||||
description: "ได้รับ 50 ผู้ติดตาม"
|
||||
_followers100:
|
||||
title: "บุคคลที่เป็นที่นิยม"
|
||||
description: "ได้รับ 100 ผู้ติดตาม"
|
||||
_followers300:
|
||||
title: "กรุณาสร้างบรรทัดเดียวนะคะ"
|
||||
description: "ได้รับ 300 คนผู้ติดตาม"
|
||||
_followers500:
|
||||
title: "เสาสัญญาณ"
|
||||
description: "ได้รับ 500 คนผู้ติดตาม"
|
||||
_followers1000:
|
||||
title: "ผู้ทรงอิทธิพล"
|
||||
description: "ได้รับ 1,000 ผู้ติดตาม"
|
||||
_collectAchievements30:
|
||||
title: "นักสะสมความสำเร็จ"
|
||||
description: "ได้รับความสำเร็จ 30 ครั้ง"
|
||||
_viewAchievements3min:
|
||||
title: "ชอบบรรลุผลสําเร็จ"
|
||||
description: "มองดูรายการความสำเร็จของคุณเป็นเวลาอย่างน้อย 3 นาที"
|
||||
_iLoveMisskey:
|
||||
title: "ฉันรัก Misskey"
|
||||
description: "โพสต์ \"I ❤ #Misskey\""
|
||||
flavor: "ทีมผู้พัฒนา Misskey ได้ขอบคุณสำหรับการสนับสนุนของคุณ!"
|
||||
_foundTreasure:
|
||||
title: "ล่าสมบัติ"
|
||||
description: "คุณพบสมบัติที่ซ่อนอยู่"
|
||||
_client30min:
|
||||
title: "พักผ่อนสักหน่อย"
|
||||
description: "ใช้เวลา 30 นาทีบน Misskey"
|
||||
_noteDeletedWithin1min:
|
||||
title: "ไม่เป็นไร"
|
||||
description: "ลบโน้ตภายในหนึ่งนาทีหลังจากที่โพสต์"
|
||||
_postedAtLateNight:
|
||||
title: "กลางคืน"
|
||||
description: "โพสต์โน้ตตอนดึกๆ"
|
||||
flavor: "ได้เวลาเข้านอนแล้วนะ"
|
||||
_postedAt0min0sec:
|
||||
title: "นาฬิกาพูดได้"
|
||||
description: "โพสต์บนโน้ตเมื่อเวลา 00:00 น."
|
||||
flavor: "คลิก คลิก คลิก แกล๊งๆ"
|
||||
_selfQuote:
|
||||
title: "อ้างอิงตนเอง"
|
||||
description: "อ้างโน้ตย่อของคุณเอง"
|
||||
_htl20npm:
|
||||
title: "ไทม์ไลน์ไหล"
|
||||
description: "มีการทำความเร็วของไทม์ไลน์ที่บ้านของคุณเกิน 20 npm (โน้ตต่อนาที)"
|
||||
_viewInstanceChart:
|
||||
title: "วิเคราะห์"
|
||||
description: "ดูแผนภูมิอินสแตนซ์ของคุณ"
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "หวัดดีชาวโลก!"
|
||||
description: "เอาพุต \"hello world\" ใน Scratchpad"
|
||||
_open3windows:
|
||||
title: "มัลติวินโดว์"
|
||||
description: "มีการเปิดหน้าต่างอย่างน้อย 3 หน้าต่างพร้อมกัน"
|
||||
_driveFolderCircularReference:
|
||||
title: "อ้างอิงวงจร"
|
||||
description: "พยายามสร้างโฟลเดอร์ที่ซ้อนกันแบบวนซ้ำในไดรฟ์"
|
||||
_reactWithoutRead:
|
||||
title: "คุณอ่านมันจริงๆหรือเปล่า?"
|
||||
description: "มีการโต้ตอบกับโน้ตที่มีความยาวมากกว่า 100 ตัวอักษรภายใน 3 วินาทีหลังจากที่โพสต์"
|
||||
_clickedClickHere:
|
||||
title: "คลิ๊กที่นี่"
|
||||
description: "คุณได้คลิกที่นี่"
|
||||
_justPlainLucky:
|
||||
title: "แค่ลัคกี้ธรรมดา"
|
||||
description: "มีโอกาสที่จะได้รับด้วยความน่าจะเป็นไปได้ 0.005% ทุก ๆ 10 วินาที"
|
||||
_setNameToSyuilo:
|
||||
title: "พระเจ้าคอมเพล็กซ์"
|
||||
description: "ตั้งชื่อของคุณเป็น \"syuilo\""
|
||||
_passedSinceAccountCreated1:
|
||||
title: "ครบรอบหนึ่งปี"
|
||||
description: "ผ่านไปหนึ่งปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ"
|
||||
_passedSinceAccountCreated2:
|
||||
title: "ครบรอบสองปี"
|
||||
description: "ผ่านไปสองปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ"
|
||||
_passedSinceAccountCreated3:
|
||||
title: "ครบรอบสามปี"
|
||||
description: "ผ่านไปสามปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ"
|
||||
_loggedInOnBirthday:
|
||||
title: "สุขสันต์วันเกิด"
|
||||
description: "เข้าสู่ระบบในวันเกิดของคุณ"
|
||||
_loggedInOnNewYearsDay:
|
||||
title: "สวัสดีปีใหม่!"
|
||||
description: "เข้าสู่ระบบในวันแรกของปี"
|
||||
flavor: "อีกปีที่ยอดเยี่ยมในโอกาสนี้เลย"
|
||||
_cookieClicked:
|
||||
title: "เกมที่คุณคลิกที่คุกกี้"
|
||||
description: "คลิกคุกกี้"
|
||||
flavor: "เดี๋ยวก่อนนะ คุณอยู่ในเว็บไซต์ที่ถูกต้องแน่อย่างงั้นเหรอ?"
|
||||
_brainDiver:
|
||||
title: "Brain Diver"
|
||||
description: "โพสต์ลิงก์ไปยัง Brain Diver"
|
||||
flavor: "Misskey-Misskey La-Tu-Ma"
|
||||
_role:
|
||||
new: "บทบาทใหม่"
|
||||
@@ -994,7 +1184,7 @@ _role:
|
||||
description: "คำอธิบายบทบาท"
|
||||
permission: "สิทธิ์ตามบทบาท"
|
||||
descriptionOfPermission: "<b>ผู้ดูแลกลั่นกรองเนื้อหา</b> สามารถดำเนินการดูแลขั้นพื้นฐานได้นะ\n<b>ผู้ดูแลระบบ</b> สามารถเปลี่ยนการตั้งค่าทั้งหมดของอินสแตนซ์ได้นะ"
|
||||
assignTarget: "กำหนดเป้าหมาย"
|
||||
assignTarget: "มอบหมาย"
|
||||
descriptionOfAssignTarget: "<b>แมนนวล</b> เพื่อเปลี่ยนผู้ที่เป็นส่วนหนึ่งของบทบาทนี้และใครที่ไม่ใช่ด้วยตนเอง\n<b>เงื่อนไข</b> เพื่อให้ผู้ใช้ได้รับการกำหนดและนำออกจากบทบาทนี้โดยอัตโนมัติตามเงื่อนไขชุดหนึ่ง"
|
||||
manual: "ปรับเอง"
|
||||
conditional: "มีเงื่อนไข"
|
||||
@@ -1007,6 +1197,9 @@ _role:
|
||||
baseRole: "บทบาทพื้นฐาน"
|
||||
useBaseValue: "ใช้บทบาทพื้นฐานเริ่มต้น"
|
||||
chooseRoleToAssign: "เลือกบทบาทที่ต้องการกำหนด"
|
||||
iconUrl: "ไอคอน URL"
|
||||
asBadge: "แสดงเป็นตรา"
|
||||
descriptionOfAsBadge: "ไอคอนของบทบาทนี้จะปรากฏถัดจากชื่อผู้ใช้ของผู้ใช้งานด้วยบทบาทนี้ถ้าหากเปิดใช้งาน"
|
||||
canEditMembersByModerator: "อนุญาตให้ผู้ดูแลแก้ไขสมาชิก"
|
||||
descriptionOfCanEditMembersByModerator: "เมื่อเปิดใช้ ผู้ดูแลนอกเหนือจากผู้ดูแลระบบแล้ว จะสามารถกำหนดและยกเลิกการมอบหมายบทบาทนี้ให้กับผู้ใช้ได้ เมื่อปิด เฉพาะผู้ดูแลระบบเท่านั้นที่จะสามารถกำหนดผู้ใช้ได้นะ"
|
||||
priority: "ลำดับความสำคัญ"
|
||||
@@ -1132,72 +1325,6 @@ _nsfw:
|
||||
respect: "ซ่อนสื่อ NSFW"
|
||||
ignore: "อย่าซ่อนสื่อ NSFW"
|
||||
force: "ซ่อนสื่อทั้งหมด"
|
||||
_mfm:
|
||||
cheatSheet: "โค้ด MFM Cheat Sheet"
|
||||
intro: "MFM เป็นภาษามาร์กอัปพิเศษเฉพาะของ Misskey ที่สามารถใช้ได้ในหลายที่ คุณยังสามารถดูรายการไวยากรณ์ MFM ที่มีอยู่ทั้งหมดได้ที่นี่นะ"
|
||||
dummy: "Misskey ขยายโลกของ Fediverse"
|
||||
mention: "กล่าวถึง"
|
||||
mentionDescription: "คุณสามารถระบุผู้ใช้โดยใช้ At-Symbol และชื่อผู้ใช้ได้นะ"
|
||||
hashtag: "แฮชแท็ก"
|
||||
hashtagDescription: "คุณสามารถระบุชื่อแฮชแท็กได้โดยใช้เครื่องหมายตัวเลขและข้อความได้นะ"
|
||||
url: "URL"
|
||||
urlDescription: "สามารถแสดง URL ได้นะ"
|
||||
link: "ลิงก์"
|
||||
linkDescription: "เจาะจงเฉพาะ ส่วนของข้อความที่สามารถแสดงเป็น URL ได้"
|
||||
bold: "ตัวหนา"
|
||||
boldDescription: "ไฮไลท์ตัวอักษรโดยทำให้หนาขึ้น"
|
||||
small: "ขนาดเล็ก"
|
||||
smallDescription: "แสดงผลเนื้อหาขนาดเล็กและบาง"
|
||||
center: "เซ็นเตอร์"
|
||||
centerDescription: "แสดงผลเนื้อหาเป็นศูนย์กลาง"
|
||||
inlineCode: "โค้ด (อินไลน์)"
|
||||
inlineCodeDescription: "แสดงผลการเน้นไวยากรณ์แบบอินไลน์สำหรับโค้ด (โปรแกรม)"
|
||||
blockCode: "โค้ด (บล็อก)"
|
||||
blockCodeDescription: "แสดงผลการเน้นไวยากรณ์สำหรับโค้ดหลายบรรทัด (โปรแกรม) ในบล็อก"
|
||||
inlineMath: "คณิต (อินไลน์)"
|
||||
inlineMathDescription: "แสดงผลสูตรคณิต (KaTeX) ในบรรทัด"
|
||||
blockMath: "คณิต (บล็อก)"
|
||||
blockMathDescription: "แสดงผลสูตรคณิตหลายบรรทัด (KaTeX) ในบล็อก"
|
||||
quote: "อ้างคำพูด"
|
||||
quoteDescription: "แสดงผลเนื้อหาเป็นใบเสนอราคา"
|
||||
emoji: "กำหนดอีโมจิเอง"
|
||||
emojiDescription: "โดยล้อมรอบชื่ออีโมจิที่กำหนดเองด้วยเครื่องหมายทวิภาค จะสามารถแสดงผลอีโมจิที่กำหนดเองได้"
|
||||
search: "ค้นหา"
|
||||
searchDescription: "แสดงผลกล่องค้นหาพร้อมกับข้อความที่ป้อนไว้ล่วงหน้า"
|
||||
flip: "พลิก"
|
||||
flipDescription: "พลิกเนื้อหาในแนวนอนหรือแนวตั้ง"
|
||||
jelly: "แอนิเมชั่น (เยลลี่)"
|
||||
jellyDescription: "ให้เนื้อหาเป็นแอนิเมชั่นเหมือนเยลลี่"
|
||||
tada: "แอนิเมชั่น (ธาดา)"
|
||||
tadaDescription: "ให้เนื้อหาเป็นแอนิเมชั่นเหมือน \"ทาด้า!\""
|
||||
jump: "อนิเมชั่น (กระโดด)"
|
||||
jumpDescription: "ให้เนื้อหามีภาพเคลื่อนไหวแบบกระโดด"
|
||||
bounce: "อนิเมชั่น (เด้ง)"
|
||||
bounceDescription: "ให้เนื้อหามีอนิเมชั่นเด้ง"
|
||||
shake: "อนิเมชั่น (เขย่า)"
|
||||
shakeDescription: "ให้เนื้อหามีภาพเคลื่อนไหวสั่น"
|
||||
twitch: "แอนิเมชั่น (Twitch)"
|
||||
twitchDescription: "ให้เนื้อหามีแอนิเมชั่นกระตุกอย่างแรง"
|
||||
spin: "แอนิเมชั่น (สปิน)"
|
||||
spinDescription: "ให้เนื้อหาเป็นภาพเคลื่อนไหวแบบหมุน"
|
||||
x2: "ขนาดใหญ่"
|
||||
x2Description: "แสดงเนื้อหาที่ใหญ่ขึ้น"
|
||||
x3: "ใหญ่มาก"
|
||||
x3Description: "แสดงเนื้อหาอีเว้นท์ที่ใหญ่ขึ้น"
|
||||
x4: "ใหญ่อย่างไม่น่าเชื่อ"
|
||||
x4Description: "แสดงผลเนื้อหาที่ใหญ่กว่าใหญ่กว่าขนาดใหญ่"
|
||||
blur: "เบลอ"
|
||||
blurDescription: "เบลอเนื้อหา จะแสดงผลอย่างชัดเจนต่อเมื่อวางเมาส์เหนือ"
|
||||
font: "ตัวอักษร"
|
||||
fontDescription: "ตั้งค่าตัวอักษรเพื่อแสดงเนื้อหาใน"
|
||||
rainbow: "สายรุ้ง"
|
||||
rainbowDescription: "ทำให้เนื้อหานั้นปรากฏเป็นสีรุ้ง"
|
||||
sparkle: "กลิตเตอร์"
|
||||
sparkleDescription: "ให้เนื้อหานั้นมีเอฟเฟกต์แบบอนุภาคประกาย"
|
||||
rotate: "หมุนหน้าจอ"
|
||||
rotateDescription: "เปลี่ยนเนื้อหาตามด้วยมุมที่ระบุไว้"
|
||||
plain: "เรียบง่าย"
|
||||
plainDescription: "ปิดการใช้งานเอฟเฟกต์ของ MFM ทั้งหมดที่มีอยู่ในเอฟเฟกต์ MFM นี้"
|
||||
_instanceTicker:
|
||||
none: "ไม่ต้องแสดง"
|
||||
remote: "แสดงสำหรับผู้ใช้ระยะไกล"
|
||||
@@ -1402,12 +1529,15 @@ _permissions:
|
||||
"read:gallery-likes": "ดูรายการโพสต์ในแกลเลอรีที่ชอบของคุณ"
|
||||
"write:gallery-likes": "แก้ไขรายการโพสต์ในแกลเลอรีที่ชอบของคุณ"
|
||||
_auth:
|
||||
shareAccessTitle: "การให้สิทธิ์แอปพลิเคชัน"
|
||||
shareAccess: "คุณต้องการอนุญาตให้ \"{name}\" เข้าถึงบัญชีนี้เลยมั้ย?"
|
||||
shareAccessAsk: "คุณแน่ใจแล้วจริงๆหรอว่าต้องการอนุญาตให้แอปพลิเคชันนี้เข้าถึงบัญชีของคุณแน่ใจแล้วหรอ?"
|
||||
permission: "{name} ได้ขอสิทธิ์การเข้าถึงดังต่อไปนี้"
|
||||
permissionAsk: "แอปพลิเคชันนี้ขอสิทธิ์ดังต่อไปนี้"
|
||||
pleaseGoBack: "กรุณากลับไปที่แอปพลิเคชัน"
|
||||
callback: "กำลังกลับไปที่แอปพลิเคชัน"
|
||||
denied: "ปฏิเสธการเข้าใช้"
|
||||
pleaseLogin: "กรุณาเข้าสู่ระบบเพื่ออนุมัติแอปพลิเคชัน"
|
||||
_antennaSources:
|
||||
all: "โน้ตทั้งหมด"
|
||||
homeTimeline: "โน้ตจากผู้ใช้ที่ติดตาม"
|
||||
@@ -1678,5 +1808,6 @@ _deck:
|
||||
tl: "ไทม์ไลน์"
|
||||
antenna: "เสาอากาศ"
|
||||
list: "รายการ"
|
||||
channel: "แชนแนล"
|
||||
mentions: "พูดถึง"
|
||||
direct: "ไดเร็ค"
|
||||
|
@@ -48,8 +48,6 @@ smtpUser: "Kullanıcı Adı"
|
||||
smtpPass: "Şifre"
|
||||
user: "Kullanıcı"
|
||||
searchByGoogle: "Arama"
|
||||
_mfm:
|
||||
search: "Arama"
|
||||
_sfx:
|
||||
notification: "Bildirim"
|
||||
_widgets:
|
||||
|
@@ -2,5 +2,3 @@
|
||||
_lang_: "ياپونچە"
|
||||
search: "ئىزدەش"
|
||||
searchByGoogle: "ئىزدەش"
|
||||
_mfm:
|
||||
search: "ئىزدەش"
|
||||
|
@@ -166,7 +166,7 @@ recipient: "Отримувач"
|
||||
annotation: "Коментарі"
|
||||
federation: "Федіверс"
|
||||
instances: "Інстанс"
|
||||
registeredAt: "Приєднався(лась)"
|
||||
registeredAt: "Реєстрація"
|
||||
latestRequestReceivedAt: "Останній запит прийнято"
|
||||
latestStatus: "Останній статус"
|
||||
storageUsage: "Використання простору"
|
||||
@@ -263,7 +263,7 @@ activity: "Активність"
|
||||
images: "Зображення"
|
||||
birthday: "День народження"
|
||||
yearsOld: "{age} років"
|
||||
registeredDate: "Приєднався(лась)"
|
||||
registeredDate: "Приєднання"
|
||||
location: "Локація"
|
||||
theme: "Тема"
|
||||
themeForLightMode: "Світла тема"
|
||||
@@ -461,7 +461,6 @@ youHaveNoGroups: "Немає груп"
|
||||
joinOrCreateGroup: "Отримуйте запрошення до груп або створюйте свої власні групи."
|
||||
noHistory: "Історія порожня"
|
||||
signinHistory: "Історія входів"
|
||||
disableAnimatedMfm: "Відключити анімації MFM"
|
||||
doing: "Виконується"
|
||||
category: "Категорія"
|
||||
tags: "Теги"
|
||||
@@ -529,7 +528,7 @@ state: "Стан"
|
||||
sort: "Сортування"
|
||||
ascendingOrder: "За зростанням"
|
||||
descendingOrder: "За спаданням"
|
||||
scratchpad: "Чернетка"
|
||||
scratchpad: "Scratchpad"
|
||||
scratchpadDescription: "Scratchpad надає середовище для експериментів з AiScript. Ви можете писати, виконувати його і тестувати взаємодію з Misskey."
|
||||
output: "Вихід"
|
||||
script: "Скрипт"
|
||||
@@ -688,7 +687,7 @@ pageLikesCount: "Кількість отриманих вподобань сто
|
||||
pageLikedCount: "Кількість вподобаних сторінок"
|
||||
contact: "Контакт"
|
||||
useSystemFont: "Використовувати стандартний шрифт системи"
|
||||
clips: "Добірка"
|
||||
clips: "Добірки"
|
||||
experimentalFeatures: "Експериментальні функції"
|
||||
developer: "Розробник"
|
||||
makeExplorable: "Зробіть обліковий запис видимим у розділі \"Огляд\""
|
||||
@@ -901,9 +900,10 @@ show: "Відображення"
|
||||
color: "Колір"
|
||||
achievements: "Досягнення"
|
||||
_achievements:
|
||||
earnedAt: "Відкрито"
|
||||
_types:
|
||||
_notes1:
|
||||
title: "налаштовую свій msky"
|
||||
title: "Привіт, Misskey!"
|
||||
description: "Перша нотатка"
|
||||
flavor: "Приємного часу з Misskey!"
|
||||
_notes10:
|
||||
@@ -954,35 +954,170 @@ _achievements:
|
||||
flavor: "Так багато потрібно сказати?"
|
||||
_login3:
|
||||
title: "Новачок I"
|
||||
description: "3 дні користування загально"
|
||||
flavor: "Відсьогодні називайте мене \"Місскіст\""
|
||||
_login7:
|
||||
title: "Новачок II"
|
||||
description: "7 днів користування загально"
|
||||
flavor: "Ви звикли до цього?"
|
||||
_login15:
|
||||
title: "Новачок III"
|
||||
description: "15 днів користування загально"
|
||||
_login30:
|
||||
title: "Міскієць I"
|
||||
description: "30 днів користування загально"
|
||||
_login60:
|
||||
title: "Міскієць II"
|
||||
description: "60 днів користування загально"
|
||||
_login100:
|
||||
title: "Міскієць III"
|
||||
description: "100 днів користування загально"
|
||||
flavor: "Цей юзер лютий місскіст"
|
||||
_login200:
|
||||
title: "Завсідник I"
|
||||
description: "200 днів користування загально"
|
||||
_login300:
|
||||
title: "Завсідник II"
|
||||
description: "300 днів користування загально"
|
||||
_login400:
|
||||
title: "Завсідник III"
|
||||
description: "400 днів користування загально"
|
||||
_login500:
|
||||
title: "Ветеран I"
|
||||
description: "500 днів користування загально"
|
||||
flavor: "Meine Kameraden, ich liebe sie, die Notizen."
|
||||
_login600:
|
||||
title: "Ветеран II"
|
||||
description: "600 днів користування загально"
|
||||
_login700:
|
||||
title: "Ветеран III"
|
||||
description: "700 днів користування загально"
|
||||
_login800:
|
||||
title: "Майстер нотаток I"
|
||||
description: "800 днів користування загально"
|
||||
_login900:
|
||||
title: "Майстер нотаток II"
|
||||
description: "900 днів користування загально"
|
||||
_login1000:
|
||||
title: "Майстер нотаток III"
|
||||
description: "1000 днів користування загально"
|
||||
flavor: "Дякуємо, що користуєтеся Misskey!"
|
||||
_noteClipped1:
|
||||
title: "Не можна не зберегти"
|
||||
description: "Перша нотатка у добірці"
|
||||
_noteFavorited1:
|
||||
title: "Дивитися на зірки"
|
||||
_myNoteFavorited1:
|
||||
title: "У пошуках зірок"
|
||||
_profileFilled:
|
||||
title: "Повна готовність"
|
||||
description: "Профіль заповнено"
|
||||
_markedAsCat:
|
||||
title: "Я кіт"
|
||||
description: "Позначено як акаунт кота"
|
||||
flavor: "Я дам тобі ім'я пізніше"
|
||||
_following1:
|
||||
title: "Перша підписка"
|
||||
_following10:
|
||||
title: "Продовжуй, продовжуй"
|
||||
_following50:
|
||||
title: "Багато друзів"
|
||||
description: "Кількість підписок сягнула 50"
|
||||
_following100:
|
||||
title: "100 друзів"
|
||||
description: "Кількість підписок сягнула 100"
|
||||
_following300:
|
||||
title: "Надлишок друзів"
|
||||
description: "Кількість підписок сягнула 300"
|
||||
_followers1:
|
||||
title: "Перший підписник"
|
||||
description: "З'явився перший підписник"
|
||||
_followers10:
|
||||
title: "Follow me!"
|
||||
description: "Кількість підписників досягла 10"
|
||||
_followers50:
|
||||
description: "Кількість підписників досягла 50"
|
||||
_followers100:
|
||||
title: "Популярна особа"
|
||||
description: "Кількість підписників досягла 100"
|
||||
_followers300:
|
||||
title: "Ставайте в чергу"
|
||||
description: "Кількість підписників досягла 300"
|
||||
_followers500:
|
||||
title: "Радіовежа"
|
||||
description: "Кількість підписників досягла 500"
|
||||
_followers1000:
|
||||
title: "Інфлюенсер"
|
||||
description: "Кількість підписників досягла 1000"
|
||||
_collectAchievements30:
|
||||
title: "Збирач досягнень"
|
||||
description: "Отримано 30 досягнень"
|
||||
_viewAchievements3min:
|
||||
title: "Шанувальник досягнень"
|
||||
description: "Переглядати список досягнень принаймні 3 хвилини"
|
||||
_iLoveMisskey:
|
||||
title: "I Love Misskey"
|
||||
description: "Відправлено \"I ❤ #Misskey\""
|
||||
flavor: "Дякуємо вам, що користуєтесь Misskey! – команда розробників"
|
||||
_foundTreasure:
|
||||
title: "Пошуки скарбів"
|
||||
description: "Ви знайшли прихований скарб"
|
||||
_client30min:
|
||||
title: "Коротка перерва"
|
||||
description: "З моменту запуску клієнта минуло 30 хвилин"
|
||||
_noteDeletedWithin1min:
|
||||
title: "Не зважай"
|
||||
description: "Допис видалено протягом 1 хвилини після публікації"
|
||||
_postedAtLateNight:
|
||||
title: "Нічне життя"
|
||||
description: "Відправити нотатку посеред ночі"
|
||||
flavor: "Час лягати спати"
|
||||
_postedAt0min0sec:
|
||||
title: "Сигнал часу"
|
||||
description: "Відправити нотатку о 00:00"
|
||||
_selfQuote:
|
||||
title: "Самопосилання"
|
||||
description: "Процитувати власну нотатку"
|
||||
_htl20npm:
|
||||
title: "Плинна стрічка"
|
||||
description: "Перевищити швидкість домашньої стрічки 20npm (нотаток на хвилину)"
|
||||
_viewInstanceChart:
|
||||
title: "Аналітик"
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "Hello, world!"
|
||||
description: "Вивести \"hello world\" у Скретчпаді"
|
||||
_reactWithoutRead:
|
||||
title: "Прочитали як слід?"
|
||||
description: "Реакція на нотатку, що містить понад 100 символів, протягом 3 секунд після її публікації"
|
||||
_clickedClickHere:
|
||||
title: "Натисніть тут"
|
||||
description: "Натиснуто тут"
|
||||
_justPlainLucky:
|
||||
title: "Просто вдача"
|
||||
description: "Можна отримати з ймовірністю 0,01% кожні 10 секунд"
|
||||
_setNameToSyuilo:
|
||||
title: "Комплекс бога"
|
||||
description: "Встановлено ім'я \"syuilo\""
|
||||
_passedSinceAccountCreated1:
|
||||
title: "Перша річниця"
|
||||
description: "Минув рік з моменту створення акаунта"
|
||||
_passedSinceAccountCreated2:
|
||||
title: "Друга річниця"
|
||||
description: "Минуло 2 роки з моменту створення акаунта"
|
||||
_passedSinceAccountCreated3:
|
||||
title: "Третя річниця"
|
||||
description: "Минуло 3 роки з моменту створення акаунта"
|
||||
_loggedInOnBirthday:
|
||||
title: "З Днем народження!"
|
||||
description: "Увійти у свій день народження"
|
||||
_loggedInOnNewYearsDay:
|
||||
title: "З Новим роком!"
|
||||
description: "Увійшли в перший день року"
|
||||
_cookieClicked:
|
||||
flavor: "Чекайте, це вірний сайт?"
|
||||
_brainDiver:
|
||||
title: "Brain Diver"
|
||||
description: "Відправити посилання на \"Brain Diver\""
|
||||
flavor: "Misskey-Misskey La-Tu-Ma"
|
||||
_role:
|
||||
priority: "Пріоритет"
|
||||
@@ -1060,65 +1195,6 @@ _nsfw:
|
||||
respect: "Приховувати NSFW медіа"
|
||||
ignore: "Не приховувати NSFW медіа"
|
||||
force: "Приховувати всі медіа файли"
|
||||
_mfm:
|
||||
cheatSheet: " Довідка MFM"
|
||||
intro: "MFM це ексклюзивна мова розмітки тексту в Misskey, яку можна використовувати в багатьох місцях. Тут ви можете переглянути приклади її синтаксису."
|
||||
dummy: "Misskey розширює світ Федіверсу"
|
||||
mention: "Згадка"
|
||||
mentionDescription: "За допомогою знака \"@\" перед ім'ям можна згадати конкретного користувача."
|
||||
hashtag: "Хештеґ"
|
||||
hashtagDescription: "За допомогою знака \"решітка\" перед словом задається хештег."
|
||||
url: "URL"
|
||||
urlDescription: "Відображаються URL-адреси."
|
||||
link: "Посилання"
|
||||
linkDescription: "Окремі частини тексту можуть містити посилання"
|
||||
bold: "Жирний шрифт"
|
||||
boldDescription: "Виділяє літери, роблячи їх товще"
|
||||
small: "Дрібний шрифт"
|
||||
smallDescription: "Робить текст маленьким і тонким"
|
||||
center: "По центру"
|
||||
centerDescription: "Показує вміст у центрі"
|
||||
inlineCode: "Код (у рядку)"
|
||||
inlineCodeDescription: "Показує фрагмент тексту у рядку як програмний код"
|
||||
blockCode: "Код (блок)"
|
||||
blockCodeDescription: "Показує кілька рядків тексту як блок програмного кода"
|
||||
inlineMath: "Формула (у рядку)"
|
||||
inlineMathDescription: "Відображення математичних формул (KaTeX) у рядку"
|
||||
blockMath: "Формули (блок)"
|
||||
blockMathDescription: "Відображати багаторядкові формули (KaTeX) блоками"
|
||||
quote: "Цитата"
|
||||
quoteDescription: "Відображає зміст як цитату."
|
||||
emoji: "Кастомні емоджі"
|
||||
emojiDescription: "Щоб показати нетиповий емоджі, потрібно ввести його назву в двокрапках."
|
||||
search: "Пошук"
|
||||
searchDescription: "Відображає вікно пошуку з попередньо введеним текстом"
|
||||
flip: "Перевернути"
|
||||
flipDescription: "Віддзеркалює вміст по горизонталі або вертикалі"
|
||||
jelly: "Анімація (желе)"
|
||||
jellyDescription: "Створює желеподібну анімацію"
|
||||
tada: "Анімація (Тада!)"
|
||||
tadaDescription: "Створює анімацію з відчуттям \"Тада!\""
|
||||
jump: "Анімація (стрибки)"
|
||||
jumpDescription: "Показує стрибаючу анімацію"
|
||||
bounce: "Анімація (пружина)"
|
||||
bounceDescription: "Надає вмісту стрибаючу анімацію."
|
||||
shake: "Анімація (Shake)"
|
||||
shakeDescription: "Надає вмісту тремтливу анімацію."
|
||||
twitch: "Анімація (Twitch)"
|
||||
spin: "Анімація (Spin)"
|
||||
x2: "Великий"
|
||||
x2Description: "Показує контент збільшеним."
|
||||
x3: "Дуже великий"
|
||||
x3Description: "Показує контент ще більшим."
|
||||
x4: "Надзвичайно великий"
|
||||
x4Description: "Показує контент надзвичайно великим."
|
||||
blur: "Розмиття"
|
||||
blurDescription: "Цей ефект зробить контент розмитим. Контент можна зробити чітким, якщо навести на нього вказівник миші."
|
||||
font: "Шрифт"
|
||||
fontDescription: "Встановлює шрифт для контенту."
|
||||
rotate: "Обертати"
|
||||
plain: "Звичайний"
|
||||
plainDescription: "Деактивує всі ефекти MFM, що містяться в цьому ефекті MFM."
|
||||
_instanceTicker:
|
||||
none: "Не відображати"
|
||||
remote: "Відображати для віддалених користувачів"
|
||||
@@ -1251,12 +1327,12 @@ _tutorial:
|
||||
step1_1: "Ласкаво просимо!"
|
||||
step1_2: "Ця сторінка має назву \"стрічка подій\". На ній з'являються записи користувачів на яких ви підписані."
|
||||
step1_3: "Наразі ваша стрічка порожня, оскільки ви ще не написали жодної нотатки і не підписані на інших."
|
||||
step2_1: "Перш ніж зробити запис або підписатись на когось, спочатку заповніть свій обліковий запис."
|
||||
step2_2: "Надання деякої інформації про себе дозволить іншим користувачам підписатись на вас."
|
||||
step2_1: "Перш ніж зробити запис або підписатись на когось, заповніть свій профіль."
|
||||
step2_2: "Надання деякої інформації про себе допоможе іншим користувачам вирішити підписатись на вас."
|
||||
step3_1: "Ви успішно налаштували свій обліковий запис?"
|
||||
step3_2: "Наступним кроком є написання нотатки. Це можна зробити, натиснувши зображення олівця на екрані."
|
||||
step3_3: "Після написання вмісту ви можете опублікувати його, натиснувши кнопку у верхньому правому куті форми."
|
||||
step3_4: "Не знаєте що написати? Спробуйте \"налаштовую свій msky\"!"
|
||||
step3_4: "Не знаєте що написати? Спробуйте \"Привіт, Misskey!\""
|
||||
step4_1: "Ви розмістили свій перший запис?"
|
||||
step4_2: "Ура! Ваш перший запис відображається на вашій стрічці подій."
|
||||
step5_1: "Настав час оживити вашу стрічку подій підписавшись на інших користувачів."
|
||||
@@ -1520,6 +1596,7 @@ _notification:
|
||||
youReceivedFollowRequest: "Ви отримали запит на підписку"
|
||||
yourFollowRequestAccepted: "Запит на підписку прийнято"
|
||||
youWereInvitedToGroup: "Запрошення до групи"
|
||||
achievementEarned: "Досягнення відкрито"
|
||||
_types:
|
||||
all: "Все"
|
||||
follow: "Підписки"
|
||||
@@ -1557,5 +1634,6 @@ _deck:
|
||||
tl: "Стрічка"
|
||||
antenna: "Антени"
|
||||
list: "Списки"
|
||||
channel: "Канали"
|
||||
mentions: "Згадки"
|
||||
direct: "Особисте"
|
||||
|
@@ -457,7 +457,6 @@ youHaveNoGroups: "Không có nhóm nào"
|
||||
joinOrCreateGroup: "Tham gia hoặc tạo một nhóm mới."
|
||||
noHistory: "Không có dữ liệu"
|
||||
signinHistory: "Lịch sử đăng nhập"
|
||||
disableAnimatedMfm: "Tắt MFM với chuyển động"
|
||||
doing: "Đang xử lý..."
|
||||
category: "Phân loại"
|
||||
tags: "Thẻ"
|
||||
@@ -992,72 +991,6 @@ _nsfw:
|
||||
respect: "Ẩn nội dung NSFW"
|
||||
ignore: "Hiện nội dung NSFW"
|
||||
force: "Ẩn mọi media"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM là ngôn ngữ phát triển độc quyền của Misskey có thể được sử dụng ở nhiều nơi. Tại đây bạn có thể xem danh sách tất cả các cú pháp MFM có sẵn."
|
||||
dummy: "Misskey mở rộng thế giới Fediverse"
|
||||
mention: "Nhắc đến"
|
||||
mentionDescription: "Bạn có thể nhắc đến ai đó bằng cách sử dụng @tên người dùng."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Bạn có thể tạo một hashtag bằng #chữ hoặc #số."
|
||||
url: "URL"
|
||||
urlDescription: "Những URL có thể hiển thị."
|
||||
link: "Đường dẫn"
|
||||
linkDescription: "Các phần cụ thể của văn bản có thể được hiển thị dưới dạng URL."
|
||||
bold: "In đậm"
|
||||
boldDescription: "Nổi bật các chữ cái bằng cách làm chúng dày hơn."
|
||||
small: "Nhỏ"
|
||||
smallDescription: "Hiển thị nội dung nhỏ và mỏng."
|
||||
center: "Giữa"
|
||||
centerDescription: "Hiển thị nội dung căn giữa."
|
||||
inlineCode: "Mã (Trong dòng)"
|
||||
inlineCodeDescription: "Hiển thị tô sáng cú pháp trong dòng cho mã (chương trình)."
|
||||
blockCode: "Mã (Khối)"
|
||||
blockCodeDescription: "Hiển thị tô sáng cú pháp cho mã nhiều dòng (chương trình) trong một khối."
|
||||
inlineMath: "Toán học (Trong dòng)"
|
||||
inlineMathDescription: "Hiển thị công thức toán (KaTeX) trong dòng"
|
||||
blockMath: "Toán học (Khối)"
|
||||
blockMathDescription: "Hiển thị công thức toán học nhiều dòng (KaTeX) trong một khối"
|
||||
quote: "Trích dẫn"
|
||||
quoteDescription: "Hiển thị nội dung dạng lời trích dạng."
|
||||
emoji: "Tùy chỉnh emoji"
|
||||
emojiDescription: "Hiển thị emoji với cú pháp :tên emoji:"
|
||||
search: "Tìm kiếm"
|
||||
searchDescription: "Hiển thị hộp tìm kiếm với văn bản được nhập trước."
|
||||
flip: "Lật"
|
||||
flipDescription: "Lật nội dung theo chiều ngang hoặc chiều dọc."
|
||||
jelly: "Chuyển động (Thạch rau câu)"
|
||||
jellyDescription: "Cho phép nội dung chuyển động giống như thạch rau câu."
|
||||
tada: "Chuyển động (Tada)"
|
||||
tadaDescription: "Cho phép nội dung chuyển động kiểu \"Tada!\"."
|
||||
jump: "Chuyển động (Nhảy múa)"
|
||||
jumpDescription: "Cho phép nội dung chuyển động nhảy nhót."
|
||||
bounce: "Chuyển động (Cà tưng)"
|
||||
bounceDescription: "Cho phép nội dung chuyển động cà tưng."
|
||||
shake: "Chuyển động (Rung)"
|
||||
shakeDescription: "Cho phép nội dung chuyển động rung lắc."
|
||||
twitch: "Chuyển động (Co rút)"
|
||||
twitchDescription: "Cho phép nội dung chuyển động co rút."
|
||||
spin: "Chuyển động (Xoay tít)"
|
||||
spinDescription: "Cho phép nội dung chuyển động xoay tít."
|
||||
x2: "Lớn"
|
||||
x2Description: "Hiển thị nội dung cỡ lớn hơn."
|
||||
x3: "Rất lớn"
|
||||
x3Description: "Hiển thị nội dung cỡ lớn hơn nữa."
|
||||
x4: "Khổng lồ"
|
||||
x4Description: "Hiển thị nội dung cỡ khổng lồ."
|
||||
blur: "Làm mờ"
|
||||
blurDescription: "Làm mờ nội dung. Nó sẽ được hiển thị rõ ràng khi di chuột qua."
|
||||
font: "Phông chữ"
|
||||
fontDescription: "Chọn phông chữ để hiển thị nội dung."
|
||||
rainbow: "Cầu vồng"
|
||||
rainbowDescription: "Làm cho nội dung hiển thị với màu sắc cầu vồng."
|
||||
sparkle: "Lấp lánh"
|
||||
sparkleDescription: "Làm cho nội dung hiệu ứng hạt lấp lánh."
|
||||
rotate: "Xoay"
|
||||
rotateDescription: "Xoay nội dung theo một góc cụ thể."
|
||||
plain: "Đơn giản"
|
||||
plainDescription: "Vô hiệu hóa mọi hiệu ứng MFM chứa trong hiệu ứng MFM này."
|
||||
_instanceTicker:
|
||||
none: "Không hiển thị"
|
||||
remote: "Hiện cho người dùng từ máy chủ khác"
|
||||
@@ -1520,5 +1453,6 @@ _deck:
|
||||
tl: "Bảng tin"
|
||||
antenna: "Trạm phát sóng"
|
||||
list: "Danh sách"
|
||||
channel: "Kênh"
|
||||
mentions: "Lượt nhắc"
|
||||
direct: "Nhắn riêng"
|
||||
|
@@ -103,6 +103,8 @@ renoted: "已转发。"
|
||||
cantRenote: "该帖无法转发。"
|
||||
cantReRenote: "转发无法被再次转发。"
|
||||
quote: "引用"
|
||||
inChannelRenote: "在频道内转发"
|
||||
inChannelQuote: "在频道内引用"
|
||||
pinnedNote: "已置顶的帖子"
|
||||
pinned: "置顶"
|
||||
you: "您"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "确定要解除拉黑吗?"
|
||||
suspendConfirm: "要冻结吗?"
|
||||
unsuspendConfirm: "要解除冻结吗?"
|
||||
selectList: "选择列表"
|
||||
selectChannel: "选择频道"
|
||||
selectAntenna: "选择天线"
|
||||
selectWidget: "选择小工具"
|
||||
editWidgets: "编辑部件"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "没有更多的历史记录"
|
||||
startMessaging: "添加聊天"
|
||||
nUsersRead: "{n}人已读"
|
||||
agreeTo: "勾选则表示已阅读并同意{0}"
|
||||
agreeBelow: "同意以下观点"
|
||||
basicNotesBeforeCreateAccount: "基本注意事项"
|
||||
tos: "服务条款"
|
||||
start: "开始"
|
||||
home: "首页"
|
||||
@@ -464,7 +469,8 @@ youHaveNoGroups: "没有群组"
|
||||
joinOrCreateGroup: "请加入一个现有的群组,或者创建新群组。"
|
||||
noHistory: "没有历史记录"
|
||||
signinHistory: "登录历史"
|
||||
disableAnimatedMfm: "禁用MFM动画"
|
||||
enableAdvancedMfm: "启用扩展MFM"
|
||||
enableAnimatedMfm: "启用MFM动画"
|
||||
doing: "正在进行"
|
||||
category: "类别"
|
||||
tags: "标签"
|
||||
@@ -861,6 +867,8 @@ failedToFetchAccountInformation: "获取账户信息失败"
|
||||
rateLimitExceeded: "已超過速率限制"
|
||||
cropImage: "剪裁图像"
|
||||
cropImageAsk: "是否要裁剪图像?"
|
||||
cropYes: "已裁剪"
|
||||
cropNo: "就这样吧!"
|
||||
file: "文件"
|
||||
recentNHours: "最近{n}小时"
|
||||
recentNDays: "最近{n}天"
|
||||
@@ -939,6 +947,16 @@ cannotPerformTemporaryDescription: "因操作过于频繁,暂时不可用,
|
||||
preset: "預設值"
|
||||
selectFromPresets: "從預設值中選擇"
|
||||
achievements: "成就"
|
||||
gotInvalidResponseError: "服务器无应答"
|
||||
gotInvalidResponseErrorDescription: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后重试。"
|
||||
thisPostMayBeAnnoying: "这个帖子可能会让其他人感到困扰。"
|
||||
thisPostMayBeAnnoyingHome: "发到首页"
|
||||
thisPostMayBeAnnoyingCancel: "取消"
|
||||
thisPostMayBeAnnoyingIgnore: "就这样发布"
|
||||
collapseRenotes: "省略显示已经看过的转发内容"
|
||||
internalServerError: "内部服务器错误"
|
||||
internalServerErrorDescription: "内部服务器发生了预期外的错误"
|
||||
copyErrorInfo: "复制错误信息"
|
||||
_achievements:
|
||||
earnedAt: "达成时间"
|
||||
_types:
|
||||
@@ -995,52 +1013,170 @@ _achievements:
|
||||
_login3:
|
||||
title: "初学者 I"
|
||||
description: "连续登录3天"
|
||||
flavor: "今天开始我就是Misskist!"
|
||||
_login7:
|
||||
title: "初学者 II"
|
||||
description: "连续登录7天"
|
||||
flavor: "您开始习惯了吗?"
|
||||
_login15:
|
||||
title: "初学者 III"
|
||||
description: "连续登录15天"
|
||||
_login30:
|
||||
title: "Misskist Ⅰ"
|
||||
description: "连续登录30天"
|
||||
_login60:
|
||||
title: "Misskist Ⅱ"
|
||||
description: "连续登录60天"
|
||||
_login100:
|
||||
title: "Misskist Ⅲ"
|
||||
description: "总登入100天"
|
||||
flavor: "那个用户,是Misskist喔"
|
||||
_login200:
|
||||
title: "定期联系Ⅰ"
|
||||
description: "总登录天数200天"
|
||||
_login300:
|
||||
title: "定期联系Ⅱ"
|
||||
description: "总登录天数300天"
|
||||
_login400:
|
||||
title: "定期联系Ⅲ"
|
||||
description: "总登录天数400天"
|
||||
_login500:
|
||||
title: "老熟人Ⅰ"
|
||||
description: "总登录天数500天"
|
||||
flavor: "诸君,我喜欢贴文"
|
||||
_login600:
|
||||
title: "老熟人Ⅱ"
|
||||
description: "总登录天数600天"
|
||||
_login700:
|
||||
title: "老熟人Ⅲ"
|
||||
description: "总登录天数700天"
|
||||
_login800:
|
||||
title: "帖子大师Ⅰ"
|
||||
description: "总登录天数800天"
|
||||
_login900:
|
||||
title: "帖子大师Ⅱ"
|
||||
description: "总登录天数900天"
|
||||
_login1000:
|
||||
title: "帖子大师Ⅲ"
|
||||
description: "总登录天数1000天"
|
||||
flavor: "感谢您使用Misskey!"
|
||||
_noteClipped1:
|
||||
title: "忍不住要收藏到便签"
|
||||
description: "第一次将贴文贴进便签"
|
||||
_noteFavorited1:
|
||||
title: "观星者"
|
||||
description: "第一次将帖子加入收藏"
|
||||
_myNoteFavorited1:
|
||||
title: "想要星星"
|
||||
description: "自己的帖子被其他人加入收藏了"
|
||||
_profileFilled:
|
||||
title: "整装待发"
|
||||
description: "设置了个人资料"
|
||||
_markedAsCat:
|
||||
title: "我是猫"
|
||||
description: "将账户设定为一只猫"
|
||||
flavor: "还没有名字"
|
||||
_following1:
|
||||
title: "首次关注"
|
||||
description: "第一次关注别人"
|
||||
_following10:
|
||||
title: "关注,跟随"
|
||||
description: "关注超过10人"
|
||||
_following50:
|
||||
title: "我的朋友很多"
|
||||
description: "关注超过50人"
|
||||
_following100:
|
||||
title: "我的朋友很多"
|
||||
description: "关注超过100人"
|
||||
_following300:
|
||||
title: "朋友成群"
|
||||
description: "关注数超过300"
|
||||
_followers1:
|
||||
title: "最初的关注者"
|
||||
description: "第一次被关注"
|
||||
_followers10:
|
||||
title: "关注我吧!"
|
||||
description: "拥有超过10名关注者"
|
||||
_followers50:
|
||||
title: "三五成群"
|
||||
description: "拥有超过50名关注者"
|
||||
_followers100:
|
||||
title: "胜友如云"
|
||||
description: "拥有超过100名关注者"
|
||||
_followers300:
|
||||
title: "排列成行"
|
||||
description: "拥有超过300名关注者"
|
||||
_followers500:
|
||||
title: "信号塔"
|
||||
description: "拥有超过500名关注者"
|
||||
_followers1000:
|
||||
title: "大影响家"
|
||||
description: "拥有超过1000名关注者"
|
||||
_collectAchievements30:
|
||||
title: "成就收藏家"
|
||||
description: "获得超过30个成就"
|
||||
_viewAchievements3min:
|
||||
title: "成就爱好者"
|
||||
description: "盯着成就看三分钟"
|
||||
_iLoveMisskey:
|
||||
title: "I Love Misskey"
|
||||
description: "发布\"I ❤ #Misskey\"帖子"
|
||||
flavor: "感谢您使用 Misskey ! by 开发团队"
|
||||
_foundTreasure:
|
||||
title: "寻宝"
|
||||
description: "发现了隐藏的宝藏"
|
||||
_client30min:
|
||||
title: "休息一下!"
|
||||
description: "启动客户端超过30分钟"
|
||||
_noteDeletedWithin1min:
|
||||
title: "无话可说"
|
||||
description: "发帖后一分钟内就将其删除"
|
||||
_postedAtLateNight:
|
||||
title: "夜行者"
|
||||
title: "夜猫子"
|
||||
description: "深夜发布帖子"
|
||||
flavor: "差不多该去睡了喔。"
|
||||
_postedAt0min0sec:
|
||||
title: "报时"
|
||||
description: "在0点发布一篇帖子"
|
||||
flavor: "嘣 嘣 嘣 Biu——!"
|
||||
_selfQuote:
|
||||
title: "自我引用"
|
||||
description: "引用了自己的帖子"
|
||||
_htl20npm:
|
||||
title: "流动的时间线"
|
||||
description: "在首页时间线的流速超过20npm"
|
||||
_viewInstanceChart:
|
||||
title: "分析师"
|
||||
description: "查看了实例信息中的图表"
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "Hello, world!"
|
||||
description: "在AiScript控制台中输出 hello world"
|
||||
_open3windows:
|
||||
title: "多窗口"
|
||||
description: "打开了三个或更多的窗口"
|
||||
_driveFolderCircularReference:
|
||||
title: "循环引用"
|
||||
description: "试图对网盘中的文件夹进行循环嵌套"
|
||||
_reactWithoutRead:
|
||||
title: "有好好读过吗?"
|
||||
description: "在含有100字以上的帖子被发出三秒内做出回应"
|
||||
_clickedClickHere:
|
||||
title: "点这里"
|
||||
description: "点了这里"
|
||||
_justPlainLucky:
|
||||
title: "超高校级的幸运"
|
||||
description: "每10秒有0.01的概率自动获得"
|
||||
_setNameToSyuilo:
|
||||
title: "像神一样呐"
|
||||
description: "将名称设定为syuilo"
|
||||
_passedSinceAccountCreated1:
|
||||
title: "一周年"
|
||||
description: "账户创建时间超过1年"
|
||||
_passedSinceAccountCreated2:
|
||||
title: "二周年"
|
||||
description: "账户创建时间超过2年"
|
||||
_passedSinceAccountCreated3:
|
||||
title: "三周年"
|
||||
description: "账户创建时间超过3年"
|
||||
_loggedInOnBirthday:
|
||||
title: "生日快乐"
|
||||
@@ -1048,6 +1184,15 @@ _achievements:
|
||||
_loggedInOnNewYearsDay:
|
||||
title: "恭贺新禧"
|
||||
description: "在元旦登入"
|
||||
flavor: "今年也请对本实例多多指教!"
|
||||
_cookieClicked:
|
||||
title: "点击饼干小游戏"
|
||||
description: "点击了可疑的饼干"
|
||||
flavor: "是不是软件有问题?"
|
||||
_brainDiver:
|
||||
title: "Brain Diver"
|
||||
description: "发布了包含Brain Diver链接的帖子"
|
||||
flavor: "Misskey-Misskey La-Tu-Ma"
|
||||
_role:
|
||||
new: "创建角色"
|
||||
edit: "编辑角色"
|
||||
@@ -1068,6 +1213,9 @@ _role:
|
||||
baseRole: "基本角色"
|
||||
useBaseValue: "使用基本角色的值"
|
||||
chooseRoleToAssign: "选择要分配的角色"
|
||||
iconUrl: "图标URL"
|
||||
asBadge: "作为徽章显示"
|
||||
descriptionOfAsBadge: "开启后,用户名旁边将会出现角色图标。"
|
||||
canEditMembersByModerator: "允许监察者编辑成员"
|
||||
descriptionOfCanEditMembersByModerator: "如果选中,监察者和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
|
||||
priority: "优先级"
|
||||
@@ -1193,72 +1341,6 @@ _nsfw:
|
||||
respect: "隐藏敏感内容"
|
||||
ignore: "不隐藏敏感内容"
|
||||
force: "总是隐藏内容"
|
||||
_mfm:
|
||||
cheatSheet: "MFM代码速查表"
|
||||
intro: "MFM是一种在Misskey中的各个位置使用的专用标记语言。在这里您可以看到MFM中可用的语法列表。"
|
||||
dummy: "通过Misskey扩展联邦宇宙的世界"
|
||||
mention: "提及"
|
||||
mentionDescription: "可以使用 @+用户名 来指示特定用户"
|
||||
hashtag: "话题标签"
|
||||
hashtagDescription: "可以使用井号+文字来表示话题标签。"
|
||||
url: "URL"
|
||||
urlDescription: "可以表示URL地址。"
|
||||
link: "链接"
|
||||
linkDescription: "可以将部分文字和URL关联起来。"
|
||||
bold: "粗体"
|
||||
boldDescription: "可以将文字显示为粗体来表示强调。"
|
||||
small: "缩小"
|
||||
smallDescription: "可以使内容文字变小、变淡。"
|
||||
center: "居中"
|
||||
centerDescription: "可以将内容居中显示。"
|
||||
inlineCode: "代码(内嵌)"
|
||||
inlineCodeDescription: "将文字中的程序代码语法高亮显示。"
|
||||
blockCode: "代码(块)"
|
||||
blockCodeDescription: "语法高亮显示整块程序代码。"
|
||||
inlineMath: "数学公式(内嵌)"
|
||||
inlineMathDescription: "显示内嵌的KaTex公式。"
|
||||
blockMath: "数学公式(块)"
|
||||
blockMathDescription: "显示整块的多行KaTex数学公式。"
|
||||
quote: "引用"
|
||||
quoteDescription: "可以用来表示引用的内容。"
|
||||
emoji: "自定义表情符号"
|
||||
emojiDescription: "可以将自定义表情符号使用冒号括起来,就可以显示自定义表情符号了。"
|
||||
search: "搜索"
|
||||
searchDescription: "显示含有搜索内容示例的搜索框。"
|
||||
flip: "翻转"
|
||||
flipDescription: "将内容上下或左右翻转。"
|
||||
jelly: "动画(果冻)"
|
||||
jellyDescription: "显示果冻一样的动画效果。"
|
||||
tada: "动画(锵锵)"
|
||||
tadaDescription: "显示\"锵锵!\"的动画效果。"
|
||||
jump: "动画(跳动)"
|
||||
jumpDescription: "显示跳动的动画效果。"
|
||||
bounce: "动画(弹性)"
|
||||
bounceDescription: "显示弹性一样的动画效果。"
|
||||
shake: "动画(摇晃)"
|
||||
shakeDescription: "显示摇晃的动画效果。"
|
||||
twitch: "动画(颤抖)"
|
||||
twitchDescription: "显示强烈颤抖的动画效果。"
|
||||
spin: "动画(旋转)"
|
||||
spinDescription: "显示旋转的动画效果。"
|
||||
x2: "大"
|
||||
x2Description: "以大尺寸显示内容。"
|
||||
x3: "非常大"
|
||||
x3Description: "以更大尺寸显示内容。"
|
||||
x4: "最大"
|
||||
x4Description: "以最大尺寸显示内容。"
|
||||
blur: "模糊"
|
||||
blurDescription: "产生模糊效果。将鼠标指针放在上面即可将内容显示出来。"
|
||||
font: "字体"
|
||||
fontDescription: "可以设置内容所使用的字体。"
|
||||
rainbow: "彩虹"
|
||||
rainbowDescription: "用彩虹色来显示内容。"
|
||||
sparkle: "闪光"
|
||||
sparkleDescription: "添加发光粒子效果。"
|
||||
rotate: "旋转"
|
||||
rotateDescription: "旋转指定的角度。"
|
||||
plain: "简洁"
|
||||
plainDescription: "禁用所有内部语法。"
|
||||
_instanceTicker:
|
||||
none: "不显示"
|
||||
remote: "仅远程用户"
|
||||
@@ -1463,12 +1545,15 @@ _permissions:
|
||||
"read:gallery-likes": "读取喜欢的图片"
|
||||
"write:gallery-likes": "操作喜欢的图片"
|
||||
_auth:
|
||||
shareAccessTitle: "应用程序授权许可"
|
||||
shareAccess: "您要授权允许“{name}”访问您的帐户吗?"
|
||||
shareAccessAsk: "您确定要授权此应用程序访问您的帐户吗?"
|
||||
permission: "{name}需要以下权限"
|
||||
permissionAsk: "这个应用程序需要以下权限"
|
||||
pleaseGoBack: "请返回到应用程序"
|
||||
callback: "回到应用程序"
|
||||
denied: "拒绝访问"
|
||||
pleaseLogin: "在对应用进行授权许可之前,请先登录"
|
||||
_antennaSources:
|
||||
all: "所有帖子"
|
||||
homeTimeline: "已关注用户的帖子"
|
||||
@@ -1566,7 +1651,7 @@ _profile:
|
||||
name: "昵称"
|
||||
username: "用户名"
|
||||
description: "个人简介"
|
||||
youCanIncludeHashtags: "您可以包含一个哈希标签。"
|
||||
youCanIncludeHashtags: "你可以在个人简介中包含一个#标签。"
|
||||
metadata: "附加信息"
|
||||
metadataEdit: "附加信息编辑"
|
||||
metadataDescription: "最多可以在个人资料中以表格形式显示四条其他信息。"
|
||||
@@ -1739,5 +1824,6 @@ _deck:
|
||||
tl: "时间线"
|
||||
antenna: "天线"
|
||||
list: "列表"
|
||||
channel: "频道"
|
||||
mentions: "提及"
|
||||
direct: "指定用户"
|
||||
|
@@ -103,6 +103,8 @@ renoted: "轉傳成功"
|
||||
cantRenote: "無法轉發此貼文。"
|
||||
cantReRenote: "無法轉傳之前已經轉傳過的內容。"
|
||||
quote: "引用"
|
||||
inChannelRenote: "在頻道內轉發"
|
||||
inChannelQuote: "在頻道內引用"
|
||||
pinnedNote: "已置頂的貼文"
|
||||
pinned: "置頂"
|
||||
you: "您"
|
||||
@@ -129,6 +131,7 @@ unblockConfirm: "確定解除封鎖此用戶?"
|
||||
suspendConfirm: "確定凍結此帳號?"
|
||||
unsuspendConfirm: "確定解凍此帳號?"
|
||||
selectList: "選擇清單"
|
||||
selectChannel: "選擇頻道"
|
||||
selectAntenna: "選擇天線"
|
||||
selectWidget: "選擇小工具"
|
||||
editWidgets: "編輯小工具"
|
||||
@@ -240,7 +243,7 @@ removeAreYouSure: "確定要刪掉「{x}」嗎?"
|
||||
deleteAreYouSure: "確定要刪掉「{x}」嗎?"
|
||||
resetAreYouSure: "確定要重設嗎?"
|
||||
saved: "已儲存"
|
||||
messaging: "傳送訊息"
|
||||
messaging: "聊天"
|
||||
upload: "上傳"
|
||||
keepOriginalUploading: "保留原圖"
|
||||
keepOriginalUploadingDescription: "上傳圖片時保留原始圖片。關閉時,瀏覽器會在上傳時生成一張用於web發布的圖片。"
|
||||
@@ -256,6 +259,8 @@ noMoreHistory: "沒有更多歷史紀錄"
|
||||
startMessaging: "開始聊天"
|
||||
nUsersRead: "{n}人已讀"
|
||||
agreeTo: "我同意{0}"
|
||||
agreeBelow: "同意以下內容"
|
||||
basicNotesBeforeCreateAccount: "基本注意事項"
|
||||
tos: "使用條款"
|
||||
start: "開始"
|
||||
home: "首頁"
|
||||
@@ -326,15 +331,15 @@ connectService: "己連結"
|
||||
disconnectService: "己斷開 "
|
||||
enableLocalTimeline: "開啟本地時間軸"
|
||||
enableGlobalTimeline: "啟用全域時間軸"
|
||||
disablingTimelinesInfo: "為了方便,即使您關閉了時間線功能,管理員和審核員仍可以繼續使用。"
|
||||
disablingTimelinesInfo: "為了方便,即使您關閉了時間線功能,管理員和審查員仍可以繼續使用。"
|
||||
registration: "註冊"
|
||||
enableRegistration: "開啟新使用者註冊"
|
||||
invite: "邀請"
|
||||
driveCapacityPerLocalAccount: "每個本地用戶的雲端空間大小"
|
||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
|
||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
|
||||
inMb: "以Mbps為單位"
|
||||
iconUrl: "圖像URL"
|
||||
bannerUrl: "橫幅圖像URL"
|
||||
iconUrl: "圖標URL"
|
||||
bannerUrl: "橫幅圖片URL"
|
||||
backgroundImageUrl: "背景圖片的來源網址 "
|
||||
basicInfo: "基本資訊"
|
||||
pinnedUsers: "置頂用戶"
|
||||
@@ -373,8 +378,8 @@ connectedTo: "您的帳戶已連接到以下社交帳戶"
|
||||
notesAndReplies: "貼文與回覆"
|
||||
withFiles: "附件"
|
||||
silence: "禁言"
|
||||
silenceConfirm: "確定要禁言此用戶嗎?"
|
||||
unsilence: "解除禁言"
|
||||
silenceConfirm: "確定要靜音此使用者嗎?"
|
||||
unsilence: "解除靜音"
|
||||
unsilenceConfirm: "確定要解除禁言嗎?"
|
||||
popularUsers: "熱門使用者"
|
||||
recentlyUpdatedUsers: "最近發文的使用者"
|
||||
@@ -383,14 +388,14 @@ recentlyDiscoveredUsers: "最近發現的使用者"
|
||||
exploreUsersCount: "有{count}個使用者"
|
||||
exploreFediverse: "探索聯邦世界"
|
||||
popularTags: "熱門標籤"
|
||||
userList: "清單"
|
||||
about: "資訊"
|
||||
userList: "使用者清單"
|
||||
about: "關於"
|
||||
aboutMisskey: "關於 Misskey"
|
||||
administrator: "管理員"
|
||||
token: "權杖"
|
||||
twoStepAuthentication: "兩階段驗證"
|
||||
moderator: "監察員"
|
||||
moderation: "監察"
|
||||
moderator: "審查員"
|
||||
moderation: "審查"
|
||||
nUsersMentioned: "提到了{n}"
|
||||
securityKey: "安全金鑰"
|
||||
securityKeyName: "金鑰名稱"
|
||||
@@ -421,7 +426,7 @@ invites: "邀請"
|
||||
groupName: "群組名稱"
|
||||
members: "成員"
|
||||
transfer: "轉讓"
|
||||
messagingWithUser: "傳送訊息給其他使用者"
|
||||
messagingWithUser: "與其他使用者聊天"
|
||||
messagingWithGroup: "發送訊息至群組"
|
||||
title: "標題"
|
||||
text: "文字"
|
||||
@@ -464,7 +469,8 @@ youHaveNoGroups: "找不到群組"
|
||||
joinOrCreateGroup: "請加入現有群組,或創建新群組。"
|
||||
noHistory: "沒有歷史紀錄"
|
||||
signinHistory: "登入歷史"
|
||||
disableAnimatedMfm: "禁用MFM動畫"
|
||||
enableAdvancedMfm: "啟用高級MFM"
|
||||
enableAnimatedMfm: "啟用MFM動畫"
|
||||
doing: "正在進行"
|
||||
category: "類別"
|
||||
tags: "標籤"
|
||||
@@ -473,7 +479,7 @@ createAccount: "建立帳戶"
|
||||
existingAccount: "現有帳戶"
|
||||
regenerate: "再生"
|
||||
fontSize: "字體大小"
|
||||
noFollowRequests: "沒有要求跟隨您的申請"
|
||||
noFollowRequests: "沒有跟隨您的請求"
|
||||
openImageInNewTab: "於新分頁中開啟圖片"
|
||||
dashboard: "儀表板"
|
||||
local: "本地"
|
||||
@@ -530,8 +536,8 @@ installedDate: "安裝時間"
|
||||
lastUsedDate: "最後上線日期"
|
||||
state: "狀態"
|
||||
sort: "排序"
|
||||
ascendingOrder: "昇冪"
|
||||
descendingOrder: "降冪"
|
||||
ascendingOrder: "遞增"
|
||||
descendingOrder: "遞減"
|
||||
scratchpad: "暫存記憶體"
|
||||
scratchpadDescription: "AiScript控制台為AiScript提供了實驗環境。您可以在此編寫、執行和確認代碼與Misskey互動的结果。"
|
||||
output: "輸出"
|
||||
@@ -607,7 +613,7 @@ testEmail: "測試郵件發送"
|
||||
wordMute: "被靜音的文字"
|
||||
regexpError: "正規表達式錯誤"
|
||||
regexpErrorDescription: "{tab} 靜音文字的第 {line} 行的正規表達式有錯誤:"
|
||||
instanceMute: "實例的靜音"
|
||||
instanceMute: "被靜音的實例"
|
||||
userSaysSomething: "{name}說了什麼"
|
||||
makeActive: "啟用"
|
||||
display: "檢視"
|
||||
@@ -861,6 +867,8 @@ failedToFetchAccountInformation: "取得帳戶資訊失敗"
|
||||
rateLimitExceeded: "已超過速率限制"
|
||||
cropImage: "圖片裁剪"
|
||||
cropImageAsk: "要剪裁圖片嗎?"
|
||||
cropYes: "裁剪"
|
||||
cropNo: "使用原圖"
|
||||
file: "檔案"
|
||||
recentNHours: "過去{n}小時"
|
||||
recentNDays: "過去{n}天"
|
||||
@@ -939,6 +947,16 @@ cannotPerformTemporaryDescription: "由於超過操作次數限制,暫時無
|
||||
preset: "預設值"
|
||||
selectFromPresets: "從預設值中選擇"
|
||||
achievements: "成就"
|
||||
gotInvalidResponseError: "伺服器的回應無效"
|
||||
gotInvalidResponseErrorDescription: "伺服器可能已關閉或者在維護中,請稍後再試。"
|
||||
thisPostMayBeAnnoying: "這篇貼文可能會造成別人的困擾。"
|
||||
thisPostMayBeAnnoyingHome: "發布到首頁"
|
||||
thisPostMayBeAnnoyingCancel: "退出"
|
||||
thisPostMayBeAnnoyingIgnore: "直接發布貼文"
|
||||
collapseRenotes: "省略顯示已看過的轉發貼文"
|
||||
internalServerError: "內部伺服器錯誤"
|
||||
internalServerErrorDescription: "內部伺服器發生了非預期的錯誤。"
|
||||
copyErrorInfo: "複製錯誤資訊"
|
||||
_achievements:
|
||||
earnedAt: "獲得日期"
|
||||
_types:
|
||||
@@ -995,24 +1013,24 @@ _achievements:
|
||||
_login3:
|
||||
title: "初學者Ⅰ"
|
||||
description: "總登入天數為3天"
|
||||
flavor: "從今天開始,我就是Misskeyist"
|
||||
flavor: "從今天開始,我就是Misskist"
|
||||
_login7:
|
||||
title: "初學者ⅠⅠ"
|
||||
description: "總登入天數為7天"
|
||||
flavor: "您開始習慣了嗎?"
|
||||
_login15:
|
||||
title: "初學者III"
|
||||
title: "初學者ⅠⅠⅠ"
|
||||
description: "總登入天數為15天"
|
||||
_login30:
|
||||
title: "Misskeyist Ⅰ"
|
||||
title: "Misskist Ⅰ"
|
||||
description: "總登入天數為30天"
|
||||
_login60:
|
||||
title: "Misskeyist ⅠⅠ"
|
||||
title: "Misskist ⅠⅠ"
|
||||
description: "總登入天數為60天"
|
||||
_login100:
|
||||
title: "Misskeyist ⅠⅠⅠ"
|
||||
title: "Misskist ⅠⅠⅠ"
|
||||
description: "總登入天數為100天"
|
||||
flavor: "辣個 Misskeyist 用戶"
|
||||
flavor: "辣個 Misskist 用戶"
|
||||
_login200:
|
||||
title: "普通Ⅰ"
|
||||
description: "總登入天數為200天"
|
||||
@@ -1089,7 +1107,7 @@ _achievements:
|
||||
title: "請排成一排"
|
||||
description: "跟隨者超過300人了"
|
||||
_followers500:
|
||||
title: "基站"
|
||||
title: "基地台"
|
||||
description: "超過500名追隨者了"
|
||||
_followers1000:
|
||||
title: "影響者"
|
||||
@@ -1111,7 +1129,7 @@ _achievements:
|
||||
title: "休息一下"
|
||||
description: "用戶端啟動已超過30分鐘"
|
||||
_noteDeletedWithin1min:
|
||||
title: "現在沒有"
|
||||
title: "現在沒有了"
|
||||
description: "發文後1分鐘內刪文"
|
||||
_postedAtLateNight:
|
||||
title: "夜行性"
|
||||
@@ -1181,7 +1199,7 @@ _role:
|
||||
name: "角色名稱"
|
||||
description: "角色描述 "
|
||||
permission: "角色的權限"
|
||||
descriptionOfPermission: "<b>審核員</b>執行與審核相關的基本操作。\n<b>管理員</b>能變更實例的全部設定。"
|
||||
descriptionOfPermission: "<b>審查員</b>執行與審查相關的基本操作。\n<b>管理員</b>能變更實例的全部設定"
|
||||
assignTarget: "指派目標"
|
||||
descriptionOfAssignTarget: "<b>手動</b>是以手動管理這個角色包含的人員。\n<b>符合條件</b>是設定條件以自動包含符合條件的使用者。"
|
||||
manual: "手動"
|
||||
@@ -1195,8 +1213,11 @@ _role:
|
||||
baseRole: "基本角色"
|
||||
useBaseValue: "使用基本角色的值"
|
||||
chooseRoleToAssign: "選擇要指派的角色"
|
||||
canEditMembersByModerator: "允許編輯監察員的成員"
|
||||
descriptionOfCanEditMembersByModerator: "如果開啟,管理員與監察員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
|
||||
iconUrl: "圖示的URL"
|
||||
asBadge: "顯示為徽章"
|
||||
descriptionOfAsBadge: "開啟的話,角色圖示會顯示在用戶名旁邊。"
|
||||
canEditMembersByModerator: "允許編輯審查員的成員"
|
||||
descriptionOfCanEditMembersByModerator: "如果開啟,管理員與審查員都可以為使用者指派/解除指派該角色。如果關閉,則只有管理員可以執行。"
|
||||
priority: "優先級"
|
||||
_priority:
|
||||
low: "低"
|
||||
@@ -1233,7 +1254,7 @@ _role:
|
||||
or: "~或~"
|
||||
not: "~否"
|
||||
_sensitiveMediaDetection:
|
||||
description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
|
||||
description: "您可以使用機器學習自動檢測敏感媒體並將其用於審查。 伺服器的負荷會稍微增加。"
|
||||
sensitivity: "檢測敏感度"
|
||||
sensitivityDescription: "敏感度低時,誤檢測(偽陽性)會減少。敏感度高時,漏檢(偽陰性)會減少。"
|
||||
setSensitiveFlagAutomatically: "設定 NSFW 旗標"
|
||||
@@ -1320,72 +1341,6 @@ _nsfw:
|
||||
respect: "隱藏敏感內容"
|
||||
ignore: "不隱藏敏感內容"
|
||||
force: "隱藏所有內容"
|
||||
_mfm:
|
||||
cheatSheet: "MFM代碼小抄"
|
||||
intro: "MFM是Misskey專用的標記語言,可以在Misskey中的各個位置使用。 您可以這裏看到MFM可用語法列表。"
|
||||
dummy: "Misskey拓展了Fediverse的世界"
|
||||
mention: "提及"
|
||||
mentionDescription: "透過 @+用戶名 來標示特定使用者。"
|
||||
hashtag: "#tag"
|
||||
hashtagDescription: "可以使用\"#\"符號後加文字表示話題標籤。"
|
||||
url: "URL"
|
||||
urlDescription: "可以展示URL位址。"
|
||||
link: "鏈接"
|
||||
linkDescription: "您可以將特定範圍的文章與 URL 相關聯。 "
|
||||
bold: "粗體"
|
||||
boldDescription: "可以將文字顯示为粗體来強調。"
|
||||
small: "縮小"
|
||||
smallDescription: "可以使內容文字變小、變淡。"
|
||||
center: "置中"
|
||||
centerDescription: "可以將內容置中顯示。"
|
||||
inlineCode: "程式碼(内嵌)"
|
||||
inlineCodeDescription: "在行內用高亮度顯示,例如程式碼語法。"
|
||||
blockCode: "程式碼(區塊)"
|
||||
blockCodeDescription: "在區塊中用高亮度顯示,例如複數行的程式碼語法。"
|
||||
inlineMath: "數學公式(內嵌)"
|
||||
inlineMathDescription: "顯示內嵌的KaTex數學公式。"
|
||||
blockMath: "數學公式(方塊)"
|
||||
blockMathDescription: "以區塊顯示複數行的KaTex數學式。"
|
||||
quote: "引用"
|
||||
quoteDescription: "可以用來表示引用的内容。"
|
||||
emoji: "自訂表情符號"
|
||||
emojiDescription: "您可以通過將自定義表情符號名稱括在冒號中來顯示自定義表情符號。 "
|
||||
search: "搜尋"
|
||||
searchDescription: "您可以顯示所輸入的搜索框。"
|
||||
flip: "翻轉"
|
||||
flipDescription: "將內容上下或左右翻轉。"
|
||||
jelly: "動畫(果凍)"
|
||||
jellyDescription: "顯示果凍一樣的動畫效果。"
|
||||
tada: "動畫(鏘~)"
|
||||
tadaDescription: "顯示「鏘~!」這種感覺的動畫效果。"
|
||||
jump: "動畫(跳動)"
|
||||
jumpDescription: "顯示跳動的動畫效果。"
|
||||
bounce: "動畫(反彈)"
|
||||
bounceDescription: "顯示有彈性的動畫效果。"
|
||||
shake: "動畫(搖晃)"
|
||||
shakeDescription: "顯示顫抖的動畫效果。"
|
||||
twitch: "動畫(顫抖)"
|
||||
twitchDescription: "顯示強烈顫抖的動畫效果。"
|
||||
spin: "動畫(旋轉)"
|
||||
spinDescription: "顯示旋轉的動畫效果。"
|
||||
x2: "大"
|
||||
x2Description: "放大顯示內容。"
|
||||
x3: "較大"
|
||||
x3Description: "放大顯示內容。"
|
||||
x4: "最大"
|
||||
x4Description: "將顯示內容放至最大。"
|
||||
blur: "模糊"
|
||||
blurDescription: "產生模糊效果。将游標放在上面即可將内容顯示出來。"
|
||||
font: "字型"
|
||||
fontDescription: "您可以設定顯示內容的字型"
|
||||
rainbow: "彩虹"
|
||||
rainbowDescription: "用彩虹色來顯示內容。"
|
||||
sparkle: "閃閃發光"
|
||||
sparkleDescription: "添加閃閃發光的粒子效果。"
|
||||
rotate: "旋轉"
|
||||
rotateDescription: "以指定的角度旋轉。"
|
||||
plain: "簡潔"
|
||||
plainDescription: "停用全部的內部語法。"
|
||||
_instanceTicker:
|
||||
none: "隱藏"
|
||||
remote: "向遠端使用者顯示"
|
||||
@@ -1590,12 +1545,15 @@ _permissions:
|
||||
"read:gallery-likes": "讀取喜歡的圖片"
|
||||
"write:gallery-likes": "操作喜歡的圖片"
|
||||
_auth:
|
||||
shareAccessTitle: "應用程式的存取權限"
|
||||
shareAccess: "要授權「“{name}”」存取您的帳戶嗎?"
|
||||
shareAccessAsk: "您確定要授權這個應用程式使用您的帳戶嗎?"
|
||||
permission: "{name}要求以下的權限"
|
||||
permissionAsk: "此應用程式需要以下權限"
|
||||
pleaseGoBack: "請返回至應用程式"
|
||||
callback: "回到應用程式"
|
||||
denied: "拒絕訪問"
|
||||
pleaseLogin: "必須登入以提供應用程式的存取權限。"
|
||||
_antennaSources:
|
||||
all: "全部貼文"
|
||||
homeTimeline: "來自已追隨使用者的貼文"
|
||||
@@ -1866,5 +1824,6 @@ _deck:
|
||||
tl: "時間軸"
|
||||
antenna: "天線"
|
||||
list: "清單"
|
||||
channel: "頻道"
|
||||
mentions: "提及"
|
||||
direct: "指定使用者"
|
||||
|
28
package.json
28
package.json
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"version": "13.2.1",
|
||||
"version": "13.7.0",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/misskey-dev/misskey.git"
|
||||
},
|
||||
"packageManager": "pnpm@7.24.3",
|
||||
"packageManager": "pnpm@7.27.0",
|
||||
"workspaces": [
|
||||
"packages/frontend",
|
||||
"packages/backend",
|
||||
@@ -19,7 +19,7 @@
|
||||
"start": "cd packages/backend && node ./built/boot/index.js",
|
||||
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/index.js",
|
||||
"init": "pnpm migrate",
|
||||
"migrate": "cd packages/backend && pnpm typeorm migration:run -d ormconfig.js",
|
||||
"migrate": "cd packages/backend && pnpm migrate",
|
||||
"migrateandstart": "pnpm migrate && pnpm start",
|
||||
"gulp": "pnpm exec gulp build",
|
||||
"watch": "pnpm dev",
|
||||
@@ -28,8 +28,8 @@
|
||||
"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
|
||||
"cy:run": "pnpm cypress run",
|
||||
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
|
||||
"jest": "cd packages/backend && pnpm cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
|
||||
"jest-and-coverage": "cd packages/backend && pnpm cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
|
||||
"jest": "cd packages/backend && pnpm jest",
|
||||
"jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
|
||||
"test": "pnpm jest",
|
||||
"test-and-coverage": "pnpm jest-and-coverage",
|
||||
"format": "pnpm exec gulp format",
|
||||
@@ -38,8 +38,8 @@
|
||||
"cleanall": "pnpm clean-all"
|
||||
},
|
||||
"resolutions": {
|
||||
"chokidar": "^3.5.3",
|
||||
"lodash": "^4.17.21"
|
||||
"chokidar": "3.5.3",
|
||||
"lodash": "4.17.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"execa": "5.1.1",
|
||||
@@ -49,19 +49,19 @@
|
||||
"gulp-replace": "1.1.4",
|
||||
"gulp-terser": "2.1.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"typescript": "4.9.4"
|
||||
"typescript": "4.9.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/gulp": "4.0.10",
|
||||
"@types/gulp-rename": "2.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.49.0",
|
||||
"@typescript-eslint/parser": "5.49.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.52.0",
|
||||
"@typescript-eslint/parser": "5.52.0",
|
||||
"cross-env": "7.0.3",
|
||||
"cypress": "12.3.0",
|
||||
"eslint": "^8.32.0",
|
||||
"start-server-and-test": "1.15.3"
|
||||
"cypress": "12.6.0",
|
||||
"eslint": "8.34.0",
|
||||
"start-server-and-test": "1.15.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tensorflow/tfjs-core": "^4.2.0"
|
||||
"@tensorflow/tfjs-core": "4.2.0"
|
||||
}
|
||||
}
|
||||
|
@@ -1,14 +0,0 @@
|
||||
// https://github.com/facebook/jest/issues/12270#issuecomment-1194746382
|
||||
|
||||
const nativeModule = require('node:module');
|
||||
|
||||
function resolver(module, options) {
|
||||
const { basedir, defaultResolver } = options;
|
||||
try {
|
||||
return defaultResolver(module, options);
|
||||
} catch (error) {
|
||||
return nativeModule.createRequire(basedir).resolve(module);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = resolver;
|
@@ -83,7 +83,14 @@ module.exports = {
|
||||
|
||||
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||
moduleNameMapper: {
|
||||
"^@/(.*?).js": "<rootDir>/src/$1.ts",
|
||||
// Do not resolve .wasm.js to .wasm by the rule below
|
||||
'^(.+)\\.wasm\\.js$': '$1.wasm.js',
|
||||
// SWC converts @/foo/bar.js to `../../src/foo/bar.js`, and then this rule
|
||||
// converts it again to `../../src/foo/bar` which then can be resolved to
|
||||
// `.ts` files.
|
||||
// See https://github.com/swc-project/jest/issues/64#issuecomment-1029753225
|
||||
// TODO: Use `--allowImportingTsExtensions` on TypeScript 5.0 so that we can
|
||||
// directly import `.ts` files without this hack.
|
||||
'^(\\.{1,2}/.*)\\.js$': '$1',
|
||||
},
|
||||
|
||||
@@ -112,7 +119,7 @@ module.exports = {
|
||||
// resetModules: false,
|
||||
|
||||
// A path to a custom resolver
|
||||
resolver: './jest-resolver.cjs',
|
||||
// resolver: './jest-resolver.cjs',
|
||||
|
||||
// Automatically restore mock state between every test
|
||||
restoreMocks: true,
|
||||
|
29
packages/backend/migration/1675404035646-cleanup.js
Normal file
29
packages/backend/migration/1675404035646-cleanup.js
Normal file
@@ -0,0 +1,29 @@
|
||||
export class cleanup1675404035646 {
|
||||
name = 'cleanup1675404035646'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTwitterIntegration"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableGithubIntegration"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableDiscordIntegration"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "twitterConsumerKey"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "twitterConsumerSecret"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "githubClientId"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "githubClientSecret"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "discordClientId"`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "discordClientSecret"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "integrations"`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ADD "integrations" jsonb NOT NULL DEFAULT '{}'`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "discordClientSecret" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "discordClientId" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "githubClientSecret" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "githubClientId" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "twitterConsumerSecret" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "twitterConsumerKey" character varying(128)`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "enableDiscordIntegration" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "enableGithubIntegration" boolean NOT NULL DEFAULT false`);
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "enableTwitterIntegration" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
}
|
13
packages/backend/migration/1675557528704-role-icon-badge.js
Normal file
13
packages/backend/migration/1675557528704-role-icon-badge.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export class roleIconBadge1675557528704 {
|
||||
name = 'roleIconBadge1675557528704'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "role" ADD "iconUrl" character varying(512)`);
|
||||
await queryRunner.query(`ALTER TABLE "role" ADD "asBadge" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "asBadge"`);
|
||||
await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "iconUrl"`);
|
||||
}
|
||||
}
|
35
packages/backend/migration/1676434944993-drop-group.js
Normal file
35
packages/backend/migration/1676434944993-drop-group.js
Normal file
@@ -0,0 +1,35 @@
|
||||
export class dropGroup1676434944993 {
|
||||
name = 'dropGroup1676434944993'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP CONSTRAINT "FK_ccbf5a8c0be4511133dcc50ddeb"`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" DROP CONSTRAINT "FK_8fe87814e978053a53b1beb7e98"`);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "userGroupJoiningId"`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" DROP COLUMN "userGroupInvitationId"`);
|
||||
await queryRunner.query(`ALTER TYPE "public"."antenna_src_enum" RENAME TO "antenna_src_enum_old"`);
|
||||
await queryRunner.query(`CREATE TYPE "public"."antenna_src_enum" AS ENUM('home', 'all', 'users', 'list')`);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "src" TYPE "public"."antenna_src_enum" USING "src"::"text"::"public"."antenna_src_enum"`);
|
||||
await queryRunner.query(`DROP TYPE "public"."antenna_src_enum_old"`);
|
||||
await queryRunner.query(`ALTER TYPE "public"."notification_type_enum" RENAME TO "notification_type_enum_old"`);
|
||||
await queryRunner.query(`CREATE TYPE "public"."notification_type_enum" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'achievementEarned', 'app')`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ALTER COLUMN "type" TYPE "public"."notification_type_enum" USING "type"::"text"::"public"."notification_type_enum"`);
|
||||
await queryRunner.query(`DROP TYPE "public"."notification_type_enum_old"`);
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "emailNotificationTypes" SET DEFAULT '["follow","receiveFollowRequest"]'`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "user_profile" ALTER COLUMN "emailNotificationTypes" SET DEFAULT '["follow", "receiveFollowRequest", "groupInvited"]'`);
|
||||
await queryRunner.query(`CREATE TYPE "public"."notification_type_enum_old" AS ENUM('follow', 'mention', 'reply', 'renote', 'quote', 'reaction', 'pollVote', 'pollEnded', 'receiveFollowRequest', 'followRequestAccepted', 'groupInvited', 'achievementEarned', 'app')`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ALTER COLUMN "type" TYPE "public"."notification_type_enum_old" USING "type"::"text"::"public"."notification_type_enum_old"`);
|
||||
await queryRunner.query(`DROP TYPE "public"."notification_type_enum"`);
|
||||
await queryRunner.query(`ALTER TYPE "public"."notification_type_enum_old" RENAME TO "notification_type_enum"`);
|
||||
await queryRunner.query(`CREATE TYPE "public"."antenna_src_enum_old" AS ENUM('home', 'all', 'users', 'list', 'group')`);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "src" TYPE "public"."antenna_src_enum_old" USING "src"::"text"::"public"."antenna_src_enum_old"`);
|
||||
await queryRunner.query(`DROP TYPE "public"."antenna_src_enum"`);
|
||||
await queryRunner.query(`ALTER TYPE "public"."antenna_src_enum_old" RENAME TO "antenna_src_enum"`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ADD "userGroupInvitationId" character varying(32)`);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD "userGroupJoiningId" character varying(32)`);
|
||||
await queryRunner.query(`ALTER TABLE "notification" ADD CONSTRAINT "FK_8fe87814e978053a53b1beb7e98" FOREIGN KEY ("userGroupInvitationId") REFERENCES "user_group_invitation"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "antenna" ADD CONSTRAINT "FK_ccbf5a8c0be4511133dcc50ddeb" FOREIGN KEY ("userGroupJoiningId") REFERENCES "user_group_joining"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
}
|
||||
}
|
9
packages/backend/migration/1676438468213-ad3.js
Normal file
9
packages/backend/migration/1676438468213-ad3.js
Normal file
@@ -0,0 +1,9 @@
|
||||
export class ad1676438468213 {
|
||||
name = 'ad1676438468213';
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "ad" ADD "startsAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`);
|
||||
}
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "startsAt"`);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
import { loadConfig } from './built/config.js';
|
||||
import { entities } from './built/postgre.js';
|
||||
import { entities } from './built/postgres.js';
|
||||
|
||||
const config = loadConfig();
|
||||
|
||||
|
@@ -11,7 +11,9 @@
|
||||
"watch:swc": "swc src -d built -D -w",
|
||||
"build": "tsc -p tsconfig.json || echo done. && tsc-alias -p tsconfig.json",
|
||||
"watch": "node watch.mjs",
|
||||
"lint": "tsc --noEmit && eslint --quiet \"src/**/*.ts\"",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"eslint": "eslint --quiet \"src/**/*.ts\"",
|
||||
"lint": "pnpm typecheck && pnpm eslint",
|
||||
"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --runInBand",
|
||||
"jest-and-coverage": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --coverage --forceExit --runInBand",
|
||||
"jest-clear": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --clearCache",
|
||||
@@ -19,34 +21,34 @@
|
||||
"test-and-coverage": "pnpm jest-and-coverage"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@tensorflow/tfjs": "^4.2.0",
|
||||
"@tensorflow/tfjs": "4.2.0",
|
||||
"@tensorflow/tfjs-node": "4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bull-board/api": "^4.11.0",
|
||||
"@bull-board/fastify": "^4.11.0",
|
||||
"@bull-board/ui": "^4.11.0",
|
||||
"@bull-board/api": "4.12.1",
|
||||
"@bull-board/fastify": "4.12.1",
|
||||
"@bull-board/ui": "4.12.1",
|
||||
"@discordapp/twemoji": "14.0.2",
|
||||
"@fastify/accepts": "4.1.0",
|
||||
"@fastify/cookie": "^8.3.0",
|
||||
"@fastify/cookie": "8.3.0",
|
||||
"@fastify/cors": "8.2.0",
|
||||
"@fastify/http-proxy": "^8.4.0",
|
||||
"@fastify/multipart": "7.4.0",
|
||||
"@fastify/static": "6.6.1",
|
||||
"@fastify/view": "7.4.0",
|
||||
"@nestjs/common": "9.2.1",
|
||||
"@nestjs/core": "9.2.1",
|
||||
"@nestjs/testing": "9.2.1",
|
||||
"@fastify/http-proxy": "8.4.0",
|
||||
"@fastify/multipart": "7.4.1",
|
||||
"@fastify/static": "6.9.0",
|
||||
"@fastify/view": "7.4.1",
|
||||
"@nestjs/common": "9.3.9",
|
||||
"@nestjs/core": "9.3.9",
|
||||
"@nestjs/testing": "9.3.9",
|
||||
"@peertube/http-signature": "1.7.0",
|
||||
"@sinonjs/fake-timers": "10.0.2",
|
||||
"accepts": "^1.3.8",
|
||||
"accepts": "1.3.8",
|
||||
"ajv": "8.12.0",
|
||||
"archiver": "5.3.1",
|
||||
"autwh": "0.1.0",
|
||||
"aws-sdk": "2.1295.0",
|
||||
"aws-sdk": "2.1318.0",
|
||||
"bcryptjs": "2.4.3",
|
||||
"blurhash": "2.0.4",
|
||||
"bull": "4.10.2",
|
||||
"blurhash": "2.0.5",
|
||||
"bull": "4.10.4",
|
||||
"cacheable-lookup": "6.1.0",
|
||||
"cbor": "8.1.0",
|
||||
"chalk": "5.2.0",
|
||||
@@ -58,15 +60,16 @@
|
||||
"date-fns": "2.29.3",
|
||||
"deep-email-validator": "0.1.21",
|
||||
"escape-regexp": "0.0.1",
|
||||
"fastify": "4.12.0",
|
||||
"fastify": "4.13.0",
|
||||
"feed": "4.2.2",
|
||||
"file-type": "18.2.0",
|
||||
"file-type": "18.2.1",
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"form-data": "^4.0.0",
|
||||
"form-data": "4.0.0",
|
||||
"got": "12.5.3",
|
||||
"happy-dom": "^8.7.0",
|
||||
"hpagent": "1.2.0",
|
||||
"ioredis": "4.28.5",
|
||||
"ip-cidr": "3.0.11",
|
||||
"ip-cidr": "3.1.0",
|
||||
"is-svg": "4.3.2",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsdom": "21.1.0",
|
||||
@@ -75,21 +78,23 @@
|
||||
"jsrsasign": "10.6.1",
|
||||
"mfm-js": "0.23.3",
|
||||
"mime-types": "2.1.35",
|
||||
"misskey-js": "0.0.14",
|
||||
"misskey-js": "0.0.15",
|
||||
"ms": "3.0.0-canary.1",
|
||||
"nested-property": "4.0.0",
|
||||
"nodemailer": "6.9.0",
|
||||
"node-fetch": "3.3.0",
|
||||
"nodemailer": "6.9.1",
|
||||
"nsfwjs": "2.4.2",
|
||||
"oauth": "^0.10.0",
|
||||
"oauth": "0.10.0",
|
||||
"os-utils": "0.0.14",
|
||||
"otpauth": "^9.0.2",
|
||||
"parse5": "7.1.2",
|
||||
"pg": "8.8.0",
|
||||
"pg": "8.9.0",
|
||||
"private-ip": "3.0.0",
|
||||
"probe-image-size": "7.2.3",
|
||||
"promise-limit": "2.7.0",
|
||||
"pug": "3.0.2",
|
||||
"punycode": "2.3.0",
|
||||
"pureimage": "0.3.15",
|
||||
"pureimage": "0.3.17",
|
||||
"qrcode": "1.5.1",
|
||||
"random-seed": "0.3.0",
|
||||
"ratelimiter": "3.4.1",
|
||||
@@ -101,55 +106,53 @@
|
||||
"rss-parser": "3.12.0",
|
||||
"rxjs": "7.8.0",
|
||||
"s-age": "1.1.2",
|
||||
"sanitize-html": "2.8.1",
|
||||
"seedrandom": "^3.0.5",
|
||||
"sanitize-html": "2.10.0",
|
||||
"seedrandom": "3.0.5",
|
||||
"semver": "7.3.8",
|
||||
"sharp": "0.31.3",
|
||||
"speakeasy": "2.0.0",
|
||||
"strict-event-emitter-types": "2.0.0",
|
||||
"stringz": "2.1.0",
|
||||
"summaly": "2.7.0",
|
||||
"syslog-pro": "git+https://github.com/misskey-dev/SyslogPro#0.2.9-misskey.2",
|
||||
"systeminformation": "5.17.3",
|
||||
"tinycolor2": "1.5.2",
|
||||
"summaly": "github:misskey-dev/summaly",
|
||||
"systeminformation": "5.17.9",
|
||||
"tinycolor2": "1.6.0",
|
||||
"tmp": "0.2.1",
|
||||
"tsc-alias": "1.8.2",
|
||||
"tsconfig-paths": "4.1.2",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typeorm": "0.3.11",
|
||||
"typescript": "4.9.4",
|
||||
"typescript": "4.9.5",
|
||||
"ulid": "2.3.0",
|
||||
"undici": "^5.16.0",
|
||||
"unzipper": "0.10.11",
|
||||
"uuid": "9.0.0",
|
||||
"vary": "1.1.2",
|
||||
"web-push": "3.5.0",
|
||||
"websocket": "1.0.34",
|
||||
"ws": "8.12.0",
|
||||
"ws": "8.12.1",
|
||||
"xev": "3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redocly/openapi-core": "1.0.0-beta.120",
|
||||
"@swc/cli": "^0.1.59",
|
||||
"@swc/core": "1.3.27",
|
||||
"@jest/globals": "29.4.3",
|
||||
"@redocly/openapi-core": "1.0.0-beta.123",
|
||||
"@swc/cli": "0.1.62",
|
||||
"@swc/core": "1.3.35",
|
||||
"@swc/jest": "0.2.24",
|
||||
"@types/accepts": "1.3.5",
|
||||
"@types/archiver": "5.3.1",
|
||||
"@types/bcryptjs": "2.4.2",
|
||||
"@types/bull": "4.10.0",
|
||||
"@types/cbor": "6.0.0",
|
||||
"@types/color-convert": "^2.0.0",
|
||||
"@types/content-disposition": "^0.5.5",
|
||||
"@types/color-convert": "2.0.0",
|
||||
"@types/content-disposition": "0.5.5",
|
||||
"@types/escape-regexp": "0.0.1",
|
||||
"@types/fluent-ffmpeg": "2.1.20",
|
||||
"@types/ioredis": "4.28.10",
|
||||
"@types/jest": "29.2.6",
|
||||
"@types/jest": "29.4.0",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/jsdom": "20.0.1",
|
||||
"@types/jsdom": "21.1.0",
|
||||
"@types/jsonld": "1.5.8",
|
||||
"@types/jsrsasign": "10.5.4",
|
||||
"@types/jsrsasign": "10.5.5",
|
||||
"@types/mime-types": "2.1.1",
|
||||
"@types/node": "18.11.18",
|
||||
"@types/node": "18.14.0",
|
||||
"@types/node-fetch": "3.0.3",
|
||||
"@types/nodemailer": "6.4.7",
|
||||
"@types/oauth": "0.9.1",
|
||||
@@ -165,8 +168,6 @@
|
||||
"@types/semver": "7.3.13",
|
||||
"@types/sharp": "0.31.1",
|
||||
"@types/sinonjs__fake-timers": "8.1.2",
|
||||
"@types/speakeasy": "2.0.7",
|
||||
"@types/syslog-pro": "^1.0.0",
|
||||
"@types/tinycolor2": "1.4.3",
|
||||
"@types/tmp": "0.2.3",
|
||||
"@types/unzipper": "0.10.5",
|
||||
@@ -175,14 +176,13 @@
|
||||
"@types/web-push": "3.3.2",
|
||||
"@types/websocket": "1.0.5",
|
||||
"@types/ws": "8.5.4",
|
||||
"@typescript-eslint/eslint-plugin": "5.49.0",
|
||||
"@typescript-eslint/parser": "5.49.0",
|
||||
"@typescript-eslint/eslint-plugin": "5.52.0",
|
||||
"@typescript-eslint/parser": "5.52.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.32.0",
|
||||
"eslint": "8.34.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"execa": "6.1.0",
|
||||
"jest": "29.3.1",
|
||||
"jest-mock": "^29.3.1",
|
||||
"node-fetch": "3.3.0"
|
||||
"jest": "29.4.3",
|
||||
"jest-mock": "29.4.3"
|
||||
}
|
||||
}
|
||||
|
8
packages/backend/src/@types/redis-lock.d.ts
vendored
Normal file
8
packages/backend/src/@types/redis-lock.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
declare module 'redis-lock' {
|
||||
import type Redis from 'ioredis';
|
||||
|
||||
type Lock = (lockName: string, timeout?: number, taskToPerform?: () => Promise<void>) => void;
|
||||
function redisLock(client: Redis.Redis, retryDelay: number): Lock;
|
||||
|
||||
export = redisLock;
|
||||
}
|
@@ -4,7 +4,7 @@ import { DataSource } from 'typeorm';
|
||||
import { createRedisConnection } from '@/redis.js';
|
||||
import { DI } from './di-symbols.js';
|
||||
import { loadConfig } from './config.js';
|
||||
import { createPostgreDataSource } from './postgre.js';
|
||||
import { createPostgresDataSource } from './postgres.js';
|
||||
import { RepositoryModule } from './models/RepositoryModule.js';
|
||||
import type { Provider, OnApplicationShutdown } from '@nestjs/common';
|
||||
|
||||
@@ -18,7 +18,7 @@ const $config: Provider = {
|
||||
const $db: Provider = {
|
||||
provide: DI.db,
|
||||
useFactory: async (config) => {
|
||||
const db = createPostgreDataSource(config);
|
||||
const db = createPostgresDataSource(config);
|
||||
return await db.initialize();
|
||||
},
|
||||
inject: [DI.config],
|
||||
|
@@ -65,13 +65,9 @@ export type Source = {
|
||||
deliverJobMaxAttempts?: number;
|
||||
inboxJobMaxAttempts?: number;
|
||||
|
||||
syslog: {
|
||||
host: string;
|
||||
port: number;
|
||||
};
|
||||
|
||||
mediaProxy?: string;
|
||||
proxyRemoteFiles?: boolean;
|
||||
videoThumbnailGenerator?: string;
|
||||
|
||||
signToActivityPubGet?: boolean;
|
||||
};
|
||||
@@ -92,6 +88,9 @@ export type Mixin = {
|
||||
userAgent: string;
|
||||
clientEntry: string;
|
||||
clientManifestExists: boolean;
|
||||
mediaProxy: string;
|
||||
externalMediaProxyEnabled: boolean;
|
||||
videoThumbnailGenerator: string | null;
|
||||
};
|
||||
|
||||
export type Config = Source & Mixin;
|
||||
@@ -113,7 +112,7 @@ const path = process.env.NODE_ENV === 'test'
|
||||
|
||||
export function loadConfig() {
|
||||
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../built/meta.json`, 'utf-8'));
|
||||
const clientManifestExists = fs.existsSync(_dirname + '/../../../built/_vite_/manifest.json')
|
||||
const clientManifestExists = fs.existsSync(_dirname + '/../../../built/_vite_/manifest.json');
|
||||
const clientManifest = clientManifestExists ?
|
||||
JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_vite_/manifest.json`, 'utf-8'))
|
||||
: { 'src/init.ts': { file: 'src/init.ts' } };
|
||||
@@ -140,6 +139,17 @@ export function loadConfig() {
|
||||
mixin.clientEntry = clientManifest['src/init.ts'];
|
||||
mixin.clientManifestExists = clientManifestExists;
|
||||
|
||||
const externalMediaProxy = config.mediaProxy ?
|
||||
config.mediaProxy.endsWith('/') ? config.mediaProxy.substring(0, config.mediaProxy.length - 1) : config.mediaProxy
|
||||
: null;
|
||||
const internalMediaProxy = `${mixin.scheme}://${mixin.host}/proxy`;
|
||||
mixin.mediaProxy = externalMediaProxy ?? internalMediaProxy;
|
||||
mixin.externalMediaProxyEnabled = externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy;
|
||||
|
||||
mixin.videoThumbnailGenerator = config.videoThumbnailGenerator ?
|
||||
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
||||
: null;
|
||||
|
||||
if (!config.redis.prefix) config.redis.prefix = mixin.host;
|
||||
|
||||
return Object.assign(config, mixin);
|
||||
|
@@ -32,7 +32,7 @@ export class AccountUpdateService {
|
||||
|
||||
// フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信
|
||||
if (this.userEntityService.isLocalUser(user)) {
|
||||
const content = this.apRendererService.renderActivity(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user));
|
||||
const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user));
|
||||
this.apDeliverManagerService.deliverToFollowers(user, content);
|
||||
this.relayService.deliverToRelays(user, content);
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import { DI } from '@/di-symbols.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { CreateNotificationService } from '@/core/CreateNotificationService.js';
|
||||
|
||||
const ACHIEVEMENT_TYPES = [
|
||||
export const ACHIEVEMENT_TYPES = [
|
||||
'notes1',
|
||||
'notes10',
|
||||
'notes100',
|
||||
|
@@ -10,10 +10,9 @@ import { isUserRelated } from '@/misc/is-user-related.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||
import * as Acct from '@/misc/acct.js';
|
||||
import { Cache } from '@/misc/cache.js';
|
||||
import type { Packed } from '@/misc/schema.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { MutingsRepository, BlockingsRepository, NotesRepository, AntennaNotesRepository, AntennasRepository, UserGroupJoiningsRepository, UserListJoiningsRepository } from '@/models/index.js';
|
||||
import type { MutingsRepository, NotesRepository, AntennaNotesRepository, AntennasRepository, UserListJoiningsRepository } from '@/models/index.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { StreamMessages } from '@/server/api/stream/types.js';
|
||||
@@ -23,7 +22,6 @@ import type { OnApplicationShutdown } from '@nestjs/common';
|
||||
export class AntennaService implements OnApplicationShutdown {
|
||||
private antennasFetched: boolean;
|
||||
private antennas: Antenna[];
|
||||
private blockingCache: Cache<User['id'][]>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redisSubscriber)
|
||||
@@ -32,9 +30,6 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
@Inject(DI.mutingsRepository)
|
||||
private mutingsRepository: MutingsRepository,
|
||||
|
||||
@Inject(DI.blockingsRepository)
|
||||
private blockingsRepository: BlockingsRepository,
|
||||
|
||||
@Inject(DI.notesRepository)
|
||||
private notesRepository: NotesRepository,
|
||||
|
||||
@@ -44,22 +39,18 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
@Inject(DI.antennasRepository)
|
||||
private antennasRepository: AntennasRepository,
|
||||
|
||||
@Inject(DI.userGroupJoiningsRepository)
|
||||
private userGroupJoiningsRepository: UserGroupJoiningsRepository,
|
||||
|
||||
@Inject(DI.userListJoiningsRepository)
|
||||
private userListJoiningsRepository: UserListJoiningsRepository,
|
||||
|
||||
private utilityService: UtilityService,
|
||||
private idService: IdService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private pushNotificationService: PushNotificationService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private antennaEntityService: AntennaEntityService,
|
||||
) {
|
||||
this.antennasFetched = false;
|
||||
this.antennas = [];
|
||||
this.blockingCache = new Cache<User['id'][]>(1000 * 60 * 5);
|
||||
|
||||
this.redisSubscriber.on('message', this.onRedisMessage);
|
||||
}
|
||||
@@ -77,10 +68,16 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
const { type, body } = obj.message as StreamMessages['internal']['payload'];
|
||||
switch (type) {
|
||||
case 'antennaCreated':
|
||||
this.antennas.push(body);
|
||||
this.antennas.push({
|
||||
...body,
|
||||
createdAt: new Date(body.createdAt),
|
||||
});
|
||||
break;
|
||||
case 'antennaUpdated':
|
||||
this.antennas[this.antennas.findIndex(a => a.id === body.id)] = body;
|
||||
this.antennas[this.antennas.findIndex(a => a.id === body.id)] = {
|
||||
...body,
|
||||
createdAt: new Date(body.createdAt),
|
||||
};
|
||||
break;
|
||||
case 'antennaDeleted':
|
||||
this.antennas = this.antennas.filter(a => a.id !== body.id);
|
||||
@@ -103,7 +100,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
read: read,
|
||||
});
|
||||
|
||||
this.globalEventServie.publishAntennaStream(antenna.id, 'note', note);
|
||||
this.globalEventService.publishAntennaStream(antenna.id, 'note', note);
|
||||
|
||||
if (!read) {
|
||||
const mutings = await this.mutingsRepository.find({
|
||||
@@ -133,7 +130,7 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
setTimeout(async () => {
|
||||
const unread = await this.antennaNotesRepository.findOneBy({ antennaId: antenna.id, read: false });
|
||||
if (unread) {
|
||||
this.globalEventServie.publishMainStream(antenna.userId, 'unreadAntenna', antenna);
|
||||
this.globalEventService.publishMainStream(antenna.userId, 'unreadAntenna', antenna);
|
||||
this.pushNotificationService.pushNotification(antenna.userId, 'unreadAntennaNote', {
|
||||
antenna: { id: antenna.id, name: antenna.name },
|
||||
note: await this.noteEntityService.pack(note),
|
||||
@@ -149,10 +146,6 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
public async checkHitAntenna(antenna: Antenna, note: (Note | Packed<'Note'>), noteUser: { id: User['id']; username: string; host: string | null; }): Promise<boolean> {
|
||||
if (note.visibility === 'specified') return false;
|
||||
if (note.visibility === 'followers') return false;
|
||||
|
||||
// アンテナ作成者がノート作成者にブロックされていたらスキップ
|
||||
const blockings = await this.blockingCache.fetch(noteUser.id, () => this.blockingsRepository.findBy({ blockerId: noteUser.id }).then(res => res.map(x => x.blockeeId)));
|
||||
if (blockings.some(blocking => blocking === antenna.userId)) return false;
|
||||
|
||||
if (!antenna.withReplies && note.replyId != null) return false;
|
||||
|
||||
@@ -164,14 +157,6 @@ export class AntennaService implements OnApplicationShutdown {
|
||||
})).map(x => x.userId);
|
||||
|
||||
if (!listUsers.includes(note.userId)) return false;
|
||||
} else if (antenna.src === 'group') {
|
||||
const joining = await this.userGroupJoiningsRepository.findOneByOrFail({ id: antenna.userGroupJoiningId! });
|
||||
|
||||
const groupUsers = (await this.userGroupJoiningsRepository.findBy({
|
||||
userGroupId: joining.userGroupId,
|
||||
})).map(x => x.userId);
|
||||
|
||||
if (!groupUsers.includes(note.userId)) return false;
|
||||
} else if (antenna.src === 'users') {
|
||||
const accts = antenna.users.map(x => {
|
||||
const { username, host } = Acct.parse(x);
|
||||
|
@@ -12,7 +12,7 @@ const retryDelay = 100;
|
||||
|
||||
@Injectable()
|
||||
export class AppLockService {
|
||||
private lock: (key: string, timeout?: number) => Promise<() => void>;
|
||||
private lock: (key: string, timeout?: number, _?: (() => Promise<void>) | undefined) => Promise<() => void>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.redis)
|
||||
|
@@ -21,18 +21,13 @@ export class CaptchaService {
|
||||
response,
|
||||
});
|
||||
|
||||
const res = await this.httpRequestService.fetch(
|
||||
url,
|
||||
{
|
||||
method: 'POST',
|
||||
body: params,
|
||||
const res = await this.httpRequestService.send(url, {
|
||||
method: 'POST',
|
||||
body: params.toString(),
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
{
|
||||
noOkError: true,
|
||||
}
|
||||
).catch(err => {
|
||||
throw `${err.message ?? err}`;
|
||||
});
|
||||
}, { throwErrorWhenResponseNotOk: false });
|
||||
|
||||
if (!res.ok) {
|
||||
throw `${res.status}`;
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DI } from '../di-symbols.js';
|
||||
import { AccountUpdateService } from './AccountUpdateService.js';
|
||||
import { AiService } from './AiService.js';
|
||||
import { AntennaService } from './AntennaService.js';
|
||||
@@ -22,7 +21,6 @@ import { IdService } from './IdService.js';
|
||||
import { ImageProcessingService } from './ImageProcessingService.js';
|
||||
import { InstanceActorService } from './InstanceActorService.js';
|
||||
import { InternalStorageService } from './InternalStorageService.js';
|
||||
import { MessagingService } from './MessagingService.js';
|
||||
import { MetaService } from './MetaService.js';
|
||||
import { MfmService } from './MfmService.js';
|
||||
import { ModerationLogService } from './ModerationLogService.js';
|
||||
@@ -62,7 +60,6 @@ import PerUserNotesChart from './chart/charts/per-user-notes.js';
|
||||
import PerUserPvChart from './chart/charts/per-user-pv.js';
|
||||
import DriveChart from './chart/charts/drive.js';
|
||||
import PerUserReactionsChart from './chart/charts/per-user-reactions.js';
|
||||
import HashtagChart from './chart/charts/hashtag.js';
|
||||
import PerUserFollowingChart from './chart/charts/per-user-following.js';
|
||||
import PerUserDriveChart from './chart/charts/per-user-drive.js';
|
||||
import ApRequestChart from './chart/charts/ap-request.js';
|
||||
@@ -83,7 +80,6 @@ import { GalleryLikeEntityService } from './entities/GalleryLikeEntityService.js
|
||||
import { GalleryPostEntityService } from './entities/GalleryPostEntityService.js';
|
||||
import { HashtagEntityService } from './entities/HashtagEntityService.js';
|
||||
import { InstanceEntityService } from './entities/InstanceEntityService.js';
|
||||
import { MessagingMessageEntityService } from './entities/MessagingMessageEntityService.js';
|
||||
import { ModerationLogEntityService } from './entities/ModerationLogEntityService.js';
|
||||
import { MutingEntityService } from './entities/MutingEntityService.js';
|
||||
import { NoteEntityService } from './entities/NoteEntityService.js';
|
||||
@@ -94,8 +90,6 @@ import { PageEntityService } from './entities/PageEntityService.js';
|
||||
import { PageLikeEntityService } from './entities/PageLikeEntityService.js';
|
||||
import { SigninEntityService } from './entities/SigninEntityService.js';
|
||||
import { UserEntityService } from './entities/UserEntityService.js';
|
||||
import { UserGroupEntityService } from './entities/UserGroupEntityService.js';
|
||||
import { UserGroupInvitationEntityService } from './entities/UserGroupInvitationEntityService.js';
|
||||
import { UserListEntityService } from './entities/UserListEntityService.js';
|
||||
import { FlashEntityService } from './entities/FlashEntityService.js';
|
||||
import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
|
||||
@@ -147,7 +141,6 @@ const $IdService: Provider = { provide: 'IdService', useExisting: IdService };
|
||||
const $ImageProcessingService: Provider = { provide: 'ImageProcessingService', useExisting: ImageProcessingService };
|
||||
const $InstanceActorService: Provider = { provide: 'InstanceActorService', useExisting: InstanceActorService };
|
||||
const $InternalStorageService: Provider = { provide: 'InternalStorageService', useExisting: InternalStorageService };
|
||||
const $MessagingService: Provider = { provide: 'MessagingService', useExisting: MessagingService };
|
||||
const $MetaService: Provider = { provide: 'MetaService', useExisting: MetaService };
|
||||
const $MfmService: Provider = { provide: 'MfmService', useExisting: MfmService };
|
||||
const $ModerationLogService: Provider = { provide: 'ModerationLogService', useExisting: ModerationLogService };
|
||||
@@ -187,7 +180,6 @@ const $PerUserNotesChart: Provider = { provide: 'PerUserNotesChart', useExisting
|
||||
const $PerUserPvChart: Provider = { provide: 'PerUserPvChart', useExisting: PerUserPvChart };
|
||||
const $DriveChart: Provider = { provide: 'DriveChart', useExisting: DriveChart };
|
||||
const $PerUserReactionsChart: Provider = { provide: 'PerUserReactionsChart', useExisting: PerUserReactionsChart };
|
||||
const $HashtagChart: Provider = { provide: 'HashtagChart', useExisting: HashtagChart };
|
||||
const $PerUserFollowingChart: Provider = { provide: 'PerUserFollowingChart', useExisting: PerUserFollowingChart };
|
||||
const $PerUserDriveChart: Provider = { provide: 'PerUserDriveChart', useExisting: PerUserDriveChart };
|
||||
const $ApRequestChart: Provider = { provide: 'ApRequestChart', useExisting: ApRequestChart };
|
||||
@@ -209,7 +201,6 @@ const $GalleryLikeEntityService: Provider = { provide: 'GalleryLikeEntityService
|
||||
const $GalleryPostEntityService: Provider = { provide: 'GalleryPostEntityService', useExisting: GalleryPostEntityService };
|
||||
const $HashtagEntityService: Provider = { provide: 'HashtagEntityService', useExisting: HashtagEntityService };
|
||||
const $InstanceEntityService: Provider = { provide: 'InstanceEntityService', useExisting: InstanceEntityService };
|
||||
const $MessagingMessageEntityService: Provider = { provide: 'MessagingMessageEntityService', useExisting: MessagingMessageEntityService };
|
||||
const $ModerationLogEntityService: Provider = { provide: 'ModerationLogEntityService', useExisting: ModerationLogEntityService };
|
||||
const $MutingEntityService: Provider = { provide: 'MutingEntityService', useExisting: MutingEntityService };
|
||||
const $NoteEntityService: Provider = { provide: 'NoteEntityService', useExisting: NoteEntityService };
|
||||
@@ -220,8 +211,6 @@ const $PageEntityService: Provider = { provide: 'PageEntityService', useExisting
|
||||
const $PageLikeEntityService: Provider = { provide: 'PageLikeEntityService', useExisting: PageLikeEntityService };
|
||||
const $SigninEntityService: Provider = { provide: 'SigninEntityService', useExisting: SigninEntityService };
|
||||
const $UserEntityService: Provider = { provide: 'UserEntityService', useExisting: UserEntityService };
|
||||
const $UserGroupEntityService: Provider = { provide: 'UserGroupEntityService', useExisting: UserGroupEntityService };
|
||||
const $UserGroupInvitationEntityService: Provider = { provide: 'UserGroupInvitationEntityService', useExisting: UserGroupInvitationEntityService };
|
||||
const $UserListEntityService: Provider = { provide: 'UserListEntityService', useExisting: UserListEntityService };
|
||||
const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisting: FlashEntityService };
|
||||
const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
|
||||
@@ -275,7 +264,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
ImageProcessingService,
|
||||
InstanceActorService,
|
||||
InternalStorageService,
|
||||
MessagingService,
|
||||
MetaService,
|
||||
MfmService,
|
||||
ModerationLogService,
|
||||
@@ -315,7 +303,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
PerUserPvChart,
|
||||
DriveChart,
|
||||
PerUserReactionsChart,
|
||||
HashtagChart,
|
||||
PerUserFollowingChart,
|
||||
PerUserDriveChart,
|
||||
ApRequestChart,
|
||||
@@ -336,7 +323,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
GalleryPostEntityService,
|
||||
HashtagEntityService,
|
||||
InstanceEntityService,
|
||||
MessagingMessageEntityService,
|
||||
ModerationLogEntityService,
|
||||
MutingEntityService,
|
||||
NoteEntityService,
|
||||
@@ -347,8 +333,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
PageLikeEntityService,
|
||||
SigninEntityService,
|
||||
UserEntityService,
|
||||
UserGroupEntityService,
|
||||
UserGroupInvitationEntityService,
|
||||
UserListEntityService,
|
||||
FlashEntityService,
|
||||
FlashLikeEntityService,
|
||||
@@ -397,7 +381,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$ImageProcessingService,
|
||||
$InstanceActorService,
|
||||
$InternalStorageService,
|
||||
$MessagingService,
|
||||
$MetaService,
|
||||
$MfmService,
|
||||
$ModerationLogService,
|
||||
@@ -437,7 +420,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$PerUserPvChart,
|
||||
$DriveChart,
|
||||
$PerUserReactionsChart,
|
||||
$HashtagChart,
|
||||
$PerUserFollowingChart,
|
||||
$PerUserDriveChart,
|
||||
$ApRequestChart,
|
||||
@@ -458,7 +440,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$GalleryPostEntityService,
|
||||
$HashtagEntityService,
|
||||
$InstanceEntityService,
|
||||
$MessagingMessageEntityService,
|
||||
$ModerationLogEntityService,
|
||||
$MutingEntityService,
|
||||
$NoteEntityService,
|
||||
@@ -469,8 +450,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$PageLikeEntityService,
|
||||
$SigninEntityService,
|
||||
$UserEntityService,
|
||||
$UserGroupEntityService,
|
||||
$UserGroupInvitationEntityService,
|
||||
$UserListEntityService,
|
||||
$FlashEntityService,
|
||||
$FlashLikeEntityService,
|
||||
@@ -520,7 +499,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
ImageProcessingService,
|
||||
InstanceActorService,
|
||||
InternalStorageService,
|
||||
MessagingService,
|
||||
MetaService,
|
||||
MfmService,
|
||||
ModerationLogService,
|
||||
@@ -559,7 +537,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
PerUserPvChart,
|
||||
DriveChart,
|
||||
PerUserReactionsChart,
|
||||
HashtagChart,
|
||||
PerUserFollowingChart,
|
||||
PerUserDriveChart,
|
||||
ApRequestChart,
|
||||
@@ -580,7 +557,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
GalleryPostEntityService,
|
||||
HashtagEntityService,
|
||||
InstanceEntityService,
|
||||
MessagingMessageEntityService,
|
||||
ModerationLogEntityService,
|
||||
MutingEntityService,
|
||||
NoteEntityService,
|
||||
@@ -591,8 +567,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
PageLikeEntityService,
|
||||
SigninEntityService,
|
||||
UserEntityService,
|
||||
UserGroupEntityService,
|
||||
UserGroupInvitationEntityService,
|
||||
UserListEntityService,
|
||||
FlashEntityService,
|
||||
FlashLikeEntityService,
|
||||
@@ -641,7 +615,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$ImageProcessingService,
|
||||
$InstanceActorService,
|
||||
$InternalStorageService,
|
||||
$MessagingService,
|
||||
$MetaService,
|
||||
$MfmService,
|
||||
$ModerationLogService,
|
||||
@@ -680,7 +653,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$PerUserPvChart,
|
||||
$DriveChart,
|
||||
$PerUserReactionsChart,
|
||||
$HashtagChart,
|
||||
$PerUserFollowingChart,
|
||||
$PerUserDriveChart,
|
||||
$ApRequestChart,
|
||||
@@ -701,7 +673,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$GalleryPostEntityService,
|
||||
$HashtagEntityService,
|
||||
$InstanceEntityService,
|
||||
$MessagingMessageEntityService,
|
||||
$ModerationLogEntityService,
|
||||
$MutingEntityService,
|
||||
$NoteEntityService,
|
||||
@@ -712,8 +683,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||
$PageLikeEntityService,
|
||||
$SigninEntityService,
|
||||
$UserEntityService,
|
||||
$UserGroupEntityService,
|
||||
$UserGroupInvitationEntityService,
|
||||
$UserListEntityService,
|
||||
$FlashEntityService,
|
||||
$FlashLikeEntityService,
|
||||
|
@@ -26,7 +26,7 @@ export class CreateNotificationService {
|
||||
|
||||
private notificationEntityService: NotificationEntityService,
|
||||
private idService: IdService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private pushNotificationService: PushNotificationService,
|
||||
) {
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export class CreateNotificationService {
|
||||
const packed = await this.notificationEntityService.pack(notification, {});
|
||||
|
||||
// Publish notification event
|
||||
this.globalEventServie.publishMainStream(notifieeId, 'notification', packed);
|
||||
this.globalEventService.publishMainStream(notifieeId, 'notification', packed);
|
||||
|
||||
// 2秒経っても(今回作成した)通知が既読にならなかったら「未読の通知がありますよ」イベントを発行する
|
||||
setTimeout(async () => {
|
||||
@@ -77,7 +77,7 @@ export class CreateNotificationService {
|
||||
}
|
||||
//#endregion
|
||||
|
||||
this.globalEventServie.publishMainStream(notifieeId, 'unreadNotification', packed);
|
||||
this.globalEventService.publishMainStream(notifieeId, 'unreadNotification', packed);
|
||||
this.pushNotificationService.pushNotification(notifieeId, 'notification', packed);
|
||||
|
||||
if (type === 'follow') this.emailNotificationFollow(notifieeId, await this.usersRepository.findOneByOrFail({ id: data.notifierId! }));
|
||||
|
@@ -2,22 +2,39 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { DataSource, In, IsNull } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { EmojiEntityService } from '@/core/entities/EmojiEntityService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import type { DriveFile } from '@/models/entities/DriveFile.js';
|
||||
import type { Emoji } from '@/models/entities/Emoji.js';
|
||||
import type { EmojisRepository } from '@/models/index.js';
|
||||
import type { EmojisRepository, Note } from '@/models/index.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { Cache } from '@/misc/cache.js';
|
||||
import { UtilityService } from '@/core/UtilityService.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { ReactionService } from '@/core/ReactionService.js';
|
||||
import { query } from '@/misc/prelude/url.js';
|
||||
|
||||
@Injectable()
|
||||
export class CustomEmojiService {
|
||||
private cache: Cache<Emoji | null>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.db)
|
||||
private db: DataSource,
|
||||
|
||||
@Inject(DI.emojisRepository)
|
||||
private emojisRepository: EmojisRepository,
|
||||
|
||||
private utilityService: UtilityService,
|
||||
private idService: IdService,
|
||||
private emojiEntityService: EmojiEntityService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private reactionService: ReactionService,
|
||||
) {
|
||||
this.cache = new Cache<Emoji | null>(1000 * 60 * 60 * 12);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
@@ -40,8 +57,135 @@ export class CustomEmojiService {
|
||||
type: data.driveFile.webpublicType ?? data.driveFile.type,
|
||||
}).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
|
||||
|
||||
await this.db.queryResultCache!.remove(['meta_emojis']);
|
||||
if (data.host == null) {
|
||||
await this.db.queryResultCache!.remove(['meta_emojis']);
|
||||
|
||||
this.globalEventService.publishBroadcastStream('emojiAdded', {
|
||||
emoji: await this.emojiEntityService.packDetailed(emoji.id),
|
||||
});
|
||||
}
|
||||
|
||||
return emoji;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private normalizeHost(src: string | undefined, noteUserHost: string | null): string | null {
|
||||
// クエリに使うホスト
|
||||
let host = src === '.' ? null // .はローカルホスト (ここがマッチするのはリアクションのみ)
|
||||
: src === undefined ? noteUserHost // ノートなどでホスト省略表記の場合はローカルホスト (ここがリアクションにマッチすることはない)
|
||||
: this.utilityService.isSelfHost(src) ? null // 自ホスト指定
|
||||
: (src || noteUserHost); // 指定されたホスト || ノートなどの所有者のホスト (こっちがリアクションにマッチすることはない)
|
||||
|
||||
host = this.utilityService.toPunyNullable(host);
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private parseEmojiStr(emojiName: string, noteUserHost: string | null) {
|
||||
const match = emojiName.match(/^(\w+)(?:@([\w.-]+))?$/);
|
||||
if (!match) return { name: null, host: null };
|
||||
|
||||
const name = match[1];
|
||||
|
||||
// ホスト正規化
|
||||
const host = this.utilityService.toPunyNullable(this.normalizeHost(match[2], noteUserHost));
|
||||
|
||||
return { name, host };
|
||||
}
|
||||
|
||||
/**
|
||||
* 添付用(リモート)カスタム絵文字URLを解決する
|
||||
* @param emojiName ノートやユーザープロフィールに添付された、またはリアクションのカスタム絵文字名 (:は含めない, リアクションでローカルホストの場合は@.を付ける (これはdecodeReactionで可能))
|
||||
* @param noteUserHost ノートやユーザープロフィールの所有者のホスト
|
||||
* @returns URL, nullは未マッチを意味する
|
||||
*/
|
||||
@bindThis
|
||||
public async populateEmoji(emojiName: string, noteUserHost: string | null): Promise<string | null> {
|
||||
const { name, host } = this.parseEmojiStr(emojiName, noteUserHost);
|
||||
if (name == null) return null;
|
||||
if (host == null) return null;
|
||||
|
||||
const queryOrNull = async () => (await this.emojisRepository.findOneBy({
|
||||
name,
|
||||
host: host ?? IsNull(),
|
||||
})) ?? null;
|
||||
|
||||
const emoji = await this.cache.fetch(`${name} ${host}`, queryOrNull);
|
||||
|
||||
if (emoji == null) return null;
|
||||
|
||||
const isLocal = emoji.host == null;
|
||||
const emojiUrl = emoji.publicUrl || emoji.originalUrl; // || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
||||
const url = isLocal
|
||||
? emojiUrl
|
||||
: this.config.proxyRemoteFiles
|
||||
? `${this.config.mediaProxy}/emoji.webp?${query({ url: emojiUrl })}`
|
||||
: emojiUrl;
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 複数の添付用(リモート)カスタム絵文字URLを解決する (キャシュ付き, 存在しないものは結果から除外される)
|
||||
*/
|
||||
@bindThis
|
||||
public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise<Record<string, string>> {
|
||||
const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
|
||||
const res = {} as any;
|
||||
for (let i = 0; i < emojiNames.length; i++) {
|
||||
if (emojis[i] != null) {
|
||||
res[emojiNames[i]] = emojis[i];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public aggregateNoteEmojis(notes: Note[]) {
|
||||
let emojis: { name: string | null; host: string | null; }[] = [];
|
||||
for (const note of notes) {
|
||||
emojis = emojis.concat(note.emojis
|
||||
.map(e => this.parseEmojiStr(e, note.userHost)));
|
||||
if (note.renote) {
|
||||
emojis = emojis.concat(note.renote.emojis
|
||||
.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
|
||||
if (note.renote.user) {
|
||||
emojis = emojis.concat(note.renote.user.emojis
|
||||
.map(e => this.parseEmojiStr(e, note.renote!.userHost)));
|
||||
}
|
||||
}
|
||||
const customReactions = Object.keys(note.reactions).map(x => this.reactionService.decodeReaction(x)).filter(x => x.name != null) as typeof emojis;
|
||||
emojis = emojis.concat(customReactions);
|
||||
if (note.user) {
|
||||
emojis = emojis.concat(note.user.emojis
|
||||
.map(e => this.parseEmojiStr(e, note.userHost)));
|
||||
}
|
||||
}
|
||||
return emojis.filter(x => x.name != null && x.host != null) as { name: string; host: string; }[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 与えられた絵文字のリストをデータベースから取得し、キャッシュに追加します
|
||||
*/
|
||||
@bindThis
|
||||
public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise<void> {
|
||||
const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null);
|
||||
const emojisQuery: any[] = [];
|
||||
const hosts = new Set(notCachedEmojis.map(e => e.host));
|
||||
for (const host of hosts) {
|
||||
if (host == null) continue;
|
||||
emojisQuery.push({
|
||||
name: In(notCachedEmojis.filter(e => e.host === host).map(e => e.name)),
|
||||
host: host,
|
||||
});
|
||||
}
|
||||
const _emojis = emojisQuery.length > 0 ? await this.emojisRepository.find({
|
||||
where: emojisQuery,
|
||||
select: ['name', 'host', 'originalUrl', 'publicUrl'],
|
||||
}) : [];
|
||||
for (const emoji of _emojis) {
|
||||
this.cache.set(`${emoji.name} ${emoji.host}`, emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ export class DeleteAccountService {
|
||||
|
||||
private userSuspendService: UserSuspendService,
|
||||
private queueService: QueueService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
private globalEventService: GlobalEventService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -38,6 +38,6 @@ export class DeleteAccountService {
|
||||
});
|
||||
|
||||
// Terminate streaming
|
||||
this.globalEventServie.publishUserEvent(user.id, 'terminate', {});
|
||||
this.globalEventService.publishUserEvent(user.id, 'terminate', {});
|
||||
}
|
||||
}
|
||||
|
@@ -5,10 +5,10 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import IPCIDR from 'ip-cidr';
|
||||
import PrivateIp from 'private-ip';
|
||||
import chalk from 'chalk';
|
||||
import { buildConnector } from 'undici';
|
||||
import got, * as Got from 'got';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { createTemp } from '@/misc/create-temp.js';
|
||||
import { StatusError } from '@/misc/status-error.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
@@ -20,7 +20,6 @@ import { bindThis } from '@/decorators.js';
|
||||
@Injectable()
|
||||
export class DownloadService {
|
||||
private logger: Logger;
|
||||
private undiciFetcher: UndiciFetcher;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
@@ -30,21 +29,6 @@ export class DownloadService {
|
||||
private loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = this.loggerService.getLogger('download');
|
||||
|
||||
this.undiciFetcher = this.httpRequestService.createFetcher({
|
||||
connect: process.env.NODE_ENV === 'development' ?
|
||||
this.httpRequestService.clientDefaults.connect
|
||||
:
|
||||
this.httpRequestService.getConnectorWithIpCheck(
|
||||
buildConnector({
|
||||
...this.httpRequestService.clientDefaults.connect,
|
||||
}),
|
||||
(ip) => !this.isPrivateIp(ip),
|
||||
),
|
||||
bodyTimeout: 30 * 1000,
|
||||
}, {
|
||||
connect: this.httpRequestService.clientDefaults.connect,
|
||||
}, this.logger);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
@@ -55,14 +39,61 @@ export class DownloadService {
|
||||
const operationTimeout = 60 * 1000;
|
||||
const maxSize = this.config.maxFileSize ?? 262144000;
|
||||
|
||||
const response = await this.undiciFetcher.fetch(url);
|
||||
const req = got.stream(url, {
|
||||
headers: {
|
||||
'User-Agent': this.config.userAgent,
|
||||
},
|
||||
timeout: {
|
||||
lookup: timeout,
|
||||
connect: timeout,
|
||||
secureConnect: timeout,
|
||||
socket: timeout, // read timeout
|
||||
response: timeout,
|
||||
send: timeout,
|
||||
request: operationTimeout, // whole operation timeout
|
||||
},
|
||||
agent: {
|
||||
http: this.httpRequestService.httpAgent,
|
||||
https: this.httpRequestService.httpsAgent,
|
||||
},
|
||||
http2: false, // default
|
||||
retry: {
|
||||
limit: 0,
|
||||
},
|
||||
enableUnixSockets: false,
|
||||
}).on('response', (res: Got.Response) => {
|
||||
if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) {
|
||||
if (this.isPrivateIp(res.ip)) {
|
||||
this.logger.warn(`Blocked address: ${res.ip}`);
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (response.body === null) {
|
||||
throw new StatusError('No body', 400, 'No body');
|
||||
const contentLength = res.headers['content-length'];
|
||||
if (contentLength != null) {
|
||||
const size = Number(contentLength);
|
||||
if (size > maxSize) {
|
||||
this.logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
|
||||
req.destroy();
|
||||
}
|
||||
}
|
||||
}).on('downloadProgress', (progress: Got.Progress) => {
|
||||
if (progress.transferred > maxSize) {
|
||||
this.logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`);
|
||||
req.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await pipeline(req, fs.createWriteStream(path));
|
||||
} catch (e) {
|
||||
if (e instanceof Got.HTTPError) {
|
||||
throw new StatusError(`${e.response.statusCode} ${e.response.statusMessage}`, e.response.statusCode, e.response.statusMessage);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
await pipeline(stream.Readable.fromWeb(response.body), fs.createWriteStream(path));
|
||||
|
||||
this.logger.succ(`Download finished: ${chalk.cyan(url)}`);
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import { DI } from '@/di-symbols.js';
|
||||
import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository } from '@/models/index.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import Logger from '@/logger.js';
|
||||
import type { IRemoteUser, User } from '@/models/entities/User.js';
|
||||
import type { RemoteUser, User } from '@/models/entities/User.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
import { DriveFile } from '@/models/entities/DriveFile.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
@@ -250,6 +250,14 @@ export class DriveService {
|
||||
@bindThis
|
||||
public async generateAlts(path: string, type: string, generateWeb: boolean) {
|
||||
if (type.startsWith('video/')) {
|
||||
if (this.config.videoThumbnailGenerator != null) {
|
||||
// videoThumbnailGeneratorが指定されていたら動画サムネイル生成はスキップ
|
||||
return {
|
||||
webpublic: null,
|
||||
thumbnail: null,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const thumbnail = await this.videoProcessingService.generateVideoThumbnail(path);
|
||||
return {
|
||||
@@ -391,7 +399,7 @@ export class DriveService {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async deleteOldFile(user: IRemoteUser) {
|
||||
private async deleteOldFile(user: RemoteUser) {
|
||||
const q = this.driveFilesRepository.createQueryBuilder('file')
|
||||
.where('file.userId = :userId', { userId: user.id })
|
||||
.andWhere('file.isLink = FALSE');
|
||||
@@ -492,7 +500,7 @@ export class DriveService {
|
||||
throw new IdentifiableError('c6244ed2-a39a-4e1c-bf93-f0fbd7764fa6', 'No free space.');
|
||||
} else {
|
||||
// (アバターまたはバナーを含まず)最も古いファイルを削除する
|
||||
this.deleteOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as IRemoteUser);
|
||||
this.deleteOldFile(await this.usersRepository.findOneByOrFail({ id: user.id }) as RemoteUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -190,7 +190,9 @@ export class FetchInstanceMetadataService {
|
||||
|
||||
const faviconUrl = url + '/favicon.ico';
|
||||
|
||||
const favicon = await this.httpRequestService.fetch(faviconUrl, {}, { noOkError: true });
|
||||
const favicon = await this.httpRequestService.send(faviconUrl, {
|
||||
method: 'HEAD',
|
||||
}, { throwErrorWhenResponseNotOk: false });
|
||||
|
||||
if (favicon.ok) {
|
||||
return faviconUrl;
|
||||
|
@@ -3,7 +3,7 @@ import * as crypto from 'node:crypto';
|
||||
import { join } from 'node:path';
|
||||
import * as stream from 'node:stream';
|
||||
import * as util from 'node:util';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { FSWatcher } from 'chokidar';
|
||||
import { fileTypeFromFile } from 'file-type';
|
||||
import FFmpeg from 'fluent-ffmpeg';
|
||||
|
@@ -3,21 +3,15 @@ import Redis from 'ioredis';
|
||||
import type { User } from '@/models/entities/User.js';
|
||||
import type { Note } from '@/models/entities/Note.js';
|
||||
import type { UserList } from '@/models/entities/UserList.js';
|
||||
import type { UserGroup } from '@/models/entities/UserGroup.js';
|
||||
import type { Antenna } from '@/models/entities/Antenna.js';
|
||||
import type { Channel } from '@/models/entities/Channel.js';
|
||||
import type {
|
||||
StreamChannels,
|
||||
AdminStreamTypes,
|
||||
AntennaStreamTypes,
|
||||
BroadcastTypes,
|
||||
ChannelStreamTypes,
|
||||
DriveStreamTypes,
|
||||
GroupMessagingStreamTypes,
|
||||
InternalStreamTypes,
|
||||
MainStreamTypes,
|
||||
MessagingIndexStreamTypes,
|
||||
MessagingStreamTypes,
|
||||
NoteStreamTypes,
|
||||
UserListStreamTypes,
|
||||
UserStreamTypes,
|
||||
@@ -83,11 +77,6 @@ export class GlobalEventService {
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public publishChannelStream<K extends keyof ChannelStreamTypes>(channelId: Channel['id'], type: K, value?: ChannelStreamTypes[K]): void {
|
||||
this.publish(`channelStream:${channelId}`, type, typeof value === 'undefined' ? null : value);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public publishUserListStream<K extends keyof UserListStreamTypes>(listId: UserList['id'], type: K, value?: UserListStreamTypes[K]): void {
|
||||
this.publish(`userListStream:${listId}`, type, typeof value === 'undefined' ? null : value);
|
||||
@@ -98,21 +87,6 @@ export class GlobalEventService {
|
||||
this.publish(`antennaStream:${antennaId}`, type, typeof value === 'undefined' ? null : value);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public publishMessagingStream<K extends keyof MessagingStreamTypes>(userId: User['id'], otherpartyId: User['id'], type: K, value?: MessagingStreamTypes[K]): void {
|
||||
this.publish(`messagingStream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public publishGroupMessagingStream<K extends keyof GroupMessagingStreamTypes>(groupId: UserGroup['id'], type: K, value?: GroupMessagingStreamTypes[K]): void {
|
||||
this.publish(`messagingStream:${groupId}`, type, typeof value === 'undefined' ? null : value);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public publishMessagingIndexStream<K extends keyof MessagingIndexStreamTypes>(userId: User['id'], type: K, value?: MessagingIndexStreamTypes[K]): void {
|
||||
this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public publishNotesStream(note: Packed<'Note'>): void {
|
||||
this.publish('notesStream', null, note);
|
||||
|
@@ -4,7 +4,6 @@ import type { User } from '@/models/entities/User.js';
|
||||
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { Hashtag } from '@/models/entities/Hashtag.js';
|
||||
import HashtagChart from '@/core/chart/charts/hashtag.js';
|
||||
import type { HashtagsRepository, UsersRepository } from '@/models/index.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
@@ -20,7 +19,6 @@ export class HashtagService {
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private idService: IdService,
|
||||
private hashtagChart: HashtagChart,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -143,9 +141,5 @@ export class HashtagService {
|
||||
} as Hashtag);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUserAttached) {
|
||||
this.hashtagChart.update(tag, user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,284 +1,67 @@
|
||||
import * as http from 'node:http';
|
||||
import * as https from 'node:https';
|
||||
import { LookupFunction } from 'node:net';
|
||||
import CacheableLookup from 'cacheable-lookup';
|
||||
import fetch from 'node-fetch';
|
||||
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as undici from 'undici';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { StatusError } from '@/misc/status-error.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import type Logger from '@/logger.js';
|
||||
|
||||
// true to allow, false to deny
|
||||
export type IpChecker = (ip: string) => boolean;
|
||||
|
||||
/*
|
||||
* Child class to create and save Agent for fetch.
|
||||
* You should construct this when you want
|
||||
* to change timeout, size limit, socket connect function, etc.
|
||||
*/
|
||||
export class UndiciFetcher {
|
||||
/**
|
||||
* Get http non-proxy agent (undici)
|
||||
*/
|
||||
public nonProxiedAgent: undici.Agent;
|
||||
|
||||
/**
|
||||
* Get http proxy or non-proxy agent (undici)
|
||||
*/
|
||||
public agent: undici.ProxyAgent | undici.Agent;
|
||||
|
||||
private proxyBypassHosts: string[];
|
||||
private userAgent: string | undefined;
|
||||
|
||||
private logger: Logger | undefined;
|
||||
|
||||
constructor(
|
||||
args: {
|
||||
agentOptions: undici.Agent.Options;
|
||||
proxy?: {
|
||||
uri: string;
|
||||
options?: undici.Agent.Options; // Override of agentOptions
|
||||
},
|
||||
proxyBypassHosts?: string[];
|
||||
userAgent?: string;
|
||||
},
|
||||
logger?: Logger,
|
||||
) {
|
||||
this.logger = logger;
|
||||
this.logger?.debug('UndiciFetcher constructor', args);
|
||||
|
||||
this.proxyBypassHosts = args.proxyBypassHosts ?? [];
|
||||
this.userAgent = args.userAgent;
|
||||
|
||||
this.nonProxiedAgent = new undici.Agent({
|
||||
...args.agentOptions,
|
||||
connect: (process.env.NODE_ENV !== 'production' && typeof args.agentOptions.connect !== 'function')
|
||||
? (options, cb) => {
|
||||
// Custom connector for debug
|
||||
undici.buildConnector(args.agentOptions.connect as undici.buildConnector.BuildOptions)(options, (err, socket) => {
|
||||
this.logger?.debug('Socket connector called', socket);
|
||||
if (err) {
|
||||
this.logger?.debug('Socket error', err);
|
||||
cb(new Error(`Error while socket connecting\n${err}`), null);
|
||||
return;
|
||||
}
|
||||
this.logger?.debug(`Socket connected: port ${socket.localPort} => remote ${socket.remoteAddress}`);
|
||||
cb(null, socket);
|
||||
});
|
||||
} : args.agentOptions.connect,
|
||||
});
|
||||
|
||||
this.agent = args.proxy
|
||||
? new undici.ProxyAgent({
|
||||
...args.agentOptions,
|
||||
...args.proxy.options,
|
||||
|
||||
uri: args.proxy.uri,
|
||||
|
||||
connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy.options?.connect ?? args.agentOptions.connect) !== 'function')
|
||||
? (options, cb) => {
|
||||
// Custom connector for debug
|
||||
undici.buildConnector((args.proxy?.options?.connect ?? args.agentOptions.connect) as undici.buildConnector.BuildOptions)(options, (err, socket) => {
|
||||
this.logger?.debug('Socket connector called (secure)', socket);
|
||||
if (err) {
|
||||
this.logger?.debug('Socket error', err);
|
||||
cb(new Error(`Error while socket connecting\n${err}`), null);
|
||||
return;
|
||||
}
|
||||
this.logger?.debug(`Socket connected (secure): port ${socket.localPort} => remote ${socket.remoteAddress}`);
|
||||
cb(null, socket);
|
||||
});
|
||||
} : (args.proxy.options?.connect ?? args.agentOptions.connect),
|
||||
})
|
||||
: this.nonProxiedAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get agent by URL
|
||||
* @param url URL
|
||||
* @param bypassProxy Allways bypass proxy
|
||||
*/
|
||||
@bindThis
|
||||
public getAgentByUrl(url: URL, bypassProxy = false): undici.Agent | undici.ProxyAgent {
|
||||
if (bypassProxy || this.proxyBypassHosts.includes(url.hostname)) {
|
||||
return this.nonProxiedAgent;
|
||||
} else {
|
||||
return this.agent;
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async fetch(
|
||||
url: string | URL,
|
||||
options: undici.RequestInit = {},
|
||||
privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false },
|
||||
): Promise<undici.Response> {
|
||||
const res = await undici.fetch(url, {
|
||||
dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
|
||||
...options,
|
||||
headers: {
|
||||
'User-Agent': this.userAgent ?? '',
|
||||
...(options.headers ?? {}),
|
||||
},
|
||||
}).catch((err) => {
|
||||
this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err);
|
||||
throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable');
|
||||
});
|
||||
if (!res.ok && !privateOptions.noOkError) {
|
||||
throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async request(
|
||||
url: string | URL,
|
||||
options: { dispatcher?: undici.Dispatcher } & Omit<undici.Dispatcher.RequestOptions, 'origin' | 'path' | 'method'> & Partial<Pick<undici.Dispatcher.RequestOptions, 'method'>> = {},
|
||||
privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false },
|
||||
): Promise<undici.Dispatcher.ResponseData> {
|
||||
const res = await undici.request(url, {
|
||||
dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
|
||||
...options,
|
||||
headers: {
|
||||
'user-agent': this.userAgent ?? '',
|
||||
...(options.headers ?? {}),
|
||||
},
|
||||
}).catch((err) => {
|
||||
this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err);
|
||||
throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable');
|
||||
});
|
||||
|
||||
if (res.statusCode >= 400) {
|
||||
throw new StatusError(`${res.statusCode}`, res.statusCode, '');
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getJson<T extends unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
|
||||
const { body } = await this.request(
|
||||
url,
|
||||
{
|
||||
headers: Object.assign({
|
||||
Accept: accept,
|
||||
}, headers ?? {}),
|
||||
},
|
||||
);
|
||||
|
||||
return await body.json() as T;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
|
||||
const { body } = await this.request(
|
||||
url,
|
||||
{
|
||||
headers: Object.assign({
|
||||
Accept: accept,
|
||||
}, headers ?? {}),
|
||||
},
|
||||
);
|
||||
|
||||
return await body.text();
|
||||
}
|
||||
}
|
||||
import type { Response } from 'node-fetch';
|
||||
import type { URL } from 'node:url';
|
||||
|
||||
@Injectable()
|
||||
export class HttpRequestService {
|
||||
public defaultFetcher: UndiciFetcher;
|
||||
public fetch: UndiciFetcher['fetch'];
|
||||
public request: UndiciFetcher['request'];
|
||||
public getHtml: UndiciFetcher['getHtml'];
|
||||
public defaultJsonFetcher: UndiciFetcher;
|
||||
public getJson: UndiciFetcher['getJson'];
|
||||
|
||||
//#region for old http/https, only used in S3Service
|
||||
// http non-proxy agent
|
||||
/**
|
||||
* Get http non-proxy agent
|
||||
*/
|
||||
private http: http.Agent;
|
||||
|
||||
// https non-proxy agent
|
||||
/**
|
||||
* Get https non-proxy agent
|
||||
*/
|
||||
private https: https.Agent;
|
||||
|
||||
// http proxy or non-proxy agent
|
||||
/**
|
||||
* Get http proxy or non-proxy agent
|
||||
*/
|
||||
public httpAgent: http.Agent;
|
||||
|
||||
// https proxy or non-proxy agent
|
||||
/**
|
||||
* Get https proxy or non-proxy agent
|
||||
*/
|
||||
public httpsAgent: https.Agent;
|
||||
//#endregion
|
||||
|
||||
public readonly dnsCache: CacheableLookup;
|
||||
public readonly clientDefaults: undici.Agent.Options;
|
||||
private maxSockets: number;
|
||||
|
||||
private logger: Logger;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
private loggerService: LoggerService,
|
||||
) {
|
||||
this.logger = this.loggerService.getLogger('http-request');
|
||||
|
||||
this.dnsCache = new CacheableLookup({
|
||||
const cache = new CacheableLookup({
|
||||
maxTtl: 3600, // 1hours
|
||||
errorTtl: 30, // 30secs
|
||||
lookup: false, // nativeのdns.lookupにfallbackしない
|
||||
});
|
||||
|
||||
this.clientDefaults = {
|
||||
keepAliveTimeout: 30 * 1000,
|
||||
keepAliveMaxTimeout: 10 * 60 * 1000,
|
||||
keepAliveTimeoutThreshold: 1 * 1000,
|
||||
strictContentLength: true,
|
||||
headersTimeout: 10 * 1000,
|
||||
bodyTimeout: 10 * 1000,
|
||||
maxHeaderSize: 16364, // default
|
||||
maxResponseSize: 10 * 1024 * 1024,
|
||||
maxRedirections: 3,
|
||||
connect: {
|
||||
timeout: 10 * 1000, // コネクションが確立するまでのタイムアウト
|
||||
maxCachedSessions: 300, // TLSセッションのキャッシュ数 https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L80
|
||||
lookup: this.dnsCache.lookup as LookupFunction, // https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L98
|
||||
},
|
||||
};
|
||||
|
||||
this.maxSockets = Math.max(64, ((this.config.deliverJobConcurrency ?? 128) / (this.config.clusterLimit ?? 1)));
|
||||
|
||||
this.defaultFetcher = this.createFetcher({}, {}, this.logger);
|
||||
|
||||
this.fetch = this.defaultFetcher.fetch;
|
||||
this.request = this.defaultFetcher.request;
|
||||
this.getHtml = this.defaultFetcher.getHtml;
|
||||
|
||||
this.defaultJsonFetcher = this.createFetcher({
|
||||
maxResponseSize: 1024 * 256,
|
||||
}, {}, this.logger);
|
||||
|
||||
this.getJson = this.defaultJsonFetcher.getJson;
|
||||
|
||||
//#region for old http/https, only used in S3Service
|
||||
|
||||
this.http = new http.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
lookup: this.dnsCache.lookup,
|
||||
lookup: cache.lookup,
|
||||
} as http.AgentOptions);
|
||||
|
||||
this.https = new https.Agent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
lookup: this.dnsCache.lookup,
|
||||
lookup: cache.lookup,
|
||||
} as https.AgentOptions);
|
||||
|
||||
|
||||
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
|
||||
|
||||
this.httpAgent = config.proxy
|
||||
? new HttpProxyAgent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
maxSockets: this.maxSockets,
|
||||
maxSockets,
|
||||
maxFreeSockets: 256,
|
||||
scheduling: 'lifo',
|
||||
proxy: config.proxy,
|
||||
@@ -289,47 +72,21 @@ export class HttpRequestService {
|
||||
? new HttpsProxyAgent({
|
||||
keepAlive: true,
|
||||
keepAliveMsecs: 30 * 1000,
|
||||
maxSockets: this.maxSockets,
|
||||
maxSockets,
|
||||
maxFreeSockets: 256,
|
||||
scheduling: 'lifo',
|
||||
proxy: config.proxy,
|
||||
})
|
||||
: this.https;
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) {
|
||||
return {
|
||||
agentOptions: {
|
||||
...this.clientDefaults,
|
||||
...opts,
|
||||
},
|
||||
...(this.config.proxy ? {
|
||||
proxy: {
|
||||
uri: this.config.proxy,
|
||||
options: {
|
||||
connections: this.maxSockets,
|
||||
...proxyOpts,
|
||||
},
|
||||
},
|
||||
} : {}),
|
||||
userAgent: this.config.userAgent,
|
||||
};
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public createFetcher(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}, logger: Logger) {
|
||||
return new UndiciFetcher(this.getStandardUndiciFetcherOption(opts, proxyOpts), logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get http agent by URL
|
||||
* Get agent by URL
|
||||
* @param url URL
|
||||
* @param bypassProxy Allways bypass proxy
|
||||
*/
|
||||
@bindThis
|
||||
public getHttpAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
|
||||
public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
|
||||
if (bypassProxy || (this.config.proxyBypassHosts || []).includes(url.hostname)) {
|
||||
return url.protocol === 'http:' ? this.http : this.https;
|
||||
} else {
|
||||
@@ -337,37 +94,68 @@ export class HttpRequestService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check ip
|
||||
*/
|
||||
@bindThis
|
||||
public getConnectorWithIpCheck(connector: undici.buildConnector.connector, checkIp: IpChecker): undici.buildConnector.connectorAsync {
|
||||
return (options, cb) => {
|
||||
connector(options, (err, socket) => {
|
||||
this.logger.debug('Socket connector (with ip checker) called', socket);
|
||||
if (err) {
|
||||
this.logger.error('Socket error', err);
|
||||
cb(new Error(`Error while socket connecting\n${err}`), null);
|
||||
return;
|
||||
}
|
||||
public async getJson<T = unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
|
||||
const res = await this.send(url, {
|
||||
method: 'GET',
|
||||
headers: Object.assign({
|
||||
Accept: accept,
|
||||
}, headers ?? {}),
|
||||
timeout: 5000,
|
||||
size: 1024 * 256,
|
||||
});
|
||||
|
||||
if (socket.remoteAddress == undefined) {
|
||||
this.logger.error('Socket error: remoteAddress is undefined');
|
||||
cb(new Error('remoteAddress is undefined (maybe socket destroyed)'), null);
|
||||
return;
|
||||
}
|
||||
return await res.json() as T;
|
||||
}
|
||||
|
||||
// allow
|
||||
if (checkIp(socket.remoteAddress)) {
|
||||
this.logger.debug(`Socket connected (ip ok): ${socket.localPort} => ${socket.remoteAddress}`);
|
||||
cb(null, socket);
|
||||
return;
|
||||
}
|
||||
@bindThis
|
||||
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
|
||||
const res = await this.send(url, {
|
||||
method: 'GET',
|
||||
headers: Object.assign({
|
||||
Accept: accept,
|
||||
}, headers ?? {}),
|
||||
timeout: 5000,
|
||||
});
|
||||
|
||||
this.logger.error('IP is not allowed', socket);
|
||||
cb(new StatusError('IP is not allowed', 403, 'IP is not allowed'), null);
|
||||
socket.destroy();
|
||||
});
|
||||
};
|
||||
return await res.text();
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async send(url: string, args: {
|
||||
method?: string,
|
||||
body?: string,
|
||||
headers?: Record<string, string>,
|
||||
timeout?: number,
|
||||
size?: number,
|
||||
} = {}, extra: {
|
||||
throwErrorWhenResponseNotOk: boolean;
|
||||
} = {
|
||||
throwErrorWhenResponseNotOk: true,
|
||||
}): Promise<Response> {
|
||||
const timeout = args.timeout ?? 5000;
|
||||
|
||||
const controller = new AbortController();
|
||||
setTimeout(() => {
|
||||
controller.abort();
|
||||
}, timeout);
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: args.method ?? 'GET',
|
||||
headers: {
|
||||
'User-Agent': this.config.userAgent,
|
||||
...(args.headers ?? {})
|
||||
},
|
||||
body: args.body,
|
||||
size: args.size ?? 10 * 1024 * 1024,
|
||||
agent: (url) => this.getAgentByUrl(url),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (!res.ok && extra.throwErrorWhenResponseNotOk) {
|
||||
throw new StatusError(`${res.status} ${res.statusText}`, res.status, res.statusText);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,14 @@ export type IImage = {
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type IImageStream = {
|
||||
data: Readable;
|
||||
ext: string | null;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type IImageStreamable = IImage | IImageStream;
|
||||
|
||||
export const webpDefault: sharp.WebpOptions = {
|
||||
quality: 85,
|
||||
alphaQuality: 95,
|
||||
@@ -19,6 +27,7 @@ export const webpDefault: sharp.WebpOptions = {
|
||||
};
|
||||
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { Readable } from 'node:stream';
|
||||
|
||||
@Injectable()
|
||||
export class ImageProcessingService {
|
||||
@@ -64,7 +73,7 @@ export class ImageProcessingService {
|
||||
*/
|
||||
@bindThis
|
||||
public async convertToWebp(path: string, width: number, height: number, options: sharp.WebpOptions = webpDefault): Promise<IImage> {
|
||||
return this.convertSharpToWebp(await sharp(path), width, height, options);
|
||||
return this.convertSharpToWebp(sharp(path), width, height, options);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
@@ -85,6 +94,27 @@ export class ImageProcessingService {
|
||||
};
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public convertToWebpStream(path: string, width: number, height: number, options: sharp.WebpOptions = webpDefault): IImageStream {
|
||||
return this.convertSharpToWebpStream(sharp(path), width, height, options);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public convertSharpToWebpStream(sharp: sharp.Sharp, width: number, height: number, options: sharp.WebpOptions = webpDefault): IImageStream {
|
||||
const data = sharp
|
||||
.resize(width, height, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true,
|
||||
})
|
||||
.rotate()
|
||||
.webp(options);
|
||||
|
||||
return {
|
||||
data,
|
||||
ext: 'webp',
|
||||
type: 'image/webp',
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Convert to PNG
|
||||
* with resize, remove metadata, resolve orientation, stop animation
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { IsNull } from 'typeorm';
|
||||
import type { ILocalUser } from '@/models/entities/User.js';
|
||||
import type { LocalUser } from '@/models/entities/User.js';
|
||||
import type { UsersRepository } from '@/models/index.js';
|
||||
import { Cache } from '@/misc/cache.js';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
@@ -11,7 +11,7 @@ const ACTOR_USERNAME = 'instance.actor' as const;
|
||||
|
||||
@Injectable()
|
||||
export class InstanceActorService {
|
||||
private cache: Cache<ILocalUser>;
|
||||
private cache: Cache<LocalUser>;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
@@ -19,24 +19,24 @@ export class InstanceActorService {
|
||||
|
||||
private createSystemUserService: CreateSystemUserService,
|
||||
) {
|
||||
this.cache = new Cache<ILocalUser>(Infinity);
|
||||
this.cache = new Cache<LocalUser>(Infinity);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async getInstanceActor(): Promise<ILocalUser> {
|
||||
public async getInstanceActor(): Promise<LocalUser> {
|
||||
const cached = this.cache.get(null);
|
||||
if (cached) return cached;
|
||||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
host: IsNull(),
|
||||
username: ACTOR_USERNAME,
|
||||
}) as ILocalUser | undefined;
|
||||
}) as LocalUser | undefined;
|
||||
|
||||
if (user) {
|
||||
this.cache.set(null, user);
|
||||
return user;
|
||||
} else {
|
||||
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as ILocalUser;
|
||||
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as LocalUser;
|
||||
this.cache.set(null, created);
|
||||
return created;
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as SyslogPro from 'syslog-pro';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import Logger from '@/logger.js';
|
||||
@@ -8,29 +7,14 @@ import type { KEYWORD } from 'color-convert/conversions';
|
||||
|
||||
@Injectable()
|
||||
export class LoggerService {
|
||||
private syslogClient;
|
||||
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
) {
|
||||
if (this.config.syslog) {
|
||||
this.syslogClient = new SyslogPro.RFC5424({
|
||||
applicationName: 'Misskey',
|
||||
timestamp: true,
|
||||
includeStructuredData: true,
|
||||
color: true,
|
||||
extendedColor: true,
|
||||
server: {
|
||||
target: config.syslog.host,
|
||||
port: config.syslog.port,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getLogger(domain: string, color?: KEYWORD | undefined, store?: boolean) {
|
||||
return new Logger(domain, color, store, this.syslogClient);
|
||||
return new Logger(domain, color, store);
|
||||
}
|
||||
}
|
||||
|
@@ -1,307 +0,0 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { In, Not } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import type { DriveFile } from '@/models/entities/DriveFile.js';
|
||||
import type { MessagingMessage } from '@/models/entities/MessagingMessage.js';
|
||||
import type { Note } from '@/models/entities/Note.js';
|
||||
import type { User, CacheableUser, IRemoteUser } from '@/models/entities/User.js';
|
||||
import type { UserGroup } from '@/models/entities/UserGroup.js';
|
||||
import { QueueService } from '@/core/QueueService.js';
|
||||
import { toArray } from '@/misc/prelude/array.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import type { MessagingMessagesRepository, MutingsRepository, UserGroupJoiningsRepository, UsersRepository } from '@/models/index.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
|
||||
import { MessagingMessageEntityService } from '@/core/entities/MessagingMessageEntityService.js';
|
||||
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
|
||||
@Injectable()
|
||||
export class MessagingService {
|
||||
constructor(
|
||||
@Inject(DI.config)
|
||||
private config: Config,
|
||||
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
|
||||
@Inject(DI.messagingMessagesRepository)
|
||||
private messagingMessagesRepository: MessagingMessagesRepository,
|
||||
|
||||
@Inject(DI.userGroupJoiningsRepository)
|
||||
private userGroupJoiningsRepository: UserGroupJoiningsRepository,
|
||||
|
||||
@Inject(DI.mutingsRepository)
|
||||
private mutingsRepository: MutingsRepository,
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private messagingMessageEntityService: MessagingMessageEntityService,
|
||||
private idService: IdService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private apRendererService: ApRendererService,
|
||||
private queueService: QueueService,
|
||||
private pushNotificationService: PushNotificationService,
|
||||
) {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async createMessage(user: { id: User['id']; host: User['host']; }, recipientUser: CacheableUser | undefined, recipientGroup: UserGroup | undefined, text: string | null | undefined, file: DriveFile | null, uri?: string) {
|
||||
const message = {
|
||||
id: this.idService.genId(),
|
||||
createdAt: new Date(),
|
||||
fileId: file ? file.id : null,
|
||||
recipientId: recipientUser ? recipientUser.id : null,
|
||||
groupId: recipientGroup ? recipientGroup.id : null,
|
||||
text: text ? text.trim() : null,
|
||||
userId: user.id,
|
||||
isRead: false,
|
||||
reads: [] as any[],
|
||||
uri,
|
||||
} as MessagingMessage;
|
||||
|
||||
await this.messagingMessagesRepository.insert(message);
|
||||
|
||||
const messageObj = await this.messagingMessageEntityService.pack(message);
|
||||
|
||||
if (recipientUser) {
|
||||
if (this.userEntityService.isLocalUser(user)) {
|
||||
// 自分のストリーム
|
||||
this.globalEventService.publishMessagingStream(message.userId, recipientUser.id, 'message', messageObj);
|
||||
this.globalEventService.publishMessagingIndexStream(message.userId, 'message', messageObj);
|
||||
this.globalEventService.publishMainStream(message.userId, 'messagingMessage', messageObj);
|
||||
}
|
||||
|
||||
if (this.userEntityService.isLocalUser(recipientUser)) {
|
||||
// 相手のストリーム
|
||||
this.globalEventService.publishMessagingStream(recipientUser.id, message.userId, 'message', messageObj);
|
||||
this.globalEventService.publishMessagingIndexStream(recipientUser.id, 'message', messageObj);
|
||||
this.globalEventService.publishMainStream(recipientUser.id, 'messagingMessage', messageObj);
|
||||
}
|
||||
} else if (recipientGroup) {
|
||||
// グループのストリーム
|
||||
this.globalEventService.publishGroupMessagingStream(recipientGroup.id, 'message', messageObj);
|
||||
|
||||
// メンバーのストリーム
|
||||
const joinings = await this.userGroupJoiningsRepository.findBy({ userGroupId: recipientGroup.id });
|
||||
for (const joining of joinings) {
|
||||
this.globalEventService.publishMessagingIndexStream(joining.userId, 'message', messageObj);
|
||||
this.globalEventService.publishMainStream(joining.userId, 'messagingMessage', messageObj);
|
||||
}
|
||||
}
|
||||
|
||||
// 2秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する
|
||||
setTimeout(async () => {
|
||||
const freshMessage = await this.messagingMessagesRepository.findOneBy({ id: message.id });
|
||||
if (freshMessage == null) return; // メッセージが削除されている場合もある
|
||||
|
||||
if (recipientUser && this.userEntityService.isLocalUser(recipientUser)) {
|
||||
if (freshMessage.isRead) return; // 既読
|
||||
|
||||
//#region ただしミュートされているなら発行しない
|
||||
const mute = await this.mutingsRepository.findBy({
|
||||
muterId: recipientUser.id,
|
||||
});
|
||||
if (mute.map(m => m.muteeId).includes(user.id)) return;
|
||||
//#endregion
|
||||
|
||||
this.globalEventService.publishMainStream(recipientUser.id, 'unreadMessagingMessage', messageObj);
|
||||
this.pushNotificationService.pushNotification(recipientUser.id, 'unreadMessagingMessage', messageObj);
|
||||
} else if (recipientGroup) {
|
||||
const joinings = await this.userGroupJoiningsRepository.findBy({ userGroupId: recipientGroup.id, userId: Not(user.id) });
|
||||
for (const joining of joinings) {
|
||||
if (freshMessage.reads.includes(joining.userId)) return; // 既読
|
||||
this.globalEventService.publishMainStream(joining.userId, 'unreadMessagingMessage', messageObj);
|
||||
this.pushNotificationService.pushNotification(joining.userId, 'unreadMessagingMessage', messageObj);
|
||||
}
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
if (recipientUser && this.userEntityService.isLocalUser(user) && this.userEntityService.isRemoteUser(recipientUser)) {
|
||||
const note = {
|
||||
id: message.id,
|
||||
createdAt: message.createdAt,
|
||||
fileIds: message.fileId ? [message.fileId] : [],
|
||||
text: message.text,
|
||||
userId: message.userId,
|
||||
visibility: 'specified',
|
||||
mentions: [recipientUser].map(u => u.id),
|
||||
mentionedRemoteUsers: JSON.stringify([recipientUser].map(u => ({
|
||||
uri: u.uri,
|
||||
username: u.username,
|
||||
host: u.host,
|
||||
}))),
|
||||
} as Note;
|
||||
|
||||
const activity = this.apRendererService.renderActivity(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false, true), note));
|
||||
|
||||
this.queueService.deliver(user, activity, recipientUser.inbox);
|
||||
}
|
||||
return messageObj;
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async deleteMessage(message: MessagingMessage) {
|
||||
await this.messagingMessagesRepository.delete(message.id);
|
||||
this.postDeleteMessage(message);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async postDeleteMessage(message: MessagingMessage) {
|
||||
if (message.recipientId) {
|
||||
const user = await this.usersRepository.findOneByOrFail({ id: message.userId });
|
||||
const recipient = await this.usersRepository.findOneByOrFail({ id: message.recipientId });
|
||||
|
||||
if (this.userEntityService.isLocalUser(user)) this.globalEventService.publishMessagingStream(message.userId, message.recipientId, 'deleted', message.id);
|
||||
if (this.userEntityService.isLocalUser(recipient)) this.globalEventService.publishMessagingStream(message.recipientId, message.userId, 'deleted', message.id);
|
||||
|
||||
if (this.userEntityService.isLocalUser(user) && this.userEntityService.isRemoteUser(recipient)) {
|
||||
const activity = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), user));
|
||||
this.queueService.deliver(user, activity, recipient.inbox);
|
||||
}
|
||||
} else if (message.groupId) {
|
||||
this.globalEventService.publishGroupMessagingStream(message.groupId, 'deleted', message.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark messages as read
|
||||
*/
|
||||
@bindThis
|
||||
public async readUserMessagingMessage(
|
||||
userId: User['id'],
|
||||
otherpartyId: User['id'],
|
||||
messageIds: MessagingMessage['id'][],
|
||||
) {
|
||||
if (messageIds.length === 0) return;
|
||||
|
||||
const messages = await this.messagingMessagesRepository.findBy({
|
||||
id: In(messageIds),
|
||||
});
|
||||
|
||||
for (const message of messages) {
|
||||
if (message.recipientId !== userId) {
|
||||
throw new IdentifiableError('e140a4bf-49ce-4fb6-b67c-b78dadf6b52f', 'Access denied (user).');
|
||||
}
|
||||
}
|
||||
|
||||
// Update documents
|
||||
await this.messagingMessagesRepository.update({
|
||||
id: In(messageIds),
|
||||
userId: otherpartyId,
|
||||
recipientId: userId,
|
||||
isRead: false,
|
||||
}, {
|
||||
isRead: true,
|
||||
});
|
||||
|
||||
// Publish event
|
||||
this.globalEventService.publishMessagingStream(otherpartyId, userId, 'read', messageIds);
|
||||
this.globalEventService.publishMessagingIndexStream(userId, 'read', messageIds);
|
||||
|
||||
if (!await this.userEntityService.getHasUnreadMessagingMessage(userId)) {
|
||||
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
||||
this.globalEventService.publishMainStream(userId, 'readAllMessagingMessages');
|
||||
this.pushNotificationService.pushNotification(userId, 'readAllMessagingMessages', undefined);
|
||||
} else {
|
||||
// そのユーザーとのメッセージで未読がなければイベント発行
|
||||
const count = await this.messagingMessagesRepository.count({
|
||||
where: {
|
||||
userId: otherpartyId,
|
||||
recipientId: userId,
|
||||
isRead: false,
|
||||
},
|
||||
take: 1,
|
||||
});
|
||||
|
||||
if (!count) {
|
||||
this.pushNotificationService.pushNotification(userId, 'readAllMessagingMessagesOfARoom', { userId: otherpartyId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark messages as read
|
||||
*/
|
||||
@bindThis
|
||||
public async readGroupMessagingMessage(
|
||||
userId: User['id'],
|
||||
groupId: UserGroup['id'],
|
||||
messageIds: MessagingMessage['id'][],
|
||||
) {
|
||||
if (messageIds.length === 0) return;
|
||||
|
||||
// check joined
|
||||
const joining = await this.userGroupJoiningsRepository.findOneBy({
|
||||
userId: userId,
|
||||
userGroupId: groupId,
|
||||
});
|
||||
|
||||
if (joining == null) {
|
||||
throw new IdentifiableError('930a270c-714a-46b2-b776-ad27276dc569', 'Access denied (group).');
|
||||
}
|
||||
|
||||
const messages = await this.messagingMessagesRepository.findBy({
|
||||
id: In(messageIds),
|
||||
});
|
||||
|
||||
const reads: MessagingMessage['id'][] = [];
|
||||
|
||||
for (const message of messages) {
|
||||
if (message.userId === userId) continue;
|
||||
if (message.reads.includes(userId)) continue;
|
||||
|
||||
// Update document
|
||||
await this.messagingMessagesRepository.createQueryBuilder().update()
|
||||
.set({
|
||||
reads: (() => `array_append("reads", '${joining.userId}')`) as any,
|
||||
})
|
||||
.where('id = :id', { id: message.id })
|
||||
.execute();
|
||||
|
||||
reads.push(message.id);
|
||||
}
|
||||
|
||||
// Publish event
|
||||
this.globalEventService.publishGroupMessagingStream(groupId, 'read', {
|
||||
ids: reads,
|
||||
userId: userId,
|
||||
});
|
||||
this.globalEventService.publishMessagingIndexStream(userId, 'read', reads);
|
||||
|
||||
if (!await this.userEntityService.getHasUnreadMessagingMessage(userId)) {
|
||||
// 全ての(いままで未読だった)自分宛てのメッセージを(これで)読みましたよというイベントを発行
|
||||
this.globalEventService.publishMainStream(userId, 'readAllMessagingMessages');
|
||||
this.pushNotificationService.pushNotification(userId, 'readAllMessagingMessages', undefined);
|
||||
} else {
|
||||
// そのグループにおいて未読がなければイベント発行
|
||||
const unreadExist = await this.messagingMessagesRepository.createQueryBuilder('message')
|
||||
.where('message.groupId = :groupId', { groupId: groupId })
|
||||
.andWhere('message.userId != :userId', { userId: userId })
|
||||
.andWhere('NOT (:userId = ANY(message.reads))', { userId: userId })
|
||||
.andWhere('message.createdAt > :joinedAt', { joinedAt: joining.createdAt }) // 自分が加入する前の会話については、未読扱いしない
|
||||
.getOne().then(x => x != null);
|
||||
|
||||
if (!unreadExist) {
|
||||
this.pushNotificationService.pushNotification(userId, 'readAllMessagingMessagesOfARoom', { groupId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async deliverReadActivity(user: { id: User['id']; host: null; }, recipient: IRemoteUser, messages: MessagingMessage | MessagingMessage[]) {
|
||||
messages = toArray(messages).filter(x => x.uri);
|
||||
const contents = messages.map(x => this.apRendererService.renderRead(user, x));
|
||||
|
||||
if (contents.length > 1) {
|
||||
const collection = this.apRendererService.renderOrderedCollection(null, contents.length, undefined, undefined, contents);
|
||||
this.queueService.deliver(user, this.apRendererService.renderActivity(collection), recipient.inbox);
|
||||
} else {
|
||||
for (const content of contents) {
|
||||
this.queueService.deliver(user, this.apRendererService.renderActivity(content), recipient.inbox);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,9 +1,8 @@
|
||||
import { URL } from 'node:url';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as parse5 from 'parse5';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { Window } from 'happy-dom';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { UsersRepository } from '@/models/index.js';
|
||||
import type { Config } from '@/config.js';
|
||||
import { intersperse } from '@/misc/prelude/array.js';
|
||||
import type { IMentionedRemoteUsers } from '@/models/entities/Note.js';
|
||||
@@ -236,7 +235,7 @@ export class MfmService {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { window } = new JSDOM('');
|
||||
const { window } = new Window();
|
||||
|
||||
const doc = window.document;
|
||||
|
||||
@@ -301,7 +300,7 @@ export class MfmService {
|
||||
|
||||
hashtag: (node) => {
|
||||
const a = doc.createElement('a');
|
||||
a.href = `${this.config.url}/tags/${node.props.hashtag}`;
|
||||
a.setAttribute('href', `${this.config.url}/tags/${node.props.hashtag}`);
|
||||
a.textContent = `#${node.props.hashtag}`;
|
||||
a.setAttribute('rel', 'tag');
|
||||
return a;
|
||||
@@ -327,7 +326,7 @@ export class MfmService {
|
||||
|
||||
link: (node) => {
|
||||
const a = doc.createElement('a');
|
||||
a.href = node.props.url;
|
||||
a.setAttribute('href', node.props.url);
|
||||
appendChildren(node.children, a);
|
||||
return a;
|
||||
},
|
||||
@@ -336,7 +335,7 @@ export class MfmService {
|
||||
const a = doc.createElement('a');
|
||||
const { username, host, acct } = node.props;
|
||||
const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
|
||||
a.href = remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${this.config.url}/${acct}`;
|
||||
a.setAttribute('href', remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${this.config.url}/${acct}`);
|
||||
a.className = 'u-url mention';
|
||||
a.textContent = acct;
|
||||
return a;
|
||||
@@ -361,14 +360,14 @@ export class MfmService {
|
||||
|
||||
url: (node) => {
|
||||
const a = doc.createElement('a');
|
||||
a.href = node.props.url;
|
||||
a.setAttribute('href', node.props.url);
|
||||
a.textContent = node.props.url;
|
||||
return a;
|
||||
},
|
||||
|
||||
search: (node) => {
|
||||
const a = doc.createElement('a');
|
||||
a.href = `https://www.google.com/search?q=${node.props.query}`;
|
||||
a.setAttribute('href', `https://www.google.com/search?q=${node.props.query}`);
|
||||
a.textContent = node.props.content;
|
||||
return a;
|
||||
},
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import * as mfm from 'mfm-js';
|
||||
import { Not, In, DataSource } from 'typeorm';
|
||||
import { In, DataSource } from 'typeorm';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { extractMentions } from '@/misc/extract-mentions.js';
|
||||
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
|
||||
@@ -11,7 +11,7 @@ import type { DriveFile } from '@/models/entities/DriveFile.js';
|
||||
import type { App } from '@/models/entities/App.js';
|
||||
import { concat } from '@/misc/prelude/array.js';
|
||||
import { IdService } from '@/core/IdService.js';
|
||||
import type { User, ILocalUser, IRemoteUser } from '@/models/entities/User.js';
|
||||
import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js';
|
||||
import type { IPoll } from '@/models/entities/Poll.js';
|
||||
import { Poll } from '@/models/entities/Poll.js';
|
||||
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
|
||||
@@ -52,7 +52,7 @@ class NotificationManager {
|
||||
private notifier: { id: User['id']; };
|
||||
private note: Note;
|
||||
private queue: {
|
||||
target: ILocalUser['id'];
|
||||
target: LocalUser['id'];
|
||||
reason: NotificationType;
|
||||
}[];
|
||||
|
||||
@@ -68,7 +68,7 @@ class NotificationManager {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public push(notifiee: ILocalUser['id'], reason: NotificationType) {
|
||||
public push(notifiee: LocalUser['id'], reason: NotificationType) {
|
||||
// 自分自身へは通知しない
|
||||
if (this.notifier.id === notifiee) return;
|
||||
|
||||
@@ -175,7 +175,7 @@ export class NoteCreateService {
|
||||
private userEntityService: UserEntityService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private idService: IdService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private queueService: QueueService,
|
||||
private noteReadService: NoteReadService,
|
||||
private createNotificationService: CreateNotificationService,
|
||||
@@ -535,7 +535,7 @@ export class NoteCreateService {
|
||||
// Pack the note
|
||||
const noteObj = await this.noteEntityService.pack(note);
|
||||
|
||||
this.globalEventServie.publishNotesStream(noteObj);
|
||||
this.globalEventService.publishNotesStream(noteObj);
|
||||
|
||||
this.webhookService.getActiveWebhooks().then(webhooks => {
|
||||
webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note'));
|
||||
@@ -561,7 +561,7 @@ export class NoteCreateService {
|
||||
|
||||
if (!threadMuted) {
|
||||
nm.push(data.reply.userId, 'reply');
|
||||
this.globalEventServie.publishMainStream(data.reply.userId, 'reply', noteObj);
|
||||
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
|
||||
|
||||
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply'));
|
||||
for (const webhook of webhooks) {
|
||||
@@ -584,7 +584,7 @@ export class NoteCreateService {
|
||||
|
||||
// Publish event
|
||||
if ((user.id !== data.renote.userId) && data.renote.userHost === null) {
|
||||
this.globalEventServie.publishMainStream(data.renote.userId, 'renote', noteObj);
|
||||
this.globalEventService.publishMainStream(data.renote.userId, 'renote', noteObj);
|
||||
|
||||
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote'));
|
||||
for (const webhook of webhooks) {
|
||||
@@ -605,7 +605,7 @@ export class NoteCreateService {
|
||||
|
||||
// メンションされたリモートユーザーに配送
|
||||
for (const u of mentionedUsers.filter(u => this.userEntityService.isRemoteUser(u))) {
|
||||
dm.addDirectRecipe(u as IRemoteUser);
|
||||
dm.addDirectRecipe(u as RemoteUser);
|
||||
}
|
||||
|
||||
// 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
|
||||
@@ -684,7 +684,7 @@ export class NoteCreateService {
|
||||
detail: true,
|
||||
});
|
||||
|
||||
this.globalEventServie.publishMainStream(u.id, 'mention', detailPackedNote);
|
||||
this.globalEventService.publishMainStream(u.id, 'mention', detailPackedNote);
|
||||
|
||||
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention'));
|
||||
for (const webhook of webhooks) {
|
||||
@@ -711,7 +711,7 @@ export class NoteCreateService {
|
||||
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
|
||||
: this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
|
||||
|
||||
return this.apRendererService.renderActivity(content);
|
||||
return this.apRendererService.addContext(content);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { Brackets, In } from 'typeorm';
|
||||
import { Injectable, Inject } from '@nestjs/common';
|
||||
import type { User, ILocalUser, IRemoteUser } from '@/models/entities/User.js';
|
||||
import type { User, LocalUser, RemoteUser } from '@/models/entities/User.js';
|
||||
import type { Note, IMentionedRemoteUsers } from '@/models/entities/Note.js';
|
||||
import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/index.js';
|
||||
import { RelayService } from '@/core/RelayService.js';
|
||||
@@ -34,7 +34,7 @@ export class NoteDeleteService {
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private noteEntityService: NoteEntityService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private relayService: RelayService,
|
||||
private federatedInstanceService: FederatedInstanceService,
|
||||
private apRendererService: ApRendererService,
|
||||
@@ -63,7 +63,7 @@ export class NoteDeleteService {
|
||||
}
|
||||
|
||||
if (!quiet) {
|
||||
this.globalEventServie.publishNoteStream(note.id, 'deleted', {
|
||||
this.globalEventService.publishNoteStream(note.id, 'deleted', {
|
||||
deletedAt: deletedAt,
|
||||
});
|
||||
|
||||
@@ -78,7 +78,7 @@ export class NoteDeleteService {
|
||||
});
|
||||
}
|
||||
|
||||
const content = this.apRendererService.renderActivity(renote
|
||||
const content = this.apRendererService.addContext(renote
|
||||
? this.apRendererService.renderUndo(this.apRendererService.renderAnnounce(renote.uri ?? `${this.config.url}/notes/${renote.id}`, note), user)
|
||||
: this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${note.id}`), user));
|
||||
|
||||
@@ -90,7 +90,7 @@ export class NoteDeleteService {
|
||||
for (const cascadingNote of cascadingNotes) {
|
||||
if (!cascadingNote.user) continue;
|
||||
if (!this.userEntityService.isLocalUser(cascadingNote.user)) continue;
|
||||
const content = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
|
||||
const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
|
||||
this.deliverToConcerned(cascadingNote.user, cascadingNote, content);
|
||||
}
|
||||
//#endregion
|
||||
@@ -159,11 +159,11 @@ export class NoteDeleteService {
|
||||
|
||||
return await this.usersRepository.find({
|
||||
where,
|
||||
}) as IRemoteUser[];
|
||||
}) as RemoteUser[];
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async deliverToConcerned(user: { id: ILocalUser['id']; host: null; }, note: Note, content: any) {
|
||||
private async deliverToConcerned(user: { id: LocalUser['id']; host: null; }, note: Note, content: any) {
|
||||
this.apDeliverManagerService.deliverToFollowers(user, content);
|
||||
this.relayService.deliverToRelays(user, content);
|
||||
const remoteUsers = await this.getMentionedRemoteUsers(note);
|
||||
|
@@ -115,7 +115,7 @@ export class NotePiningService {
|
||||
|
||||
const target = `${this.config.url}/users/${user.id}/collections/featured`;
|
||||
const item = `${this.config.url}/notes/${noteId}`;
|
||||
const content = this.apRendererService.renderActivity(isAddition ? this.apRendererService.renderAdd(user, target, item) : this.apRendererService.renderRemove(user, target, item));
|
||||
const content = this.apRendererService.addContext(isAddition ? this.apRendererService.renderAdd(user, target, item) : this.apRendererService.renderRemove(user, target, item));
|
||||
|
||||
this.apDeliverManagerService.deliverToFollowers(user, content);
|
||||
this.relayService.deliverToRelays(user, content);
|
||||
|
@@ -9,9 +9,9 @@ import { IdService } from '@/core/IdService.js';
|
||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||
import type { UsersRepository, NoteUnreadsRepository, MutingsRepository, NoteThreadMutingsRepository, FollowingsRepository, ChannelFollowingsRepository, AntennaNotesRepository } from '@/models/index.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { NotificationService } from './NotificationService.js';
|
||||
import { AntennaService } from './AntennaService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { PushNotificationService } from './PushNotificationService.js';
|
||||
|
||||
@Injectable()
|
||||
@@ -40,7 +40,7 @@ export class NoteReadService {
|
||||
|
||||
private userEntityService: UserEntityService,
|
||||
private idService: IdService,
|
||||
private globalEventServie: GlobalEventService,
|
||||
private globalEventService: GlobalEventService,
|
||||
private notificationService: NotificationService,
|
||||
private antennaService: AntennaService,
|
||||
private pushNotificationService: PushNotificationService,
|
||||
@@ -87,13 +87,13 @@ export class NoteReadService {
|
||||
if (exist == null) return;
|
||||
|
||||
if (params.isMentioned) {
|
||||
this.globalEventServie.publishMainStream(userId, 'unreadMention', note.id);
|
||||
this.globalEventService.publishMainStream(userId, 'unreadMention', note.id);
|
||||
}
|
||||
if (params.isSpecified) {
|
||||
this.globalEventServie.publishMainStream(userId, 'unreadSpecifiedNote', note.id);
|
||||
this.globalEventService.publishMainStream(userId, 'unreadSpecifiedNote', note.id);
|
||||
}
|
||||
if (note.channelId) {
|
||||
this.globalEventServie.publishMainStream(userId, 'unreadChannel', note.id);
|
||||
this.globalEventService.publishMainStream(userId, 'unreadChannel', note.id);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
@@ -107,12 +107,6 @@ export class NoteReadService {
|
||||
followingChannels: Set<Channel['id']>;
|
||||
},
|
||||
): Promise<void> {
|
||||
const following = info?.following ? info.following : new Set<string>((await this.followingsRepository.find({
|
||||
where: {
|
||||
followerId: userId,
|
||||
},
|
||||
select: ['followeeId'],
|
||||
})).map(x => x.followeeId));
|
||||
const followingChannels = info?.followingChannels ? info.followingChannels : new Set<string>((await this.channelFollowingsRepository.find({
|
||||
where: {
|
||||
followerId: userId,
|
||||
@@ -139,7 +133,7 @@ export class NoteReadService {
|
||||
|
||||
if (note.user != null) { // たぶんnullになることは無いはずだけど一応
|
||||
for (const antenna of myAntennas) {
|
||||
if (await this.antennaService.checkHitAntenna(antenna, note, note.user, undefined, Array.from(following))) {
|
||||
if (await this.antennaService.checkHitAntenna(antenna, note, note.user)) {
|
||||
readAntennaNotes.push(note);
|
||||
}
|
||||
}
|
||||
@@ -161,7 +155,7 @@ export class NoteReadService {
|
||||
}).then(mentionsCount => {
|
||||
if (mentionsCount === 0) {
|
||||
// 全て既読になったイベントを発行
|
||||
this.globalEventServie.publishMainStream(userId, 'readAllUnreadMentions');
|
||||
this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -171,7 +165,7 @@ export class NoteReadService {
|
||||
}).then(specifiedCount => {
|
||||
if (specifiedCount === 0) {
|
||||
// 全て既読になったイベントを発行
|
||||
this.globalEventServie.publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
|
||||
this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -181,7 +175,7 @@ export class NoteReadService {
|
||||
}).then(channelNoteCount => {
|
||||
if (channelNoteCount === 0) {
|
||||
// 全て既読になったイベントを発行
|
||||
this.globalEventServie.publishMainStream(userId, 'readAllChannels');
|
||||
this.globalEventService.publishMainStream(userId, 'readAllChannels');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -206,14 +200,14 @@ export class NoteReadService {
|
||||
});
|
||||
|
||||
if (count === 0) {
|
||||
this.globalEventServie.publishMainStream(userId, 'readAntenna', antenna);
|
||||
this.globalEventService.publishMainStream(userId, 'readAntenna', antenna);
|
||||
this.pushNotificationService.pushNotification(userId, 'readAntenna', { antennaId: antenna.id });
|
||||
}
|
||||
}
|
||||
|
||||
this.userEntityService.getHasUnreadAntenna(userId).then(unread => {
|
||||
if (!unread) {
|
||||
this.globalEventServie.publishMainStream(userId, 'readAllAntennas');
|
||||
this.globalEventService.publishMainStream(userId, 'readAllAntennas');
|
||||
this.pushNotificationService.pushNotification(userId, 'readAllAntennas', undefined);
|
||||
}
|
||||
});
|
||||
|
@@ -2,13 +2,12 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { In } from 'typeorm';
|
||||
import { DI } from '@/di-symbols.js';
|
||||
import type { NotificationsRepository } from '@/models/index.js';
|
||||
import type { UsersRepository } from '@/models/index.js';
|
||||
import type { User } from '@/models/entities/User.js';
|
||||
import type { Notification } from '@/models/entities/Notification.js';
|
||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { GlobalEventService } from './GlobalEventService.js';
|
||||
import { PushNotificationService } from './PushNotificationService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
|
||||
@Injectable()
|
||||
export class NotificationService {
|
||||
@@ -66,7 +65,6 @@ export class NotificationService {
|
||||
|
||||
@bindThis
|
||||
private postReadNotifications(userId: User['id'], notificationIds: Notification['id'][]) {
|
||||
this.globalEventService.publishMainStream(userId, 'readNotifications', notificationIds);
|
||||
return this.pushNotificationService.pushNotification(userId, 'readNotifications', { notificationIds });
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user