Compare commits
167 commits
Author | SHA1 | Date | |
---|---|---|---|
|
8afbe5e3bc | ||
|
58be48d164 | ||
|
1056b89fd1 | ||
|
3e64d78d05 | ||
|
3947aafeba | ||
|
345934c2f3 | ||
|
42a13b0f1b | ||
|
e13c4b6b85 | ||
|
6a1409e09b | ||
|
174f98b1cb | ||
|
ab146b67ec | ||
|
3b4208ea41 | ||
|
856324fa26 | ||
|
5a9322d2c7 | ||
|
b52bfbcba0 | ||
|
2b05a738c9 | ||
|
fa5d31b793 | ||
|
29cfdcbbcd | ||
|
5174b95918 | ||
|
56528206b8 | ||
|
590380c084 | ||
|
dfcbb3c1ec | ||
|
9b01c31283 | ||
|
6be003b2f8 | ||
|
cc302fb0e2 | ||
|
c4e768f977 | ||
|
d8a7217335 | ||
|
35d10ab9ff | ||
|
43d0a24547 | ||
|
51ebe643d5 | ||
|
7c14e1a5bd | ||
|
0da0e2c814 | ||
|
af97dd7484 | ||
|
28bf597443 | ||
|
a249baea8c | ||
|
a4e82f7886 | ||
|
32dc55b07c | ||
|
91eab22d77 | ||
|
e2125c57d6 | ||
|
e0a6418e91 | ||
|
14ed359c33 | ||
|
2d387e2eb4 | ||
|
57f70371a9 | ||
|
8feffbcdf6 | ||
|
42ffce97d6 | ||
|
2f479c670f | ||
|
ee6e7026ab | ||
|
17c05a5ca2 | ||
|
42896c2abf | ||
|
ecb6be2152 | ||
|
6c92983af6 | ||
|
9e4985e225 | ||
|
60ff715aff | ||
|
04bcf7d804 | ||
|
5fa305c58c | ||
|
a2ceb89d5e | ||
|
6b3b55455d | ||
|
8c6ccc321d | ||
|
596ae7e377 | ||
|
0d22a22a10 | ||
|
2a76be56e7 | ||
|
661a98d38d | ||
|
94d640f9f1 | ||
|
1f943ce8a5 | ||
|
c540764408 | ||
|
a4dfdc0853 | ||
|
ddea499a36 | ||
|
db33fe8ee2 | ||
|
f1bf22436d | ||
|
459c73ec02 | ||
|
2acf1e5c59 | ||
|
33c4459744 | ||
|
b00487e51f | ||
|
1e1cab643c | ||
|
8d3219a6d2 | ||
|
ec9753758f | ||
|
97ff4a7241 | ||
|
14cedc5ed1 | ||
|
5911777aa2 | ||
|
47fc082fb9 | ||
|
7e1b1e79f4 | ||
|
b92b2f74a4 | ||
|
7361f4e77e | ||
|
9f7f9e2798 | ||
|
42ab3eada4 | ||
|
6fdef479d0 | ||
|
fe08691f05 | ||
|
6a9764951f | ||
|
0f33b1cd79 | ||
|
999c38594e | ||
|
626c880038 | ||
|
6d7761c7e5 | ||
|
996ce3dde3 | ||
|
2c007f06e3 | ||
|
00704bd88c | ||
|
6a9d169e24 | ||
|
581c53a15e | ||
|
9e04e4fd80 | ||
|
88d5149db5 | ||
|
b4b13d777f | ||
|
7f4dd9ff03 | ||
|
a9a95e9120 | ||
|
56fd2e773b | ||
|
42dc1a027a | ||
|
236bc2c762 | ||
|
e9f47509ae | ||
|
f288d0c219 | ||
|
d973396c96 | ||
|
62287fffae | ||
|
e9f16af82d | ||
|
dfba8be134 | ||
|
313ddcebcb | ||
|
236b19e854 | ||
|
ea941d7cfa | ||
|
2e5001e5de | ||
|
014f8b0dd2 | ||
|
dd403b295f | ||
|
9cd62fe08d | ||
|
f668455dff | ||
|
5a4315384e | ||
|
401dfa8fa6 | ||
|
bb243168b3 | ||
|
da491f3278 | ||
|
d00e28d5e9 | ||
|
7ff17ab722 | ||
|
b009428814 | ||
|
7bec96a1bf | ||
|
0b5793c1e0 | ||
|
72ef2e7454 | ||
|
c39332c1bf | ||
|
8c6cf86de3 | ||
|
909271c764 | ||
|
413acbc7dd | ||
|
6e1ba218df | ||
|
830e8fdb45 | ||
|
9bf310d509 | ||
|
e3e8b19df3 | ||
|
e86c7abb39 | ||
|
8a0da8861d | ||
|
6c7e691aea | ||
|
b33d15a739 | ||
|
40e86998e6 | ||
|
177f344033 | ||
|
9079ac4afa | ||
|
dfc4e0a026 | ||
|
3d732d1d28 | ||
|
e8ee31afed | ||
|
d9d6b1e80b | ||
|
1dd7a89544 | ||
|
d3280c4ab3 | ||
|
abc75c360b | ||
|
a8e119b0f1 | ||
|
17e574b173 | ||
|
71d2e0b0ce | ||
|
b68e968bf9 | ||
|
eb49295422 | ||
|
337a30fe01 | ||
|
105ecd3836 | ||
|
a3e490edcd | ||
|
f8f5e1c89b | ||
|
e132814478 | ||
|
6af1df8bef | ||
|
b86f12cede | ||
|
c669701762 | ||
|
0900a9d87b | ||
|
0a01a2bdf0 | ||
|
7860c885c4 |
133 changed files with 4413 additions and 1500 deletions
49
.gitea/issue_template/bug.yml
Normal file
49
.gitea/issue_template/bug.yml
Normal file
|
@ -0,0 +1,49 @@
|
|||
name: "Bug report"
|
||||
about: "Something isn't working as expected"
|
||||
title: "[bug] "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thanks for taking the time to file this bug report! Please try to be as specific and detailed as you can, so we can track down the issue and fix it as soon as possible."
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: "Version"
|
||||
description: "Which version of pleroma-fe are you running? If running develop, specify the commit hash."
|
||||
placeholder: "e.g. 2022.11, 40e86998e6"
|
||||
- type: textarea
|
||||
id: attempt
|
||||
attributes:
|
||||
label: "What were you trying to do?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expectation
|
||||
attributes:
|
||||
label: "What did you expect to happen?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reality
|
||||
attributes:
|
||||
label: "What actually happened?"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: severity
|
||||
attributes:
|
||||
label: "Severity"
|
||||
description: "Does this issue prevent you from using the software as normal?"
|
||||
options:
|
||||
- "I cannot use the software"
|
||||
- "I cannot use it as easily as I'd like"
|
||||
- "I can manage"
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: searched
|
||||
attributes:
|
||||
label: "Have you searched for this issue?"
|
||||
description: "Please double-check that your issue is not already being tracked on [the forums](https://meta.akkoma.dev) or [the issue tracker](https://akkoma.dev/AkkomaGang/pleroma-fe/issues)."
|
||||
options:
|
||||
- label: "I have double-checked and have not found this issue mentioned anywhere."
|
29
.gitea/issue_template/feat.yml
Normal file
29
.gitea/issue_template/feat.yml
Normal file
|
@ -0,0 +1,29 @@
|
|||
name: "Feature request"
|
||||
about: "I'd like something to be added to pleroma-fe"
|
||||
title: "[feat] "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Thanks for taking the time to request a new feature! Please be as concise and clear as you can in your proposal, so we could understand what you're going for."
|
||||
- type: textarea
|
||||
id: idea
|
||||
attributes:
|
||||
label: "The idea"
|
||||
description: "What do you think you should be able to do in pleroma-fe?"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: reason
|
||||
attributes:
|
||||
label: "The reasoning"
|
||||
description: "Why would this be a worthwhile feature? Does it solve any problems? Have people talked about wanting it?"
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: searched
|
||||
attributes:
|
||||
label: "Have you searched for this feature request?"
|
||||
description: "Please double-check that your issue is not already being tracked on [the forums](https://meta.akkoma.dev), [the issue tracker](https://akkoma.dev/AkkomaGang/pleroma-fe/issues), or the one for [the backend](https://akkoma.dev/AkkomaGang/akkoma/issues)."
|
||||
options:
|
||||
- label: "I have double-checked and have not found this feature request mentioned anywhere."
|
||||
- label: "This feature is related to the pleroma-fe Akkoma frontend specifically, and not the backend."
|
|
@ -1,3 +1,4 @@
|
|||
platform: linux/amd64
|
||||
pipeline:
|
||||
lint:
|
||||
when:
|
||||
|
|
10
README.md
10
README.md
|
@ -1,22 +1,22 @@
|
|||
# Pleroma-FE
|
||||
# Akkoma-FE
|
||||
|
||||
 
|
||||
|
||||
This is a fork of Pleroma-FE from the Pleroma project, with support for new Akkoma features such as:
|
||||
This is a fork of Akkoma-FE from the Pleroma project, with support for new Akkoma features such as:
|
||||
- MFM support via [marked-mfm](https://akkoma.dev/sfr/marked-mfm)
|
||||
- Custom emoji reactions
|
||||
|
||||
# For Translators
|
||||
|
||||
The [Weblate UI](https://translate.akkoma.dev/projects/akkoma/pleroma-fe/) is recommended for adding or modifying translations for Pleroma-FE.
|
||||
The [Weblate UI](https://translate.akkoma.dev/projects/akkoma/pleroma-fe/) is recommended for adding or modifying translations for Akkoma-FE.
|
||||
|
||||
Alternatively, edit/create `src/i18n/$LANGUAGE_CODE.json` (where `$LANGUAGE_CODE` is the [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) for your language), then add your language to [src/i18n/messages.js](https://akkoma.dev/AkkomaGang/pleroma-fe/src/branch/develop/src/i18n/messages.js) if it doesn't already exist there.
|
||||
|
||||
Pleroma-FE will set your language by your browser locale, but you can temporarily force it in the code by changing the locale in main.js.
|
||||
Akkoma-FE will set your language by your browser locale, but you can temporarily force it in the code by changing the locale in main.js.
|
||||
|
||||
# FOR ADMINS
|
||||
|
||||
To use Pleroma-FE in Akkoma, use the [frontend](https://docs.akkoma.dev/stable/administration/CLI_tasks/frontend/) CLI task to install Pleroma-FE, then modify your configuration as described in the [Frontend Management](https://docs.akkoma.dev/stable/configuration/frontend_management/) doc.
|
||||
To use Akkoma-FE in Akkoma, use the [frontend](https://docs.akkoma.dev/stable/administration/CLI_tasks/frontend/) CLI task to install Akkoma-FE, then modify your configuration as described in the [Frontend Management](https://docs.akkoma.dev/stable/configuration/frontend_management/) doc.
|
||||
|
||||
## Build Setup
|
||||
|
||||
|
|
|
@ -38,6 +38,11 @@ module.exports = {
|
|||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
proxyTable: {
|
||||
'/manifest.json': {
|
||||
target,
|
||||
changeOrigin: true,
|
||||
cookieDomainRewrite: 'localhost'
|
||||
},
|
||||
'/api': {
|
||||
target,
|
||||
changeOrigin: true,
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
# Pleroma-FE configuration and customization for instance administrators
|
||||
# Akkoma-FE configuration and customization for instance administrators
|
||||
|
||||
* *For user configuration, see [Pleroma-FE user guide](../user_guide)*
|
||||
* *For user configuration, see [Akkoma-FE user guide](../user_guide)*
|
||||
* *For local development server configuration, see [Hacking, tweaking, contributing](HACKING.md)*
|
||||
|
||||
## Where configuration is stored
|
||||
|
||||
PleromaFE gets its configuration from several sources, in order of preference (the one above overrides ones below it)
|
||||
Akkoma-FE gets its configuration from several sources, in order of preference (the one above overrides ones below it)
|
||||
|
||||
1. `/api/statusnet/config.json` - this is generated on Backend and contains multiple things including instance name, char limit etc. It also contains FE/Client-specific data, PleromaFE uses `pleromafe` field of it. For more info on changing config on BE, look [here](https://docs.akkoma.dev/stable/configuration/cheatsheet.md#frontend_configurations)
|
||||
2. `/static/config.json` - this is a static FE-provided file, containing only FE specific configuration. This file is completely optional and could be removed but is useful as a fallback if some configuration JSON property isn't present in BE-provided config. It's also a reference point to check what default configuration are and what JSON properties even exist. In local dev mode it could be used to override BE configuration, more about that in HACKING.md. File is located [here](https://akkoma.dev/AkkomaGang/pleroma-fe/src/branch/develop/static/config.json).
|
||||
3. Built-in defaults. Those are hard-coded defaults that are used when `/static/config.json` is not available and BE-provided configuration JSON is missing some JSON properties. ( [Code](https://akkoma.dev/AkkomaGang/pleroma-fe/src/branch/develop/src/modules/instance.js) )
|
||||
1. `/api/statusnet/config.json` - this is generated on Backend and contains multiple things including instance name, char limit etc. It also contains FE/Client-specific data, Akkoma-FE uses `pleromafe` field of it. For more info on changing config on BE, look [here](https://docs.akkoma.dev/stable/configuration/cheatsheet.md#frontend_configurations)
|
||||
2. `/static/config.json` - this is a static FE-provided file, containing only FE specific configuration. This file is completely optional and could be removed but is useful as a fallback if some configuration JSON property isn't present in BE-provided config. It's also a reference point to check what default configuration are and what JSON properties even exist. In local dev mode it could be used to override BE configuration, more about that in HACKING.md. File is located [here](https://akkoma.dev/AkkomaGang/akkoma-fe/src/branch/develop/static/config.json).
|
||||
3. Built-in defaults. Those are hard-coded defaults that are used when `/static/config.json` is not available and BE-provided configuration JSON is missing some JSON properties. ( [Code](https://akkoma.dev/AkkomaGang/akkoma-fe/src/branch/develop/src/modules/instance.js) )
|
||||
|
||||
## Instance-defaults
|
||||
|
||||
|
@ -59,7 +59,7 @@ Instance `logo`, could be any image, including svg. By default it assumes logo u
|
|||
`logoMargin` allows you to adjust vertical margins between logo boundary and navbar borders. The idea is that to have logo's image without any extra margins and instead adjust them to your need in layout.
|
||||
|
||||
### `minimalScopesMode`
|
||||
Limit scope selection to *Direct*, *User default* and *Scope of post replying to*. This also makes it impossible to reply to a DM with a non-DM post from PleromaFE.
|
||||
Limit scope selection to *Direct*, *User default* and *Scope of post replying to*. This also makes it impossible to reply to a DM with a non-DM post from Akkoma-FE.
|
||||
|
||||
### `nsfwCensorImage`
|
||||
Use custom image for NSFW'd images
|
||||
|
@ -77,7 +77,7 @@ Change alignment of sidebar and panels to the right. Defaults to `false`.
|
|||
Show panel showcasing instance features/settings to logged-out visitors
|
||||
|
||||
### `showInstanceSpecificPanel`
|
||||
This allows you to include arbitrary HTML content in a panel below navigation menu. PleromaFE looks for an html page `instance/panel.html`, by default it's not provided in FE, but BE bundles some [default one](https://git.pleroma.social/pleroma/pleroma/blob/develop/priv/static/instance/panel.html). De-facto instance-defaults, since user can hide instance-specific panel.
|
||||
This allows you to include arbitrary HTML content in a panel below navigation menu. Akkoma-FE looks for an html page `instance/panel.html`, by default it's not provided in FE, but BE bundles some [default one](https://git.pleroma.social/pleroma/pleroma/blob/develop/priv/static/instance/panel.html). De-facto instance-defaults, since user can hide instance-specific panel.
|
||||
|
||||
### `subjectLineBehavior`
|
||||
How to handle subject line (CW) when replying to a post.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Hacking, tweaking, contributing
|
||||
|
||||
## What PleromaFE even is, how it works
|
||||
## What Akkoma-FE even is, how it works
|
||||
|
||||
PleromaFE is an SPA (Single-Page Application) backed by [Vue](https://vuejs.org/) framework. It means that it's just a nearly-empty HTML page with bunch of JavaScript that actually generates and controls DOM (i.e. html elements) in Runtime. Currently, there's no way around it - you have to have Javascript enabled in the browser to make it work, there is a theoretical possibility to generate some HTML server-side but it's not implemented yet.
|
||||
Akkoma-FE is an SPA (Single-Page Application) backed by [Vue](https://vuejs.org/) framework. It means that it's just a nearly-empty HTML page with bunch of JavaScript that actually generates and controls DOM (i.e. html elements) in Runtime. Currently, there's no way around it - you have to have Javascript enabled in the browser to make it work, there is a theoretical possibility to generate some HTML server-side but it's not implemented yet.
|
||||
|
||||
You can serve static html page and everything from any HTTP(S) server but currently it will try to access /api/ path at same domain it's running on, meaning that as of right now you cannot put it on one domain and access the other without proxying requests.
|
||||
|
||||
|
@ -67,19 +67,19 @@ server {
|
|||
|
||||
### API, Data, Operations
|
||||
|
||||
In 99% cases PleromaFE uses [MastoAPI](https://docs.joinmastodon.org/api/) with [Pleroma Extensions](https://docs.akkoma.dev/stable/differences_in_mastoapi_responses.md) to fetch the data. The rest is either QvitterAPI leftovers or pleroma-exclusive APIs. QvitterAPI doesn't exactly have documentation and uses different JSON structure and sometimes different parameters and workflows, [this](https://twitter-api.readthedocs.io/en/latest/index.html) could be a good reference though. Some pleroma-exclusive API may still be using QvitterAPI JSON structure.
|
||||
In 99% cases Akkoma-FE uses [MastoAPI](https://docs.joinmastodon.org/api/) with [Pleroma Extensions](https://docs.akkoma.dev/stable/differences_in_mastoapi_responses.md) to fetch the data. The rest is either QvitterAPI leftovers or pleroma-exclusive APIs. QvitterAPI doesn't exactly have documentation and uses different JSON structure and sometimes different parameters and workflows, [this](https://twitter-api.readthedocs.io/en/latest/index.html) could be a good reference though. Some pleroma-exclusive API may still be using QvitterAPI JSON structure.
|
||||
|
||||
PleromaFE supports both formats by transforming them into internal format which is basically QvitterAPI one with some additions and renaming. All data is passed trough [Entity Normalizer](https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/src/services/entity_normalizer/entity_normalizer.service.js) which can serve as a reference of API and what's actually used, it's also a host for all the hacks and data transformation.
|
||||
Akkoma-FE supports both formats by transforming them into internal format which is basically QvitterAPI one with some additions and renaming. All data is passed trough [Entity Normalizer](https://akkoma.dev/AkkomaGang/akkoma-fe/src/branch/develop/src/services/entity_normalizer/entity_normalizer.service.js) which can serve as a reference of API and what's actually used, it's also a host for all the hacks and data transformation.
|
||||
|
||||
For most part, PleromaFE tries to store all the info it can get in global vuex store - every user and post are passed trough updating mechanism where data is either added or merged with existing data, reactively updating the information throughout UI, so if in newest request user's post counter increased, it will be instantly updated in open user profile cards. This is also used to find users, posts and sometimes to build timelines and/or request parameters.
|
||||
For most part, Akkoma-FE tries to store all the info it can get in global vuex store - every user and post are passed trough updating mechanism where data is either added or merged with existing data, reactively updating the information throughout UI, so if in newest request user's post counter increased, it will be instantly updated in open user profile cards. This is also used to find users, posts and sometimes to build timelines and/or request parameters.
|
||||
|
||||
PleromaFE also tries to persist this store, however only stable data is stored, such as user authentication and preferences, user highlights. Persistence is performed by saving and loading chunk of vuex store in browser's LocalStorage/IndexedDB.
|
||||
Akkoma-FE also tries to persist this store, however only stable data is stored, such as user authentication and preferences, user highlights. Persistence is performed by saving and loading chunk of vuex store in browser's LocalStorage/IndexedDB.
|
||||
|
||||
TODO: Refactor API code and document it here
|
||||
|
||||
### Themes
|
||||
|
||||
PleromaFE uses custom theme "framework" which is pretty much just a style tag rendered by vue which only contains CSS3 variables. Every color used in UI should be derived from theme. Theme is stored in a JSON object containing color, opacity, shadow and font information, with most of it being optional.
|
||||
Akkoma-FE uses custom theme "framework" which is pretty much just a style tag rendered by vue which only contains CSS3 variables. Every color used in UI should be derived from theme. Theme is stored in a JSON object containing color, opacity, shadow and font information, with most of it being optional.
|
||||
|
||||
The most basic theme can consist of 4 to 8 "basic colors", which is also what previous version of themes allowed, with all other colors being derived from those basic colors, i.e. "light background" will be "background" color lightened/darkened, "panel header" will be same as "foreground". The idea is that you can specify just basic color palette and everything else will be generated automatically, but if you really need to tweak some specific color - you can.
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 491 B After Width: | Height: | Size: 1.4 KiB |
BIN
docs/docs/images/akkoma_logo_vector_bg_32.png
Normal file
BIN
docs/docs/images/akkoma_logo_vector_bg_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
24
docs/docs/images/akkoma_logo_vector_nobg.svg
Normal file
24
docs/docs/images/akkoma_logo_vector_nobg.svg
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 362.83 362.83">
|
||||
<defs>
|
||||
<style>
|
||||
.cls-1, .cls-2 {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.cls-2 {
|
||||
stroke: #fff;
|
||||
stroke-miterlimit: 10;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<g id="Layer_6" data-name="Layer 6">
|
||||
<path class="cls-1" d="M115.2,131.89c6.26-6.54,20.19-20.63,42.39-26.14,15.79-3.92,28.51-1.28,33.51,0,83.72,21.41,116.03,201.78,77.79,226.32-10.28,6.6-26.86,2.7-36.77-3.3-32.63-19.78-29.3-72.87-44.44-73.73-5.11-.29-7.15,5.8-20.91,24.94-19.63,27.3-31.49,43.44-49.21,50.87-2.53,1.06-26.91,12.07-41.84,1.23-38.55-28-2.96-155.84,39.49-200.18Zm56.31,10.45c-27.39-.52-46.38,38.21-37.98,54.55,10.09,19.62,65.5,18.26,74.77-3.3,7.21-16.78-11.38-50.77-36.79-51.24Z"/>
|
||||
</g>
|
||||
<g id="Layer_4" data-name="Layer 4">
|
||||
<path class="cls-1" d="M68.93,86.51c-6.55,27.74,252.45,113.97,267.56,89.66,9.24-14.87-64.9-83.62-163.53-97.57-39.06-5.52-100.95-5.14-104.03,7.91Z"/>
|
||||
</g>
|
||||
<g id="Layer_5" data-name="Layer 5">
|
||||
<path class="cls-2" d="M138.96,93.76c.41-5.25,6.51-5.74,28.85-19.42,26.97-16.51,28.85-22.38,56.86-40.83,30.07-19.81,48.46-31.94,54.82-26.61,9.72,8.15-25.18,43.33-21.31,99.35,.87,12.61,3.12,17.79-.86,23.01-18.25,23.95-120.07-13.68-118.35-35.5Z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Before Width: | Height: | Size: 530 B |
|
@ -1,92 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="svg4485"
|
||||
width="512"
|
||||
height="512"
|
||||
viewBox="0 0 512 512"
|
||||
sodipodi:docname="pleroma_logo_vector_nobg.svg"
|
||||
inkscape:version="0.92.1 r15371">
|
||||
<metadata
|
||||
id="metadata4491">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4489" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
id="namedview4487"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.70710678"
|
||||
inkscape:cx="26.131594"
|
||||
inkscape:cy="235.37499"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="22"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4485" />
|
||||
<g
|
||||
id="g4612">
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4495"
|
||||
d="M 235,89 V 423 H 152 V 115 l 26,-26 z"
|
||||
style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#009bff;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.17587938" />
|
||||
<circle
|
||||
r="26"
|
||||
cx="178"
|
||||
cy="115"
|
||||
id="path4497"
|
||||
style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#009bff;stroke-width:0;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.17587938" />
|
||||
<circle
|
||||
r="26"
|
||||
cx="335"
|
||||
cy="230"
|
||||
id="path4497-0"
|
||||
style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#009bff;stroke-width:0;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.17587938" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4516"
|
||||
d="M 277,256 V 89 l 84,3e-6 L 361.00002,230 335,256 Z"
|
||||
style="fill:#fba457;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle
|
||||
r="26"
|
||||
cx="335"
|
||||
cy="397"
|
||||
id="path4497-0-6"
|
||||
style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#009bff;stroke-width:0;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.17587938" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4516-5"
|
||||
d="m 277,423 v -83 h 84 l 2e-5,57 L 335,423 Z"
|
||||
style="opacity:1;fill:#fba457;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.3 KiB |
|
@ -1,8 +1,8 @@
|
|||
# Introduction to Pleroma-FE
|
||||
## What is Pleroma-FE?
|
||||
# Introduction to Akkoma-FE
|
||||
## What is Akkoma-FE?
|
||||
|
||||
Pleroma-FE is the default user-facing frontend for Pleroma. It's user interface is modeled after Qvitter which is modeled after an older Twitter design. It provides a simple 2-column interface for microblogging. While being simple by default it also provides many powerful customization options.
|
||||
Akkoma-FE is the default user-facing frontend for Pleroma. It's user interface is modeled after Qvitter which is modeled after an older Twitter design. It provides a simple 2-column interface for microblogging. While being simple by default it also provides many powerful customization options.
|
||||
|
||||
## How can I use it?
|
||||
|
||||
If your instance uses Pleroma-FE, you can acces it by going to your instance (e.g. <https://pleroma.soykaf.com>). You can read more about it's basic functionality in the [Pleroma-FE User Guide](./user_guide/). We also have [a guide for administrators](./CONFIGURATION.md) and for [hackers/contributors](./HACKING.md).
|
||||
If your instance uses Akkoma-FE, you can acces it by going to your instance (e.g. <https://pleroma.soykaf.com>). You can read more about it's basic functionality in the [Akkoma-FE User Guide](./user_guide/). We also have [a guide for administrators](./CONFIGURATION.md) and for [hackers/contributors](./HACKING.md).
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# Adding stickers
|
||||
|
||||
Pleroma-fe supports stickers, which are essentially little images stored server-side
|
||||
Akkoma-FE supports stickers, which are essentially little images stored server-side
|
||||
which can be selected by a user to automatically attach them to a post.
|
||||
|
||||
There's no explicit setting for these, they just rely on the existence of certain files.
|
||||
|
||||
## Initialising the sticker config file
|
||||
|
||||
You're probably serving pleroma-fe from your instance's `instance/static/` directory -
|
||||
You're probably serving Akkoma-FE from your instance's `instance/static/` directory -
|
||||
this directy can also override files served at a given path.
|
||||
|
||||
The first thing we need to do is set up our `stickers.json` file. At `instance/static/static/stickers.json`,
|
||||
|
@ -50,4 +50,4 @@ The `tabIcon` will appear on the sticker picker itself as a representative of th
|
|||
|
||||
You can add as many stickers as you like. They should all be in the same directory as your `pack.json`.
|
||||
|
||||
Now you should find that there's a sticky note icon on the emoji picker on pleroma-fe that allows you to attach stickers.
|
||||
Now you should find that there's a sticky note icon on the emoji picker on Akkoma-FE that allows you to attach stickers.
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
>
|
||||
> --Catbag
|
||||
|
||||
Pleroma-FE is the default user-facing frontend for Pleroma. If your instance uses Pleroma-FE, you can access it by going to your instance (e.g. <https://pleroma.soykaf.com>). After logging in you will have two columns in front of you. Here we're going to keep it to the default behaviour, but some instances swap the left and right columns. If you're on such an instance what we refer to as the left column will be on your right and vice versa.
|
||||
Akkoma-FE is the default user-facing frontend for Pleroma. If your instance uses Akkoma-FE, you can access it by going to your instance (e.g. <https://pleroma.soykaf.com>). After logging in you will have two columns in front of you. Here we're going to keep it to the default behaviour, but some instances swap the left and right columns. If you're on such an instance what we refer to as the left column will be on your right and vice versa.
|
||||
|
||||
### Left column
|
||||
|
||||
- first block: This section is dedicated to [posting](posting_reading_basic_functions.md)
|
||||
- second block: Here you can switch between the different views for the right column.
|
||||
- Optional third block: This is the Instance panel that can be activated, but is deactivated by default. It's fully customisable by instance admins and by default has links to the Pleroma-FE and Mastodon-FE.
|
||||
- Optional third block: This is the Instance panel that can be activated, but is deactivated by default. It's fully customisable by instance admins and by default has links to the Akkoma-FE and Mastodon-FE.
|
||||
- fourth block: This is the Notifications block, here you will get notified whenever somebody mentions you, follows you, repeats or favorites one of your statuses
|
||||
|
||||
### Right column
|
||||
|
|
|
@ -15,11 +15,11 @@ Posts will contain the text you are posting, but some content will be modified:
|
|||
Let's clear up some basic stuff. When you post something it's called a **post** or it could be called a **status** or even a **toot** or a **prööt** depending on whom you ask. Post has body/content but it also has some other stuff in it - from attachments, visibility scope, subject line...
|
||||
|
||||
**Emoji** are small images embedded in text, there are two major types of emoji: [unicode emoji](https://en.wikipedia.org/wiki/Emoji) and custom emoji. While unicode emoji are universal and standardized, they can appear differently depending on where you are using them or may not appear at all on older systems. Custom emoji are a more *fun* kind - instance administrator can define many images as *custom emoji* for their users. This works very simple - custom emoji is defined by its *shortcode* and an image, so that any shortcode enclosed in colons get replaced with image if such shortcode exist.
|
||||
Let's say there's a `:pleroma:` emoji defined on an instance. That means
|
||||
> First time using :pleroma: pleroma!
|
||||
Let's say there's a `:akkoma:` emoji defined on an instance. That means
|
||||
> First time using :akkoma: akkoma!
|
||||
|
||||
will become
|
||||
> First time using  pleroma!
|
||||
> First time using  akkoma!
|
||||
|
||||
Note that you can only use emoji defined on your instance, you cannot "copy" someone else's emoji, and will have to ask your administrator to copy emoji from other instance to yours.
|
||||
Lastly, there's two convenience options for emoji: an emoji picker (smiley face to the right of "submit" button) and autocomplete suggestions - when you start typing :shortcode: it will automatically try to suggest you emoji and complete the shortcode for you if you select one. If emoji doesn't show up in suggestions nor in emoji picker it means there's no such emoji on your instance, if shortcode doesn't match any defined emoji it will appear as text.
|
||||
|
@ -42,7 +42,7 @@ A few things to consider about the security and usage of these scopes:
|
|||
- Changing scopes during a thread or adding people to a direct message will not retroactively make them see the whole conversation. If you add someone to a direct message conversation, they will not see the post that happened before they were mentioned.
|
||||
* **Reply-to** if you are replying to someone, your post will also contain a note that your post is referring to the post you're replying to. Person you're replying to will receive a notification *even* if you remove them from mentioned people. You won't receive notifications when replying to your own posts, but it's useful to reply to your own posts to provide people some context if it's a follow-up to a previous post. There's a small "Reply to ..." label under post author's name which you can hover on to see what post it's referring to.
|
||||
|
||||
Sometimes you may encounter posts that seem different than what they are supposed to. For example, you might see a direct message without any mentions in the text. This can happen because internally, the Fediverse has a different addressing mechanism similar to email, with `to` and `cc` fields. While these are not directly accessible in PleromaFE, other software in the Fediverse might generate those posts. Do not worry in these cases, these are normal and not a bug.
|
||||
Sometimes you may encounter posts that seem different than what they are supposed to. For example, you might see a direct message without any mentions in the text. This can happen because internally, the Fediverse has a different addressing mechanism similar to email, with `to` and `cc` fields. While these are not directly accessible in Akkoma-FE, other software in the Fediverse might generate those posts. Do not worry in these cases, these are normal and not a bug.
|
||||
|
||||
## Rich text
|
||||
|
||||
|
@ -67,7 +67,7 @@ If you set the input-method to Markdown, and post this, it will look something l
|
|||
|
||||
## Misskey markdown
|
||||
|
||||
The akkoma version of pleroma-fe includes support for writing and rendering
|
||||
Akkoma-FE includes support for writing and rendering
|
||||
misskey markdown (MFM). To write this you will need to select "MFM" from
|
||||
the content type dropdown (if supported), and then you can format text
|
||||
[in MFM](https://akkoma.dev/sfr/marked-mfm/src/branch/master/docs/syntax.md).
|
||||
|
|
|
@ -83,7 +83,7 @@ Here you can change your password, revoke access tokens, configure 2-factor auth
|
|||
|
||||
## Theme
|
||||
|
||||
Here you can change the look and feel of Pleroma-FE. You can choose from several instance-provided presets and you can load one from file and save current theme to file. Before you apply new theme you can see what it will look like approximately in preview section.
|
||||
Here you can change the look and feel of Akkoma-FE. You can choose from several instance-provided presets and you can load one from file and save current theme to file. Before you apply new theme you can see what it will look like approximately in preview section.
|
||||
|
||||
The themes engine was made to be easy to use while giving an option for powerful in-depth customization - you can just tweak colors on "Common" tab and leave everything else as is.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ When you see someone, you can click on their user picture to view their profile,
|
|||
|
||||
**Following** is self-explanatory, it adds them to your Home Timeline, lists you as a follower and gives you access to follower-only posts if they have any.
|
||||
|
||||
**Muting** collapses posts and notifications made by them, giving you an option to see the post if you're curious. Clients other than PleromaFE may completely remove their posts.
|
||||
**Muting** collapses posts and notifications made by them, giving you an option to see the post if you're curious. Clients other than Akkoma-FE may completely remove their posts.
|
||||
|
||||
**Blocking** a user removes them from your timeline and notifications and prevents them from following you (automatically unfollows them from you).
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
site_name: Pleroma-FE Documentation
|
||||
site_name: Akkoma-FE Documentation
|
||||
theme:
|
||||
favicon: 'images/pleroma_logo_vector_bg_32.png'
|
||||
favicon: 'images/akkoma_logo_vector_bg_32.png'
|
||||
name: 'material'
|
||||
custom_dir: 'theme'
|
||||
# Disable google fonts
|
||||
font: false
|
||||
logo: 'images/pleroma_logo_vector_nobg.svg'
|
||||
logo: 'images/akkoma_logo_vector_nobg.svg'
|
||||
features:
|
||||
- tabs
|
||||
palette:
|
||||
|
@ -14,8 +14,8 @@ theme:
|
|||
|
||||
extra_css:
|
||||
- css/extra.css
|
||||
repo_name: 'AkkomaGang/pleroma-fe'
|
||||
repo_url: 'https://akkoma.dev/AkkomaGang/pleroma-fe'
|
||||
repo_name: 'AkkomaGang/akkoma-fe'
|
||||
repo_url: 'https://akkoma.dev/AkkomaGang/akkoma-fe'
|
||||
|
||||
extra:
|
||||
repo_icon: gitea
|
||||
|
|
8
docs/theme/partials/source.html
vendored
8
docs/theme/partials/source.html
vendored
|
@ -38,11 +38,11 @@
|
|||
{% endif %}
|
||||
|
||||
{% if page and page.url.startswith('backend') %}
|
||||
{% set repo_url = "https://git.pleroma.social/pleroma/pleroma" %}
|
||||
{% set repo_name = "pleroma/pleroma" %}
|
||||
{% set repo_url = "https://akkoma.dev/AkkomaGang/akkoma" %}
|
||||
{% set repo_name = "AkkomaGang/akkoma" %}
|
||||
{% elif page and page.url.startswith('frontend') %}
|
||||
{% set repo_url = "https://git.pleroma.social/pleroma/pleroma-fe" %}
|
||||
{% set repo_name = "pleroma/pleroma-fe" %}
|
||||
{% set repo_url = "https://akkoma.dev/AkkomaGang/akkoma-fe" %}
|
||||
{% set repo_name = "AkkomaGang/akkoma-fe" %}
|
||||
{% else %}
|
||||
{% set repo_url = config.repo_url %}
|
||||
{% set repo_name = config.repo_name %}
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
|
||||
<title>Akkoma</title>
|
||||
<link rel="stylesheet" href="/static/font/css/fontello.css">
|
||||
<link rel="stylesheet" href="/static/font/css/animation.css">
|
||||
<link rel="stylesheet" href="/static/font/tiresias.css">
|
||||
<link rel="stylesheet" href="/static/font/css/lato.css">
|
||||
<link rel="stylesheet" href="/static/mfm.css">
|
||||
<link rel="stylesheet" href="/static/custom.css">
|
||||
<link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder">
|
||||
<!--server-generated-meta-->
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
</head>
|
||||
<body class="hidden">
|
||||
<noscript>To use Akkoma, please enable JavaScript.</noscript>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "pleroma_fe",
|
||||
"version": "3.2.0",
|
||||
"version": "3.10.0",
|
||||
"description": "A frontend for Akkoma instances",
|
||||
"author": "Roger Braun <roger@rogerbraun.net>",
|
||||
"private": true,
|
||||
|
@ -18,19 +18,21 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "7.17.8",
|
||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||
"@floatingghost/pinch-zoom-element": "^1.3.1",
|
||||
"@fortawesome/fontawesome-svg-core": "1.3.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.1.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.0",
|
||||
"@fortawesome/vue-fontawesome": "3.0.1",
|
||||
"@kazvmoe-infra/pinch-zoom-element": "1.2.0",
|
||||
"@vuelidate/core": "^2.0.0",
|
||||
"@vuelidate/validators": "^2.0.0",
|
||||
"blurhash": "^2.0.4",
|
||||
"body-scroll-lock": "2.7.1",
|
||||
"chromatism": "3.0.0",
|
||||
"click-outside-vue3": "4.0.1",
|
||||
"cropperjs": "1.5.12",
|
||||
"diff": "3.5.0",
|
||||
"escape-html": "1.0.3",
|
||||
"iso-639-1": "^2.1.15",
|
||||
"js-cookie": "^3.0.1",
|
||||
"localforage": "1.10.0",
|
||||
"parse-link-header": "^2.0.0",
|
||||
|
@ -82,7 +84,6 @@
|
|||
"html-webpack-plugin": "^5.5.0",
|
||||
"http-proxy-middleware": "0.21.0",
|
||||
"inject-loader": "2.0.1",
|
||||
"iso-639-1": "2.1.15",
|
||||
"isparta-loader": "2.0.0",
|
||||
"json-loader": "0.5.7",
|
||||
"karma": "6.3.17",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// stylelint-disable rscss/class-format
|
||||
@import './_variables.scss';
|
||||
|
||||
@import '@fortawesome/fontawesome-svg-core/styles.css';
|
||||
@import '@floatingghost/pinch-zoom-element/dist/pinch-zoom.css';
|
||||
:root {
|
||||
--navbar-height: 3.5rem;
|
||||
--post-line-height: 1.4;
|
||||
|
@ -468,7 +469,7 @@ textarea,
|
|||
color: $fallback--lightText;
|
||||
color: var(--inputText, $fallback--lightText);
|
||||
font-family: sans-serif;
|
||||
font-family: var(--inputFont, sans-serif);
|
||||
font-family: var(--interfaceFont, sans-serif);
|
||||
font-size: 1em;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
|
|
|
@ -4,6 +4,8 @@ import { createRouter, createWebHistory } from 'vue-router'
|
|||
import vClickOutside from 'click-outside-vue3'
|
||||
|
||||
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
|
||||
import { config } from '@fortawesome/fontawesome-svg-core';
|
||||
config.autoAddCss = false
|
||||
|
||||
import App from '../App.vue'
|
||||
import routes from './routes'
|
||||
|
@ -320,6 +322,9 @@ const getNodeInfo = async ({ store }) => {
|
|||
: federation.enabled
|
||||
})
|
||||
|
||||
store.dispatch('setInstanceOption', { name: 'publicTimelineVisibility', value: metadata.publicTimelineVisibility })
|
||||
store.dispatch('setInstanceOption', { name: 'federatedTimelineAvailable', value: metadata.federatedTimelineAvailable })
|
||||
|
||||
const accountActivationRequired = metadata.accountActivationRequired
|
||||
store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired })
|
||||
|
||||
|
@ -394,9 +399,6 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
|||
])
|
||||
|
||||
// Start fetching things that don't need to block the UI
|
||||
store.dispatch('fetchMutes')
|
||||
store.dispatch('startFetchingAnnouncements')
|
||||
store.dispatch('startFetchingReports')
|
||||
getTOS({ store })
|
||||
getStickers({ store })
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
faPencilAlt,
|
||||
faAlignRight
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import Blurhash from '../blurhash/Blurhash.vue'
|
||||
|
||||
library.add(
|
||||
faFile,
|
||||
|
@ -63,7 +64,8 @@ const Attachment = {
|
|||
components: {
|
||||
Flash,
|
||||
StillImage,
|
||||
VideoAttachment
|
||||
VideoAttachment,
|
||||
Blurhash
|
||||
},
|
||||
computed: {
|
||||
classNames () {
|
||||
|
@ -84,6 +86,9 @@ const Attachment = {
|
|||
useContainFit () {
|
||||
return this.$store.getters.mergedConfig.useContainFit
|
||||
},
|
||||
useBlurhash () {
|
||||
return this.$store.getters.mergedConfig.useBlurhash
|
||||
},
|
||||
placeholderName () {
|
||||
if (this.attachment.description === '' || !this.attachment.description) {
|
||||
return this.type.toUpperCase()
|
||||
|
|
|
@ -64,7 +64,15 @@
|
|||
:title="attachment.description"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
>
|
||||
<Blurhash
|
||||
v-if="useBlurhash && attachment.blurhash"
|
||||
:height="512"
|
||||
:width="1024"
|
||||
:hash="attachment.blurhash"
|
||||
:punch="1"
|
||||
/>
|
||||
<img
|
||||
v-else
|
||||
:key="nsfwImage"
|
||||
class="nsfw"
|
||||
:src="nsfwImage"
|
||||
|
|
66
src/components/blurhash/Blurhash.vue
Normal file
66
src/components/blurhash/Blurhash.vue
Normal file
|
@ -0,0 +1,66 @@
|
|||
<template>
|
||||
<canvas
|
||||
ref="canvas"
|
||||
class="blurhash"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { decode } from "blurhash";
|
||||
|
||||
export default {
|
||||
name: 'Blurhash',
|
||||
props: {
|
||||
hash: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
punch: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
canvas: null,
|
||||
ctx: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.canvas = this.$refs.canvas;
|
||||
this.ctx = this.canvas.getContext('2d');
|
||||
this.canvas.width = 1024;
|
||||
this.canvas.height = 512;
|
||||
this.draw();
|
||||
},
|
||||
methods: {
|
||||
draw() {
|
||||
const pixels = decode(this.hash, this.width, this.height, this.punch);
|
||||
const imageData = this.ctx.createImageData(this.width, this.height);
|
||||
imageData.data.set(pixels);
|
||||
this.ctx.putImageData(imageData, 0, 0);
|
||||
fetch("/static/blurhash-overlay.png")
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => {
|
||||
const img = new Image();
|
||||
img.src = URL.createObjectURL(blob);
|
||||
img.onload = () => {
|
||||
this.ctx.drawImage(img, 0, 0, this.width, this.height);
|
||||
};
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,6 +1,11 @@
|
|||
import SearchBar from 'components/search_bar/search_bar.vue'
|
||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
publicTimelineVisible,
|
||||
federatedTimelineVisible,
|
||||
bubbleTimelineVisible,
|
||||
} from '../../lib/timeline_visibility'
|
||||
import {
|
||||
faSignInAlt,
|
||||
faSignOutAlt,
|
||||
|
@ -19,6 +24,7 @@ import {
|
|||
faInfoCircle,
|
||||
faUserTie
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
library.add(
|
||||
faSignInAlt,
|
||||
|
@ -103,7 +109,12 @@ export default {
|
|||
},
|
||||
showBubbleTimeline () {
|
||||
return this.$store.state.instance.localBubbleInstances.length > 0
|
||||
}
|
||||
},
|
||||
...mapState({
|
||||
publicTimelineVisible,
|
||||
federatedTimelineVisible,
|
||||
bubbleTimelineVisible,
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
scrollToTop () {
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<router-link
|
||||
:to="{ name: 'public-timeline' }"
|
||||
class="nav-icon"
|
||||
v-if="publicTimelineVisible"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
|
@ -55,7 +56,7 @@
|
|||
/>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="currentUser && showBubbleTimeline"
|
||||
v-if="bubbleTimelineVisible"
|
||||
:to="{ name: 'bubble-timeline' }"
|
||||
class="nav-icon"
|
||||
>
|
||||
|
@ -69,6 +70,7 @@
|
|||
<router-link
|
||||
:to="{ name: 'public-external-timeline' }"
|
||||
class="nav-icon"
|
||||
v-if="federatedTimelineVisible"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
|
|
133
src/components/emoji_grid/emoji_grid.js
Normal file
133
src/components/emoji_grid/emoji_grid.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
const EMOJI_SIZE = 32 + 8
|
||||
const GROUP_TITLE_HEIGHT = 24
|
||||
const BUFFER_SIZE = 3 * EMOJI_SIZE
|
||||
|
||||
const EmojiGrid = {
|
||||
props: {
|
||||
groups: {
|
||||
required: true,
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
containerWidth: 0,
|
||||
containerHeight: 0,
|
||||
scrollPos: 0,
|
||||
resizeObserver: null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
const rect = this.$refs.container.getBoundingClientRect()
|
||||
this.containerWidth = rect.width
|
||||
this.containerHeight = rect.height
|
||||
this.resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
this.containerWidth = entry.contentRect.width
|
||||
this.containerHeight = entry.contentRect.height
|
||||
}
|
||||
})
|
||||
this.resizeObserver.observe(this.$refs.container)
|
||||
},
|
||||
beforeUnmount () {
|
||||
this.resizeObserver.disconnect()
|
||||
this.resizeObserver = null
|
||||
},
|
||||
watch: {
|
||||
groups () {
|
||||
// Scroll to top when grid content changes
|
||||
if (this.$refs.container) {
|
||||
this.$refs.container.scrollTo(0, 0)
|
||||
}
|
||||
},
|
||||
activeGroup (group) {
|
||||
this.$emit('activeGroup', group)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onScroll () {
|
||||
this.scrollPos = this.$refs.container.scrollTop
|
||||
},
|
||||
onEmoji (emoji) {
|
||||
this.$emit('emoji', emoji)
|
||||
},
|
||||
scrollToItem (itemId) {
|
||||
const container = this.$refs.container
|
||||
if (!container) return
|
||||
|
||||
for (const item of this.itemList) {
|
||||
if (item.id === itemId) {
|
||||
container.scrollTo(0, item.position.y)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// Total height of scroller content
|
||||
gridHeight () {
|
||||
if (this.itemList.length === 0) return 0
|
||||
const lastItem = this.itemList[this.itemList.length - 1]
|
||||
return (
|
||||
lastItem.position.y +
|
||||
('title' in lastItem ? GROUP_TITLE_HEIGHT : EMOJI_SIZE)
|
||||
)
|
||||
},
|
||||
activeGroup () {
|
||||
const items = this.itemList
|
||||
for (let i = items.length - 1; i >= 0; i--) {
|
||||
const item = items[i]
|
||||
if ('title' in item && item.position.y <= this.scrollPos) {
|
||||
return item.id
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
itemList () {
|
||||
const items = []
|
||||
let x = 0
|
||||
let y = 0
|
||||
for (const group of this.groups) {
|
||||
items.push({ position: { x, y }, id: group.id, title: group.text })
|
||||
if (group.text.length) {
|
||||
y += GROUP_TITLE_HEIGHT
|
||||
}
|
||||
for (const emoji of group.emojis) {
|
||||
items.push({
|
||||
position: { x, y },
|
||||
id: `${group.id}-${emoji.displayText}`,
|
||||
emoji
|
||||
})
|
||||
x += EMOJI_SIZE
|
||||
if (x + EMOJI_SIZE > this.containerWidth) {
|
||||
y += EMOJI_SIZE
|
||||
x = 0
|
||||
}
|
||||
}
|
||||
if (x > 0) {
|
||||
y += EMOJI_SIZE
|
||||
x = 0
|
||||
}
|
||||
}
|
||||
return items
|
||||
},
|
||||
visibleItems () {
|
||||
const startPos = this.scrollPos - BUFFER_SIZE
|
||||
const endPos = this.scrollPos + this.containerHeight + BUFFER_SIZE
|
||||
return this.itemList.filter((i) => {
|
||||
return i.position.y >= startPos && i.position.y < endPos
|
||||
})
|
||||
},
|
||||
scrolledClass () {
|
||||
if (this.scrollPos <= 5) {
|
||||
return 'scrolled-top'
|
||||
} else if (this.scrollPos >= this.gridHeight - this.containerHeight - 5) {
|
||||
return 'scrolled-bottom'
|
||||
} else {
|
||||
return 'scrolled-middle'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default EmojiGrid
|
60
src/components/emoji_grid/emoji_grid.scss
Normal file
60
src/components/emoji_grid/emoji_grid.scss
Normal file
|
@ -0,0 +1,60 @@
|
|||
.emoji {
|
||||
&-grid {
|
||||
flex: 1 1 1px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
user-select: none;
|
||||
mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
|
||||
linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
|
||||
linear-gradient(to top, white, white);
|
||||
transition: mask-size 150ms;
|
||||
mask-size: 100% 20px, 100% 20px, auto;
|
||||
// Autoprefixed seem to ignore this one, and also syntax is different
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
&.scrolled {
|
||||
&-top {
|
||||
mask-size: 100% 20px, 100% 0, auto;
|
||||
}
|
||||
&-bottom {
|
||||
mask-size: 100% 0, 100% 20px, auto;
|
||||
}
|
||||
}
|
||||
margin-left: 5px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
&-group-title {
|
||||
position: absolute;
|
||||
font-size: 0.85em;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
|
||||
&.disabled {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-item {
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
font-size: 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 4px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
object-fit: contain;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
48
src/components/emoji_grid/emoji_grid.vue
Normal file
48
src/components/emoji_grid/emoji_grid.vue
Normal file
|
@ -0,0 +1,48 @@
|
|||
<template>
|
||||
<div
|
||||
ref="container"
|
||||
class="emoji-grid"
|
||||
:class="scrolledClass"
|
||||
@scroll.passive="onScroll"
|
||||
>
|
||||
<div
|
||||
:style="{
|
||||
height: `${gridHeight}px`,
|
||||
}"
|
||||
>
|
||||
<template v-for="item in visibleItems">
|
||||
<h6
|
||||
v-if="'title' in item && item.title.length"
|
||||
:key="'title-' + item.id"
|
||||
class="emoji-group-title"
|
||||
:style="{
|
||||
top: item.position.y + 'px',
|
||||
left: item.position.x + 'px'
|
||||
}"
|
||||
>
|
||||
{{ item.title }}
|
||||
</h6>
|
||||
<span
|
||||
v-else-if="'emoji' in item"
|
||||
:key="'emoji-' + item.id"
|
||||
class="emoji-item"
|
||||
:title="item.emoji.displayText"
|
||||
:style="{
|
||||
top: item.position.y + 'px',
|
||||
left: item.position.x + 'px'
|
||||
}"
|
||||
@click.stop.prevent="onEmoji(item.emoji)"
|
||||
>
|
||||
<span v-if="!item.emoji.imageUrl">{{ item.emoji.replacement }}</span>
|
||||
<img
|
||||
v-else
|
||||
:src="item.emoji.imageUrl"
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./emoji_grid.js"></script>
|
||||
<style lang="scss" src="./emoji_grid.scss"></style>
|
|
@ -205,7 +205,6 @@ const EmojiInput = {
|
|||
},
|
||||
triggerShowPicker () {
|
||||
this.showPicker = true
|
||||
this.$refs.picker.startEmojiLoad()
|
||||
this.$nextTick(() => {
|
||||
this.scrollIntoView()
|
||||
this.focusPickerInput()
|
||||
|
@ -223,7 +222,6 @@ const EmojiInput = {
|
|||
this.showPicker = !this.showPicker
|
||||
if (this.showPicker) {
|
||||
this.scrollIntoView()
|
||||
this.$refs.picker.startEmojiLoad()
|
||||
this.$nextTick(this.focusPickerInput)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<EmojiPicker
|
||||
v-if="enableEmojiPicker"
|
||||
ref="picker"
|
||||
show-keep-open
|
||||
:class="{ hide: !showPicker }"
|
||||
:enable-sticker-picker="enableStickerPicker"
|
||||
class="emoji-picker-panel"
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { defineAsyncComponent } from 'vue'
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
import EmojiGrid from '../emoji_grid/emoji_grid.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faBoxOpen,
|
||||
faStickyNote,
|
||||
faSmileBeam
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { trim, escapeRegExp, startCase } from 'lodash'
|
||||
import { trim, escapeRegExp, startCase, debounce } from 'lodash'
|
||||
|
||||
library.add(
|
||||
faBoxOpen,
|
||||
|
@ -14,19 +15,17 @@ library.add(
|
|||
faSmileBeam
|
||||
)
|
||||
|
||||
// At widest, approximately 20 emoji are visible in a row,
|
||||
// loading 3 rows, could be overkill for narrow picker
|
||||
const LOAD_EMOJI_BY = 60
|
||||
|
||||
// When to start loading new batch emoji, in pixels
|
||||
const LOAD_EMOJI_MARGIN = 64
|
||||
|
||||
const EmojiPicker = {
|
||||
props: {
|
||||
enableStickerPicker: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
showKeepOpen: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
|
@ -34,18 +33,18 @@ const EmojiPicker = {
|
|||
keyword: '',
|
||||
activeGroup: 'standard',
|
||||
showingStickers: false,
|
||||
groupsScrolledClass: 'scrolled-top',
|
||||
keepOpen: false,
|
||||
customEmojiBufferSlice: LOAD_EMOJI_BY,
|
||||
customEmojiTimeout: null,
|
||||
customEmojiLoadAllConfirmed: false
|
||||
keepOpen: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
|
||||
Checkbox
|
||||
Checkbox,
|
||||
EmojiGrid
|
||||
},
|
||||
methods: {
|
||||
debouncedSearch: debounce(function (e) {
|
||||
this.keyword = e.target.value
|
||||
}, 500),
|
||||
onStickerUploaded (e) {
|
||||
this.$emit('sticker-uploaded', e)
|
||||
},
|
||||
|
@ -55,12 +54,7 @@ const EmojiPicker = {
|
|||
onEmoji (emoji) {
|
||||
const value = emoji.imageUrl ? `:${emoji.displayText}:` : emoji.replacement
|
||||
this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
|
||||
},
|
||||
onScroll (e) {
|
||||
const target = (e && e.target) || this.$refs['emoji-groups']
|
||||
this.updateScrolledClass(target)
|
||||
this.scrolledGroup(target)
|
||||
this.triggerLoadMore(target)
|
||||
this.$store.commit('emojiUsed', emoji)
|
||||
},
|
||||
onWheel (e) {
|
||||
e.preventDefault()
|
||||
|
@ -69,68 +63,12 @@ const EmojiPicker = {
|
|||
highlight (key) {
|
||||
this.setShowStickers(false)
|
||||
this.activeGroup = key
|
||||
},
|
||||
updateScrolledClass (target) {
|
||||
if (target.scrollTop <= 5) {
|
||||
this.groupsScrolledClass = 'scrolled-top'
|
||||
} else if (target.scrollTop >= target.scrollTopMax - 5) {
|
||||
this.groupsScrolledClass = 'scrolled-bottom'
|
||||
} else {
|
||||
this.groupsScrolledClass = 'scrolled-middle'
|
||||
if (this.keyword.length) {
|
||||
this.$refs.emojiGrid.scrollToItem(key)
|
||||
}
|
||||
},
|
||||
triggerLoadMore (target) {
|
||||
const ref = this.$refs['group-end-custom']
|
||||
if (!ref) return
|
||||
const bottom = ref.offsetTop + ref.offsetHeight
|
||||
|
||||
const scrollerBottom = target.scrollTop + target.clientHeight
|
||||
const scrollerTop = target.scrollTop
|
||||
const scrollerMax = target.scrollHeight
|
||||
|
||||
// Loads more emoji when they come into view
|
||||
const approachingBottom = bottom - scrollerBottom < LOAD_EMOJI_MARGIN
|
||||
// Always load when at the very top in case there's no scroll space yet
|
||||
const atTop = scrollerTop < 5
|
||||
// Don't load when looking at unicode category or at the very bottom
|
||||
const bottomAboveViewport = bottom < scrollerTop || scrollerBottom === scrollerMax
|
||||
if (!bottomAboveViewport && (approachingBottom || atTop)) {
|
||||
this.loadEmoji()
|
||||
}
|
||||
},
|
||||
scrolledGroup (target) {
|
||||
const top = target.scrollTop + 5
|
||||
this.$nextTick(() => {
|
||||
this.emojisView.forEach(group => {
|
||||
const ref = this.$refs['group-' + group.id]
|
||||
if (ref.offsetTop <= top) {
|
||||
this.activeGroup = group.id
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
loadEmoji () {
|
||||
const allLoaded = this.customEmojiBuffer.length === this.filteredEmoji.length
|
||||
|
||||
if (allLoaded) {
|
||||
return
|
||||
}
|
||||
|
||||
this.customEmojiBufferSlice += LOAD_EMOJI_BY
|
||||
},
|
||||
startEmojiLoad (forceUpdate = false) {
|
||||
if (!forceUpdate) {
|
||||
this.keyword = ''
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs['emoji-groups'].scrollTop = 0
|
||||
})
|
||||
const bufferSize = this.customEmojiBuffer.length
|
||||
const bufferPrefilledAll = bufferSize === this.filteredEmoji.length
|
||||
if (bufferPrefilledAll && !forceUpdate) {
|
||||
return
|
||||
}
|
||||
this.customEmojiBufferSlice = LOAD_EMOJI_BY
|
||||
onActiveGroup (group) {
|
||||
this.activeGroup = group
|
||||
},
|
||||
toggleStickers () {
|
||||
this.showingStickers = !this.showingStickers
|
||||
|
@ -146,32 +84,12 @@ const EmojiPicker = {
|
|||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
keyword () {
|
||||
this.customEmojiLoadAllConfirmed = false
|
||||
this.onScroll()
|
||||
this.startEmojiLoad(true)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
activeGroupView () {
|
||||
return this.showingStickers ? '' : this.activeGroup
|
||||
},
|
||||
stickersAvailable () {
|
||||
if (this.$store.state.instance.stickers) {
|
||||
return this.$store.state.instance.stickers.length > 0
|
||||
}
|
||||
return 0
|
||||
},
|
||||
filteredEmoji () {
|
||||
return this.filterByKeyword(
|
||||
this.$store.state.instance.customEmoji || []
|
||||
)
|
||||
},
|
||||
customEmojiBuffer () {
|
||||
return this.filteredEmoji.slice(0, this.customEmojiBufferSlice)
|
||||
},
|
||||
emojis () {
|
||||
const recentEmojis = this.$store.getters.recentEmojis
|
||||
const standardEmojis = this.$store.state.instance.emoji || []
|
||||
const customEmojis = this.sortedEmoji
|
||||
const emojiPacks = []
|
||||
|
@ -184,6 +102,15 @@ const EmojiPicker = {
|
|||
})
|
||||
})
|
||||
return [
|
||||
{
|
||||
id: 'recent',
|
||||
text: this.$t('emoji.recent'),
|
||||
first: {
|
||||
imageUrl: '',
|
||||
replacement: '🕒',
|
||||
},
|
||||
emojis: this.filterByKeyword(recentEmojis)
|
||||
},
|
||||
{
|
||||
id: 'standard',
|
||||
text: this.$t('emoji.unicode'),
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
@import '../../_variables.scss';
|
||||
|
||||
// The worst query selector ever
|
||||
// selects ONLY emojis pickers in replies in notifications
|
||||
// who thought this was a good idea?
|
||||
.notification > .Status > .status-container > .post-status-form > form > .form-group > .emoji-input > .emoji-picker {
|
||||
max-width: 100%;
|
||||
left: 0;
|
||||
@media (min-width: 1300px) {
|
||||
left: -30px;
|
||||
}
|
||||
}
|
||||
|
||||
.Notification {
|
||||
.emoji-picker {
|
||||
min-width: 160%;
|
||||
|
@ -7,7 +18,7 @@
|
|||
overflow: hidden;
|
||||
left: -70%;
|
||||
max-width: 100%;
|
||||
@media (min-width: 800px) and (max-width: 1300px) {
|
||||
@media (min-width: 800px) and (max-width: 1280px) {
|
||||
left: -50%;
|
||||
min-width: 50%;
|
||||
max-width: 130%;
|
||||
|
@ -18,6 +29,10 @@
|
|||
min-width: 50%;
|
||||
max-width: 130%;
|
||||
}
|
||||
|
||||
.Status > .emoji-picker {
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
.emoji-picker {
|
||||
|
@ -70,10 +85,6 @@
|
|||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.emoji-groups {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.additional-tabs {
|
||||
border-left: 1px solid;
|
||||
border-left-color: $fallback--icon;
|
||||
|
@ -152,76 +163,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
&-search {
|
||||
padding: 5px;
|
||||
flex: 0 0 auto;
|
||||
.emoji-search {
|
||||
padding: 5px;
|
||||
flex: 0 0 auto;
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-groups {
|
||||
flex: 1 1 1px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
user-select: none;
|
||||
mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
|
||||
linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
|
||||
linear-gradient(to top, white, white);
|
||||
transition: mask-size 150ms;
|
||||
mask-size: 100% 20px, 100% 20px, auto;
|
||||
// Autoprefixed seem to ignore this one, and also syntax is different
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
&.scrolled {
|
||||
&-top {
|
||||
mask-size: 100% 20px, 100% 0, auto;
|
||||
}
|
||||
&-bottom {
|
||||
mask-size: 100% 0, 100% 20px, auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding-left: 5px;
|
||||
justify-content: left;
|
||||
|
||||
&-title {
|
||||
font-size: 0.85em;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
||||
&.disabled {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-item {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
font-size: 32px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 4px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
object-fit: contain;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
<div class="emoji-picker panel panel-default panel-body">
|
||||
<div class="heading">
|
||||
<span
|
||||
ref="emoji-tabs"
|
||||
class="emoji-tabs"
|
||||
@wheel="onWheel"
|
||||
ref="emoji-tabs"
|
||||
>
|
||||
<span
|
||||
v-for="group in emojis"
|
||||
|
@ -44,47 +44,22 @@
|
|||
>
|
||||
<div class="emoji-search">
|
||||
<input
|
||||
v-model="keyword"
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="$t('emoji.search_emoji')"
|
||||
@input="$event.target.composing = false"
|
||||
@input="debouncedSearch"
|
||||
>
|
||||
</div>
|
||||
<EmojiGrid
|
||||
ref="emojiGrid"
|
||||
:groups="emojisView"
|
||||
@emoji="onEmoji"
|
||||
@active-group="onActiveGroup"
|
||||
/>
|
||||
<div
|
||||
ref="emoji-groups"
|
||||
class="emoji-groups"
|
||||
:class="groupsScrolledClass"
|
||||
@scroll="onScroll"
|
||||
v-if="showKeepOpen"
|
||||
class="keep-open"
|
||||
>
|
||||
<div
|
||||
v-for="group in emojisView"
|
||||
:key="group.id"
|
||||
class="emoji-group"
|
||||
>
|
||||
<h6
|
||||
:ref="'group-' + group.id"
|
||||
class="emoji-group-title"
|
||||
>
|
||||
{{ group.text }}
|
||||
</h6>
|
||||
<span
|
||||
v-for="emoji in group.emojis"
|
||||
:key="group.id + emoji.displayText"
|
||||
:title="emoji.displayText"
|
||||
class="emoji-item"
|
||||
@click.stop.prevent="onEmoji(emoji)"
|
||||
>
|
||||
<span v-if="!emoji.imageUrl">{{ emoji.replacement }}</span>
|
||||
<img
|
||||
v-else
|
||||
:src="emoji.imageUrl"
|
||||
>
|
||||
</span>
|
||||
<span :ref="'group-end-' + group.id" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="keep-open">
|
||||
<Checkbox v-model="keepOpen">
|
||||
{{ $t('emoji.keep_open') }}
|
||||
</Checkbox>
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import UserListPopover from '../user_list_popover/user_list_popover.vue'
|
||||
import StillImage from '../still-image/still-image.vue'
|
||||
|
||||
const EMOJI_REACTION_COUNT_CUTOFF = 12
|
||||
|
||||
const findEmojiByReplacement = (state, replacement) => {
|
||||
const allEmojis = state.instance.emoji.concat(state.instance.customEmoji)
|
||||
return allEmojis.find(emoji => emoji.replacement === replacement)
|
||||
}
|
||||
|
||||
const EmojiReactions = {
|
||||
name: 'EmojiReactions',
|
||||
components: {
|
||||
UserAvatar,
|
||||
UserListPopover
|
||||
UserListPopover,
|
||||
StillImage
|
||||
},
|
||||
props: ['status'],
|
||||
data: () => ({
|
||||
|
@ -54,6 +61,8 @@ const EmojiReactions = {
|
|||
},
|
||||
reactWith (emoji) {
|
||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||
const emojiObject = findEmojiByReplacement(this.$store.state, emoji)
|
||||
this.$store.commit('emojiUsed', emojiObject)
|
||||
},
|
||||
unreact (emoji) {
|
||||
this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
|
||||
|
|
|
@ -14,12 +14,13 @@
|
|||
<span
|
||||
v-if="reaction.url !== null"
|
||||
>
|
||||
<img
|
||||
<StillImage
|
||||
:src="reaction.url"
|
||||
:title="reaction.name"
|
||||
:alt="reaction.name"
|
||||
class="reaction-emoji"
|
||||
width="2.55em"
|
||||
>
|
||||
height="2.55em"
|
||||
/>
|
||||
{{ reaction.count }}
|
||||
</span>
|
||||
<span v-else>
|
||||
|
@ -49,6 +50,7 @@
|
|||
display: flex;
|
||||
margin-top: 0.25em;
|
||||
flex-wrap: wrap;
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.unicode-emoji {
|
||||
|
@ -64,7 +66,9 @@
|
|||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
.reaction-emoji {
|
||||
width: 2.55em !important;
|
||||
width: auto;
|
||||
max-width: 96cqw;
|
||||
height: 2.55em !important;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
&:focus {
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
faBookmark as faBookmarkReg,
|
||||
faFlag
|
||||
} from '@fortawesome/free-regular-svg-icons'
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
library.add(
|
||||
faEllipsisH,
|
||||
|
@ -135,17 +136,26 @@ const ExtraButtons = {
|
|||
},
|
||||
doRedraftStatus () {
|
||||
this.$store.dispatch('fetchStatusSource', { id: this.status.id })
|
||||
.then(data => this.$store.dispatch('openPostStatusModal', {
|
||||
isRedraft: true,
|
||||
statusId: this.status.id,
|
||||
subject: data.spoiler_text,
|
||||
statusText: data.text,
|
||||
statusIsSensitive: this.status.nsfw,
|
||||
statusPoll: this.status.poll,
|
||||
statusFiles: [...this.status.attachments],
|
||||
statusScope: this.status.visibility,
|
||||
statusContentType: data.content_type
|
||||
}))
|
||||
.then(data => {
|
||||
let repliedUserId = this.status.in_reply_to_user_id;
|
||||
let repliedUser = this.status.attentions.filter(user =>
|
||||
user.id === repliedUserId);
|
||||
this.$store.dispatch('openPostStatusModal', {
|
||||
isRedraft: true,
|
||||
attentions: this.status.attentions,
|
||||
statusId: this.status.id,
|
||||
subject: data.spoiler_text,
|
||||
statusText: data.text,
|
||||
statusIsSensitive: this.status.nsfw,
|
||||
statusPoll: this.status.poll,
|
||||
statusFiles: [...this.status.attachments],
|
||||
statusScope: this.status.visibility,
|
||||
statusLanguage: this.status.language,
|
||||
statusContentType: data.content_type,
|
||||
replyTo: this.status.in_reply_to_status_id,
|
||||
repliedUser: repliedUser
|
||||
})
|
||||
})
|
||||
this.doDeleteStatus()
|
||||
},
|
||||
showRedraftStatusConfirmDialog () {
|
||||
|
@ -190,7 +200,7 @@ const ExtraButtons = {
|
|||
isEdited () {
|
||||
return this.status.edited_at !== null
|
||||
},
|
||||
editingAvailable () { return this.$store.state.instance.editingAvailable }
|
||||
editingAvailable () { return this.$store.state.instance.editingAvailable },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,9 @@
|
|||
|
||||
.interactive {
|
||||
.svg-inline--fa {
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: unset;
|
||||
}
|
||||
animation-duration: 0.6s;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ const FollowRequestCard = {
|
|||
doApprove () {
|
||||
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
|
||||
this.$store.dispatch('removeFollowRequest', this.user)
|
||||
this.$store.dispatch('decrementFollowRequestsCount')
|
||||
|
||||
const notifId = this.findFollowRequestNotificationId()
|
||||
this.$store.dispatch('markSingleNotificationAsSeen', { id: notifId })
|
||||
|
@ -66,6 +67,7 @@ const FollowRequestCard = {
|
|||
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
|
||||
.then(() => {
|
||||
this.$store.dispatch('dismissNotificationLocal', { id: notifId })
|
||||
this.$store.dispatch('decrementFollowRequestsCount')
|
||||
this.$store.dispatch('removeFollowRequest', this.user)
|
||||
})
|
||||
this.hideDenyConfirmDialog()
|
||||
|
@ -80,6 +82,11 @@ const FollowRequestCard = {
|
|||
},
|
||||
shouldConfirmDeny () {
|
||||
return this.mergedConfig.modalOnDenyFollow
|
||||
},
|
||||
show () {
|
||||
const notifId = this.$store.state.api.followRequests.find(req => req.id === this.user.id)
|
||||
|
||||
return notifId !== undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<basic-user-card :user="user">
|
||||
<basic-user-card :user="user" v-if="show">
|
||||
<div class="follow-request-card-content-container">
|
||||
<button
|
||||
class="btn button-default"
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
import FollowRequestCard from '../follow_request_card/follow_request_card.vue'
|
||||
import withLoadMore from '../../hocs/with_load_more/with_load_more'
|
||||
import List from '../list/list.vue'
|
||||
import get from 'lodash/get'
|
||||
|
||||
const FollowRequestList = withLoadMore({
|
||||
fetch: (props, $store) => $store.dispatch('fetchFollowRequests'),
|
||||
select: (props, $store) => get($store.state.api, 'followRequests', []).map(req => $store.getters.findUser(req.id)),
|
||||
destroy: (props, $store) => $store.dispatch('clearFollowRequests'),
|
||||
childPropName: 'items',
|
||||
additionalPropNames: ['userId']
|
||||
})(List);
|
||||
|
||||
|
||||
const FollowRequests = {
|
||||
components: {
|
||||
FollowRequestCard
|
||||
FollowRequestCard,
|
||||
FollowRequestList
|
||||
},
|
||||
computed: {
|
||||
userId () {
|
||||
return this.$store.state.users.currentUser.id
|
||||
},
|
||||
requests () {
|
||||
return this.$store.state.api.followRequests
|
||||
}
|
||||
|
|
|
@ -6,12 +6,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<FollowRequestCard
|
||||
v-for="request in requests"
|
||||
:key="request.id"
|
||||
:user="request"
|
||||
class="list-item"
|
||||
/>
|
||||
<FollowRequestList :user-id="userId">
|
||||
<template #item="{item}">
|
||||
<FollowRequestCard :user="item" />
|
||||
</template>
|
||||
</FollowRequestList>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
77
src/components/followed_tag_card/FollowedTagCard.vue
Normal file
77
src/components/followed_tag_card/FollowedTagCard.vue
Normal file
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div class="followed-tag-card">
|
||||
<span>
|
||||
<router-link :to="{ name: 'tag-timeline', params: {tag: tag.name}}">
|
||||
<span class="tag-link">#{{ tag.name }}</span>
|
||||
</router-link>
|
||||
<span class="unfollow-tag">
|
||||
<button
|
||||
v-if="isFollowing"
|
||||
class="button-default unfollow-tag-button"
|
||||
:title="$t('user_card.unfollow_tag')"
|
||||
@click="unfollowTag(tag.name)"
|
||||
>
|
||||
{{ $t('user_card.unfollow_tag') }}
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="button-default follow-tag-button"
|
||||
:title="$t('user_card.follow_tag')"
|
||||
@click="followTag(tag.name)"
|
||||
>
|
||||
{{ $t('user_card.follow_tag') }}
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FollowedTagCard',
|
||||
props: {
|
||||
tag: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
// this is a hack to update the state of the button
|
||||
// for some reason, List does not update on changes to the tag object
|
||||
data: () => ({
|
||||
isFollowing: true
|
||||
}),
|
||||
mounted () {
|
||||
this.isFollowing = this.tag.following
|
||||
},
|
||||
methods: {
|
||||
unfollowTag (tag) {
|
||||
this.$store.dispatch('unfollowTag', tag)
|
||||
this.isFollowing = false
|
||||
},
|
||||
followTag (tag) {
|
||||
this.$store.dispatch('followTag', tag)
|
||||
this.isFollowing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.followed-tag-card {
|
||||
margin-left: 1rem;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.unfollow-tag {
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
}
|
||||
|
||||
.tag-link {
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
.unfollow-tag-button, .follow-tag-button {
|
||||
font-size: medium;
|
||||
}
|
||||
</style>
|
|
@ -1,9 +1,13 @@
|
|||
<template>
|
||||
<div class="list">
|
||||
<div
|
||||
class="list"
|
||||
role="list"
|
||||
>
|
||||
<div
|
||||
v-for="item in items"
|
||||
:key="getKey(item)"
|
||||
class="list-item"
|
||||
role="listitem"
|
||||
>
|
||||
<slot
|
||||
name="item"
|
||||
|
|
|
@ -157,6 +157,9 @@
|
|||
box-shadow: var(--panelShadow);
|
||||
transition-property: transform;
|
||||
transition-duration: 0.25s;
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: unset;
|
||||
}
|
||||
transform: translateX(0);
|
||||
z-index: 1001;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
|
|
@ -33,11 +33,6 @@ library.add(
|
|||
)
|
||||
|
||||
const NavPanel = {
|
||||
created () {
|
||||
if (this.currentUser && this.currentUser.locked) {
|
||||
this.$store.dispatch('startFetchingFollowRequests')
|
||||
}
|
||||
},
|
||||
components: {
|
||||
TimelineMenuContent
|
||||
},
|
||||
|
@ -54,11 +49,13 @@ const NavPanel = {
|
|||
computed: {
|
||||
...mapState({
|
||||
currentUser: state => state.users.currentUser,
|
||||
followRequestCount: state => state.api.followRequests.length,
|
||||
privateMode: state => state.instance.private,
|
||||
federating: state => state.instance.federating
|
||||
federating: state => state.instance.federating,
|
||||
}),
|
||||
...mapGetters(['unreadAnnouncementCount'])
|
||||
...mapGetters(['unreadAnnouncementCount']),
|
||||
followRequestCount () {
|
||||
return this.$store.state.users.currentUser.follow_requests_count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import PinchZoom from '@kazvmoe-infra/pinch-zoom-element'
|
||||
import PinchZoom from '@floatingghost/pinch-zoom-element'
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
|
|
|
@ -103,9 +103,9 @@ export default {
|
|||
convertExpiryFromUnit (unit, amount) {
|
||||
// Note: we want seconds and not milliseconds
|
||||
switch (unit) {
|
||||
case 'minutes': return 0.001 * amount * DateUtils.MINUTE
|
||||
case 'hours': return 0.001 * amount * DateUtils.HOUR
|
||||
case 'days': return 0.001 * amount * DateUtils.DAY
|
||||
case 'minutes': return amount * DateUtils.MINUTE / 1000
|
||||
case 'hours': return amount * DateUtils.HOUR / 1000
|
||||
case 'days': return amount * DateUtils.DAY / 1000
|
||||
}
|
||||
},
|
||||
expiryAmountChange () {
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
svg {
|
||||
width: 22px;
|
||||
margin-right: 0.75rem;
|
||||
color: var(--menuPopoverIcon, $fallback--icon)
|
||||
color: var(--popoverIcon, $fallback--icon)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import suggestor from '../emoji_input/suggestor.js'
|
|||
import { mapGetters, mapState } from 'vuex'
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
import Select from '../select/select.vue'
|
||||
import iso6391 from 'iso-639-1'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -53,6 +54,14 @@ const pxStringToNumber = (str) => {
|
|||
return Number(str.substring(0, str.length - 2))
|
||||
}
|
||||
|
||||
const deleteDraft = (draftKey) => {
|
||||
const draftData = JSON.parse(localStorage.getItem('drafts') || '{}');
|
||||
|
||||
delete draftData[draftKey];
|
||||
|
||||
localStorage.setItem('drafts', JSON.stringify(draftData));
|
||||
}
|
||||
|
||||
const PostStatusForm = {
|
||||
props: [
|
||||
'statusId',
|
||||
|
@ -63,6 +72,7 @@ const PostStatusForm = {
|
|||
'statusMediaDescriptions',
|
||||
'statusScope',
|
||||
'statusContentType',
|
||||
'statusLanguage',
|
||||
'replyTo',
|
||||
'quoteId',
|
||||
'repliedUser',
|
||||
|
@ -128,7 +138,7 @@ const PostStatusForm = {
|
|||
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
|
||||
}
|
||||
|
||||
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject } = this.$store.getters.mergedConfig
|
||||
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage } = this.$store.getters.mergedConfig
|
||||
|
||||
let statusParams = {
|
||||
spoilerText: this.subject || '',
|
||||
|
@ -139,6 +149,7 @@ const PostStatusForm = {
|
|||
poll: {},
|
||||
mediaDescriptions: {},
|
||||
visibility: this.suggestedVisibility(),
|
||||
language: interfaceLanguage,
|
||||
contentType
|
||||
}
|
||||
|
||||
|
@ -153,10 +164,41 @@ const PostStatusForm = {
|
|||
poll: this.statusPoll || {},
|
||||
mediaDescriptions: this.statusMediaDescriptions || {},
|
||||
visibility: this.statusScope || this.suggestedVisibility(),
|
||||
language: this.statusLanguage || interfaceLanguage,
|
||||
contentType: statusContentType
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.statusId) {
|
||||
let draftKey = 'status';
|
||||
if (this.replyTo) {
|
||||
draftKey = 'reply:' + this.replyTo;
|
||||
} else if (this.quoteId) {
|
||||
draftKey = 'quote:' + this.quoteId;
|
||||
}
|
||||
|
||||
const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[draftKey];
|
||||
|
||||
if (draft) {
|
||||
statusParams = {
|
||||
spoilerText: draft.data.spoilerText,
|
||||
status: draft.data.status,
|
||||
sensitiveIfSubject,
|
||||
nsfw: draft.data.nsfw,
|
||||
files: draft.data.files,
|
||||
poll: draft.data.poll,
|
||||
mediaDescriptions: draft.data.mediaDescriptions,
|
||||
visibility: draft.data.visibility,
|
||||
language: draft.data.language,
|
||||
contentType: draft.data.contentType
|
||||
}
|
||||
|
||||
if (draft.data.poll) {
|
||||
this.togglePollForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dropFiles: [],
|
||||
uploadingFiles: false,
|
||||
|
@ -259,7 +301,10 @@ const PostStatusForm = {
|
|||
...mapGetters(['mergedConfig']),
|
||||
...mapState({
|
||||
mobileLayout: state => state.interface.mobileLayout
|
||||
})
|
||||
}),
|
||||
isoLanguages () {
|
||||
return iso6391.getAllCodes();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'newStatus': {
|
||||
|
@ -273,6 +318,7 @@ const PostStatusForm = {
|
|||
statusChanged () {
|
||||
this.autoPreview()
|
||||
this.updateIdempotencyKey()
|
||||
this.saveDraft()
|
||||
},
|
||||
clearStatus () {
|
||||
const newStatus = this.newStatus
|
||||
|
@ -282,6 +328,7 @@ const PostStatusForm = {
|
|||
files: [],
|
||||
visibility: newStatus.visibility,
|
||||
contentType: newStatus.contentType,
|
||||
language: newStatus.language,
|
||||
poll: {},
|
||||
mediaDescriptions: {}
|
||||
}
|
||||
|
@ -341,6 +388,7 @@ const PostStatusForm = {
|
|||
inReplyToStatusId: this.replyTo,
|
||||
quoteId: this.quoteId,
|
||||
contentType: newStatus.contentType,
|
||||
language: newStatus.language,
|
||||
poll,
|
||||
idempotencyKey: this.idempotencyKey
|
||||
}
|
||||
|
@ -375,6 +423,7 @@ const PostStatusForm = {
|
|||
inReplyToStatusId: this.replyTo,
|
||||
quoteId: this.quoteId,
|
||||
contentType: newStatus.contentType,
|
||||
language: newStatus.language,
|
||||
poll: {},
|
||||
preview: true
|
||||
}).then((data) => {
|
||||
|
@ -391,8 +440,38 @@ const PostStatusForm = {
|
|||
}).finally(() => {
|
||||
this.previewLoading = false
|
||||
})
|
||||
|
||||
let draftKey = 'status';
|
||||
if (this.replyTo) {
|
||||
draftKey = 'reply:' + this.replyTo;
|
||||
} else if (this.quoteId) {
|
||||
draftKey = 'quote:' + this.quoteId;
|
||||
}
|
||||
deleteDraft(draftKey)
|
||||
},
|
||||
debouncePreviewStatus: debounce(function () { this.previewStatus() }, 500),
|
||||
saveDraft() {
|
||||
const draftData = JSON.parse(localStorage.getItem('drafts') || '{}');
|
||||
|
||||
let draftKey = 'status';
|
||||
if (this.replyTo) {
|
||||
draftKey = 'reply:' + this.replyTo;
|
||||
} else if (this.quoteId) {
|
||||
draftKey = 'quote:' + this.quoteId;
|
||||
}
|
||||
|
||||
if (this.newStatus.status || this.newStatus.spoilerText || this.newStatus.files.length > 0 || this.newStatus.poll.length > 0) {
|
||||
draftData[draftKey] = {
|
||||
updatedAt: new Date(),
|
||||
data: this.newStatus,
|
||||
};
|
||||
|
||||
localStorage.setItem('drafts', JSON.stringify(draftData));
|
||||
|
||||
} else {
|
||||
deleteDraft(draftKey);
|
||||
}
|
||||
},
|
||||
autoPreview () {
|
||||
if (!this.preview) return
|
||||
this.previewLoading = true
|
||||
|
|
|
@ -194,6 +194,23 @@
|
|||
:on-scope-change="changeVis"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="language-selector"
|
||||
>
|
||||
<Select
|
||||
id="post-language"
|
||||
v-model="newStatus.language"
|
||||
class="form-control"
|
||||
>
|
||||
<option
|
||||
v-for="language in isoLanguages"
|
||||
:key="language"
|
||||
:value="language"
|
||||
>
|
||||
{{ language }}
|
||||
</option>
|
||||
</Select>
|
||||
</div>
|
||||
<div
|
||||
v-if="postFormats.length > 1"
|
||||
class="text-format"
|
||||
|
@ -274,12 +291,14 @@
|
|||
>
|
||||
{{ $t('post_status.post') }}
|
||||
</button>
|
||||
<!-- touchstart is used to keep the OSK at the same position after a message send -->
|
||||
<!-- To keep the OSK at the same position after a message send, -->
|
||||
<!-- @touchstart.stop.prevent was used. But while OSK position is -->
|
||||
<!-- quirky, accidental mobile posts caused by the workaround -->
|
||||
<!-- when people tried to scroll were a more serious bug. -->
|
||||
<button
|
||||
v-else
|
||||
:disabled="uploadingFiles || disableSubmit"
|
||||
class="btn button-default"
|
||||
@touchstart.stop.prevent="postStatus($event, newStatus)"
|
||||
@click.stop.prevent="postStatus($event, newStatus)"
|
||||
>
|
||||
{{ $t('post_status.post') }}
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
|
||||
.interactive {
|
||||
.svg-inline--fa {
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
animation: unset;
|
||||
}
|
||||
animation-duration: 0.6s;
|
||||
}
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ export default {
|
|||
break
|
||||
}
|
||||
case 'span':
|
||||
if (this.handleLinks && attrs['class'] && attrs['class'].includes('h-card')) {
|
||||
if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) {
|
||||
return ['', children.map(processItem), '']
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
|
||||
.emoji {
|
||||
display: inline-block;
|
||||
width: var(--emoji-size, 32px);
|
||||
height: var(--emoji-size, 32px);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</button>
|
||||
{{ ' ' }}
|
||||
<button
|
||||
v-if="showPrivate"
|
||||
class="button-unstyled scope"
|
||||
|
@ -30,7 +29,6 @@
|
|||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</button>
|
||||
{{ ' ' }}
|
||||
<button
|
||||
v-if="showUnlisted"
|
||||
class="button-unstyled scope"
|
||||
|
@ -44,7 +42,6 @@
|
|||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</button>
|
||||
{{ ' ' }}
|
||||
<button
|
||||
v-if="showPublic"
|
||||
class="button-unstyled scope"
|
||||
|
@ -87,6 +84,7 @@
|
|||
min-width: 1.3em;
|
||||
min-height: 1.3em;
|
||||
text-align: center;
|
||||
margin-right: 0.4em;
|
||||
|
||||
&.selected svg {
|
||||
color: $fallback--lightText;
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
|
||||
.search-bar-input {
|
||||
flex: 1 0 auto;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
.cancel-search {
|
||||
|
|
|
@ -38,7 +38,7 @@ label.Select {
|
|||
margin: 0;
|
||||
padding: 0 2em 0 .2em;
|
||||
font-family: sans-serif;
|
||||
font-family: var(--inputFont, sans-serif);
|
||||
font-family: var(--interfaceFont, sans-serif);
|
||||
font-size: 1em;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
|
|
|
@ -76,6 +76,10 @@
|
|||
position: absolute;
|
||||
right: 20px;
|
||||
padding-right: 10px;
|
||||
|
||||
@media all and (max-width: 800px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,10 @@
|
|||
<div class="panel-body">
|
||||
<SettingsModalContent v-if="modalOpenedOnce" />
|
||||
</div>
|
||||
<span
|
||||
id="unscrolled-content"
|
||||
class="extra-content"
|
||||
/>
|
||||
<div class="panel-footer settings-footer">
|
||||
<Popover
|
||||
class="export"
|
||||
|
@ -53,7 +57,7 @@
|
|||
:bound-to="{ x: 'container' }"
|
||||
remove-padding
|
||||
>
|
||||
<template v-slot:trigger>
|
||||
<template #trigger>
|
||||
<button
|
||||
class="btn button-default"
|
||||
:title="$t('general.close')"
|
||||
|
@ -65,7 +69,7 @@
|
|||
/>
|
||||
</button>
|
||||
</template>
|
||||
<template v-slot:content="{close}">
|
||||
<template #content="{close}">
|
||||
<div class="dropdown-menu">
|
||||
<button
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
|
@ -103,14 +107,11 @@
|
|||
|
||||
<Checkbox
|
||||
:model-value="!!expertLevel"
|
||||
class="expertMode"
|
||||
@update:modelValue="expertLevel = Number($event)"
|
||||
>
|
||||
{{ $t("settings.expert_mode") }}
|
||||
</Checkbox>
|
||||
<span
|
||||
id="unscrolled-content"
|
||||
class="extra-content"
|
||||
/>
|
||||
<button
|
||||
v-if="currentUser"
|
||||
class="button-default logout-button"
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
>
|
||||
{{ $t('settings.settings_profile_force_sync') }}
|
||||
</button>
|
||||
|
||||
</p>
|
||||
<div
|
||||
@click="toggleExpandedSettings"
|
||||
|
@ -407,6 +406,15 @@
|
|||
{{ $t('settings.preload_images') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path="useBlurhash"
|
||||
expert="1"
|
||||
:disabled="!hideNsfw"
|
||||
>
|
||||
{{ $t('settings.use_blurhash') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting
|
||||
path="useOneClickNsfw"
|
||||
|
|
|
@ -10,17 +10,20 @@ import SelectableList from 'src/components/selectable_list/selectable_list.vue'
|
|||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||
import withSubscription from 'src/components/../hocs/with_subscription/with_subscription'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import withLoadMore from 'src/components/../hocs/with_load_more/with_load_more'
|
||||
|
||||
const BlockList = withSubscription({
|
||||
const BlockList = withLoadMore({
|
||||
fetch: (props, $store) => $store.dispatch('fetchBlocks'),
|
||||
select: (props, $store) => get($store.state.users.currentUser, 'blockIds', []),
|
||||
childPropName: 'items'
|
||||
childPropName: 'items',
|
||||
destroy: () => {}
|
||||
})(SelectableList)
|
||||
|
||||
const MuteList = withSubscription({
|
||||
const MuteList = withLoadMore({
|
||||
fetch: (props, $store) => $store.dispatch('fetchMutes'),
|
||||
select: (props, $store) => get($store.state.users.currentUser, 'muteIds', []),
|
||||
childPropName: 'items'
|
||||
childPropName: 'items',
|
||||
destroy: () => {}
|
||||
})(SelectableList)
|
||||
|
||||
const DomainMuteList = withSubscription({
|
||||
|
|
|
@ -12,6 +12,7 @@ import InterfaceLanguageSwitcher from 'src/components/interface_language_switche
|
|||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import localeService from 'src/services/locale/locale.service.js'
|
||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -43,10 +44,19 @@ const ProfileTab = {
|
|||
bannerPreview: null,
|
||||
background: null,
|
||||
backgroundPreview: null,
|
||||
emailLanguage: this.$store.state.users.currentUser.language || ''
|
||||
emailLanguage: this.$store.state.users.currentUser.language || '',
|
||||
newPostTTLDays: this.$store.state.users.currentUser.status_ttl_days,
|
||||
expirePosts: this.$store.state.users.currentUser.status_ttl_days !== null,
|
||||
userAcceptsDirectMessagesFrom: this.$store.state.users.currentUser.accepts_direct_messages_from,
|
||||
userAcceptsDirectMessagesFromOptions: ["everybody", "nobody", "people_i_follow"].map(mode => ({
|
||||
key: mode,
|
||||
value: mode,
|
||||
label: this.$t(`settings.user_accepts_direct_messages_from_${mode}`)
|
||||
}))
|
||||
}
|
||||
},
|
||||
components: {
|
||||
ChoiceSetting,
|
||||
ScopeSelector,
|
||||
ImageCropper,
|
||||
EmojiInput,
|
||||
|
@ -123,7 +133,9 @@ const ProfileTab = {
|
|||
display_name: this.newName,
|
||||
fields_attributes: this.newFields.filter(el => el != null),
|
||||
bot: this.bot,
|
||||
show_role: this.showRole
|
||||
show_role: this.showRole,
|
||||
status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1,
|
||||
accepts_direct_messages_from: this.userAcceptsDirectMessagesFrom
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.expire-posts-days {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.visibility-tray {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,32 @@
|
|||
<Checkbox v-model="bot">
|
||||
{{ $t('settings.bot') }}
|
||||
</Checkbox>
|
||||
</p>
|
||||
<p>
|
||||
<ChoiceSetting
|
||||
id="userAcceptsDirectMessagesFrom"
|
||||
path="userAcceptsDirectMessagesFrom"
|
||||
:options="userAcceptsDirectMessagesFromOptions"
|
||||
>
|
||||
{{ $t('settings.user_accepts_direct_messages_from') }}
|
||||
</ChoiceSetting>
|
||||
</p>
|
||||
<p>
|
||||
<Checkbox v-model="expirePosts">
|
||||
{{ $t('settings.expire_posts_enabled') }}
|
||||
</Checkbox>
|
||||
<input
|
||||
v-model="newPostTTLDays"
|
||||
:disabled="!expirePosts"
|
||||
type="number"
|
||||
min="1"
|
||||
max="730"
|
||||
class="expire-posts-days"
|
||||
:placeholder="$t('settings.expire_posts_input_placeholder')"
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<interface-language-switcher
|
||||
|
|
|
@ -89,6 +89,10 @@
|
|||
margin: 1em 1em 0;
|
||||
}
|
||||
|
||||
.presets {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
@ -284,7 +288,6 @@
|
|||
box-shadow: none;
|
||||
background: transparent;
|
||||
color: var(--faint, $fallback--faint);
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.theme-color-cl,
|
||||
|
@ -318,11 +321,11 @@
|
|||
|
||||
.extra-content {
|
||||
.apply-container {
|
||||
padding-left: 15vw;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
justify-content: space-evenly;
|
||||
flex-grow: 1;
|
||||
|
||||
.btn {
|
||||
flex-grow: 1;
|
||||
min-height: 2em;
|
||||
|
|
|
@ -958,20 +958,22 @@
|
|||
v-if="isActive"
|
||||
to="#unscrolled-content"
|
||||
>
|
||||
<div class="apply-container">
|
||||
<button
|
||||
class="btn button-default submit"
|
||||
:disabled="!themeValid"
|
||||
@click="setCustomTheme"
|
||||
>
|
||||
{{ $t('general.apply') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearAll"
|
||||
>
|
||||
{{ $t('settings.style.switcher.reset') }}
|
||||
</button>
|
||||
<div class="panel-body settings-footer">
|
||||
<div class="apply-container">
|
||||
<button
|
||||
class="btn button-default submit"
|
||||
:disabled="!themeValid"
|
||||
@click="setCustomTheme"
|
||||
>
|
||||
{{ $t('general.apply') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearAll"
|
||||
>
|
||||
{{ $t('settings.style.switcher.reset') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</teleport>
|
||||
</div>
|
||||
|
|
|
@ -268,6 +268,10 @@
|
|||
.side-drawer {
|
||||
overflow-x: hidden;
|
||||
transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition-timing-function: unset;
|
||||
transition: unset;
|
||||
}
|
||||
transition: 0.35s;
|
||||
transition-property: transform;
|
||||
margin: 0 0 0 -100px;
|
||||
|
|
|
@ -20,6 +20,7 @@ import generateProfileLink from 'src/services/user_profile_link_generator/user_p
|
|||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||
import { muteWordHits } from '../../services/status_parser/status_parser.js'
|
||||
import { unescape, uniqBy } from 'lodash'
|
||||
import StillImage from '../still-image/still-image.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -117,7 +118,8 @@ const Status = {
|
|||
RichContent,
|
||||
MentionLink,
|
||||
MentionsLine,
|
||||
QuoteButton
|
||||
QuoteButton,
|
||||
StillImage
|
||||
},
|
||||
props: [
|
||||
'statusoid',
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
display: flex;
|
||||
padding: var(--status-margin, $status-margin);
|
||||
|
||||
.content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
> * {
|
||||
min-width: 0;
|
||||
}
|
||||
|
|
|
@ -174,12 +174,12 @@
|
|||
>
|
||||
@{{ status.user.screen_name_ui }}
|
||||
</router-link>
|
||||
<img
|
||||
<StillImage
|
||||
v-if="!!(status.user && status.user.favicon)"
|
||||
class="status-favicon"
|
||||
:src="status.user.favicon"
|
||||
:title="faviconAlt(status)"
|
||||
>
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
@ -352,22 +352,25 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<StatusContent
|
||||
ref="content"
|
||||
:status="status"
|
||||
:no-heading="noHeading"
|
||||
:highlight="highlight"
|
||||
:focused="isFocused"
|
||||
:controlled-showing-tall="controlledShowingTall"
|
||||
:controlled-expanding-subject="controlledExpandingSubject"
|
||||
:controlled-showing-long-subject="controlledShowingLongSubject"
|
||||
:controlled-toggle-showing-tall="controlledToggleShowingTall"
|
||||
:controlled-toggle-expanding-subject="controlledToggleExpandingSubject"
|
||||
:controlled-toggle-showing-long-subject="controlledToggleShowingLongSubject"
|
||||
@mediaplay="addMediaPlaying($event)"
|
||||
@mediapause="removeMediaPlaying($event)"
|
||||
@parseReady="setHeadTailLinks"
|
||||
/>
|
||||
<div class="content">
|
||||
<StatusContent
|
||||
ref="content"
|
||||
class="status-content"
|
||||
:status="status"
|
||||
:no-heading="noHeading"
|
||||
:highlight="highlight"
|
||||
:focused="isFocused"
|
||||
:controlled-showing-tall="controlledShowingTall"
|
||||
:controlled-expanding-subject="controlledExpandingSubject"
|
||||
:controlled-showing-long-subject="controlledShowingLongSubject"
|
||||
:controlled-toggle-showing-tall="controlledToggleShowingTall"
|
||||
:controlled-toggle-expanding-subject="controlledToggleExpandingSubject"
|
||||
:controlled-toggle-showing-long-subject="controlledToggleShowingLongSubject"
|
||||
@mediaplay="addMediaPlaying($event)"
|
||||
@mediapause="removeMediaPlaying($event)"
|
||||
@parseReady="setHeadTailLinks"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="inConversation && !isPreview && replies && replies.length"
|
||||
|
@ -534,6 +537,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./status.js" ></script>
|
||||
<script src="./status.js"></script>
|
||||
|
||||
<style src="./status.scss" lang="scss"></style>
|
||||
|
|
|
@ -17,26 +17,26 @@
|
|||
|
||||
.emoji:hover {
|
||||
transform: scale(1.4);
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: unset;
|
||||
}
|
||||
transition: 0.05s;
|
||||
}
|
||||
|
||||
._mfm_x2_ {
|
||||
.emoji {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
._mfm_x3_ {
|
||||
.emoji {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
._mfm_x4_ {
|
||||
.emoji {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,11 +68,10 @@
|
|||
.StatusContent {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
|
||||
img, video {
|
||||
&.emoji {
|
||||
width: 50px;
|
||||
max-width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +89,6 @@
|
|||
animation: none !important;
|
||||
}
|
||||
.emoji {
|
||||
width: 32px !important;
|
||||
height: 32px !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,9 @@ const StillImage = {
|
|||
],
|
||||
data () {
|
||||
return {
|
||||
stopGifs: this.$store.getters.mergedConfig.stopGifs,
|
||||
isAnimated: false
|
||||
stopGifs: this.$store.getters.mergedConfig.stopGifs || window.matchMedia('(prefers-reduced-motion: reduce)').matches,
|
||||
isAnimated: false,
|
||||
imageTypeLabel: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -39,14 +40,22 @@ const StillImage = {
|
|||
this.imageLoadError && this.imageLoadError()
|
||||
},
|
||||
detectAnimation (image) {
|
||||
if (this.mimetype === 'image/gif' || this.src.endsWith('.gif')) {
|
||||
this.isAnimated = true
|
||||
const mediaProxyAvailable = this.$store.state.instance.mediaProxyAvailable
|
||||
|
||||
// harmless CORS errors without-- clean console with
|
||||
if (!mediaProxyAvailable) {
|
||||
// It's a bit aggressive to assume all images we can't find the mimetype of is animated, but necessary for
|
||||
// people in need of reduced motion accessibility. As such, we'll consider those images animated if the user
|
||||
// agent is set to prefer reduced motion. Otherwise, it'll just be used as an early exit.
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||||
// Only for no media-proxy for now, since we're capturing gif, webp, and apng (are there others?)
|
||||
// Since the canvas and images are not pixel-perfect matching (due to scaling),
|
||||
// It makes the images jiggle on hover, which is not ideal for accessibility, methinks
|
||||
this.isAnimated = true
|
||||
}
|
||||
return
|
||||
}
|
||||
// harmless CORS errors without-- clean console with
|
||||
if (!this.$store.state.instance.mediaProxyAvailable) return
|
||||
// Animated JPEGs?
|
||||
if (!(this.src.endsWith('.webp') || this.src.endsWith('.png'))) return
|
||||
|
||||
// Browser Cache should ensure image doesn't get loaded twice if cache exists
|
||||
fetch(image.src, {
|
||||
referrerPolicy: 'same-origin'
|
||||
|
@ -55,12 +64,20 @@ const StillImage = {
|
|||
// We don't need to read the whole file so only call it once
|
||||
data.body.getReader().read()
|
||||
.then(reader => {
|
||||
if (this.src.endsWith('.webp') && this.isAnimatedWEBP(reader.value)) {
|
||||
// Ordered from least to most intensive
|
||||
if (this.isGIF(reader.value)) {
|
||||
this.isAnimated = true
|
||||
this.setLabel('GIF')
|
||||
return
|
||||
}
|
||||
if (this.src.endsWith('.png') && this.isAnimatedPNG(reader.value)) {
|
||||
if (this.isAnimatedWEBP(reader.value)) {
|
||||
this.isAnimated = true
|
||||
this.setLabel('WEBP')
|
||||
return
|
||||
}
|
||||
if (this.isAnimatedPNG(reader.value)) {
|
||||
this.isAnimated = true
|
||||
this.setLabel('APNG')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -68,6 +85,23 @@ const StillImage = {
|
|||
// this.imageLoadError && this.imageLoadError()
|
||||
})
|
||||
},
|
||||
setLabel (name) {
|
||||
this.imageTypeLabel = name;
|
||||
},
|
||||
isGIF (data) {
|
||||
// I am a perfectly sane individual
|
||||
//
|
||||
// GIF HEADER CHUNK
|
||||
// === START HEADER ===
|
||||
// 47 49 46 38 ("GIF8")
|
||||
const gifHeader = [0x47, 0x49, 0x46];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (data[i] !== gifHeader[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
isAnimatedWEBP (data) {
|
||||
/**
|
||||
* WEBP HEADER CHUNK
|
||||
|
@ -101,15 +135,54 @@ const StillImage = {
|
|||
const idatPos = str.indexOf('IDAT')
|
||||
return (str.substring(0, idatPos > 0 ? idatPos : 0).indexOf('acTL') > 0)
|
||||
},
|
||||
drawThumbnail () {
|
||||
const canvas = this.$refs.canvas
|
||||
if (!this.$refs.canvas) return
|
||||
const image = this.$refs.src
|
||||
const width = image.naturalWidth
|
||||
const height = image.naturalHeight
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
canvas.getContext('2d').drawImage(image, 0, 0, width, height)
|
||||
drawThumbnail() {
|
||||
const canvas = this.$refs.canvas;
|
||||
if (!canvas) return;
|
||||
|
||||
const context = canvas.getContext('2d');
|
||||
const image = this.$refs.src;
|
||||
const parentElement = canvas.parentElement;
|
||||
|
||||
// Draw the quick, unscaled version first
|
||||
context.drawImage(image, 0, 0, parentElement.clientWidth, parentElement.clientHeight);
|
||||
|
||||
// Use requestAnimationFrame to schedule the scaling to the next frame
|
||||
requestAnimationFrame(() => {
|
||||
// Compute scaling ratio between the natural dimensions of the image and its display dimensions
|
||||
const scalingRatioWidth = parentElement.clientWidth / image.naturalWidth;
|
||||
const scalingRatioHeight = parentElement.clientHeight / image.naturalHeight;
|
||||
|
||||
// Adjust for high-DPI displays
|
||||
const ratio = window.devicePixelRatio || 1;
|
||||
canvas.width = image.naturalWidth * scalingRatioWidth * ratio;
|
||||
canvas.height = image.naturalHeight * scalingRatioHeight * ratio;
|
||||
canvas.style.width = `${parentElement.clientWidth}px`;
|
||||
canvas.style.height = `${parentElement.clientHeight}px`;
|
||||
context.scale(ratio, ratio);
|
||||
|
||||
// Maintain the aspect ratio of the image
|
||||
const imgAspectRatio = image.naturalWidth / image.naturalHeight;
|
||||
const canvasAspectRatio = parentElement.clientWidth / parentElement.clientHeight;
|
||||
|
||||
let drawWidth, drawHeight;
|
||||
|
||||
if (imgAspectRatio > canvasAspectRatio) {
|
||||
drawWidth = parentElement.clientWidth;
|
||||
drawHeight = parentElement.clientWidth / imgAspectRatio;
|
||||
} else {
|
||||
drawHeight = parentElement.clientHeight;
|
||||
drawWidth = parentElement.clientHeight * imgAspectRatio;
|
||||
}
|
||||
|
||||
context.clearRect(0, 0, canvas.width, canvas.height); // Clear the previous unscaled image
|
||||
context.imageSmoothingEnabled = true;
|
||||
context.imageSmoothingQuality = 'high';
|
||||
|
||||
// Draw the good one for realsies
|
||||
const dx = (parentElement.clientWidth - drawWidth) / 2;
|
||||
const dy = (parentElement.clientHeight - drawHeight) / 2;
|
||||
context.drawImage(image, dx, dy, drawWidth, drawHeight);
|
||||
});
|
||||
}
|
||||
},
|
||||
updated () {
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
<template>
|
||||
<div
|
||||
ref="still-image"
|
||||
class="still-image"
|
||||
:class="{ animated: animated }"
|
||||
:style="style"
|
||||
>
|
||||
<div
|
||||
v-if="animated && imageTypeLabel"
|
||||
class="image-type-label">
|
||||
{{ imageTypeLabel }}
|
||||
</div>
|
||||
<canvas
|
||||
v-if="animated"
|
||||
ref="canvas"
|
||||
|
@ -57,30 +63,26 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.animated {
|
||||
&::before {
|
||||
zoom: var(--_still_image-label-scale, 1);
|
||||
content: 'gif';
|
||||
position: absolute;
|
||||
line-height: 1;
|
||||
font-size: 0.7em;
|
||||
top: 0.5em;
|
||||
left: 0.5em;
|
||||
background: rgba(127, 127, 127, 0.5);
|
||||
color: #fff;
|
||||
display: block;
|
||||
padding: 2px 4px;
|
||||
border-radius: $fallback--tooltipRadius;
|
||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
||||
z-index: 2;
|
||||
visibility: var(--_still-image-label-visibility, visible);
|
||||
}
|
||||
.image-type-label {
|
||||
position: absolute;
|
||||
top: 0.25em;
|
||||
left: 0.25em;
|
||||
line-height: 1;
|
||||
font-size: 0.6em;
|
||||
background: rgba(127, 127, 127, 0.5);
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
||||
z-index: 2;
|
||||
visibility: var(--_still-image-label-visibility, visible);
|
||||
}
|
||||
|
||||
&.animated {
|
||||
&:hover canvas {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
&:hover .image-type-label {
|
||||
visibility: var(--_still-image-label-visibility, hidden);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,13 @@ import TimelineMenuTabs from '../timeline_menu_tabs/timeline_menu_tabs.vue'
|
|||
import TimelineQuickSettings from './timeline_quick_settings.vue'
|
||||
import { debounce, throttle, keyBy } from 'lodash'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faCircleNotch, faCog } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faCircleNotch, faCog, faPlus, faMinus } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faCircleNotch,
|
||||
faCog
|
||||
faCog,
|
||||
faPlus,
|
||||
faMinus
|
||||
)
|
||||
|
||||
const Timeline = {
|
||||
|
@ -90,6 +92,15 @@ const Timeline = {
|
|||
},
|
||||
showPanelNavShortcuts () {
|
||||
return this.$store.getters.mergedConfig.showPanelNavShortcuts
|
||||
},
|
||||
currentUser () {
|
||||
return this.$store.state.users.currentUser
|
||||
},
|
||||
tagData () {
|
||||
return this.$store.state.tags.tags[this.tag]
|
||||
},
|
||||
tagFollowed () {
|
||||
return this.$store.state.tags.tags[this.tag]?.following
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
@ -118,6 +129,10 @@ const Timeline = {
|
|||
}
|
||||
window.addEventListener('keydown', this.handleShortKey)
|
||||
setTimeout(this.determineVisibleStatuses, 250)
|
||||
|
||||
if (this.tag) {
|
||||
this.$store.dispatch('getTag', this.tag)
|
||||
}
|
||||
},
|
||||
unmounted () {
|
||||
window.removeEventListener('scroll', this.handleScroll)
|
||||
|
@ -232,6 +247,12 @@ const Timeline = {
|
|||
}, 200),
|
||||
handleVisibilityChange () {
|
||||
this.unfocused = document.hidden
|
||||
},
|
||||
followTag (tag) {
|
||||
return this.$store.dispatch('followTag', tag)
|
||||
},
|
||||
unfollowTag (tag) {
|
||||
return this.$store.dispatch('unfollowTag', tag)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -21,6 +21,36 @@
|
|||
{{ $t('timeline.up_to_date') }}
|
||||
</div>
|
||||
<TimelineQuickSettings v-if="!embedded" />
|
||||
<div
|
||||
v-if="currentUser && tag !== undefined && tagData && !tagFollowed"
|
||||
class="followTag"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
:title="$t('timeline.follow_tag')"
|
||||
@click="followTag(tag)"
|
||||
>
|
||||
<FAIcon
|
||||
size="sm"
|
||||
icon="plus"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-if="currentUser && tag !== undefined && tagData && tagFollowed"
|
||||
class="followTag"
|
||||
>
|
||||
<button
|
||||
class="button-default"
|
||||
:title="$t('timeline.unfollow_tag')"
|
||||
@click="unfollowTag(tag)"
|
||||
>
|
||||
<FAIcon
|
||||
size="sm"
|
||||
icon="minus"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="classes.body">
|
||||
<div
|
||||
|
|
|
@ -62,6 +62,9 @@
|
|||
border-top-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
transform: translateY(-100%);
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: unset;
|
||||
}
|
||||
transition: transform 100ms;
|
||||
}
|
||||
|
||||
|
@ -89,6 +92,9 @@
|
|||
|
||||
svg {
|
||||
margin-left: 0.6em;
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
transition: unset;
|
||||
}
|
||||
transition: transform 100ms;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
faHome,
|
||||
faCircle
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { federatedTimelineVisible, publicTimelineVisible, bubbleTimelineVisible } from '../../lib/timeline_visibility'
|
||||
|
||||
library.add(
|
||||
faUsers,
|
||||
|
@ -24,7 +25,9 @@ const TimelineMenuContent = {
|
|||
currentUser: state => state.users.currentUser,
|
||||
privateMode: state => state.instance.private,
|
||||
federating: state => state.instance.federating,
|
||||
showBubbleTimeline: state => (state.instance.localBubbleInstances.length > 0)
|
||||
publicTimelineVisible,
|
||||
federatedTimelineVisible,
|
||||
bubbleTimelineVisible,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,23 +16,7 @@
|
|||
>{{ $t("nav.home_timeline") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser && showBubbleTimeline">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'bubble-timeline' }"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding "
|
||||
icon="circle"
|
||||
/>
|
||||
<span
|
||||
:title="$t('nav.bubble_timeline_description')"
|
||||
:aria-label="$t('nav.bubble_timeline_description')"
|
||||
>{{ $t("nav.bubble_timeline") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser || !privateMode">
|
||||
<li v-if="publicTimelineVisible">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'public-timeline' }"
|
||||
|
@ -48,7 +32,23 @@
|
|||
>{{ $t("nav.public_tl") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="federating && (currentUser || !privateMode)">
|
||||
<li v-if="bubbleTimelineVisible">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'bubble-timeline' }"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding "
|
||||
icon="circle"
|
||||
/>
|
||||
<span
|
||||
:title="$t('nav.bubble_timeline_description')"
|
||||
:aria-label="$t('nav.bubble_timeline_description')"
|
||||
>{{ $t("nav.bubble_timeline") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="federatedTimelineVisible">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'public-external-timeline' }"
|
||||
|
@ -62,6 +62,7 @@
|
|||
:title="$t('nav.twkn_timeline_description')"
|
||||
:aria-label="$t('nav.twkn_timeline_description')"
|
||||
>{{ $t("nav.twkn") }}</span>
|
||||
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser">
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
faHome
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { faCircle } from '@fortawesome/free-regular-svg-icons'
|
||||
import { federatedTimelineVisible, publicTimelineVisible, bubbleTimelineVisible } from '../../lib/timeline_visibility'
|
||||
library.add(
|
||||
faUsers,
|
||||
faGlobe,
|
||||
|
@ -22,7 +23,10 @@ const TimelineMenuContent = {
|
|||
...mapState({
|
||||
currentUser: state => state.users.currentUser,
|
||||
privateMode: state => state.instance.private,
|
||||
federating: state => state.instance.federating
|
||||
federating: state => state.instance.federating,
|
||||
publicTimelineVisible,
|
||||
federatedTimelineVisible,
|
||||
bubbleTimelineVisible,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
>{{ $t("nav.home_timeline") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser">
|
||||
<li v-if="bubbleTimelineVisible">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'bubble-timeline' }"
|
||||
|
@ -32,7 +32,7 @@
|
|||
>{{ $t("nav.bubble_timeline") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser || !privateMode">
|
||||
<li v-if="publicTimelineVisible">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'public-timeline' }"
|
||||
|
@ -48,7 +48,7 @@
|
|||
>{{ $t("nav.public_tl") }}</span>
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="federating && (currentUser || !privateMode)">
|
||||
<li v-if="federatedTimelineVisible">
|
||||
<router-link
|
||||
class="menu-item"
|
||||
:to="{ name: 'public-external-timeline' }"
|
||||
|
|
|
@ -4,6 +4,12 @@ import { library } from '@fortawesome/fontawesome-svg-core'
|
|||
import {
|
||||
faChevronDown
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { mapState } from 'vuex'
|
||||
import {
|
||||
publicTimelineVisible,
|
||||
federatedTimelineVisible,
|
||||
bubbleTimelineVisible,
|
||||
} from '../../lib/timeline_visibility'
|
||||
|
||||
library.add(faChevronDown)
|
||||
|
||||
|
@ -36,12 +42,15 @@ const TimelineMenuTabs = {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser () {
|
||||
return this.$store.state.users.currentUser
|
||||
},
|
||||
privateMode () {
|
||||
return this.$store.state.instance.private
|
||||
}
|
||||
},
|
||||
...mapState({
|
||||
currentUser: state => state.users.currentUser,
|
||||
publicTimelineVisible,
|
||||
federatedTimelineVisible,
|
||||
bubbleTimelineVisible,
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
timelineName () {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<router-link
|
||||
:to="{ name: 'public-timeline' }"
|
||||
class="nav-icon"
|
||||
v-if="publicTimelineVisible"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
|
@ -27,7 +28,7 @@
|
|||
/>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="currentUser"
|
||||
v-if="bubbleTimelineVisible"
|
||||
:to="{ name: 'bubble-timeline' }"
|
||||
class="nav-icon"
|
||||
>
|
||||
|
@ -41,6 +42,7 @@
|
|||
<router-link
|
||||
:to="{ name: 'public-external-timeline' }"
|
||||
class="nav-icon"
|
||||
v-if="federatedTimelineVisible"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
--_avatarShadowBox: var(--avatarStatusShadow);
|
||||
--_avatarShadowFilter: var(--avatarStatusShadowFilter);
|
||||
--_avatarShadowInset: var(--avatarStatusShadowInset);
|
||||
--_still-image-label-visibility: hidden;
|
||||
// --_still-image-label-visibility: hidden;
|
||||
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
.user-card {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
z-index: 10;
|
||||
|
||||
&:hover {
|
||||
--_still-image-img-visibility: visible;
|
||||
|
@ -235,7 +235,7 @@
|
|||
line-height: 22px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.following, .requested_by {
|
||||
.following, .requested_by, .blocking {
|
||||
flex: 1 0 auto;
|
||||
margin: 0;
|
||||
margin-bottom: .25em;
|
||||
|
|
|
@ -67,6 +67,17 @@
|
|||
icon="external-link-alt"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
v-if="isOtherUser"
|
||||
:href="user.statusnet_profile_url + '.rss'"
|
||||
target="_blank"
|
||||
class="button-unstyled external-link-button"
|
||||
>
|
||||
<FAIcon
|
||||
class="icon"
|
||||
icon="rss"
|
||||
/>
|
||||
</a>
|
||||
<AccountActions
|
||||
v-if="isOtherUser && loggedIn"
|
||||
:user="user"
|
||||
|
@ -116,6 +127,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="user-meta">
|
||||
<div
|
||||
v-if="relationship.blocked_by && loggedIn && isOtherUser"
|
||||
class="blocking"
|
||||
>
|
||||
{{ $t('user_card.blocks_you') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="relationship.followed_by && loggedIn && isOtherUser"
|
||||
class="following"
|
||||
|
@ -176,6 +193,7 @@
|
|||
<FollowButton
|
||||
:relationship="relationship"
|
||||
:user="user"
|
||||
:disabled="relationship.blocked_by"
|
||||
/>
|
||||
<template v-if="relationship.following">
|
||||
<ProgressButton
|
||||
|
|
|
@ -10,11 +10,14 @@ import withLoadMore from '../../hocs/with_load_more/with_load_more'
|
|||
import { debounce } from 'lodash'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faCircleNotch
|
||||
faCircleNotch,
|
||||
faCircleCheck
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import FollowedTagCard from '../followed_tag_card/FollowedTagCard.vue'
|
||||
|
||||
library.add(
|
||||
faCircleNotch
|
||||
faCircleNotch,
|
||||
faCircleCheck
|
||||
)
|
||||
|
||||
const FollowerList = withLoadMore({
|
||||
|
@ -33,6 +36,14 @@ const FriendList = withLoadMore({
|
|||
additionalPropNames: ['userId']
|
||||
})(List)
|
||||
|
||||
const FollowedTagList = withLoadMore({
|
||||
fetch: (props, $store) => $store.dispatch('fetchFollowedTags', props.userId),
|
||||
select: (props, $store) => get($store.getters.findUser(props.userId), 'followedTagIds', []).map(id => $store.getters.findTag(id)),
|
||||
destroy: (props, $store) => $store.dispatch('clearFollowedTags', props.userId),
|
||||
childPropName: 'items',
|
||||
additionalPropNames: ['userId']
|
||||
})(List)
|
||||
|
||||
const isUserPage = ({ name }) => name === 'user-profile' || name === 'external-user-profile'
|
||||
|
||||
const UserProfile = {
|
||||
|
@ -41,6 +52,7 @@ const UserProfile = {
|
|||
error: false,
|
||||
userId: null,
|
||||
tab: 'statuses',
|
||||
followsTab: 'users',
|
||||
footerRef: null,
|
||||
note: null,
|
||||
noteLoading: false
|
||||
|
@ -165,6 +177,9 @@ const UserProfile = {
|
|||
this.tab = tab
|
||||
this.$router.replace({ hash: `#${tab}` })
|
||||
},
|
||||
onFollowsTabSwitch (tab) {
|
||||
this.followsTab = tab
|
||||
},
|
||||
linkClicked ({ target }) {
|
||||
if (target.tagName === 'SPAN') {
|
||||
target = target.parentNode
|
||||
|
@ -200,6 +215,7 @@ const UserProfile = {
|
|||
}
|
||||
},
|
||||
components: {
|
||||
FollowedTagCard,
|
||||
UserCard,
|
||||
Timeline,
|
||||
FollowerList,
|
||||
|
@ -207,7 +223,8 @@ const UserProfile = {
|
|||
FollowCard,
|
||||
TabSwitcher,
|
||||
Conversation,
|
||||
RichContent
|
||||
RichContent,
|
||||
FollowedTagList
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,15 @@
|
|||
:html="field.value"
|
||||
:emoji="user.emoji"
|
||||
/>
|
||||
<span
|
||||
v-if="field.verified_at"
|
||||
class="user-profile-field-validated"
|
||||
>
|
||||
<FAIcon
|
||||
icon="check-circle"
|
||||
:title="$t('user_profile.field_validated')"
|
||||
/>
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
@ -95,22 +104,48 @@
|
|||
v-if="followsTabVisible"
|
||||
key="followees"
|
||||
:label="$t('user_card.followees')"
|
||||
:disabled="!user.friends_count"
|
||||
>
|
||||
<FriendList :user-id="userId">
|
||||
<template v-slot:item="{item}">
|
||||
<FollowCard :user="item" />
|
||||
</template>
|
||||
</FriendList>
|
||||
<tab-switcher
|
||||
:active-tab="followsTab"
|
||||
:render-only-focused="true"
|
||||
:on-switch="onFollowsTabSwitch"
|
||||
>
|
||||
<div
|
||||
key="users"
|
||||
:label="$t('user_card.followed_users')"
|
||||
>
|
||||
<FriendList :user-id="userId">
|
||||
<template #item="{item}">
|
||||
<FollowCard :user="item" />
|
||||
</template>
|
||||
</FriendList>
|
||||
</div>
|
||||
<div
|
||||
key="tags"
|
||||
v-if="isUs"
|
||||
:label="$t('user_card.followed_tags')"
|
||||
>
|
||||
<FollowedTagList
|
||||
:user-id="userId"
|
||||
:get-key="(item) => item.name"
|
||||
>
|
||||
<template #item="{item}">
|
||||
<FollowedTagCard :tag="item" />
|
||||
</template>
|
||||
<template #empty>
|
||||
{{ $t('user_card.not_following_any_hashtags')}}
|
||||
</template>
|
||||
</FollowedTagList>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
<div
|
||||
v-if="followersTabVisible"
|
||||
key="followers"
|
||||
:label="$t('user_card.followers')"
|
||||
:disabled="!user.followers_count"
|
||||
>
|
||||
<FollowerList :user-id="userId">
|
||||
<template v-slot:item="{item}">
|
||||
<template #item="{item}">
|
||||
<FollowCard
|
||||
:user="item"
|
||||
:no-follows-you="isUs"
|
||||
|
@ -225,6 +260,11 @@
|
|||
padding: 0.5em 1.5em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.user-profile-field-validated {
|
||||
margin-left: 1rem;
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,13 @@ import * as bodyScrollLock from 'body-scroll-lock'
|
|||
let previousNavPaddingRight
|
||||
let previousAppBgWrapperRight
|
||||
const lockerEls = new Set([])
|
||||
const allowedScrollableClasses = ['emoji-tabs-item', 'emoji-item']
|
||||
|
||||
const disableBodyScroll = (el) => {
|
||||
const scrollBarGap = window.innerWidth - document.documentElement.clientWidth
|
||||
bodyScrollLock.disableBodyScroll(el, {
|
||||
reserveScrollBarGap: true
|
||||
reserveScrollBarGap: true,
|
||||
allowTouchMove: el => allowedScrollableClasses.includes(el.parentElement.className),
|
||||
})
|
||||
lockerEls.add(el)
|
||||
setTimeout(() => {
|
||||
|
|
|
@ -59,7 +59,8 @@ const withLoadMore = ({
|
|||
this.loading = false
|
||||
this.bottomedOut = isEmpty(newEntries)
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
this.loading = false
|
||||
this.error = true
|
||||
})
|
||||
|
@ -88,7 +89,7 @@ const withLoadMore = ({
|
|||
const children = this.$slots
|
||||
return (
|
||||
<div class="with-load-more">
|
||||
<WrappedComponent {...props}>
|
||||
<WrappedComponent {...props} >
|
||||
{children}
|
||||
</WrappedComponent>
|
||||
<div class="with-load-more-footer">
|
||||
|
|
149
src/i18n/de.json
149
src/i18n/de.json
|
@ -135,7 +135,7 @@
|
|||
},
|
||||
"scope_in_timeline": {
|
||||
"direct": "Direkt",
|
||||
"local": "Lokal - nur deine eigene Instanz kann diesen Beitrag sehen",
|
||||
"local": "Lokal - nur deine eigene Instanz kann diese Nachricht sehen",
|
||||
"private": "Nur an Folgende",
|
||||
"public": "Öffentlich",
|
||||
"unlisted": "Nicht gelistet"
|
||||
|
@ -252,6 +252,10 @@
|
|||
"hint": "Anmelden um an der Diskussion teilzunehmen",
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"logout_confirm": "Willst du dich wirklich abmelden?",
|
||||
"logout_confirm_accept_button": "Abmelden",
|
||||
"logout_confirm_cancel_button": "Abbrechen",
|
||||
"logout_confirm_title": "Abmelden",
|
||||
"password": "Passwort",
|
||||
"placeholder": "meinbenutzername",
|
||||
"recovery_code": "Wiederherstellungscode",
|
||||
|
@ -264,6 +268,32 @@
|
|||
"next": "Weiter",
|
||||
"previous": "Zurück"
|
||||
},
|
||||
"moderation": {
|
||||
"moderation": "Moderation",
|
||||
"reports": {
|
||||
"add_note": "Notiz hinzufügen",
|
||||
"close": "Schließen",
|
||||
"delete_note": "Löschen",
|
||||
"delete_note_accept": "Ja, löschen",
|
||||
"delete_note_cancel": "Nein, behalten",
|
||||
"delete_note_confirm": "Soll diese Notiz wirklich gelöscht werden?",
|
||||
"delete_note_title": "Löschen bestätigen",
|
||||
"no_content": "Keine Beschreibung angegeben",
|
||||
"no_reports": "Keine Meldungen verfügbar",
|
||||
"note_placeholder": "Hinterlasse eine Notiz",
|
||||
"notes": "{ count } Notiz | { count } Notizen",
|
||||
"reopen": "Wieder öffnen",
|
||||
"report": "Meldung über",
|
||||
"reports": "Meldungen",
|
||||
"resolve": "Lösen",
|
||||
"show_closed": "Geschlossene anzeigen",
|
||||
"statuses": "{ count } Post| { count } Posts",
|
||||
"tag_policy_notice": "Schalte die TagPolicy-MRF ein, um Post-Beschränkungen einzustellen",
|
||||
"tags": "Post-Einschränkungen einstellen"
|
||||
},
|
||||
"statuses": "Posts",
|
||||
"users": "Benutzer"
|
||||
},
|
||||
"nav": {
|
||||
"about": "Über",
|
||||
"administration": "Administration",
|
||||
|
@ -278,6 +308,7 @@
|
|||
"interactions": "Interaktionen",
|
||||
"lists": "Listen",
|
||||
"mentions": "Erwähnungen",
|
||||
"moderation": "Moderation",
|
||||
"preferences": "Voreinstellungen",
|
||||
"public_timeline_description": "Öffentliche Beiträge von dieser Instanz",
|
||||
"public_tl": "Öffentliche Zeitleiste",
|
||||
|
@ -345,10 +376,10 @@
|
|||
},
|
||||
"content_warning": "Inhaltswarnung (optional)",
|
||||
"default": "Sitze gerade im Hofbräuhaus",
|
||||
"direct_warning_to_all": "Dieser Beitrag wird für alle erwähnten Benutzer sichtbar sein.",
|
||||
"direct_warning_to_first_only": "Dieser Beitrag wird für alle Benutzer, die am Anfang der Nachricht erwähnt wurden, sichtbar sein.",
|
||||
"direct_warning_to_all": "Diese Nachricht wird für alle erwähnten Benutzer sichtbar sein.",
|
||||
"direct_warning_to_first_only": "Diese Nachricht wird für alle Benutzer, die am Anfang der Nachricht erwähnt wurden, sichtbar sein.",
|
||||
"edit_remote_warning": "Änderungen könnten auf manchen Instanzen nicht sichtbar sein!",
|
||||
"edit_status": "Beitrag ändern",
|
||||
"edit_status": "Nachricht bearbeiten",
|
||||
"edit_unsupported_warning": "Umfragen und Erwähnungen werden durch die Bearbeitung nicht geändert.",
|
||||
"empty_status_error": "Eine Nachricht ohne Text und ohne Anhänge kann nicht gesendet werden",
|
||||
"media_description": "Medienbeschreibung",
|
||||
|
@ -360,20 +391,22 @@
|
|||
"preview": "Vorschau",
|
||||
"preview_empty": "Leer",
|
||||
"scope": {
|
||||
"direct": "Direkt - Beitrag nur an erwähnte Profile",
|
||||
"local": "Lokal - diesen Beitrag nicht föderieren",
|
||||
"private": "Nur Follower - Beitrag nur für Follower sichtbar",
|
||||
"public": "Öffentlich - Beitrag an öffentliche Zeitleisten",
|
||||
"direct": "Direkt - Nachricht nur an erwähnte Profile",
|
||||
"local": "Lokal - diese Nachricht nicht föderieren",
|
||||
"private": "Nur Follower - Nachricht nur für Follower sichtbar",
|
||||
"public": "Öffentlich - Nachricht an öffentliche Zeitleisten",
|
||||
"unlisted": "Nicht gelistet - Nicht in öffentlichen Zeitleisten anzeigen"
|
||||
},
|
||||
"scope_notice": {
|
||||
"local": "Dieser Bericht ist auf anderen Instanzen nicht sichbar",
|
||||
"private": "Dieser Beitrag wird nur für deine Follower sichtbar sein",
|
||||
"public": "Dieser Beitrag wird für alle sichtbar sein",
|
||||
"unlisted": "Dieser Beitrag wird weder in der öffentlichen Zeitleiste noch im gesamten bekannten Netzwerk sichtbar sein"
|
||||
"private": "Diese Nachricht wird nur für deine Follower sichtbar sein",
|
||||
"public": "Diese Nachricht wird für alle sichtbar sein",
|
||||
"unlisted": "Diese Nachricht wird weder in der öffentlichen Zeitleiste noch im gesamten bekannten Netzwerk sichtbar sein"
|
||||
}
|
||||
},
|
||||
"registration": {
|
||||
"awaiting_email_confirmation": "Dein Account wurde registriert und eine E-Mail wurde an deine Adresse gesendet. Bitte lies die E-Mail, um die Registrierung abzuschließen.",
|
||||
"awaiting_email_confirmation_title": "Warte auf E-Mail-Bestätigung",
|
||||
"bio": "Bio",
|
||||
"bio_placeholder": "z. B.\nHallo! Willkommen auf meinem Profil.\nIch mag Anime und Spiele. Hoffentlich können wir Freunde sein!",
|
||||
"captcha": "CAPTCHA",
|
||||
|
@ -387,6 +420,8 @@
|
|||
"reason_placeholder": "Diese Instanz bestätigt Registrierungen manuell. \nLass die Admins wissen warum du dich registrieren willst.",
|
||||
"register": "Registrierung",
|
||||
"registration": "Registrierung",
|
||||
"request_sent": "Deine Bitte zur Registrierung wurde weitergeleitet. Du erhälst eine E-Mail, wenn deiner Registrierung zugestimmt wurde.",
|
||||
"request_sent_title": "Bitte zur Registrierung gesendet",
|
||||
"token": "Einladungsschlüssel",
|
||||
"username_placeholder": "z. B. akko",
|
||||
"validations": {
|
||||
|
@ -465,10 +500,10 @@
|
|||
"confirm_dialogs": "Bestätigung erforderlich für:",
|
||||
"confirm_dialogs_approve_follow": "Annehmen einer Followanfrage",
|
||||
"confirm_dialogs_block": "Jemanden blockieren",
|
||||
"confirm_dialogs_delete": "Löschen eines Beitrages",
|
||||
"confirm_dialogs_delete": "Löschen einer Nachricht",
|
||||
"confirm_dialogs_deny_follow": "Ablehnen einer Followanfrage",
|
||||
"confirm_dialogs_mute": "Jemanden stummschalten",
|
||||
"confirm_dialogs_repeat": "Wiederholen eines Beitrages",
|
||||
"confirm_dialogs_repeat": "Wiederholen einer Nachricht",
|
||||
"confirm_dialogs_unfollow": "Folgen beenden",
|
||||
"confirm_new_password": "Neues Passwort bestätigen",
|
||||
"confirmation_dialogs": "Bestätigungs-Einstellungen",
|
||||
|
@ -496,6 +531,8 @@
|
|||
"enable_web_push_notifications": "Web-Pushbenachrichtigungen aktivieren",
|
||||
"enter_current_password_to_confirm": "Gib dein aktuelles Passwort ein, um deine Identität zu bestätigen",
|
||||
"expert_mode": "Erweiterte Einstellungen anzeigen",
|
||||
"expire_posts_enabled": "Posts löschen, die älter als eine Anzahl an Tagen sind",
|
||||
"expire_posts_input_placeholder": "Anzahl an Tagen",
|
||||
"export_theme": "Farbschema speichern",
|
||||
"file_export_import": {
|
||||
"backup_restore": "Einstellungen backuppen",
|
||||
|
@ -535,7 +572,7 @@
|
|||
"hide_media_previews": "Verstecke Vorschau von Medien",
|
||||
"hide_muted_posts": "Verberge Beiträge stummgeschalteter Nutzer",
|
||||
"hide_muted_threads": "Stummgeschaltete Unterhaltungen ausblenden",
|
||||
"hide_post_stats": "Beitragsstatistiken verbergen (z.B. die Anzahl der Favoriten)",
|
||||
"hide_post_stats": "Nachrichtenstatistiken verbergen (z.B. die Anzahl der Favoriten)",
|
||||
"hide_shoutbox": "Shoutbox der Instanz verbergen",
|
||||
"hide_site_favicon": "Favicon der Instanz im Top-Panel nicht anzeigen",
|
||||
"hide_site_name": "Instanznamen im Top-Panel nicht anzeigen",
|
||||
|
@ -562,7 +599,7 @@
|
|||
"loop_video_silent_only": "Nur Videos ohne Ton wiederholen (z.B. Mastodons \"gifs\")",
|
||||
"mascot": "Mastodon-FE-Maskottchen",
|
||||
"max_depth_in_thread": "Maximale Tiefe, bis zu der Unterhaltungen standardmäßig angezeigt werden",
|
||||
"max_thumbnails": "Maximale Anzahl von Vorschaubildern pro Beitrag",
|
||||
"max_thumbnails": "Maximale Anzahl von Vorschaubildern pro Nachricht (leer = keine Beschränkung)",
|
||||
"mention_link_bolden_you": "eigene Erwähnungen hervorheben",
|
||||
"mention_link_display": "Erwähungs-Links anzeigen",
|
||||
"mention_link_display_full": "immer als vollständige Namen (z. B. {'@'}foo{'@'}example.org)",
|
||||
|
@ -638,7 +675,7 @@
|
|||
"panelRadius": "Panel",
|
||||
"pause_on_unfocused": "Streaming pausieren, wenn das Tab nicht fokussiert ist",
|
||||
"play_videos_in_modal": "Videos in größerem Medienfenster abspielen",
|
||||
"post_status_content_type": "Standard-Beitragsart",
|
||||
"post_status_content_type": "Standard-Format für Nachrichten",
|
||||
"posts": "Beiträge",
|
||||
"preload_images": "Bilder vorausladen",
|
||||
"presets": "Voreinstellungen",
|
||||
|
@ -656,7 +693,7 @@
|
|||
"remove_alias": "Dieses Pseudonym entfernen",
|
||||
"remove_backup": "Entfernen",
|
||||
"render_mfm": "Misskey-Markdown darstellen",
|
||||
"render_mfm_on_hover": "MFM-Animationen pausieren, solange sich der Mauszeiger nicht über dem Beitrag befindet",
|
||||
"render_mfm_on_hover": "MFM-Animationen pausieren, solange sich der Mauszeiger nicht über der Nachricht befindet",
|
||||
"replies_in_timeline": "Antworten in der Zeitleiste",
|
||||
"reply_visibility_all": "Alle Antworten zeigen",
|
||||
"reply_visibility_following": "Zeige nur Antworten an mich oder an Benutzer, denen ich folge",
|
||||
|
@ -680,7 +717,7 @@
|
|||
"security": "Sicherheit",
|
||||
"security_tab": "Sicherheit",
|
||||
"sensitive_by_default": "Alle Beiträge standardmäßig als heikel markieren",
|
||||
"sensitive_if_subject": "Bilder automatisch als heikel markieren, wenn der Beitrag eine Inhaltswarnung hat",
|
||||
"sensitive_if_subject": "Bilder automatisch als heikel markieren, wenn die Nachricht eine Inhaltswarnung hat",
|
||||
"set_new_avatar": "Setze einen neuen Avatar",
|
||||
"set_new_mascot": "Neues Maskottchen einstellen",
|
||||
"set_new_profile_background": "Setze einen neuen Hintergrund für dein Profil",
|
||||
|
@ -688,6 +725,19 @@
|
|||
"setting_changed": "Einstellungen weichen von den Standardeinstellungen ab",
|
||||
"setting_server_side": "Diese Einstellung hängt an deinem Profil und gilt für alle Sitzungen und Clients",
|
||||
"settings": "Einstellungen",
|
||||
"settings_profile": "Einstellungs-Profile",
|
||||
"settings_profile_creation": "Neues Profil erstellen",
|
||||
"settings_profile_creation_new_name_label": "Name",
|
||||
"settings_profile_creation_submit": "Erstellen",
|
||||
"settings_profile_currently": "Benutze Profil {name} (version: {version})",
|
||||
"settings_profile_delete": "Löschen",
|
||||
"settings_profile_delete_confirm": "Dieses Profil wirklich löschen?",
|
||||
"settings_profile_force_sync": "Synchronisieren",
|
||||
"settings_profile_in_use": "In Benutzung",
|
||||
"settings_profile_use": "Verwenden",
|
||||
"settings_profiles_refresh": "Einstellungs-Profile neu laden",
|
||||
"settings_profiles_show": "Alle Einstellungs-Profile anzeigen",
|
||||
"settings_profiles_unshow": "Alle Einstellungs-Profile verbergen",
|
||||
"show_admin_badge": "Zeige Admin-Abzeichen auf meinem Profil",
|
||||
"show_moderator_badge": "Zeige Moderator-Abzeichen auf meinem Profil",
|
||||
"show_nav_shortcuts": "Zusätzliche Schnellnavigation im Top-Panel anzeigen",
|
||||
|
@ -758,8 +808,8 @@
|
|||
"components": {
|
||||
"input": "Eingabefelder",
|
||||
"interface": "Oberfläche",
|
||||
"post": "Beitragstext",
|
||||
"postCode": "Dicktengleicher Text in einem Beitrag (Rich-Text)"
|
||||
"post": "Nachrichtentext",
|
||||
"postCode": "nichtproportionaler Text in einer Nachricht (Rich-Text)"
|
||||
},
|
||||
"custom": "Benutzerdefiniert",
|
||||
"family": "Schriftname",
|
||||
|
@ -790,7 +840,7 @@
|
|||
"component": "Komponente",
|
||||
"components": {
|
||||
"avatar": "Benutzer-Avatar (in der Profilansicht)",
|
||||
"avatarStatus": "Benutzer-Avatar (in der Beitragsanzeige)",
|
||||
"avatarStatus": "Benutzer-Avatar (in der Nachrichtenanzeige)",
|
||||
"button": "Schaltfläche",
|
||||
"buttonHover": "Schaltfläche (hover)",
|
||||
"buttonPressed": "Schaltfläche (gedrückt)",
|
||||
|
@ -861,12 +911,13 @@
|
|||
"tooltipRadius": "Tooltips/Warnungen",
|
||||
"translation_language": "Sprache für automatische Übersetzungen",
|
||||
"tree_advanced": "Weitere Knöpfe zum Öffnen und Schließen von Antworten anzeigen",
|
||||
"tree_fade_ancestors": "Vorgänger des aktuellen Beitrags schwach darstellen",
|
||||
"tree_fade_ancestors": "Vorgänger der aktuellen Nachricht schwach darstellen",
|
||||
"type_domains_to_mute": "Tippe die Domains ein, die du stummschalten willst",
|
||||
"upload_a_photo": "Lade ein Foto hoch",
|
||||
"useStreamingApi": "Empfange Posts und Benachrichtigungen in Echtzeit",
|
||||
"useStreamingApiWarning": "(Nicht empfohlen, experimentell, bekannt dafür, Posts zu überspringen)",
|
||||
"use_at_icon": "{'@'}-Symbol als Icon und nicht als Text anzeigen",
|
||||
"use_blurhash": "Blurhash für NSFW-Vorschauen verwenden",
|
||||
"use_contain_fit": "Vorschaubilder nicht zuschneiden",
|
||||
"use_one_click_nsfw": "Heikle Anhänge mit nur einem Klick öffnen",
|
||||
"user_mutes": "User",
|
||||
|
@ -887,15 +938,21 @@
|
|||
"word_filter": "Wortfilter",
|
||||
"wordfilter": "Wortfilter"
|
||||
},
|
||||
"settings_profile": {
|
||||
"creating": "Erstelle ein neues Einstellungs-Profil \"{profile}\"...",
|
||||
"synchronization_error": "Konnte Einstellungen nicht synchronisieren: {err}",
|
||||
"synchronized": "Einstellungen synchronisiert!",
|
||||
"synchronizing": "Synchronisiere Einstellungs-Profil \"{profile}\"..."
|
||||
},
|
||||
"status": {
|
||||
"ancestor_follow": "Zeige {numReplies} andere Antwort unter diesem Beitrag | Zeige {numReplies} andere Antworten unter diesem Beitrag",
|
||||
"ancestor_follow": "Zeige {numReplies} andere Antwort unter dieser Nachricht | Zeige {numReplies} andere Antworten unter dieser Nachricht",
|
||||
"ancestor_follow_with_icon": "{icon} {text}",
|
||||
"attachment_stop_flash": "Flash-Player stoppen",
|
||||
"bookmark": "Lesezeichen setzen",
|
||||
"collapse_attachments": "Anhänge einklappen",
|
||||
"copy_link": "Beitragslink kopieren",
|
||||
"delete": "Lösche Beitrag",
|
||||
"delete_confirm": "Möchtest du diese Beitrag wirklich löschen?",
|
||||
"copy_link": "Link zur Nachricht kopieren",
|
||||
"delete": "Lösche Nachricht",
|
||||
"delete_confirm": "Möchtest du diese Nachricht wirklich löschen?",
|
||||
"delete_confirm_accept_button": "Ja, löschen",
|
||||
"delete_confirm_cancel_button": "Nein, behalten",
|
||||
"delete_confirm_title": "Löschen bestätigen",
|
||||
|
@ -909,7 +966,7 @@
|
|||
"hide_attachment": "Anhänge verbergen",
|
||||
"hide_content": "Inhalt verbergen",
|
||||
"hide_full_subject": "Vollständige Inhaltswarnung verbergen",
|
||||
"many_attachments": "Beitrag hat {number} Anhang | Beitrag hat {number} Anhänge",
|
||||
"many_attachments": "Nachricht hat {number} Anhang | Nachricht hat {number} Anhänge",
|
||||
"mentions": "Erwähnungen",
|
||||
"move_down": "Anhang nach rechts verschieben",
|
||||
"move_up": "Anhang nach links verschieben",
|
||||
|
@ -920,8 +977,13 @@
|
|||
"pin": "An Profil anheften",
|
||||
"pinned": "Angeheftet",
|
||||
"plus_more": "+{number} mehr",
|
||||
"redraft": "Löschen & neu erstellen",
|
||||
"redraft_confirm": "Diesen Post wirklich löschen und neu erstellen? Interaktionen des ursprünglichen Posts werden nicht erhalten.",
|
||||
"redraft_confirm_accept_button": "Ja, löschen und neu erstellen",
|
||||
"redraft_confirm_cancel_button": "Nein, das Original behalten",
|
||||
"redraft_confirm_title": "Löschen und neu erstellen bestätigen",
|
||||
"remove_attachment": "Anhang entfernen",
|
||||
"repeat_confirm": "Beitrag wirklich wiederholen?",
|
||||
"repeat_confirm": "Nachricht wirklich wiederholen?",
|
||||
"repeat_confirm_accept_button": "Ja, wiederholen",
|
||||
"repeat_confirm_cancel_button": "Nein, nicht wiederholen",
|
||||
"repeat_confirm_title": "Wiederholen bestätigen",
|
||||
|
@ -930,15 +992,15 @@
|
|||
"replies_list_with_others": "Zeige noch {numReplies} Antwort | Zeige noch {numReplies} Antworten",
|
||||
"reply_to": "Antworten auf",
|
||||
"show_all_attachments": "Alle Anhänge anzeigen",
|
||||
"show_all_conversation": "Ganzes Gespräch anzeigen (noch {numStatus} Beitrag) | Ganzes Gespräch anzeigen (noch {numStatus} Beiträge)",
|
||||
"show_all_conversation": "Ganzes Gespräch anzeigen (noch {numStatus} Nachricht) | Ganzes Gespräch anzeigen (noch {numStatus} Nachrichten)",
|
||||
"show_all_conversation_with_icon": "{icon} {text}",
|
||||
"show_attachment_description": "Vorschau-Beschreibung (Anhang öffnen für vollständige Beschreibung)",
|
||||
"show_attachment_in_modal": "Anhang in einem Fenster anzeigen",
|
||||
"show_content": "Inhalt anzeigen",
|
||||
"show_full_subject": "Vollständige Inhaltswarnung anzeigen",
|
||||
"show_only_conversation_under_this": "Nur Antworten auf diesen Bericht anzeigen",
|
||||
"status_deleted": "Dieser Beitrag wurde gelöscht",
|
||||
"status_unavailable": "Beitrag nicht verfügbar",
|
||||
"status_deleted": "Diese Nachricht wurde gelöscht",
|
||||
"status_unavailable": "Nachricht nicht verfügbar",
|
||||
"thread_follow": "Zeige noch {numStatus} Antwort | Zeige noch {numStatus} Antworten",
|
||||
"thread_follow_with_icon": "{icon} {text}",
|
||||
"thread_hide": "Diese Unterhaltung stummschalten",
|
||||
|
@ -948,6 +1010,7 @@
|
|||
"thread_show_full": "Zeige {numStatus} Antwort | Zeige {numStatus} Antworten",
|
||||
"thread_show_full_with_icon": "{icon} {text}",
|
||||
"translate": "Übersetzen",
|
||||
"translated_from": "Übersetzt von {language}",
|
||||
"unbookmark": "Lesezeichen entfernen",
|
||||
"unmute_conversation": "Konversation nicht mehr stummstellen",
|
||||
"unpin": "Nicht mehr an Profil anheften",
|
||||
|
@ -979,17 +1042,22 @@
|
|||
"collapse": "Einklappen",
|
||||
"conversation": "Unterhaltung",
|
||||
"error": "Fehler beim Lesen der Timeline: {0}",
|
||||
"load_older": "Lade ältere Beiträge",
|
||||
"no_more_statuses": "Keine weiteren Beiträge",
|
||||
"no_retweet_hint": "Der Beitrag ist als nur-für-Follower oder Direktnachricht markiert und kann nicht wiederholt oder zitiert werden",
|
||||
"no_statuses": "Keine Beiträge",
|
||||
"follow_tag": "Hashtag folgen",
|
||||
"load_older": "Lade ältere Nachrichten",
|
||||
"no_more_statuses": "Keine weiteren Nachrichten",
|
||||
"no_retweet_hint": "Die Nachricht ist als nur-für-Follower oder Direktnachricht markiert und kann nicht wiederholt oder zitiert werden",
|
||||
"no_statuses": "Keine Nachrichten",
|
||||
"reload": "Neu laden",
|
||||
"repeated": "wiederholte",
|
||||
"show_new": "Zeige Neuere",
|
||||
"socket_broke": "Netzverbindung verloren: CloseEvent code {0}",
|
||||
"socket_reconnected": "Netzverbindung hergestellt",
|
||||
"unfollow_tag": "Hashtag entfolgen",
|
||||
"up_to_date": "Aktuell"
|
||||
},
|
||||
"toast": {
|
||||
"no_translation_target_set": "Keine Zielsprache für Übersetzungen eingestellt - das könnte schiefgehen. Bitte stell eine Zielsprache in deinen Einstellungen ein."
|
||||
},
|
||||
"tool_tip": {
|
||||
"accept_follow_request": "Folgeanfrage annehmen",
|
||||
"add_reaction": "Emoji-Reaktion hinzufügen",
|
||||
|
@ -1049,6 +1117,7 @@
|
|||
"block_confirm_title": "Benutzer blockieren",
|
||||
"block_progress": "Blocken…",
|
||||
"blocked": "Blockiert!",
|
||||
"blocks_you": "Blockt dich!",
|
||||
"bot": "Bot",
|
||||
"deactivated": "Deaktiviert",
|
||||
"deny": "Ablehnen",
|
||||
|
@ -1063,7 +1132,10 @@
|
|||
"follow_cancel": "Anfrage ablehnen",
|
||||
"follow_progress": "Anfragen…",
|
||||
"follow_sent": "Anfrage gesendet!",
|
||||
"follow_tag": "Hashtag folgen",
|
||||
"follow_unfollow": "Folgen beenden",
|
||||
"followed_tags": "Gefolgte Hashtags",
|
||||
"followed_users": "Gefolgte Benutzer",
|
||||
"followees": "Folgt",
|
||||
"followers": "Folgende",
|
||||
"following": "Folgst du!",
|
||||
|
@ -1088,13 +1160,16 @@
|
|||
"mute_domain": "Domain blockieren",
|
||||
"mute_progress": "Stummschalten erfolgt…",
|
||||
"muted": "Stummgeschaltet",
|
||||
"not_following_any_hashtags": "Du folgst keinen Hashtags",
|
||||
"note": "Private Notiz",
|
||||
"per_day": "pro Tag",
|
||||
"remote_follow": "Folgen",
|
||||
"remove_follower": "Nicht mehr folgen",
|
||||
"replies": "Mit Antworten",
|
||||
"report": "Melden",
|
||||
"requested_by": "Möchte dir gern folgen",
|
||||
"show_repeats": "Geteilte Beiträge anzeigen",
|
||||
"statuses": "Beiträge",
|
||||
"statuses": "Nachrichten",
|
||||
"subscribe": "Folgen",
|
||||
"unblock": "Entblocken",
|
||||
"unblock_progress": "Entblocken…",
|
||||
|
@ -1102,11 +1177,13 @@
|
|||
"unfollow_confirm_accept_button": "Ja, nicht mehr folgen",
|
||||
"unfollow_confirm_cancel_button": "Nein, weiter folgen",
|
||||
"unfollow_confirm_title": "Benutzer nicht mehr folgen",
|
||||
"unfollow_tag": "Hashtag nicht mehr folgen",
|
||||
"unmute": "Stummschalten aufheben",
|
||||
"unmute_progress": "Aufhebung erfolgt…",
|
||||
"unsubscribe": "Entfolgen"
|
||||
},
|
||||
"user_profile": {
|
||||
"field_validated": "Link verifiziert",
|
||||
"profile_does_not_exist": "Profil nicht vorhanden.",
|
||||
"profile_loading_error": "Beim Laden dieses Profils ist ein Fehler aufgetreten.",
|
||||
"timeline_title": "Beiträge"
|
||||
|
|
215
src/i18n/el.json
Normal file
215
src/i18n/el.json
Normal file
|
@ -0,0 +1,215 @@
|
|||
{
|
||||
"about": {
|
||||
"mrf": {
|
||||
"keyword": {
|
||||
"keyword_policies": "Πολιτικές λέξεων-κλειδιών",
|
||||
"reject": "Απόρριψη",
|
||||
"replace": "Αντικατάσταση"
|
||||
},
|
||||
"mrf_policies": "Ενεργοποιημένες πολιτικές MRF",
|
||||
"mrf_policies_desc": "",
|
||||
"simple": {
|
||||
"accept": "Αποδοχή",
|
||||
"accept_desc": "Αυτό το instance αποδέχεται μηνύματα μόνο από τα ακόλουθα instances:",
|
||||
"ftl_removal": "Αφαίρεση από το χρονολόγιο \"Γνωστού Δίκτυου\"",
|
||||
"ftl_removal_desc": "Αυτό το instance αφαιρεί αυτά τα instances από το χρονολόγιο \"Γνωστού Δικτύου\":",
|
||||
"quarantine": "Καραντίνα",
|
||||
"quarantine_desc": "Αυτό το instance δε θα στέλνει αναρτήσεις στα ακόλουθα instances:",
|
||||
"reason": "Λόγος",
|
||||
"simple_policies": "Πολιτικές του instance"
|
||||
}
|
||||
}
|
||||
},
|
||||
"announcements": {
|
||||
"all_day_prompt": "Αυτό είναι ένα ολοήμερο συμβάν",
|
||||
"cancel_edit_action": "Ακύρωση",
|
||||
"close_error": "Κλείσιμο",
|
||||
"delete_action": "Διαγραφή",
|
||||
"edit_action": "Επεξεργασία",
|
||||
"end_time_display": "Λήγει στις {time}",
|
||||
"page_header": "Ανακοινώσεις",
|
||||
"title": "Ανακοίνωση"
|
||||
},
|
||||
"chats": {
|
||||
"empty_message_error": "Δε μπορεί να σταλεί κενό μήνυμα",
|
||||
"error_sending_message": "Κάτι πήγε λάθος κατά την αποστολή του μηνύματος.",
|
||||
"message_user": "Στείλε μήνυμα στον/στην {nickname}",
|
||||
"more": "Περισσότερα",
|
||||
"new": "Νέο Chat",
|
||||
"you": "Εσείς:"
|
||||
},
|
||||
"display_date": {
|
||||
"today": "Σήμερα"
|
||||
},
|
||||
"domain_mute_card": {
|
||||
"mute": "Σίγαση"
|
||||
},
|
||||
"emoji": {
|
||||
"add_emoji": "Εισαγωγή emoji",
|
||||
"load_all": "Φόρτωση όλων των {emojiAmount} emoji",
|
||||
"recent": "Χρησιμοποιήθηκαν πρόσφατα",
|
||||
"search_emoji": "Αναζήτηση για ένα emoji",
|
||||
"stickers": "Αυτοκόλλητα"
|
||||
},
|
||||
"errors": {
|
||||
"storage_unavailable": "Το Pleroma δε μπόρεσε να προσπελάσει τον αποθηκευτικό χώρο του browser. Η σύνδεσή σας ή οι τοπικές ρυθμίσεις σας δε θα αποθηκευτούν και μπορεί να αντιμετωπίσετε απρόοπτα θέματα. Προσπαθήστε να ενεργοποιήσετε τα cookies."
|
||||
},
|
||||
"exporter": {
|
||||
"export": "Εξαγωγή"
|
||||
},
|
||||
"features_panel": {
|
||||
"text_limit": "Όριο κειμένου"
|
||||
},
|
||||
"file_type": {
|
||||
"audio": "Ήχος",
|
||||
"file": "Αρχείο",
|
||||
"image": "Εικόνα",
|
||||
"video": "Βίντεο"
|
||||
},
|
||||
"general": {
|
||||
"apply": "Εφαρμογή",
|
||||
"cancel": "Ακύρωση",
|
||||
"close": "Κλείσιμο",
|
||||
"disable": "Απενεργοποίηση",
|
||||
"enable": "Ενεργοποίηση",
|
||||
"error_retry": "Παρακαλώ δοκιμάστε ξανά",
|
||||
"flash_content": "Κάντε κλικ για την εμφάνιση Flash περιεχομένου με τη χρήση του Ruffle (Πειραματικό, μπορεί να μη λειτουργεί).",
|
||||
"loading": "Φόρτωση…",
|
||||
"more": "Περισσότερα",
|
||||
"optional": "προαιρετικό",
|
||||
"retry": "Δοκιμάστε ξανά",
|
||||
"role": {
|
||||
"admin": "Διαχειριστής",
|
||||
"moderator": "Συντονιστής"
|
||||
},
|
||||
"scope_in_timeline": {
|
||||
"direct": "Άμεσο",
|
||||
"local": "Τοπικό",
|
||||
"private": "Μόνο για ακόλουθους",
|
||||
"public": "Δημόσιο",
|
||||
"unlisted": "Εκτός Λίστας"
|
||||
},
|
||||
"show_less": "Δείξε λιγότερα",
|
||||
"show_more": "Δείξε περισσότερα"
|
||||
},
|
||||
"image_cropper": {
|
||||
"cancel": "Ακύρωση",
|
||||
"crop_picture": "Περικοπή εικόνας",
|
||||
"save": "Αποθήκευση",
|
||||
"save_without_cropping": "Αποθήκευση χωρίς περικοπή"
|
||||
},
|
||||
"importer": {
|
||||
"success": "Εισήχθη επιτυχώς."
|
||||
},
|
||||
"languages": {
|
||||
"ar": "Αραβικά",
|
||||
"az": "Αζερικά",
|
||||
"bg": "Βουλγαρικά",
|
||||
"cs": "Τσεχικά",
|
||||
"da": "Δανικά",
|
||||
"de": "Γερμανικά",
|
||||
"el": "Ελληνικά",
|
||||
"en": "Αγγλικά",
|
||||
"eo": "Εσπεράντο",
|
||||
"es": "Ισπανικά",
|
||||
"fa": "Περσικά",
|
||||
"fi": "Φινλανδικά",
|
||||
"fr": "Γαλλικά",
|
||||
"ga": "Ιρλανδικά",
|
||||
"he": "Εβραϊκά",
|
||||
"hi": "Χίντι",
|
||||
"hu": "Ουγγρικά",
|
||||
"id": "Ινδονησιακά",
|
||||
"it": "Ιταλικά",
|
||||
"ja": "Ιαπωνικά",
|
||||
"ko": "Κορεατικά",
|
||||
"lt": "Λιθουανικά",
|
||||
"lv": "Λετονικά",
|
||||
"nl": "Ολλανδικά",
|
||||
"pl": "Πολωνικά",
|
||||
"pt": "Πορτογαλικά",
|
||||
"ru": "Ρωσικά",
|
||||
"sk": "Σλοβακικά",
|
||||
"sv": "Σουηδικά",
|
||||
"tr": "Τουρκικά",
|
||||
"translated_from": {
|
||||
"ar": "Μεταφράστηκε από τα @:languages.ar",
|
||||
"az": "Μεταφράστηκε από τα @:languages.az",
|
||||
"bg": "Μεταφράστηκε από τα @:languages.bg",
|
||||
"cs": "Μεταφράστηκε από τα @:languages.cs",
|
||||
"da": "Μεταφράστηκε από τα @:languages.da",
|
||||
"de": "Μεταφράστηκε από τα @:languages.de",
|
||||
"el": "Μεταφράστηκε από τα @:languages.el",
|
||||
"en": "Μεταφράστηκε από τα @:languages.en",
|
||||
"eo": "Μεταφράστηκε από τα @:languages.eo",
|
||||
"es": "Μεταφράστηκε από τα @:languages.es",
|
||||
"fa": "Μεταφράστηκε από τα @:languages.fa",
|
||||
"fi": "Μεταφράστηκε από τα @:languages.fi",
|
||||
"fr": "Μεταφράστηκε από τα @:languages.fr",
|
||||
"ga": "Μεταφράστηκε από τα @:languages.ga",
|
||||
"he": "Μεταφράστηκε από τα @:languages.he",
|
||||
"hi": "Μεταφράστηκε από τα @:languages.hi",
|
||||
"hu": "Μεταφράστηκε από τα @:languages.hu",
|
||||
"id": "Μεταφράστηκε από τα @:languages.id",
|
||||
"it": "Μεταφράστηκε από τα @:languages.it",
|
||||
"ja": "Μεταφράστηκε από τα @:languages.ja",
|
||||
"ko": "Μεταφράστηκε από τα @:languages.ko",
|
||||
"lt": "Μεταφράστηκε από τα @:languages.lt",
|
||||
"lv": "Μεταφράστηκε από τα @:languages.lv",
|
||||
"nl": "Μεταφράστηκε από τα @:languages.nl",
|
||||
"pl": "Μεταφράστηκε από τα @:languages.pl",
|
||||
"pt": "Μεταφράστηκε από τα @:languages.pt",
|
||||
"ru": "Μεταφράστηκε από τα @:languages.ru",
|
||||
"sk": "Μεταφράστηκε από τα @:languages.sk",
|
||||
"sv": "Μεταφράστηκε από τα @:languages.sv",
|
||||
"tr": "tr",
|
||||
"uk": "Μεταφράστηκε από τα @:languages.uk",
|
||||
"zh": "Μεταφράστηκε από τα @:languages.zh"
|
||||
},
|
||||
"uk": "Ουκρανικά",
|
||||
"zh": "Κινεζικά"
|
||||
},
|
||||
"lists": {
|
||||
"create": "Δημιουργία",
|
||||
"delete": "Διαγραφή λίστας",
|
||||
"lists": "Λίστες",
|
||||
"new": "Νέα Λίστα",
|
||||
"save": "Αποθήκευση αλλαγών",
|
||||
"search": "Αναζήτηση χρηστών",
|
||||
"title": "Τίτλος λίστας"
|
||||
},
|
||||
"login": {
|
||||
"authentication_code": "Κωδικός επαλήθευσης",
|
||||
"description": "Σύνδεση με OAuth",
|
||||
"enter_recovery_code": "Εισάγετε τον κωδικό ανάκτησης",
|
||||
"hint": "Συνδεθείτε για να μπείτε στη συζήτηση",
|
||||
"login": "Σύνδεση",
|
||||
"logout": "Αποσύνδεση",
|
||||
"logout_confirm": "Θέλετε σίγουρα να αποσυνδεθείτε;",
|
||||
"logout_confirm_accept_button": "Αποσύνδεση",
|
||||
"logout_confirm_cancel_button": "Ακύρωση",
|
||||
"logout_confirm_title": "Αποσύνδεση",
|
||||
"password": "Κωδικός πρόσβασης",
|
||||
"placeholder": "τοονομαχρηστημου",
|
||||
"recovery_code": "Κωδικός ανάκτησης",
|
||||
"register": "Εγγραφή",
|
||||
"username": "Όνομα χρήστη"
|
||||
},
|
||||
"media_modal": {
|
||||
"next": "Επόμενο",
|
||||
"previous": "Προηγούμενο"
|
||||
},
|
||||
"moderation": {
|
||||
"reports": {
|
||||
"add_note": "Προσθήκη σημείωσης",
|
||||
"close": "Κλείσιμο",
|
||||
"delete_note": "Διαγραφή",
|
||||
"delete_note_accept": "Ναι, διάγραψέ το",
|
||||
"delete_note_cancel": "Όχι, κράτα το",
|
||||
"delete_note_confirm": "Θέλετε σίγουρα να διαγράψετε αυτήν τη σημείωση;",
|
||||
"note_placeholder": "Αφήστε μια σημείωση",
|
||||
"notes": "{ count } σημείωση | { count } σημειώσεις",
|
||||
"statuses": "{ count } ανάρτηση| { count } αναρτήσεις"
|
||||
}
|
||||
}
|
||||
}
|
156
src/i18n/en.json
156
src/i18n/en.json
|
@ -86,7 +86,8 @@
|
|||
"load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.",
|
||||
"search_emoji": "Search for an emoji",
|
||||
"stickers": "Stickers",
|
||||
"unicode": "Unicode emoji"
|
||||
"unicode": "Unicode emoji",
|
||||
"recent": "Recently used"
|
||||
},
|
||||
"errors": {
|
||||
"storage_unavailable": "Pleroma could not access browser storage. Your login or your local settings won't be saved and you might encounter unexpected issues. Try enabling cookies."
|
||||
|
@ -165,72 +166,72 @@
|
|||
"moves": "User migrates"
|
||||
},
|
||||
"languages": {
|
||||
"bg": "Bulgarian",
|
||||
"en": "English",
|
||||
"ar": "Arabic",
|
||||
"az": "Azerbaijani",
|
||||
"zh": "Chinese",
|
||||
"bg": "Bulgarian",
|
||||
"cs": "Czech",
|
||||
"da": "Danish",
|
||||
"nl": "Dutch",
|
||||
"eo": "Esperanto",
|
||||
"fi": "Finnish",
|
||||
"fr": "French",
|
||||
"de": "German",
|
||||
"el": "Greek",
|
||||
"en": "English",
|
||||
"eo": "Esperanto",
|
||||
"es": "Spanish",
|
||||
"fa": "Persian",
|
||||
"fi": "Finnish",
|
||||
"fr": "French",
|
||||
"ga": "Irish",
|
||||
"he": "Hebrew",
|
||||
"hi": "Hindi",
|
||||
"hu": "Hungarian",
|
||||
"id": "Indonesian",
|
||||
"ga": "Irish",
|
||||
"it": "Italian",
|
||||
"ja": "Japanese",
|
||||
"ko": "Korean",
|
||||
"fa": "Persian",
|
||||
"lt": "Lithuanian",
|
||||
"lv": "Latvian",
|
||||
"nl": "Dutch",
|
||||
"pl": "Polish",
|
||||
"pt": "Portuguese",
|
||||
"ru": "Russian",
|
||||
"sk": "Slovak",
|
||||
"es": "Spanish",
|
||||
"sv": "Swedish",
|
||||
"tr": "Turkish",
|
||||
"uk": "Ukrainian",
|
||||
"lt": "Lithuanian",
|
||||
"lv": "Latvian",
|
||||
"translated_from": {
|
||||
"bg": "Translated from @:languages.bg",
|
||||
"en": "Translated from @:languages.en",
|
||||
"ar": "Translated from @:languages.ar",
|
||||
"az": "Translated from @:languages.az",
|
||||
"zh": "Translated from @:languages.zh",
|
||||
"bg": "Translated from @:languages.bg",
|
||||
"cs": "Translated from @:languages.cs",
|
||||
"da": "Translated from @:languages.da",
|
||||
"nl": "Translated from @:languages.nl",
|
||||
"eo": "Translated from @:languages.eo",
|
||||
"fi": "Translated from @:languages.fi",
|
||||
"fr": "Translated from @:languages.fr",
|
||||
"de": "Translated from @:languages.de",
|
||||
"el": "Translated from @:languages.el",
|
||||
"en": "Translated from @:languages.en",
|
||||
"eo": "Translated from @:languages.eo",
|
||||
"es": "Translated from @:languages.es",
|
||||
"fa": "Translated from @:languages.fa",
|
||||
"fi": "Translated from @:languages.fi",
|
||||
"fr": "Translated from @:languages.fr",
|
||||
"ga": "Translated from @:languages.ga",
|
||||
"he": "Translated from @:languages.he",
|
||||
"hi": "Translated from @:languages.hi",
|
||||
"hu": "Translated from @:languages.hu",
|
||||
"id": "Translated from @:languages.id",
|
||||
"ga": "Translated from @:languages.ga",
|
||||
"it": "Translated from @:languages.it",
|
||||
"ja": "Translated from @:languages.ja",
|
||||
"ko": "Translated from @:languages.ko",
|
||||
"fa": "Translated from @:languages.fa",
|
||||
"lt": "Translated from @:languages.lt",
|
||||
"lv": "Translated from @:languages.lv",
|
||||
"nl": "Translated from @:languages.nl",
|
||||
"pl": "Translated from @:languages.pl",
|
||||
"pt": "Translated from @:languages.pt",
|
||||
"ru": "Translated from @:languages.ru",
|
||||
"sk": "Translated from @:languages.sk",
|
||||
"es": "Translated from @:languages.es",
|
||||
"sv": "Translated from @:languages.sv",
|
||||
"tr": "Translated from @:languages.tr",
|
||||
"uk": "Translated from @:languages.uk",
|
||||
"lt": "Translated from @:languages.lt",
|
||||
"lv": "Translated from @:languages.lv"
|
||||
}
|
||||
"zh": "Translated from @:languages.zh"
|
||||
},
|
||||
"uk": "Ukrainian",
|
||||
"zh": "Chinese"
|
||||
},
|
||||
"lists": {
|
||||
"create": "Create",
|
||||
|
@ -254,15 +255,15 @@
|
|||
"hint": "Log in to join the discussion",
|
||||
"login": "Log in",
|
||||
"logout": "Log out",
|
||||
"logout_confirm": "Are you sure you want to log out?",
|
||||
"logout_confirm_accept_button": "Log out",
|
||||
"logout_confirm_cancel_button": "Cancel",
|
||||
"logout_confirm_title": "Log out",
|
||||
"password": "Password",
|
||||
"placeholder": "myusername",
|
||||
"recovery_code": "Recovery code",
|
||||
"register": "Register",
|
||||
"username": "Username",
|
||||
"logout_confirm_cancel_button": "Cancel",
|
||||
"logout_confirm_accept_button": "Log out",
|
||||
"logout_confirm": "Are you sure you want to log out?",
|
||||
"logout_confirm_title": "Log out"
|
||||
"username": "Username"
|
||||
},
|
||||
"media_modal": {
|
||||
"counter": "{current} / {total}",
|
||||
|
@ -271,30 +272,30 @@
|
|||
"previous": "Previous"
|
||||
},
|
||||
"moderation": {
|
||||
"moderation": "Moderation",
|
||||
"reports": {
|
||||
"no_reports": "No reports to show",
|
||||
"add_note": "Add note",
|
||||
"close": "Close",
|
||||
"delete_note": "Delete",
|
||||
"delete_note_accept": "Yes, delete it",
|
||||
"delete_note_cancel": "No, keep it",
|
||||
"delete_note_confirm": "Are you sure you want to delete this note?",
|
||||
"delete_note_title": "Confirm deletion",
|
||||
"no_content": "No description given",
|
||||
"note_placeholder": "Leave a note...",
|
||||
"notes": "{ count } note | { count } notes",
|
||||
"reopen": "Reopen",
|
||||
"report": "Report on",
|
||||
"reports": "Reports",
|
||||
"resolve": "Resolve",
|
||||
"show_closed": "Show closed",
|
||||
"statuses": "{ count } status | { count } statuses",
|
||||
"tag_policy_notice": "Enable the TagPolicy MRF to set post restrictions",
|
||||
"tags": "Set post restrictions"
|
||||
},
|
||||
"statuses": "Statuses",
|
||||
"users": "Users"
|
||||
"moderation": "Moderation",
|
||||
"reports": {
|
||||
"add_note": "Add note",
|
||||
"close": "Close",
|
||||
"delete_note": "Delete",
|
||||
"delete_note_accept": "Yes, delete it",
|
||||
"delete_note_cancel": "No, keep it",
|
||||
"delete_note_confirm": "Are you sure you want to delete this note?",
|
||||
"delete_note_title": "Confirm deletion",
|
||||
"no_content": "No description given",
|
||||
"no_reports": "No reports to show",
|
||||
"note_placeholder": "Leave a note",
|
||||
"notes": "{ count } note | { count } notes",
|
||||
"reopen": "Reopen",
|
||||
"report": "Report on",
|
||||
"reports": "Reports",
|
||||
"resolve": "Resolve",
|
||||
"show_closed": "Show closed",
|
||||
"statuses": "{ count } post| { count } posts",
|
||||
"tag_policy_notice": "Enable the TagPolicy MRF to set post restrictions",
|
||||
"tags": "Set post restrictions"
|
||||
},
|
||||
"statuses": "Posts",
|
||||
"users": "Users"
|
||||
},
|
||||
"nav": {
|
||||
"about": "About",
|
||||
|
@ -409,8 +410,8 @@
|
|||
}
|
||||
},
|
||||
"registration": {
|
||||
"awaiting_email_confirmation_title": "Awaiting email confirmation",
|
||||
"awaiting_email_confirmation": "Your account has been registered and an email has been sent to your address. Please check the email to complete registration.",
|
||||
"awaiting_email_confirmation_title": "Awaiting email confirmation",
|
||||
"bio": "Bio",
|
||||
"bio_placeholder": "e.g.\nHi! Welcome to my bio.\nI love watching anime and playing games. I hope we can be friends!",
|
||||
"captcha": "CAPTCHA",
|
||||
|
@ -535,6 +536,8 @@
|
|||
"enable_web_push_notifications": "Enable web push notifications",
|
||||
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
|
||||
"expert_mode": "Show advanced",
|
||||
"expire_posts_enabled": "Delete posts after a set amount of days",
|
||||
"expire_posts_input_placeholder": "Number of days",
|
||||
"export_theme": "Save preset",
|
||||
"file_export_import": {
|
||||
"backup_restore": "Settings backup",
|
||||
|
@ -729,18 +732,18 @@
|
|||
"setting_server_side": "This setting is tied to your profile and affects all sessions and clients",
|
||||
"settings": "Settings",
|
||||
"settings_profile": "Settings Profiles",
|
||||
"settings_profile_currently": "Currently using {name} (version: {version})",
|
||||
"settings_profiles_show": "Show all settings profiles",
|
||||
"settings_profiles_unshow": "Hide all settings profiles",
|
||||
"settings_profile_in_use": "In use",
|
||||
"settings_profile_creation": "Create new profile",
|
||||
"settings_profile_creation_submit": "Create",
|
||||
"settings_profile_creation_new_name_label": "Name",
|
||||
"settings_profile_use": "Use",
|
||||
"settings_profile_creation_submit": "Create",
|
||||
"settings_profile_currently": "Currently using {name} (version: {version})",
|
||||
"settings_profile_delete": "Delete",
|
||||
"settings_profile_delete_confirm": "Do you really want to delete this profile?",
|
||||
"settings_profile_force_sync": "Synchronize",
|
||||
"settings_profile_in_use": "In use",
|
||||
"settings_profile_use": "Use",
|
||||
"settings_profiles_refresh": "Reload settings profiles",
|
||||
"settings_profiles_show": "Show all settings profiles",
|
||||
"settings_profiles_unshow": "Hide all settings profiles",
|
||||
"show_admin_badge": "Show \"Admin\" badge in my profile",
|
||||
"show_moderator_badge": "Show \"Moderator\" badge in my profile",
|
||||
"show_nav_shortcuts": "Show extra navigation shortcuts in top panel",
|
||||
|
@ -926,6 +929,10 @@
|
|||
"user_profile_default_tab": "Default Tab on User Profile",
|
||||
"user_profiles": "User Profiles",
|
||||
"user_settings": "User Settings",
|
||||
"user_accepts_direct_messages_from": "Accept DMs From",
|
||||
"user_accepts_direct_messages_from_everybody": "Everybody",
|
||||
"user_accepts_direct_messages_from_nobody": "Nobody",
|
||||
"user_accepts_direct_messages_from_people_i_follow": "People I follow",
|
||||
"valid_until": "Valid until",
|
||||
"values": {
|
||||
"false": "no",
|
||||
|
@ -937,14 +944,15 @@
|
|||
"title": "Version"
|
||||
},
|
||||
"virtual_scrolling": "Optimize timeline rendering",
|
||||
"use_blurhash": "Use blurhashes for NSFW thumbnails",
|
||||
"word_filter": "Word filter",
|
||||
"wordfilter": "Wordfilter"
|
||||
},
|
||||
"settings_profile": {
|
||||
"synchronizing": "Synchronizing setting profile \"{profile}\"...",
|
||||
"synchronized": "Synchronized settings!",
|
||||
"synchronization_error": "Could not synchronize settings: {err}",
|
||||
"creating": "Creating new setting profile \"{profile}\"..."
|
||||
"creating": "Creating new setting profile \"{profile}\"...",
|
||||
"synchronization_error": "Could not synchronize settings: {err}",
|
||||
"synchronized": "Synchronized settings!",
|
||||
"synchronizing": "Synchronizing setting profile \"{profile}\"..."
|
||||
},
|
||||
"status": {
|
||||
"ancestor_follow": "See {numReplies} other reply under this post | See {numReplies} other replies under this post",
|
||||
|
@ -1044,6 +1052,7 @@
|
|||
"collapse": "Collapse",
|
||||
"conversation": "Conversation",
|
||||
"error": "Error fetching timeline: {0}",
|
||||
"follow_tag": "Follow hashtag",
|
||||
"load_older": "Load older posts",
|
||||
"no_more_statuses": "No more posts",
|
||||
"no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated or quoted",
|
||||
|
@ -1053,6 +1062,8 @@
|
|||
"show_new": "Show new",
|
||||
"socket_broke": "Realtime connection lost: CloseEvent code {0}",
|
||||
"socket_reconnected": "Realtime connection established",
|
||||
"follow_tag": "Follow hashtag",
|
||||
"unfollow_tag": "Unfollow hashtag",
|
||||
"up_to_date": "Up-to-date"
|
||||
},
|
||||
"toast": {
|
||||
|
@ -1117,6 +1128,7 @@
|
|||
"block_confirm_title": "Block user",
|
||||
"block_progress": "Blocking…",
|
||||
"blocked": "Blocked!",
|
||||
"blocks_you": "Blocks you!",
|
||||
"bot": "Bot",
|
||||
"deactivated": "Deactivated",
|
||||
"deny": "Deny",
|
||||
|
@ -1134,9 +1146,10 @@
|
|||
"follow_unfollow": "Unfollow",
|
||||
"followees": "Following",
|
||||
"followers": "Followers",
|
||||
"followed_tags": "Followed hashtags",
|
||||
"followed_users": "Followed users",
|
||||
"following": "Following!",
|
||||
"follows_you": "Follows you!",
|
||||
"requested_by": "Has requested to follow you",
|
||||
"hidden": "Hidden",
|
||||
"hide_repeats": "Hide repeats",
|
||||
"highlight": {
|
||||
|
@ -1163,6 +1176,7 @@
|
|||
"remove_follower": "Remove follower",
|
||||
"replies": "With Replies",
|
||||
"report": "Report",
|
||||
"requested_by": "Has requested to follow you",
|
||||
"show_repeats": "Show repeats",
|
||||
"statuses": "Posts",
|
||||
"subscribe": "Subscribe",
|
||||
|
@ -1172,6 +1186,9 @@
|
|||
"unfollow_confirm_accept_button": "Yes, unfollow",
|
||||
"unfollow_confirm_cancel_button": "No, don't unfollow",
|
||||
"unfollow_confirm_title": "Unfollow user",
|
||||
"not_following_any_hashtags": "You are not following any hashtags",
|
||||
"follow_tag": "Follow hashtag",
|
||||
"unfollow_tag": "Unfollow hashtag",
|
||||
"unmute": "Unmute",
|
||||
"unmute_progress": "Unmuting…",
|
||||
"unsubscribe": "Unsubscribe"
|
||||
|
@ -1179,7 +1196,8 @@
|
|||
"user_profile": {
|
||||
"profile_does_not_exist": "Sorry, this profile does not exist.",
|
||||
"profile_loading_error": "Sorry, there was an error loading this profile.",
|
||||
"timeline_title": "User timeline"
|
||||
"timeline_title": "User timeline",
|
||||
"field_validated": "Link Verified"
|
||||
},
|
||||
"user_reporting": {
|
||||
"add_comment_description": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
|
|
|
@ -282,18 +282,18 @@
|
|||
"delete_note_title": "Confirma la eliminación",
|
||||
"no_content": "Sin descripción dada",
|
||||
"no_reports": "No hay informes que mostrar",
|
||||
"note_placeholder": "Dejar una nota...",
|
||||
"note_placeholder": "Dejar una nota",
|
||||
"notes": "{ count } nota | { count } notas",
|
||||
"reopen": "Reabrir",
|
||||
"report": "Reportar",
|
||||
"reports": "Reportes",
|
||||
"resolve": "Resolver",
|
||||
"show_closed": "Mostrar cerrados",
|
||||
"statuses": "{ count } estado | { count } estados",
|
||||
"statuses": "{ count } publicación | { count } publicaciones",
|
||||
"tag_policy_notice": "Habilitar TagPolicy MRF para establecer restricciones de publicación",
|
||||
"tags": "Establecer restricciones de publicación"
|
||||
},
|
||||
"statuses": "Estados",
|
||||
"statuses": "Publicaciones",
|
||||
"users": "Usuarios"
|
||||
},
|
||||
"nav": {
|
||||
|
@ -409,6 +409,8 @@
|
|||
}
|
||||
},
|
||||
"registration": {
|
||||
"awaiting_email_confirmation": "Su cuenta ha sido registrada y se ha enviado un correo electrónico a su dirección. Por favor revise el correo electrónico para completar el registro.",
|
||||
"awaiting_email_confirmation_title": "En espera de confirmación por correo electrónico",
|
||||
"bio": "Biografía",
|
||||
"bio_placeholder": "p. ej.\nHola, soy un ejemplo.\nAquí puedes poner algo representativo tuyo... o no.",
|
||||
"captcha": "CAPTCHA",
|
||||
|
@ -422,6 +424,8 @@
|
|||
"reason_placeholder": "Los registros de esta instancia son aprobados manualmente.\nComéntanos por qué quieres registrarte aquí.",
|
||||
"register": "Registrarse",
|
||||
"registration": "Registro",
|
||||
"request_sent": "Su solicitud de registro ha sido enviada para su aprobación. Recibirá un correo electrónico cuando se apruebe su cuenta.",
|
||||
"request_sent_title": "Solicitud de registro enviada",
|
||||
"token": "Token de invitación",
|
||||
"username_placeholder": "p. ej. akko",
|
||||
"validations": {
|
||||
|
@ -531,6 +535,8 @@
|
|||
"enable_web_push_notifications": "Habilitar las notificiaciones en el navegador",
|
||||
"enter_current_password_to_confirm": "Introduce la contraseña actual para confirmar tu identidad",
|
||||
"expert_mode": "Mostrar avanzados",
|
||||
"expire_posts_enabled": "Eliminar publicaciones después de una cantidad determinada de días",
|
||||
"expire_posts_input_placeholder": "Número de días",
|
||||
"export_theme": "Exportar tema",
|
||||
"file_export_import": {
|
||||
"backup_restore": "Copia de seguridad de la configuración",
|
||||
|
@ -664,6 +670,7 @@
|
|||
"notification_visibility_likes": "Favoritos",
|
||||
"notification_visibility_mentions": "Menciones",
|
||||
"notification_visibility_moves": "Usuario Migrado",
|
||||
"notification_visibility_polls": "Encuestas finalizadas en las que has participado",
|
||||
"notification_visibility_repeats": "Repeticiones (Repeats)",
|
||||
"notifications": "Notificaciones",
|
||||
"nsfw_clickthrough": "Habilitar la ocultación de la imagen de vista previa del enlace y el adjunto para los estados NSFW por defecto",
|
||||
|
@ -672,7 +679,9 @@
|
|||
"panelRadius": "Paneles",
|
||||
"pause_on_unfocused": "Parar la transmisión cuando no estés en foco",
|
||||
"play_videos_in_modal": "Reproducir los vídeos en un marco emergente",
|
||||
"post_status_content_type": "Formato de publicación",
|
||||
"post_look_feel": "Aspecto de las publicaciones",
|
||||
"post_status_content_type": "Formato predeterminado de publicación",
|
||||
"posts": "Publicaciones",
|
||||
"preload_images": "Precargar las imágenes",
|
||||
"presets": "Por defecto",
|
||||
"profile_background": "Imagen de fondo del perfil",
|
||||
|
@ -686,6 +695,10 @@
|
|||
"profile_tab": "Perfil",
|
||||
"radii_help": "Establezca el redondeo de las esquinas de la interfaz (en píxeles)",
|
||||
"refresh_token": "Actualizar el token",
|
||||
"remove_alias": "Eliminar este alias",
|
||||
"remove_backup": "Eliminar",
|
||||
"render_mfm": "Renderizar Markdown de Misskey",
|
||||
"render_mfm_on_hover": "Pausa las animaciones MFM hasta que se desplace el mensaje",
|
||||
"replies_in_timeline": "Réplicas en la línea temporal",
|
||||
"reply_visibility_all": "Mostrar todas las réplicas",
|
||||
"reply_visibility_following": "Solo mostrar réplicas para mí o usuarios a los que sigo",
|
||||
|
@ -709,13 +722,34 @@
|
|||
"security": "Seguridad",
|
||||
"security_tab": "Seguridad",
|
||||
"sensitive_by_default": "Identificar las publicaciones como sensibles de forma predeterminada",
|
||||
"sensitive_if_subject": "Marcar automáticamente las imágenes como confidenciales si se especifica una advertencia de contenido",
|
||||
"set_new_avatar": "Cambiar avatar",
|
||||
"set_new_mascot": "Fijar nueva mascota",
|
||||
"set_new_profile_background": "Cambiar el fondo del perfil",
|
||||
"set_new_profile_banner": "Cambiar la cabecera del perfil",
|
||||
"setting_changed": "La configuración es diferente a la predeterminada",
|
||||
"setting_server_side": "Esta configuración está vinculada a su perfil y afecta a todas las sesiones y clientes",
|
||||
"settings": "Ajustes",
|
||||
"settings_profile": "Ajustes de Perfiles",
|
||||
"settings_profile_creation": "Crear nuevo perfil",
|
||||
"settings_profile_creation_new_name_label": "Nombre",
|
||||
"settings_profile_creation_submit": "Crear",
|
||||
"settings_profile_currently": "Actualmente usando {nombre} (versión: {version})",
|
||||
"settings_profile_delete": "Eliminar",
|
||||
"settings_profile_delete_confirm": "¿Realmente quieres eliminar este perfil?",
|
||||
"settings_profile_force_sync": "Sincronizar",
|
||||
"settings_profile_in_use": "En uso",
|
||||
"settings_profile_use": "Usar",
|
||||
"settings_profiles_refresh": "Recargar perfiles de configuración",
|
||||
"settings_profiles_show": "Mostrar todos los perfiles de configuración",
|
||||
"settings_profiles_unshow": "Ocultar todos los perfiles de configuración",
|
||||
"show_admin_badge": "Mostrar la insignia de \"Administrador/a\" en mi perfil",
|
||||
"show_moderator_badge": "Mostrar la insignia de \"Moderador/a\" en mi perfil",
|
||||
"show_nav_shortcuts": "Mostrar accesos directos de navegación adicionales en el panel superior",
|
||||
"show_panel_nav_shortcuts": "Mostrar accesos directos de navegación de la línea de tiempo en la parte superior del panel",
|
||||
"show_scrollbars": "Mostrar las barras de desplazamiento de la columna lateral",
|
||||
"show_wider_shortcuts": "Mostrar una brecha más amplia entre los accesos directos del panel superior",
|
||||
"show_yous": "Mostrar (Tú)s",
|
||||
"stop_gifs": "Iniciar GIFs al pasar el ratón",
|
||||
"streaming": "Habilitar la transmisión automática de nuevas publicaciones cuando se desplaza hacia la parte superior",
|
||||
"style": {
|
||||
|
@ -864,9 +898,9 @@
|
|||
"use_source": "Nueva versión"
|
||||
}
|
||||
},
|
||||
"subject_input_always_show": "Mostrar siempre el campo del tema",
|
||||
"subject_line_behavior": "Copiar el tema en las respuestas",
|
||||
"subject_line_email": "Como email: \"re: tema\"",
|
||||
"subject_input_always_show": "Mostrar siempre el campo de advertencia de contenido",
|
||||
"subject_line_behavior": "Copiar el campo de advertencia en las respuestas",
|
||||
"subject_line_email": "Como email: \"re: advertencia\"",
|
||||
"subject_line_mastodon": "Como mastodon: copiar como es",
|
||||
"subject_line_noop": "No copiar",
|
||||
"text": "Texto",
|
||||
|
@ -874,8 +908,13 @@
|
|||
"theme_help": "Use códigos de color hexadecimales (#rrggbb) para personalizar su tema de colores.",
|
||||
"theme_help_v2_1": "También puede invalidar los colores y la opacidad de ciertos componentes si activa la casilla de verificación. Use el botón \"Borrar todo\" para deshacer los cambios.",
|
||||
"theme_help_v2_2": "Los iconos debajo de algunas publicaciones son indicadores de contraste de fondo/texto, desplace el ratón por encima para obtener información más detallada. Tenga en cuenta que cuando se utilizan indicadores de contraste de transparencia se muestra el peor caso posible.",
|
||||
"third_column_mode": "Cuando haya suficiente espacio, muestre la tercera columna",
|
||||
"third_column_mode_none": "No mostrar la tercera columna en absoluto",
|
||||
"third_column_mode_notifications": "Columna de notificaciones",
|
||||
"third_column_mode_postform": "Formulario principal de publicación y navegación",
|
||||
"token": "Token",
|
||||
"tooltipRadius": "Información/alertas",
|
||||
"translation_language": "Idioma de traducción automática",
|
||||
"type_domains_to_mute": "Buscar dominios para silenciar",
|
||||
"upload_a_photo": "Subir una foto",
|
||||
"useStreamingApi": "Recibir publicaciones y notificaciones en tiempo real",
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
"keep_open": "Garder ouvert",
|
||||
"load_all": "Charger tout les {emojiAmount} émojis",
|
||||
"load_all_hint": "{saneAmount} émojis chargé, charger tout les émojis peuvent causer des problèmes de performances.",
|
||||
"recent": "Utilisé récemment",
|
||||
"search_emoji": "Rechercher un émoji",
|
||||
"stickers": "Stickers",
|
||||
"unicode": "émoji unicode"
|
||||
|
@ -254,6 +255,10 @@
|
|||
"hint": "Connectez-vous pour rejoindre la discussion",
|
||||
"login": "Connexion",
|
||||
"logout": "Déconnexion",
|
||||
"logout_confirm": "Voulez-vous vraiment vous déconnecter ?",
|
||||
"logout_confirm_accept_button": "Déconnexion",
|
||||
"logout_confirm_cancel_button": "Annuler",
|
||||
"logout_confirm_title": "Déconnexion",
|
||||
"password": "Mot de passe",
|
||||
"placeholder": "mon nom d'utilisateur",
|
||||
"recovery_code": "Code de récupération",
|
||||
|
@ -266,6 +271,32 @@
|
|||
"next": "Suivant",
|
||||
"previous": "Précédent"
|
||||
},
|
||||
"moderation": {
|
||||
"moderation": "Modération",
|
||||
"reports": {
|
||||
"add_note": "Ajouter une note",
|
||||
"close": "Fermer",
|
||||
"delete_note": "Supprimer",
|
||||
"delete_note_accept": "Oui, supprimer",
|
||||
"delete_note_cancel": "Non, abandonner",
|
||||
"delete_note_confirm": "Voulez-vous vraiment supprimer cette note ?",
|
||||
"delete_note_title": "Confirmer la suppression",
|
||||
"no_content": "Description vide",
|
||||
"no_reports": "Aucun rapport",
|
||||
"note_placeholder": "Laisser une note",
|
||||
"notes": "{ count } note | { count } notes",
|
||||
"reopen": "Rouvrir",
|
||||
"report": "Signaler",
|
||||
"reports": "Rapports",
|
||||
"resolve": "Résoudre",
|
||||
"show_closed": "Afficher les rapports classés",
|
||||
"statuses": "{ count } statut| { count } statuts",
|
||||
"tag_policy_notice": "Activer la politique MRF pour établir les restrictions de publication",
|
||||
"tags": "Établir les restrictions de publication"
|
||||
},
|
||||
"statuses": "Statuts",
|
||||
"users": "Utilisateurs"
|
||||
},
|
||||
"nav": {
|
||||
"about": "À propos",
|
||||
"administration": "Administration",
|
||||
|
@ -282,6 +313,7 @@
|
|||
"interactions": "Interactions",
|
||||
"lists": "Listes",
|
||||
"mentions": "Mentions",
|
||||
"moderation": "Moderation",
|
||||
"preferences": "Préférences",
|
||||
"public_timeline_description": "Tous les statuts publics de cette instance",
|
||||
"public_tl": "Flux publique",
|
||||
|
@ -378,6 +410,8 @@
|
|||
}
|
||||
},
|
||||
"registration": {
|
||||
"awaiting_email_confirmation": "Votre compte a été enregistré et un courriel envoyé à votre adresse. Veuillez consulter votre boîte mail pour terminer la registration.",
|
||||
"awaiting_email_confirmation_title": "En attente de confirmation par courriel",
|
||||
"bio": "Biographie",
|
||||
"bio_placeholder": "ex :\nSalut, je me présente ici !\nJ’adore les animés et les jeux vidéos. J’espère qu'on peut être amis⋅ies !",
|
||||
"captcha": "CAPTCHA",
|
||||
|
@ -391,6 +425,8 @@
|
|||
"reason_placeholder": "Cette instance modère les inscriptions manuellement.\nExpliquer ce qui motive votre inscription à l'administration.",
|
||||
"register": "Enregistrer",
|
||||
"registration": "Inscription",
|
||||
"request_sent": "Votre demande d'enregistrement est en attente d'approbation. Vous recevrez un courriel lorsque votre compte sera approuvé.",
|
||||
"request_sent_title": "Demande d'abonnement envoyée",
|
||||
"token": "Jeton d'invitation",
|
||||
"username_placeholder": "ex : misato",
|
||||
"validations": {
|
||||
|
|
416
src/i18n/id.json
416
src/i18n/id.json
|
@ -1,37 +1,72 @@
|
|||
{
|
||||
"about": {
|
||||
"bubble_instances": "Instance Bubble Lokal",
|
||||
"bubble_instances_description": "Instansi yang dipilih oleh admin untuk mewakili instance ini",
|
||||
"mrf": {
|
||||
"federation": "Federasi",
|
||||
"keyword": {
|
||||
"ftl_removal": "Penghapusan dari Linimasa \"Jaringan Yang Dikenal\"",
|
||||
"is_replaced_by": "→",
|
||||
"reject": "Tolak"
|
||||
"keyword_policies": "Kebijakan Kata Kunci",
|
||||
"reject": "Tolak",
|
||||
"replace": "Ganti"
|
||||
},
|
||||
"mrf_policies": "Kebijakan MRF yang diaktifkan",
|
||||
"mrf_policies_desc": "Kebijakan MRF memanipulasi federasi yang terjadi pada instansi ini. Kebijakan berikut adalah yang aktif:",
|
||||
"simple": {
|
||||
"accept": "Terima",
|
||||
"accept_desc": "Instansi ini hanya menerima pesan dari instansi-instansi berikut:",
|
||||
"ftl_removal": "Penghapusan dari Linimasa \"Jaringan Yang Dikenal\"",
|
||||
"ftl_removal_desc": "Instansi ini menghapus instansi berikut dari linimasa \"Jaringan Yang Dikenal\":",
|
||||
"instance": "Instansi",
|
||||
"media_nsfw": "Media diatur sebagai sensitif secara paksa",
|
||||
"media_nsfw_desc": "Instansi ini secara paksa menandai media pada postingan dari instansi berikut sebagai sensitif:",
|
||||
"media_removal": "Penghapusan Media",
|
||||
"media_removal_desc": "Instansi ini menghapus media dari postingan yang berasal dari instansi-instansi berikut:",
|
||||
"not_applicable": "Tidak berlaku",
|
||||
"quarantine": "Karantina",
|
||||
"quarantine_desc": "Instansi ini hanya akan mengirim postingan publik ke instansi-instansi berikut:",
|
||||
"quarantine_desc": "Instansi ini tidak akan mengirim postingan publik ke instansi berikut:",
|
||||
"reason": "Alasan",
|
||||
"reject": "Tolak",
|
||||
"reject_desc": "Instansi ini tidak akan menerima pesan dari instansi-instansi berikut:"
|
||||
"reject_desc": "Instansi ini tidak akan menerima pesan dari instansi-instansi berikut:",
|
||||
"simple_policies": "Kebijakan khusus instansi"
|
||||
}
|
||||
},
|
||||
"staff": "Staf"
|
||||
},
|
||||
"announcements": {
|
||||
"all_day_prompt": "Ini adalah acara sepanjang hari",
|
||||
"cancel_edit_action": "Batal",
|
||||
"close_error": "Tutup",
|
||||
"delete_action": "Hapus",
|
||||
"edit_action": "Sunting",
|
||||
"end_time_display": "Berakhir pada {time}",
|
||||
"end_time_prompt": "Waktu berakhir: ",
|
||||
"inactive_message": "Pengumuman ini nonaktif",
|
||||
"mark_as_read_action": "Tandai sebagai dibaca",
|
||||
"page_header": "Pengumuman",
|
||||
"post_action": "Posting",
|
||||
"post_error": "Kesalahan: {error}",
|
||||
"post_form_header": "Posting pengumuman",
|
||||
"post_placeholder": "Isi pengumuman",
|
||||
"published_time_display": "Diterbitkan pada {time}",
|
||||
"start_time_display": "Dimulai pada {time}",
|
||||
"start_time_prompt": "Waktu mulai: ",
|
||||
"submit_edit_action": "Kirim",
|
||||
"title": "Pengumuman"
|
||||
},
|
||||
"chats": {
|
||||
"chats": "Obrolan",
|
||||
"delete": "Hapus",
|
||||
"delete_confirm": "Apakah Anda benar-benar ingin menghapus pesan ini?",
|
||||
"empty_chat_list_placeholder": "Anda belum memiliki obrolan. Buat sbeuah obrolan baru!",
|
||||
"delete_confirm": "Apakah kamu benar-benar ingin menghapus pesan ini?",
|
||||
"empty_chat_list_placeholder": "Kamu belum memiliki obrolan. Mulai obrolan baru!",
|
||||
"empty_message_error": "Tidak dapat memposting pesan yang kosong",
|
||||
"error_loading_chat": "Sesuatu yang salah terjadi ketika memuat obrolan.",
|
||||
"error_sending_message": "Sesuatu yang salah terjadi ketika mengirim pesan.",
|
||||
"message_user": "Kirim Pesan ke {nickname}",
|
||||
"more": "Lebih banyak",
|
||||
"new": "Obrolan Baru",
|
||||
"you": "Anda:"
|
||||
"you": "Kamu:"
|
||||
},
|
||||
"display_date": {
|
||||
"today": "Hari Ini"
|
||||
|
@ -40,7 +75,7 @@
|
|||
"mute": "Bisukan",
|
||||
"mute_progress": "Membisukan…",
|
||||
"unmute": "Berhenti membisukan",
|
||||
"unmute_progress": "Memberhentikan pembisuan…"
|
||||
"unmute_progress": "Menghentikan pembisuan…"
|
||||
},
|
||||
"emoji": {
|
||||
"add_emoji": "Sisipkan emoji",
|
||||
|
@ -49,21 +84,25 @@
|
|||
"keep_open": "Tetap buka pemilih",
|
||||
"load_all": "Memuat semua {emojiAmount} emoji",
|
||||
"load_all_hint": "Memuat {saneAmount} emoji pertama, memuat semua emoji dapat menyebabkan masalah performa.",
|
||||
"recent": "Baru-baru ini digunakan",
|
||||
"search_emoji": "Cari emoji",
|
||||
"stickers": "Stiker",
|
||||
"unicode": "Emoji unicode"
|
||||
"unicode": "Emoji Unicode"
|
||||
},
|
||||
"errors": {
|
||||
"storage_unavailable": "Pleroma tidak dapat mengakses penyimpanan browser. Login Anda atau pengaturan lokal Anda tidak akan tersimpan dan masalah yang tidak terduga dapat terjadi. Coba mengaktifkan kuki."
|
||||
"storage_unavailable": "Pleroma tidak dapat mengakses penyimpanan browser. Login kamu atau pengaturan lokal kamu tidak akan tersimpan dan masalah yang tidak terduga dapat terjadi. Coba aktifkan kuki."
|
||||
},
|
||||
"exporter": {
|
||||
"export": "Ekspor",
|
||||
"processing": "Memproses, Anda akan segera diminta untuk mengunduh berkas Anda"
|
||||
"processing": "Memproses, kamu akan segera diminta untuk mengunduh berkas kamu"
|
||||
},
|
||||
"features_panel": {
|
||||
"media_proxy": "Proxy media",
|
||||
"scope_options": "Opsi cakupan",
|
||||
"text_limit": "Batas teks",
|
||||
"title": "Fitur-fitur",
|
||||
"upload_limit": "Batas unggahan"
|
||||
"upload_limit": "Batas unggahan",
|
||||
"who_to_follow": "Siapa untuk diikuti"
|
||||
},
|
||||
"file_type": {
|
||||
"audio": "Audio",
|
||||
|
@ -81,6 +120,7 @@
|
|||
"close": "Tutup",
|
||||
"confirm": "Konfirmasi",
|
||||
"disable": "Nonaktifkan",
|
||||
"dismiss": "Tutup",
|
||||
"enable": "Aktifkan",
|
||||
"error_retry": "Harap coba lagi",
|
||||
"flash_content": "Klik untuk menampilkan konten Flash menggunakan Ruffle (Eksperimental, mungkin tidak bekerja).",
|
||||
|
@ -96,6 +136,13 @@
|
|||
"admin": "Admin",
|
||||
"moderator": "Moderator"
|
||||
},
|
||||
"scope_in_timeline": {
|
||||
"direct": "Langsung",
|
||||
"local": "Lokal - hanya instansi kamu yang dapat melihat postingan ini",
|
||||
"private": "Hanya pengikut",
|
||||
"public": "Publik",
|
||||
"unlisted": "Tidak Tercantum"
|
||||
},
|
||||
"show_less": "Tampilkan lebih sedikit",
|
||||
"show_more": "Tampilkan lebih banyak",
|
||||
"submit": "Kirim",
|
||||
|
@ -118,68 +165,192 @@
|
|||
"load_older": "Muat interaksi yang lebih tua",
|
||||
"moves": "Pengguna yang bermigrasi"
|
||||
},
|
||||
"languages": {
|
||||
"ar": "Arab",
|
||||
"az": "Azerbaijan",
|
||||
"bg": "Bulgaria",
|
||||
"cs": "Ceko",
|
||||
"da": "Denmark",
|
||||
"de": "Jerman",
|
||||
"el": "Yunani",
|
||||
"en": "Inggris",
|
||||
"eo": "Esperanto",
|
||||
"es": "Spanyol",
|
||||
"fa": "Persia",
|
||||
"fi": "Finlandia",
|
||||
"fr": "Prancis",
|
||||
"ga": "Irlandia",
|
||||
"he": "Ibrani",
|
||||
"hi": "Hindi",
|
||||
"hu": "Hongaria",
|
||||
"id": "Indonesia",
|
||||
"it": "Italia",
|
||||
"ja": "Jepang",
|
||||
"ko": "Korea",
|
||||
"lt": "Lithuania",
|
||||
"lv": "Latvia",
|
||||
"nl": "Belanda",
|
||||
"pl": "Polandia",
|
||||
"pt": "Portugis",
|
||||
"ru": "Rusia",
|
||||
"sk": "Slovakia",
|
||||
"sv": "Swedia",
|
||||
"tr": "Turki",
|
||||
"translated_from": {
|
||||
"ar": "Diterjemahkan dari bahasa @:languages.ar",
|
||||
"az": "Diterjemahkan dari bahasa @:languages.az",
|
||||
"bg": "Diterjemahkan dari bahasa @:languages.bg",
|
||||
"cs": "Diterjemahkan dari bahasa @:languages.cs",
|
||||
"da": "Diterjemahkan dari bahasa @:languages.da",
|
||||
"de": "Diterjemahkan dari bahasa @:languages.de",
|
||||
"el": "Diterjemahkan dari bahasa @:languages.el",
|
||||
"en": "Diterjemahkan dari bahasa @:languages.en",
|
||||
"eo": "Diterjemahkan dari bahasa @:languages.eo",
|
||||
"es": "Diterjemahkan dari bahasa @:languages.es",
|
||||
"fa": "Diterjemahkan dari bahasa @:languages.fa",
|
||||
"fi": "Diterjemahkan dari bahasa @:languages.fi",
|
||||
"fr": "Diterjemahkan dari bahasa @:languages.fr",
|
||||
"ga": "Diterjemahkan dari bahasa @:languages.ga",
|
||||
"he": "Diterjemahkan dari bahasa @:languages.he",
|
||||
"hi": "Diterjemahkan dari bahasa @:languages.hi",
|
||||
"hu": "Diterjemahkan dari bahasa @:languages.hu",
|
||||
"id": "Diterjemahkan dari bahasa @:languages.id",
|
||||
"it": "Diterjemahkan dari bahasa @:languages.it",
|
||||
"ja": "Diterjemahkan dari bahasa @:languages.ja",
|
||||
"ko": "Diterjemahkan dari bahasa @:languages.ko",
|
||||
"lt": "Diterjemahkan dari bahasa @:languages.lt",
|
||||
"lv": "Diterjemahkan dari bahasa @:languages.lv",
|
||||
"nl": "Diterjemahkan dari bahasa @:languages.nl",
|
||||
"pl": "Diterjemahkan dari bahasa @:languages.pl",
|
||||
"pt": "Diterjemahkan dari bahasa @:languages.pt",
|
||||
"ru": "Diterjemahkan dari bahasa @:languages.ru",
|
||||
"sk": "Diterjemahkan dari bahasa @:languages.sk",
|
||||
"sv": "Diterjemahkan dari bahasa @:languages.sv",
|
||||
"tr": "Diterjemahkan dari bahasa @:languages.tr",
|
||||
"uk": "Diterjemahkan dari bahasa @:languages.uk",
|
||||
"zh": "Diterjemahkan dari bahasa @:languages.zh"
|
||||
},
|
||||
"uk": "Ukraina",
|
||||
"zh": "Tionghoa"
|
||||
},
|
||||
"lists": {
|
||||
"create": "Buat",
|
||||
"delete": "Hapus daftar",
|
||||
"following_only": "Batas mengikuti",
|
||||
"lists": "Daftar",
|
||||
"new": "Buat Daftar",
|
||||
"save": "Simpan perubahan",
|
||||
"search": "Telusuri pengguna",
|
||||
"title": "Judul daftar"
|
||||
},
|
||||
"login": {
|
||||
"authentication_code": "Kode otentikasi",
|
||||
"description": "Masuk dengan OAuth",
|
||||
"enter_recovery_code": "Masukkan kode pemulihan",
|
||||
"enter_two_factor_code": "Masukkan kode dua-faktor",
|
||||
"heading": {
|
||||
"recovery": "Pemulihan dua-faktor",
|
||||
"totp": "Otentikasi dua-faktor"
|
||||
},
|
||||
"hint": "Masuk untuk ikut berdiskusi",
|
||||
"login": "Masuk",
|
||||
"logout": "Keluar",
|
||||
"logout_confirm": "Apa kamu yakin ingin keluar?",
|
||||
"logout_confirm_accept_button": "Keluar",
|
||||
"logout_confirm_cancel_button": "Batal",
|
||||
"logout_confirm_title": "Keluar",
|
||||
"password": "Kata sandi",
|
||||
"placeholder": "contoh: lain",
|
||||
"placeholder": "namapenggunaku",
|
||||
"recovery_code": "Kode pemulihan",
|
||||
"register": "Daftar",
|
||||
"username": "Nama pengguna"
|
||||
},
|
||||
"media_modal": {
|
||||
"next": "Selanjutnya",
|
||||
"previous": "Sebelum"
|
||||
"counter": "{current} / {total}",
|
||||
"hide": "Tutup penampil media",
|
||||
"next": "Berikutnya",
|
||||
"previous": "Sebelumnya"
|
||||
},
|
||||
"moderation": {
|
||||
"moderation": "Moderasi",
|
||||
"reports": {
|
||||
"add_note": "Tambahkan catatan",
|
||||
"close": "Tutup",
|
||||
"delete_note": "Hapus",
|
||||
"delete_note_accept": "Ya, hapus",
|
||||
"delete_note_cancel": "Tidak, kembalikan",
|
||||
"delete_note_confirm": "Apa kamu yakin ingin menghapus catatan ini?",
|
||||
"delete_note_title": "Konfirmasi penghapusan",
|
||||
"no_content": "Tak diberikan keterangan",
|
||||
"no_reports": "Tak ada laporan",
|
||||
"note_placeholder": "Tinggalkan catatan",
|
||||
"notes": "{ count } catatan",
|
||||
"reopen": "Buka kembali",
|
||||
"report": "Laporan di",
|
||||
"reports": "Laporan",
|
||||
"resolve": "Selesaikan",
|
||||
"show_closed": "Tampilkan yang telah ditutup",
|
||||
"statuses": "{ count } postingan",
|
||||
"tag_policy_notice": "Aktifkan MRF TagPolicy untuk mengatur pembatasan postingan",
|
||||
"tags": "Atur pembatasan postingan"
|
||||
},
|
||||
"statuses": "Postingan",
|
||||
"users": "Pengguna"
|
||||
},
|
||||
"nav": {
|
||||
"about": "Tentang",
|
||||
"administration": "Administrasi",
|
||||
"announcements": "Pengumuman",
|
||||
"back": "Kembali",
|
||||
"bookmarks": "Bookmark",
|
||||
"bubble_timeline": "Timeline Bubble",
|
||||
"bubble_timeline_description": "Postingan dari instansi yang dekat dengan instansimu, yang direkomendasikan oleh admin kamu",
|
||||
"chats": "Obrolan",
|
||||
"dms": "Pesan langsung",
|
||||
"friend_requests": "Ingin mengikuti",
|
||||
"home_timeline": "Linimasa beranda",
|
||||
"home_timeline_description": "Postingan dari orang yang kamu ikuti",
|
||||
"interactions": "Interaksi",
|
||||
"lists": "Daftar",
|
||||
"mentions": "Sebutan",
|
||||
"moderation": "Moderasi",
|
||||
"preferences": "Preferensi",
|
||||
"public_timeline_description": "Postingan publik dari instansi ini",
|
||||
"public_tl": "Linimasa publik",
|
||||
"search": "Cari",
|
||||
"search": "Penelusuran",
|
||||
"timeline": "Linimasa",
|
||||
"timelines": "Linimasa",
|
||||
"user_search": "Pencarian Pengguna"
|
||||
"twkn": "Jaringan Yang Dikenal",
|
||||
"twkn_timeline_description": "Postingan dari seluruh jaringan",
|
||||
"user_search": "Penelusuran Pengguna",
|
||||
"who_to_follow": "Siapa untuk diikuti"
|
||||
},
|
||||
"notifications": {
|
||||
"broken_favorite": "Status tak diketahui, mencarinya…",
|
||||
"broken_favorite": "Postingan tak dikenal, mencarinya…",
|
||||
"error": "Terjadi kesalahan ketika memuat notifikasi: {0}",
|
||||
"favorited_you": "memfavoritkan status Anda",
|
||||
"follow_request": "ingin mengikuti Anda",
|
||||
"followed_you": "mengikuti Anda",
|
||||
"favorited_you": "memfavoritkan postinganmu",
|
||||
"follow_request": "ingin mengikuti kamu",
|
||||
"followed_you": "mengikuti kamu",
|
||||
"load_older": "Muat notifikasi yang lebih lama",
|
||||
"migrated_to": "bermigrasi ke",
|
||||
"no_more_notifications": "Tidak ada notifikasi lagi",
|
||||
"notifications": "Notifikasi",
|
||||
"poll_ended": "japat telah berakhir",
|
||||
"reacted_with": "bereaksi dengan {0}",
|
||||
"read": "Dibaca!",
|
||||
"repeated_you": "mengulangi status Anda"
|
||||
"repeated_you": "mengulangi postinganmu"
|
||||
},
|
||||
"password_reset": {
|
||||
"check_email": "Periksa surelmu untuk mendapatkan tautan yang digunakan untuk mengatur ulang kata sandimu.",
|
||||
"forgot_password": "Lupa kata sandi?",
|
||||
"instruction": "Masukkan surel atau nama pengguna Anda. Kami akan mengirimkan Anda tautan untuk mengatur ulang kata sandi.",
|
||||
"password_reset": "Pengatur-ulangan kata sandi",
|
||||
"password_reset_disabled": "Pengatur-ulangan kata sandi dinonaktifkan. Hubungi administrator instansi Anda.",
|
||||
"password_reset_required": "Anda harus mengatur ulang kata sandi Anda untuk masuk.",
|
||||
"password_reset_required_but_mailer_is_disabled": "Anda harus mengatur ulang kata sandi, tetapi pengatur-ulangan kata sandi dinonaktifkan. Silakan hubungi administrator instansi Anda.",
|
||||
"placeholder": "Surel atau nama pengguna Anda",
|
||||
"instruction": "Masukkan surel atau nama pengguna kamu. Kami akan mengirimkan kamu tautan untuk mengatur ulang kata sandi.",
|
||||
"password_reset": "Pengatur ulangan kata sandi",
|
||||
"password_reset_disabled": "Pengatur-ulangan kata sandi dinonaktifkan. Silakan hubungi administrator instansi kamu.",
|
||||
"password_reset_required": "Kamu harus mengatur ulang kata sandi kamu untuk masuk.",
|
||||
"password_reset_required_but_mailer_is_disabled": "Kamu harus mengatur ulang kata sandi, tetapi pengatur-ulangan kata sandi dinonaktifkan. Silakan hubungi administrator instansimu.",
|
||||
"placeholder": "Surel atau nama pengguna kamu",
|
||||
"return_home": "Kembali ke halaman beranda",
|
||||
"too_many_requests": "Anda telah mencapai batas percobaan, coba lagi nanti."
|
||||
"too_many_requests": "Kamu telah mencapai batas percobaan, coba lagi nanti."
|
||||
},
|
||||
"polls": {
|
||||
"add_option": "Tambahkan opsi",
|
||||
|
@ -187,70 +358,90 @@
|
|||
"expired": "Japat berakhir {0} yang lalu",
|
||||
"expires_in": "Japat berakhir dalam {0}",
|
||||
"expiry": "Usia japat",
|
||||
"multiple_choices": "Lebih dari satu opsi dapat dipilih",
|
||||
"not_enough_options": "Terlalu sedikit opsi yang unik pada japat",
|
||||
"option": "Opsi",
|
||||
"people_voted_count": "{count} orang memilih | {count} orang memilih",
|
||||
"single_choice": "Hanya satu opsi dapat dipilih",
|
||||
"type": "Jenis japat",
|
||||
"vote": "Pilih",
|
||||
"votes": "suara",
|
||||
"votes_count": "{count} suara | {count} suara"
|
||||
},
|
||||
"post_status": {
|
||||
"account_not_locked_warning": "Akun Anda tidak {0}. Siapapun dapat mengikuti Anda untuk melihat postingan hanya-pengikut Anda.",
|
||||
"account_not_locked_warning": "Akun kamu tidak {0}. Siapapun dapat mengikuti kamu untuk melihat postingan hanya-pengikut kamu.",
|
||||
"account_not_locked_warning_link": "terkunci",
|
||||
"attachments_sensitive": "Tandai lampiran sebagai sensitif",
|
||||
"content_type": {
|
||||
"text/bbcode": "BBCode",
|
||||
"text/html": "HTML",
|
||||
"text/markdown": "Markdown",
|
||||
"text/plain": "Teks biasa"
|
||||
"text/plain": "Teks biasa",
|
||||
"text/x.misskeymarkdown": "MFM"
|
||||
},
|
||||
"content_warning": "Subyek (opsional)",
|
||||
"default": "Baru saja mendarat di L.A.",
|
||||
"content_warning": "Peringatan Konten (opsional)",
|
||||
"default": "Baru saja tiba di Luna Nova Academy",
|
||||
"direct_warning_to_all": "Postingan ini akan terlihat oleh pengguna yang disebutkan.",
|
||||
"direct_warning_to_first_only": "Postingan ini akan terlihat oleh pengguna yang disebutkan di awal pesan.",
|
||||
"empty_status_error": "Tidak dapat memposting status kosong tanpa berkas",
|
||||
"edit_remote_warning": "Perubahan yang dibuat pada postingan ini mungkin tidak terlihat pada beberapa instansi!",
|
||||
"edit_status": "Sunting Status",
|
||||
"edit_unsupported_warning": "Japat dan sebutan tidak bisa diubah dengan menyunting.",
|
||||
"empty_status_error": "Tidak dapat memposting tanpa isi atau berkas",
|
||||
"media_description": "Keterangan media",
|
||||
"media_description_error": "Gagal memperbarui media, coba lagi",
|
||||
"new_status": "Posting status baru",
|
||||
"media_not_sensitive_warning": "Kamu memasang Peringatan Konten, namun lampirannya tidak ditandai sebagai sensitif!",
|
||||
"new_status": "Posting",
|
||||
"post": "Posting",
|
||||
"posting": "Memposting",
|
||||
"preview": "Pratinjau",
|
||||
"preview_empty": "Kosong",
|
||||
"scope": {
|
||||
"direct": "Langsung - posting hanya kepada pengguna yang disebut",
|
||||
"local": "Lokal - postingan tidak akan difederasi",
|
||||
"private": "Hanya-pengikut - posting hanya kepada pengikut",
|
||||
"public": "Publik - posting ke linimasa publik"
|
||||
"public": "Publik - posting ke linimasa publik",
|
||||
"unlisted": "Tidak Tercantum - Tidak memposting ke timeline publik"
|
||||
},
|
||||
"scope_notice": {
|
||||
"private": "Postingan ini akan terlihat hanya oleh pengikut Anda",
|
||||
"public": "Postingan ini akan terlihat oleh siapa saja"
|
||||
"local": "Postingan ini tidak akan terlihat di instansi lain",
|
||||
"private": "Postingan ini akan terlihat hanya oleh pengikut kamu",
|
||||
"public": "Postingan ini akan terlihat oleh siapa saja",
|
||||
"unlisted": "Postingan ini tidak akan terlihat di Linimasa Publik dan Jaringan Yang Dikenal"
|
||||
}
|
||||
},
|
||||
"registration": {
|
||||
"awaiting_email_confirmation": "Akunmu telah terdaftar dan sebuah surel telah dikirimkan ke alamat kamu. Harap periksa surel untuk menyelesaikan pendaftaran.",
|
||||
"awaiting_email_confirmation_title": "Menunggu konfirmasi surel",
|
||||
"bio": "Bio",
|
||||
"bio_placeholder": "contoh.\nHai, aku Lain.\nAku seorang putri anime yang tinggal di pinggiran kota Jepang. Kamu mungkin mengenal aku dari Wired.",
|
||||
"bio_placeholder": "cth.\nHai! Selamat datang di bioku.\nAku suka menonton anime dan bermain game. Semoga kita bisa berteman!",
|
||||
"captcha": "CAPTCHA",
|
||||
"email": "Surel",
|
||||
"fullname_placeholder": "contoh. Lain Iwakura",
|
||||
"email_language": "Dalam bahasa apa kamu ingin menerima surel dari server ini?",
|
||||
"fullname": "Tampilan Nama",
|
||||
"fullname_placeholder": "cth. Atsuko Kagari",
|
||||
"new_captcha": "Klik gambarnya untuk mendapatkan captcha baru",
|
||||
"password_confirm": "Konfirmasi kata sandi",
|
||||
"reason": "Alasan mendaftar",
|
||||
"reason_placeholder": "Instansi ini menerima pendaftaran secara manual.\nBeritahu administrasinya mengapa Anda ingin mendaftar.",
|
||||
"reason_placeholder": "Instansi ini menerima pendaftaran secara manual.\nBeritahu administrasinya mengapa kamu ingin mendaftar.",
|
||||
"register": "Daftar",
|
||||
"registration": "Pendaftaran",
|
||||
"request_sent": "Permintaan pendaftaran kamu telah dikirim untuk diperiksa. Kamu akan menerima surel saat akunmu diterima.",
|
||||
"request_sent_title": "Permintaan pendaftaran dikirim",
|
||||
"token": "Token undangan",
|
||||
"username_placeholder": "contoh. lain",
|
||||
"username_placeholder": "cth. akko",
|
||||
"validations": {
|
||||
"email_required": "tidak boleh kosong",
|
||||
"fullname_required": "tidak boleh kosong",
|
||||
"password_confirmation_match": "harus sama dengan kata sandi",
|
||||
"password_confirmation_required": "tidak boleh kosong",
|
||||
"password_required": "tidak boleh kosong",
|
||||
"username_required": "tidak boleh kosong"
|
||||
}
|
||||
},
|
||||
"remote_user_resolver": {
|
||||
"error": "Tidak ditemukan."
|
||||
"error": "Tidak ditemukan.",
|
||||
"remote_user_resolver": "Pencarian pengguna jarak jauh",
|
||||
"searching_for": "Mencari"
|
||||
},
|
||||
"search": {
|
||||
"hashtags": "Tagar",
|
||||
|
@ -263,17 +454,31 @@
|
|||
"select_all": "Pilih semua"
|
||||
},
|
||||
"settings": {
|
||||
"accent": "Aksen",
|
||||
"account_alias": "Akun alias",
|
||||
"account_backup": "Pencadangan akun",
|
||||
"account_backup_description": "Ini memungkinkan kamu untuk mengunduh arsip yang berisi informasi tentang akun dan postingan kamu, namun belum bisa diimpor ke akun Pleroma.",
|
||||
"account_privacy": "Privasi",
|
||||
"add_alias_error": "Gagal menambahkan alias: {error}",
|
||||
"add_backup": "Buat cadangan baru",
|
||||
"add_backup_error": "Gagal menambahkan cadangan baru: {error}",
|
||||
"added_alias": "Alias telah ditambahkan.",
|
||||
"added_backup": "Cadangan baru ditambahkan.",
|
||||
"allow_following_move": "Ikuti otomatis apabila akun yang diikuti pindah",
|
||||
"always_show_post_button": "Selalu tampilkan tombol posting baru yang mengambang",
|
||||
"app_name": "Nama aplikasi",
|
||||
"attachmentRadius": "Lampiran",
|
||||
"attachments": "Lampiran",
|
||||
"autohide_floating_post_button": "Sembunyikan tombol buat posting secara otomatis (Ponsel)",
|
||||
"avatar": "Avatar",
|
||||
"avatarAltRadius": "Avatar (notifikasi)",
|
||||
"avatarRadius": "Avatar",
|
||||
"avatar_size_instruction": "Ukuran minimum gambar avatar yang disarankan adalah 150x150 piksel.",
|
||||
"background": "Latar belakang",
|
||||
"backup_not_ready": "Cadangan ini belum siap.",
|
||||
"bio": "Bio",
|
||||
"block_export": "Ekspor blokiran",
|
||||
"block_export_button": "Ekspor blokiran Anda menjadi berkas csv",
|
||||
"block_export_button": "Ekspor blokiranmu menjadi berkas csv",
|
||||
"block_import": "Impor blokiran",
|
||||
"block_import_error": "Terjadi kesalahan ketika mengimpor blokiran",
|
||||
"blocks_imported": "Blokiran diimpor! Pemrosesannya mungkin memakan sedikit waktu.",
|
||||
|
@ -285,65 +490,124 @@
|
|||
"cOrange": "Jingga (Favorit)",
|
||||
"cRed": "Merah (Batal)",
|
||||
"change_email": "Ubah surel",
|
||||
"change_email_error": "Ada masalah ketika mengubah surel Anda.",
|
||||
"change_email_error": "Ada masalah ketika mengubah surel kamu.",
|
||||
"change_password": "Ubah kata sandi",
|
||||
"change_password_error": "Ada masalah ketika mengubah kata sandi Anda.",
|
||||
"change_password_error": "Ada masalah ketika mengubah kata sandi kamu.",
|
||||
"changed_email": "Surel berhasil diubah!",
|
||||
"changed_password": "Kata sandi berhasil diubah!",
|
||||
"chatMessageRadius": "Pesan obrolan",
|
||||
"checkboxRadius": "Kotak centang",
|
||||
"collapse_subject": "Tampilkan post dengan peringatan",
|
||||
"columns": "Kolum",
|
||||
"composing": "Menulis",
|
||||
"confirm_dialogs": "Perlukan konfirmasi sebelum:",
|
||||
"confirm_dialogs_approve_follow": "Menerima permintaan mengikuti",
|
||||
"confirm_dialogs_block": "Memblokir seseorang",
|
||||
"confirm_dialogs_delete": "Menghapus postingan",
|
||||
"confirm_dialogs_deny_follow": "Menolak permintaan mengikuti",
|
||||
"confirm_dialogs_mute": "Membisukan seseorang",
|
||||
"confirm_dialogs_repeat": "Mengulangi postingan",
|
||||
"confirm_dialogs_unfollow": "Berhenti mengikuti seseorang",
|
||||
"confirm_new_password": "Konfirmasi kata sandi baru",
|
||||
"confirmation_dialogs": "Opsi Konfirmasi",
|
||||
"conversation_display": "Gaya tampilan percakapan",
|
||||
"conversation_display_linear": "Gaya Linier",
|
||||
"conversation_display_tree": "Bercabang",
|
||||
"conversation_other_replies_button": "Tampilkan tombol \"Balasan lainnya\"",
|
||||
"conversation_other_replies_button_below": "Di bawah postingan",
|
||||
"conversation_other_replies_button_inside": "Di postingan",
|
||||
"current_avatar": "Avatarmu saat ini",
|
||||
"current_mascot": "Maskot utamamu",
|
||||
"current_password": "Kata sandi saat ini",
|
||||
"data_import_export_tab": "Impor / ekspor data",
|
||||
"default_vis": "Cakupan visibilitas default",
|
||||
"delete_account": "Hapus akun",
|
||||
"delete_account_description": "Hapus data Anda secara permanen dan menonaktifkan akun Anda.",
|
||||
"delete_account_error": "Ada masalah ketika menghapus akun Anda. Jika ini terus terjadi harap hubungi adminstrator instansi Anda.",
|
||||
"delete_account_instructions": "Ketik kata sandi Anda pada input di bawah untuk mengkonfirmasi penghapusan akun.",
|
||||
"delete_account_description": "Hapus data kamu secara permanen dan nonaktifkan akunmu.",
|
||||
"delete_account_error": "Ada masalah ketika menghapus akun kamu. Jika ini terus terjadi harap hubungi adminstrator instansi kamu.",
|
||||
"delete_account_instructions": "Ketik kata sandi kamu pada input di bawah untuk mengonfirmasi penghapusan akun.",
|
||||
"disable_sticky_headers": "Jangan tempel tajuk kolom ke bagian atas layar",
|
||||
"discoverable": "Izinkan penelusuran akun ini pada hasil pencarian dan layanan lainnya",
|
||||
"domain_mutes": "Domain",
|
||||
"download_backup": "Unduh",
|
||||
"email_language": "Bahasa yang digunakan untuk menerima surel dari server ini",
|
||||
"emoji_reactions_on_timeline": "Tampilkan reaksi emoji pada linimasa",
|
||||
"enable_web_push_notifications": "Aktifkan notifikasi push web",
|
||||
"enter_current_password_to_confirm": "Masukkan kata sandi Anda saat ini untuk mengkonfirmasi identitas Anda",
|
||||
"enter_current_password_to_confirm": "Masukkan kata sandi kamu saat ini untuk mengonfirmasi identitas kamu",
|
||||
"expert_mode": "Tampilkan pengaturan lanjutan",
|
||||
"expire_posts_enabled": "Hapus postingan setelah jumlah hari yang ditentukan",
|
||||
"expire_posts_input_placeholder": "Jumlah hari",
|
||||
"export_theme": "Simpan preset",
|
||||
"file_export_import": {
|
||||
"backup_restore": "Pencadangan pengaturan",
|
||||
"backup_settings": "Cadangkan pengaturan ke berkas",
|
||||
"backup_settings_theme": "Cadangkan pengaturan dan tema ke berkas",
|
||||
"errors": {
|
||||
"file_slightly_new": "Versi minor berkas berbeda, beberapa pengaturan mungkin tidak termuat",
|
||||
"file_too_new": "Versi major tidak kompatibel: {fileMajor}, PleromaFE ini (versi {feMajor}) terlalu lama untuk menanganinya",
|
||||
"file_too_old": "Versi major tidak kompatibel: {fileMajor}, versi berkas terlalu lama dan tidak lagi didukung (min. versi {feMajor})",
|
||||
"invalid_file": "Berkas yang dipilih bukan cadangan pengaturan Pleroma yang didukung. Tidak dibuat perubahan."
|
||||
},
|
||||
"restore_settings": "Pulihkan pengaturan dari berkas"
|
||||
},
|
||||
"filtering": "Penyaringan",
|
||||
"filtering_explanation": "Semua postingan yang mengandung kata-kata ini akan dibisukan, satu kata per baris",
|
||||
"follow_export": "Ekspor Follow",
|
||||
"follow_export_button": "Export yang kamu ikuti ke dalam file csv",
|
||||
"follow_import": "Import pengikut",
|
||||
"follow_import_error": "Terjadi kesalahan ketika mengimpor pengikut",
|
||||
"follows_imported": "Pengguna yang diikuti telak diimpor! Proses mungkin membutuhkan beberapa saat.",
|
||||
"fun": "Seru",
|
||||
"general": "Umum",
|
||||
"greentext": "Panah meme",
|
||||
"hide_all_muted_posts": "Sembunyikan postingan yang dibisukan",
|
||||
"hide_attachments_in_convo": "Sembunyikan lampiran pada percakapan",
|
||||
"hide_attachments_in_tl": "Sembunyikan lampiran di linimasa",
|
||||
"hide_bot_indication": "Sembunyikan tanda bot pada postingan",
|
||||
"hide_filtered_statuses": "Sembunyikan semua postingan yang tersaring",
|
||||
"hide_followers_count_description": "Jangan tampilkan jumlah pengikut",
|
||||
"hide_followers_description": "Jangan tampilkan siapa yang mengikuti saya",
|
||||
"hide_followers_description": "Jangan tampilkan siapa yang mengikutiku",
|
||||
"hide_follows_count_description": "Jangan tampilkan jumlah mengikuti",
|
||||
"hide_follows_description": "Jangan tampilkan siapa yang saya ikuti",
|
||||
"hide_follows_description": "Jangan tampilkan siapa yang aku ikuti",
|
||||
"hide_muted_posts": "Sembunyikan postingan-postingan dari pengguna yang dibisukan",
|
||||
"hide_post_stats": "Sembunyikan statistik postingan (contoh. jumlah favorit)",
|
||||
"hide_post_stats": "Sembunyikan statistik postingan (seperti jumlah favorit)",
|
||||
"hide_shoutbox": "Sembunyikan kotak suara instansi",
|
||||
"hide_user_stats": "Sembunyikan statistik pengguna (contoh. jumlah pengikut)",
|
||||
"hide_user_stats": "Sembunyikan statistik pengguna (seperti jumlah pengikut)",
|
||||
"hide_wallpaper": "Sembunyikan latar belakang instansi",
|
||||
"import_blocks_from_a_csv_file": "Impor blokiran dari berkas csv",
|
||||
"instance_default": "(bawaan: {value})",
|
||||
"instance_default_simple": "(bawaan)",
|
||||
"interface": "Antarmuka",
|
||||
"interfaceLanguage": "Bahasa antarmuka",
|
||||
"invalid_theme_imported": "Berkas yang dipilih bukan sebuah tema yang didukung Pleroma. Tidak ada perbuahan yang dibuat pada tema Anda.",
|
||||
"limited_availability": "Tidak tersedia di browser Anda",
|
||||
"invalid_theme_imported": "Berkas yang dipilih bukan sebuah tema yang didukung Pleroma. Tidak ada perubahan yang dibuat pada tema kamu.",
|
||||
"limited_availability": "Tidak tersedia di browser kamu",
|
||||
"links": "Tautan",
|
||||
"lock_account_description": "Batasi akunmu kepada pengikut yang sudah disetujui saja",
|
||||
"loop_video": "Ulang-ulang video",
|
||||
"loop_video_silent_only": "Ulang-ulang video tanpa suara (seperti \"gif\" Mastodon)",
|
||||
"max_thumbnails": "Jumlah thumbnail maksimum per postingan",
|
||||
"max_thumbnails": "Jumlah thumbnail maksimum per postingan (kosong = tidak terbatas)",
|
||||
"mention_link_bolden_you": "Sorot sebutan kamu apabila kamu disebut",
|
||||
"mention_link_display": "Tampilkan tautan sebutan",
|
||||
"mention_link_display_full": "selalu sebagai nama lengkap (cth. {'@'}foo{'@'}example.org)",
|
||||
"mention_link_display_full_for_remote": "sebagai nama lengkap hanya untuk pengguna di instansi lain (cth. {'@'}foo{'@'}example.org)",
|
||||
"mention_link_display_short": "selalu sebagai nama pendek (cth. {'@'}foo)",
|
||||
"mention_link_show_avatar": "Tampilkan avatar pengguna di samping tautan",
|
||||
"mfa": {
|
||||
"authentication_methods": "Metode otentikasi",
|
||||
"confirm_and_enable": "Konfirmasi & aktifkan OTP",
|
||||
"generate_new_recovery_codes": "Hasilkan kode pemulihan baru",
|
||||
"otp": "OTP",
|
||||
"recovery_codes": "Kode pemulihan.",
|
||||
"recovery_codes_warning": "Tulis kode-kode nya atau simpan mereka di tempat yang aman - jika tidak Anda tidak akan melihat mereka lagi. Jika Anda tidak dapat mengakses aplikasi 2FA Anda dan kode pemulihan Anda hilang Anda tidak akan bisa mengakses akun Anda.",
|
||||
"recovery_codes_warning": "Tulis kodenya atau simpan mereka di tempat yang aman - jika tidak kamu tidak akan melihat mereka lagi. Jika kamu tidak dapat mengakses aplikasi 2FA kamu dan kode pemulihanmu hilang, kamu tidak akan bisa mengakses akun kamu.",
|
||||
"scan": {
|
||||
"title": "Pindai"
|
||||
},
|
||||
"setup_otp": "Siapkan OTP",
|
||||
"title": "Otentikasi Dua-faktor",
|
||||
"verify": {
|
||||
"desc": "Untuk mengaktifkan otentikasi dua-faktor, masukkan kode dari aplikasi dua-faktor Anda:"
|
||||
"desc": "Untuk mengaktifkan otentikasi dua-faktor, masukkan kode dari aplikasi dua-faktor kamu:"
|
||||
},
|
||||
"waiting_a_recovery_codes": "Menerima kode cadangan…",
|
||||
"warning_of_generate_new_codes": "Ketika Anda menghasilkan kode pemulihan baru, kode lama Anda berhenti bekerja."
|
||||
"warning_of_generate_new_codes": "Ketika kamu menghasilkan kode pemulihan baru, kode lama kamu berhenti bekerja."
|
||||
},
|
||||
"more_settings": "Lebih banyak pengaturan",
|
||||
"mutes_and_blocks": "Bisuan dan Blokiran",
|
||||
|
@ -372,21 +636,21 @@
|
|||
},
|
||||
"profile_tab": "Profil",
|
||||
"reply_visibility_all": "Tampilkan semua balasan",
|
||||
"reply_visibility_following": "Hanya tampilkan balasan yang ditujukan kepada saya atau orang yang saya ikuti",
|
||||
"reply_visibility_following_short": "Tampilkan balasan ke orang yang saya ikuti",
|
||||
"reply_visibility_self": "Hanya tampilkan balasan yang ditujukan kepada saya",
|
||||
"reply_visibility_following": "Hanya tampilkan balasan yang ditujukan kepadaku atau orang yang aku ikuti",
|
||||
"reply_visibility_following_short": "Tampilkan balasan ke orang yang aku ikuti",
|
||||
"reply_visibility_self": "Hanya tampilkan balasan yang ditujukan kepadaku",
|
||||
"save": "Simpan perubahan",
|
||||
"saving_err": "Terjadi kesalahan ketika menyimpan pengaturan",
|
||||
"saving_ok": "Pengaturan disimpan",
|
||||
"search_user_to_block": "Cari siapa yang Anda ingin blokir",
|
||||
"search_user_to_mute": "Cari siapa yang ingin Anda bisukan",
|
||||
"search_user_to_block": "Cari siapa yang ingin kamu blokir",
|
||||
"search_user_to_mute": "Cari siapa yang ingin kamu bisukan",
|
||||
"security": "Keamanan",
|
||||
"security_tab": "Keamanan",
|
||||
"set_new_avatar": "Tetapkan avatar baru",
|
||||
"set_new_profile_background": "Tetapkan latar belakang profil baru",
|
||||
"settings": "Pengaturan",
|
||||
"show_admin_badge": "Tampilkan lencana \"Admin\" di profil saya",
|
||||
"show_moderator_badge": "Tampilkan lencana \"Moderator\" di profil saya",
|
||||
"show_admin_badge": "Tampilkan lencana \"Admin\" di profilku",
|
||||
"show_moderator_badge": "Tampilkan lencana \"Moderator\" di profilku",
|
||||
"style": {
|
||||
"advanced_colors": {
|
||||
"_tab_label": "Lanjutan",
|
||||
|
@ -429,7 +693,7 @@
|
|||
},
|
||||
"preview": {
|
||||
"button": "Tombol",
|
||||
"checkbox": "Saya telah membaca sekilas syarat dan ketentuan",
|
||||
"checkbox": "Aku telah membaca sekilas syarat dan ketentuan",
|
||||
"error": "Contoh kesalahan",
|
||||
"faint_link": "manual berguna",
|
||||
"fine_print": "Baca {0} kami untuk belajar sesuatu yang tak ada gunanya!",
|
||||
|
@ -447,9 +711,9 @@
|
|||
"switcher": {
|
||||
"help": {
|
||||
"fe_upgraded": "Mesin tema PleromaFE diperbarui setelah pembaruan versi.",
|
||||
"future_version_imported": "Berkas yang Anda impor dibuat pada versi FE yang lebih baru.",
|
||||
"older_version_imported": "Berkas yang Anda impor dibuat pada versi FE yang lebih lama.",
|
||||
"upgraded_from_v2": "PleromaFE telah diperbarui, tema dapat terlihat sedikit berbeda dari apa yang Anda ingat."
|
||||
"future_version_imported": "Berkas yang kamu impor dibuat pada versi FE yang lebih baru.",
|
||||
"older_version_imported": "Berkas yang kamu impor dibuat pada versi FE yang lebih lama.",
|
||||
"upgraded_from_v2": "PleromaFE telah diperbarui, tema dapat terlihat sedikit berbeda dari apa yang kamu ingat."
|
||||
},
|
||||
"load_theme": "Muat tema",
|
||||
"use_snapshot": "Versi lama",
|
||||
|
@ -481,7 +745,7 @@
|
|||
},
|
||||
"status": {
|
||||
"delete": "Hapus status",
|
||||
"delete_confirm": "Apakah Anda benar-benar ingin menghapus status ini?",
|
||||
"delete_confirm": "Apakah kamu benar-benar ingin menghapus postingan ini?",
|
||||
"favorites": "Favorit",
|
||||
"hide_content": "",
|
||||
"mute_conversation": "Bisukan percakapan",
|
||||
|
@ -524,7 +788,7 @@
|
|||
"conversation": "Percakapan",
|
||||
"error": "Terjadi kesalahan memuat linimasa: {0}",
|
||||
"no_more_statuses": "Tidak ada status lagi",
|
||||
"no_retweet_hint": "Postingan ditandai sebagai hanya-pengikut atau langsung dan tidak dapat diulang",
|
||||
"no_retweet_hint": "Postingan ditandai sebagai hanya-pengikut atau langsung dan tidak dapat diulang atau dikutip",
|
||||
"no_statuses": "Tidak ada status",
|
||||
"reload": "Muat ulang",
|
||||
"repeated": "diulangi"
|
||||
|
@ -576,10 +840,10 @@
|
|||
"followees": "Mengikuti",
|
||||
"followers": "Pengikut",
|
||||
"following": "Diikuti!",
|
||||
"follows_you": "Mengikuti Anda!",
|
||||
"follows_you": "Mengikuti kamu!",
|
||||
"hidden": "Disembunyikan",
|
||||
"hide_repeats": "Sembunyikan ulangan",
|
||||
"its_you": "Ini Anda!",
|
||||
"its_you": "Ini kamu!",
|
||||
"media": "Media",
|
||||
"mention": "Sebut",
|
||||
"message": "Kirimkan pesan",
|
||||
|
@ -599,10 +863,10 @@
|
|||
"timeline_title": "Linimasa pengguna"
|
||||
},
|
||||
"user_reporting": {
|
||||
"add_comment_description": "Laporan ini akan dikirim ke moderator instansi Anda. Anda dapat menyediakan penjelasan mengapa Anda melaporkan akun ini di bawah:",
|
||||
"add_comment_description": "Laporan ini akan dikirim ke moderator instansi kamu. Kamu dapat menyediakan penjelasan mengapa kamu melaporkan akun ini di bawah:",
|
||||
"additional_comments": "Komentar tambahan",
|
||||
"forward_description": "Akun ini berada di server lain. Kirim salinan dari laporannya juga?",
|
||||
"generic_error": "Sebuah kesalahan terjadi ketika memproses permintaan Anda.",
|
||||
"generic_error": "Sebuah kesalahan terjadi ketika memproses permintaan kamu.",
|
||||
"submit": "Kirim",
|
||||
"title": "Melaporkan {0}"
|
||||
},
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
{
|
||||
"about": {
|
||||
"bubble_instances": "ローカルバブルインスタンス",
|
||||
"mrf": {
|
||||
"federation": "フェデレーション",
|
||||
"keyword": {
|
||||
"ftl_removal": "「せつぞくしているすべてのネットワーク」タイムラインからのぞく",
|
||||
"is_replaced_by": "→",
|
||||
"keyword_policies": "キーワードポリシー",
|
||||
"reject": "おことわり",
|
||||
"replace": "おきかえ"
|
||||
},
|
||||
"mrf_policies": "ゆうこうなMRFポリシー",
|
||||
"mrf_policies_desc": "MRFポリシーは、このインスタンスのフェデレーションのふるまいを、いじります。これらのMRFポリシーがゆうこうになっています:",
|
||||
"simple": {
|
||||
"accept": "うけいれ",
|
||||
"accept_desc": "このインスンスは、これらのインスタンスからのメッセージのみをうけいれます:",
|
||||
"ftl_removal": "「つながっているすべてのネットワーク」タイムラインからのぞく",
|
||||
"ftl_removal_desc": "このインスタンスは、つながっているすべてのネットワーク」タイムラインから、これらのインスタンスを、とりのぞきます:",
|
||||
"ftl_removal_desc": "このインスタンスは、「つながっているすべてのネットワーク」タイムラインから、これらのインスタンスを、とりのぞきます:",
|
||||
"instance": "インスタンス",
|
||||
"media_nsfw": "メディアをすべてセンシティブにする",
|
||||
"media_nsfw_desc": "このインスタンスは、これらのインスタンスからおくられてきたメディアを、すべて、センシティブにマークします:",
|
||||
"media_removal": "メディアをのぞく",
|
||||
"media_removal_desc": "このインスタンスは、これらのインスタンスからおくられてきたメディアを、とりのぞきます:",
|
||||
"not_applicable": "なし",
|
||||
"quarantine": "けんえき",
|
||||
"quarantine_desc": "このインスタンスは、これらのインスタンスに、パブリックなとうこうのみを、おくります:",
|
||||
"quarantine_desc": "このインスタンスは、これらのインスタンスに、とうこうをおくりません:",
|
||||
"reason": "りゆう",
|
||||
"reject": "おことわり",
|
||||
"reject_desc": "このインスタンスは、これらのインスタンスからのメッセージをうけいれません:",
|
||||
"simple_policies": "インスタンスのポリシー"
|
||||
|
@ -22,6 +33,49 @@
|
|||
},
|
||||
"staff": "スタッフ"
|
||||
},
|
||||
"announcements": {
|
||||
"all_day_prompt": "いちにちじゅう",
|
||||
"cancel_edit_action": "キャンセル",
|
||||
"close_error": "とじる",
|
||||
"delete_action": "けす",
|
||||
"edit_action": "へんしゅう",
|
||||
"end_time_display": "{time} におわります",
|
||||
"end_time_prompt": "おわるじかん: ",
|
||||
"inactive_message": "このおしらせは、アクティブではありません",
|
||||
"mark_as_read_action": "よんだ!",
|
||||
"page_header": "おしらせ",
|
||||
"post_action": "とうこう",
|
||||
"post_error": "エラーになりました: {error}",
|
||||
"post_form_header": "おしらせする",
|
||||
"post_placeholder": "おしらせのほんぶん",
|
||||
"published_time_display": "{time} に、おしらせされました",
|
||||
"start_time_display": "{time} から、はじまります",
|
||||
"start_time_prompt": "はじまるじかん: ",
|
||||
"submit_edit_action": "そうしん",
|
||||
"title": "おしらせ"
|
||||
},
|
||||
"chats": {
|
||||
"chats": "チャット",
|
||||
"delete": "けす",
|
||||
"delete_confirm": "ほんとうに、このメッセージを、けしてもいいですか?",
|
||||
"empty_chat_list_placeholder": "チャットはありません。あたらしく、チャットをはじみてみましょう!",
|
||||
"empty_message_error": "からっぽのメッセージは、おくれません",
|
||||
"error_loading_chat": "チャットをよみこむことが、できなかったかもしれません。",
|
||||
"error_sending_message": "メッセージをおくることが、できなかったかもしれません。",
|
||||
"message_user": "{nickname} にメッセージ",
|
||||
"more": "つづき",
|
||||
"new": "あたらしいチャット",
|
||||
"you": "あなた:"
|
||||
},
|
||||
"display_date": {
|
||||
"today": "きょう"
|
||||
},
|
||||
"domain_mute_card": {
|
||||
"mute": "ミュート",
|
||||
"mute_progress": "ミュートしています…",
|
||||
"unmute": "ミュートをやめる",
|
||||
"unmute_progress": "ミュートをとりけしています…"
|
||||
},
|
||||
"emoji": {
|
||||
"add_emoji": "えもじをうちこむ",
|
||||
"custom": "カスタムえもじ",
|
||||
|
@ -29,6 +83,7 @@
|
|||
"keep_open": "ピッカーをあけたままにする",
|
||||
"load_all": "すべてのえもじをロード ({emojiAmount} こあります)",
|
||||
"load_all_hint": "はじめの {saneAmount} このえもじだけがロードされています。すべてのえもじをロードすると、パフォーマンスがわるくなるかもしれません。",
|
||||
"recent": "さいきんつかった",
|
||||
"search_emoji": "えもじをさがす",
|
||||
"stickers": "ステッカー",
|
||||
"unicode": "ユニコードえもじ"
|
||||
|
@ -42,8 +97,15 @@
|
|||
"scope_options": "こうかいはんいせんたく",
|
||||
"text_limit": "もじのかず",
|
||||
"title": "ゆうこうなきのう",
|
||||
"upload_limit": "ファイルのおおきさのじょうげん",
|
||||
"who_to_follow": "おすすめユーザー"
|
||||
},
|
||||
"file_type": {
|
||||
"audio": "おんせい",
|
||||
"file": "ファイル",
|
||||
"image": "がぞう",
|
||||
"video": "ビデオ"
|
||||
},
|
||||
"finder": {
|
||||
"error_fetching_user": "ユーザーけんさくがエラーになりました",
|
||||
"find_user": "ユーザーをさがす"
|
||||
|
@ -51,12 +113,32 @@
|
|||
"general": {
|
||||
"apply": "てきよう",
|
||||
"cancel": "キャンセル",
|
||||
"close": "とじる",
|
||||
"confirm": "たしかめる",
|
||||
"disable": "なし",
|
||||
"dismiss": "わすれる",
|
||||
"enable": "あり",
|
||||
"error_retry": "もういちど、ためしてください",
|
||||
"flash_content": "クリックすると、Ruffle をつかって、フラッシュさくひんをひょうじします。(うまくうごかないかもしれません)",
|
||||
"flash_fail": "フラッシュさくひんのロードに、しっぱいしました。コンソールに、くわしいことがかかれています。",
|
||||
"flash_security": "フラッシュさくひんは、あなたのコンピューターに、あぶないことをしてくるかもしれないので、ちゅういしてください。",
|
||||
"generic_error": "エラーになりました",
|
||||
"loading": "ロードしています…",
|
||||
"more": "つづき",
|
||||
"optional": "かかなくてもよい",
|
||||
"peek": "かくす",
|
||||
"retry": "もういちど、ためしてください",
|
||||
"role": {
|
||||
"admin": "アドミン",
|
||||
"moderator": "モデレーター"
|
||||
},
|
||||
"scope_in_timeline": {
|
||||
"direct": "ダイレクト",
|
||||
"local": "ローカル: このとうこうは、このインスタンスのユーザーだけが、みることができます",
|
||||
"private": "フォロワーげんてい",
|
||||
"public": "パブリック",
|
||||
"unlisted": "アンリステッド"
|
||||
},
|
||||
"show_less": "たたむ",
|
||||
"show_more": "つづきをみる",
|
||||
"submit": "そうしん",
|
||||
|
@ -76,7 +158,86 @@
|
|||
"interactions": {
|
||||
"favs_repeats": "リピートとおきにいり",
|
||||
"follows": "あたらしいフォロー",
|
||||
"load_older": "ふるいやりとりをみる"
|
||||
"load_older": "ふるいやりとりをみる",
|
||||
"moves": "ユーザーをひっこしする"
|
||||
},
|
||||
"languages": {
|
||||
"ar": "アラビアご",
|
||||
"az": "アゼルバイジャンご",
|
||||
"bg": "ブルガリアご",
|
||||
"cs": "チェコご",
|
||||
"da": "デンマークご",
|
||||
"de": "ドイツご",
|
||||
"el": "ギリシャご",
|
||||
"en": "えいご",
|
||||
"eo": "エスご",
|
||||
"es": "スペインご",
|
||||
"fa": "ペルシャご",
|
||||
"fi": "フィンランドご",
|
||||
"fr": "フランスご",
|
||||
"ga": "アイルランドご",
|
||||
"he": "ヘブライご",
|
||||
"hi": "ヒンディーご",
|
||||
"hu": "ハンガリーご",
|
||||
"id": "インドネシアご",
|
||||
"it": "イタリアご",
|
||||
"ja": "にほんご",
|
||||
"ko": "かんこくご",
|
||||
"lt": "リトアニアご",
|
||||
"lv": "ラトビアご",
|
||||
"nl": "オランダご",
|
||||
"pl": "ポーランドご",
|
||||
"pt": "ポルトガルご",
|
||||
"ru": "ロシアご",
|
||||
"sk": "スロバキアご",
|
||||
"sv": "スウェーデンご",
|
||||
"tr": "トルコご",
|
||||
"translated_from": {
|
||||
"ar": "@:languages.ar から、ほんやくされました",
|
||||
"az": "@:languages.az から、ほんやくされました",
|
||||
"bg": "@:languages.bg から、ほんやくされました",
|
||||
"cs": "@:languages.cs から、ほんやくされました",
|
||||
"da": "@:languages.da から、ほんやくされました",
|
||||
"de": "@:languages.de から、ほんやくされました",
|
||||
"el": "@:languages.el から、ほんやくされました",
|
||||
"en": "@:languages.en から、ほんやくされました",
|
||||
"eo": "@:languages.eo から、ほんやくされました",
|
||||
"es": "@:languages.es から、ほんやくされました",
|
||||
"fa": "@:languages.fa から、ほんやくされました",
|
||||
"fi": "@:languages.fi から、ほんやくされました",
|
||||
"fr": "@:languages.fr から、ほんやくされました",
|
||||
"ga": "@:languages.ga から、ほんやくされました",
|
||||
"he": "@:languages.he から、ほんやくされました",
|
||||
"hi": "@:languages.hi から、ほんやくされました",
|
||||
"hu": "@:languages.hu から、ほんやくされました",
|
||||
"id": "@:languages.id から、ほんやくされました",
|
||||
"it": "@:languages.it から、ほんやくされました",
|
||||
"ja": "@:languages.ja から、ほんやくされました",
|
||||
"ko": "@:languages.ko から、ほんやくされました",
|
||||
"lt": "@:languages.lt から、ほんやくされました",
|
||||
"lv": "@:languages.lv から、ほんやくされました",
|
||||
"nl": "@:languages.nl から、ほんやくされました",
|
||||
"pl": "@:languages.pl から、ほんやくされました",
|
||||
"pt": "@:languages.pt から、ほんやくされました",
|
||||
"ru": "@:languages.ru から、ほんやくされました",
|
||||
"sk": "@:languages.sk から、ほんやくされました",
|
||||
"sv": "@:languages.sv から、ほんやくされました",
|
||||
"tr": "@:languages.tr から、ほんやくされました",
|
||||
"uk": "@:languages.uk から、ほんやくされました",
|
||||
"zh": "@:languages.zh から、ほんやくされました"
|
||||
},
|
||||
"uk": "ウクライナご",
|
||||
"zh": "ちゅうごくご"
|
||||
},
|
||||
"lists": {
|
||||
"create": "つくる",
|
||||
"delete": "けす",
|
||||
"following_only": "フォローしているユーザーのみ",
|
||||
"lists": "リスト",
|
||||
"new": "リストをつくる",
|
||||
"save": "セーブ",
|
||||
"search": "ユーザーをさがす",
|
||||
"title": "リストのなまえ"
|
||||
},
|
||||
"login": {
|
||||
"authentication_code": "にんしょうコード",
|
||||
|
@ -90,41 +251,90 @@
|
|||
"hint": "はなしあいにくわわるには、ログインしてください",
|
||||
"login": "ログイン",
|
||||
"logout": "ログアウト",
|
||||
"logout_confirm": "ほんとうに、ログアウトしてもいいですか?",
|
||||
"logout_confirm_accept_button": "ログアウト",
|
||||
"logout_confirm_cancel_button": "キャンセル",
|
||||
"logout_confirm_title": "ログアウト",
|
||||
"password": "パスワード",
|
||||
"placeholder": "れい: lain",
|
||||
"placeholder": "ユーザーめい",
|
||||
"recovery_code": "リカバリーコード",
|
||||
"register": "はじめる",
|
||||
"username": "ユーザーめい"
|
||||
},
|
||||
"media_modal": {
|
||||
"counter": "{current} / {total}",
|
||||
"hide": "とじる",
|
||||
"next": "つぎ",
|
||||
"previous": "まえ"
|
||||
},
|
||||
"moderation": {
|
||||
"moderation": "モデレーション",
|
||||
"reports": {
|
||||
"add_note": "メモする",
|
||||
"close": "とじる",
|
||||
"delete_note": "けす",
|
||||
"delete_note_accept": "けす",
|
||||
"delete_note_cancel": "キャンセル",
|
||||
"delete_note_confirm": "ほんとうに、このメモをけしてもいいですか?",
|
||||
"delete_note_title": "かくにんしてください",
|
||||
"no_content": "せつめいはありません",
|
||||
"no_reports": "つうほうはありません",
|
||||
"note_placeholder": "メモする",
|
||||
"notes": "{ count }こ",
|
||||
"reopen": "ひらきなおす",
|
||||
"report": "つうほう:",
|
||||
"reports": "つうほう",
|
||||
"resolve": "かいけつ",
|
||||
"show_closed": "かいけつしたつうほうをみる",
|
||||
"statuses": "{ count } こ",
|
||||
"tag_policy_notice": "とうこうをせいげんするには、TagPolicy MRF をゆうこうにしてください",
|
||||
"tags": "とうこうをせいげんする"
|
||||
},
|
||||
"statuses": "とうこう",
|
||||
"users": "ユーザー"
|
||||
},
|
||||
"nav": {
|
||||
"about": "これはなに?",
|
||||
"administration": "アドミニストレーション",
|
||||
"announcements": "おしらせ",
|
||||
"back": "もどる",
|
||||
"bookmarks": "ブックマーク",
|
||||
"bubble_timeline": "バブルタイムライン",
|
||||
"bubble_timeline_description": "アドミンがおすすめするインスタンスからのとうこう",
|
||||
"chats": "チャット",
|
||||
"dms": "ダイレクトメッセージ",
|
||||
"friend_requests": "フォローリクエスト",
|
||||
"home_timeline": "ホームタイムライン",
|
||||
"home_timeline_description": "フォローしているユーザーのとうこう",
|
||||
"interactions": "やりとり",
|
||||
"lists": "リスト",
|
||||
"mentions": "メンション",
|
||||
"moderation": "モデレーション",
|
||||
"preferences": "せってい",
|
||||
"public_timeline_description": "このインスタンスからの、パブリックなとうこう",
|
||||
"public_tl": "パブリックタイムライン",
|
||||
"search": "さがす",
|
||||
"timeline": "タイムライン",
|
||||
"timelines": "タイムライン",
|
||||
"twkn": "つながっているすべてのネットワーク",
|
||||
"twkn_timeline_description": "つながっているすべてのネットワークからのとうこう",
|
||||
"user_search": "ユーザーをさがす",
|
||||
"who_to_follow": "おすすめユーザー"
|
||||
},
|
||||
"notifications": {
|
||||
"broken_favorite": "ステータスがみつかりません。さがしています…",
|
||||
"favorited_you": "あなたのステータスがおきにいりされました",
|
||||
"broken_favorite": "とうこうがみつかりません。さがしています…",
|
||||
"error": "つうちのしゅとくがエラーになりました: {0}",
|
||||
"favorited_you": "あなたのとうこうが、おきにいりされました",
|
||||
"follow_request": "フォローリクエストされました",
|
||||
"followed_you": "フォローされました",
|
||||
"load_older": "ふるいつうちをみる",
|
||||
"migrated_to": "インスタンスをひっこしました",
|
||||
"no_more_notifications": "つうちはありません",
|
||||
"notifications": "つうち",
|
||||
"poll_ended": "いれふだがおわりました",
|
||||
"reacted_with": "{0} でリアクションされました",
|
||||
"read": "よんだ!",
|
||||
"repeated_you": "あなたのステータスがリピートされました"
|
||||
"repeated_you": "あなたのとうこうが、リピートされました"
|
||||
},
|
||||
"password_reset": {
|
||||
"check_email": "パスワードをリセットするためのリンクがかかれたメールが、とどいているかどうか、みてください。",
|
||||
|
@ -147,49 +357,72 @@
|
|||
"multiple_choices": "いくつでもえらべる",
|
||||
"not_enough_options": "ユニークなオプションが、たりません",
|
||||
"option": "オプション",
|
||||
"people_voted_count": "{count} にんが、ふだをいれています",
|
||||
"single_choice": "ひとつえらぶ",
|
||||
"type": "いれふだのかた",
|
||||
"vote": "ふだをいれる",
|
||||
"votes": "いれふだ"
|
||||
"votes": "いれふだ",
|
||||
"votes_count": "{count} ふだ"
|
||||
},
|
||||
"post_status": {
|
||||
"account_not_locked_warning": "あなたのアカウントは {0} ではありません。あなたをフォローすれば、だれでも、フォロワーげんていのステータスをよむことができます。",
|
||||
"account_not_locked_warning": "あなたのアカウントは {0} ではありません。あなたをフォローすれば、だれでも、フォロワーげんていのとうこうをよむことができます。",
|
||||
"account_not_locked_warning_link": "ロックされたアカウント",
|
||||
"attachments_sensitive": "ファイルをNSFWにする",
|
||||
"content_type": {
|
||||
"text/bbcode": "BBCode",
|
||||
"text/html": "HTML",
|
||||
"text/markdown": "Markdown",
|
||||
"text/plain": "プレーンテキスト"
|
||||
"text/plain": "プレーンテキスト",
|
||||
"text/x.misskeymarkdown": "MFM"
|
||||
},
|
||||
"content_warning": "せつめい (かかなくてもよい)",
|
||||
"content_warning": "ちゅういがき (かかなくてもよい)",
|
||||
"default": "はねだくうこうに、つきました。",
|
||||
"direct_warning_to_all": "このとうこうは、メンションされたすべてのユーザーが、みることができます。",
|
||||
"direct_warning_to_first_only": "このとうこうは、メッセージのはじめでメンションされたユーザーだけが、みることができます。",
|
||||
"edit_remote_warning": "へんしゅうしたとうこうは、ほかのインスタンスに、はんえいされないことがあります!",
|
||||
"edit_status": "へんしゅう",
|
||||
"edit_unsupported_warning": "いれふだとメンションは、へんしゅうでかえることができません。",
|
||||
"empty_status_error": "からっぽのとうこうは、おくることができません",
|
||||
"media_description": "メディアのせつめい",
|
||||
"media_description_error": "メディアのアップデートにしっぱいしました。もういちど、ためしてください",
|
||||
"media_not_sensitive_warning": "ちゅういがきがついていますが、NSFWはついていません!",
|
||||
"new_status": "とうこうする",
|
||||
"post": "とうこう",
|
||||
"posting": "とうこう",
|
||||
"preview": "プレビュー",
|
||||
"preview_empty": "からっぽです",
|
||||
"scope": {
|
||||
"direct": "ダイレクト: メンションされたユーザーのみにとどきます",
|
||||
"local": "ローカル: パブリックタイムラインにとどきますが、ほかのインスタンスにはとどきません",
|
||||
"private": "フォロワーげんてい: フォロワーのみにとどきます",
|
||||
"public": "パブリック: パブリックタイムラインにとどきます",
|
||||
"unlisted": "アンリステッド: パブリックタイムラインにとどきません"
|
||||
},
|
||||
"scope_notice": {
|
||||
"local": "このとうこうは、このインスタンスのユーザーだけが、みることができます",
|
||||
"private": "このとうこうは、あなたのフォロワーだけが、みることができます",
|
||||
"public": "このとうこうは、だれでもみることができます",
|
||||
"unlisted": "このとうこうは、パブリックタイムラインと、つながっているすべてのネットワークでは、みることができません"
|
||||
}
|
||||
},
|
||||
"registration": {
|
||||
"awaiting_email_confirmation": "あなたのメールアドレスに、メールをおくりました。メールをかくにんして、とうろくをかんりょうさせてください。",
|
||||
"awaiting_email_confirmation_title": "メールをかくにんするのをまっています",
|
||||
"bio": "プロフィール",
|
||||
"bio_placeholder": "れい:\nごきげんよう。わたしはれいん。\nわたしはアニメのおんなのこで、にほんのベッドタウンにすんでいます。ワイヤードで、わたしにあったことが、あるかもしれませんね。",
|
||||
"captcha": "CAPTCHA",
|
||||
"email": "Eメール",
|
||||
"email_language": "サーバーからのメールは、どのことばで、かいてほしいですか?",
|
||||
"fullname": "スクリーンネーム",
|
||||
"fullname_placeholder": "れい: いわくら れいん",
|
||||
"new_captcha": "もじがよめないときは、がぞうをクリックすると、あたらしいがぞうになります",
|
||||
"password_confirm": "パスワードのかくにん",
|
||||
"reason": "とうろくしたいりゆう",
|
||||
"reason_placeholder": "このインスタンスは、しゅどうで、とうろくをうけつけています。\nとうろくしたいりゆうを、アドミニストレーターにおしえてください。",
|
||||
"register": "はじめる",
|
||||
"registration": "はじめる",
|
||||
"request_sent": "とうろくリクエストをおくりました。とうろくがうけいれられると、メールがとどきます。",
|
||||
"request_sent_title": "とうろくリクエストをおくりました",
|
||||
"token": "しょうたいトークン",
|
||||
"username_placeholder": "れい: lain",
|
||||
"validations": {
|
||||
|
@ -217,6 +450,20 @@
|
|||
"select_all": "すべてえらぶ"
|
||||
},
|
||||
"settings": {
|
||||
"accent": "アクセント",
|
||||
"account_alias": "アカウントのエイリアス",
|
||||
"account_alias_table_head": "エイリアス",
|
||||
"account_backup": "アカウントのバックアップ",
|
||||
"account_backup_description": "あなたのアカウントのじょうほうと、とうこうの、アーカイブをダウンロードできます。しかし、いまのところは、バックアップを Pleromaのアカウントにインポートすることはできません。",
|
||||
"account_backup_table_head": "バックアップ",
|
||||
"account_privacy": "プライバシー",
|
||||
"add_alias_error": "エイリアスのついかがエラーになりました: {error}",
|
||||
"add_backup": "あたらしいバックアップをつくる",
|
||||
"add_backup_error": "バックアップのついかがエラーになりました: {error}",
|
||||
"added_alias": "エイリアスをついかしました。",
|
||||
"added_backup": "バックアップをつくりました。",
|
||||
"allow_following_move": "フォローしているアカウントがひっこしたときに、じどうでフォローしてもよい",
|
||||
"always_show_post_button": "みぎしたのとうこうボタンをいつでもひょうじする",
|
||||
"app_name": "アプリのなまえ",
|
||||
"attachmentRadius": "ファイル",
|
||||
"attachments": "ファイル",
|
||||
|
@ -226,6 +473,7 @@
|
|||
"avatarRadius": "アバター",
|
||||
"avatar_size_instruction": "アバターのおおきさは、150×150ピクセルか、それよりもおおきくするといいです。",
|
||||
"background": "バックグラウンド",
|
||||
"backup_not_ready": "このバックアップは、まだ、かんせいしていません。",
|
||||
"bio": "プロフィール",
|
||||
"block_export": "ブロックのエクスポート",
|
||||
"block_export_button": "ブロックをCSVファイルにエクスポート",
|
||||
|
@ -233,6 +481,7 @@
|
|||
"block_import_error": "ブロックのインポートがエラーになりました",
|
||||
"blocks_imported": "ブロックをインポートしました! じっさいにブロックするまでには、もうしばらくかかります。",
|
||||
"blocks_tab": "ブロック",
|
||||
"bot": "これは bot アカウントです",
|
||||
"btnRadius": "ボタン",
|
||||
"cBlue": "リプライとフォロー",
|
||||
"cGreen": "リピート",
|
||||
|
@ -244,11 +493,29 @@
|
|||
"change_password_error": "パスワードをかえることが、できなかったかもしれません。",
|
||||
"changed_email": "メールアドレスをかえることができました!",
|
||||
"changed_password": "パスワードが、かわりました!",
|
||||
"chatMessageRadius": "チャットメッセージ",
|
||||
"checkboxRadius": "チェックボックス",
|
||||
"collapse_subject": "せつめいのあるとうこうをたたむ",
|
||||
"collapse_subject": "ちゅういがきのあるとうこうをたたむ",
|
||||
"columns": "カラム",
|
||||
"composing": "とうこう",
|
||||
"confirm_dialogs": "いつ、かくにんがめんをひょうじしますか:",
|
||||
"confirm_dialogs_approve_follow": "フォローリクエストをうけいれるとき",
|
||||
"confirm_dialogs_block": "だれかをブロックするとき",
|
||||
"confirm_dialogs_delete": "とうこうをけすとき",
|
||||
"confirm_dialogs_deny_follow": "フォローリクエストをおことわりするとき",
|
||||
"confirm_dialogs_mute": "だれかをミュートするとき",
|
||||
"confirm_dialogs_repeat": "とうこうをリピートするとき",
|
||||
"confirm_dialogs_unfollow": "だれかのフォローをやめるとき",
|
||||
"confirm_new_password": "あたらしいパスワードのかくにん",
|
||||
"confirmation_dialogs": "かくにんがめんのせってい",
|
||||
"conversation_display": "スレッドのみため",
|
||||
"conversation_display_linear": "リニア",
|
||||
"conversation_display_tree": "ツリー",
|
||||
"conversation_other_replies_button": "「ほかのへんしん」ボタンをひょうじするばしょ",
|
||||
"conversation_other_replies_button_below": "とうこうのした",
|
||||
"conversation_other_replies_button_inside": "とうこうのうちがわ",
|
||||
"current_avatar": "いまのアバター",
|
||||
"current_mascot": "いまのマスコット",
|
||||
"current_password": "いまのパスワード",
|
||||
"data_import_export_tab": "インポートとエクスポート",
|
||||
"default_vis": "デフォルトのこうかいはんい",
|
||||
|
@ -256,12 +523,18 @@
|
|||
"delete_account_description": "あなたのアカウントとメッセージが、きえます。",
|
||||
"delete_account_error": "アカウントをけすことが、できなかったかもしれません。インスタンスのアドミニストレーターに、おといあわせください。",
|
||||
"delete_account_instructions": "ほんとうにアカウントをけしてもいいなら、パスワードをかいてください。",
|
||||
"disable_sticky_headers": "カラムヘッダーを、がめんのいちばんうえにくっつけない",
|
||||
"discoverable": "けんさくなどのサービスで、このアカウントをみつけてもよい",
|
||||
"domain_mutes": "ドメイン",
|
||||
"download_backup": "ダウンロード",
|
||||
"email_language": "メールのことば",
|
||||
"emoji_reactions_on_timeline": "えもじのリアクションをタイムラインにひょうじする",
|
||||
"enable_web_push_notifications": "ウェブプッシュつうちをゆるす",
|
||||
"enter_current_password_to_confirm": "あなたのアイデンティティをたしかめるため、あなたのいまのパスワードをかいてください",
|
||||
"expert_mode": "こまかいせっていをひょうじ",
|
||||
"export_theme": "セーブ",
|
||||
"filtering": "フィルタリング",
|
||||
"filtering_explanation": "これらのことばをふくむすべてのものがミュートされます。1ぎょうに1つのことばをかいてください",
|
||||
"filtering_explanation": "これらのことばをふくむすべてのとうこうがミュートされます。1ぎょうに1つのことばをかいてください",
|
||||
"follow_export": "フォローのエクスポート",
|
||||
"follow_export_button": "エクスポート",
|
||||
"follow_import": "フォローインポート",
|
||||
|
@ -329,6 +602,7 @@
|
|||
"no_rich_text_description": "リッチテキストをつかわない",
|
||||
"notification_blocks": "ブロックしているユーザーからのつうちは、すべてとまります。",
|
||||
"notification_mutes": "あるユーザーからのつうちをとめるには、ミュートしてください。",
|
||||
"notification_setting_hide_if_cw": "ちゅういがきがあるとうこうのないようを、つうちからみえないようにする",
|
||||
"notification_visibility": "ひょうじするつうち",
|
||||
"notification_visibility_follows": "フォロー",
|
||||
"notification_visibility_likes": "おきにいり",
|
||||
|
@ -361,6 +635,7 @@
|
|||
"search_user_to_mute": "ミュートしたいひとを、ここでけんさくできます",
|
||||
"security": "セキュリティ",
|
||||
"security_tab": "セキュリティ",
|
||||
"sensitive_if_subject": "ちゅういがきを、つけたときに、がぞうをじどうてきにNSFWにする",
|
||||
"set_new_avatar": "あたらしいアバターをせっていする",
|
||||
"set_new_profile_background": "あたらしいプロフィールのバックグラウンドをせっていする",
|
||||
"set_new_profile_banner": "あたらしいプロフィールバナーを設定する",
|
||||
|
@ -478,8 +753,8 @@
|
|||
"save_load_hint": "「のこす」オプションをONにすると、テーマをえらんだときとロードしたとき、いまのせっていをのこします。また、テーマをエクスポートするとき、これらのオプションをストアします。すべてのチェックボックスをOFFにすると、テーマをエクスポートしたとき、すべてのせっていをセーブします。"
|
||||
}
|
||||
},
|
||||
"subject_input_always_show": "サブジェクトフィールドをいつでもひょうじする",
|
||||
"subject_line_behavior": "リプライするときサブジェクトをコピーする",
|
||||
"subject_input_always_show": "ちゅういがきフィールドをいつでもひょうじする",
|
||||
"subject_line_behavior": "リプライするとき、ちゅういがきをコピーする",
|
||||
"subject_line_email": "メールふう: \"re: サブジェクト\"",
|
||||
"subject_line_mastodon": "マストドンふう: そのままコピー",
|
||||
"subject_line_noop": "コピーしない",
|
||||
|
@ -506,8 +781,8 @@
|
|||
}
|
||||
},
|
||||
"status": {
|
||||
"delete": "ステータスをけす",
|
||||
"delete_confirm": "ほんとうに、このステータスを、けしてもいいですか?",
|
||||
"delete": "とうこうをけす",
|
||||
"delete_confirm": "ほんとうに、このとうこうを、けしてもいいですか?",
|
||||
"favorites": "おきにいり",
|
||||
"mute_conversation": "スレッドをミュートする",
|
||||
"pin": "プロフィールにピンどめする",
|
||||
|
@ -515,6 +790,8 @@
|
|||
"repeats": "リピート",
|
||||
"replies_list": "へんしん:",
|
||||
"reply_to": "へんしん:",
|
||||
"translate": "ほんやく",
|
||||
"translated_from": "{language} から、ほんやくされました",
|
||||
"unmute_conversation": "スレッドをミュートするのをやめる",
|
||||
"unpin": "プロフィールにピンどめするのをやめる"
|
||||
},
|
||||
|
@ -543,7 +820,7 @@
|
|||
"timeline": {
|
||||
"collapse": "たたむ",
|
||||
"conversation": "スレッド",
|
||||
"load_older": "ふるいステータス",
|
||||
"load_older": "ふるいとうこう",
|
||||
"no_more_statuses": "これでおわりです",
|
||||
"no_retweet_hint": "とうこうを「フォロワーのみ」または「ダイレクト」にすると、リピートできなくなります",
|
||||
"no_statuses": "ありません",
|
||||
|
@ -611,16 +888,18 @@
|
|||
"media": "メディア",
|
||||
"mention": "メンション",
|
||||
"mute": "ミュート",
|
||||
"mute_domain": "ドメインをブロック",
|
||||
"mute_progress": "ミュートしています…",
|
||||
"muted": "ミュートしています!",
|
||||
"per_day": "/日",
|
||||
"remote_follow": "リモートフォロー",
|
||||
"report": "つうほう",
|
||||
"show_repeats": "リピートをみる",
|
||||
"statuses": "ステータス",
|
||||
"statuses": "とうこう",
|
||||
"subscribe": "サブスクライブ",
|
||||
"unblock": "ブロックをやめる",
|
||||
"unblock_progress": "ブロックをとりけしています…",
|
||||
"unfollow_confirm": "{user}のフォローをやめますか?",
|
||||
"unmute": "ミュートをやめる",
|
||||
"unmute_progress": "ミュートをとりけしています…",
|
||||
"unsubscribe": "サブスクライブをやめる"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue