-
+
**🌎 **[Sharkey](https://joinsharkey.org/)** is an open source, decentralized social media platform that's free forever! 🚀**
---
+
+
+
@@ -16,8 +19,8 @@
-
-
+
+
---
@@ -25,13 +28,13 @@
-
+
## ✨ Features
- **ActivityPub support**\
Not on Sharkey? No problem! Not only can Sharkey instances talk to each other, but you can make friends with people on other networks like Mastodon and Pixelfed!
- **Federated Backgrounds and Music status**\
-You can add a background to your profile as well as a music status via ListenBrainz, show everyone what music you are currently listening to
+You can add a background to your profile as well as a music status via ListenBrainz, show everyone what music you are currently listening too
- **Mastodon API**\
Sharkey implements the Mastodon API unlike normal Misskey
- **UI/UX Improvements**\
@@ -39,9 +42,9 @@ Sharkey makes some UI/UX improvements to make it easier to navigate
- **Sign-Up Approval**\
With Sharkey, you can enable sign-ups, subject to manual moderator approval and mandatory user-provided reasons for joining.
- **Rich Web UI**\
- Sharkey has a rich and easy to use Web UI!
- It is highly customizable, from changing the layout and adding widgets to making custom themes.
- Furthermore, plugins can be created using AiScript, an original programming language.
+ Sharkey has a rich and easy to use Web UI!
+ It is highly customizable, from changing the layout and adding widgets to making custom themes.
+ Furthermore, plugins can be created using AiScript, an original programming language.
- And much more...
diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
deleted file mode 100644
index c941de6643..0000000000
--- a/UPGRADE_NOTES.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Upgrade Notes
-
-## 2024.10.0
-
-### Hellspawns
-
-Sharkey versions before 2024.10 suffered from a bug in the "Mark instance as NSFW" feature.
-When a user from such an instance boosted a note, the boost would be converted to a hellspawn (pure renote with Content Warning).
-Hellspawns are buggy and do not properly federate, so it may be desirable to correct any that already exist in the database.
-The following script will correct any local or remote hellspawns in the database.
-
-```postgresql
-/* Remove "instance is marked as NSFW" hellspawns */
-UPDATE "note"
-SET "cw" = null
-WHERE
- "renoteId" IS NOT NULL
- AND "text" IS NULL
- AND "cw" = 'Instance is marked as NSFW'
- AND "replyId" IS NULL
- AND "hasPoll" = false
- AND "fileIds" = '{}';
-
-/* Fix legacy / user-created hellspawns */
-UPDATE "note"
-SET "text" = '.'
-WHERE
- "renoteId" IS NOT NULL
- AND "text" IS NULL
- AND "cw" IS NOT NULL
- AND "replyId" IS NULL
- AND "hasPoll" = false
- AND "fileIds" = '{}';
-```
-
-## 2024.9.0
-
-### Following Feed
-
-When upgrading an existing instance to version 2024.9.0, the Following Feed will initially be empty.
-The feed will gradually fill as new posts federate, but it may be desirable to back-fill the feed with existing data.
-This database script will populate the feed with the latest post of each type for all users, ensuring that data is fully populated after the update.
-Run this after migrations but before starting the instance.
-Warning: the script may take a long time to execute!
-
-```postgresql
-INSERT INTO latest_note (user_id, note_id, is_public, is_reply, is_quote)
-SELECT
- "userId" as user_id,
- id as note_id,
- visibility = 'public' AS is_public,
- "replyId" IS NOT NULL AS is_reply,
- (
- "renoteId" IS NOT NULL
- AND (
- text IS NOT NULL
- OR cw IS NOT NULL
- OR "replyId" IS NOT NULL
- OR "hasPoll"
- OR "fileIds" != '{}'
- )
- ) AS is_quote
-FROM note
-WHERE ( -- Exclude pure renotes (boosts)
- "renoteId" IS NULL
- OR text IS NOT NULL
- OR cw IS NOT NULL
- OR "replyId" IS NOT NULL
- OR "hasPoll"
- OR "fileIds" != '{}'
- )
-ORDER BY id DESC -- This part is very important: it ensures that we only load the *latest* notes of each type. Do not remove it!
-ON CONFLICT DO NOTHING; -- Any conflicts are guaranteed to be older notes that we can ignore.
-```
diff --git a/chart/files/default.yml b/chart/files/default.yml
index 97201aad66..9c81964736 100644
--- a/chart/files/default.yml
+++ b/chart/files/default.yml
@@ -124,14 +124,6 @@ redis:
# #prefix: example-prefix
# #db: 1
-#redisForReactions:
-# host: redis
-# port: 6379
-# #family: 0 # 0=Both, 4=IPv4, 6=IPv6
-# #pass: example-pass
-# #prefix: example-prefix
-# #db: 1
-
# ┌───────────────────────────┐
#───┘ MeiliSearch configuration └─────────────────────────────
@@ -160,22 +152,6 @@ redis:
# ID SETTINGS AFTER THAT!
id: "aidx"
-
-# ┌────────────────┐
-#───┘ Error tracking └──────────────────────────────────────────
-
-# Sentry is available for error tracking.
-# See the Sentry documentation for more details on options.
-
-#sentryForBackend:
-# enableNodeProfiling: true
-# options:
-# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
-
-#sentryForFrontend:
-# options:
-# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
-
# ┌─────────────────────┐
#───┘ Other configuration └─────────────────────────────────────
@@ -216,13 +192,8 @@ id: "aidx"
# Media Proxy
#mediaProxy: https://example.com/proxy
-# Sign outgoing ActivityPub GET request (default: true)
+# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true
-# Sign outgoing ActivityPub Activities (default: true)
-# Linked Data signatures are cryptographic signatures attached to each activity to provide proof of authenticity.
-# When using authorized fetch, this is often undesired as any signed activity can be forwarded to a blocked instance by relays and other instances.
-# This setting allows admins to disable LD signatures for increased privacy, at the expense of fewer relayed activities and additional inbound fetch (GET) requests.
-attachLdSignatureForRelays: true
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
checkActivityPubGetSignature: false
diff --git a/crowdin.yml b/crowdin.yml
index 0525ac7b0b..774ddc7a63 100644
--- a/crowdin.yml
+++ b/crowdin.yml
@@ -1,4 +1,4 @@
files:
- - source: /sharkey-locales/en-US.yml
- translation: /sharkey-locales/%locale%.yml
+ - source: /locales/ja-JP.yml
+ translation: /locales/%locale%.yml
update_option: update_as_unapproved
diff --git a/cypress/e2e/basic.cy.ts b/cypress/e2e/basic.cy.js
similarity index 98%
rename from cypress/e2e/basic.cy.ts
rename to cypress/e2e/basic.cy.js
index d2525e0a7d..604241d13c 100644
--- a/cypress/e2e/basic.cy.ts
+++ b/cypress/e2e/basic.cy.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
describe('Before setup instance', () => {
beforeEach(() => {
cy.resetState();
diff --git a/cypress/e2e/router.cy.ts b/cypress/e2e/router.cy.js
similarity index 91%
rename from cypress/e2e/router.cy.ts
rename to cypress/e2e/router.cy.js
index 8d8fb3af31..6de27be5f4 100644
--- a/cypress/e2e/router.cy.ts
+++ b/cypress/e2e/router.cy.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
describe('Router transition', () => {
describe('Redirect', () => {
// サーバの初期化。ルートのテストに関しては各describeごとに1度だけ実行で十分だと思う(使いまわした方が早い)
diff --git a/cypress/e2e/widgets.cy.ts b/cypress/e2e/widgets.cy.js
similarity index 95%
rename from cypress/e2e/widgets.cy.ts
rename to cypress/e2e/widgets.cy.js
index 847801a69f..df6ec8357d 100644
--- a/cypress/e2e/widgets.cy.ts
+++ b/cypress/e2e/widgets.cy.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
/* flaky
describe('After user signed in', () => {
beforeEach(() => {
diff --git a/cypress/support/commands.ts b/cypress/support/commands.js
similarity index 87%
rename from cypress/support/commands.ts
rename to cypress/support/commands.js
index 281f2e6ccd..91a4d7abe6 100644
--- a/cypress/support/commands.ts
+++ b/cypress/support/commands.js
@@ -30,13 +30,9 @@ Cypress.Commands.add('visitHome', () => {
})
Cypress.Commands.add('resetState', () => {
- // iframe.contentWindow.indexedDB.deleteDatabase() がchromeのバグで使用できないため、indexedDBを無効化している。
- // see https://github.com/misskey-dev/misskey/issues/13605#issuecomment-2053652123
- /*
- cy.window().then(win => {
+ cy.window(win => {
win.indexedDB.deleteDatabase('keyval-store');
});
- */
cy.request('POST', '/api/reset-db', {}).as('reset');
cy.get('@reset').its('status').should('equal', 204);
cy.reload(true);
diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.js
similarity index 100%
rename from cypress/support/e2e.ts
rename to cypress/support/e2e.js
diff --git a/cypress/support/index.ts b/cypress/support/index.ts
deleted file mode 100644
index c1bed21979..0000000000
--- a/cypress/support/index.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-declare global {
- namespace Cypress {
- interface Chainable {
- login(username: string, password: string): Chainable
;
-
- registerUser(
- username: string,
- password: string,
- isAdmin?: boolean
- ): Chainable;
-
- resetState(): Chainable;
-
- visitHome(): Chainable;
- }
- }
-}
-
-export {}
diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json
deleted file mode 100644
index 6fe7f32cc4..0000000000
--- a/cypress/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "compilerOptions": {
- "lib": ["dom", "es5"],
- "target": "es5",
- "types": ["cypress", "node"]
- },
- "include": ["./**/*.ts"]
-}
diff --git a/compose.local-db.yml b/docker-compose.local-db.yml
similarity index 98%
rename from compose.local-db.yml
rename to docker-compose.local-db.yml
index 3835cb23db..16ba4b49e1 100644
--- a/compose.local-db.yml
+++ b/docker-compose.local-db.yml
@@ -1,3 +1,5 @@
+version: "3"
+
# このconfigは、 dockerでMisskey本体を起動せず、 redisとpostgresql などだけを起動します
services:
diff --git a/compose_example.yml b/docker-compose_example.yml
similarity index 91%
rename from compose_example.yml
rename to docker-compose_example.yml
index 0db8b04dc6..647f6f0c77 100644
--- a/compose_example.yml
+++ b/docker-compose_example.yml
@@ -1,3 +1,5 @@
+version: "3"
+
services:
web:
# image: registry.activitypub.software/transfem-org/sharkey:latest
@@ -17,8 +19,6 @@ services:
- "3000:3000"
networks:
- shonk
- # env_file:
- # - .config/docker.env
volumes:
- ./files:/sharkey/files
- ./.config:/sharkey/.config:ro
@@ -53,7 +53,8 @@ services:
# restart: always
# image: mcaptcha/mcaptcha:latest
# networks:
-# shonk:
+# internal_network:
+# external_network:
# aliases:
# - localhost
# ports:
@@ -63,8 +64,6 @@ services:
# environment:
# PORT: 7493
# MCAPTCHA_redis_URL: "redis://mcaptcha_redis/"
-# MCAPTCHA_allow_registration: true
-# MCAPTCHA_server_DOMAIN: "example.tld"
# depends_on:
# db:
# condition: service_healthy
@@ -74,7 +73,7 @@ services:
# mcaptcha_redis:
# image: mcaptcha/cache:latest
# networks:
-# - shonk
+# - internal_network
# healthcheck:
# test: "redis-cli ping"
# interval: 5s
diff --git a/eslint/locale.js b/eslint/locale.js
deleted file mode 100644
index dbb807b714..0000000000
--- a/eslint/locale.js
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * SPDX-FileCopyrightText: dakkar and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
-*/
-
-/* This is a ESLint rule to report use of the `i18n.ts` and `i18n.tsx`
- * objects that reference translation items that don't actually exist
- * in the lexicon (the `locale/` files)
- */
-
-/* given a MemberExpression node, collects all the member names
- *
- * e.g. for a bit of code like `foo=one.two.three`, `collectMembers`
- * called on the node for `three` would return `['one', 'two',
- * 'three']`
- */
-function collectMembers(node) {
- if (!node) return [];
- if (node.type !== 'MemberExpression') return [];
- // this is something like `foo[bar]`
- if (node.computed) return [];
- return [ node.property.name, ...collectMembers(node.parent) ];
-}
-
-/* given an object and an array of names, recursively descends the
- * object via those names
- *
- * e.g. `walkDown({one:{two:{three:15}}},['one','two','three'])` would
- * return 15
- */
-function walkDown(locale, path) {
- if (!locale) return null;
- if (!path || path.length === 0 || !path[0]) return locale;
- return walkDown(locale[path[0]], path.slice(1));
-}
-
-/* given a MemberExpression node, returns its attached CallExpression
- * node if present
- *
- * e.g. for a bit of code like `foo=one.two.three()`,
- * `findCallExpression` called on the node for `three` would return
- * the node for function call (which is the parent of the `one` and
- * `two` nodes, and holds the nodes for the argument list)
- *
- * if the code had been `foo=one.two.three`, `findCallExpression`
- * would have returned null, because there's no function call attached
- * to the MemberExpressions
- */
-function findCallExpression(node) {
- if (!node.parent) return null;
-
- // the second half of this guard protects from cases like
- // `foo(one.two.three)` where the CallExpression is parent of the
- // MemberExpressions, but via `arguments`, not `callee`
- if (node.parent.type === 'CallExpression' && node.parent.callee === node) return node.parent;
- if (node.parent.type === 'MemberExpression') return findCallExpression(node.parent);
- return null;
-}
-
-// same, but for Vue expressions (``)
-function findVueExpression(node) {
- if (!node.parent) return null;
-
- if (node.parent.type.match(/^VExpr/) && node.parent.expression === node) return node.parent;
- if (node.parent.type === 'MemberExpression') return findVueExpression(node.parent);
- return null;
-}
-
-function areArgumentsOneObject(node) {
- return node.arguments.length === 1 &&
- node.arguments[0].type === 'ObjectExpression';
-}
-
-// only call if `areArgumentsOneObject(node)` is true
-function getArgumentObjectProperties(node) {
- return new Set(node.arguments[0].properties.map(
- p => {
- if (p.key && p.key.type === 'Identifier') return p.key.name;
- return null;
- },
- ));
-}
-
-function getTranslationParameters(translation) {
- return new Set(Array.from(translation.matchAll(/\{(\w+)\}/g)).map( m => m[1] ));
-}
-
-function setDifference(a,b) {
- const result = [];
- for (const element of a.values()) {
- if (!b.has(element)) {
- result.push(element);
- }
- }
-
- return result;
-}
-
-/* the actual rule body
- */
-function theRuleBody(context,node) {
- // we get the locale/translations via the options; it's the data
- // that goes into a specific language's JSON file, see
- // `scripts/build-assets.mjs`
- const locale = context.options[0];
-
- // sometimes we get MemberExpression nodes that have a
- // *descendent* with the right identifier: skip them, we'll get
- // the right ones as well
- if (node.object?.name !== 'i18n') {
- return;
- }
-
- // `method` is going to be `'ts'` or `'tsx'`, `path` is going to
- // be the various translation steps/names
- const [ method, ...path ] = collectMembers(node);
- const pathStr = `i18n.${method}.${path.join('.')}`;
-
- // does that path point to a real translation?
- const translation = walkDown(locale, path);
- if (!translation) {
- context.report({
- node,
- message: `translation missing for ${pathStr}`,
- });
- return;
- }
-
- // we hit something weird, assume the programmers know what
- // they're doing (this is usually some complicated slicing of
- // the translation structure)
- if (typeof(translation) !== 'string') return;
-
- const callExpression = findCallExpression(node);
- const vueExpression = findVueExpression(node);
-
- // some more checks on how the translation is called
- if (method === 'ts') {
- // the ` component gets parametric translations via
- // `i18n.ts.*`, but we error out elsewhere
- if (translation.match(/\{/) && !vueExpression) {
- context.report({
- node,
- message: `translation for ${pathStr} is parametric, but called via 'ts'`,
- });
- return;
- }
-
- if (callExpression) {
- context.report({
- node,
- message: `translation for ${pathStr} is not parametric, but is called as a function`,
- });
- }
- }
-
- if (method === 'tsx') {
- if (!translation.match(/\{/)) {
- context.report({
- node,
- message: `translation for ${pathStr} is not parametric, but called via 'tsx'`,
- });
- return;
- }
-
- if (!callExpression && !vueExpression) {
- context.report({
- node,
- message: `translation for ${pathStr} is parametric, but not called as a function`,
- });
- return;
- }
-
- // we're not currently checking arguments when used via the
- // `` component, because it's too complicated (also, it
- // would have to be done inside the `if (method === 'ts')`)
- if (!callExpression) return;
-
- if (!areArgumentsOneObject(callExpression)) {
- context.report({
- node,
- message: `translation for ${pathStr} should be called with a single object as argument`,
- });
- return;
- }
-
- const translationParameters = getTranslationParameters(translation);
- const parameterCount = translationParameters.size;
- const callArguments = getArgumentObjectProperties(callExpression);
- const argumentCount = callArguments.size;
-
- if (parameterCount !== argumentCount) {
- context.report({
- node,
- message: `translation for ${pathStr} has ${parameterCount} parameters, but is called with ${argumentCount} arguments`,
- });
- }
-
- // node 20 doesn't have `Set.difference`...
- const extraArguments = setDifference(callArguments, translationParameters);
- const missingArguments = setDifference(translationParameters, callArguments);
-
- if (extraArguments.length > 0) {
- context.report({
- node,
- message: `translation for ${pathStr} passes unused arguments ${extraArguments.join(' ')}`,
- });
- }
-
- if (missingArguments.length > 0) {
- context.report({
- node,
- message: `translation for ${pathStr} does not pass arguments ${missingArguments.join(' ')}`,
- });
- }
- }
-}
-
-function theRule(context) {
- // we get the locale/translations via the options; it's the data
- // that goes into a specific language's JSON file, see
- // `scripts/build-assets.mjs`
- const locale = context.options[0];
-
- // for all object member access that have an identifier 'i18n'...
- return context.getSourceCode().parserServices.defineTemplateBodyVisitor(
- {
- // this is for bits, needs work
- 'MemberExpression:has(Identifier[name=i18n])': (node) => theRuleBody(context, node),
- },
- {
- // this is for normal code
- 'MemberExpression:has(Identifier[name=i18n])': (node) => theRuleBody(context, node),
- },
- );
-}
-
-module.exports = {
- meta: {
- type: 'problem',
- docs: {
- description: 'assert that all translations used are present in the locale files',
- },
- schema: [
- // here we declare that we need the locale/translation as a
- // generic object
- { type: 'object', additionalProperties: true },
- ],
- },
- create: theRule,
-};
diff --git a/eslint/locale.test.js b/eslint/locale.test.js
deleted file mode 100644
index 2b69672d27..0000000000
--- a/eslint/locale.test.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * SPDX-FileCopyrightText: dakkar and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
-*/
-
-const {RuleTester} = require("eslint");
-const localeRule = require("./locale");
-
-const locale = { foo: { bar: 'ok', baz: 'good {x}' }, top: '123' };
-
-const ruleTester = new RuleTester({
- languageOptions: {
- parser: require('vue-eslint-parser'),
- ecmaVersion: 2015,
- },
-});
-
-function testCase(code,errors) {
- return { code, errors, options: [ locale ], filename: 'test.ts' };
-}
-function testCaseVue(code,errors) {
- return { code, errors, options: [ locale ], filename: 'test.vue' };
-}
-
-ruleTester.run(
- 'sharkey-locale',
- localeRule,
- {
- valid: [
- testCase('i18n.ts.foo.bar'),
- testCase('i18n.ts.top'),
- testCase('i18n.tsx.foo.baz({x:1})'),
- testCase('whatever.i18n.ts.blah.blah'),
- testCase('whatever.i18n.tsx.does.not.matter'),
- testCase('whatever(i18n.ts.foo.bar)'),
- testCaseVue('{{ i18n.ts.foo.bar }}
'),
- testCaseVue(' '),
- // we don't detect the problem here, but should still accept it
- testCase('i18n.ts.foo["something"]'),
- testCase('i18n.ts.foo[something]'),
- ],
- invalid: [
- testCase('i18n.ts.not', 1),
- testCase('i18n.tsx.deep.not', 1),
- testCase('i18n.tsx.deep.not({x:12})', 1),
- testCase('i18n.tsx.top({x:1})', 1),
- testCase('i18n.ts.foo.baz', 1),
- testCase('i18n.tsx.foo.baz', 1),
- testCase('i18n.tsx.foo.baz({y:2})', 2),
- testCaseVue('{{ i18n.ts.not }}
', 1),
- testCaseVue(' ', 1),
- ],
- },
-);
diff --git a/flake.lock b/flake.lock
deleted file mode 100644
index 9de322090e..0000000000
--- a/flake.lock
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "nodes": {
- "nixpkgs": {
- "locked": {
- "lastModified": 1733212471,
- "narHash": "sha256-M1+uCoV5igihRfcUKrr1riygbe73/dzNnzPsmaLCmpo=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "55d15ad12a74eb7d4646254e13638ad0c4128776",
- "type": "github"
- },
- "original": {
- "owner": "NixOS",
- "ref": "nixos-unstable",
- "repo": "nixpkgs",
- "type": "github"
- }
- },
- "root": {
- "inputs": {
- "nixpkgs": "nixpkgs"
- }
- }
- },
- "root": "root",
- "version": 7
-}
diff --git a/flake.nix b/flake.nix
deleted file mode 100644
index e32d28bea5..0000000000
--- a/flake.nix
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
-
- outputs = { self, nixpkgs }: {
-
- nixosConfigurations.container = nixpkgs.lib.nixosSystem {
- system = "x86_64-linux";
- modules =
- [
- ( import ./sharkey-service.nix )
- ({ pkgs, ... }: {
- boot.isContainer = true;
-
- # Let 'nixos-version --json' know about the Git revision
- # of this flake.
- system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
-
- # Network configuration.
- networking.useDHCP = false;
- networking.firewall.allowedTCPPorts = [ 3000 ];
-
- system.stateVersion = "24.04";
-
- services.sharkey = {
- enable = true;
- package = (pkgs.callPackage ./sharkey.nix {});
- settings = {
- url = "https://sharkey.localhost";
- };
- redis.createLocally = true;
- database.createLocally = true;
- };
- })
- ];
- };
-
- };
-}
diff --git a/healthcheck.sh b/healthcheck.sh
index 216776b28f..02f13576e9 100644
--- a/healthcheck.sh
+++ b/healthcheck.sh
@@ -4,4 +4,4 @@
# SPDX-License-Identifier: AGPL-3.0-only
PORT=$(grep '^port:' /sharkey/.config/default.yml | awk 'NR==1{print $2; exit}')
-curl -Sfso/dev/null "http://localhost:${PORT}/healthz"
+curl -s -S -o /dev/null "http://localhost:${PORT}"
diff --git a/idea/MkDisableSection.vue b/idea/MkDisableSection.vue
deleted file mode 100644
index d177886569..0000000000
--- a/idea/MkDisableSection.vue
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/idea/README.md b/idea/README.md
deleted file mode 100644
index f64d16800a..0000000000
--- a/idea/README.md
+++ /dev/null
@@ -1 +0,0 @@
-使われなくなったけど消すのは勿体ない(将来使えるかもしれない)コードを入れておくとこ
diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml
index de24ad4bb9..b0f7408587 100644
--- a/locales/ar-SA.yml
+++ b/locales/ar-SA.yml
@@ -123,7 +123,6 @@ reactions: "التفاعلات"
reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة."
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
attachCancel: "أزل المرفق"
-deleteFile: "حُذف الملف"
markAsSensitive: "علّمه كمحتوى حساس"
unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس"
enterFileName: "ادخل اسم الملف"
@@ -626,7 +625,10 @@ abuseReported: "أُرسل البلاغ، شكرًا لك"
reporter: "المُبلّغ"
reporteeOrigin: "أصل البلاغ"
reporterOrigin: "أصل المُبلّغ"
+forwardReport: "وجّه البلاغ إلى المثيل البعيد"
+forwardReportIsAnonymous: "في المثيل البعيد سيظهر المبلّغ كحساب مجهول."
send: "أرسل"
+abuseMarkAsResolved: "علّم البلاغ كمحلول"
openInNewTab: "افتح في لسان جديد"
defaultNavigationBehaviour: "سلوك الملاحة الافتراضي"
editTheseSettingsMayBreakAccount: "تعديل هذه الإعدادات قد يسبب عطبًا لحسابك"
@@ -1012,9 +1014,6 @@ renotes: "أعد النشر"
sourceCode: "الشفرة المصدرية"
flip: "اقلب"
lastNDays: "آخر {n} أيام"
-surrender: "ألغِ"
-_delivery:
- stop: "مُعلّق"
_initialAccountSetting:
accountCreated: "نجح إنشاء حسابك!"
letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
@@ -1252,12 +1251,15 @@ _theme:
buttonBg: "خلفية الأزرار"
buttonHoverBg: "خلفية الأزرار (عند التمرير فوقها)"
inputBorder: "حواف حقل الإدخال"
+ listItemHoverBg: "خلفية عناصر القائمة (عند التمرير فوقها)"
driveFolderBg: "خلفية مجلد قرص التخزين"
messageBg: "خلفية المحادثة"
_sfx:
note: "الملاحظات"
noteMy: "ملاحظتي"
notification: "الإشعارات"
+ antenna: "الهوائيات"
+ channel: "إشعارات القنات"
_ago:
future: "المستقبَل"
justNow: "اللحظة"
@@ -1529,7 +1531,6 @@ _notification:
reaction: "التفاعل"
receiveFollowRequest: "طلبات المتابعة"
followRequestAccepted: "طلبات المتابعة المقبولة"
- login: "لِج"
app: "إشعارات التطبيقات المرتبطة"
_actions:
followBack: "تابعك بالمثل"
@@ -1561,27 +1562,10 @@ _webhookSettings:
active: "مُفعّل"
_events:
reaction: "عند التفاعل"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "البريد الإلكتروني "
_moderationLogTypes:
suspend: "علِق"
- deleteDriveFile: "حُذف الملف"
- deleteNote: "حُذفت الملاحظة"
- createGlobalAnnouncement: "أُنشئ إعلان عام"
- createUserAnnouncement: "أُنشئ إعلان مستخدم"
- updateGlobalAnnouncement: "حُدث إعلان عام"
- updateUserAnnouncement: "حُدث إعلان مستخدم"
resetPassword: "أعد تعيين كلمتك السرية"
createInvitation: "ولِّد دعوة"
_reversi:
total: "المجموع"
- lookingForPlayer: "يبحث عن خصم..."
- gameCanceled: "أُلغيت اللعبة."
- opponentHasSettingsChanged: "غيَر الخصم إعدادته."
- showBoardLabels: "اعرض ترقيم الصفوف والأعمدة على اللوح"
- useAvatarAsStone: "حوَل الحجارة إلى صور مستخدمين"
-_offlineScreen:
- title: "غير متصل - يتعذر الاتصال بالخادم"
- header: "يتعذر الاتصال بالخادم"
+
diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml
index 0e761b0743..2a23cda06b 100644
--- a/locales/bn-BD.yml
+++ b/locales/bn-BD.yml
@@ -451,6 +451,7 @@ or: "অথবা"
language: "ভাষা"
uiLanguage: "UI এর ভাষা"
aboutX: "{x} সম্পর্কে"
+disableDrawer: "ড্রয়ার মেনু প্রদর্শন করবেন না"
noHistory: "কোনো ইতিহাস নেই"
signinHistory: "প্রবেশ করার ইতিহাস"
doing: "প্রক্রিয়া করছে..."
@@ -624,7 +625,10 @@ abuseReported: "আপনার অভিযোগটি দাখিল কর
reporter: "অভিযোগকারী"
reporteeOrigin: "অভিযোগটির উৎস"
reporterOrigin: "অভিযোগকারীর উৎস"
+forwardReport: "রিমোট ইন্সত্যান্সে অভিযোগটি পাঠান"
+forwardReportIsAnonymous: "আপনার তথ্য রিমোট ইন্সত্যান্সে পাঠানো হবে না এবং একটি বেনামী সিস্টেম অ্যাকাউন্ট হিসাবে প্রদর্শিত হবে।"
send: "পাঠান"
+abuseMarkAsResolved: "অভিযোগটিকে সমাধাকৃত হিসাবে চিহ্নিত করুন"
openInNewTab: "নতুন ট্যাবে খুলুন"
openInSideView: "সাইড ভিউতে খুলুন"
defaultNavigationBehaviour: "ডিফল্ট নেভিগেশন"
@@ -853,10 +857,6 @@ replies: "জবাব"
renotes: "রিনোট"
sourceCode: "সোর্স কোড"
flip: "উল্টান"
-_delivery:
- stop: "স্থগিত করা হয়েছে"
- _type:
- none: "প্রকাশ করা হচ্ছে"
_role:
priority: "অগ্রাধিকার"
_priority:
@@ -1017,6 +1017,7 @@ _theme:
buttonBg: "বাটনের পটভূমি"
buttonHoverBg: "বাটনের পটভূমি (হভার)"
inputBorder: "ইনপুট ফিল্ডের বর্ডার"
+ listItemHoverBg: "লিস্ট আইটেমের পটভূমি (হোভার)"
driveFolderBg: "ড্রাইভ ফোল্ডারের পটভূমি"
wallpaperOverlay: "ওয়ালপেপার ওভারলে"
badge: "ব্যাজ"
@@ -1028,6 +1029,8 @@ _sfx:
note: "নোটগুলি"
noteMy: "নোট (আপনার)"
notification: "বিজ্ঞপ্তি"
+ antenna: "অ্যান্টেনাগুলি"
+ channel: "চ্যানেলের বিজ্ঞপ্তি"
_ago:
future: "ভবিষ্যৎ"
justNow: "এইমাত্র"
@@ -1309,7 +1312,6 @@ _notification:
pollEnded: "পোল শেষ"
receiveFollowRequest: "প্রাপ্ত অনুসরণের অনুরোধসমূহ"
followRequestAccepted: "গৃহীত অনুসরণের অনুরোধসমূহ"
- login: "প্রবেশ করুন"
app: "লিঙ্ক করা অ্যাপ থেকে বিজ্ঞপ্তি"
_actions:
followBack: "ফলো ব্যাক করেছে"
@@ -1340,12 +1342,9 @@ _deck:
_webhookSettings:
name: "নাম"
active: "চালু"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "ইমেইল"
_moderationLogTypes:
suspend: "স্থগিত করা"
resetPassword: "পাসওয়ার্ড রিসেট করুন"
_reversi:
total: "মোট"
+
diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml
index b9f3fecc76..23c5382ee4 100644
--- a/locales/ca-ES.yml
+++ b/locales/ca-ES.yml
@@ -8,8 +8,6 @@ search: "Cercar"
notifications: "Notificacions"
username: "Nom d'usuari"
password: "Contrasenya"
-initialPasswordForSetup: "Contrasenya inicial per la configuració inicial"
-initialPasswordIsIncorrect: "La contrasenya no és correcta."
forgotPassword: "Contrasenya oblidada"
fetchingAsApObject: "Cercant en el Fediverse..."
ok: "OK"
@@ -62,7 +60,6 @@ copyFileId: "Copiar ID d'arxiu"
copyFolderId: "Copiar ID de carpeta"
copyProfileUrl: "Copiar URL del perfil"
searchUser: "Cercar un usuari"
-searchThisUsersNotes: "Cerca les publicacions de l'usuari"
reply: "Respondre"
loadMore: "Carregar més"
showMore: "Veure més"
@@ -111,14 +108,11 @@ enterEmoji: "Introduir un emoji"
renote: "Impulsa"
unrenote: "Anul·la l'impuls"
renoted: "S'ha impulsat"
-renotedToX: "Impulsat per {name}."
cantRenote: "No es pot impulsar aquesta publicació"
cantReRenote: "No es pot impulsar l'impuls."
quote: "Cita"
inChannelRenote: "Renotar només al Canal"
inChannelQuote: "Citar només al Canal"
-renoteToChannel: "Impulsa a un canal"
-renoteToOtherChannel: "Impulsa a un altre canal"
pinnedNote: "Nota fixada"
pinned: "Fixar al perfil"
you: "Tu"
@@ -157,7 +151,6 @@ editList: "Editar llista"
selectChannel: "Selecciona un canal"
selectAntenna: "Tria una antena"
editAntenna: "Modificar antena"
-createAntenna: "Crea una antena"
selectWidget: "Triar un giny"
editWidgets: "Editar ginys"
editWidgetsExit: "Fet"
@@ -184,10 +177,6 @@ addAccount: "Afegeix un compte"
reloadAccountsList: "Recarregar la llista de contactes"
loginFailed: "S'ha produït un error al accedir."
showOnRemote: "Navega més en el perfil original"
-continueOnRemote: "Veure perfil original"
-chooseServerOnMisskeyHub: "Escull un servidor des del Hub de Misskey"
-specifyServerHost: "Especifica un servidor directament"
-inputHostName: "Introdueix el domini"
general: "General"
wallpaper: "Fons de Pantalla"
setWallpaper: "Defineix el fons de pantalla"
@@ -198,7 +187,6 @@ followConfirm: "Estàs segur que vols deixar de seguir {name}?"
proxyAccount: "Compte de proxy"
proxyAccountDescription: "Un compte proxy és un compte que actua com a seguidor remot per als usuaris en determinades condicions. Per exemple, quan un usuari afegeix un usuari remot a la llista, l'activitat de l'usuari remot no es lliurarà al servidor si cap usuari local segueix aquest usuari, de manera que el compte proxy el seguirà."
host: "Amfitrió"
-selectSelf: "Escollir manualment"
selectUser: "Selecciona usuari/a"
recipient: "Destinatari"
annotation: "Comentaris"
@@ -214,7 +202,6 @@ perDay: "Per dia"
stopActivityDelivery: "Deixa d'enviar activitats"
blockThisInstance: "Deixa d'enviar activitats"
silenceThisInstance: "Silencia aquesta instància "
-mediaSilenceThisInstance: "Silenciar els arxius d'aquesta instància "
operations: "Accions"
software: "Programari"
version: "Versió"
@@ -236,10 +223,6 @@ blockedInstances: "Instàncies bloquejades"
blockedInstancesDescription: "Llista els enllaços d'amfitrió de les instàncies que vols bloquejar separades per un salt de pàgina. Les instàncies llistades no podran comunicar-se amb aquesta instància."
silencedInstances: "Instàncies silenciades"
silencedInstancesDescription: "Llista els enllaços d'amfitrió de les instàncies que vols silenciar. Tots els comptes de les instàncies llistades s'establiran com silenciades i només podran fer sol·licitacions de seguiment, i no podran mencionar als comptes locals si no els segueixen. Això no afectarà les instàncies bloquejades."
-mediaSilencedInstances: "Instàncies amb els arxius silenciats"
-mediaSilencedInstancesDescription: "Llista els noms dels servidors que vulguis silenciar els arxius, un servidor per línia. Tots els comptes que pertanyin als servidors llistats seran tractats com sensibles i no podran fer servir emojis personalitzats. Això no tindrà efecte sobre els servidors blocats."
-federationAllowedHosts: "Llista de servidors federats"
-federationAllowedHostsDescription: "Llista dels servidors amb els quals es federa."
muteAndBlock: "Silencia i bloca"
mutedUsers: "Usuaris silenciats"
blockedUsers: "Usuaris bloquejats"
@@ -330,7 +313,6 @@ selectFile: "Selecciona fitxers"
selectFiles: "Selecciona fitxers"
selectFolder: "Selecció de carpeta"
selectFolders: "Selecció de carpeta"
-fileNotSelected: "Cap fitxer seleccionat"
renameFile: "Canvia el nom del fitxer"
folderName: "Nom de la carpeta"
createFolder: "Crea una carpeta"
@@ -338,7 +320,6 @@ renameFolder: "Canvia el nom de la carpeta"
deleteFolder: "Elimina la carpeta"
folder: "Carpeta "
addFile: "Afegeix un fitxer"
-showFile: "Mostrar fitxer"
emptyDrive: "La teva unitat és buida"
emptyFolder: "La carpeta està buida"
unableToDelete: "No es pot eliminar"
@@ -419,7 +400,6 @@ name: "Nom"
antennaSource: "Font de l'antena"
antennaKeywords: "Paraules clau a seguir"
antennaExcludeKeywords: "Paraules clau a excloure"
-antennaExcludeBots: "Exclou els bots"
antennaKeywordsDescription: "Separar amb espais per la condició AND o amb salts de línia per la condició OR."
notifyAntenna: "Notifica'm les publicacions noves"
withFileAntenna: "Només les publicacions amb fitxers"
@@ -453,7 +433,6 @@ totpDescription: "Escriu una contrasenya d'un sol us fent servir l'aplicació d'
moderator: "Moderador/a"
moderation: "Moderació"
moderationNote: "Nota de moderació "
-moderationNoteDescription: "Pots escriure notes que es compartiran entre els moderadors."
addModerationNote: "Afegir una nota de moderació "
moderationLogs: "Registre de moderació "
nUsersMentioned: "{n} usuaris mencionats"
@@ -488,12 +467,10 @@ retype: "Torneu a introduir-la"
noteOf: "Publicació de: {user}"
quoteAttached: "Frase adjunta"
quoteQuestion: "Vols annexar-la com a cita?"
-attachAsFileQuestion: "El text copiat és massa llarg. Vols adjuntar-lo com un fitxer de text?"
noMessagesYet: "Encara no hi ha missatges"
newMessageExists: "Has rebut un nou missatge"
onlyOneFileCanBeAttached: "Només pots adjuntar un fitxer a un missatge"
signinRequired: "Si us plau, Registra't o inicia la sessió abans de continuar"
-signinOrContinueOnRemote: "Per continuar necessites moure el teu servidor o registrar-te / iniciar sessió en aquest servidor."
invitations: "Convida"
invitationCode: "Codi d'invitació"
checking: "Comprovació en curs..."
@@ -515,12 +492,8 @@ uiLanguage: "Idioma de l'interfície"
aboutX: "Respecte a {x}"
emojiStyle: "Estil d'emoji"
native: "Nadiu"
-menuStyle: "Estil de menú"
-style: "Estil"
-drawer: "Calaix"
-popup: "Emergent"
+disableDrawer: "No mostrar els menús en calaixos"
showNoteActionsOnlyHover: "Només mostra accions de la nota en passar amb el cursor"
-showReactionsCount: "Mostra el nombre de reaccions a les publicacions"
noHistory: "No hi ha un registre previ"
signinHistory: "Historial d'autenticacions"
enableAdvancedMfm: "Habilitar l'MFM avançat"
@@ -568,9 +541,9 @@ objectStorageUseSSLDesc: "Desactiva'l si no tens pensat fer servir HTTPS per les
objectStorageUseProxy: "Connectar-se mitjançant un Proxy"
objectStorageUseProxyDesc: "Desactiva'l si no faràs servir un Proxy per les connexions de l'API"
objectStorageSetPublicRead: "Configurar les pujades com públiques "
-s3ForcePathStyleDesc: "Si s3ForcePathStyle es troba activat el nom del cubell s'haurà d'especificar com a part de l'adreça URL en comptes del nom del servidor. Podria ser que necessitis activar aquesta opció quan facis servir serveis com ara l'allotjament a un servidor propi."
+s3ForcePathStyleDesc: "Si s3ForcePathStyle es troba activat el nom del dipòsit s'ha d'incloure a l'adreça URL en comtes del nom del host. Potser que necessitis activar-ho quan facis servir, per exemple, Minio a un servidor propi."
serverLogs: "Registres del servidor"
-deleteAll: "Elimina-ho tot"
+deleteAll: "Esborrar tot"
showFixedPostForm: "Mostrar el formulari per escriure a l'inici de la línia de temps"
showFixedPostFormInChannel: "Mostrar el formulari d'escriptura al principi de la línia de temps (Canals)"
withRepliesByDefaultForNewlyFollowed: "Inclou les respostes d'usuaris nous seguits a la línia de temps per defecte."
@@ -601,8 +574,6 @@ ascendingOrder: "Ascendent"
descendingOrder: "Descendent"
scratchpad: "Bloc de proves"
scratchpadDescription: "El bloc de proves proporciona un entorn experimental per AiScript. Pot escriure i verificar els resultats que interactuen amb Misskey."
-uiInspector: "Inspector de la interfície"
-uiInspectorDescription: "Podeu visualitzar una llista d'elements UI presents en la memòria. Els components de la interfície d'usuari són generats per les funcions Ui:C:."
output: "Sortida"
script: "Script"
disablePagesScript: "Desactivar AiScript a les pàgines "
@@ -719,7 +690,10 @@ abuseReported: "La teva denúncia s'ha enviat. Moltes gràcies."
reporter: "Denunciant "
reporteeOrigin: "Origen de la denúncia "
reporterOrigin: "Origen del denunciant"
-send: "Envia"
+forwardReport: "Transferir la denúncia a una instància remota"
+forwardReportIsAnonymous: "En comptes del teu compte, es farà servir un compte anònim com a denunciat a la instància remota."
+send: "Enviar"
+abuseMarkAsResolved: "Marcar la denúncia com a resolta"
openInNewTab: "Obre a una pestanya nova"
openInSideView: "Obre a una vista lateral"
defaultNavigationBehaviour: "Navegació per defecte"
@@ -856,7 +830,6 @@ administration: "Administració"
accounts: "Comptes"
switch: "Canvia"
noMaintainerInformationWarning: "La informació de l'administrador no s'ha configurat"
-noInquiryUrlWarning: "No s'ha desat l'URL de consulta."
noBotProtectionWarning: "La protecció contra bots no s'ha configurat."
configure: "Configurar"
postToGallery: "Crear una nova publicació a la galeria"
@@ -880,7 +853,7 @@ customCss: "CSS personalitzat"
customCssWarn: "Aquesta configuració només hauries de configurar-la si saps que fas. Si poses valors inadequats pots fer que el client deixi de funcionar correctament."
global: "Global"
squareAvatars: "Mostrar avatars quadrats"
-sent: "Envia"
+sent: "Enviar"
received: "Rebut"
searchResult: "Resultats de la cerca"
hashtags: "Etiquetes"
@@ -921,7 +894,6 @@ followersVisibility: "Visibilitat dels seguidors"
continueThread: "Veure la continuació del fil"
deleteAccountConfirm: "Això eliminarà el teu compte irreversiblement. Procedir?"
incorrectPassword: "Contrasenya incorrecta."
-incorrectTotp: "La contrasenya no és correcta, o ha caducat."
voteConfirm: "Confirma el teu vot \"{choice}\""
hide: "Amagar"
useDrawerReactionPickerForMobile: "Mostrar el selector de reaccions com un calaix al mòbil "
@@ -1019,7 +991,6 @@ neverShow: "No mostrar més "
remindMeLater: "Recorda-m'ho més tard"
didYouLikeMisskey: "T'està agradant Misskey?"
pleaseDonate: "A {host} fem servir el software lliure Misskey. Considera fer un donatiu a Misskey perquè pugui continuar el seu desenvolupament!"
-correspondingSourceIsAvailable: "El codi font corresponent està disponible a {anchor}."
roles: "Rols"
role: "Rols"
noRole: "No s'han trobat rols"
@@ -1047,7 +1018,6 @@ thisPostMayBeAnnoyingHome: "Publicar a la línia de temps d'Inici"
thisPostMayBeAnnoyingCancel: "Cancel·lar "
thisPostMayBeAnnoyingIgnore: "Publicar de totes maneres"
collapseRenotes: "Col·lapsar les renotes que ja has vist"
-collapseRenotesDescription: "Col·lapse les notes a les quals ja has reaccionat o que ja has renotat"
internalServerError: "Error intern del servidor"
internalServerErrorDescription: "El servidor ha fallat de manera inexplicable."
copyErrorInfo: "Copiar la informació de l'error "
@@ -1121,8 +1091,6 @@ preservedUsernames: "Noms d'usuaris reservats"
preservedUsernamesDescription: "Llistat de noms d'usuaris que no es poden fer servir separats per salts de linia. Aquests noms d'usuaris no estaran disponibles quan es creï un compte d'usuari normal, però els administradors els poden fer servir per crear comptes manualment. Per altre banda els comptes ja creats amb aquests noms d'usuari no es veure'n afectats."
createNoteFromTheFile: "Compon una nota des d'aquest fitxer"
archive: "Arxiu"
-archived: "Arxivat"
-unarchive: "Desarxivar"
channelArchiveConfirmTitle: "Vols arxivar {name}?"
channelArchiveConfirmDescription: "Un Canal arxivat no apareixerà a la llista de canals o als resultats de cerca. Tampoc es poden afegir noves entrades."
thisChannelArchived: "Aquest Canal ha sigut arxivat."
@@ -1133,9 +1101,6 @@ preventAiLearning: "Descartar l'ús d'aprenentatge automàtic (IA Generativa)"
preventAiLearningDescription: "Demanar els indexadors no fer servir els texts, imatges, etc. en cap conjunt de dades per alimentar l'aprenentatge automàtic (IA Predictiva/ Generativa). Això s'aconsegueix afegint la etiqueta \"noai\" com a resposta HTML al contingut corresponent. Prevenir aquest ús totalment pot ser que no sigui aconseguit, ja que molts indexadors poden obviar aquesta etiqueta."
options: "Opcions"
specifyUser: "Especificar usuari"
-lookupConfirm: "Vols fer una cerca?"
-openTagPageConfirm: "Vols obrir una pàgina d'etiquetes?"
-specifyHost: "Especifica un servidor"
failedToPreviewUrl: "Vista prèvia no disponible"
update: "Actualitzar"
rolesThatCanBeUsedThisEmojiAsReaction: "Rols que poden fer servir aquest emoji com a reacció "
@@ -1178,7 +1143,7 @@ currentAnnouncements: "Informes actuals"
pastAnnouncements: "Informes passats"
youHaveUnreadAnnouncements: "Tens informes per llegir."
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
-replies: "Respondre"
+replies: "Respostes"
renotes: "Impulsa"
loadReplies: "Mostrar les respostes"
loadConversation: "Mostrar la conversació "
@@ -1194,7 +1159,6 @@ showRenotes: "Mostrar impulsos"
edited: "Editat"
notificationRecieveConfig: "Paràmetres de notificacions"
mutualFollow: "Seguidor mutu"
-followingOrFollower: "Seguit o seguidor"
fileAttachedOnly: "Només notes amb adjunts"
showRepliesToOthersInTimeline: "Mostrar les respostes a altres a la línia de temps"
hideRepliesToOthersInTimeline: "Amagar les respostes a altres a la línia de temps"
@@ -1204,12 +1168,6 @@ confirmShowRepliesAll: "Aquesta opció no té marxa enrere. Vols mostrar les tev
confirmHideRepliesAll: "Aquesta opció no té marxa enrere. Vols ocultar les teves respostes a tots els usuaris que segueixes a la línia de temps?"
externalServices: "Serveis externs"
sourceCode: "Codi font"
-sourceCodeIsNotYetProvided: "El codi font encara no es troba disponible. Contacta amb l'administrador per solucionar aquest problema."
-repositoryUrl: "URL del repositori"
-repositoryUrlDescription: "Si estàs fent servir Misskey tal com és (sense cap canvi al codi font), introdueix https://github.com/misskey-dev/misskey"
-repositoryUrlOrTarballRequired: "Si no ofereixes cap repositori, publica un fitxer tarball. Dona una ullada a .config/example.yml per a més informació."
-feedback: "Opinió"
-feedbackUrl: "URL per a opinar"
impressum: "Impressum"
impressumUrl: "Adreça URL impressum"
impressumDescription: "A països, com Alemanya, la inclusió de la informació de contacte de l'operador (un Impressum) és requereix de manera legal per llocs comercials."
@@ -1245,8 +1203,6 @@ soundWillBePlayed: "Es reproduiran efectes de so"
showReplay: "Veure reproducció"
replay: "Reproduir"
replaying: "Reproduint"
-endReplay: "Tanca la redifusió"
-copyReplayData: "Copia les dades de la resposta"
ranking: "Classificació"
lastNDays: "Últims {n} dies"
backToTitle: "Torna al títol"
@@ -1254,66 +1210,8 @@ hemisphere: "Geolocalització"
withSensitive: "Incloure notes amb fitxers sensibles"
userSaysSomethingSensitive: "La publicació de {name} conte material sensible"
enableHorizontalSwipe: "Lliscar per canviar de pestanya"
-loading: "S’està carregant"
-surrender: "Cancel·lar "
-gameRetry: "Torna a provar"
-notUsePleaseLeaveBlank: "Si no voleu usar-ho, deixeu-ho en blanc"
-useTotp: "Usa una contrasenya d'un sol ús"
-useBackupCode: "Usa un codi de recuperació"
-launchApp: "Inicia l'aplicació "
-useNativeUIForVideoAudioPlayer: "Fes servir la UI del navegador quan reprodueixis vídeo i àudio "
-keepOriginalFilename: "Desa el nom del fitxer original"
-keepOriginalFilenameDescription: "Si desactives aquesta opció els noms dels fitxers se substituiran per una cadena aleatòria quan carreguis nous fitxers de forma automàtica."
-noDescription: "No hi ha una descripció "
-alwaysConfirmFollow: "Confirma sempre els seguiments"
-inquiry: "Contacte"
-tryAgain: "Intenta-ho més tard."
-confirmWhenRevealingSensitiveMedia: "Confirmació quan revelis contingut sensible "
-sensitiveMediaRevealConfirm: "Aquest contingut potser sensible. Segur que ho vols revelar?"
-createdLists: "Llistes creades "
-createdAntennas: "Antenes creades"
-fromX: "De {x}"
-genEmbedCode: "Obtenir el codi per incrustar"
-noteOfThisUser: "Notes d'aquest usuari"
-clipNoteLimitExceeded: "No es poden afegir més notes a aquest clip."
-performance: "Rendiment"
-modified: "Modificat"
-discard: "Descarta"
-thereAreNChanges: "Hi ha(n) {n} canvi(s)"
-signinWithPasskey: "Inicia sessió amb Passkey"
-unknownWebAuthnKey: "Passkey desconeguda"
-passkeyVerificationFailed: "La verificació a fallat"
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificació de la passkey a estat correcta, però s'ha deshabilitat l'inici de sessió sense contrasenya."
-messageToFollower: "Missatge als meus seguidors"
-target: "Assumpte "
-testCaptchaWarning: "És una característica dissenyada per a la prova de CAPTCHA. No l'utilitzes en l'entorn real. "
-_abuseUserReport:
- forward: "Reenviar "
- forwardDescription: "Reenvia l'informe a una altra instància com un compte del sistema anònima."
- resolve: "Solució "
- accept: "Acceptar "
- reject: "Rebutjar"
- resolveTutorial: "Si l'informe és legítim selecciona \"Acceptar\" per resoldre'l positivament. Però si l'informe no és legítim selecciona \"Rebutjar\" per resoldre'l negativament."
-_delivery:
- status: "Estat d'entrega "
- stop: "Suspés"
- resume: "Torna a enviar"
- _type:
- none: "S'està publicant"
- manuallySuspended: "Suspendre manualment"
- goneSuspended: "Servidor suspès perquè el servidor s'ha esborrat"
- autoSuspendedForNotResponding: "Servidor suspès perquè el servidor no respon"
_bubbleGame:
howToPlay: "Com es juga"
- hold: "Mantenir"
- _score:
- score: "Puntuació "
- scoreYen: "Diners guanyats"
- highScore: "Millor puntuació "
- maxChain: "Nombre màxim de combos"
- yen: "{yen}Ien"
- estimatedQty: "{qty}peces"
- scoreSweets: "{onigiriQtyWithUnit}ongiris"
_howToPlay:
section1: "Ajusta la posició i deixa caure l'objecte dintre la caixa."
section2: "Quan dos objectes del mateix tipus es toquen, canviaran en un objecte diferent i guanyares punts."
@@ -1428,10 +1326,6 @@ _serverSettings:
fanoutTimelineDescription: "Quan es troba activat millora bastant el rendiment quan es recuperen les línies de temps i redueix la carrega de la base de dades. Com a contrapunt, l'ús de memòria de Redis es veurà incrementada. Considera d'estabilitat aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes de inestabilitat."
fanoutTimelineDbFallback: "Carregar de la base de dades"
fanoutTimelineDbFallbackDescription: "Quan s'activa, la línia de temps fa servir la base de dades per consultes adicionals si la línia de temps no es troba a la memòria cau. Si és desactiva la càrrega del servidor és veure reduïda, però també és reduirà el nombre de línies de temps que és poden obtenir."
- reactionsBufferingDescription: "Quan s'activa aquesta opció millora bastant el rendiment en recuperar les línies de temps reduint la càrrega de la base. Com a contrapunt, augmentarà l'ús de memòria de Redís. Desactiva aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes d'inestabilitat."
- inquiryUrl: "URL de consulta "
- inquiryUrlDescription: "Escriu adreça URL per al formulari de consulta per al mantenidor del servidor o una pàgina web amb el contacte d'informació."
- thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Si no es detecta activitat per part del moderador durant un període de temps, aquesta opció es desactiva automàticament per evitar el correu brossa."
_accountMigration:
moveFrom: "Migrar un altre compte a aquest"
moveFromSub: "Crear un àlies per un altre compte"
@@ -1739,7 +1633,6 @@ _role:
gtlAvailable: "Pot veure la línia de temps global"
ltlAvailable: "Pot veure la línia de temps local"
canPublicNote: "Pot enviar notes públiques"
- mentionMax: "Nombre màxim de mencions a una nota"
canInvite: "Pot crear invitacions a la instància "
inviteLimit: "Límit d'invitacions "
inviteLimitCycle: "Temps de refresc de les invitacions"
@@ -1748,7 +1641,6 @@ _role:
canManageAvatarDecorations: "Gestiona les decoracions dels avatars "
driveCapacity: "Capacitat del disc"
alwaysMarkNsfw: "Marca sempre els fitxers com a sensibles"
- canUpdateBioMedia: "Permet l'edició d'una icona o un bàner"
pinMax: "Nombre màxim de notes fixades"
antennaMax: "Nombre màxim d'antenes"
wordMuteMax: "Nombre màxim de caràcters permesos a les paraules silenciades"
@@ -1763,20 +1655,9 @@ _role:
canSearchNotes: "Pot cercar notes"
canUseTranslator: "Pot fer servir el traductor"
avatarDecorationLimit: "Nombre màxim de decoracions que es poden aplicar els avatars"
- canImportAntennas: "Autoritza la importació d'antenes "
- canImportBlocking: "Autoritza la importació de bloquejats"
- canImportFollowing: "Autoritza la importació de seguidors"
- canImportMuting: "Autoritza la importació de silenciats"
- canImportUserLists: "Autoritza la importació de llistes d'usuaris "
_condition:
- roleAssignedTo: "Assignat a rols manuals"
isLocal: "Usuari local"
isRemote: "Usuari remot"
- isCat: "Usuaris gats"
- isBot: "Usuaris bots"
- isSuspended: "Usuari suspès"
- isLocked: "Comptes privats"
- isExplorable: "Fes que el compte aparegui a les cerques"
createdLessThan: "Han passat menys de X a passat des de la creació del compte"
createdMoreThan: "Han passat més de X des de la creació del compte"
followersLessThanOrEq: "Té menys de X seguidors"
@@ -1846,7 +1727,6 @@ _plugin:
installWarn: "Si us plau, no instal·lis afegits que no siguin de confiança."
manage: "Gestionar els afegits"
viewSource: "Veure l'origen "
- viewLog: "Mostra el registre"
_preferencesBackups:
list: "Llista de còpies de seguretat"
saveNew: "Fer una còpia de seguretat nova"
@@ -1876,8 +1756,6 @@ _aboutMisskey:
contributors: "Col·laboradors principals"
allContributors: "Tots els col·laboradors "
source: "Codi font"
- original: "Original"
- thisIsModifiedVersion: "En {name} fa servir una versió modificada de Misskey."
translation: "Tradueix Misskey"
donate: "Fes un donatiu a Misskey"
morePatrons: "També agraïm el suport d'altres col·laboradors que no surten en aquesta llista. Gràcies! 🥰"
@@ -1985,6 +1863,7 @@ _theme:
buttonBg: "Fons botó "
buttonHoverBg: "Fons botó (en passar-hi per sobre)"
inputBorder: "Contorn del cap d'introducció "
+ listItemHoverBg: "Fons dels elements d'una llista"
driveFolderBg: "Fons de la carpeta Disc"
wallpaperOverlay: "Superposició del fons de pantalla "
badge: "Insígnia "
@@ -1996,6 +1875,8 @@ _sfx:
note: "Notes"
noteMy: "Nota (per mi)"
notification: "Notificacions"
+ antenna: "Antenes"
+ channel: "Notificacions dels canals"
reaction: "Quan se selecciona una reacció "
_soundSettings:
driveFile: "Fer servir un fitxer d'àudio del disc"
@@ -2004,7 +1885,6 @@ _soundSettings:
driveFileTypeWarnDescription: "Seleccionar un fitxer d'àudio "
driveFileDurationWarn: "L'àudio és massa llarg"
driveFileDurationWarnDescription: "Els àudios molt llargs pot interrompre l'ús de Misskey. Vols continuar?"
- driveFileError: "El so no es pot carregar. Canvia la configuració"
_ago:
future: "Futur "
justNow: "Ara mateix"
@@ -2034,6 +1914,7 @@ _2fa:
registerTOTP: "Registrar una aplicació autenticadora"
step1: "Primer instal·la una aplicació autenticadora (com {a} o {b}) al teu dispositiu."
step2: "Després escaneja el codi QR que es mostra en aquesta pantalla."
+ step2Click: "Fent clic en aquest codi QR et permetrà registrar l'autenticació de doble factor a la teva clau de seguretat o en l'aplicació d'autenticació del teu dispositiu."
step2Uri: "Escriu la següent URI si estàs fent servir una aplicació d'escriptori "
step3Title: "Escriu un codi d'autenticació"
step3: "Escriu el codi d'autenticació (token) que es mostra a la teva aplicació per finalitzar la configuració."
@@ -2057,7 +1938,6 @@ _2fa:
backupCodesDescription: "Si l'aplicació d'autenticació no es pot utilitzar, es pot accedir al compte utilitzant els següents codis de còpia de seguretat. Assegura't de mantenir aquests codis en un lloc segur. Cada codi es pot utilitzar només una vegada."
backupCodeUsedWarning: "Es va utilitzar un codi de còpia de seguretat. Si l'aplicació de certificació està disponible, reconfigura l'aplicació d'autenticació tan aviat com sigui possible."
backupCodesExhaustedWarning: "Es van utilitzar tots els codis de còpia de seguretat. Si no es pot utilitzar l'aplicació d'autenticació, ja no es pot accedir al compte. Torna a registrar l'aplicació d'autenticació."
- moreDetailedGuideHere: "Aquí tens una guia al detall"
_permissions:
"read:account": "Veure la informació del compte."
"write:account": "Editar la informació del compte."
@@ -2108,6 +1988,7 @@ _permissions:
"read:admin:server-info": "Veure informació del servidor"
"read:admin:show-moderation-log": "Veure registre de moderació "
"read:admin:show-user": "Veure informació privada de l'usuari "
+ "read:admin:show-users": "Veure informació privada de l'usuari "
"write:admin:suspend-user": "Suspendre usuari"
"write:admin:unset-user-avatar": "Esborrar avatar d'usuari "
"write:admin:unset-user-banner": "Esborrar bàner de l'usuari "
@@ -2131,73 +2012,22 @@ _permissions:
"read:admin:emoji": "Veure emojis"
"write:admin:queue": "Gestionar la cua de feines"
"read:admin:queue": "Veure la cua de feines"
- "write:admin:promo": "Gestiona les notes promocionals"
- "write:admin:drive": "Gestiona el disc de l'usuari"
- "read:admin:drive": "Veure la informació del disc de l'usuari"
- "read:admin:stream": "Fes servir l'API sobre Websocket per l'administració"
- "write:admin:ad": "Gestiona la publicitat"
- "read:admin:ad": "Veure anuncis"
- "write:invite-codes": "Crear codis d'invitació"
- "read:invite-codes": "Obtenir codis d'invitació"
- "write:clip-favorite": "Gestionar els clips favorits"
- "read:clip-favorite": "Veure clips favorits"
- "read:federation": "Veure dades de federació"
- "write:report-abuse": "Informar d'un abús"
-_auth:
- shareAccessTitle: "Concedeix permisos a l'aplicació"
- shareAccess: "Vols que {name} pugui accedir al vostre compte?"
- shareAccessAsk: "Segur que vols que aquesta aplicació pugui accedir al vostre compte?"
- permission: "{name} demana els següents permisos"
- permissionAsk: "Aquesta aplicació demana els següents permisos"
- pleaseGoBack: "Si us plau, torna a l'aplicació"
- callback: "Tornant a l'aplicació"
- denied: "Accés denegat"
- pleaseLogin: "Si us plau, identificat per autoritzar l'aplicació."
_antennaSources:
all: "Totes les publicacions"
homeTimeline: "Publicacions dels usuaris seguits"
users: "Publicacions d'usuaris específics"
userList: "Publicacions d'una llista d'usuaris"
- userBlacklist: "Totes les notes excepte les d'un o alguns usuaris especificats"
-_weekday:
- sunday: "Diumenge"
- monday: "Dilluns"
- tuesday: "Dimarts"
- wednesday: "Dimecres"
- thursday: "Dijous"
- friday: "Divendres"
- saturday: "Dissabte"
_widgets:
profile: "Perfil"
instanceInfo: "Informació del fitxer d'instal·lació"
- memo: "Notes adhesives"
notifications: "Notificacions"
timeline: "Línia de temps"
- calendar: "Calendari"
- trends: "Tendència"
- clock: "Rellotge"
- rss: "Lector RSS"
- rssTicker: "RSS ticker"
activity: "Activitat"
- photos: "Fotografies"
- digitalClock: "Rellotge digital"
- unixClock: "Rellotge UNIX"
federation: "Federació"
- instanceCloud: "Núvol d'instàncies"
- postForm: "Formulari de publicació"
- slideshow: "Presentació"
button: "Botó "
- onlineUsers: "Usuaris actius"
jobQueue: "Cua de tasques"
- serverMetric: "Mètriques del servidor"
- aiscript: "Consola AiScript"
- aiscriptApp: "Aplicació AiScript"
- aichan: "Ai"
- userList: "Llistat d'usuaris"
_userList:
chooseList: "Tria una llista"
- clicker: "Clicker"
- birthdayFollowings: "Usuaris que fan l'aniversari avui"
_cw:
hide: "Amagar"
show: "Carregar més"
@@ -2261,79 +2091,27 @@ _profile:
changeBanner: "Canviar el bàner "
verifiedLinkDescription: "Escrivint una adreça URL que enllaci a aquest perfil, una icona de propietat verificada es mostrarà al costat del camp."
avatarDecorationMax: "Pot afegir un màxim de {max} decoracions."
- followedMessage: "Missatge als nous seguidors"
- followedMessageDescription: "Es pot configurar un missatge curt que es mostra a l'altra persona quan comença a seguir-te."
- followedMessageDescriptionForLockedAccount: "Si comencen a seguir-te es mostra un missatge de quan es permet aquesta sol·licitud. "
_exportOrImport:
allNotes: "Totes les publicacions"
- favoritedNotes: "Notes preferides"
clips: "Retalls"
followingList: "Seguint"
muteList: "Silencia"
blockingList: "Bloqueja"
userLists: "Llistes"
- excludeMutingUsers: "Exclou usuaris silenciats"
- excludeInactiveUsers: "Exclou usuaris inactius"
- withReplies: "Inclou a la línia de temps les respostes d'usuaris importats"
_charts:
federation: "Federació"
- apRequest: "Peticions"
- usersIncDec: "Diferència entre el nombre d'usuaris"
- usersTotal: "Nombre total d'usuaris"
- activeUsers: "Usuaris actius"
- notesIncDec: "Diferència entre el nombre de notes"
- localNotesIncDec: "Diferencia en el nombre de notes locals"
- remoteNotesIncDec: "Diferencia en el nombre de notes remotes"
- notesTotal: "Nombre total de notes"
- filesIncDec: "Diferencia en el nombre de fitxers"
- filesTotal: "Nombre total de fitxers"
- storageUsageIncDec: "Diferencia en l'emmagatzematge usat"
- storageUsageTotal: "Emmagatzematge usat"
-_instanceCharts:
- requests: "Peticions"
- users: "Diferència entre el nombre d'usuaris"
- usersTotal: "Usuaris totals acumulats"
- notes: "Diferència entre el nombre de notes"
- notesTotal: "Notes totals acumulades"
- ff: "Diferència en nombre d'usuaris seguits / seguidors"
- ffTotal: "Nombre total acumulat d'usuaris seguits / seguidors"
- cacheSize: "Diferència a la mida de la memòria cau"
- cacheSizeTotal: "Total acumulat de la mida de la memòria cau"
- files: "Diferència al nombre d'arxius"
- filesTotal: "Nombre acumulatiu de fitxers"
_timelines:
home: "Inici"
local: "Local"
social: "Social"
global: "Global"
_play:
- new: "Crear un guió"
- edit: "Editar guió"
- created: "Guió creat"
- updated: "Guió editat"
- deleted: "Guió esborrat"
- pageSetting: "Configuració del guió"
- editThisPage: "Edita aquest guió"
viewSource: "Veure l'origen "
- my: "Els meus guions"
- liked: "Guions que m'han agradat"
featured: "Popular"
title: "Títol "
script: "Script"
summary: "Descripció"
- visibilityDescription: ""
_pages:
- newPage: "pa"
- editPage: "Editar la pàgina"
- readPage: "Veure el codi font d'aquesta pàgina"
- created: "La pàgina ha sigut creada correctament"
- updated: "La pàgina s'ha editat correctament"
- deleted: "La pàgina s'ha esborrat sense problemes"
- pageSetting: "Configuració de la pàgina"
- nameAlreadyExists: "L'adreça URL de la pàgina ja existeix"
- invalidNameTitle: "L'adreça URL de la pàgina no és vàlida"
- invalidNameText: "Assegurat que el títol de la pàgina no és buit"
- editThisPage: "Editar la pàgina"
viewSource: "Veure l'origen "
viewPage: "Veure les teves pàgines "
like: "M'agrada "
@@ -2356,7 +2134,6 @@ _pages:
eyeCatchingImageSet: "Escull una miniatura"
eyeCatchingImageRemove: "Esborrar la miniatura"
chooseBlock: "Afegeix un bloc"
- enterSectionTitle: "Escriu el títol de la secció"
selectType: "Seleccionar tipus"
contentBlocks: "Contingut"
inputBlocks: "Entrada "
@@ -2367,8 +2144,6 @@ _pages:
section: "Secció "
image: "Imatges"
button: "Botó "
- dynamic: "Blocs dinàmics"
- dynamicDescription: "Aquest bloc és antic. Ara en endavant fes servir {play}"
note: "Incorporar una Nota"
_note:
id: "ID de la publicació"
@@ -2398,54 +2173,29 @@ _notification:
sendTestNotification: "Enviar notificació de prova"
notificationWillBeDisplayedLikeThis: "Les notificacions és veure'n així "
reactedBySomeUsers: "Han reaccionat {n} usuaris"
- likedBySomeUsers: "A {n} usuaris els hi agrada la teva nota"
renotedBySomeUsers: "L'han impulsat {n} usuaris"
- followedBySomeUsers: "Et segueixen {n} usuaris"
- flushNotification: "Netejar notificacions"
- exportOfXCompleted: "Completada l'exportació de {n}"
_types:
all: "Tots"
- note: "Notes noves"
follow: "Seguint"
mention: "Menció"
- reply: "Respostes"
renote: "Renotar"
quote: "Citar"
reaction: "Reaccions"
- pollEnded: "Enquesta terminada"
- receiveFollowRequest: "Rebuda una petició de seguiment"
- followRequestAccepted: "Petició de seguiment acceptada"
- roleAssigned: "Rol donat"
- achievementEarned: "Assoliment desbloquejat"
- exportCompleted: "Exportació completada"
- login: "Iniciar sessió"
- test: "Prova la notificació"
- app: "Notificacions d'aplicacions"
_actions:
followBack: "t'ha seguit també"
reply: "Respondre"
renote: "Renotar"
_deck:
- alwaysShowMainColumn: "Mostrar sempre la columna principal"
columnAlign: "Alinea les columnes"
addColumn: "Afig una columna"
- newNoteNotificationSettings: "Configuració de notificacions per a notes noves"
- configureColumn: "Configuració de columnes"
swapLeft: "Mou a l’esquerra"
swapRight: "Mou a la dreta"
swapUp: "Mou cap amunt"
swapDown: "Mou cap avall"
- stackLeft: "Pila a la columna esquerra"
popRight: "Col·loca a la dreta"
profile: "Perfil"
newProfile: "Perfil nou"
deleteProfile: "Elimina el perfil"
- introduction: "Crea la interfície perfecta posant les columnes allà on vulguis!"
- introduction2: "Fes clic al botó + de la dreta per afegir noves columnes sempre que vulguis."
- widgetsIntroduction: "Selecciona \"Editar ginys\" a la columna del menú i afegeix un."
- useSimpleUiForNonRootPages: "Usa una interfície senzilla per a les pàgines navegades"
- usedAsMinWidthWhenFlexible: "L'amplada mínima es farà servir quan \"Ajust automàtic de l'amplada\" estigui activat"
- flexible: "Ajust automàtic de l'amplada"
_columns:
main: "Principal"
widgets: "Ginys"
@@ -2456,82 +2206,17 @@ _deck:
channel: "Canals"
mentions: "Mencions"
direct: "Publicacions directes"
- roleTimeline: "Línia de temps dels rols"
-_dialog:
- charactersExceeded: "Has arribat al màxim de caràcters! Actualment és {current} de {max}"
- charactersBelow: "Ets per sota del mínim de caràcters! Actualment és {current} de {min}"
-_disabledTimeline:
- title: "Línia de tems desactivada"
- description: "No pots fer servir aquesta línia de temps amb els teus rols actuals."
-_drivecleaner:
- orderBySizeDesc: "Mida del fitxer descendent"
- orderByCreatedAtAsc: "Data ascendent"
_webhookSettings:
- createWebhook: "Crear un Webhook"
- modifyWebhook: "Modificar un Webhook"
name: "Nom"
- secret: "Secret"
- trigger: "Activador"
active: "Activat"
- _events:
- follow: "Quan se segueix a un usuari"
- followed: "Quan et segueixen"
- note: "Quan es publica una nota"
- reply: "Quan es rep una resposta"
- renote: "Quan es renoti"
- reaction: "Quan es rep una reacció "
- mention: "Quan et mencionen"
- _systemEvents:
- abuseReport: "Quan reps un nou informe de moderació "
- abuseReportResolved: "Quan resols un informe de moderació "
- userCreated: "Quan es crea un usuari"
- deleteConfirm: "Segur que vols esborrar el webhook?"
- testRemarks: "Si feu clic al botó a la dreta de l'interruptor, podeu enviar un webhook de prova amb dades dummy."
-_abuseReport:
- _notificationRecipient:
- createRecipient: "Afegeix un destinatari a l'informe de moderació "
- modifyRecipient: "Editar un destinatari en l'informe de moderació "
- recipientType: "Tipus de notificació "
- _recipientType:
- mail: "Correu electrònic"
- webhook: "Webhook"
- _captions:
- mail: "Enviar un correu electrònic a tots els moderadors quan es rep un informe de moderació "
- webhook: "Enviar una notificació al SystemWebhook quan es rebi o es resolgui un informe de moderació "
- keywords: "Paraules clau"
- notifiedUser: "Usuaris que s'han de notificar "
- notifiedWebhook: "Webhook que s'ha de fer servir"
- deleteConfirm: "Segur que vols esborrar el destinatari de l'informe de moderació?"
_moderationLogTypes:
- createRole: "Rol creat"
- deleteRole: "Rol esborrat"
- updateRole: "Rol actualitzat"
- assignRole: "Assignat al rol"
- unassignRole: "Esborrat del rol"
suspend: "Suspèn"
- unsuspend: "Suspensió treta"
- addCustomEmoji: "Afegit emoji personalitzat"
- updateCustomEmoji: "Actualitzat emoji personalitzat"
- deleteCustomEmoji: "Esborrat emoji personalitzat"
- updateServerSettings: "Configuració del servidor actualitzada"
- updateUserNote: "Nota de moderació actualitzada"
- deleteDriveFile: "Fitxer esborrat"
- deleteNote: "Nota esborrada"
- createGlobalAnnouncement: "Anunci global creat"
- createUserAnnouncement: "Anunci individual creat"
- updateGlobalAnnouncement: "Anunci global actualitzat"
- updateUserAnnouncement: "Anunci individual actualitzat "
- deleteGlobalAnnouncement: "Anunci global esborrat"
- deleteUserAnnouncement: "Anunci individual esborrat "
resetPassword: "Restableix la contrasenya"
suspendRemoteInstance: "Servidor remot suspès "
unsuspendRemoteInstance: "S'ha tret la suspensió del servidor remot"
- updateRemoteInstanceNote: "Nota de moderació de la instància remota actualitzada"
markSensitiveDriveFile: "Fitxer marcat com a sensible"
unmarkSensitiveDriveFile: "S'ha tret la marca de sensible del fitxer"
resolveAbuseReport: "Informe resolt"
- forwardAbuseReport: "Informe reenviat"
- updateAbuseReportNote: "Nota de moderació d'un informe actualitzat"
createInvitation: "Crear codi d'invitació "
createAd: "Anunci creat"
deleteAd: "Anunci esborrat"
@@ -2541,16 +2226,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "S'ha esborrat la decoració de l'avatar "
unsetUserAvatar: "Esborrar l'avatar d'aquest usuari"
unsetUserBanner: "Esborrar el bàner d'aquest usuari"
- createSystemWebhook: "Crear un SystemWebhook"
- updateSystemWebhook: "Actualitzar SystemWebhook"
- deleteSystemWebhook: "Esborrar SystemWebhook"
- createAbuseReportNotificationRecipient: "Crear un destinatari per l'informe de moderació "
- updateAbuseReportNotificationRecipient: "Actualitzar destinatari per l'informe de moderació "
- deleteAbuseReportNotificationRecipient: "Esborrar destinatari de l'informe de moderació "
- deleteAccount: "Esborrar el compte "
- deletePage: "Esborrar la pàgina"
- deleteFlash: "Esborrar el guió"
- deleteGalleryPost: "Esborrar la publicació de la galeria"
_fileViewer:
title: "Detall del fitxer"
type: "Tipus de fitxer"
@@ -2577,54 +2252,6 @@ _externalResourceInstaller:
_errors:
_invalidParams:
title: "Paràmetres no vàlids "
- description: "No hi ha suficient informació per carregar les dades del lloc extern. Confirma l'URL que hi ha escrita."
- _resourceTypeNotSupported:
- title: "El recurs extern no està suportat."
- description: "Aquesta mena de recurs no està suportat. Contacta amb l'administrador."
- _failedToFetch:
- title: "Ha fallat l'obtenció de dades"
- fetchErrorDescription: "Ha aparegut un error comunicant-se amb el lloc extern. Si després d'intentar-ho un altre cop no es resol, contacta amb l'administrador."
- parseErrorDescription: "Ha aparegut un error processant les dades carregades del lloc extern. Contacta amb l'administrador."
- _hashUnmatched:
- title: "Ha fallat la verificació de les dades"
- description: "Ha aparegut un error verificant les dades obtingudes. Com a mesura de seguretat la instal·lació no pot continuar. Contacta amb l'administrador."
- _pluginParseFailed:
- title: "Error d'AiScript"
- description: "Les dades sol·licitades s'han obtingut correctament, però hem trobat un error durant el processament d'AiScript. Contacta amb l'autor de l'afegit. Detalls de l'error es pot veure a la consola JavaScript."
- _pluginInstallFailed:
- title: "La instal·lació de l'afegit a fallat"
- description: "Ha aparegut un error durant la instal·lació de l'afegit. Intenta-ho una altra vegada. El detall de l'error es pot veure a la consola JavaScript."
- _themeParseFailed:
- title: "Ha fallat el processament del tema"
- description: "Les dades sol·licitades s'han obtingut correctament, però hem trobat un error durant el processament del tema. Contacta amb l'autor de l'afegit. Detalls de l'error es pot veure a la consola JavaScript."
- _themeInstallFailed:
- title: "La instal·lació del tema a fallat"
- description: "Ha aparegut un error durant la instal·lació del tema. Intenta-ho una altra vegada. El detall de l'error es pot veure a la consola JavaScript."
-_dataSaver:
- _media:
- title: "Carregant multimèdia "
- description: "Desactiva la càrrega automàtica d'imatges i vídeos. Les imatges i els vídeos amagats es carregaran quan es faci clic a sobre."
- _avatar:
- title: "Avatars animats"
- description: "Detenir l'animació dels avatars animats. Les imatges animades solen tenir un pes més gran que les imatges normals, reduint el tràfic disponible."
- _urlPreview:
- title: "Miniatures vista prèvia de l'URL"
- description: "Les imatges en miniatura que serveixen com a vista prèvia de les URLs no es tornaran a carregar."
- _code:
- title: "Ressaltat del codi "
_reversi:
total: "Total"
-_embedCodeGen:
- title: "Personalitza el codi per incrustar"
- header: "Mostrar la capçalera"
- autoload: "Carregar automàticament (no recomanat)"
- maxHeight: "Alçada màxima"
- maxHeightDescription: "0 anul·la la configuració màxima. Per evitar que continuï creixent verticalment, especifiqui qualsevol valor."
- maxHeightWarn: "El límit màxim d'alçada és nul (0). Si això no és un canvi previst, estableix el màxim d'alçada a un cert valor."
- previewIsNotActual: "La visualització és diferent de la que es mostra quan s'implanta."
- rounded: "Angle recte"
- border: "Afegeix un marc al contenidor"
- applyToPreview: "Aplica a la vista prèvia"
- generateCode: "Crea el codi per incrustar"
- codeGenerated: "Codi generat"
- codeGeneratedDescription: "Si us plau, enganxeu el codi generat al lloc web."
+
diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml
index caf6d6e163..e778bc4fdc 100644
--- a/locales/cs-CZ.yml
+++ b/locales/cs-CZ.yml
@@ -471,6 +471,7 @@ uiLanguage: "Jazyk uživatelského rozhraní"
aboutX: "O {x}"
emojiStyle: "Styl emoji"
native: "Výchozí"
+disableDrawer: "Nepoužívat šuplíkové menu"
showNoteActionsOnlyHover: "Zobrazit akce poznámky jenom při naběhnutí myši"
noHistory: "Žádná historie"
signinHistory: "Historie přihlášení"
@@ -657,7 +658,10 @@ abuseReported: "Nahlášení bylo odesláno. Děkujeme převelice."
reporter: "Nahlásil"
reporteeOrigin: "Původ nahlášení"
reporterOrigin: "Původ nahlasovače"
+forwardReport: "Přeposlat nahlášení do vzdálené instance"
+forwardReportIsAnonymous: "Místo vašeho účtu se ve vzdálené instanci zobrazí anonymní systémový účet jako nahlašovač."
send: "Odeslat"
+abuseMarkAsResolved: "Označit nahlášení jako vyřešené"
openInNewTab: "Otevřít v nové kartě"
openInSideView: "Otevřít v bočním panelu"
defaultNavigationBehaviour: "Výchozí chování navigace"
@@ -1089,16 +1093,11 @@ doYouAgree: "Souhlasíte?"
beSureToReadThisAsItIsImportant: "Přečtěte si prosím tyto důležité informace."
iHaveReadXCarefullyAndAgree: "Přečetl jsem si text \"{x}\" a souhlasím s ním."
icon: "Avatar"
-replies: "Odpovědět"
+replies: "Odpovědi"
renotes: "Přeposlat"
sourceCode: "Zdrojový kód"
flip: "Otočit"
lastNDays: "Posledních {n} dnů"
-surrender: "Zrušit"
-_delivery:
- stop: "Suspendováno"
- _type:
- none: "Publikuji"
_initialAccountSetting:
accountCreated: "Váš účet byl úspěšně vytvořen!"
letsStartAccountSetup: "Pro začátek si nastavte svůj profil."
@@ -1629,6 +1628,7 @@ _theme:
buttonBg: "Pozadí tlačítka"
buttonHoverBg: "Pozadí tlačítka (Hover)"
inputBorder: "Ohraničení vstupního pole"
+ listItemHoverBg: "Pozadí položky seznamu (Hover)"
driveFolderBg: "Pozadí složky disku"
wallpaperOverlay: "Překrytí tapety"
badge: "Odznak"
@@ -1640,6 +1640,8 @@ _sfx:
note: "Poznámky"
noteMy: "Moje poznámka"
notification: "Oznámení"
+ antenna: "Antény"
+ channel: "Oznámení kanálu"
_ago:
future: "Budoucí"
justNow: "Teď"
@@ -1661,6 +1663,7 @@ _2fa:
registerTOTP: "Registrovat aplikaci autentizátoru"
step1: "Nejprve si do zařízení nainstalujte aplikaci pro ověřování (například {a} nebo {b})."
step2: "Poté naskenujte QR kód zobrazený na této obrazovce."
+ step2Click: "Kliknutím na tento QR kód můžete zaregistrovat 2FA do bezpečnostního klíče nebo aplikace autentizace telefonu."
step3Title: "Zadejte ověřovací kód"
step3: "Pro dokončení nastavení zadejte token poskytnutý vaší aplikací."
step4: "Od této chvíle budou všechny budoucí pokusy o přihlášení vyžadovat tento přihlašovací token."
@@ -1714,7 +1717,7 @@ _auth:
shareAccessTitle: "Udělovat oprávnění k aplikacím"
shareAccess: "Chcete autorizovat \"{name}\" pro přístup k tomuto účtu?"
shareAccessAsk: "Opravdu chcete této aplikaci povolit přístup k vašemu účtu?"
- permission: "{name} požaduje tato oprávnění"
+ permission: "{jméno} požaduje tato oprávnění"
permissionAsk: "Tato aplikace požaduje následující oprávnění"
pleaseGoBack: "Vraťte se prosím zpět do aplikace"
callback: "Návrat k aplikaci"
@@ -1938,7 +1941,7 @@ _notification:
youGotMention: "{name} vás zmínil"
youGotReply: "{name} vám odpověděl"
youGotQuote: "{name} vás citoval"
- youRenoted: "Poznámka od {name}"
+ youRenoted: "Poznámka od {jméno}"
youWereFollowed: "Máte nového následovníka"
youReceivedFollowRequest: "Obdrželi jste žádost o sledování"
yourFollowRequestAccepted: "Vaše žádost o sledování byla přijata"
@@ -1958,7 +1961,6 @@ _notification:
receiveFollowRequest: "Obdržené žádosti o sledování"
followRequestAccepted: "Přijaté žádosti o sledování"
achievementEarned: "Úspěch odemčen"
- login: "Přihlásit se"
app: "Oznámení z propojených aplikací"
_actions:
followBack: "vás začal sledovat zpět"
@@ -2006,6 +2008,7 @@ _webhookSettings:
createWebhook: "Vytvořit Webhook"
name: "Jméno"
secret: "Tajné"
+ events: "Události Webhook"
active: "Zapnuto"
_events:
follow: "Při sledování uživatele"
@@ -2015,13 +2018,10 @@ _webhookSettings:
renote: "Při renotaci poznámky"
reaction: "Při obdržení reakce"
mention: "Při zmínce"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Email"
_moderationLogTypes:
suspend: "Zmrazit"
resetPassword: "Resetovat heslo"
createInvitation: "Vygenerovat pozvánku"
_reversi:
total: "Celkem"
+
diff --git a/locales/da-DK.yml b/locales/da-DK.yml
index 5eb7a5a5f4..d1fbec9f67 100644
--- a/locales/da-DK.yml
+++ b/locales/da-DK.yml
@@ -1,4 +1,3 @@
---
_lang_: "Dansk"
-headlineMisskey: ""
-introMisskey: "ようこそ!Misskeyは、オープンソースの分散型マイクロブログサービスです。\n「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
+
diff --git a/locales/de-DE.yml b/locales/de-DE.yml
index 4e2bd06934..43808117bd 100644
--- a/locales/de-DE.yml
+++ b/locales/de-DE.yml
@@ -1,8 +1,8 @@
---
_lang_: "Deutsch"
headlineMisskey: "Ein durch Notizen verbundenes Netzwerk"
-introMisskey: "Willkommen! Misskey ist eine dezentralisierte Open-Source Microblogging-Platform.\nVerfasse „Notizen“ um mitzuteilen, was gerade passiert oder um Ereignisse mit anderen zu teilen. 📡\nMit „Reaktionen“ kannst du außerdem schnell deine Gefühle über Notizen anderer Benutzer zum Ausdruck bringen. 👍\nEine neue Welt wartet auf dich! 🚀"
-poweredByMisskeyDescription: "{name} ist einer der durch die Open-Source-Plattform Misskey betriebenen Dienste."
+introMisskey: "Willkommen! Sharkey ist eine dezentralisierte Open-Source Microblogging-Platform.\nVerfasse „Notizen“ um mitzuteilen, was gerade passiert oder um Ereignisse mit anderen zu teilen. 📡\nMit „Reaktionen“ kannst du außerdem schnell deine Gefühle über Notizen anderer Benutzer zum Ausdruck bringen. 👍\nEine neue Welt wartet auf dich! 🚀"
+poweredByMisskeyDescription: "{name} ist einer der durch die Open-Source-Plattform Sharkey betriebenen Dienste die auf Misskey basiert ist (meist als \"Misskey-Instanz\" bezeichnet)."
monthAndDay: "{day}.{month}."
search: "Suchen"
notifications: "Benachrichtigungen"
@@ -15,7 +15,7 @@ gotIt: "Verstanden!"
cancel: "Abbrechen"
noThankYou: "Nein, danke"
enterUsername: "Benutzername eingeben"
-renotedBy: "Renote von {user}"
+renotedBy: "Geboostet von {user}"
noNotes: "Keine Notizen gefunden"
noNotifications: "Keine Benachrichtigungen gefunden"
instance: "Instanz"
@@ -105,13 +105,13 @@ followRequests: "Follow-Anfragen"
unfollow: "Entfolgen"
followRequestPending: "Follow-Anfrage ausstehend"
enterEmoji: "Gib ein Emoji ein"
-renote: "Renote"
-unrenote: "Renote zurücknehmen"
-renoted: "Renote getätigt."
-cantRenote: "Renote dieses Beitrags nicht möglich."
-cantReRenote: "Renote einer Renote nicht möglich."
+renote: "Boost"
+unrenote: "Boost zurücknehmen"
+renoted: "Boost getätigt."
+cantRenote: "Boosten dieses Beitrags nicht möglich."
+cantReRenote: "Boosten von einen Boost nicht möglich."
quote: "Zitieren"
-inChannelRenote: "Kanal-interner Renote"
+inChannelRenote: "Kanal-interner Boost"
inChannelQuote: "Kanal-internes Zitat"
pinnedNote: "Angeheftete Notiz"
pinned: "Angeheftet"
@@ -166,7 +166,7 @@ youCanCleanRemoteFilesCache: "Klicke auf den 🗑️-Knopf der Dateiverwaltungsa
cacheRemoteSensitiveFiles: "Sensitive Dateien von fremden Instanzen im Cache speichern"
cacheRemoteSensitiveFilesDescription: "Ist diese Einstellung deaktiviert, so werden sensitive Dateien fremder Instanzen direkt von dort ohne Zwischenspeicherung geladen."
flagAsBot: "Als Bot markieren"
-flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Misskeys interne Systeme dieses Benutzerkonto als Bot behandeln."
+flagAsBotDescription: "Aktiviere diese Option, falls dieses Benutzerkonto durch ein Programm gesteuert wird. Falls aktiviert, agiert es als Flag für andere Entwickler zur Verhinderung von endlosen Kettenreaktionen mit anderen Bots und lässt Sharkeys interne Systeme dieses Benutzerkonto als Bot behandeln."
flagAsCat: "Als Katze markieren"
flagAsCatDescription: "Aktiviere diese Option, um dieses Benutzerkonto als Katze zu markieren."
flagShowTimelineReplies: "Antworten in der Chronik anzeigen"
@@ -229,7 +229,7 @@ noUsers: "Keine Benutzer gefunden"
editProfile: "Profil bearbeiten"
noteDeleteConfirm: "Möchtest du diese Notiz wirklich löschen?"
pinLimitExceeded: "Du kannst nicht noch mehr Notizen anheften."
-intro: "Misskey ist installiert! Lass uns nun ein Administratorkonto einrichten."
+intro: "Sharkey ist installiert! Lass uns nun ein Administratorkonto einrichten."
done: "Fertig"
processing: "In Bearbeitung …"
preview: "Vorschau"
@@ -422,7 +422,7 @@ exploreFediverse: "Das Fediverse erkunden"
popularTags: "Beliebte Schlagwörter"
userList: "Liste"
about: "Über"
-aboutMisskey: "Über Misskey"
+aboutMisskey: "Über Sharkey"
administrator: "Administrator"
token: "Token"
2fa: "Zwei-Faktor-Authentifizierung"
@@ -491,6 +491,7 @@ uiLanguage: "Sprache der Benutzeroberfläche"
aboutX: "Über {x}"
emojiStyle: "Emoji-Stil"
native: "Nativ"
+disableDrawer: "Keine ausfahrbaren Menüs verwenden"
showNoteActionsOnlyHover: "Notizmenü nur bei Mouseover anzeigen"
noHistory: "Kein Verlauf gefunden"
signinHistory: "Anmeldungsverlauf"
@@ -571,7 +572,7 @@ sort: "Sortieren"
ascendingOrder: "Aufsteigende Reihenfolge"
descendingOrder: "Absteigende Reihenfolge"
scratchpad: "Testumgebung"
-scratchpadDescription: "Die Testumgebung bietet einen Bereich für AiScript-Experimente. Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Misskey überprüfen."
+scratchpadDescription: "Die Testumgebung bietet einen Bereich für AiScript-Experimente. Dort kannst du AiScript schreiben, ausführen sowie dessen Auswirkungen auf Sharkey überprüfen."
output: "Ausgabe"
script: "Skript"
disablePagesScript: "AiScript auf Seiten deaktivieren"
@@ -653,7 +654,7 @@ smtpSecureInfo: "Schalte dies aus, falls du STARTTLS verwendest."
testEmail: "Emailversand testen"
wordMute: "Wortstummschaltung"
regexpError: "Fehler in einem regulären Ausdruck"
-regexpErrorDescription: "Im regulären Ausdruck deiner in Zeile {line} von {tab}en Wortstummschaltungen ist ein Fehler aufgetreten:"
+regexpErrorDescription: "Im regulären Ausdruck deiner {tab}en Wortstummschaltungen ist ein Fehler aufgetreten:"
instanceMute: "Instanzstummschaltungen"
userSaysSomething: "{name} hat etwas gesagt"
makeActive: "Aktivieren"
@@ -686,7 +687,10 @@ abuseReported: "Deine Meldung wurde versendet. Vielen Dank."
reporter: "Melder"
reporteeOrigin: "Herkunft des Gemeldeten"
reporterOrigin: "Herkunft des Meldenden"
+forwardReport: "Meldung an fremde Instanz weiterleiten"
+forwardReportIsAnonymous: "Anstatt deines Benutzerkontos wird bei der fremden Instanz ein anonymes Systemkonto als Melder angezeigt."
send: "Senden"
+abuseMarkAsResolved: "Meldung als gelöst markieren"
openInNewTab: "In neuem Tab öffnen"
openInSideView: "In Seitenansicht öffnen"
defaultNavigationBehaviour: "Standardnavigationsverhalten"
@@ -705,14 +709,14 @@ unclip: "Aus Clip entfernen"
confirmToUnclipAlreadyClippedNote: "Diese Notiz ist bereits im \"{name}\" Clip enthalten. Möchtest du sie aus diesem Clip entfernen?"
public: "Öffentlich"
private: "Privat"
-i18nInfo: "Misskey wird durch freiwillige Helfer in viele verschiedene Sprachen übersetzt. Auf {link} kannst du mithelfen."
+i18nInfo: "Sharkey wird durch freiwillige Helfer in viele verschiedene Sprachen übersetzt. Auf {link} kannst du mithelfen."
manageAccessTokens: "Zugriffstokens verwalten"
accountInfo: "Benutzerkonto-Informationen"
notesCount: "Anzahl der Notizen"
repliesCount: "Anzahl gesendeter Antworten"
renotesCount: "Anzahl getätigter Renotes"
repliedCount: "Anzahl erhaltener Antworten"
-renotedCount: "Anzahl erhaltener Renotes"
+renotedCount: "Anzahl erhaltener Boosts"
followingCount: "Anzahl gefolgter Benutzer"
followersCount: "Anzahl an Followern"
sentReactionsCount: "Anzahl gesendeter Reaktionen"
@@ -759,7 +763,7 @@ onlineUsersCount: "{n} Benutzer sind online"
nUsers: "{n} Benutzer"
nNotes: "{n} Notizen"
sendErrorReports: "Fehlerberichte senden"
-sendErrorReportsDescription: "Ist diese Option aktiviert, so werden beim Auftreten von Fehlern detaillierte Fehlerinformationen an Misskey weitergegeben, was zur Verbesserung der Qualität von Misskey beiträgt.\nEnthalten in diesen Informationen sind u.a. die Version deines Betriebssystems, welchen Browser du verwendest und ein Verlauf deiner Aktivitäten innerhalb Misskey."
+sendErrorReportsDescription: "Ist diese Option aktiviert, so werden beim Auftreten von Fehlern detaillierte Fehlerinformationen an Sharkey weitergegeben, was zur Verbesserung der Qualität von Sharkey beiträgt.\nEnthalten in diesen Informationen sind u.a. die Version deines Betriebssystems, welchen Browser du verwendest und ein Verlauf deiner Aktivitäten innerhalb Sharkey."
myTheme: "Mein Farbschema"
backgroundColor: "Hintergrundfarbe"
accentColor: "Akzentfarbe"
@@ -853,7 +857,7 @@ hashtags: "Hashtags"
troubleshooting: "Problembehandlung"
useBlurEffect: "Weichzeichnungseffekt in der Benutzeroberfläche verwenden"
learnMore: "Mehr erfahren"
-misskeyUpdated: "Misskey wurde aktualisiert!"
+misskeyUpdated: "Sharkey wurde aktualisiert!"
whatIsNew: "Änderungen anzeigen"
translate: "Übersetzen"
translatedFrom: "Aus {x} übersetzt"
@@ -980,8 +984,9 @@ numberOfLikes: "\"Gefällt mir\"-Anzahl"
show: "Anzeigen"
neverShow: "Nicht wieder anzeigen"
remindMeLater: "Vielleicht später"
-didYouLikeMisskey: "Gefällt dir Misskey?"
-pleaseDonate: "Misskey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!"
+didYouLikeMisskey: "Gefällt dir Sharkey?"
+pleaseDonate: "Sharkey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!"
+pleaseDonateInstance: "Du kannst {host} auch direkt unterstützen, indem du an deine Instanz Administration spendest."
roles: "Rollen"
role: "Rolle"
noRole: "Rolle nicht gefunden"
@@ -1001,7 +1006,7 @@ permissionDeniedError: "Aktion verweigert"
permissionDeniedErrorDescription: "Dieses Benutzerkonto besitzt nicht die Berechtigung, um diese Aktion auszuführen."
preset: "Vorlage"
selectFromPresets: "Aus Vorlagen wählen"
-achievements: "Errungenschaften"
+achievements: "Erfolge"
gotInvalidResponseError: "Ungültige Antwort des Servers"
gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
thisPostMayBeAnnoying: "Dieser Beitrag stört eventuell andere Benutzer."
@@ -1096,7 +1101,7 @@ rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Diese Rollen müssen öffe
cancelReactionConfirm: "Möchtest du deine Reaktion wirklich löschen?"
changeReactionConfirm: "Möchtest du deine Reaktion wirklich ändern?"
later: "Später"
-goToMisskey: "Zu Misskey"
+goToMisskey: "Zu Sharkey"
additionalEmojiDictionary: "Zusätzliche Emoji-Wörterbücher"
installed: "Installiert"
branding: "Branding"
@@ -1161,6 +1166,8 @@ impressumDescription: "In manchen Ländern, wie Deutschland und dessen Umgebung,
privacyPolicy: "Datenschutzerklärung"
privacyPolicyUrl: "Datenschutzerklärungs-URL"
tosAndPrivacyPolicy: "Nutzungsbedingungen und Datenschutzerklärung"
+donation: "Spenden"
+donationUrl: "Spenden-URL"
avatarDecorations: "Profilbilddekoration"
attach: "Anbringen"
detach: "Entfernen"
@@ -1180,11 +1187,6 @@ decorate: "Dekorieren"
addMfmFunction: "MFM hinzufügen"
sfx: "Soundeffekte"
lastNDays: "Letzten {n} Tage"
-surrender: "Abbrechen"
-_delivery:
- stop: "Gesperrt"
- _type:
- none: "Wird veröffentlicht"
_announcement:
forExistingUsers: "Nur für existierende Nutzer"
forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
@@ -1264,7 +1266,7 @@ _accountMigration:
moveTo: "Dieses Konto zu einem neuen migrieren"
moveToLabel: "Umzugsziel:"
moveCannotBeUndone: "Die Migration eines Benutzerkontos ist unwiderruflich."
- moveAccountDescription: "Hierdurch wird dein Konto zu einem anderen migriert.\n ・Follower von diesem Konto werden automatisch auf das neue Konto migriert\n ・Dieses Konto wird allen Nutzern, denen es derzeit folgt, nicht mehr folgen\n ・Mit diesem Konto können keine neuen Notizen usw. erstellt werden\n\nWährend die Migration der Follower automatisch erfolgt, muss die Migration der Konten, denen du folgst, manuell vorbereitet werden. Exportiere hierzu die Liste der gefolgten Nutzer über das Einstellungsmenu, und importiere diese Liste im neuen Konto. Das gleiche Verfahren gilt für erstellte Listen und stummgeschaltete oder blockierte Nutzer.\n\n(Diese Erklärung gilt für Misskey v13.12.0 oder später. Die Funktionsweise andere ActivityPub-Software, beispielsweise Mastodon, kann hiervon abweichen.)"
+ moveAccountDescription: "Hierdurch wird dein Konto zu einem anderen migriert.\n ・Follower von diesem Konto werden automatisch auf das neue Konto migriert\n ・Dieses Konto wird allen Nutzern, denen es derzeit folgt, nicht mehr folgen\n ・Mit diesem Konto können keine neuen Notizen usw. erstellt werden\n\nWährend die Migration der Follower automatisch erfolgt, muss die Migration der Konten, denen du folgst, manuell vorbereitet werden. Exportiere hierzu die Liste der gefolgten Nutzer über das Einstellungsmenu, und importiere diese Liste im neuen Konto. Das gleiche Verfahren gilt für erstellte Listen und stummgeschaltete oder blockierte Nutzer.\n\n(Diese Erklärung gilt für Sharkey v13.12.0 oder später. Die Funktionsweise andere ActivityPub-Software, beispielsweise Mastodon, kann hiervon abweichen.)"
moveAccountHowTo: "Um ein Konto zu migrieren, erstelle zuerst auf dem Umzugsziel einen Alias für dieses Konto.\nGib dann das Umzugsziel in folgendem Format ein: @username@server.example.com"
startMigration: "Migrieren"
migrationConfirm: "Dieses Konto wirklich zu {account} umziehen? Sobald der Umzug beginnt, kann er nicht rückgängig gemacht werden, und dieses Konto nicht wieder im ursprünglichen Zustand verwendet werden."
@@ -1275,26 +1277,26 @@ _achievements:
earnedAt: "Freigeschaltet am"
_types:
_notes1:
- title: "Hallo Misskey!"
+ title: "Hallo Sharkey!"
description: "Sende deine erste Notiz"
- flavor: "Hab eine schöne Zeit mit Misskey!"
+ flavor: "Hab eine schöne Zeit mit Sharkey!"
_notes10:
- title: "Ein paar Notizen"
+ title: "Notizblog"
description: "10 Notizen gesendet"
_notes100:
- title: "Viele Notizen"
+ title: "Schreiberling"
description: "100 Notizen gesendet"
_notes500:
- title: "Überschüttet mit Notizen"
+ title: "Autor"
description: "500 Notizen gesendet"
_notes1000:
- title: "Berg an Notizen"
+ title: "Bestseller"
description: "1.000 Notizen gesendet"
_notes5000:
- title: "Überquellende Notizen"
+ title: "Dicker Wälzer"
description: "5.000 Notizen gesendet"
_notes10000:
- title: "Supernotiz"
+ title: "Verlagshaus"
description: "10.000 Notizen gesendet"
_notes20000:
title: "Brauche... mehr... Notizen..."
@@ -1321,28 +1323,28 @@ _achievements:
title: "Notizversum"
description: "90.000 Notizen gesendet"
_notes100000:
- title: "ALL YOUR NOTE ARE BELONG TO US"
+ title: "ALL YOUR NOTES ARE BELONG TO US"
description: "100.000 Notizen gesendet"
flavor: "Du hast wirklich viel zu sagen."
_login3:
- title: "Anfänger Ⅰ"
+ title: "Neuling Ⅰ"
description: "An 3 Tagen eingeloggt"
flavor: "Nenn' mich ab heute Misskist"
_login7:
- title: "Anfänger Ⅱ"
+ title: "Neuling Ⅱ"
description: "An 7 Tagen eingeloggt"
flavor: "Na, eingewöht?"
_login15:
- title: "Anfänger Ⅲ"
+ title: "Neuling Ⅲ"
description: "An 15 Tagen eingeloggt"
_login30:
- title: "Misskist Ⅰ"
+ title: "Fedizen Ⅰ"
description: "An 30 Tagen eingeloggt"
_login60:
- title: "Misskist Ⅱ"
+ title: "Fedizen Ⅱ"
description: "An 60 Tagen eingeloggt"
_login100:
- title: "Misskist Ⅲ"
+ title: "Fedizen Ⅲ"
description: "An 100 Tagen eingeloggt"
flavor: "Violent Misskist"
_login200:
@@ -1355,14 +1357,14 @@ _achievements:
title: "Stammbesucher Ⅲ"
description: "An 400 Tagen eingeloggt"
_login500:
- title: "Veteran Ⅰ"
+ title: "Alter Hase Ⅰ"
description: "An 500 Tagen eingeloggt"
flavor: "Meine Kameraden, ich liebe sie, die Notizen."
_login600:
- title: "Veteran Ⅱ"
+ title: "Alter Hase Ⅱ"
description: "An 600 Tagen eingeloggt"
_login700:
- title: "Veteran Ⅲ"
+ title: "Alter Hase Ⅲ"
description: "An 700 Tagen eingeloggt"
_login800:
title: "Meister der Notizen Ⅰ"
@@ -1371,39 +1373,39 @@ _achievements:
title: "Meister der Notizen Ⅱ"
description: "An 900 Tagen eingeloggt"
_login1000:
- title: "Meister der Notizen Ⅲ"
+ title: "Wie die Zeit vergeht"
description: "An 1000 Tagen eingeloggt"
- flavor: "Danke, dass du Misskey nutzt!"
+ flavor: "Danke, dass du Sharkey nutzt!"
_noteClipped1:
- title: "Muss... clippen..."
+ title: "Das merk ich mir"
description: "Die erste Notiz geclippt"
_noteFavorited1:
title: "Sternengucker"
description: "Eine Notiz als Favorit markiert"
_myNoteFavorited1:
- title: "Sternensucher"
+ title: "Hilfreich"
description: "Ein anderer Benutzer hat eine deiner Notizen als Favoriten markiert"
_profileFilled:
title: "Perfekte Vorbereitung"
description: "Fülle dein Profil aus"
_markedAsCat:
- title: "Ich der Kater"
- description: "Markiere dein Konto als Katze"
- flavor: "Einen Namen bekommst du später. "
+ title: "Das Königreich der Katzen"
+ description: "Markiere dein Profil als Katze"
+ flavor: "Einen Namen bekommst du später~ "
_following1:
- title: "Das Folgen beginnt"
+ title: "Immer auf dem neusten Stand"
description: "Du folgst deiner ersten Person"
_following10:
title: "Folge ihnen... folge ihnen..."
description: "Du folgst über 10 Leuten"
_following50:
- title: "Viele Freunde"
+ title: "Lieblingsposter"
description: "Du folgst über 50 Leuten"
_following100:
- title: "100 Freunde"
+ title: "Die Top 100"
description: "Du folgst über 100 Leuten"
_following300:
- title: "Freundeüberschuss"
+ title: "Folgen, folgen, folgen!"
description: "Du folgst über 300 Leuten"
_followers1:
title: "Der erste Follower"
@@ -1418,7 +1420,7 @@ _achievements:
title: "Beliebt"
description: "Die Anzahl deiner Follower hat 100 überschritten"
_followers300:
- title: "Eine geordnete Reihe, bitte!"
+ title: "Teil des Schiffs, Teil der Crew"
description: "Die Anzahl deiner Follower hat 300 überschritten"
_followers500:
title: "Funkmast"
@@ -1427,31 +1429,31 @@ _achievements:
title: "Influencer"
description: "Die Anzahl deiner Follower hat 1000 überschritten"
_collectAchievements30:
- title: "Sammler der Errungenschaften"
+ title: "Sammler der Erfolge"
description: "Schalte 30 Errungenschaften frei"
_viewAchievements3min:
- title: "Fan von Errungenschaften"
+ title: "Ausstellung"
description: "Schau dir die Liste deiner Errungenschaften für mindestens 3 Minuten an"
_iLoveMisskey:
- title: "I Love Misskey"
- description: "Sende \"I ❤ #Misskey\""
- flavor: "Danke, dass du Misskey verwendest! - vom Entwicklerteam"
+ title: "I Love Sharkey"
+ description: "Sende \"I ❤ #Sharkey\""
+ flavor: "Danke, dass du Sharkey verwendest! - vom Entwicklerteam"
_foundTreasure:
title: "Schatzsuche"
description: "Du hast einen verborgenen Schatz gefunden"
_client30min:
title: "Kurze Pause"
- description: "Habe Misskey für mindestens 30 Minuten geöffnet"
+ description: "Habe Sharkey für mindestens 30 Minuten geöffnet"
_client60min:
- title: "Munter mit Misskey"
- description: "Habe Misskey für mindestens 60 Minuten geöffnet"
+ title: "Munter mit Sharkey"
+ description: "Habe Sharkey für mindestens 60 Minuten geöffnet"
_noteDeletedWithin1min:
- title: "Ups"
+ title: "Katze auf der Tastatur"
description: "Lösche eine Notiz innerhalb von 1 Minute nachdem sie gesendet wurde"
_postedAtLateNight:
title: "Nachtaktiv"
description: "Sende mitten in der Nacht eine Notiz"
- flavor: "Geh bald schlafen."
+ flavor: "Echte Katzen sind nunmal nachtaktiv~"
_postedAt0min0sec:
title: "Zeitansage"
description: "Sende um 00:00 eine Notiz"
@@ -1466,7 +1468,7 @@ _achievements:
title: "Analyst"
description: "Schau dir die Messwerte der Instanz an"
_outputHelloWorldOnScratchpad:
- title: "Hallo Welt!"
+ title: "Junghacker"
description: "Gib \"hello world\" in der Testumgebung aus"
_open3windows:
title: "Splitscreen"
@@ -1475,25 +1477,25 @@ _achievements:
title: "Zyklischer Verweis"
description: "Versuche, in Drive einen Zirkelbezug von Ordnern herzustellen"
_reactWithoutRead:
- title: "Hast du das wirklich gelesen?"
+ title: "Erst reagieren, dann lesen"
description: "Reagiere auf eine Notiz mit mindestens 100 Zeichen innerhalb von 3 Sekunden der Erstellung der Notiz"
_clickedClickHere:
title: "Klicke hier"
description: "Du hast hier geklickt"
_justPlainLucky:
- title: "Pures Glück"
+ title: "Glück 100"
description: "Kann alle 10 Sekunden mit einer Warscheinlichkeit von 0.005% erhalten werden"
_setNameToSyuilo:
title: "Gottkomplex"
description: "Setze deinen Namen auf \"syuilo\""
_passedSinceAccountCreated1:
- title: "Einjahresjubiläum"
+ title: "Davon erzähle ich meinen Enkeln"
description: "Seit der Erstellung deines Kontos ist 1 Jahr vergangen"
_passedSinceAccountCreated2:
- title: "Zweijahresjubiläum"
+ title: "Diese Software hat mich zur Katze gemacht"
description: "Seit der Erstellung deines Kontos sind 2 Jahre vergangen"
_passedSinceAccountCreated3:
- title: "Dreijahresjubiläum"
+ title: "Goldene Zeit"
description: "Seit der Erstellung deines Kontos sind 3 Jahre vergangen"
_loggedInOnBirthday:
title: "Alles Gute Zum Geburtstag"
@@ -1501,15 +1503,15 @@ _achievements:
_loggedInOnNewYearsDay:
title: "Frohes Neujahr"
description: "Logge dich am Neujahrstag ein"
- flavor: "Auf ein weiteres tolles Jahr in dieser Instanz"
+ flavor: "Auf ein weiteres tolles Jahr in diesem Universum!"
_cookieClicked:
- title: "Ein Spiel, in dem du auf einen Keks klickst"
+ title: "Kreise klicken für Omas"
description: "Den Keks geklickt"
flavor: "Bist du hier richtig?"
_brainDiver:
title: "Brain Diver"
description: "Sende den Link zu Brain Diver"
- flavor: "Misskey-Misskey La-Tu-Ma"
+ flavor: "Sharkey-Sharkey La-Tu-Ma"
_smashTestNotificationButton:
title: "Testüberfluss"
description: "Betätige den Benachrichtigungstest mehrfach innerhalb einer extrem kurzen Zeitspanne"
@@ -1674,12 +1676,12 @@ _registry:
domain: "Domain"
createKey: "Schlüssel erstellen"
_aboutMisskey:
- about: "Misskey ist Open-Source-Software, welche von syuilo seit 2014 entwickelt wird."
+ about: "Sharkey ist Open-Source-Software basiert auf Misskey welche von syuilo seit 2014 entwickelt wird."
contributors: "Hauptmitwirkende"
allContributors: "Alle Mitwirkenden"
source: "Quellcode"
- translation: "Misskey übersetzen"
- donate: "An Misskey spenden"
+ translation: "Sharkey übersetzen"
+ donate: "An Sharkey spenden"
morePatrons: "Wir schätzen ebenso die Unterstützung vieler anderer hier nicht gelisteter Personen sehr. Danke! 🥰"
patrons: "UnterstützerInnen"
projectMembers: "Projektmitglieder"
@@ -1784,6 +1786,7 @@ _theme:
buttonBg: "Hintergrund von Schaltflächen"
buttonHoverBg: "Hintergrund von Schaltflächen (Mouseover)"
inputBorder: "Rahmen von Eingabefeldern"
+ listItemHoverBg: "Hintergrund von Listeneinträgen (Mouseover)"
driveFolderBg: "Hintergrund von Drive-Ordnern"
wallpaperOverlay: "Hintergrundbild-Overlay"
badge: "Wappen"
@@ -1795,6 +1798,8 @@ _sfx:
note: "Notizen"
noteMy: "Meine Notizen"
notification: "Benachrichtigungen"
+ antenna: "Antennen"
+ channel: "Kanalbenachrichtigung"
_ago:
future: "Zukunft"
justNow: "Gerade eben"
@@ -1816,6 +1821,7 @@ _2fa:
registerTOTP: "Authentifizierungs-App registrieren"
step1: "Installiere zuerst eine Authentifizierungsapp (z.B. {a} oder {b}) auf deinem Gerät."
step2: "Dann, scanne den angezeigten QR-Code mit deinem Gerät."
+ step2Click: "Durch Klicken dieses QR-Codes kannst du Verifikation mit deinem Security-Token oder einer App registrieren."
step2Uri: "Nutzt du ein Desktopprogramm, gib folgende URI eingeben"
step3Title: "Authentifizierungsscode eingeben"
step3: "Gib zum Abschluss den Code (Token) ein, der von deiner App angezeigt wird."
@@ -2108,7 +2114,7 @@ _notification:
youGotMention: "{name} hat dich erwähnt"
youGotReply: "{name} hat dir geantwortet"
youGotQuote: "{name} hat dich zitiert"
- youRenoted: "Renote deiner Notiz von {name}"
+ youRenoted: "Boost deiner Notiz von {name}"
youWereFollowed: "ist dir gefolgt"
youReceivedFollowRequest: "Du hast eine Follow-Anfrage erhalten"
yourFollowRequestAccepted: "Deine Follow-Anfrage wurde akzeptiert"
@@ -2137,7 +2143,6 @@ _notification:
receiveFollowRequest: "Erhaltene Follow-Anfragen"
followRequestAccepted: "Akzeptierte Follow-Anfragen"
achievementEarned: "Errungenschaft freigeschaltet"
- login: "Anmelden"
app: "Benachrichtigungen von Apps"
_actions:
followBack: "folgt dir nun auch"
@@ -2187,6 +2192,7 @@ _webhookSettings:
createWebhook: "Webhook erstellen"
name: "Name"
secret: "Secret"
+ events: "Webhook-Ereignisse"
active: "Aktiviert"
_events:
follow: "Wenn du jemandem folgst"
@@ -2196,10 +2202,6 @@ _webhookSettings:
renote: "Wenn du ein Renote erhältst"
reaction: "Wenn du eine Reaktion erhältst"
mention: "Wenn du erwähnt wirst"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Email"
_moderationLogTypes:
createRole: "Rolle erstellt"
deleteRole: "Rolle gelöscht"
@@ -2289,3 +2291,4 @@ _reversi:
black: "Schwarz"
white: "Weiß"
total: "Gesamt"
+
diff --git a/locales/el-GR.yml b/locales/el-GR.yml
index 4657842ca5..bb5639a741 100644
--- a/locales/el-GR.yml
+++ b/locales/el-GR.yml
@@ -301,6 +301,8 @@ _theme:
_sfx:
note: "Σημειώματα"
notification: "Ειδοποιήσεις"
+ antenna: "Αντένες"
+ channel: "Ειδοποιήσεις καναλιών"
_ago:
future: "Μελλοντικό"
justNow: "Μόλις τώρα"
@@ -378,7 +380,6 @@ _notification:
renote: "Κοινοποίηση σημειώματος"
quote: "Παράθεση"
reaction: "Αντιδράσεις"
- login: "Σύνδεση"
_actions:
reply: "Απάντηση"
renote: "Κοινοποίηση σημειώματος"
@@ -397,3 +398,4 @@ _moderationLogTypes:
suspend: "Αποβολή"
_reversi:
total: "Σύνολο"
+
diff --git a/locales/en-US.yml b/locales/en-US.yml
index 6ea7fb4f8d..64033d6a2b 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1,16 +1,13 @@
---
_lang_: "English"
headlineMisskey: "A network connected by notes"
-introMisskey: "Welcome! Misskey is an open source, decentralized microblogging service.\nCreate \"notes\" to share your thoughts with everyone around you. 📡\nWith \"reactions\", you can also quickly express your feelings about everyone's notes. 👍\nLet's explore a new world! 🚀"
-poweredByMisskeyDescription: "{name} is one of the services powered by the open source platform Misskey (referred to as a \"Misskey instance\")."
+introMisskey: "Welcome! Sharkey is an open source, decentralized microblogging service.\nCreate \"notes\" to share your thoughts with everyone around you. 📡\nWith \"reactions\", you can also quickly express your feelings about everyone's notes. 👍\nLet's explore a new world! 🚀"
+poweredByMisskeyDescription: "{name} is one of the services powered by the open source platform Sharkey which is based on Misskey (referred to as a \"Misskey instance\")."
monthAndDay: "{month}/{day}"
search: "Search"
notifications: "Notifications"
username: "Username"
password: "Password"
-initialPasswordForSetup: "Initial password for setup"
-initialPasswordIsIncorrect: "Initial password for setup is incorrect"
-initialPasswordForSetupDescription: "Use the password you entered in the configuration file if you installed Misskey yourself.\n If you are using a Misskey hosting service, use the password provided.\n If you have not set a password, leave it blank to continue."
forgotPassword: "Forgot password"
fetchingAsApObject: "Fetching from the Fediverse..."
ok: "OK"
@@ -18,7 +15,7 @@ gotIt: "Got it!"
cancel: "Cancel"
noThankYou: "Not now"
enterUsername: "Enter username"
-renotedBy: "Renoted by {user}"
+renotedBy: "Boosted by {user}"
noNotes: "No notes"
noNotifications: "No notifications"
instance: "Instance"
@@ -37,6 +34,7 @@ signup: "Sign Up"
uploading: "Uploading..."
save: "Save"
users: "Users"
+approvals: "Approvals"
addUser: "Add a user"
favorite: "Add to favorites"
favorites: "Favorites"
@@ -48,22 +46,22 @@ pin: "Pin to profile"
unpin: "Unpin from profile"
copyContent: "Copy contents"
copyLink: "Copy link"
-copyLinkRenote: "Copy renote link"
+copyLinkRenote: "Copy boost link"
delete: "Delete"
deleteAndEdit: "Delete and edit"
-deleteAndEditConfirm: "Are you sure you want to redraft this note? This means you will lose all reactions, renotes, and replies to it."
+deleteAndEditConfirm: "Are you sure you want to redraft this note? This means you will lose all reactions, boosts, and replies to it."
addToList: "Add to list"
addToAntenna: "Add to antenna"
sendMessage: "Send a message"
copyRSS: "Copy RSS"
copyUsername: "Copy username"
+openRemoteProfile: "Open remote profile"
copyUserId: "Copy user ID"
copyNoteId: "Copy note ID"
copyFileId: "Copy file ID"
copyFolderId: "Copy folder ID"
copyProfileUrl: "Copy profile URL"
searchUser: "Search for a user"
-searchThisUsersNotes: "Search this user’s notes"
reply: "Reply"
loadMore: "Load more"
showMore: "Show more"
@@ -109,17 +107,16 @@ followRequests: "Follow requests"
unfollow: "Unfollow"
followRequestPending: "Follow request pending"
enterEmoji: "Enter an emoji"
-renote: "Renote"
-unrenote: "Remove renote"
-renoted: "Renoted."
-renotedToX: "Renoted to {name}."
-cantRenote: "This post can't be renoted."
-cantReRenote: "A renote can't be renoted."
+renote: "Boost"
+unrenote: "Remove boost"
+renoted: "Boosted."
+quoted: "Quoted."
+rmboost: "Unboosted."
+cantRenote: "This post can't be boosted."
+cantReRenote: "A boost can't be boosted."
quote: "Quote"
-inChannelRenote: "Channel-only Renote"
+inChannelRenote: "Channel-only Boost"
inChannelQuote: "Channel-only Quote"
-renoteToChannel: "Renote to channel"
-renoteToOtherChannel: "Renote to other channel"
pinnedNote: "Pinned note"
pinned: "Pin to profile"
you: "You"
@@ -129,36 +126,39 @@ add: "Add"
reaction: "Reactions"
reactions: "Reactions"
emojiPicker: "Emoji picker"
-pinnedEmojisForReactionSettingDescription: "Set the emojis to be pinned and displayed when reacting."
-pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker."
+pinnedEmojisForReactionSettingDescription: "Set the emojis which should be pinned and displayed immediately when reacting."
+pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker"
emojiPickerDisplay: "Emoji picker display"
overwriteFromPinnedEmojisForReaction: "Override from reaction settings"
overwriteFromPinnedEmojis: "Override from general settings"
reactionSettingDescription2: "Drag to reorder, click to delete, press \"+\" to add."
rememberNoteVisibility: "Remember note visibility settings"
attachCancel: "Remove attachment"
-deleteFile: "Delete file"
+deleteFile: "File deleted"
markAsSensitive: "Mark as sensitive"
unmarkAsSensitive: "Unmark as sensitive"
enterFileName: "Enter filename"
mute: "Mute"
unmute: "Unmute"
-renoteMute: "Mute Renotes"
-renoteUnmute: "Unmute Renotes"
+renoteMute: "Mute Boosts"
+renoteUnmute: "Unmute Boosts"
block: "Block"
unblock: "Unblock"
+markAsNSFW: "Mark all media from user as NSFW"
suspend: "Suspend"
unsuspend: "Unsuspend"
blockConfirm: "Are you sure that you want to block this account?"
unblockConfirm: "Are you sure that you want to unblock this account?"
+nsfwConfirm: "Are you sure that you want to mark all media from this account as NSFW?"
+unNsfwConfirm: "Are you sure that you want to unmark all media from this account as NSFW?"
suspendConfirm: "Are you sure that you want to suspend this account?"
+approveConfirm: "Are you sure that you want to approve this account?"
unsuspendConfirm: "Are you sure that you want to unsuspend this account?"
selectList: "Select a list"
editList: "Edit list"
selectChannel: "Select a channel"
selectAntenna: "Select an antenna"
editAntenna: "Edit antenna"
-createAntenna: "Create an antenna"
selectWidget: "Select a widget"
editWidgets: "Edit widgets"
editWidgetsExit: "Done"
@@ -170,14 +170,16 @@ emojiUrl: "Emoji URL"
addEmoji: "Add an emoji"
settingGuide: "Recommended settings"
cacheRemoteFiles: "Cache remote files"
-cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote servers. Disabling this will decrease storage usage, but increase traffic, as thumbnails will not be generated."
+cacheRemoteFilesDescription: "When this setting is disabled, remote files are loaded directly from the remote instance. Disabling this will decrease storage usage, but increase traffic, as thumbnails will not be generated."
youCanCleanRemoteFilesCache: "You can clear the cache by clicking the 🗑️ button in the file management view."
cacheRemoteSensitiveFiles: "Cache sensitive remote files"
cacheRemoteSensitiveFilesDescription: "When this setting is disabled, sensitive remote files are loaded directly from the remote instance without caching."
flagAsBot: "Mark this account as a bot"
-flagAsBotDescription: "Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Misskey's internal systems to treat this account as a bot."
+flagAsBotDescription: "Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Sharkey's internal systems to treat this account as a bot."
flagAsCat: "Mark this account as a cat"
flagAsCatDescription: "Enable this option to mark this account as a cat."
+flagSpeakAsCat: "Speak as a cat"
+flagSpeakAsCatDescription: "Your posts will get nyanified when in cat mode."
flagShowTimelineReplies: "Show replies in timeline"
flagShowTimelineRepliesDescription: "Shows replies of users to notes of other users in the timeline if turned on."
autoAcceptFollowed: "Automatically approve follow requests from users you're following"
@@ -185,10 +187,6 @@ addAccount: "Add account"
reloadAccountsList: "Reload account list"
loginFailed: "Failed to sign in"
showOnRemote: "View on remote instance"
-continueOnRemote: "Continue on a remote server"
-chooseServerOnMisskeyHub: "Choose a server from the Misskey Hub"
-specifyServerHost: "Specify a server host directly"
-inputHostName: "Enter the domain"
general: "General"
wallpaper: "Wallpaper"
setWallpaper: "Set wallpaper"
@@ -199,7 +197,6 @@ followConfirm: "Are you sure that you want to follow {name}?"
proxyAccount: "Proxy account"
proxyAccountDescription: "A proxy account is an account that acts as a remote follower for users under certain conditions. For example, when a user adds a remote user to the list, the remote user's activity will not be delivered to the instance if no local user is following that user, so the proxy account will follow instead."
host: "Host"
-selectSelf: "Select myself"
selectUser: "Select a user"
recipient: "Recipient"
annotation: "Comments"
@@ -215,7 +212,6 @@ perDay: "Per Day"
stopActivityDelivery: "Stop sending activities"
blockThisInstance: "Block this instance"
silenceThisInstance: "Silence this instance"
-mediaSilenceThisInstance: "Media-silence this server"
operations: "Operations"
software: "Software"
version: "Version"
@@ -236,11 +232,7 @@ clearCachedFilesConfirm: "Are you sure that you want to delete all cached remote
blockedInstances: "Blocked Instances"
blockedInstancesDescription: "List the hostnames of the instances you want to block separated by linebreaks. Listed instances will no longer be able to communicate with this instance."
silencedInstances: "Silenced instances"
-silencedInstancesDescription: "List the host names of the servers that you want to silence, separated by a new line. All accounts belonging to the listed servers will be treated as silenced, and can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked servers."
-mediaSilencedInstances: "Media-silenced servers"
-mediaSilencedInstancesDescription: "List the host names of the servers that you want to media-silence, separated by a new line. All accounts belonging to the listed servers will be treated as sensitive, and can't use custom emojis. This will not affect the blocked servers."
-federationAllowedHosts: "Federation allowed servers"
-federationAllowedHostsDescription: "Specify the hostnames of the servers you want to allow federation separated by line breaks."
+silencedInstancesDescription: "List the hostnames of the instances that you want to silence. All accounts of the listed instances will be treated as silenced, can only make follow requests, and cannot mention local accounts if not followed. This will not affect blocked instances."
muteAndBlock: "Mutes and Blocks"
mutedUsers: "Muted users"
blockedUsers: "Blocked users"
@@ -248,7 +240,7 @@ noUsers: "There are no users"
editProfile: "Edit profile"
noteDeleteConfirm: "Are you sure you want to delete this note?"
pinLimitExceeded: "You cannot pin any more notes"
-intro: "Installation of Misskey has been finished! Please create an admin user."
+intro: "Installation of Sharkey has been finished! Please create an admin user."
done: "Done"
processing: "Processing..."
preview: "Preview"
@@ -331,7 +323,6 @@ selectFile: "Select a file"
selectFiles: "Select files"
selectFolder: "Select a folder"
selectFolders: "Select folders"
-fileNotSelected: ""
renameFile: "Rename file"
folderName: "Folder name"
createFolder: "Create a folder"
@@ -339,7 +330,6 @@ renameFolder: "Rename this folder"
deleteFolder: "Delete this folder"
folder: "Folder"
addFile: "Add a file"
-showFile: "Show files"
emptyDrive: "Your Drive is empty"
emptyFolder: "This folder is empty"
unableToDelete: "Unable to delete"
@@ -352,6 +342,7 @@ copyUrl: "Copy URL"
rename: "Rename"
avatar: "Avatar"
banner: "Banner"
+background: "Background"
displayOfSensitiveMedia: "Display of sensitive media"
whenServerDisconnected: "When losing connection to the server"
disconnectedFromServer: "Connection to server has been lost"
@@ -404,7 +395,7 @@ mcaptcha: "mCaptcha"
enableMcaptcha: "Enable mCaptcha"
mcaptchaSiteKey: "Site key"
mcaptchaSecretKey: "Secret key"
-mcaptchaInstanceUrl: "mCaptcha server URL"
+mcaptchaInstanceUrl: "mCaptcha instance URL"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Enable reCAPTCHA"
recaptchaSiteKey: "Site key"
@@ -420,7 +411,6 @@ name: "Name"
antennaSource: "Antenna source"
antennaKeywords: "Keywords to listen to"
antennaExcludeKeywords: "Keywords to exclude"
-antennaExcludeBots: "Exclude bot accounts"
antennaKeywordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
notifyAntenna: "Notify about new notes"
withFileAntenna: "Only notes with files"
@@ -444,7 +434,7 @@ exploreFediverse: "Explore the Fediverse"
popularTags: "Popular tags"
userList: "Lists"
about: "About"
-aboutMisskey: "About Misskey"
+aboutMisskey: "About Sharkey"
administrator: "Administrator"
token: "Token"
2fa: "Two-factor authentication"
@@ -454,7 +444,6 @@ totpDescription: "Use an authenticator app to enter one-time passwords"
moderator: "Moderator"
moderation: "Moderation"
moderationNote: "Moderation note"
-moderationNoteDescription: "You can fill in notes that will be shared only among moderators."
addModerationNote: "Add moderation note"
moderationLogs: "Moderation logs"
nUsersMentioned: "Mentioned by {n} users"
@@ -487,14 +476,14 @@ enable: "Enable"
next: "Next"
retype: "Enter again"
noteOf: "Note by {user}"
+expandAllCws: "Show content for all replies"
+collapseAllCws: "Hide content for all replies"
quoteAttached: "Quote"
quoteQuestion: "Append as quote?"
-attachAsFileQuestion: "The text in clipboard is long. Would you want to attach it as text file?"
noMessagesYet: "No messages yet"
newMessageExists: "There are new messages"
onlyOneFileCanBeAttached: "You can only attach one file to a message"
signinRequired: "Please register or sign in before continuing"
-signinOrContinueOnRemote: "To continue, you need to move your server or sign up / log in to this server."
invitations: "Invites"
invitationCode: "Invitation code"
checking: "Checking..."
@@ -516,12 +505,8 @@ uiLanguage: "User interface language"
aboutX: "About {x}"
emojiStyle: "Emoji style"
native: "Native"
-menuStyle: "Menu style"
-style: "Style"
-drawer: "Drawer"
-popup: "Pop up"
+disableDrawer: "Don't use drawer-style menus"
showNoteActionsOnlyHover: "Only show note actions on hover"
-showReactionsCount: "See the number of reactions in notes"
noHistory: "No history available"
signinHistory: "Login history"
enableAdvancedMfm: "Enable advanced MFM"
@@ -534,10 +519,12 @@ createAccount: "Create account"
existingAccount: "Existing account"
regenerate: "Regenerate"
fontSize: "Font size"
+cornerRadius: "Corner roundness"
mediaListWithOneImageAppearance: "Height of media lists with one image only"
limitTo: "Limit to {x}"
noFollowRequests: "You don't have any pending follow requests"
openImageInNewTab: "Open images in new tab"
+warnForMissingAltText: "Warn you when you forget to put alt text"
dashboard: "Dashboard"
local: "Local"
remote: "Remote"
@@ -570,6 +557,8 @@ objectStorageUseProxy: "Connect over Proxy"
objectStorageUseProxyDesc: "Turn this off if you are not going to use a Proxy for API connections"
objectStorageSetPublicRead: "Set \"public-read\" on upload"
s3ForcePathStyleDesc: "If s3ForcePathStyle is enabled, the bucket name has to included in the path of the URL as opposed to the hostname of the URL. You may need to enable this setting when using services such as a self-hosted Minio instance."
+deeplFreeMode: "Use DeepLX-JS (No Auth Key)"
+deeplFreeModeDescription: "Need Help? Check our documentation to know how to setup DeepLX-JS."
serverLogs: "Server logs"
deleteAll: "Delete all"
showFixedPostForm: "Display the posting form at the top of the timeline"
@@ -585,7 +574,7 @@ popout: "Pop-out"
volume: "Volume"
masterVolume: "Master volume"
notUseSound: "Disable sound"
-useSoundOnlyWhenActive: "Output sounds only if Misskey is active."
+useSoundOnlyWhenActive: "Output sounds only if Sharkey is active."
details: "Details"
chooseEmoji: "Select an emoji"
unableToProcess: "The operation could not be completed"
@@ -601,9 +590,7 @@ sort: "Sorting order"
ascendingOrder: "Ascending"
descendingOrder: "Descending"
scratchpad: "Scratchpad"
-scratchpadDescription: "The Scratchpad provides an environment for AiScript experiments. You can write, execute, and check the results of it interacting with Misskey in it."
-uiInspector: "UI inspector"
-uiInspectorDescription: "You can see the UI component server list on memory. UI component will be generated by Ui:C: function."
+scratchpadDescription: "The Scratchpad provides an environment for AiScript experiments. You can write, execute, and check the results of it interacting with Sharkey in it."
output: "Output"
script: "Script"
disablePagesScript: "Disable AiScript on Pages"
@@ -713,14 +700,17 @@ behavior: "Behavior"
sample: "Sample"
abuseReports: "Reports"
reportAbuse: "Report"
-reportAbuseRenote: "Report renote"
+reportAbuseRenote: "Report boost"
reportAbuseOf: "Report {name}"
fillAbuseReportDescription: "Please fill in details regarding this report. If it is about a specific note, please include its URL."
abuseReported: "Your report has been sent. Thank you very much."
reporter: "Reporter"
reporteeOrigin: "Reportee Origin"
reporterOrigin: "Reporter Origin"
+forwardReport: "Forward report to remote instance"
+forwardReportIsAnonymous: "Instead of your account, an anonymous system account will be displayed as reporter at the remote instance."
send: "Send"
+abuseMarkAsResolved: "Mark report as resolved"
openInNewTab: "Open in new tab"
openInSideView: "Open in side view"
defaultNavigationBehaviour: "Default navigation behavior"
@@ -739,14 +729,14 @@ unclip: "Unclip"
confirmToUnclipAlreadyClippedNote: "This note is already part of the \"{name}\" clip. Do you want to remove it from this clip instead?"
public: "Public"
private: "Private"
-i18nInfo: "Misskey is being translated into various languages by volunteers. You can help at {link}."
+i18nInfo: "Sharkey is being translated into various languages by volunteers. You can help at {link}."
manageAccessTokens: "Manage access tokens"
accountInfo: "Account Info"
notesCount: "Number of notes"
repliesCount: "Number of replies sent"
-renotesCount: "Number of renotes sent"
+renotesCount: "Number of boosts sent"
repliedCount: "Number of replies received"
-renotedCount: "Number of renotes received"
+renotedCount: "Number of boosts received"
followingCount: "Number of followed accounts"
followersCount: "Number of followers"
sentReactionsCount: "Number of sent reactions"
@@ -779,6 +769,8 @@ thisIsExperimentalFeature: "This is an experimental feature. Its functionality i
developer: "Developer"
makeExplorable: "Make account visible in \"Explore\""
makeExplorableDescription: "If you turn this off, your account will not show up in the \"Explore\" section."
+makeIndexable: "Make public notes not indexable"
+makeIndexableDescription: "Stop note search from indexing your public notes."
showGapBetweenNotesInTimeline: "Show a gap between posts on the timeline"
duplicate: "Duplicate"
left: "Left"
@@ -793,7 +785,7 @@ onlineUsersCount: "{n} users are online"
nUsers: "{n} Users"
nNotes: "{n} Notes"
sendErrorReports: "Send error reports"
-sendErrorReportsDescription: "When turned on, detailed error information will be shared with Misskey when a problem occurs, helping to improve the quality of Misskey.\nThis will include information such the version of your OS, what browser you're using, your activity in Misskey, etc."
+sendErrorReportsDescription: "When turned on, detailed error information will be shared with Sharkey when a problem occurs, helping to improve the quality of Sharkey.\nThis will include information such the version of your OS, what browser you're using, your activity in Sharkey, etc."
myTheme: "My theme"
backgroundColor: "Background color"
accentColor: "Accent color"
@@ -857,7 +849,6 @@ administration: "Management"
accounts: "Accounts"
switch: "Switch"
noMaintainerInformationWarning: "Maintainer information is not configured."
-noInquiryUrlWarning: "Inquiry URL isn’t set"
noBotProtectionWarning: "Bot protection is not configured."
configure: "Configure"
postToGallery: "Create new gallery post"
@@ -888,7 +879,7 @@ hashtags: "Hashtags"
troubleshooting: "Troubleshooting"
useBlurEffect: "Use blur effects in the UI"
learnMore: "Learn more"
-misskeyUpdated: "Misskey has been updated!"
+misskeyUpdated: "Sharkey has been updated!"
whatIsNew: "Show changes"
translate: "Translate"
translatedFrom: "Translated from {x}"
@@ -908,6 +899,7 @@ itsOff: "Disabled"
on: "On"
off: "Off"
emailRequiredForSignup: "Require email address for sign-up"
+approvalRequiredForSignup: "Require approval for new users"
unread: "Unread"
filter: "Filter"
controlPanel: "Control Panel"
@@ -922,8 +914,8 @@ followersVisibility: "Visibility of followers"
continueThread: "View thread continuation"
deleteAccountConfirm: "This will irreversibly delete your account. Proceed?"
incorrectPassword: "Incorrect password."
-incorrectTotp: "The one-time password is incorrect or has expired."
voteConfirm: "Confirm your vote for \"{choice}\"?"
+voteConfirmMulti: "Confirm your vote for \"{choice}\"?\n You can choose more options after confirmation."
hide: "Hide"
useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile"
welcomeBackWithName: "Welcome back, {name}"
@@ -959,6 +951,7 @@ recentNHours: "Last {n} hours"
recentNDays: "Last {n} days"
noEmailServerWarning: "Email server not configured."
thereIsUnresolvedAbuseReportWarning: "There are unsolved reports."
+pendingUserApprovals: "There are users awaiting approval."
recommended: "Recommended"
check: "Check"
driveCapOverrideLabel: "Change the drive capacity for this user"
@@ -967,9 +960,20 @@ requireAdminForView: "You must log in with an administrator account to view this
isSystemAccount: "An account created and automatically operated by the system."
typeToConfirm: "Please enter {x} to confirm"
deleteAccount: "Delete account"
+approveAccount: "Approve"
+denyAccount: "Deny & Delete"
+approved: "Approved"
+notApproved: "Not Approved"
+approvalStatus: "Approval Status"
document: "Documentation"
numberOfPageCache: "Number of cached pages"
numberOfPageCacheDescription: "Increasing this number will improve convenience for but cause more load as more memory usage on the user's device."
+numberOfReplies: "Number of replies in a thread"
+numberOfRepliesDescription: "Increasing this number will display more replies. Setting this too high can cause replies to be cramped and unreadable."
+boostSettings: "Boost Settings"
+showVisibilitySelectorOnBoost: "Show Visibility Selector"
+showVisibilitySelectorOnBoostDescription: "Shows the visiblity selector if enabled when clicking boost, if disabled it will use the default visiblity defined below and the selector will not show up."
+visibilityOnBoost: "Default boost visibility"
logoutConfirm: "Really log out?"
lastActiveDate: "Last used at"
statusbar: "Status bar"
@@ -1014,13 +1018,15 @@ cannotLoad: "Unable to load"
numberOfProfileView: "Profile views"
like: "Like"
unlike: "Unlike"
+defaultLike: "Default like emoji"
numberOfLikes: "Likes"
show: "Show"
neverShow: "Don't show again"
remindMeLater: "Maybe later"
-didYouLikeMisskey: "Have you taken a liking to Misskey?"
-pleaseDonate: "{host} uses the free software, Misskey. We would highly appreciate your donations so development of Misskey can continue!"
-correspondingSourceIsAvailable: "The corresponding source code is available at {anchor}"
+didYouLikeMisskey: "Have you taken a liking to Sharkey?"
+pleaseDonate: "{host} uses the free software, Sharkey. We would highly appreciate your donations so development of Sharkey can continue!"
+pleaseDonateInstance: "You can also support {host} directly by donating to your instance administration."
+correspondingSourceIsAvailable: "The corresponding source code is available from {anchor}."
roles: "Roles"
role: "Role"
noRole: "Role not found"
@@ -1047,8 +1053,12 @@ thisPostMayBeAnnoying: "This note may annoy others."
thisPostMayBeAnnoyingHome: "Post to home timeline"
thisPostMayBeAnnoyingCancel: "Cancel"
thisPostMayBeAnnoyingIgnore: "Post anyway"
-collapseRenotes: "Collapse renotes you've already seen"
-collapseRenotesDescription: "Collapse notes that you've reacted to or renoted before."
+thisPostIsMissingAltTextCancel: "Cancel"
+thisPostIsMissingAltTextIgnore: "Post anyway"
+thisPostIsMissingAltText: "One of the files attached to this post is missing alt text. Please ensure all the attachments have alt text."
+collapseRenotes: "Collapse boosts you've already seen"
+collapseFiles: "Collapse files"
+autoloadConversation: "Load conversation on replies"
internalServerError: "Internal Server Error"
internalServerErrorDescription: "The server has run into an unexpected error."
copyErrorInfo: "Copy error details"
@@ -1059,6 +1069,7 @@ disableFederationConfirm: "Really disable federation?"
disableFederationConfirmWarn: "Even if defederated, posts will continue to be public unless set otherwise. You usually do not need to do this."
disableFederationOk: "Disable"
invitationRequiredToRegister: "This instance is invite-only. You must enter a valid invite code sign up."
+approvalRequiredToRegister: "This instance is only accepting users who specify a reason for registration."
emailNotSupported: "This instance does not support sending emails"
postToTheChannel: "Post to channel"
cannotBeChangedLater: "This cannot be changed later."
@@ -1072,8 +1083,6 @@ resetPasswordConfirm: "Really reset your password?"
sensitiveWords: "Sensitive words"
sensitiveWordsDescription: "The visibility of all notes containing any of the configured words will be set to \"Home\" automatically. You can list multiple by separating them via line breaks."
sensitiveWordsDescription2: "Using spaces will create AND expressions and surrounding keywords with slashes will turn them into a regular expression."
-prohibitedWords: "Prohibited words"
-prohibitedWordsDescription: "Enables an error when attempting to post a note containing the set word(s). Multiple words can be set, separated by a new line."
prohibitedWordsDescription2: "Using spaces will create AND expressions and surrounding keywords with slashes will turn them into a regular expression."
hiddenTags: "Hidden hashtags"
hiddenTagsDescription: "Select tags which will not shown on trend list.\nMultiple tags could be registered by lines."
@@ -1089,7 +1098,7 @@ enableChartsForRemoteUser: "Generate remote user data charts"
enableChartsForFederatedInstances: "Generate remote instance data charts"
showClipButtonInNoteFooter: "Add \"Clip\" to note action menu"
reactionsDisplaySize: "Reaction display size"
-limitWidthOfReaction: "Limit the maximum width of reactions and display them in reduced size."
+limitWidthOfReaction: "Limits the maximum width of reactions and display them in reduced size."
noteIdOrUrl: "Note ID or URL"
video: "Video"
videos: "Videos"
@@ -1101,10 +1110,11 @@ accountMoved: "This user has moved to a new account:"
accountMovedShort: "This account has been migrated."
operationForbidden: "Operation forbidden"
forceShowAds: "Always show ads"
+oneko: "Cat friend :3"
addMemo: "Add memo"
editMemo: "Edit memo"
reactionsList: "Reactions"
-renotesList: "Renotes"
+renotesList: "Boosts"
notificationDisplay: "Notifications"
leftTop: "Top left"
rightTop: "Top right"
@@ -1122,8 +1132,6 @@ preservedUsernames: "Reserved usernames"
preservedUsernamesDescription: "List usernames to reserve separated by linebreaks. These will become unable during normal account creation, but can be used by administrators to manually create accounts. Already existing accounts using these usernames will not be affected."
createNoteFromTheFile: "Compose note from this file"
archive: "Archive"
-archived: "Archived"
-unarchive: "Unarchive"
channelArchiveConfirmTitle: "Really archive {name}?"
channelArchiveConfirmDescription: "An archived channel won't appear in the channel list or search results anymore. New posts can also not be added to it anymore."
thisChannelArchived: "This channel has been archived."
@@ -1134,9 +1142,6 @@ preventAiLearning: "Reject usage in Machine Learning (Generative AI)"
preventAiLearningDescription: "Requests crawlers to not use posted text or image material etc. in machine learning (Predictive / Generative AI) data sets. This is achieved by adding a \"noai\" HTML-Response flag to the respective content. A complete prevention can however not be achieved through this flag, as it may simply be ignored."
options: "Options"
specifyUser: "Specific user"
-lookupConfirm: "Do you want to look up?"
-openTagPageConfirm: "Do you want to open a hashtag page?"
-specifyHost: "Specific host"
failedToPreviewUrl: "Could not preview"
update: "Update"
rolesThatCanBeUsedThisEmojiAsReaction: "Roles that can use this emoji as reaction"
@@ -1145,11 +1150,15 @@ rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "These roles must be public
cancelReactionConfirm: "Really delete your reaction?"
changeReactionConfirm: "Really change your reaction?"
later: "Later"
-goToMisskey: "To Misskey"
+goToMisskey: "To Sharkey"
additionalEmojiDictionary: "Additional emoji dictionaries"
installed: "Installed"
branding: "Branding"
enableServerMachineStats: "Publish server hardware stats"
+enableAchievements: "Enable Achievements"
+turnOffAchievements: "Turning this off will disable the achievement system"
+enableBotTrending: "Populate Hashtags with Bots"
+turnOffBotTrending: "Turning this off will stop Bots from populating Hashtags"
enableIdenticonGeneration: "Enable user identicon generation"
turnOffToImprovePerformance: "Turning this off can increase performance."
createInviteCode: "Generate invite"
@@ -1179,23 +1188,24 @@ currentAnnouncements: "Current announcements"
pastAnnouncements: "Past announcements"
youHaveUnreadAnnouncements: "There are unread announcements."
useSecurityKey: "Please follow your browser's or device's instructions to use your security- or passkey."
-replies: "Reply"
-renotes: "Renotes"
+replies: "Replies"
+renotes: "Boosts"
loadReplies: "Show replies"
loadConversation: "Show conversation"
pinnedList: "Pinned list"
keepScreenOn: "Keep screen on"
+clickToOpen: "Click to open notes"
+showBots: "Show bots in timeline"
verifiedLink: "Link ownership has been verified"
notifyNotes: "Notify about new notes"
unnotifyNotes: "Stop notifying about new notes"
authentication: "Authentication"
authenticationRequiredToContinue: "Please authenticate to continue"
dateAndTime: "Timestamp"
-showRenotes: "Show renotes"
+showRenotes: "Show boosts"
edited: "Edited"
notificationRecieveConfig: "Notification Settings"
mutualFollow: "Mutual follow"
-followingOrFollower: "Following or follower"
fileAttachedOnly: "Only notes with files"
showRepliesToOthersInTimeline: "Show replies to others in timeline"
hideRepliesToOthersInTimeline: "Hide replies to others from timeline"
@@ -1205,10 +1215,10 @@ confirmShowRepliesAll: "This operation is irreversible. Would you really like to
confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?"
externalServices: "External Services"
sourceCode: "Source code"
-sourceCodeIsNotYetProvided: "Source code is not yet available. Contact the administrator to fix this problem."
+sourceCodeIsNotYetProvided: "The source code is not yet available. Please contact your administrator to fix this issue."
repositoryUrl: "Repository URL"
-repositoryUrlDescription: "If you are using Misskey as is (without any changes to the source code), enter https://github.com/misskey-dev/misskey"
-repositoryUrlOrTarballRequired: "If you have not published a repository, you must provide a tarball instead. See .config/example.yml for more information."
+repositoryUrlDescription: "If there is a repository where the source code is publicly available, enter its URL. If you are using Sharkey as-is (without any changes to the source code), enter https://activitypub.software/TransFem-org/Sharkey/."
+repositoryUrlOrTarballRequired: "If you don't have a public repository, you'll need to provide a tarball instead. See .config/example.yml for details."
feedback: "Feedback"
feedbackUrl: "Feedback URL"
impressum: "Impressum"
@@ -1217,6 +1227,8 @@ impressumDescription: "In some countries, like germany, the inclusion of operato
privacyPolicy: "Privacy Policy"
privacyPolicyUrl: "Privacy Policy URL"
tosAndPrivacyPolicy: "Terms of Service and Privacy Policy"
+donation: "Donate"
+donationUrl: "Donation URL"
avatarDecorations: "Avatar decorations"
attach: "Attach"
detach: "Remove"
@@ -1236,7 +1248,7 @@ code: "Code"
reloadRequiredToApplySettings: "Reloading is required to apply the settings."
remainingN: "Remaining: {n}"
overwriteContentConfirm: "Are you sure you want to overwrite the current content?"
-seasonalScreenEffect: "Seasonal Screen Effect"
+seasonalScreenEffect: "Seasonal screen effects"
decorate: "Decorate"
addMfmFunction: "Add MFM"
enableQuickAddMfmFunction: "Show advanced MFM picker"
@@ -1246,8 +1258,6 @@ soundWillBePlayed: "Sound will be played"
showReplay: "View Replay"
replay: "Replay"
replaying: "Showing replay"
-endReplay: "Exit Replay"
-copyReplayData: "Copy replay data"
ranking: "Ranking"
lastNDays: "Last {n} days"
backToTitle: "Go back to title"
@@ -1255,65 +1265,8 @@ hemisphere: "Where are you located"
withSensitive: "Include notes with sensitive files"
userSaysSomethingSensitive: "Post by {name} contains sensitive content"
enableHorizontalSwipe: "Swipe to switch tabs"
-loading: "Loading"
-surrender: "Cancel"
-gameRetry: "Retry"
-notUsePleaseLeaveBlank: "Leave blank if not used"
-useTotp: "Enter the One-Time Password"
-useBackupCode: "Use the backup codes"
-launchApp: "Launch the app"
-useNativeUIForVideoAudioPlayer: "Use UI of browser when play video and audio"
-keepOriginalFilename: "Keep original file name"
-keepOriginalFilenameDescription: "If you turn off this setting, files names will be replaced with random string automatically when you upload files."
-noDescription: "There is no explanation"
-alwaysConfirmFollow: "Always confirm when following"
-inquiry: "Contact"
-tryAgain: "Please try again later"
-confirmWhenRevealingSensitiveMedia: "Confirm when revealing sensitive media"
-sensitiveMediaRevealConfirm: "This might be a sensitive media. Are you sure to reveal?"
-createdLists: "Created lists"
-createdAntennas: "Created antennas"
-fromX: "From {x}"
-genEmbedCode: "Generate embed code"
-noteOfThisUser: "Notes by this user"
-clipNoteLimitExceeded: "No more notes can be added to this clip."
-performance: "Performance"
-modified: "Modified"
-discard: "Discard"
-thereAreNChanges: "There are {n} change(s)"
-signinWithPasskey: "Sign in with Passkey"
-unknownWebAuthnKey: "Unknown Passkey"
-passkeyVerificationFailed: "Passkey verification has failed."
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "Passkey verification has succeeded but password-less login is disabled."
-messageToFollower: "Message to followers"
-target: "Target"
-_abuseUserReport:
- forward: "Forward"
- forwardDescription: "Forward the report to a remote server as an anonymous system account."
- resolve: "Resolve"
- accept: "Accept"
- reject: "Reject"
- resolveTutorial: "If the report is legitimate in content, select \"Accept\" to mark the case as resolved in the affirmative.\nIf the content of the report is not legitimate, select \"Reject\" to mark the case as resolved in the negative."
-_delivery:
- status: "Delivery status"
- stop: "Suspended"
- resume: "Delivery resume"
- _type:
- none: "Publishing"
- manuallySuspended: "Manually suspended"
- goneSuspended: "Server is suspended due to server deletion"
- autoSuspendedForNotResponding: "Server is suspended due to no responding"
_bubbleGame:
howToPlay: "How to play"
- hold: "Hold"
- _score:
- score: "Score"
- scoreYen: "Amount of money earned"
- highScore: "High score"
- maxChain: "Maximum number of chains"
- yen: "{yen} Yen"
- estimatedQty: "{qty} Pieces"
- scoreSweets: "{onigiriQtyWithUnit} Onigiri"
_howToPlay:
section1: "Adjust the position and drop the object into the box."
section2: "When two objects of the same type touch each other, they will change into a different object and you score points."
@@ -1343,7 +1296,7 @@ _initialAccountSetting:
pushNotificationDescription: "Enabling push notifications will allow you to receive notifications from {name} directly on your device."
initialAccountSettingCompleted: "Profile setup complete!"
haveFun: "Enjoy {name}!"
- youCanContinueTutorial: "You can proceed to a tutorial on how to use {name} (Misskey) or you can exit the setup here and start using it immediately."
+ youCanContinueTutorial: "You can proceed to a tutorial on how to use {name} (Sharkey) or you can exit the setup here and start using it immediately."
startTutorial: "Start Tutorial"
skipAreYouSure: "Really skip profile setup?"
laterAreYouSure: "Really do profile setup later?"
@@ -1354,10 +1307,10 @@ _initialTutorial:
skipAreYouSure: "Quit Tutorial?"
_landing:
title: "Welcome to the Tutorial"
- description: "Here, you can learn the basics of using Misskey and its features."
+ description: "Here, you can learn the basics of using Sharkey and its features."
_note:
title: "What is a Note?"
- description: "Posts on Misskey are called 'Notes.' Notes are arranged chronologically on the timeline and are updated in real-time."
+ description: "Posts on Sharkey are called 'Notes.' Notes are arranged chronologically on the timeline and are updated in real-time."
reply: "Click on this button to reply to a message. It's also possible to reply to replies, continuing the conversation like a thread."
renote: "You can share that note to your own timeline. You can also quote them with your comments."
reaction: "You can add reactions to the Note. More details will be explained on the next page."
@@ -1371,7 +1324,7 @@ _initialTutorial:
reactDone: "You can undo a reaction by pressing the '-' button."
_timeline:
title: "The Concept of Timelines"
- description1: "Misskey provides multiple timelines based on usage (some may not be available depending on the server's policies)."
+ description1: "Sharkey provides multiple timelines based on usage (some may not be available depending on the server's policies)."
home: "You can view notes from accounts you follow."
local: "You can view notes from all users on this server."
social: "Notes from the Home and Local timelines will be displayed."
@@ -1380,12 +1333,12 @@ _initialTutorial:
description3: "Additionally, there are list timelines and channel timelines. For more details, please refer to {link}."
_postNote:
title: "Note Posting Settings"
- description1: "When posting a note on Misskey, various options are available. The posting form looks like this."
+ description1: "When posting a note on Sharkey, various options are available. The posting form looks like this."
_visibility:
description: "You can limit who can view your note."
public: "Your note will be visible for all users."
- home: "Public only on the Home timeline. People visiting your profile, via followers, and through renotes can see it."
- followers: "Visible to followers only. Only followers can see it and no one else, and it cannot be renoted by others."
+ home: "Public only on the Home timeline. People visiting your profile, via followers, and through boosts can see it."
+ followers: "Visible to followers only. Only followers can see it and no one else, and it cannot be boosted by others."
direct: "Visible only to specified users, and the recipient will be notified. It can be used as an alternative to direct messaging."
doNotSendConfidencialOnDirect1: "Be careful when sending sensitive information!"
doNotSendConfidencialOnDirect2: "Administrators of the server can see what you write. Be careful with sensitive information when sending direct notes to users on untrusted servers."
@@ -1396,7 +1349,7 @@ _initialTutorial:
_exampleNote:
cw: "This will surely make you hungry!"
note: "Just had a chocolate-glazed donut 🍩😋"
- useCases: "This is used when following the server guidelines, for necessary notes, or for self-restriction of spoiler or sensitive text."
+ useCases: "This is used when following the server guidelines for necessary notes or for self-restriction of spoiler or sensitive text."
_howToMakeAttachmentsSensitive:
title: "How to Mark Attachments as Sensitive?"
description: "For attachments that are required by server guidelines or that should not be left intact, add a \"sensitive\" flag."
@@ -1407,8 +1360,8 @@ _initialTutorial:
sensitiveSucceeded: "When attaching files, please set sensitivities in accordance with the server guidelines."
doItToContinue: "Mark the attachment file as sensitive to proceed."
_done:
- title: "You've completed the tutorial! 🎉"
- description: "The functions introduced here are just a small part. For a more detailed understanding of using Misskey, please refer to {link}."
+ title: "The tutorial is complete! 🎉"
+ description: "The functions introduced here are just a small part. For a more detailed understanding of using Sharkey, please refer to {link}."
_timelineDescription:
home: "In the Home timeline, you can see notes from accounts you follow."
local: "In the Local timeline, you can see notes from all users on this server."
@@ -1428,9 +1381,6 @@ _serverSettings:
fanoutTimelineDescription: "Greatly increases performance of timeline retrieval and reduces load on the database when enabled. In exchange, memory usage of Redis will increase. Consider disabling this in case of low server memory or server instability."
fanoutTimelineDbFallback: "Fallback to database"
fanoutTimelineDbFallbackDescription: "When enabled, the timeline will fall back to the database for additional queries if the timeline is not cached. Disabling it further reduces the server load by eliminating the fallback process, but limits the range of timelines that can be retrieved."
- reactionsBufferingDescription: "When enabled, performance during reaction creation will be greatly improved, reducing the load on the database. However, Redis memory usage will increase."
- inquiryUrl: "Inquiry URL"
- inquiryUrlDescription: "Specify a URL for the inquiry form to the server maintainer or a web page for the contact information."
_accountMigration:
moveFrom: "Migrate another account to this one"
moveFromSub: "Create alias to another account"
@@ -1439,7 +1389,7 @@ _accountMigration:
moveTo: "Migrate this account to a different one"
moveToLabel: "Account to move to:"
moveCannotBeUndone: "Account migration cannot be undone."
- moveAccountDescription: "This will migrate your account to a different one.\n ・Followers from this account will automatically be migrated to the new account\n ・This account will unfollow all users it is currently following\n ・You will be unable to create new notes etc. on this account\n\nWhile migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.\n\n(This explanation applies to Misskey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)"
+ moveAccountDescription: "This will migrate your account to a different one.\n ・Followers from this account will automatically be migrated to the new account\n ・This account will unfollow all users it is currently following\n ・You will be unable to create new notes etc. on this account\n\nWhile migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.\n\n(This explanation applies to Sharkey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)"
moveAccountHowTo: "To migrate, first create an alias for this account on the account to move to.\nAfter you have created the alias, enter the account to move to in the following format: @username@server.example.com"
startMigration: "Migrate"
migrationConfirm: "Really migrate this account to {account}? Once started, this process cannot be stopped or taken back, and you will not be able to use this account in its original state anymore."
@@ -1450,9 +1400,9 @@ _achievements:
earnedAt: "Unlocked at"
_types:
_notes1:
- title: "just setting up my msky"
+ title: "just setting up my shonk"
description: "Post your first note"
- flavor: "Have a good time with Misskey!"
+ flavor: "Have a good time with Sharkey!"
_notes10:
title: "Some notes"
description: "Post 10 notes"
@@ -1548,7 +1498,7 @@ _achievements:
_login1000:
title: "Master of Notes III"
description: "Log in for a total of 1,000 days"
- flavor: "Thank you for using Misskey!"
+ flavor: "Thank you for using Sharkey!"
_noteClipped1:
title: "Must... clip..."
description: "Clip your first note"
@@ -1608,18 +1558,18 @@ _achievements:
title: "Likes Achievements"
description: "Look at your list of achievements for at least 3 minutes"
_iLoveMisskey:
- title: "I Love Misskey"
- description: "Post \"I ❤ #Misskey\""
- flavor: "Misskey's development team greatly appreciates your support!"
+ title: "I Love Sharkey"
+ description: "Post \"I ❤ #Sharkey\""
+ flavor: "Sharkey's development team greatly appreciates your support!"
_foundTreasure:
title: "Treasure Hunt"
description: "You've found the hidden treasure"
_client30min:
title: "Short break"
- description: "Keep Misskey opened for at least 30 minutes"
+ description: "Keep Sharkey opened for at least 30 minutes"
_client60min:
- title: "No \"Miss\" in Misskey"
- description: "Keep Misskey opened for at least 60 minutes"
+ title: "No \"Miss\" in Sharkey"
+ description: "Keep Sharkey opened for at least 60 minutes"
_noteDeletedWithin1min:
title: "Nevermind"
description: "Delete a note within a minute of posting it"
@@ -1684,12 +1634,12 @@ _achievements:
_brainDiver:
title: "Brain Diver"
description: "Post the link to Brain Diver"
- flavor: "Misskey-Misskey La-Tu-Ma"
+ flavor: "Sharkey-Sharkey La-Tu-Ma"
_smashTestNotificationButton:
title: "Test overflow"
description: "Trigger the notification test repeatedly within an extremely short time"
_tutorialCompleted:
- title: "Misskey Elementary Course Diploma"
+ title: "Sharkey Elementary Course Diploma"
description: "Tutorial completed"
_bubbleGameExplodingHead:
title: "🤯"
@@ -1736,9 +1686,10 @@ _role:
high: "High"
_options:
gtlAvailable: "Can view the global timeline"
+ btlAvailable: "Can view the bubble timeline"
ltlAvailable: "Can view the local timeline"
canPublicNote: "Can send public notes"
- mentionMax: "Maximum number of mentions in a note"
+ canImportNotes: "Can import notes"
canInvite: "Can create instance invite codes"
inviteLimit: "Invite limit"
inviteLimitCycle: "Invite limit cooldown"
@@ -1747,7 +1698,6 @@ _role:
canManageAvatarDecorations: "Manage avatar decorations"
driveCapacity: "Drive capacity"
alwaysMarkNsfw: "Always mark files as NSFW"
- canUpdateBioMedia: "Can edit an icon or a banner image"
pinMax: "Maximum number of pinned notes"
antennaMax: "Maximum number of antennas"
wordMuteMax: "Maximum number of characters allowed in word mutes"
@@ -1762,20 +1712,9 @@ _role:
canSearchNotes: "Usage of note search"
canUseTranslator: "Translator usage"
avatarDecorationLimit: "Maximum number of avatar decorations that can be applied"
- canImportAntennas: "Allow importing antennas"
- canImportBlocking: "Allow importing blocking"
- canImportFollowing: "Allow importing following"
- canImportMuting: "Allow importing muting"
- canImportUserLists: "Allow importing lists"
_condition:
- roleAssignedTo: "Assigned to manual roles"
isLocal: "Local user"
isRemote: "Remote user"
- isCat: "Cat Users"
- isBot: "Bot Users"
- isSuspended: "Suspended user"
- isLocked: "Private accounts"
- isExplorable: "Effective user of \"make an account discoverable\""
createdLessThan: "Less than X has passed since account creation"
createdMoreThan: "More than X has passed since account creation"
followersLessThanOrEq: "Has X or fewer followers"
@@ -1801,7 +1740,7 @@ _emailUnavailable:
disposable: "Disposable email addresses may not be used"
mx: "This email server is invalid"
smtp: "This email server is not responding"
- banned: "You cannot register with this email address"
+ banned: "This email address is banned"
_ffVisibility:
public: "Public"
followers: "Visible to followers only"
@@ -1810,6 +1749,8 @@ _signup:
almostThere: "Almost there"
emailAddressInfo: "Please enter your email address. It will not be made public."
emailSent: "A confirmation email has been sent to your email address ({email}). Please click the included link to complete account creation."
+ approvalPending: "Your account has been created and is awaiting approval."
+ reasonInfo: "Please enter a reason as to why you want to join the instance."
_accountDelete:
accountDelete: "Delete account"
mayTakeTime: "As account deletion is a resource-heavy process, it may take some time to complete depending on how much content you have created and how many files you have uploaded."
@@ -1845,7 +1786,6 @@ _plugin:
installWarn: "Please do not install untrustworthy plugins."
manage: "Manage plugins"
viewSource: "View source"
- viewLog: "Show log"
_preferencesBackups:
list: "Created backups"
saveNew: "Save new backup"
@@ -1871,14 +1811,16 @@ _registry:
domain: "Domain"
createKey: "Create key"
_aboutMisskey:
- about: "Misskey is open-source software being developed by syuilo since 2014."
+ about: "Sharkey is open-source software based on Misskey which has been in developed since 2014 by syuilo."
contributors: "Main contributors"
allContributors: "All contributors"
source: "Source code"
- original: "Original"
- thisIsModifiedVersion: "{name} uses a modified version of the original Misskey."
- translation: "Translate Misskey"
+ original: "Misskey original"
+ original_sharkey: "Sharkey original"
+ thisIsModifiedVersion: "{name} uses a modified version of the original Sharkey"
+ translation: "Translate Sharkey"
donate: "Donate to Misskey"
+ donate_sharkey: "Donate to Sharkey"
morePatrons: "We also appreciate the support of many other helpers not listed here. Thank you! 🥰"
patrons: "Patrons"
projectMembers: "Project members"
@@ -1894,6 +1836,7 @@ _serverDisconnectedBehavior:
reload: "Automatically reload"
dialog: "Show warning dialog"
quiet: "Show unobtrusive warning"
+ disabled: "Disable warning"
_channel:
create: "Create channel"
edit: "Edit channel"
@@ -1906,7 +1849,7 @@ _channel:
notesCount: "{n} Notes"
nameAndDescription: "Name and description"
nameOnly: "Name only"
- allowRenoteToExternal: "Allow renote and quote outside the channel"
+ allowRenoteToExternal: "Allow boosts and quote outside the channel"
_menuDisplay:
sideFull: "Side"
sideIcon: "Side (Icons)"
@@ -1917,7 +1860,7 @@ _wordMute:
muteWordsDescription: "Separate with spaces for an AND condition or with line breaks for an OR condition."
muteWordsDescription2: "Surround keywords with slashes to use regular expressions."
_instanceMute:
- instanceMuteDescription: "This will mute any notes/renotes from the listed instances, including those of users replying to a user from a muted instance."
+ instanceMuteDescription: "This will mute any notes/boosts from the listed instances, including those of users replying to a user from a muted instance."
instanceMuteDescription2: "Separate with newlines"
title: "Hides notes from listed instances."
heading: "List of instances to be muted"
@@ -1969,7 +1912,7 @@ _theme:
hashtag: "Hashtag"
mention: "Mention"
mentionMe: "Mentions (Me)"
- renote: "Renote"
+ renote: "Boost"
modalBg: "Modal background"
divider: "Divider"
scrollbarHandle: "Scrollbar handle"
@@ -1984,6 +1927,7 @@ _theme:
buttonBg: "Button background"
buttonHoverBg: "Button background (Hover)"
inputBorder: "Input field border"
+ listItemHoverBg: "List item background (Hover)"
driveFolderBg: "Drive folder background"
wallpaperOverlay: "Wallpaper overlay"
badge: "Badge"
@@ -1995,6 +1939,8 @@ _sfx:
note: "New note"
noteMy: "Own note"
notification: "Notifications"
+ antenna: "Antennas"
+ channel: "Channel notifications"
reaction: "On choosing a reaction"
_soundSettings:
driveFile: "Use an audio file in Drive."
@@ -2002,8 +1948,7 @@ _soundSettings:
driveFileTypeWarn: "This file is not supported"
driveFileTypeWarnDescription: "Select an audio file"
driveFileDurationWarn: "The audio is too long."
- driveFileDurationWarnDescription: "Long audio may disrupt using Misskey. Still continue?"
- driveFileError: "It couldn't load the sound. Please change the setting."
+ driveFileDurationWarnDescription: "Long audio may disrupt using Sharkey. Still continue?"
_ago:
future: "Future"
justNow: "Just now"
@@ -2033,6 +1978,7 @@ _2fa:
registerTOTP: "Register authenticator app"
step1: "First, install an authentication app (such as {a} or {b}) on your device."
step2: "Then, scan the QR code displayed on this screen."
+ step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app."
step2Uri: "Enter the following URI if you are using a desktop program"
step3Title: "Enter an authentication code"
step3: "Enter the authentication code (token) provided by your app to finish setup."
@@ -2056,7 +2002,6 @@ _2fa:
backupCodesDescription: "You can use these codes to gain access to your account in case of becoming unable to use your two-factor authentificator app. Each can only be used once. Please keep them in a safe place."
backupCodeUsedWarning: "A backup code has been used. Please reconfigure two-factor authentification as soon as possible if you are no longer able to use it."
backupCodesExhaustedWarning: "All backup codes have been used. Should you lose access to your two-factor authentification app, you will be unable to access this account. Please reconfigure two-factor authentification."
- moreDetailedGuideHere: "Here is detailed guide"
_permissions:
"read:account": "View your account information"
"write:account": "Edit your account information"
@@ -2107,6 +2052,7 @@ _permissions:
"read:admin:server-info": "View server info"
"read:admin:show-moderation-log": "View moderation log"
"read:admin:show-user": "View private user info"
+ "read:admin:show-users": "View private user info"
"write:admin:suspend-user": "Suspend user"
"write:admin:unset-user-avatar": "Remove user avatar"
"write:admin:unset-user-banner": "Remove user banner"
@@ -2121,7 +2067,7 @@ _permissions:
"read:admin:invite-codes": "View invite codes"
"write:admin:announcements": "Manage announcements"
"read:admin:announcements": "View announcements"
- "write:admin:avatar-decorations": "Can manage avatar decorations"
+ "write:admin:avatar-decorations": "Manage avatar decorations"
"read:admin:avatar-decorations": "View avatar decorations"
"write:admin:federation": "Manage federation data"
"write:admin:account": "Manage user account"
@@ -2196,6 +2142,7 @@ _widgets:
_userList:
chooseList: "Select a list"
clicker: "Clicker"
+ search: "Search"
birthdayFollowings: "Users who celebrate their birthday today"
_cw:
hide: "Hide"
@@ -2224,6 +2171,7 @@ _poll:
remainingHours: "{h} hour(s) {m} minute(s) remaining"
remainingMinutes: "{m} minute(s) {s} second(s) remaining"
remainingSeconds: "{s} second(s) remaining"
+ multiple: "Multiple choices"
_visibility:
public: "Public"
publicDescription: "Your note will be visible for all users"
@@ -2258,11 +2206,13 @@ _profile:
metadataContent: "Content"
changeAvatar: "Change avatar"
changeBanner: "Change banner"
+ updateBanner: "Update banner"
+ removeBanner: "Remove banner"
+ changeBackground: "Change background"
+ updateBackground: "Update background"
+ removeBackground: "Remove background"
verifiedLinkDescription: "By entering an URL that contains a link to your profile here, an ownership verification icon can be displayed next to the field."
avatarDecorationMax: "You can add up to {max} decorations."
- followedMessage: "Message when you are followed"
- followedMessageDescription: "You can set a short message to be displayed to the recipient when they follow you."
- followedMessageDescriptionForLockedAccount: "If you have set up that follow requests require approval, this will be displayed when you grant a follow request."
_exportOrImport:
allNotes: "All notes"
favoritedNotes: "Favorite notes"
@@ -2320,7 +2270,6 @@ _play:
title: "Title"
script: "Script"
summary: "Description"
- visibilityDescription: "Putting it private means it won't be visible on your profile, but anyone that has the URL can still access it."
_pages:
newPage: "Create a new Page"
editPage: "Edit this Page"
@@ -2355,7 +2304,6 @@ _pages:
eyeCatchingImageSet: "Set thumbnail"
eyeCatchingImageRemove: "Delete thumbnail"
chooseBlock: "Add a block"
- enterSectionTitle: "Enter a section title"
selectType: "Select a type"
contentBlocks: "Content"
inputBlocks: "Input"
@@ -2366,8 +2314,6 @@ _pages:
section: "Section"
image: "Images"
button: "Button"
- dynamic: "Dynamic Blocks"
- dynamicDescription: "This block has been abolished. Please use {play} from now on."
note: "Embedded note"
_note:
id: "Note ID"
@@ -2382,7 +2328,7 @@ _notification:
youGotMention: "{name} mentioned you"
youGotReply: "{name} replied to you"
youGotQuote: "{name} quoted you"
- youRenoted: "Renote from {name}"
+ youRenoted: "Boost from {name}"
youWereFollowed: "followed you"
youReceivedFollowRequest: "You've received a follow request"
yourFollowRequestAccepted: "Your follow request was accepted"
@@ -2397,19 +2343,16 @@ _notification:
sendTestNotification: "Send test notification"
notificationWillBeDisplayedLikeThis: "Notifications look like this"
reactedBySomeUsers: "{n} users reacted"
- likedBySomeUsers: "{n} users liked your note"
- renotedBySomeUsers: "Renote from {n} users"
+ renotedBySomeUsers: "Boosted by {n} users"
followedBySomeUsers: "Followed by {n} users"
- flushNotification: "Clear notifications"
- exportOfXCompleted: "Export of {x} has been completed"
- login: "Someone logged in"
+ edited: "Note got edited"
_types:
all: "All"
note: "New notes"
follow: "New followers"
mention: "Mentions"
reply: "Replies"
- renote: "Renotes"
+ renote: "Boosts"
quote: "Quotes"
reaction: "Reactions"
pollEnded: "Polls ending"
@@ -2417,19 +2360,15 @@ _notification:
followRequestAccepted: "Accepted follow requests"
roleAssigned: "Role given"
achievementEarned: "Achievement unlocked"
- exportCompleted: "The export has been completed"
- login: "Sign In"
- test: "Notification test"
app: "Notifications from linked apps"
_actions:
followBack: "followed you back"
reply: "Reply"
- renote: "Renote"
+ renote: "Boost"
_deck:
alwaysShowMainColumn: "Always show main column"
columnAlign: "Align columns"
addColumn: "Add column"
- newNoteNotificationSettings: "Notification setting for new notes"
configureColumn: "Column settings"
swapLeft: "Swap with the left column"
swapRight: "Swap with the right column"
@@ -2468,46 +2407,25 @@ _drivecleaner:
orderByCreatedAtAsc: "Ascending Dates"
_webhookSettings:
createWebhook: "Create Webhook"
- modifyWebhook: "Modify Webhook"
name: "Name"
secret: "Secret"
- trigger: "Trigger"
+ events: "Webhook Events"
active: "Enabled"
_events:
follow: "When following a user"
followed: "When being followed"
note: "When posting a note"
reply: "When receiving a reply"
- renote: "When renoted"
+ renote: "When boosted"
reaction: "When receiving a reaction"
mention: "When being mentioned"
- _systemEvents:
- abuseReport: "When received a new report"
- abuseReportResolved: "When resolved report"
- userCreated: "When user is created"
- deleteConfirm: "Are you sure you want to delete the Webhook?"
- testRemarks: "Click the button to the right of the switch to send a test Webhook with dummy data."
-_abuseReport:
- _notificationRecipient:
- createRecipient: "Add a recipient for reports"
- modifyRecipient: "Edit a recipient for reports"
- recipientType: "Notification type"
- _recipientType:
- mail: "Email"
- webhook: "Webhook"
- _captions:
- mail: "Send the email to moderators' email addresses when you receive reports."
- webhook: "Send a notification to System Webhook when you receive or resolve reports."
- keywords: "Keywords"
- notifiedUser: "Users to notify"
- notifiedWebhook: "Webhook to use"
- deleteConfirm: "Are you sure that you want to delete the notification recipient?"
_moderationLogTypes:
createRole: "Role created"
deleteRole: "Role deleted"
updateRole: "Role updated"
assignRole: "Assigned to role"
unassignRole: "Removed from role"
+ approve: "Approved"
suspend: "Suspended"
unsuspend: "Unsuspended"
addCustomEmoji: "Custom emoji added"
@@ -2526,12 +2444,9 @@ _moderationLogTypes:
resetPassword: "Password reset"
suspendRemoteInstance: "Remote instance suspended"
unsuspendRemoteInstance: "Remote instance unsuspended"
- updateRemoteInstanceNote: "Moderation note updated for remote instance."
markSensitiveDriveFile: "File marked as sensitive"
unmarkSensitiveDriveFile: "File unmarked as sensitive"
resolveAbuseReport: "Report resolved"
- forwardAbuseReport: "Report forwarded"
- updateAbuseReportNote: "Moderation note of a report updated"
createInvitation: "Invite generated"
createAd: "Ad created"
deleteAd: "Ad deleted"
@@ -2539,18 +2454,81 @@ _moderationLogTypes:
createAvatarDecoration: "Avatar decoration created"
updateAvatarDecoration: "Avatar decoration updated"
deleteAvatarDecoration: "Avatar decoration deleted"
- unsetUserAvatar: "User avatar unset"
- unsetUserBanner: "User banner unset"
- createSystemWebhook: "System Webhook created"
- updateSystemWebhook: "System Webhook updated"
- deleteSystemWebhook: "System Webhook deleted"
- createAbuseReportNotificationRecipient: "Recipient for reports created"
- updateAbuseReportNotificationRecipient: "Recipient for reports updated"
- deleteAbuseReportNotificationRecipient: "Recipient for reports deleted"
- deleteAccount: "Account deleted"
- deletePage: "Page deleted"
- deleteFlash: "Play deleted"
- deleteGalleryPost: "Gallery post deleted"
+ unsetUserAvatar: "Unset this user's avatar"
+ unsetUserBanner: "Unset this user's banner"
+_mfm:
+ intro: "MFM is a markup language used on Misskey, Sharkey, Firefish, Akkoma, and more that can be used in many places. Here you can view a list of all available MFM syntax."
+ dummy: "Sharkey expands the world of the Fediverse"
+ mention: "Mention"
+ mentionDescription: "You can specify a user by using an At-Symbol and a username."
+ hashtag: "Hashtag"
+ hashtagDescription: "You can specify a hashtag using a number sign and text."
+ url: "URL"
+ urlDescription: "URLs can be displayed."
+ link: "Link"
+ linkDescription: "Specific parts of text can be displayed as a URL."
+ bold: "Bold"
+ boldDescription: "Highlights letters by making them thicker."
+ small: "Small"
+ smallDescription: "Displays content small and thin."
+ center: "Center"
+ centerDescription: "Displays content centered."
+ inlineCode: "Code (Inline)"
+ inlineCodeDescription: "Displays inline syntax highlighting for (program) code."
+ blockCode: "Code (Block)"
+ blockCodeDescription: "Displays syntax highlighting for multi-line (program) code in a block."
+ inlineMath: "Math (Inline)"
+ inlineMathDescription: "Display math formulas (KaTeX) in-line"
+ blockMath: "Math (Block)"
+ blockMathDescription: "Display math formulas (KaTeX) in a block"
+ quote: "Quote"
+ quoteDescription: "Displays content as a quote."
+ emoji: "Custom Emoji"
+ emojiDescription: "By surrounding a custom emoji name with colons, custom emoji can be displayed."
+ search: "Search"
+ searchDescription: "Displays a search box with pre-entered text."
+ flip: "Flip"
+ flipDescription: "Flips content horizontally or vertically."
+ jelly: "Animation (Jelly)"
+ jellyDescription: "Gives content a jelly-like animation."
+ tada: "Animation (Tada)"
+ tadaDescription: "Gives content a \"Tada!\"-like animation."
+ jump: "Animation (Jump)"
+ jumpDescription: "Gives content a jumping animation."
+ bounce: "Animation (Bounce)"
+ bounceDescription: "Gives content a bouncy animation."
+ shake: "Animation (Shake)"
+ shakeDescription: "Gives content a shaking animation."
+ twitch: "Animation (Twitch)"
+ twitchDescription: "Gives content a strongly twitching animation."
+ spin: "Animation (Spin)"
+ spinDescription: "Gives content a spinning animation."
+ x2: "Big"
+ x2Description: "Displays content bigger."
+ x3: "Very big"
+ x3Description: "Displays content even bigger."
+ x4: "Unbelievably big"
+ x4Description: "Displays content even bigger than bigger than big."
+ blur: "Blur"
+ blurDescription: "Blurs content. It will be displayed clearly when hovered over."
+ font: "Font"
+ fontDescription: "Sets the font to display content in."
+ rainbow: "Rainbow"
+ rainbowDescription: "Makes the content appear in rainbow colors."
+ sparkle: "Sparkle"
+ sparkleDescription: "Gives content a sparkling particle effect."
+ rotate: "Rotate"
+ rotateDescription: "Turns content by a specified angle."
+ position: "Position"
+ positionDescription: "Move content by a specified amount."
+ scale: "Scale"
+ scaleDescription: "Scale content by a specified amount."
+ foreground: "Foreground color"
+ foregroundDescription: "Change the foreground color of text."
+ background: "Background color"
+ backgroundDescription: "Change the background color of text."
+ plain: "Plain"
+ plainDescription: "Deactivates the effects of all MFM contained within this MFM effect."
_fileViewer:
title: "File details"
type: "File type"
@@ -2600,6 +2578,20 @@ _externalResourceInstaller:
_themeInstallFailed:
title: "Failed to install theme"
description: "A problem occurred during theme installation. Please try again. Error details can be viewed in the Javascript console."
+
+_animatedMFM:
+ play: "Play MFM Animation"
+ stop: "Stop MFM Animation"
+ _alert:
+ text: "Animated MFMs could include flashing lights and fast moving text/emojis."
+ confirm: "Animate"
+
+_dataRequest:
+ title: "Request Data"
+ warn: "Data requests are only possible every 3 days."
+ text: "Once the data is ready to download, an email will be sent to the email address registered to this account."
+ button: "Request"
+
_dataSaver:
_media:
title: "Loading Media"
@@ -2659,45 +2651,7 @@ _reversi:
opponentHasSettingsChanged: "The opponent has changed their settings."
allowIrregularRules: "Irregular rules (completely free)"
disallowIrregularRules: "No irregular rules"
- showBoardLabels: "Display row and column numbering on the board"
- useAvatarAsStone: "Turn stones into user avatars"
_offlineScreen:
title: "Offline - cannot connect to the server"
header: "Unable to connect to the server"
-_urlPreviewSetting:
- title: "URL preview settings"
- enable: "Enable URL preview"
- timeout: "Time out when getting preview (ms)"
- timeoutDescription: "If it takes longer than this value to get the preview, the preview won’t be generated."
- maximumContentLength: "Maximum Content-Length (bytes)"
- maximumContentLengthDescription: "If Content-Length is higher than this value, the preview won't be generated."
- requireContentLength: "Generate the preview only if you could get Content-Length"
- requireContentLengthDescription: "If other server doesn't return Content-Length, the preview won't be generated."
- userAgent: "User-Agent"
- userAgentDescription: "Sets the User-Agent to be used when retrieving previews. If left blank, the default User-Agent will be used."
- summaryProxy: "Proxy endpoints that generate previews"
- summaryProxyDescription: "Not Misskey itself, but generate previews using Summaly Proxy."
- summaryProxyDescription2: "The following parameters are linked to the proxy as a query string. If the proxy does not support them, the values are ignored."
-_mediaControls:
- pip: "Picture in Picture"
- playbackRate: "Playback Speed"
- loop: "Loop playback"
-_contextMenu:
- title: "Context menu"
- app: "Application"
- appWithShift: "Application with shift key"
- native: "Native"
-_embedCodeGen:
- title: "Customize embed code"
- header: "Show header"
- autoload: "Automatically load more (deprecated)"
- maxHeight: "Max height"
- maxHeightDescription: "Setting it to 0 disables the max height setting. Specify some value to prevent the widget from continuing to expand vertically."
- maxHeightWarn: "The max height limit is disabled (0). If this was not intended, set the max height to some value."
- previewIsNotActual: "The display differs from the actual embedding because it exceeds the range displayed on the preview screen."
- rounded: "Make it rounded"
- border: "Add a border to the outer frame"
- applyToPreview: "Apply to the preview"
- generateCode: "Generate embed code"
- codeGenerated: "The code has been generated"
- codeGeneratedDescription: "Paste the generated code into your website to embed the content."
+
diff --git a/locales/es-ES.yml b/locales/es-ES.yml
index d574999e40..a4d004c45e 100644
--- a/locales/es-ES.yml
+++ b/locales/es-ES.yml
@@ -60,7 +60,6 @@ copyFileId: "Copiar ID del archivo"
copyFolderId: "Copiar ID de carpeta"
copyProfileUrl: "Copiar la URL del perfil"
searchUser: "Buscar un usuario"
-searchThisUsersNotes: ""
reply: "Responder"
loadMore: "Ver más"
showMore: "Ver más"
@@ -109,14 +108,11 @@ enterEmoji: "Ingresar emojis"
renote: "Renotar"
unrenote: "Quitar renota"
renoted: "Renotado"
-renotedToX: "{name} usuarios han renotado。"
cantRenote: "No se puede renotar este post"
cantReRenote: "No se puede renotar una renota"
quote: "Citar"
inChannelRenote: "Renota sólo del canal"
inChannelQuote: "Cita sólo del canal"
-renoteToChannel: "Renotar a otro canal"
-renoteToOtherChannel: "Renotar a otro canal"
pinnedNote: "Nota fijada"
pinned: "Fijar al perfil"
you: "Tú"
@@ -155,7 +151,6 @@ editList: "Editar lista"
selectChannel: "Seleccionar canal"
selectAntenna: "Seleccionar antena"
editAntenna: "Editar antena"
-createAntenna: "Crear una antena"
selectWidget: "Seleccionar widget"
editWidgets: "Editar widgets"
editWidgetsExit: "Terminar edición"
@@ -182,10 +177,6 @@ addAccount: "Agregar Cuenta"
reloadAccountsList: "Recargar lista de cuentas"
loginFailed: "Error al iniciar sesión."
showOnRemote: "Ver en una instancia remota"
-continueOnRemote: "Ver en una instancia remota"
-chooseServerOnMisskeyHub: "Elegir un servidor en Misskey Hub"
-specifyServerHost: "Especifica una instancia directamente"
-inputHostName: "Introduzca el dominio"
general: "General"
wallpaper: "Fondo de pantalla"
setWallpaper: "Establecer fondo de pantalla"
@@ -244,7 +235,7 @@ done: "Terminado"
processing: "Procesando"
preview: "Vista previa"
default: "Predeterminado"
-defaultValueIs: "Por defecto: {value}"
+defaultValueIs: "Predeterminado"
noCustomEmojis: "No hay emojis personalizados"
noJobs: "No hay trabajos"
federating: "Federando"
@@ -311,7 +302,7 @@ location: "Lugar"
theme: "Tema"
themeForLightMode: "Tema para usar en Modo Linterna"
themeForDarkMode: "Tema para usar en Modo Oscuro"
-light: "Claro"
+light: "Linterna"
dark: "Oscuro"
lightThemes: "Tema claro"
darkThemes: "Tema oscuro"
@@ -409,7 +400,6 @@ name: "Nombre"
antennaSource: "Origen de la antena"
antennaKeywords: "Palabras clave para recibir"
antennaExcludeKeywords: "Palabras clave para excluir"
-antennaExcludeBots: "Excluir bots"
antennaKeywordsDescription: "Separar con espacios es una declaración AND, separar con una linea nueva es una declaración OR"
notifyAntenna: "Notificar nueva nota"
withFileAntenna: "Sólo notas con archivos adjuntados"
@@ -502,8 +492,8 @@ uiLanguage: "Idioma de visualización de la interfaz"
aboutX: "Acerca de {x}"
emojiStyle: "Estilo de emoji"
native: "Nativo"
+disableDrawer: "No mostrar los menús en cajones"
showNoteActionsOnlyHover: "Mostrar acciones de la nota sólo al pasar el cursor"
-showReactionsCount: "Mostrar el número de reacciones en las notas"
noHistory: "No hay datos en el historial"
signinHistory: "Historial de ingresos"
enableAdvancedMfm: "Habilitar MFM avanzado"
@@ -700,7 +690,10 @@ abuseReported: "Se ha enviado el reporte. Muchas gracias."
reporter: "Reportador"
reporteeOrigin: "Reportar a"
reporterOrigin: "Origen del reporte"
+forwardReport: "Transferir un informe a una instancia remota"
+forwardReportIsAnonymous: "No puede ver su información de la instancia remota y aparecerá como una cuenta anónima del sistema"
send: "Enviar"
+abuseMarkAsResolved: "Marcar reporte como resuelto"
openInNewTab: "Abrir en una Nueva Pestaña"
openInSideView: "Abrir en una vista al costado"
defaultNavigationBehaviour: "Navegación por defecto"
@@ -998,7 +991,6 @@ neverShow: "No mostrar de nuevo"
remindMeLater: "Recordar después"
didYouLikeMisskey: "¿Te gusta Misskey?"
pleaseDonate: "{host} usa el software gratuito Misskey. Por favor ¡Considera donar al proyecto principal para que podamos continuar!"
-correspondingSourceIsAvailable: "El código fuente correspondiente se encuentra disponible en {anchor}"
roles: "Roles"
role: "Rol"
noRole: "Rol no encontrado"
@@ -1050,7 +1042,6 @@ sensitiveWords: "Palabras sensibles"
sensitiveWordsDescription: "La visibilidad de todas las notas que contienen cualquiera de las palabras configuradas serán puestas en \"Inicio\" automáticamente. Puedes enumerás varias separándolas con saltos de línea"
sensitiveWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares."
prohibitedWords: "Palabras explícitas"
-prohibitedWordsDescription: "Activa un error cuando se intenta publicar una nota que contiene una o varias palabras prohibidas. Se pueden establecer varias palabras, una por línea."
prohibitedWordsDescription2: "Si se usan espacios se crearán expresiones AND y las palabras subsecuentes con barras inclinadas se convertirán en expresiones regulares."
hiddenTags: "Hashtags ocultos"
hiddenTagsDescription: "Selecciona las etiquetas que no se mostrarán en tendencias. Una etiqueta por línea."
@@ -1099,8 +1090,6 @@ preservedUsernames: "Nombre de usuario reservado"
preservedUsernamesDescription: "La lista de nombres de usuario para reservar tienen que separarse con saltos de línea.\nEstos estarán indisponibles durante la creación de cuentas, pero pueden ser usados para que los administradores puedan crear esas cuentas manualmente. Las cuentas existentes con esos nombres de usuario no se verán afectadas."
createNoteFromTheFile: "Componer una nota desde éste archivo"
archive: "Archivo"
-archived: "Archivado"
-unarchive: "Desarchivar"
channelArchiveConfirmTitle: "¿Seguro de archivar {name}?"
channelArchiveConfirmDescription: "Un canal archivado no aparecerá en la lista de canales ni en los resultados. Las nuevas publicaciones tampoco serán añadidas."
thisChannelArchived: "El canal ha sido archivado."
@@ -1153,8 +1142,8 @@ currentAnnouncements: "Anuncios actuales"
pastAnnouncements: "Anuncios anteriores"
youHaveUnreadAnnouncements: "Hay anuncios sin leer"
useSecurityKey: "Por favor, sigue las instrucciones de tu dispositivo o navegador para usar tu clave de seguridad o tu clave de paso."
-replies: "Responder"
-renotes: "Renotar"
+replies: "Respuestas"
+renotes: "Renotas"
loadReplies: "Ver respuestas"
loadConversation: "Ver conversación"
pinnedList: "Lista fijada"
@@ -1169,7 +1158,6 @@ showRenotes: "Mostrar renotas"
edited: "Editado"
notificationRecieveConfig: "Ajustes de Notificaciones"
mutualFollow: "Os seguís mutuamente"
-followingOrFollower: "Siguiendo o seguidor"
fileAttachedOnly: "Solo notas con archivos"
showRepliesToOthersInTimeline: "Mostrar respuestas a otros en la línea de tiempo"
hideRepliesToOthersInTimeline: "Ocultar respuestas a otros en la línea de tiempo"
@@ -1179,12 +1167,6 @@ confirmShowRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres
confirmHideRepliesAll: "Esta operación es irreversible. ¿Confirmas que quieres ocultar tus respuestas a otros usuarios que sigues en tu línea de tiempo?"
externalServices: "Servicios Externos"
sourceCode: "Código fuente"
-sourceCodeIsNotYetProvided: "El código fuente aún no está disponible. Contacta con el administrador para solucionarlo."
-repositoryUrl: "URL del repositorio"
-repositoryUrlDescription: "Si estás usando Misskey tal cual (sin cambios en el código fuente), entra en https://github.com/misskey-dev/misskey"
-repositoryUrlOrTarballRequired: "Si no has publicado un repositorio aún, deberás publicar un tarball en su lugar. Mira el archivo .config/example.yml para más información."
-feedback: "Comentarios"
-feedbackUrl: "URL de comentarios"
impressum: "Impressum"
impressumUrl: "Impressum URL"
impressumDescription: "En algunos países, como Alemania, la inclusión del operador de datos (el Impressum) es requerido legalmente para sitios web comerciales."
@@ -1220,8 +1202,6 @@ soundWillBePlayed: "Se reproducirán efectos sonoros"
showReplay: "Ver reproducción"
replay: "Reproducir"
replaying: "Reproduciendo"
-endReplay: "Terminar reproducción"
-copyReplayData: "Copiar datos de reproducción"
ranking: "Clasificación"
lastNDays: "Últimos {n} días"
backToTitle: "Regresar al inicio"
@@ -1229,32 +1209,8 @@ hemisphere: "Región"
withSensitive: "Mostrar notas que contengan material sensible"
userSaysSomethingSensitive: "La publicación de {name} contiene material sensible"
enableHorizontalSwipe: "Deslice para cambiar de pestaña"
-loading: "Cargando"
-surrender: "detener"
-gameRetry: "Reintentar"
-notUsePleaseLeaveBlank: "Dejar en blanco si no se usa"
-useTotp: "Introduce la contraseña de un solo uso"
-useBackupCode: "Usar códigos de respaldo"
-launchApp: "Ejecutar la app"
-useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reproduce audio y vídeo"
-keepOriginalFilename: "Mantener el nombre original del archivo"
-noDescription: "No hay descripción"
-alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
-_delivery:
- stop: "Suspendido"
- _type:
- none: "Publicando"
_bubbleGame:
howToPlay: "Cómo jugar"
- hold: "Mantener"
- _score:
- score: "Puntos"
- scoreYen: "Cantidad de dinero ganada"
- highScore: "Puntuación más alta"
- maxChain: "Número máximo de cadenas"
- yen: "{yen} Yenes"
- estimatedQty: "{qty} Piezas"
- scoreSweets: "{onigiriQtyWithUnit} Onigiris"
_howToPlay:
section1: "Ajuste la posición y deje caer el objeto en la caja"
section2: "Cuando dos objetos del mismo tipo se tocan, cambian a otro tipo y consigues puntos"
@@ -1372,7 +1328,7 @@ _serverSettings:
_accountMigration:
moveFrom: "Trasladar de otra cuenta a ésta"
moveFromSub: "Crear un alias para otra cuenta."
- moveFromLabel: "Cuenta desde la que se realiza el traslado #{n}"
+ moveFromLabel: "Cuenta desde la que se realiza el traslado:"
moveFromDescription: "Si quieres transferir seguidores de otra cuenta a esta cuenta y trasladarlos, tendrás que crear un alias aquí. Asegúrate de crearlo antes de realizar el traslado. Introduce la cuenta desde la que estás moviendo los seguidores así: @person@instance.com"
moveTo: "Mover esta cuenta a una nueva"
moveToLabel: "Cuenta destino:"
@@ -1631,11 +1587,8 @@ _achievements:
description: "Tutorial completado"
_bubbleGameExplodingHead:
title: "🤯"
- description: "El objeto más grande en el juego de burbujas"
_bubbleGameDoubleExplodingHead:
title: "Doble 🤯"
- description: "Dos de los objetos más grandes en el juego de burbujas al mismo tiempo"
- flavor: "Puedes llenar el bento un poco de esta forma 🤯 🤯."
_role:
new: "Crear rol"
edit: "Editar rol"
@@ -1676,7 +1629,6 @@ _role:
gtlAvailable: "Explorar la línea de tiempo global"
ltlAvailable: "Explorar la línea de tiempo local"
canPublicNote: "Permitir la publicación"
- mentionMax: "Número máximo de menciones en una nota"
canInvite: "Puede crear códigos de invitación"
inviteLimit: "Límite de invitaciones"
inviteLimitCycle: "Enfriamiento del límite de invitaciones"
@@ -1700,13 +1652,8 @@ _role:
canUseTranslator: "Uso de traductor"
avatarDecorationLimit: "Número máximo de decoraciones de avatar"
_condition:
- roleAssignedTo: "Asignado a roles manuales"
isLocal: "Usuario local"
isRemote: "Usuario remoto"
- isCat: "Usuarios Gato"
- isBot: "Usuarios Bot"
- isSuspended: "Usuario suspendido"
- isLocked: "Cuentas privadas"
createdLessThan: "Menos de X han pasado desde la creación de la cuenta"
createdMoreThan: "Más de X han pasado desde la creación de la cuenta"
followersLessThanOrEq: "Tiene X o menos seguidores"
@@ -1776,7 +1723,6 @@ _plugin:
installWarn: "Por favor no instale plugins que no son de confianza"
manage: "Gestionar plugins"
viewSource: "Ver la fuente"
- viewLog: "Ver log"
_preferencesBackups:
list: "Respaldos creados"
saveNew: "Guardar nuevo respaldo"
@@ -1806,8 +1752,6 @@ _aboutMisskey:
contributors: "Principales colaboradores"
allContributors: "Todos los colaboradores"
source: "Código fuente"
- original: "Original"
- thisIsModifiedVersion: "{name} usa una versión modificada de Misskey."
translation: "Traducir Misskey"
donate: "Donar a Misskey"
morePatrons: "Muchas más personas nos apoyan. Muchas gracias🥰"
@@ -1915,6 +1859,7 @@ _theme:
buttonBg: "Fondo de botón"
buttonHoverBg: "Fondo de botón (hover)"
inputBorder: "Borde de los campos de entrada"
+ listItemHoverBg: "Fondo de elemento de listas (hover)"
driveFolderBg: "Fondo de capeta del drive"
wallpaperOverlay: "Transparencia del fondo de pantalla"
badge: "Medalla"
@@ -1926,6 +1871,8 @@ _sfx:
note: "Notas"
noteMy: "Nota (a mí mismo)"
notification: "Notificaciones"
+ antenna: "Antena receptora"
+ channel: "Notificaciones del canal"
reaction: "Al seleccionar una reacción"
_soundSettings:
driveFile: "Usar un archivo de audio en Drive"
@@ -1963,6 +1910,7 @@ _2fa:
registerTOTP: "Registrar aplicación autenticadora"
step1: "Primero, instale en su dispositivo la aplicación de autenticación {a} o {b} u otra."
step2: "Luego, escanee con la aplicación el código QR mostrado en pantalla."
+ step2Click: "Clicking on this QR code will allow you to register 2FA to your security key or phone authenticator app.\nTocar este código QR te permitirá registrar la autenticación 2FA a tu llave de seguridad o aplicación autenticadora."
step2Uri: "Si usas una aplicación de escritorio, introduce en ella la siguiente URL."
step3Title: "Ingresa un código de autenticación"
step3: "Para terminar, ingrese el token mostrado en la aplicación."
@@ -1986,7 +1934,6 @@ _2fa:
backupCodesDescription: "En caso de que no puedas usar tu aplicación de autenticación, podrás usar los códigos de respaldo que figuran abajo para acceder a tu cuenta. Asegúrate de guardar en lugar seguro los códigos de respaldo. Cada uno de los códigos de respaldo es de un solo uso."
backupCodeUsedWarning: "Has usado todos los códigos de respaldo. Si dejas de tener acceso a tu aplicación de autenticación, no podrás volver a iniciar sesión en tu cuenta. Por favor, reconfigura tu aplicación de autenticación lo antes posible."
backupCodesExhaustedWarning: "Has usado todos los códigos de respaldo. Si dejas de tener acceso a tu aplicación de autenticación, no podrás volver a iniciar sesión en la cuenta que figura arriba. Por favor, reconfigura tu aplicación de autenticación lo antes posible."
- moreDetailedGuideHere: "Guía detallada"
_permissions:
"read:account": "Ver información de la cuenta"
"write:account": "Editar información de la cuenta"
@@ -2028,7 +1975,6 @@ _permissions:
"write:admin:delete-account": "Eliminar cuentas de usuario"
"write:admin:delete-all-files-of-a-user": "Eliminar todos los archivos de un usuario"
"read:admin:index-stats": "Ver datos indexados"
- "read:admin:table-stats": "Ver estadísticas de las tablas de la base de datos"
"read:admin:user-ips": "Ver dirección IP de usuario"
"read:admin:meta": "Ver metadatos de la instancia"
"write:admin:reset-password": "Restablecer contraseñas de usuario"
@@ -2037,6 +1983,7 @@ _permissions:
"read:admin:server-info": "Ver información del servidor"
"read:admin:show-moderation-log": "Ver log de moderación"
"read:admin:show-user": "Ver información privada de usuario"
+ "read:admin:show-users": "Ver información privada de usuario"
"write:admin:suspend-user": "Suspender cuentas de usuario"
"write:admin:unset-user-avatar": "Quitar avatares de usuario"
"write:admin:unset-user-banner": "Quitar banner de usuarios"
@@ -2154,6 +2101,7 @@ _poll:
remainingHours: "Quedan {h} horas y {m} minutos para que finalice"
remainingMinutes: "Quedan {m} minutos y {s} segundos para que finalice"
remainingSeconds: "Quedan {s} segundos para que finalice"
+ multiple: "Opciones múltiples"
_visibility:
public: "Público"
publicDescription: "Visible para todos los usuarios"
@@ -2247,7 +2195,6 @@ _play:
title: "Título"
script: "Script"
summary: "Descripción"
- visibilityDescription: "Poniéndola como privada significa que no será visible en tu perfil, pero cualquiera que tenga la URL aún podrá acceder a ella."
_pages:
newPage: "Crear página"
editPage: "Editar página"
@@ -2292,8 +2239,6 @@ _pages:
section: "Sección"
image: "Imagen"
button: "Botón"
- dynamic: "Bloques Dinámicos"
- dynamicDescription: "Los bloques dinámicos están obsoletos. A partir de ahora, utiliza {play} por favor."
note: "Nota embebida"
_note:
id: "Id de la nota"
@@ -2339,7 +2284,6 @@ _notification:
followRequestAccepted: "El seguimiento fue aceptado"
roleAssigned: "Rol asignado"
achievementEarned: "Logro desbloqueado"
- login: "Iniciar sesión"
app: "Notificaciones desde aplicaciones"
_actions:
followBack: "Te sigue de vuelta"
@@ -2389,6 +2333,7 @@ _webhookSettings:
createWebhook: "Crear Webhook"
name: "Nombre"
secret: "Secreto"
+ events: "Eventos de webhook"
active: "Activado"
_events:
follow: "Cuando se sigue a alguien"
@@ -2398,12 +2343,6 @@ _webhookSettings:
renote: "Cuando reciba un \"re-note\""
reaction: "Cuando se recibe una reacción"
mention: "Cuando hay una mención"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Correo"
- webhook: "Webhook"
- keywords: "Palabras Clave"
_moderationLogTypes:
createRole: "Rol creado"
deleteRole: "Rol eliminado"
@@ -2507,14 +2446,6 @@ _hemisphere:
S: "Hemisferio sur"
_reversi:
reversi: "Reversi"
- rules: "Reglas"
won: "{name} ha ganado"
total: "Total"
-_urlPreviewSetting:
- timeout: "Timeout de la carga de vista previa de las URLs (ms)"
- maximumContentLength: "Content-Length Máximo (bytes)"
- userAgent: "User-Agent"
-_mediaControls:
- pip: "Picture in Picture"
- playbackRate: "Velocidad de reproducción"
- loop: "Reproducción en bucle"
+
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index a7060c06fc..d3a90c6d77 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -129,7 +129,7 @@ overwriteFromPinnedEmojisForReaction: "Remplacer par les émojis épinglés pour
overwriteFromPinnedEmojis: "Remplacer par les émojis épinglés globalement"
reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser « + » pour ajouter."
rememberNoteVisibility: "Se souvenir de la visibilité des notes"
-attachCancel: "Supprimer le fichier joint"
+attachCancel: "Supprimer le fichier attaché"
deleteFile: "Fichier supprimé"
markAsSensitive: "Marquer comme sensible"
unmarkAsSensitive: "Supprimer le marquage comme sensible"
@@ -380,11 +380,8 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Activer hCaptcha"
hcaptchaSiteKey: "Clé du site"
hcaptchaSecretKey: "Clé secrète"
-mcaptcha: "mCaptcha"
-enableMcaptcha: "Activer mCaptcha"
mcaptchaSiteKey: "Clé du site"
mcaptchaSecretKey: "Clé secrète"
-mcaptchaInstanceUrl: "URL de l'instance de mCaptcha"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Activer reCAPTCHA"
recaptchaSiteKey: "Clé du site"
@@ -400,7 +397,6 @@ name: "Nom"
antennaSource: "Source de l’antenne"
antennaKeywords: "Mots clés à recevoir"
antennaExcludeKeywords: "Mots clés à exclure"
-antennaExcludeBots: "Exclure les comptes robot"
antennaKeywordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR."
notifyAntenna: "Me notifier pour les nouvelles notes"
withFileAntenna: "Notes ayant des fichiers joints uniquement"
@@ -493,8 +489,8 @@ uiLanguage: "Langue d’affichage de l’interface"
aboutX: "À propos de {x}"
emojiStyle: "Style des émojis"
native: "Natif"
+disableDrawer: "Les menus ne s'affichent pas dans le tiroir"
showNoteActionsOnlyHover: "Afficher les actions de note uniquement au survol"
-showReactionsCount: "Afficher le nombre de réactions des notes"
noHistory: "Pas d'historique"
signinHistory: "Historique de connexion"
enableAdvancedMfm: "Activer la MFM avancée"
@@ -527,7 +523,7 @@ hideThisNote: "Masquer cette note"
showFeaturedNotesInTimeline: "Afficher les notes des Tendances dans le fil d'actualité"
objectStorage: "Stockage d'objets"
useObjectStorage: "Utiliser le stockage d'objets"
-objectStorageBaseUrl: "URL de base"
+objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "Préfixe d’URL utilisé pour construire l’URL vers le référencement d’objet (média). Spécifiez son URL si vous utilisez un CDN ou un proxy, sinon spécifiez l’adresse accessible au public selon le guide de service que vous allez utiliser. P.ex. 'https://.s3.amazonaws.com' pour AWS S3 et 'https://storage.googleapis.com/' pour GCS."
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Veuillez spécifier le nom du compartiment utilisé sur le service configuré."
@@ -542,7 +538,6 @@ objectStorageUseSSLDesc: "Désactivez cette option si vous n'utilisez pas HTTPS
objectStorageUseProxy: "Se connecter via proxy"
objectStorageUseProxyDesc: "Désactivez cette option si vous n'utilisez pas de proxy pour la connexion API"
objectStorageSetPublicRead: "Régler sur « public » lors de l'envoi"
-s3ForcePathStyleDesc: "Si s3ForcePathStyle est activé, le nom du compartiment doit être spécifié comme une partie du chemin de l'URL plutôt que le nom d'hôte. Il faudra peut-être l'activer lors de l'utilisation d'une instance de Minio autohébergée, etc."
serverLogs: "Journal du serveur"
deleteAll: "Supprimer tout"
showFixedPostForm: "Afficher le formulaire de publication en haut du fil d'actualité"
@@ -633,7 +628,6 @@ medium: "Moyen"
small: "Petit"
generateAccessToken: "Générer un jeton d'accès"
permission: "Autorisations "
-adminPermission: "Droits de l'administrateur"
enableAll: "Tout activer"
disableAll: "Tout désactiver"
tokenRequested: "Autoriser l'accès au compte"
@@ -657,7 +651,7 @@ testEmail: "Tester la distribution de courriel"
wordMute: "Filtre de mots"
hardWordMute: "Filtre de mots dur"
regexpError: "Erreur d’expression régulière"
-regexpErrorDescription: "Une erreur s'est produite dans l'expression régulière sur la ligne {line} de votre mot muet {tab} :"
+regexpErrorDescription: "Une erreur s'est produite dans l'expression régulière sur la ligne {ligne} de votre mot muet {tab} :"
instanceMute: "Instance en sourdine"
userSaysSomething: "{name} a dit quelque chose"
makeActive: "Activer"
@@ -677,7 +671,6 @@ useGlobalSettingDesc: "S'il est activé, les paramètres de notification de votr
other: "Autre"
regenerateLoginToken: "Régénérer le jeton de connexion"
regenerateLoginTokenDescription: "Générer un nouveau jeton d'authentification. Cette opération ne devrait pas être nécessaire ; lors de la génération d'un nouveau jeton, tous les appareils seront déconnectés. "
-theKeywordWhenSearchingForCustomEmoji: "Ce mot-clé est utilisé lors de la recherche des émojis personnalisés."
setMultipleBySeparatingWithSpace: "Vous pouvez en définir plusieurs, en les séparant par des espaces."
fileIdOrUrl: "ID du fichier ou URL"
behavior: "Comportement"
@@ -691,7 +684,10 @@ abuseReported: "Le rapport est envoyé. Merci."
reporter: "Signalé par"
reporteeOrigin: "Origine du signalement"
reporterOrigin: "Signalé par"
+forwardReport: "Transférer le signalement à l’instance distante"
+forwardReportIsAnonymous: "L'instance distante ne sera pas en mesure de voir vos informations et apparaîtra comme un compte anonyme du système."
send: "Envoyer"
+abuseMarkAsResolved: "Marquer le signalement comme résolu"
openInNewTab: "Ouvrir dans un nouvel onglet"
openInSideView: "Ouvrir en vue latérale"
defaultNavigationBehaviour: "Navigation par défaut"
@@ -989,7 +985,6 @@ neverShow: "Ne plus afficher"
remindMeLater: "Peut-être plus tard"
didYouLikeMisskey: "Avez-vous aimé Misskey ?"
pleaseDonate: "Misskey est le logiciel libre utilisé par {host}. Merci de faire un don pour que nous puissions continuer à le développer !"
-correspondingSourceIsAvailable: "Le code source correspondant est disponible à {anchor}"
roles: "Rôles"
role: "Rôles"
noRole: "Aucun rôle"
@@ -1004,7 +999,6 @@ youCannotCreateAnymore: "Vous avez atteint la limite de création."
cannotPerformTemporary: "Temporairement indisponible"
cannotPerformTemporaryDescription: "Temporairement indisponible puisque le nombre d'opérations dépasse la limite. Veuillez patienter un peu, puis réessayer."
invalidParamError: "Paramètres invalides"
-invalidParamErrorDescription: "Les paramètres de la requête sont invalides. Il s'agit généralement d'un bogue, mais cela peut aussi être causé par un excès de caractères ou quelque chose de similaire."
permissionDeniedError: "Opération refusée"
permissionDeniedErrorDescription: "Ce compte n'a pas la permission d'effectuer cette opération."
preset: "Préréglage"
@@ -1018,7 +1012,6 @@ thisPostMayBeAnnoyingCancel: "Annuler"
thisPostMayBeAnnoyingIgnore: "Publier quand-même"
collapseRenotes: "Réduire les renotes déjà vues"
internalServerError: "Erreur interne du serveur"
-internalServerErrorDescription: "Une erreur inattendue s'est produite sur le serveur."
copyErrorInfo: "Copier les détails de l’erreur"
joinThisServer: "S'inscrire à cette instance"
exploreOtherServers: "Trouver une autre instance"
@@ -1038,20 +1031,12 @@ nonSensitiveOnlyForLocalLikeOnlyForRemote: "Non sensibles seulement (mentions j'
rolesAssignedToMe: "Rôles attribués à moi"
resetPasswordConfirm: "Souhaitez-vous réinitialiser votre mot de passe ?"
sensitiveWords: "Mots sensibles"
-sensitiveWordsDescription: "Définir la visibilité des notes contenant un mot défini ici au fil principal automatiquement. Vous pouvez définir plusieurs valeurs en les séparant par des sauts de ligne."
-sensitiveWordsDescription2: "Séparer par une espace pour créer une expression AND ; entourer de barres obliques pour créer une expression régulière."
-prohibitedWords: "Mots interdits"
-prohibitedWordsDescription: "Publier une note contenant un mot défini ici produira une erreur. Vous pouvez définir plusieurs valeurs en les séparant par des sauts de ligne."
-prohibitedWordsDescription2: "Séparer par une espace pour créer une expression AND ; entourer de barres obliques pour créer une expression régulière."
hiddenTags: "Hashtags cachés"
hiddenTagsDescription: "Les hashtags définis ne s'afficheront pas dans les tendances. Vous pouvez définir plusieurs hashtags en faisant un saut de ligne."
notesSearchNotAvailable: "La recherche de notes n'est pas disponible."
license: "Licence"
-unfavoriteConfirm: "Vraiment supprimer des favoris ?"
myClips: "Mes clips"
drivecleaner: "Nettoyeur du Disque"
-retryAllQueuesNow: "Réessayer tous les fils d'attente immédiatement"
-retryAllQueuesConfirmTitle: "Vraiment réessayer ?"
retryAllQueuesConfirmText: "Cela peut augmenter temporairement la charge du serveur."
enableChartsForRemoteUser: "Générer les graphiques pour les utilisateurs distants"
enableChartsForFederatedInstances: "Générer les graphiques pour les instances distantes"
@@ -1061,8 +1046,6 @@ limitWidthOfReaction: "Limiter la largeur maximale des réactions et les affiche
noteIdOrUrl: "Identifiant de la note ou URL"
video: "Vidéo"
videos: "Vidéos"
-audio: "Audio"
-audioFiles: "Fichiers audio"
dataSaver: "Économiseur de données"
accountMigration: "Migration de compte"
accountMoved: "Cet·te utilisateur·rice a migré son compte vers :"
@@ -1087,13 +1070,9 @@ pleaseConfirmBelowBeforeSignup: "Pour vous inscrire sur cette instance, vous dev
pleaseAgreeAllToContinue: "Pour continuer, veuillez accepter tous les champs ci-dessus."
continue: "Continuer"
preservedUsernames: "Noms d'utilisateur·rice réservés"
-preservedUsernamesDescription: "Énumérez les noms d'utilisateur à réserver, séparés par des nouvelles lignes. Les noms d'utilisateur spécifiés ici ne seront plus utilisables lors de la création d'un compte, sauf la création manuelle par un administrateur. De plus, les comptes existants ne seront pas affectés."
createNoteFromTheFile: "Rédiger une note de ce fichier"
archive: "Archive"
-archived: "Archivé"
-unarchive: "Annuler l'archivage"
channelArchiveConfirmTitle: "Voulez-vous vraiment archiver {name} ?"
-channelArchiveConfirmDescription: "Une fois archivé, le canal n'apparaîtra plus dans la liste des canaux ni dans les résultats de recherche, et la publication des nouvelles notes sera impossible."
thisChannelArchived: "Ce canal a été archivé."
displayOfNote: "Affichage de la note"
initialAccountSetting: "Configuration initiale du profil"
@@ -1105,10 +1084,7 @@ specifyUser: "Spécifier l'utilisateur·rice"
failedToPreviewUrl: "Aperçu d'URL échoué"
update: "Mettre à jour"
rolesThatCanBeUsedThisEmojiAsReaction: "Rôles qui peuvent utiliser cet émoji comme réaction"
-rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Si aucun rôle n'est spécifié, tout le monde peut utiliser cet émoji comme réaction."
-rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Il faut un rôle public."
cancelReactionConfirm: "Supprimez la réaction ?"
-changeReactionConfirm: "Changer la réaction ?"
later: "Plus tard"
goToMisskey: "Retour vers Misskey"
additionalEmojiDictionary: "Dictionnaires d'émojis additionnels"
@@ -1122,8 +1098,6 @@ createWithOptions: "Options"
createCount: "Quantité à créer"
inviteCodeCreated: "Code d'invitation créé"
inviteLimitExceeded: "Vous avez atteint la limite de codes d'invitation que vous pouvez générer."
-createLimitRemaining: "Codes d'invitation pouvant être créés : {limit} restants"
-inviteLimitResetCycle: "Vous pouvez créer jusqu'à {limit} codes d'invitation en {time}."
expirationDate: "Date d’expiration"
noExpirationDate: "Ne pas expirer"
inviteCodeUsedAt: "Code d'invitation utilisé à"
@@ -1136,21 +1110,16 @@ used: "Utilisé"
expired: "Expiré"
doYouAgree: "Êtes-vous d’accord ?"
beSureToReadThisAsItIsImportant: "Assurez-vous de le lire ; c'est important."
-iHaveReadXCarefullyAndAgree: "J'ai lu le contenu de « {x} » et donne mon accord."
dialog: "Dialogue"
icon: "Avatar"
forYou: "Pour vous"
currentAnnouncements: "Annonces actuelles"
pastAnnouncements: "Annonces passées"
-youHaveUnreadAnnouncements: "Il y a des annonces non lues."
-useSecurityKey: "Suivez les instructions de votre navigateur ou de votre appareil pour utiliser une clé de sécurité ou une clé d'accès."
replies: "Réponses"
renotes: "Renotes"
loadReplies: "Inclure les réponses"
loadConversation: "Afficher la conversation"
pinnedList: "Liste épinglée"
-keepScreenOn: "Garder l'écran toujours allumé"
-verifiedLink: "Votre propriété de ce lien a été vérifiée"
notifyNotes: "Notifier à propos des nouvelles notes"
unnotifyNotes: "Ne pas notifier pour la publication des notes"
authentication: "Authentification"
@@ -1160,8 +1129,6 @@ showRenotes: "Afficher les renotes"
edited: "Modifié"
notificationRecieveConfig: "Paramètres des notifications"
mutualFollow: "Abonnement mutuel"
-followingOrFollower: "Abonnement ou abonné"
-fileAttachedOnly: "Avec fichiers joints seulement"
showRepliesToOthersInTimeline: "Afficher les réponses aux autres dans le fil"
hideRepliesToOthersInTimeline: "Masquer les réponses aux autres dans le fil"
showRepliesToOthersInTimelineAll: "Afficher les réponses de toutes les personnes que vous suivez dans le fil"
@@ -1170,11 +1137,6 @@ confirmShowRepliesAll: "Cette opération est irréversible. Voulez-vous vraiment
confirmHideRepliesAll: "Cette opération est irréversible. Voulez-vous vraiment masquer les réponses de toutes les personnes que vous suivez dans le fil ?"
externalServices: "Services externes"
sourceCode: "Code source"
-sourceCodeIsNotYetProvided: "Le code source n'est pas encore disponible. Veuillez signaler ce problème aux administrateurs."
-repositoryUrl: "URL du dépôt"
-repositoryUrlDescription: "Entrez l'URL du dépôt où se trouve le code source ici. Si vous utilisez Misskey tel quel (sans changer le code source), entrez https://github.com/misskey-dev/misskey"
-feedback: "Commentaires"
-feedbackUrl: "URL pour les commentaires"
impressum: "Impressum"
impressumUrl: "URL de l'impressum"
impressumDescription: "Dans certains pays comme l'Allemagne, il est obligatoire d'afficher les informations sur l'opérateur d'un site (un impressum)."
@@ -1202,59 +1164,15 @@ remainingN: "Restants : {n}"
overwriteContentConfirm: "Voulez-vous remplacer le contenu actuel ?"
seasonalScreenEffect: "Effet d'écran saisonnier"
decorate: "Décorer"
-addMfmFunction: "Insérer MFM"
-enableQuickAddMfmFunction: "Afficher le sélecteur de MFM avancé"
-bubbleGame: "Jeu de bulles"
-sfx: "Effets sonores"
-soundWillBePlayed: "Le son sera joué"
-showReplay: "Voir le replay"
-replay: "Rediffusion"
-replaying: "En cours de rediffusion"
-endReplay: "Arrêter la rediffusion"
-copyReplayData: "Copier les données de la rediffusion"
-ranking: "Classement"
lastNDays: "Derniers {n} jours"
-backToTitle: "Retourner au titre"
-hemisphere: "Votre région"
-withSensitive: "Afficher les notes contenant des fichiers joints sensibles"
-userSaysSomethingSensitive: "Note de {name} contenant des fichiers joints sensibles"
-enableHorizontalSwipe: "Glisser pour changer d'onglet"
-loading: "Chargement en cours"
-surrender: "Annuler"
-gameRetry: "Réessayer"
-launchApp: "Lancer l'app"
-inquiry: "Contact"
-_delivery:
- status: "Statut de la diffusion"
- stop: "Suspendu·e"
- _type:
- none: "Publié"
-_bubbleGame:
- howToPlay: "Comment jouer"
- hold: "Réserver"
- _score:
- score: "Score"
- scoreYen: "Montant gagné"
- highScore: "Meilleur score"
- maxChain: "Nombre maximum de chaînes"
- yen: "{yen} yens"
- estimatedQty: "{qty} pièces"
_announcement:
forExistingUsers: "Pour les utilisateurs existants seulement"
- needConfirmationToRead: "Exiger la confirmation de la lecture"
- needConfirmationToReadDescription: "Si activé, afficher un dialogue de confirmation quand l'annonce est marquée comme lue. Aussi, elle sera exclue de « marquer tout comme lu » ."
- end: "Archiver l'annonce"
- tooManyActiveAnnouncementDescription: "Un grand nombre d'annonces actives peut baisser l'expérience utilisateur. Considérez d'archiver les annonces obsolètes."
readConfirmTitle: "Marquer comme lu ?"
- readConfirmText: "Cela marquera le contenu de « {title} » comme lu."
shouldNotBeUsedToPresentPermanentInfo: "Puisque cela pourrait nuire considérablement à l'expérience utilisateur pour les nouveaux utilisateurs, il est recommandé d'utiliser les annonces pour afficher des informations temporaires plutôt que des informations persistantes."
dialogAnnouncementUxWarn: "Avoir deux ou plus annonces de style dialogue en même temps pourrait nuire considérablement à l'expérience utilisateur. Veuillez les utiliser avec caution."
silence: "Ne pas me notifier"
silenceDescription: "Si activée, vous ne recevrez pas de notifications sur les annonces et n'aurez pas besoin de les marquer comme lues."
_initialAccountSetting:
- accountCreated: "Votre compte a été créé avec succès !"
- letsStartAccountSetup: "Procédons au réglage initial du compte."
- letsFillYourProfile: "Commençons par configurer votre profil !"
profileSetting: "Paramètres du profil"
privacySetting: "Paramètres de confidentialité"
initialAccountSettingCompleted: "Configuration du profil terminée avec succès !"
@@ -1322,7 +1240,7 @@ _initialTutorial:
doItToContinue: "Marquez le fichier joint comme sensible pour procéder."
_done:
title: "Le tutoriel est terminé ! 🎉"
- description: "Les fonctionnalités introduites ici ne sont que quelques-unes. Pour savoir plus sur l'utilisation de Misskey, veuillez consulter {link}."
+ description: "Les fonctionnalités introduites ici ne sont que quelques-unes. Pour savoir plus sur l'utilisation de Misskey, veuillez consulter {lien}."
_timelineDescription:
home: "Sur le fil principal, vous pouvez voir les notes des utilisateurs auxquels vous êtes abonné·e."
local: "Sur le fil local, vous pouvez voir les notes de tous les utilisateurs sur cette instance."
@@ -1346,7 +1264,7 @@ _achievements:
earnedAt: "Date d'obtention"
_types:
_notes1:
- title: "Je viens tout juste de configurer mon msky"
+ title: "Je viens tout juste de configurer mon shonk"
description: "Publiez votre première note"
flavor: "Passez un bon moment avec Misskey !"
_notes10:
@@ -1384,13 +1302,10 @@ _achievements:
title: "Régulier III"
description: "Se connecter pour un total de 400 jours"
_login500:
- title: "Expert I"
description: "Se connecter pour un total de 500 jours"
_login600:
- title: "Expert II"
description: "Se connecter pour un total de 600 jours"
_login700:
- title: "Expert III"
description: "Se connecter pour un total de 700 jours"
_login800:
description: "Se connecter pour un total de 800 jours"
@@ -1483,14 +1398,11 @@ _role:
edit: "Modifier le rôle"
name: "Nom du rôle"
description: "Description du rôle"
- permission: "Autorisations du rôle"
+ permission: "Rôle et autorisations"
assignTarget: "Attribuer"
- manual: "Manuel"
manualRoles: "Rôles manuels"
- conditional: "Conditionnel"
conditionalRoles: "Rôles conditionnels"
condition: "Condition"
- isConditionalRole: "Ceci est un rôle conditionnel."
isPublic: "Rôle public"
options: "Options"
policies: "Stratégies"
@@ -1701,6 +1613,7 @@ _theme:
buttonBg: "Arrière-plan du bouton"
buttonHoverBg: "Arrière-plan du bouton (survolé)"
inputBorder: "Cadre de la zone de texte"
+ listItemHoverBg: "Arrière-plan d'item de liste (survolé)"
driveFolderBg: "Arrière-plan du dossier de disque"
wallpaperOverlay: "Superposition de fond d'écran"
badge: "Badge"
@@ -1712,6 +1625,8 @@ _sfx:
note: "Nouvelle note"
noteMy: "Ma note"
notification: "Notifications"
+ antenna: "Réception de l’antenne"
+ channel: "Notifications de canal"
reaction: "Lors de la sélection de la réaction"
_soundSettings:
driveFile: "Utiliser un effet sonore sur le Disque"
@@ -2015,7 +1930,7 @@ _notification:
unreadAntennaNote: "Antenne {name}"
roleAssigned: "Rôle attribué"
emptyPushNotificationMessage: "Les notifications push ont été mises à jour"
- achievementEarned: "Accomplissement déverrouillé"
+ achievementEarned: "Accomplissement"
testNotification: "Tester la notification"
reactedBySomeUsers: "{n} utilisateur·rice·s ont réagi"
renotedBySomeUsers: "{n} utilisateur·rice·s ont renoté"
@@ -2032,8 +1947,7 @@ _notification:
receiveFollowRequest: "Demande d'abonnement reçue"
followRequestAccepted: "Demande d'abonnement acceptée"
roleAssigned: "Rôle reçu"
- achievementEarned: "Déverrouillage d'accomplissement"
- login: "Se connecter"
+ achievementEarned: "Accomplissement"
app: "Notifications provenant des apps"
_actions:
followBack: "Suivre"
@@ -2072,10 +1986,6 @@ _drivecleaner:
_webhookSettings:
name: "Nom"
active: "Activé"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "E-mail "
_moderationLogTypes:
createRole: "Rôle créé"
deleteRole: "Rôle supprimé"
@@ -2175,5 +2085,5 @@ _dataSaver:
title: "Mise en évidence du code"
description: "Si la notation de mise en évidence du code est utilisée, par exemple dans la MFM, elle ne sera pas chargée tant qu'elle n'aura pas été tapée. La mise en évidence du code nécessite le chargement du fichier de définition de chaque langue à mettre en évidence, mais comme ces fichiers ne sont plus chargés automatiquement, on peut s'attendre à une réduction du trafic de données."
_reversi:
- waitingBoth: "Préparez-vous"
total: "Total"
+
diff --git a/locales/generateDTS.js b/locales/generateDTS.js
index 571595de20..49807144ec 100644
--- a/locales/generateDTS.js
+++ b/locales/generateDTS.js
@@ -3,14 +3,10 @@ import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import * as yaml from 'js-yaml';
import ts from 'typescript';
-import { merge } from './index.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
-// braces preceded by backslashes are literal, they don't represent
-// parameters; they get cleaned up by `locales/index.js` before
-// getting shipped to the browser
-const parameterRegExp = /(?Manual untuk mengganti secara manual siapa yang mendapatkan peran ini dan siapa yang tidak.\nKondisional untuk pengguna secara otomatis dimasukkan atau dihapus dari peran berdasarkan kondisi yang ditentukan."
manual: "Manual"
- manualRoles: "Peran manual"
conditional: "Kondisional"
- conditionalRoles: "Peran kondisional"
condition: "Kondisi"
isConditionalRole: "Ini adalah peran kondisional"
isPublic: "Publikkan Peran"
@@ -1684,7 +1582,6 @@ _role:
gtlAvailable: "Dapat melihat lini masa global"
ltlAvailable: "Dapat melihat lini masa lokal"
canPublicNote: "Dapat mengirim catatan publik"
- mentionMax: "Jumlah maksimum sebutan dalam sebuah catatan"
canInvite: "Dapat membuat kode undangan instansi"
inviteLimit: "Batas jumlah undangan"
inviteLimitCycle: "Interval Penerbitan Kode Undangan"
@@ -1706,16 +1603,9 @@ _role:
canHideAds: "Dapat menyembunyikan iklan"
canSearchNotes: "Penggunaan pencarian catatan"
canUseTranslator: "Penggunaan penerjemah"
- avatarDecorationLimit: "Jumlah maksimum dekorasi avatar yang dapat diterapkan"
_condition:
- roleAssignedTo: "Ditugaskan ke peran manual"
isLocal: "Pengguna lokal"
isRemote: "Pengguna remote"
- isCat: "Pengguna Kucing"
- isBot: "Pengguna Bot"
- isSuspended: "Pengguna yang ditangguhkan"
- isLocked: "Akun privat"
- isExplorable: "Pengguna efektif yang akunnya dapat dicari"
createdLessThan: "Telah berlalu kurang dari X sejak pembuatan akun"
createdMoreThan: "Telah berlalu lebih dari X sejak pembuatan akun"
followersLessThanOrEq: "Memiliki pengikut X atau kurang dari tersebut"
@@ -1741,9 +1631,8 @@ _emailUnavailable:
disposable: "Alamat surel temporer tidak dapat digunakan"
mx: "Peladen alamat surel ini tidak valid"
smtp: "Peladen alamat surel ini tidak merespon"
- banned: "Kamu tidak dapat mendaftar dengan alamat surel ini"
_ffVisibility:
- public: "Publik"
+ public: "Terbitkan"
followers: "Tampil untuk pengikut saja"
private: "Tersembunyi"
_signup:
@@ -1785,7 +1674,6 @@ _plugin:
installWarn: "Mohon jangan memasang plugin yang tidak dapat dipercayai."
manage: "Manajemen plugin"
viewSource: "Lihat sumber"
- viewLog: "Tampilkan log"
_preferencesBackups:
list: "Cadangan yang dibuat"
saveNew: "Simpan cadangan baru"
@@ -1815,13 +1703,10 @@ _aboutMisskey:
contributors: "Kontributor utama"
allContributors: "Seluruh kontributor"
source: "Sumber kode"
- original: "Asli"
- thisIsModifiedVersion: "{name} menggunakan versi modifikasi dari Misskey yang asli."
translation: "Terjemahkan Misskey"
donate: "Donasi ke Misskey"
morePatrons: "Kami sangat mengapresiasi dukungan dari banyak penolong lain yang tidak tercantum disini. Terima kasih! 🥰"
patrons: "Pendukung"
- projectMembers: "Anggota proyek"
_displayOfSensitiveMedia:
respect: "Sembunyikan media yang ditandai sensitif"
ignore: "Tampilkan media yang ditandai sensitif"
@@ -1846,7 +1731,6 @@ _channel:
notesCount: "terdapat {n} catatan"
nameAndDescription: "Nama dan deskripsi"
nameOnly: "Hanya nama"
- allowRenoteToExternal: "Perbolehkan catat ulang dan kutipan di luar dari kanal"
_menuDisplay:
sideFull: "Horisontal"
sideIcon: "Horisontal (Ikon)"
@@ -1924,6 +1808,7 @@ _theme:
buttonBg: "Latar belakang tombol"
buttonHoverBg: "Latar belakang tombol (Mengambang)"
inputBorder: "Batas bidang masukan"
+ listItemHoverBg: "Latar belakang daftar item (Mengambang)"
driveFolderBg: "Latar belakang folder drive"
wallpaperOverlay: "Lapisan wallpaper"
badge: "Lencana"
@@ -1935,6 +1820,8 @@ _sfx:
note: "Catatan"
noteMy: "Catatan (Saya)"
notification: "Notifikasi"
+ antenna: "Penerimaan Antenna"
+ channel: "Notifikasi Kanal"
reaction: "Ketika memilih reaksi"
_soundSettings:
driveFile: "Menggunakan berkas audio dalam Drive"
@@ -1972,6 +1859,7 @@ _2fa:
registerTOTP: "Daftarkan aplikasi autentikator"
step1: "Pertama, pasang aplikasi autentikasi (seperti {a} atau {b}) di perangkat kamu."
step2: "Lalu, pindai kode QR yang ada di layar."
+ step2Click: "Mengeklik kode QR ini akan membolehkanmu untuk mendaftarkan 2FA ke security-key atau aplikasi autentikator ponsel."
step2Uri: "Masukkan URI berikut jika kamu menggunakan program desktop"
step3Title: "Masukkan kode autentikasi"
step3: "Masukkan token yang telah disediakan oleh aplikasimu untuk menyelesaikan pemasangan."
@@ -1995,7 +1883,6 @@ _2fa:
backupCodesDescription: "Kamu dapat menggunakan kode ini untuk mendapatkan akses ke akun kamu apabila berada dalam situasi tidak dapat menggunakan aplikasi autentikasi 2-faktor yang kamu miliki. Setiap kode hanya dapat digunakan satu kali. Mohon simpan kode ini di tempat yang aman."
backupCodeUsedWarning: "Kode cadangan telah digunakan. Mohon mengatur ulang autentikasi 2-faktor secepatnya apabila kamu sudah tidak dapat menggunakannya lagi."
backupCodesExhaustedWarning: "Semua kode cadangan telah digunakan. Apabila kamu kehilangan akses pada aplikasi autentikasi 2-faktor milikmu, kamu tidak dapat mengakses akun ini lagi. Mohon atur ulang autentikasi 2-faktor kamu."
- moreDetailedGuideHere: "Berikut panduan detilnya"
_permissions:
"read:account": "Lihat informasi akun"
"write:account": "Sunting informasi akun"
@@ -2046,6 +1933,7 @@ _permissions:
"read:admin:server-info": "Lihat informasi peladen"
"read:admin:show-moderation-log": "Lihat log moderasi"
"read:admin:show-user": "Lihat informasi pengguna privat"
+ "read:admin:show-users": "Lihat informasi pengguna privat"
"write:admin:suspend-user": "Tangguhkan pengguna"
"write:admin:unset-user-avatar": "Hapus avatar pengguna"
"write:admin:unset-user-banner": "Hapus banner pengguna"
@@ -2256,7 +2144,6 @@ _play:
title: "Judul"
script: "Script"
summary: "Deskripsi"
- visibilityDescription: "Membuat catatan ini privat berarti tidak akan terlihat pada profil kamu, namun siapapun yang memiliki URL dari catatan ini akan dapat mengaksesnya."
_pages:
newPage: "Buat halaman baru"
editPage: "Sunting halaman"
@@ -2301,8 +2188,6 @@ _pages:
section: "Bagian"
image: "Gambar"
button: "Tombol"
- dynamic: "Blok Dinamis"
- dynamicDescription: "Blok ini telah dihapus. Mohon gunakan {play} dari sekarang."
note: "Catatan yang ditanam"
_note:
id: "ID Catatan"
@@ -2332,10 +2217,8 @@ _notification:
sendTestNotification: "Kirim tes notifikasi"
notificationWillBeDisplayedLikeThis: "Notifikasi akan terlihat seperti ini"
reactedBySomeUsers: "{n} orang memberikan reaksi"
- likedBySomeUsers: "{n} pengguna menyukai catatan kamu"
renotedBySomeUsers: "{n} orang telah merenote"
followedBySomeUsers: "{n} orang telah mengikuti"
- flushNotification: "Bersihkan notifikasi"
_types:
all: "Semua"
note: "Catatan baru"
@@ -2350,7 +2233,6 @@ _notification:
followRequestAccepted: "Permintaan mengikuti disetujui"
roleAssigned: "Peran Diberikan"
achievementEarned: "Pencapaian didapatkan"
- login: "Masuk"
app: "Notifikasi dari aplikasi tertaut"
_actions:
followBack: "Ikuti Kembali"
@@ -2398,9 +2280,9 @@ _drivecleaner:
orderByCreatedAtAsc: "Tanggal (Naik)"
_webhookSettings:
createWebhook: "Buat Webhook"
- modifyWebhook: "Sunting Webhook"
name: "Nama"
secret: "Secret"
+ events: "Webhook Events"
active: "Aktif"
_events:
follow: "Ketika mengikuti pengguna"
@@ -2410,11 +2292,6 @@ _webhookSettings:
renote: "Ketika direnote"
reaction: "Ketika menerima reaksi"
mention: "Ketika sedang disebut"
- deleteConfirm: "Apakah kamu yakin ingin menghapus Webhook?"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Surel"
_moderationLogTypes:
createRole: "Peran telah dibuat"
deleteRole: "Peran telah dihapus"
@@ -2439,7 +2316,6 @@ _moderationLogTypes:
resetPassword: "Atur ulang kata sandi"
suspendRemoteInstance: "Instansi luar telah ditangguhkan"
unsuspendRemoteInstance: "Instansi luar batal ditangguhkan"
- updateRemoteInstanceNote: "Catatan moderasi telah diperbaharui untuk peladen luar."
markSensitiveDriveFile: "Berkas ditandai sensitif"
unmarkSensitiveDriveFile: "Berkas batal ditandai sensitif"
resolveAbuseReport: "Laporan terselesaikan"
@@ -2551,35 +2427,4 @@ _reversi:
isLlotheo: "Pemain dengan batu yang sedikit menang (Llotheo)"
loopedMap: "Peta melingkar"
canPutEverywhere: "Keping dapat ditaruh dimana saja"
- timeLimitForEachTurn: "Batas waktu untuk gantian"
- freeMatch: "Pertandingan bebas"
- lookingForPlayer: "Mencari lawan..."
- gameCanceled: "Permainan ini telah dibatalkan."
- shareToTlTheGameWhenStart: "Bagikan permainan ke lini masa ketika dimulai"
- iStartedAGame: "Permainan telah dimulai! #MisskeyReversi"
- opponentHasSettingsChanged: "Lawan telah mengganti pengaturan mereka."
- allowIrregularRules: "Aturan non-reguler (bebas sepenuhnya)"
- disallowIrregularRules: "Tanpa aturan non-reguler"
- showBoardLabels: "Tampilkan penomoran baris dan kolom pada papan"
- useAvatarAsStone: "Ubah batu menjadi avatar pengguna"
-_offlineScreen:
- title: "Luring - tidak dapat terhubung ke peladen"
- header: "Tidak dapat tersambung ke server"
-_urlPreviewSetting:
- title: "Pengaturan pratinjau URL"
- enable: "Aktifkan pratinjau URL"
- timeout: "Waktu timeout pratinjau URL (ms)"
- timeoutDescription: "Apabila ini memakan waktu lama dari nilai yang ditentukan untuk mendapatkan pratinjau, pratinjau tidak akan dibuat."
- maximumContentLength: "Content-Length Maksimum (bytes)"
- maximumContentLengthDescription: "Apabila Content-Length lebih besar dari nilai ini, pratinjau tidak akan dibuat."
- requireContentLength: "Buat pratinjau hanya ketika Content-Length dapat didapatkan"
- requireContentLengthDescription: "Apabila peladen lain tidak memberika Content-Length, pratinjau tidak akan dibuat."
- userAgent: "User-Agent"
- userAgentDescription: "Atur User-Agent yang digunakan untuk mengambil pratinjau. Apabila dibiarkan kosong, User-Agent bawaan akan digunakan."
- summaryProxy: "Titik akhir proksi yang membuat pratinjau"
- summaryProxyDescription: "Bukan untuk Misskey, namun untuk menghasilkan pratinjau menggunakan Summaly Proxy."
- summaryProxyDescription2: "Parameter berikut tertautkan dengan proksi sebagai string kueri. Apabila proksi tidak mendukung tersebut, nilai di dalamnya diabaikan."
-_mediaControls:
- pip: "Gambar dalam Gambar"
- playbackRate: "Kecepatan Pemutaran"
- loop: "Ulangi Pemutaran"
+
diff --git a/locales/index.d.ts b/locales/index.d.ts
index d8eb90f4e5..f816feb108 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -18,14 +18,14 @@ export interface Locale extends ILocale {
*/
"headlineMisskey": string;
/**
- * Welcome! Sharkey is an open source, decentralized microblogging service.
- * Create "notes" to share your thoughts with everyone around you. 📡
- * With "reactions", you can also quickly express your feelings about everyone's notes. 👍
- * Let's explore a new world! 🚀
+ * ようこそ!Sharkeyは、オープンソースの分散型マイクロブログサービスです。
+ * 「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡
+ * 「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍
+ * 新しい世界を探検しよう🚀
*/
"introMisskey": string;
/**
- * {name} is one of the services powered by the open source platform Sharkey which is based on Misskey (referred to as a "Misskey instance").
+ * {name}は、オープンソースのプラットフォームSharkey のサーバーのひとつです。
*/
"poweredByMisskeyDescription": ParameterizedString<"name">;
/**
@@ -48,20 +48,6 @@ export interface Locale extends ILocale {
* パスワード
*/
"password": string;
- /**
- * 初期設定開始用パスワード
- */
- "initialPasswordForSetup": string;
- /**
- * 初期設定開始用のパスワードが違います。
- */
- "initialPasswordIsIncorrect": string;
- /**
- * Misskeyを自分でインストールした場合は、設定ファイルに入力したパスワードを使用してください。
- * Misskeyのホスティングサービスなどを使用している場合は、提供されたパスワードを使用してください。
- * パスワードを設定していない場合は、空欄にしたまま続行してください。
- */
- "initialPasswordForSetupDescription": string;
/**
* パスワードを忘れた
*/
@@ -91,7 +77,7 @@ export interface Locale extends ILocale {
*/
"enterUsername": string;
/**
- * Boosted by {user}
+ * {user}がブースト
*/
"renotedBy": ParameterizedString<"user">;
/**
@@ -166,6 +152,10 @@ export interface Locale extends ILocale {
* ユーザー
*/
"users": string;
+ /**
+ * 承認
+ */
+ "approvals": string;
/**
* ユーザーを追加
*/
@@ -211,7 +201,7 @@ export interface Locale extends ILocale {
*/
"copyLink": string;
/**
- * Copy boost link
+ * ブーストのリンクをコピー
*/
"copyLinkRenote": string;
/**
@@ -223,7 +213,7 @@ export interface Locale extends ILocale {
*/
"deleteAndEdit": string;
/**
- * Are you sure you want to redraft this note? This means you will lose all reactions, boosts, and replies to it.
+ * このノートを削除してもう一度編集しますか?このノートへのリアクション、ブースト、返信も全て削除されます。
*/
"deleteAndEditConfirm": string;
/**
@@ -246,6 +236,10 @@ export interface Locale extends ILocale {
* ユーザー名をコピー
*/
"copyUsername": string;
+ /**
+ * リモートプロフィールを開く
+ */
+ "openRemoteProfile": string;
/**
* ユーザーIDをコピー
*/
@@ -270,10 +264,6 @@ export interface Locale extends ILocale {
* ユーザーを検索
*/
"searchUser": string;
- /**
- * ユーザーのノートを検索
- */
- "searchThisUsersNotes": string;
/**
* 返信
*/
@@ -455,27 +445,31 @@ export interface Locale extends ILocale {
*/
"enterEmoji": string;
/**
- * Boost
+ * ブースト
*/
"renote": string;
/**
- * Remove boost
+ * ブースト解除
*/
"unrenote": string;
/**
- * Boosted.
+ * ブーストしました。
*/
"renoted": string;
/**
- * Boosted to {name}
+ * 引用。
*/
- "renotedToX": ParameterizedString<"name">;
+ "quoted": string;
/**
- * This post can't be boosted.
+ * ブースト解除しました。
+ */
+ "rmboost": string;
+ /**
+ * この投稿はブーストできません。
*/
"cantRenote": string;
/**
- * A boost can't be boosted.
+ * ブーストをブーストすることはできません。
*/
"cantReRenote": string;
/**
@@ -483,21 +477,13 @@ export interface Locale extends ILocale {
*/
"quote": string;
/**
- * Channel-only Boost
+ * チャンネル内ブースト
*/
"inChannelRenote": string;
/**
* チャンネル内引用
*/
"inChannelQuote": string;
- /**
- * チャンネルにリノート
- */
- "renoteToChannel": string;
- /**
- * 他のチャンネルにリノート
- */
- "renoteToOtherChannel": string;
/**
* ピン留めされたノート
*/
@@ -591,11 +577,11 @@ export interface Locale extends ILocale {
*/
"unmute": string;
/**
- * Mute Boosts
+ * ブーストをミュート
*/
"renoteMute": string;
/**
- * Unmute Boosts
+ * ブーストのミュートを解除
*/
"renoteUnmute": string;
/**
@@ -606,6 +592,10 @@ export interface Locale extends ILocale {
* ブロック解除
*/
"unblock": string;
+ /**
+ * ユーザーのすべてのメディアをNSFWとしてマークする
+ */
+ "markAsNSFW": string;
/**
* 凍結
*/
@@ -622,10 +612,22 @@ export interface Locale extends ILocale {
* ブロック解除しますか?
*/
"unblockConfirm": string;
+ /**
+ * このアカウントからのすべてのメディアをNSFWとしてマークしてもよろしいですか?
+ */
+ "nsfwConfirm": string;
+ /**
+ * このアカウントのすべてのメディアをNSFWとしてマーク解除してもよろしいですか?
+ */
+ "unNsfwConfirm": string;
/**
* 凍結しますか?
*/
"suspendConfirm": string;
+ /**
+ * このアカウントを承認してもよろしいですか?
+ */
+ "approveConfirm": string;
/**
* 解凍しますか?
*/
@@ -650,10 +652,6 @@ export interface Locale extends ILocale {
* アンテナを編集
*/
"editAntenna": string;
- /**
- * アンテナを作成
- */
- "createAntenna": string;
/**
* ウィジェットを選択
*/
@@ -719,7 +717,7 @@ export interface Locale extends ILocale {
*/
"flagAsBot": string;
/**
- * Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Sharkey's internal systems to treat this account as a bot.
+ * このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Sharkeyのシステム上での扱いがBotに合ったものになります。
*/
"flagAsBotDescription": string;
/**
@@ -730,6 +728,14 @@ export interface Locale extends ILocale {
* にゃにゃにゃ??
*/
"flagAsCatDescription": string;
+ /**
+ * 猫語で話す
+ */
+ "flagSpeakAsCat": string;
+ /**
+ * 有効にすると、あなたの投稿の 「な」を「にゃ」にします。
+ */
+ "flagSpeakAsCatDescription": string;
/**
* タイムラインにノートへの返信を表示する
*/
@@ -758,22 +764,6 @@ export interface Locale extends ILocale {
* リモートで表示
*/
"showOnRemote": string;
- /**
- * Continue on remote instance
- */
- "continueOnRemote": string;
- /**
- * Choose a instance from Misskey Hub
- */
- "chooseServerOnMisskeyHub": string;
- /**
- * サーバーのドメインを直接指定
- */
- "specifyServerHost": string;
- /**
- * ドメインを入力してください
- */
- "inputHostName": string;
/**
* 全般
*/
@@ -814,10 +804,6 @@ export interface Locale extends ILocale {
* ホスト
*/
"host": string;
- /**
- * 自分を選択
- */
- "selectSelf": string;
/**
* ユーザーを選択
*/
@@ -871,17 +857,13 @@ export interface Locale extends ILocale {
*/
"stopActivityDelivery": string;
/**
- * このサーバーをブロック
+ * このインスタンスをブロック
*/
"blockThisInstance": string;
/**
- * サーバーをサイレンス
+ * インスタンスをサイレンス
*/
"silenceThisInstance": string;
- /**
- * Silence media from this instance
- */
- "mediaSilenceThisInstance": string;
/**
* 操作
*/
@@ -963,25 +945,9 @@ export interface Locale extends ILocale {
*/
"silencedInstances": string;
/**
- * List the host names of the instances that you want to silence, separated by a new line. All accounts belonging to the listed instances will be treated as silenced, and can only make follow requests, and cannot mention local accounts if not followed. This will not affect the blocked instances.
+ * サイレンスしたいインスタンスのホストを改行で区切って設定します。サイレンスされたインスタンスに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。
*/
"silencedInstancesDescription": string;
- /**
- * Media-silenced instances
- */
- "mediaSilencedInstances": string;
- /**
- * List the host names of the instances that you want to media-silence, separated by a new line. All accounts belonging to the listed instances will be treated as sensitive, and can't use custom emojis. This will not affect the blocked instances.
- */
- "mediaSilencedInstancesDescription": string;
- /**
- * 連合を許可するサーバー
- */
- "federationAllowedHosts": string;
- /**
- * 連合を許可するサーバーのホストを改行で区切って設定します。
- */
- "federationAllowedHostsDescription": string;
/**
* ミュートとブロック
*/
@@ -1011,7 +977,7 @@ export interface Locale extends ILocale {
*/
"pinLimitExceeded": string;
/**
- * Installation of Sharkey has been finished! Please create an admin user.
+ * Sharkeyのインストールが完了しました!管理者アカウントを作成しましょう。
*/
"intro": string;
/**
@@ -1342,10 +1308,6 @@ export interface Locale extends ILocale {
* フォルダーを選択
*/
"selectFolders": string;
- /**
- * No file selected
- */
- "fileNotSelected": string;
/**
* ファイル名を変更
*/
@@ -1374,10 +1336,6 @@ export interface Locale extends ILocale {
* ファイルを追加
*/
"addFile": string;
- /**
- * ファイルを表示
- */
- "showFile": string;
/**
* ドライブは空です
*/
@@ -1426,6 +1384,10 @@ export interface Locale extends ILocale {
* バナー
*/
"banner": string;
+ /**
+ * 背景
+ */
+ "background": string;
/**
* センシティブなメディアの表示
*/
@@ -1698,10 +1660,6 @@ export interface Locale extends ILocale {
* 除外キーワード
*/
"antennaExcludeKeywords": string;
- /**
- * Botアカウントを除外
- */
- "antennaExcludeBots": string;
/**
* スペースで区切るとAND指定になり、改行で区切るとOR指定になります
*/
@@ -1719,7 +1677,7 @@ export interface Locale extends ILocale {
*/
"enableServiceworker": string;
/**
- * List one username per line. Use "*@instance.com" to specify all users of an instance
+ * ユーザー名を改行で区切って指定します
*/
"antennaUsersDescription": string;
/**
@@ -1795,7 +1753,7 @@ export interface Locale extends ILocale {
*/
"about": string;
/**
- * About Sharkey
+ * Sharkeyについて
*/
"aboutMisskey": string;
/**
@@ -1834,10 +1792,6 @@ export interface Locale extends ILocale {
* モデレーションノート
*/
"moderationNote": string;
- /**
- * モデレーター間でだけ共有されるメモを記入することができます。
- */
- "moderationNoteDescription": string;
/**
* モデレーションノートを追加する
*/
@@ -1966,6 +1920,14 @@ export interface Locale extends ILocale {
* {user}のノート
*/
"noteOf": ParameterizedString<"user">;
+ /**
+ * すべての返信の内容を表示する
+ */
+ "expandAllCws": string;
+ /**
+ * すべての返信の内容を隠す
+ */
+ "collapseAllCws": string;
/**
* 引用付き
*/
@@ -1974,10 +1936,6 @@ export interface Locale extends ILocale {
* 引用として添付しますか?
*/
"quoteQuestion": string;
- /**
- * The text in clipboard is long. Would you like to attach it as a text file?
- */
- "attachAsFileQuestion": string;
/**
* まだチャットはありません
*/
@@ -1991,13 +1949,9 @@ export interface Locale extends ILocale {
*/
"onlyOneFileCanBeAttached": string;
/**
- * 続行する前に、登録またはログインが必要です
+ * 続行する前に、サインアップまたはサインインが必要です
*/
"signinRequired": string;
- /**
- * To continue, you need to go to your instance to perform this action or sign up / log in to the instance you are trying to interact with.
- */
- "signinOrContinueOnRemote": string;
/**
* 招待
*/
@@ -2083,29 +2037,13 @@ export interface Locale extends ILocale {
*/
"native": string;
/**
- * メニューのスタイル
+ * メニューをドロワーで表示しない
*/
- "menuStyle": string;
- /**
- * スタイル
- */
- "style": string;
- /**
- * ドロワー
- */
- "drawer": string;
- /**
- * ポップアップ
- */
- "popup": string;
+ "disableDrawer": string;
/**
* ノートのアクションをホバー時のみ表示する
*/
"showNoteActionsOnlyHover": string;
- /**
- * Show the number of reactions in notes
- */
- "showReactionsCount": string;
/**
* 履歴はありません
*/
@@ -2154,6 +2092,10 @@ export interface Locale extends ILocale {
* フォントサイズ
*/
"fontSize": string;
+ /**
+ * コーナーの丸み
+ */
+ "cornerRadius": string;
/**
* 画像が1枚のみのメディアリストの高さ
*/
@@ -2298,6 +2240,14 @@ export interface Locale extends ILocale {
* s3ForcePathStyleを有効にすると、バケット名をURLのホスト名ではなくパスの一部として指定することを強制します。セルフホストされたMinioなどの使用時に有効にする必要がある場合があります。
*/
"s3ForcePathStyleDesc": string;
+ /**
+ * DeepLX-JS を使用する (認証キーなし)
+ */
+ "deeplFreeMode": string;
+ /**
+ * ヘルプが必要ですか? DeepLX-JSのセットアップ方法については、ドキュメントを参照してください。
+ */
+ "deeplFreeModeDescription": string;
/**
* サーバーログ
*/
@@ -2359,7 +2309,7 @@ export interface Locale extends ILocale {
*/
"notUseSound": string;
/**
- * Output sounds only if Sharkey is active.
+ * Misskeyがアクティブな時のみサウンドを出力する
*/
"useSoundOnlyWhenActive": string;
/**
@@ -2423,17 +2373,9 @@ export interface Locale extends ILocale {
*/
"scratchpad": string;
/**
- * The Scratchpad provides an environment for AiScript experiments. You can write, execute, and check the results of it interacting with Sharkey in it.
+ * スクラッチパッドは、AiScriptの実験環境を提供します。Sharkeyと対話するコードの記述、実行、結果の確認ができます。
*/
"scratchpadDescription": string;
- /**
- * UIインスペクター
- */
- "uiInspector": string;
- /**
- * メモリ上に存在しているUIコンポーネントのインスタンスの一覧を見ることができます。UIコンポーネントはUi:C:系関数により生成されます。
- */
- "uiInspectorDescription": string;
/**
* 出力
*/
@@ -2871,7 +2813,7 @@ export interface Locale extends ILocale {
*/
"reportAbuse": string;
/**
- * Report boost
+ * ブーストを通報
*/
"reportAbuseRenote": string;
/**
@@ -2879,7 +2821,7 @@ export interface Locale extends ILocale {
*/
"reportAbuseOf": ParameterizedString<"name">;
/**
- * 通報理由の詳細を記入してください。対象のノートやページなどがある場合はそのURLも記入してください。
+ * 通報理由の詳細を記入してください。対象のノートがある場合はそのURLも記入してください。
*/
"fillAbuseReportDescription": string;
/**
@@ -2898,10 +2840,22 @@ export interface Locale extends ILocale {
* 通報元
*/
"reporterOrigin": string;
+ /**
+ * リモートサーバーに通報を転送する
+ */
+ "forwardReport": string;
+ /**
+ * リモートサーバーからはあなたの情報は見れず、匿名のシステムアカウントとして表示されます。
+ */
+ "forwardReportIsAnonymous": string;
/**
* 送信
*/
"send": string;
+ /**
+ * 対応済みにする
+ */
+ "abuseMarkAsResolved": string;
/**
* 新しいタブで開く
*/
@@ -2975,7 +2929,7 @@ export interface Locale extends ILocale {
*/
"private": string;
/**
- * Misskeyは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。
+ * Sharkeyは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。
*/
"i18nInfo": ParameterizedString<"link">;
/**
@@ -2995,7 +2949,7 @@ export interface Locale extends ILocale {
*/
"repliesCount": string;
/**
- * Number of boosts sent
+ * ブーストした数
*/
"renotesCount": string;
/**
@@ -3003,7 +2957,7 @@ export interface Locale extends ILocale {
*/
"repliedCount": string;
/**
- * Number of boosts received
+ * ブーストされた数
*/
"renotedCount": string;
/**
@@ -3134,6 +3088,14 @@ export interface Locale extends ILocale {
* オフにすると、「みつける」にアカウントが載らなくなります。
*/
"makeExplorableDescription": string;
+ /**
+ * 公開ノートをインデックス不可にする
+ */
+ "makeIndexable": string;
+ /**
+ * ノート検索があなたの公開ノートをインデックス化しないようにします。
+ */
+ "makeIndexableDescription": string;
/**
* タイムラインのノートを離して表示
*/
@@ -3159,7 +3121,7 @@ export interface Locale extends ILocale {
*/
"narrow": string;
/**
- * 設定はページリロード後に反映されます。
+ * 設定はページリロード後に反映されます。今すぐリロードしますか?
*/
"reloadToApplySetting": string;
/**
@@ -3191,8 +3153,7 @@ export interface Locale extends ILocale {
*/
"sendErrorReports": string;
/**
- * When turned on, detailed error information will be shared with Sharkey when a problem occurs, helping to improve the quality of Sharkey.
- * This will include information such the version of your OS, what browser you're using, your activity in Sharkey, etc.
+ * オンにすると、問題が発生したときにエラーの詳細情報がSharkeyに共有され、ソフトウェアの品質向上に役立てることができます。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。
*/
"sendErrorReportsDescription": string;
/**
@@ -3447,10 +3408,6 @@ export interface Locale extends ILocale {
* 管理者情報が設定されていません。
*/
"noMaintainerInformationWarning": string;
- /**
- * Contact URL is not set.
- */
- "noInquiryUrlWarning": string;
/**
* Botプロテクションが設定されていません。
*/
@@ -3572,7 +3529,7 @@ export interface Locale extends ILocale {
*/
"learnMore": string;
/**
- * Sharkey has been updated!
+ * Sharkeyが更新されました!
*/
"misskeyUpdated": string;
/**
@@ -3592,7 +3549,7 @@ export interface Locale extends ILocale {
*/
"accountDeletionInProgress": string;
/**
- * A name that identifies your account from others on this server. You can use the alphabet (a~z, A~Z), digits (0~9) or underscores (_). Usernames cannot be changed later.
+ * サーバー上であなたのアカウントを一意に識別するための名前。アルファベット(a~z, A~Z)、数字(0~9)、およびアンダーバー(_)が使用できます。ユーザー名は後から変更することは出来ません。
*/
"usernameInfo": string;
/**
@@ -3651,6 +3608,10 @@ export interface Locale extends ILocale {
* アカウント登録にメールアドレスを必須にする
*/
"emailRequiredForSignup": string;
+ /**
+ * 新規ユーザーの承認が必要
+ */
+ "approvalRequiredForSignup": string;
/**
* 未読
*/
@@ -3707,14 +3668,15 @@ export interface Locale extends ILocale {
* パスワードが間違っています。
*/
"incorrectPassword": string;
- /**
- * ワンタイムパスワードが間違っているか、期限切れになっています。
- */
- "incorrectTotp": string;
/**
* 「{choice}」に投票しますか?
*/
"voteConfirm": ParameterizedString<"choice">;
+ /**
+ * 「{choice}」に投票しますか?
+ * 確認後、選択肢を増やすことができます。
+ */
+ "voteConfirmMulti": ParameterizedString<"choice">;
/**
* 隠す
*/
@@ -3855,6 +3817,10 @@ export interface Locale extends ILocale {
* 未対応の通報があります。
*/
"thereIsUnresolvedAbuseReportWarning": string;
+ /**
+ * 承認待ちのユーザーがいる。
+ */
+ "pendingUserApprovals": string;
/**
* 推奨
*/
@@ -3887,6 +3853,26 @@ export interface Locale extends ILocale {
* アカウント削除
*/
"deleteAccount": string;
+ /**
+ * 承認する
+ */
+ "approveAccount": string;
+ /**
+ * 拒否と削除
+ */
+ "denyAccount": string;
+ /**
+ * 承認済み
+ */
+ "approved": string;
+ /**
+ * 承認されていない
+ */
+ "notApproved": string;
+ /**
+ * 承認状況
+ */
+ "approvalStatus": string;
/**
* ドキュメント
*/
@@ -3899,6 +3885,30 @@ export interface Locale extends ILocale {
* 多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。
*/
"numberOfPageCacheDescription": string;
+ /**
+ * スレッド内の返信数
+ */
+ "numberOfReplies": string;
+ /**
+ * この数値を大きくすると、より多くの返信が表示されます。この値を大きくしすぎると、返信が窮屈になり、読めなくなることがあります。
+ */
+ "numberOfRepliesDescription": string;
+ /**
+ * ブースト設定
+ */
+ "boostSettings": string;
+ /**
+ * 可視性セレクタを表示
+ */
+ "showVisibilitySelectorOnBoost": string;
+ /**
+ * 無効の場合、以下で定義されるデフォルトの可視性が使用され、セレクタは表示されません。
+ */
+ "showVisibilitySelectorOnBoostDescription": string;
+ /**
+ * デフォルトのブースト可視性の設定
+ */
+ "visibilityOnBoost": string;
/**
* ログアウトしますか?
*/
@@ -4075,6 +4085,10 @@ export interface Locale extends ILocale {
* いいねを解除
*/
"unlike": string;
+ /**
+ * 絵文字のようなデフォルト
+ */
+ "defaultLike": string;
/**
* いいね数
*/
@@ -4092,13 +4106,17 @@ export interface Locale extends ILocale {
*/
"remindMeLater": string;
/**
- * Have you taken a liking to Sharkey?
+ * Sharkeyを気に入っていただけましたか?
*/
"didYouLikeMisskey": string;
/**
- * {host} uses the free software, Sharkey. We would highly appreciate your donations so development of Sharkey can continue!
+ * Sharkeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!
*/
"pleaseDonate": ParameterizedString<"host">;
+ /**
+ * インスタンス管理者への寄付によって{host}を直接サポートすることもできます。
+ */
+ "pleaseDonateInstance": ParameterizedString<"host">;
/**
* 対応するソースコードは{anchor}から利用可能です。
*/
@@ -4208,13 +4226,29 @@ export interface Locale extends ILocale {
*/
"thisPostMayBeAnnoyingIgnore": string;
/**
- * Collapse boosts you've already seen
+ * やめる
+ */
+ "thisPostIsMissingAltTextCancel": string;
+ /**
+ * このまま投稿
+ */
+ "thisPostIsMissingAltTextIgnore": string;
+ /**
+ * この投稿に添付されたファイルの 1 つに代替テキストがありません。すべての添付ファイルに代替テキストが含まれていることを確認してください。
+ */
+ "thisPostIsMissingAltText": string;
+ /**
+ * 見たことのあるブーストを省略して表示
*/
"collapseRenotes": string;
/**
- * Collapse boosts that you have boosted or reacted to
+ * ファイルを折りたたむ
*/
- "collapseRenotesDescription": string;
+ "collapseFiles": string;
+ /**
+ * 返信に会話を読み込む
+ */
+ "autoloadConversation": string;
/**
* サーバー内部エラー
*/
@@ -4255,6 +4289,10 @@ export interface Locale extends ILocale {
* 現在このサーバーは招待制です。招待コードをお持ちの方のみ登録できます。
*/
"invitationRequiredToRegister": string;
+ /**
+ * このインスタンスは、登録理由を指定したユーザーのみを受け入れています。
+ */
+ "approvalRequiredToRegister": string;
/**
* このサーバーではメール配信はサポートされていません
*/
@@ -4367,10 +4405,6 @@ export interface Locale extends ILocale {
* リモートサーバーのチャートを生成
*/
"enableChartsForFederatedInstances": string;
- /**
- * リモートサーバーの情報を取得
- */
- "enableStatsForFederatedInstances": string;
/**
* ノートのアクションにクリップを追加
*/
@@ -4380,7 +4414,7 @@ export interface Locale extends ILocale {
*/
"reactionsDisplaySize": string;
/**
- * Limits the maximum width of reactions and display them in reduced size.
+ * リアクションの最大横幅を制限し、縮小して表示する
*/
"limitWidthOfReaction": string;
/**
@@ -4427,6 +4461,10 @@ export interface Locale extends ILocale {
* 常に広告を表示する
*/
"forceShowAds": string;
+ /**
+ * 猫友達 :3
+ */
+ "oneko": string;
/**
* メモを追加
*/
@@ -4440,7 +4478,7 @@ export interface Locale extends ILocale {
*/
"reactionsList": string;
/**
- * Boosts
+ * ブースト一覧
*/
"renotesList": string;
/**
@@ -4511,14 +4549,6 @@ export interface Locale extends ILocale {
* アーカイブ
*/
"archive": string;
- /**
- * アーカイブ済み
- */
- "archived": string;
- /**
- * アーカイブ解除
- */
- "unarchive": string;
/**
* {name}をアーカイブしますか?
*/
@@ -4559,18 +4589,6 @@ export interface Locale extends ILocale {
* ユーザー指定
*/
"specifyUser": string;
- /**
- * Are you sure that you want to look this up?
- */
- "lookupConfirm": string;
- /**
- * Are you sure you want to open this hashtags page?
- */
- "openTagPageConfirm": string;
- /**
- * Specify a host
- */
- "specifyHost": string;
/**
* プレビューできません
*/
@@ -4604,7 +4622,7 @@ export interface Locale extends ILocale {
*/
"later": string;
/**
- * To Sharkey
+ * Sharkeyへ
*/
"goToMisskey": string;
/**
@@ -4623,6 +4641,22 @@ export interface Locale extends ILocale {
* サーバーのマシン情報を公開する
*/
"enableServerMachineStats": string;
+ /**
+ * 実績を有効にする
+ */
+ "enableAchievements": string;
+ /**
+ * オフにすると実績システムは無効になります。
+ */
+ "turnOffAchievements": string;
+ /**
+ * botのハッシュタグ追加を許可する
+ */
+ "enableBotTrending": string;
+ /**
+ * オフにするとボットがハッシュタグを入力しなくなります。
+ */
+ "turnOffBotTrending": string;
/**
* ユーザーごとのIdenticon生成を有効にする
*/
@@ -4740,11 +4774,11 @@ export interface Locale extends ILocale {
*/
"useSecurityKey": string;
/**
- * Replies
+ * 返信
*/
"replies": string;
/**
- * Boosts
+ * ブースト
*/
"renotes": string;
/**
@@ -4763,6 +4797,14 @@ export interface Locale extends ILocale {
* デバイスの画面を常にオンにする
*/
"keepScreenOn": string;
+ /**
+ * クリックしてノートを開く
+ */
+ "clickToOpen": string;
+ /**
+ * ボットをタイムラインに表示
+ */
+ "showBots": string;
/**
* このリンク先の所有者であることが確認されました
*/
@@ -4788,7 +4830,7 @@ export interface Locale extends ILocale {
*/
"dateAndTime": string;
/**
- * Show boosts
+ * ブーストを表示
*/
"showRenotes": string;
/**
@@ -4803,10 +4845,6 @@ export interface Locale extends ILocale {
* 相互フォロー
*/
"mutualFollow": string;
- /**
- * フォロー中またはフォロワー
- */
- "followingOrFollower": string;
/**
* ファイル付きのみ
*/
@@ -4844,7 +4882,7 @@ export interface Locale extends ILocale {
*/
"sourceCode": string;
/**
- * The source code is not yet available. Please contact your administrator to fix this problem.
+ * ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。
*/
"sourceCodeIsNotYetProvided": string;
/**
@@ -4852,7 +4890,7 @@ export interface Locale extends ILocale {
*/
"repositoryUrl": string;
/**
- * If there is a repository where the source code is publicly available, enter its URL. If you are using Sharkey as-is (without any changes to the source code), enter https://activitypub.software/TransFem-org/Sharkey/.
+ * ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Misskeyを現状のまま(ソースコードにいかなる変更も加えずに)使用している場合は https://github.com/misskey-dev/misskey と記入します。
*/
"repositoryUrlDescription": string;
/**
@@ -4891,6 +4929,14 @@ export interface Locale extends ILocale {
* 利用規約・プライバシーポリシー
*/
"tosAndPrivacyPolicy": string;
+ /**
+ * 寄付する
+ */
+ "donation": string;
+ /**
+ * 寄付URL
+ */
+ "donationUrl": string;
/**
* アイコンデコレーション
*/
@@ -4968,7 +5014,7 @@ export interface Locale extends ILocale {
*/
"overwriteContentConfirm": string;
/**
- * Seasonal screen effects
+ * 季節に応じた画面の演出
*/
"seasonalScreenEffect": string;
/**
@@ -5007,14 +5053,6 @@ export interface Locale extends ILocale {
* リプレイ中
*/
"replaying": string;
- /**
- * リプレイを終了
- */
- "endReplay": string;
- /**
- * リプレイデータをコピー
- */
- "copyReplayData": string;
/**
* ランキング
*/
@@ -5043,252 +5081,11 @@ export interface Locale extends ILocale {
* スワイプしてタブを切り替える
*/
"enableHorizontalSwipe": string;
- /**
- * 読み込み中
- */
- "loading": string;
- /**
- * やめる
- */
- "surrender": string;
- /**
- * リトライ
- */
- "gameRetry": string;
- /**
- * 使用しない場合は空欄にしてください
- */
- "notUsePleaseLeaveBlank": string;
- /**
- * ワンタイムパスワードを使う
- */
- "useTotp": string;
- /**
- * バックアップコードを使う
- */
- "useBackupCode": string;
- /**
- * アプリを起動
- */
- "launchApp": string;
- /**
- * 動画・音声の再生にブラウザのUIを使用する
- */
- "useNativeUIForVideoAudioPlayer": string;
- /**
- * オリジナルのファイル名を保持
- */
- "keepOriginalFilename": string;
- /**
- * この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。
- */
- "keepOriginalFilenameDescription": string;
- /**
- * No description
- */
- "noDescription": string;
- /**
- * フォローの際常に確認する
- */
- "alwaysConfirmFollow": string;
- /**
- * お問い合わせ
- */
- "inquiry": string;
- /**
- * もう一度お試しください。
- */
- "tryAgain": string;
- /**
- * センシティブなメディアを表示するとき確認する
- */
- "confirmWhenRevealingSensitiveMedia": string;
- /**
- * This media might be sensitive. Are you sure you want to reveal it?
- */
- "sensitiveMediaRevealConfirm": string;
- /**
- * 作成したリスト
- */
- "createdLists": string;
- /**
- * 作成したアンテナ
- */
- "createdAntennas": string;
- /**
- * {x}から
- */
- "fromX": ParameterizedString<"x">;
- /**
- * 埋め込みコードを生成
- */
- "genEmbedCode": string;
- /**
- * このユーザーのノート一覧
- */
- "noteOfThisUser": string;
- /**
- * これ以上このクリップにノートを追加できません。
- */
- "clipNoteLimitExceeded": string;
- /**
- * パフォーマンス
- */
- "performance": string;
- /**
- * 変更あり
- */
- "modified": string;
- /**
- * 破棄
- */
- "discard": string;
- /**
- * {n}件の変更があります
- */
- "thereAreNChanges": ParameterizedString<"n">;
- /**
- * パスキーでログイン
- */
- "signinWithPasskey": string;
- /**
- * 登録されていないパスキーです。
- */
- "unknownWebAuthnKey": string;
- /**
- * パスキーの検証に失敗しました。
- */
- "passkeyVerificationFailed": string;
- /**
- * パスキーの検証に成功しましたが、パスワードレスログインが無効になっています。
- */
- "passkeyVerificationSucceededButPasswordlessLoginDisabled": string;
- /**
- * フォロワーへのメッセージ
- */
- "messageToFollower": string;
- /**
- * 対象
- */
- "target": string;
- /**
- * CAPTCHAのテストを目的とした機能です。本番環境で使用しないでください。
- */
- "testCaptchaWarning": string;
- /**
- * 禁止ワード(ユーザーの名前)
- */
- "prohibitedWordsForNameOfUser": string;
- /**
- * このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。
- */
- "prohibitedWordsForNameOfUserDescription": string;
- /**
- * 変更しようとした名前に禁止された文字列が含まれています
- */
- "yourNameContainsProhibitedWords": string;
- /**
- * 名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。
- */
- "yourNameContainsProhibitedWordsDescription": string;
- "_abuseUserReport": {
- /**
- * 転送
- */
- "forward": string;
- /**
- * 匿名のシステムアカウントとして、リモートサーバーに通報を転送します。
- */
- "forwardDescription": string;
- /**
- * 解決
- */
- "resolve": string;
- /**
- * 是認
- */
- "accept": string;
- /**
- * 否認
- */
- "reject": string;
- /**
- * 内容が正当である通報に対応した場合は「是認」を選択し、肯定的にケースが解決されたことをマークします。
- * 内容が正当でない通報の場合は「否認」を選択し、否定的にケースが解決されたことをマークします。
- */
- "resolveTutorial": string;
- };
- "_delivery": {
- /**
- * 配信状態
- */
- "status": string;
- /**
- * Suspend delivery
- */
- "stop": string;
- /**
- * Resume delivery
- */
- "resume": string;
- "_type": {
- /**
- * 配信中
- */
- "none": string;
- /**
- * 手動停止中
- */
- "manuallySuspended": string;
- /**
- * サーバー削除のため停止中
- */
- "goneSuspended": string;
- /**
- * サーバー応答なしのため停止中
- */
- "autoSuspendedForNotResponding": string;
- };
- };
"_bubbleGame": {
/**
* 遊び方
*/
"howToPlay": string;
- /**
- * ホールド
- */
- "hold": string;
- "_score": {
- /**
- * スコア
- */
- "score": string;
- /**
- * 稼いだ金額
- */
- "scoreYen": string;
- /**
- * ハイスコア
- */
- "highScore": string;
- /**
- * 最大チェーン数
- */
- "maxChain": string;
- /**
- * {yen}円
- */
- "yen": ParameterizedString<"yen">;
- /**
- * {qty}個分
- */
- "estimatedQty": ParameterizedString<"qty">;
- /**
- * おにぎり {onigiriQtyWithUnit}
- */
- "scoreSweets": ParameterizedString<"onigiriQtyWithUnit">;
- };
"_howToPlay": {
/**
* 位置を調整してハコにモノを落とします。
@@ -5353,10 +5150,6 @@ export interface Locale extends ILocale {
* オンにすると、このお知らせは通知されず、既読にする必要もなくなります。
*/
"silenceDescription": string;
- /**
- * New
- */
- "new": string;
};
"_initialAccountSetting": {
/**
@@ -5404,7 +5197,7 @@ export interface Locale extends ILocale {
*/
"haveFun": ParameterizedString<"name">;
/**
- * You can proceed to a tutorial on how to use {name} (Sharkey) or you can exit the setup here and start using it immediately.
+ * このまま{name}(Sharkey)の使い方についてのチュートリアルに進むこともできますが、ここで中断してすぐに使い始めることもできます。
*/
"youCanContinueTutorial": ParameterizedString<"name">;
/**
@@ -5443,7 +5236,7 @@ export interface Locale extends ILocale {
*/
"title": string;
/**
- * Here, you can learn the basics of using Sharkey and its features.
+ * ここでは、Sharkeyの基本的な使い方や機能を確認できます。
*/
"description": string;
};
@@ -5453,7 +5246,7 @@ export interface Locale extends ILocale {
*/
"title": string;
/**
- * Posts on Sharkey are called 'Notes.' Notes are arranged chronologically on the timeline and are updated in real-time.
+ * Sharkeyでの投稿は「ノート」と呼びます。ノートはタイムラインに時系列で並んでいて、リアルタイムで更新されていきます。
*/
"description": string;
/**
@@ -5483,9 +5276,9 @@ export interface Locale extends ILocale {
*/
"description": string;
/**
- * Reactions can be added by clicking the '{reaction}' button on the note. Try reacting to this sample note!
+ * リアクションは、ノートの「+」ボタンをクリックするとつけられます。試しにこのサンプルのノートにリアクションをつけてみてください!
*/
- "letsTryReacting": ParameterizedString<"reaction">;
+ "letsTryReacting": string;
/**
* リアクションをつけると先に進めるようになります。
*/
@@ -5495,9 +5288,9 @@ export interface Locale extends ILocale {
*/
"reactNotification": string;
/**
- * You can undo a reaction by pressing the '{undo}' button.
+ * 「ー」ボタンを押すとリアクションを取り消すことができます。
*/
- "reactDone": ParameterizedString<"undo">;
+ "reactDone": string;
};
"_timeline": {
/**
@@ -5505,7 +5298,7 @@ export interface Locale extends ILocale {
*/
"title": string;
/**
- * Sharkey provides multiple timelines based on usage (some may not be available depending on the server's policies).
+ * Sharkeyには、使い方に応じて複数のタイムラインが用意されています(サーバーによってはいずれかが無効になっていることがあります)。
*/
"description1": string;
/**
@@ -5532,10 +5325,6 @@ export interface Locale extends ILocale {
* その他にも、リストタイムラインやチャンネルタイムラインなどがあります。詳しくは{link}をご覧ください。
*/
"description3": ParameterizedString<"link">;
- /**
- * You can view notes from connected servers picked by your admins.
- */
- "bubble": string;
};
"_postNote": {
/**
@@ -5543,7 +5332,7 @@ export interface Locale extends ILocale {
*/
"title": string;
/**
- * When posting a note on Sharkey, various options are available. The posting form looks like this.
+ * Sharkeyにノートを投稿する際には、様々なオプションの設定が可能です。投稿フォームはこのようになっています。
*/
"description1": string;
"_visibility": {
@@ -5556,11 +5345,11 @@ export interface Locale extends ILocale {
*/
"public": string;
/**
- * Public only on the Home timeline. People visiting your profile, via followers, and through boosts can see it.
+ * ホームタイムラインのみに公開。フォロワー・プロフィールを見に来た人・ブーストから、他のユーザーも見ることができます。
*/
"home": string;
/**
- * Visible to followers only. Only followers can see it and no one else, and it cannot be boosted by others.
+ * フォロワーにのみ公開。本人以外がブーストすることはできず、またフォロワー以外は閲覧できません。
*/
"followers": string;
/**
@@ -5639,11 +5428,11 @@ export interface Locale extends ILocale {
};
"_done": {
/**
- * The tutorial is complete! 🎉
+ * チュートリアルは終了です🎉
*/
"title": string;
/**
- * The functions introduced here are just a small part. For a more detailed understanding of using Sharkey, please refer to {link}.
+ * ここで紹介した機能はほんの一部にすぎません。Sharkeyの使い方をより詳しく知るには、{link}をご覧ください。
*/
"description": ParameterizedString<"link">;
};
@@ -5665,10 +5454,6 @@ export interface Locale extends ILocale {
* グローバルタイムラインでは、接続している他のすべてのサーバーからの投稿を見られます。
*/
"global": string;
- /**
- * In the Bubble timeline, you can see notes from connected servers picked by your admins.
- */
- "bubble": string;
};
"_serverRules": {
/**
@@ -5721,34 +5506,6 @@ export interface Locale extends ILocale {
* 有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。
*/
"fanoutTimelineDbFallbackDescription": string;
- /**
- * 有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。
- */
- "reactionsBufferingDescription": string;
- /**
- * Contact URL
- */
- "inquiryUrl": string;
- /**
- * Specify the URL of a web page that contains a contact form or the instance operators' contact information.
- */
- "inquiryUrlDescription": string;
- /**
- * 一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。
- */
- "thisSettingWillAutomaticallyOffWhenModeratorsInactive": string;
- /**
- * Logo URL
- */
- "sidebarLogoUrl": string;
- /**
- * Specifies the logo to use instead of the regular icon in high definition, dynamic-width scenarios.
- */
- "sidebarLogoDescription": string;
- /**
- * E.g. In the sidebar, to visitors and in the "About" page.
- */
- "sidebarLogoUsageExample": string;
};
"_accountMigration": {
/**
@@ -5782,14 +5539,15 @@ export interface Locale extends ILocale {
*/
"moveCannotBeUndone": string;
/**
- * This will migrate your account to a different one.
- * ・Followers from this account will automatically be migrated to the new account
- * ・This account will unfollow all users it is currently following
- * ・You will be unable to create new notes etc. on this account
+ * 新しいアカウントへ移行します。
+ * ・フォロワーが新しいアカウントを自動でフォローします
+ * ・このアカウントからのフォローは全て解除されます
+ * ・このアカウントではノートの作成などができなくなります
*
- * While migration of followers is automatic, you must manually prepare some steps to migrate the list of users you are following. To do so, carry out a follows export that you will later import on the new account in the settings menu. The same procedure applies to your lists as well as your muted and blocked users.
+ * フォロワーの移行は自動ですが、フォローの移行は手動で行う必要があります。移行前にこのアカウントでフォローエクスポートし、移行後すぐに移行先アカウントでインポートを行なってください。
+ * リスト・ミュート・ブロックについても同様ですので、手動で移行する必要があります。
*
- * (This explanation applies to Sharkey v13.12.0 and later. Other ActivityPub software, such as Mastodon, might function differently.)
+ * (この説明はこのサーバー(Sharkey v13.12.0以降)の仕様です。Mastodonなどの他のActivityPubソフトウェアでは挙動が異なる場合があります。)
*/
"moveAccountDescription": string;
/**
@@ -5837,7 +5595,7 @@ export interface Locale extends ILocale {
*/
"description": string;
/**
- * Have a good time with Sharkey!
+ * 良いSharkeyライフを!
*/
"flavor": string;
};
@@ -6161,7 +5919,7 @@ export interface Locale extends ILocale {
*/
"description": string;
/**
- * Thank you for using Sharkey!
+ * Sharkeyを使ってくれてありがとう!
*/
"flavor": string;
};
@@ -6365,11 +6123,11 @@ export interface Locale extends ILocale {
*/
"title": string;
/**
- * Post "I ❤ #Sharkey"
+ * "I ❤ #Sharkey"を投稿した
*/
"description": string;
/**
- * Sharkey's development team greatly appreciates your support!
+ * Sharkeyを使ってくださりありがとうございます! by 開発チーム
*/
"flavor": string;
};
@@ -6389,17 +6147,17 @@ export interface Locale extends ILocale {
*/
"title": string;
/**
- * Keep Sharkey opened for at least 30 minutes
+ * クライアントを起動してから30分以上経過した
*/
"description": string;
};
"_client60min": {
/**
- * No "Miss" in Sharkey
+ * Sharkeyの見すぎ
*/
"title": string;
/**
- * Keep Sharkey opened for at least 60 minutes
+ * クライアントを起動してから60分以上経過した
*/
"description": string;
};
@@ -6619,7 +6377,7 @@ export interface Locale extends ILocale {
*/
"description": string;
/**
- * Sharkey-Sharkey La-Tu-Ma
+ * Misskey-Misskey La-Tu-Ma
*/
"flavor": string;
};
@@ -6635,7 +6393,7 @@ export interface Locale extends ILocale {
};
"_tutorialCompleted": {
/**
- * Sharkey Elementary Course Diploma
+ * Sharkey初心者講座 修了証
*/
"title": string;
/**
@@ -6815,6 +6573,10 @@ export interface Locale extends ILocale {
* グローバルタイムラインの閲覧
*/
"gtlAvailable": string;
+ /**
+ * バブルタイムラインの閲覧
+ */
+ "btlAvailable": string;
/**
* ローカルタイムラインの閲覧
*/
@@ -6824,9 +6586,9 @@ export interface Locale extends ILocale {
*/
"canPublicNote": string;
/**
- * ノート内の最大メンション数
+ * ノートのインポートが可能
*/
- "mentionMax": string;
+ "canImportNotes": string;
/**
* サーバー招待コードの発行
*/
@@ -6859,10 +6621,6 @@ export interface Locale extends ILocale {
* ファイルにNSFWを常に付与
*/
"alwaysMarkNsfw": string;
- /**
- * Allow users to edit their avatar or banner
- */
- "canUpdateBioMedia": string;
/**
* ノートのピン留めの最大数
*/
@@ -6919,40 +6677,8 @@ export interface Locale extends ILocale {
* アイコンデコレーションの最大取付個数
*/
"avatarDecorationLimit": string;
- /**
- * アンテナのインポートを許可
- */
- "canImportAntennas": string;
- /**
- * ブロックのインポートを許可
- */
- "canImportBlocking": string;
- /**
- * フォローのインポートを許可
- */
- "canImportFollowing": string;
- /**
- * ミュートのインポートを許可
- */
- "canImportMuting": string;
- /**
- * リストのインポートを許可
- */
- "canImportUserLists": string;
- /**
- * Can view the bubble timeline
- */
- "btlAvailable": string;
- /**
- * Can import notes
- */
- "canImportNotes": string;
};
"_condition": {
- /**
- * マニュアルロールにアサイン済み
- */
- "roleAssignedTo": string;
/**
* ローカルユーザー
*/
@@ -6961,26 +6687,6 @@ export interface Locale extends ILocale {
* リモートユーザー
*/
"isRemote": string;
- /**
- * 猫ユーザー
- */
- "isCat": string;
- /**
- * botユーザー
- */
- "isBot": string;
- /**
- * サスペンド済みユーザー
- */
- "isSuspended": string;
- /**
- * Private account
- */
- "isLocked": string;
- /**
- * Account is discoverable
- */
- "isExplorable": string;
/**
* アカウント作成から~以内
*/
@@ -7079,7 +6785,7 @@ export interface Locale extends ILocale {
*/
"smtp": string;
/**
- * This email address is banned
+ * このメールアドレスでは登録できません
*/
"banned": string;
};
@@ -7111,11 +6817,11 @@ export interface Locale extends ILocale {
*/
"emailSent": ParameterizedString<"email">;
/**
- * Your account has been created and is awaiting approval.
+ * アカウントが作成され、承認待ちの状態です。
*/
"approvalPending": string;
/**
- * Please enter a reason as to why you want to join the instance.
+ * インスタンスに参加したい理由を入力してください。
*/
"reasonInfo": string;
};
@@ -7242,10 +6948,6 @@ export interface Locale extends ILocale {
* ソースを表示
*/
"viewSource": string;
- /**
- * ログを表示
- */
- "viewLog": string;
};
"_preferencesBackups": {
/**
@@ -7341,11 +7043,11 @@ export interface Locale extends ILocale {
};
"_aboutMisskey": {
/**
- * Sharkey is open-source software based on Misskey which has been in development by syuilo since 2014.
+ * Sharkeyは、Misskeyをベースにしたオープンソースのソフトウェアです。
*/
"about": string;
/**
- * コントリビューター
+ * 主なコントリビューター
*/
"contributors": string;
/**
@@ -7357,21 +7059,29 @@ export interface Locale extends ILocale {
*/
"source": string;
/**
- * Misskey original
+ * Misskey オリジナル
*/
"original": string;
/**
- * {name} uses a modified version of the original Sharkey.
+ * Sharkey オリジナル
+ */
+ "original_sharkey": string;
+ /**
+ * {name}はオリジナルのSharkeyを改変したバージョンを使用しています。
*/
"thisIsModifiedVersion": ParameterizedString<"name">;
/**
- * Translate Sharkey
+ * Sharkeyを翻訳
*/
"translation": string;
/**
* Misskeyに寄付
*/
"donate": string;
+ /**
+ * Sharkeyに寄付
+ */
+ "donate_sharkey": string;
/**
* 他にも多くの方が支援してくれています。ありがとうございます🥰
*/
@@ -7384,18 +7094,6 @@ export interface Locale extends ILocale {
* プロジェクトメンバー
*/
"projectMembers": string;
- /**
- * Sharkey original
- */
- "original_sharkey": string;
- /**
- * Donate to Sharkey
- */
- "donate_sharkey": string;
- /**
- * Testers
- */
- "testers": string;
};
"_displayOfSensitiveMedia": {
/**
@@ -7439,7 +7137,7 @@ export interface Locale extends ILocale {
*/
"quiet": string;
/**
- * Disable warning
+ * 警告を無効にする
*/
"disabled": string;
};
@@ -7489,7 +7187,7 @@ export interface Locale extends ILocale {
*/
"nameOnly": string;
/**
- * Allow boosts and quote outside the channel
+ * チャンネル外へのブーストと引用ブーストを許可する
*/
"allowRenoteToExternal": string;
};
@@ -7527,7 +7225,7 @@ export interface Locale extends ILocale {
};
"_instanceMute": {
/**
- * This will mute any notes/boosts from the listed instances, including those of users replying to a user from a muted instance.
+ * ミュートしたサーバーのユーザーへの返信を含めて、設定したサーバーの全てのノートとブーストをミュートします。
*/
"instanceMuteDescription": string;
/**
@@ -7789,6 +7487,10 @@ export interface Locale extends ILocale {
* 入力ボックスの縁取り
*/
"inputBorder": string;
+ /**
+ * リスト項目の背景 (ホバー)
+ */
+ "listItemHoverBg": string;
/**
* ドライブフォルダーの背景
*/
@@ -7832,6 +7534,14 @@ export interface Locale extends ILocale {
* 通知
*/
"notification": string;
+ /**
+ * アンテナ受信
+ */
+ "antenna": string;
+ /**
+ * チャンネル通知
+ */
+ "channel": string;
/**
* リアクション選択時
*/
@@ -7859,13 +7569,9 @@ export interface Locale extends ILocale {
*/
"driveFileDurationWarn": string;
/**
- * Long audio may disrupt using Sharkey. Still continue?
+ * 長い音声を使用するとMisskeyの使用に支障をきたす可能性があります。それでも続行しますか?
*/
"driveFileDurationWarnDescription": string;
- /**
- * The audio couldn't be loaded. Please make sure you selected an audio file.
- */
- "driveFileError": string;
};
"_ago": {
/**
@@ -7971,9 +7677,13 @@ export interface Locale extends ILocale {
*/
"step1": ParameterizedString<"a" | "b">;
/**
- * 次に、表示されているQRコードをアプリでスキャンするか、ボタンをクリックして端末上でアプリを開きます。
+ * 次に、表示されているQRコードをアプリでスキャンします。
*/
"step2": string;
+ /**
+ * QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。
+ */
+ "step2Click": string;
/**
* デスクトップアプリを使用する場合は次のURIを入力します
*/
@@ -8066,10 +7776,6 @@ export interface Locale extends ILocale {
* バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。
*/
"backupCodesExhaustedWarning": string;
- /**
- * Click here for a detailed guide
- */
- "moreDetailedGuideHere": string;
};
"_permissions": {
/**
@@ -8268,6 +7974,10 @@ export interface Locale extends ILocale {
* ユーザーのプライベートな情報を見る
*/
"read:admin:show-user": string;
+ /**
+ * ユーザーのプライベートな情報を見る
+ */
+ "read:admin:show-users": string;
/**
* ユーザーを凍結する
*/
@@ -8446,10 +8156,6 @@ export interface Locale extends ILocale {
* アプリケーションにアクセス許可を与えるには、ログインが必要です。
*/
"pleaseLogin": string;
- /**
- * Allowed
- */
- "allowed": string;
};
"_antennaSources": {
/**
@@ -8618,14 +8324,14 @@ export interface Locale extends ILocale {
* クリッカー
*/
"clicker": string;
+ /**
+ * 検索
+ */
+ "search": string;
/**
* 今日誕生日のユーザー
*/
"birthdayFollowings": string;
- /**
- * Search
- */
- "search": string;
};
"_cw": {
/**
@@ -8731,7 +8437,7 @@ export interface Locale extends ILocale {
*/
"remainingSeconds": ParameterizedString<"s">;
/**
- * Multiple choices
+ * 複数の選択肢
*/
"multiple": string;
};
@@ -8862,6 +8568,26 @@ export interface Locale extends ILocale {
* バナー画像を変更
*/
"changeBanner": string;
+ /**
+ * 更新バナー
+ */
+ "updateBanner": string;
+ /**
+ * バナーを削除
+ */
+ "removeBanner": string;
+ /**
+ * 背景を変更する
+ */
+ "changeBackground": string;
+ /**
+ * 背景を更新する
+ */
+ "updateBackground": string;
+ /**
+ * 背景を削除する
+ */
+ "removeBackground": string;
/**
* 内容にURLを設定すると、リンク先のWebサイトに自分のプロフィールへのリンクが含まれている場合に所有者確認済みアイコンを表示させることができます。
*/
@@ -8870,38 +8596,6 @@ export interface Locale extends ILocale {
* 最大{max}つまでデコレーションを付けられます。
*/
"avatarDecorationMax": ParameterizedString<"max">;
- /**
- * フォローされた時のメッセージ
- */
- "followedMessage": string;
- /**
- * フォローされた時に相手に表示する短いメッセージを設定できます。
- */
- "followedMessageDescription": string;
- /**
- * フォローを承認制にしている場合、フォローリクエストを許可した時に表示されます。
- */
- "followedMessageDescriptionForLockedAccount": string;
- /**
- * Update banner
- */
- "updateBanner": string;
- /**
- * Remove banner
- */
- "removeBanner": string;
- /**
- * Change background
- */
- "changeBackground": string;
- /**
- * Update background
- */
- "updateBackground": string;
- /**
- * Remove background
- */
- "removeBackground": string;
};
"_exportOrImport": {
/**
@@ -9062,10 +8756,6 @@ export interface Locale extends ILocale {
* グローバル
*/
"global": string;
- /**
- * Bubble
- */
- "bubble": string;
};
"_play": {
/**
@@ -9124,10 +8814,6 @@ export interface Locale extends ILocale {
* 説明
*/
"summary": string;
- /**
- * 非公開に設定するとプロフィールに表示されなくなりますが、URLを知っている人は引き続きアクセスできます。
- */
- "visibilityDescription": string;
};
"_pages": {
/**
@@ -9262,10 +8948,6 @@ export interface Locale extends ILocale {
* ブロックを追加
*/
"chooseBlock": string;
- /**
- * セクションタイトルを入力
- */
- "enterSectionTitle": string;
/**
* 種類を選択
*/
@@ -9303,14 +8985,6 @@ export interface Locale extends ILocale {
* ボタン
*/
"button": string;
- /**
- * 動的ブロック
- */
- "dynamic": string;
- /**
- * This block type has been removed. Please use {play} from now on.
- */
- "dynamicDescription": ParameterizedString<"play">;
/**
* ノート埋め込み
*/
@@ -9363,7 +9037,7 @@ export interface Locale extends ILocale {
*/
"youGotQuote": ParameterizedString<"name">;
/**
- * Boost from {name}
+ * {name}がBoostしました
*/
"youRenoted": ParameterizedString<"name">;
/**
@@ -9382,6 +9056,10 @@ export interface Locale extends ILocale {
* アンケートの結果が出ました
*/
"pollEnded": string;
+ /**
+ * 投稿が編集されました
+ */
+ "edited": string;
/**
* 新しい投稿
*/
@@ -9423,29 +9101,13 @@ export interface Locale extends ILocale {
*/
"reactedBySomeUsers": ParameterizedString<"n">;
/**
- * {n}人がいいねしました
- */
- "likedBySomeUsers": ParameterizedString<"n">;
- /**
- * Boosted by {n} users
+ * {n}人がブーストしました
*/
"renotedBySomeUsers": ParameterizedString<"n">;
/**
* {n}人にフォローされました
*/
"followedBySomeUsers": ParameterizedString<"n">;
- /**
- * 通知の履歴をリセットする
- */
- "flushNotification": string;
- /**
- * {x}のエクスポートが完了しました
- */
- "exportOfXCompleted": ParameterizedString<"x">;
- /**
- * ログインがありました
- */
- "login": string;
"_types": {
/**
* すべて
@@ -9468,7 +9130,7 @@ export interface Locale extends ILocale {
*/
"reply": string;
/**
- * Boosts
+ * Boost
*/
"renote": string;
/**
@@ -9499,26 +9161,10 @@ export interface Locale extends ILocale {
* 実績の獲得
*/
"achievementEarned": string;
- /**
- * エクスポートが完了した
- */
- "exportCompleted": string;
- /**
- * ログイン
- */
- "login": string;
- /**
- * 通知のテスト
- */
- "test": string;
/**
* 連携アプリからの通知
*/
"app": string;
- /**
- * Edits
- */
- "edited": string;
};
"_actions": {
/**
@@ -9534,10 +9180,6 @@ export interface Locale extends ILocale {
*/
"renote": string;
};
- /**
- * Note got edited
- */
- "edited": string;
};
"_deck": {
/**
@@ -9552,10 +9194,6 @@ export interface Locale extends ILocale {
* カラムを追加
*/
"addColumn": string;
- /**
- * 新着ノート通知の設定
- */
- "newNoteNotificationSettings": string;
/**
* カラムの設定
*/
@@ -9661,10 +9299,6 @@ export interface Locale extends ILocale {
* ロールタイムライン
*/
"roleTimeline": string;
- /**
- * Following
- */
- "following": string;
};
};
"_dialog": {
@@ -9702,10 +9336,6 @@ export interface Locale extends ILocale {
* Webhookを作成
*/
"createWebhook": string;
- /**
- * Webhookを編集
- */
- "modifyWebhook": string;
/**
* 名前
*/
@@ -9715,9 +9345,9 @@ export interface Locale extends ILocale {
*/
"secret": string;
/**
- * トリガー
+ * Webhookを実行するタイミング
*/
- "trigger": string;
+ "events": string;
/**
* 有効
*/
@@ -9740,7 +9370,7 @@ export interface Locale extends ILocale {
*/
"reply": string;
/**
- * When boosted
+ * Boostされたとき
*/
"renote": string;
/**
@@ -9752,88 +9382,6 @@ export interface Locale extends ILocale {
*/
"mention": string;
};
- "_systemEvents": {
- /**
- * ユーザーから通報があったとき
- */
- "abuseReport": string;
- /**
- * When resolved abuse reports
- */
- "abuseReportResolved": string;
- /**
- * ユーザーが作成されたとき
- */
- "userCreated": string;
- /**
- * モデレーターが一定期間非アクティブになったとき
- */
- "inactiveModeratorsWarning": string;
- /**
- * モデレーターが一定期間非アクティブだったため、システムにより招待制へと変更されたとき
- */
- "inactiveModeratorsInvitationOnlyChanged": string;
- };
- /**
- * Webhookを削除しますか?
- */
- "deleteConfirm": string;
- /**
- * スイッチの右にあるボタンをクリックするとダミーのデータを使用したテスト用Webhookを送信できます。
- */
- "testRemarks": string;
- };
- "_abuseReport": {
- "_notificationRecipient": {
- /**
- * 通報の通知先を追加
- */
- "createRecipient": string;
- /**
- * 通報の通知先を編集
- */
- "modifyRecipient": string;
- /**
- * 通知先の種類
- */
- "recipientType": string;
- "_recipientType": {
- /**
- * メール
- */
- "mail": string;
- /**
- * Webhook
- */
- "webhook": string;
- "_captions": {
- /**
- * Send an email to the moderators when an abuse report is received.
- */
- "mail": string;
- /**
- * Send a notification to the SystemWebhook when an abuse report is received or resolved.
- */
- "webhook": string;
- };
- };
- /**
- * キーワード
- */
- "keywords": string;
- /**
- * 通知先ユーザー
- */
- "notifiedUser": string;
- /**
- * 使用するWebhook
- */
- "notifiedWebhook": string;
- /**
- * 通知先を削除しますか?
- */
- "deleteConfirm": string;
- };
};
"_moderationLogTypes": {
/**
@@ -9856,6 +9404,10 @@ export interface Locale extends ILocale {
* ロールのアサイン解除
*/
"unassignRole": string;
+ /**
+ * 承認済み
+ */
+ "approve": string;
/**
* 凍結
*/
@@ -9881,7 +9433,7 @@ export interface Locale extends ILocale {
*/
"updateServerSettings": string;
/**
- * ユーザーのモデレーションノート更新
+ * モデレーションノート更新
*/
"updateUserNote": string;
/**
@@ -9928,10 +9480,6 @@ export interface Locale extends ILocale {
* リモートサーバーを再開
*/
"unsuspendRemoteInstance": string;
- /**
- * リモートサーバーのモデレーションノート更新
- */
- "updateRemoteInstanceNote": string;
/**
* ファイルをセンシティブ付与
*/
@@ -9944,14 +9492,6 @@ export interface Locale extends ILocale {
* 通報を解決
*/
"resolveAbuseReport": string;
- /**
- * 通報を転送
- */
- "forwardAbuseReport": string;
- /**
- * 通報のモデレーションノート更新
- */
- "updateAbuseReportNote": string;
/**
* 招待コードを作成
*/
@@ -9988,66 +9528,6 @@ export interface Locale extends ILocale {
* ユーザーのバナーを解除
*/
"unsetUserBanner": string;
- /**
- * SystemWebhookを作成
- */
- "createSystemWebhook": string;
- /**
- * SystemWebhookを更新
- */
- "updateSystemWebhook": string;
- /**
- * SystemWebhookを削除
- */
- "deleteSystemWebhook": string;
- /**
- * 通報の通知先を作成
- */
- "createAbuseReportNotificationRecipient": string;
- /**
- * 通報の通知先を更新
- */
- "updateAbuseReportNotificationRecipient": string;
- /**
- * 通報の通知先を削除
- */
- "deleteAbuseReportNotificationRecipient": string;
- /**
- * アカウントを削除
- */
- "deleteAccount": string;
- /**
- * ページを削除
- */
- "deletePage": string;
- /**
- * Playを削除
- */
- "deleteFlash": string;
- /**
- * ギャラリーの投稿を削除
- */
- "deleteGalleryPost": string;
- /**
- * Approved
- */
- "approve": string;
- /**
- * Set remote instance as NSFW
- */
- "setRemoteInstanceNSFW": string;
- /**
- * Set remote instance as NSFW
- */
- "unsetRemoteInstanceNSFW": string;
- /**
- * Rejected reports from remote instance
- */
- "rejectRemoteInstanceReports": string;
- /**
- * Accepted reports from remote instance
- */
- "acceptRemoteInstanceReports": string;
};
"_fileViewer": {
/**
@@ -10215,10 +9695,48 @@ export interface Locale extends ILocale {
};
};
};
+ "_animatedMFM": {
+ /**
+ * MFMアニメーションを再生
+ */
+ "play": string;
+ /**
+ * MFMアニメーション停止
+ */
+ "stop": string;
+ "_alert": {
+ /**
+ * MFMアニメーションには、点滅するライトや高速で動くテキスト/絵文字を含まれる場合があります。
+ */
+ "text": string;
+ /**
+ * 再生する
+ */
+ "confirm": string;
+ };
+ };
+ "_dataRequest": {
+ /**
+ * データリクエスト
+ */
+ "title": string;
+ /**
+ * データリクエストは3日ごとに可能です。
+ */
+ "warn": string;
+ /**
+ * データの保存が完了すると、このアカウントに登録されているEメールアドレスにメールが送信されます。
+ */
+ "text": string;
+ /**
+ * リクエスト
+ */
+ "button": string;
+ };
"_dataSaver": {
"_media": {
/**
- * メディアの読み込みを無効化
+ * メディアの読み込み
*/
"title": string;
/**
@@ -10228,17 +9746,17 @@ export interface Locale extends ILocale {
};
"_avatar": {
/**
- * アイコン画像のアニメーションを無効化
+ * アイコン画像
*/
"title": string;
/**
- * Stop avatar image animation. Animated images can be larger in file size than normal images, potentially leading to further reductions in data traffic.
+ * アイコン画像のアニメーションが停止します。アニメーション画像は通常の画像よりファイルサイズが大きいことがあるので、データ通信量をさらに削減できます。
*/
"description": string;
};
"_urlPreview": {
/**
- * URLプレビューのサムネイルを非表示
+ * URLプレビューのサムネイル
*/
"title": string;
/**
@@ -10248,7 +9766,7 @@ export interface Locale extends ILocale {
};
"_code": {
/**
- * コードハイライトを非表示
+ * コードハイライト
*/
"title": string;
/**
@@ -10436,14 +9954,6 @@ export interface Locale extends ILocale {
* 変則なし
*/
"disallowIrregularRules": string;
- /**
- * 盤面に行・列番号を表示
- */
- "showBoardLabels": string;
- /**
- * 石をアイコンにする
- */
- "useAvatarAsStone": string;
};
"_offlineScreen": {
/**
@@ -10455,933 +9965,6 @@ export interface Locale extends ILocale {
*/
"header": string;
};
- "_urlPreviewSetting": {
- /**
- * URLプレビューの設定
- */
- "title": string;
- /**
- * URLプレビューを有効にする
- */
- "enable": string;
- /**
- * プレビュー取得時のタイムアウト(ms)
- */
- "timeout": string;
- /**
- * If it takes longer than this value to get the preview, the preview won't be generated.
- */
- "timeoutDescription": string;
- /**
- * Content-Lengthの最大値(byte)
- */
- "maximumContentLength": string;
- /**
- * Content-Lengthがこの値を超えた場合、プレビューは生成されません。
- */
- "maximumContentLengthDescription": string;
- /**
- * Generate the preview only if we can get Content-Length
- */
- "requireContentLength": string;
- /**
- * 相手サーバがContent-Lengthを返さない場合、プレビューは生成されません。
- */
- "requireContentLengthDescription": string;
- /**
- * User-Agent
- */
- "userAgent": string;
- /**
- * プレビュー取得時に使用されるUser-Agentを設定します。空欄の場合、デフォルトのUser-Agentが使用されます。
- */
- "userAgentDescription": string;
- /**
- * Endpoint for proxy to generate previews
- */
- "summaryProxy": string;
- /**
- * Generate previews using Summaly Proxy, instead of Sharkey itself.
- */
- "summaryProxyDescription": string;
- /**
- * The following parameters are sent to the proxy as a query string. If the proxy does not support them, the values are ignored.
- */
- "summaryProxyDescription2": string;
- };
- "_mediaControls": {
- /**
- * ピクチャインピクチャ
- */
- "pip": string;
- /**
- * 再生速度
- */
- "playbackRate": string;
- /**
- * ループ再生
- */
- "loop": string;
- };
- "_contextMenu": {
- /**
- * コンテキストメニュー
- */
- "title": string;
- /**
- * アプリケーション
- */
- "app": string;
- /**
- * Shiftキーでアプリケーション
- */
- "appWithShift": string;
- /**
- * ブラウザのUI
- */
- "native": string;
- };
- "_embedCodeGen": {
- /**
- * 埋め込みコードをカスタマイズ
- */
- "title": string;
- /**
- * ヘッダーを表示
- */
- "header": string;
- /**
- * 自動で続きを読み込む(非推奨)
- */
- "autoload": string;
- /**
- * 高さの最大値
- */
- "maxHeight": string;
- /**
- * 0で最大値の設定が無効になります。ウィジェットが縦に伸び続けるのを防ぐために、何らかの値に指定してください。
- */
- "maxHeightDescription": string;
- /**
- * 高さの最大値制限が無効(0)になっています。これが意図した変更ではない場合は、高さの最大値を何らかの値に設定してください。
- */
- "maxHeightWarn": string;
- /**
- * プレビュー画面で表示可能な範囲を超えたため、実際に埋め込んだ際とは表示が異なります。
- */
- "previewIsNotActual": string;
- /**
- * 角丸にする
- */
- "rounded": string;
- /**
- * 外枠に枠線をつける
- */
- "border": string;
- /**
- * プレビューに反映
- */
- "applyToPreview": string;
- /**
- * 埋め込みコードを作成
- */
- "generateCode": string;
- /**
- * コードが生成されました
- */
- "codeGenerated": string;
- /**
- * 生成されたコードをウェブサイトに貼り付けてご利用ください。
- */
- "codeGeneratedDescription": string;
- };
- /**
- * Approvals
- */
- "approvals": string;
- /**
- * Open remote profile
- */
- "openRemoteProfile": string;
- /**
- * Link to external site warning exclusion list
- */
- "trustedLinkUrlPatterns": string;
- /**
- * Separate with spaces for an AND condition or with line breaks for an OR condition. Using surrounding keywords with slashes will turn them into a regular expression. If you write only the domain name, it will be a backward match.
- */
- "trustedLinkUrlPatternsDescription": string;
- /**
- * Mutuals
- */
- "mutuals": string;
- /**
- * Private account
- */
- "isLocked": string;
- /**
- * Administrator
- */
- "isAdmin": string;
- /**
- * Bot user
- */
- "isBot": string;
- /**
- * Open
- */
- "open": string;
- /**
- * Destination address
- */
- "emailDestination": string;
- /**
- * Date
- */
- "date": string;
- /**
- * Quoted.
- */
- "quoted": string;
- /**
- * Unboosted.
- */
- "rmboost": string;
- /**
- * Muted
- */
- "muted": string;
- /**
- * Boosts muted
- */
- "renoteMuted": string;
- /**
- * Mark all media from user as NSFW
- */
- "markAsNSFW": string;
- /**
- * Mark as NSFW
- */
- "markInstanceAsNSFW": string;
- /**
- * Are you sure that you want to mark all media from this account as NSFW?
- */
- "nsfwConfirm": string;
- /**
- * Are you sure that you want to unmark all media from this account as NSFW?
- */
- "unNsfwConfirm": string;
- /**
- * Are you sure that you want to approve this account?
- */
- "approveConfirm": string;
- /**
- * Speak as a cat
- */
- "flagSpeakAsCat": string;
- /**
- * Your posts will get nyanified when in cat mode. If this isn't working, then please check that you dont have 'Disable cat speak' on under General/Note Display
- */
- "flagSpeakAsCatDescription": string;
- /**
- * Reject reports from this instance
- */
- "rejectReports": string;
- /**
- * This host is blocked implicitly because a base domain is blocked. To unblock this host, first unblock the base domain(s).
- */
- "blockedByBase": string;
- /**
- * This host is silenced implicitly because a base domain is silenced. To un-silence this host, first un-silence the base domain(s).
- */
- "silencedByBase": string;
- /**
- * This host's media is silenced implicitly because a base domain's media is silenced. To un-silence this host, first un-silence the base domain(s).
- */
- "mediaSilencedByBase": string;
- /**
- * Search drive
- */
- "driveSearchbarPlaceholder": string;
- /**
- * Background
- */
- "background": string;
- /**
- * Show content for all replies
- */
- "expandAllCws": string;
- /**
- * Hide content for all replies
- */
- "collapseAllCws": string;
- /**
- * Don't use drawer-style menus
- */
- "disableDrawer": string;
- /**
- * Corner roundness
- */
- "cornerRadius": string;
- /**
- * Warn you when you forget to put alt text
- */
- "warnForMissingAltText": string;
- /**
- * Use DeepLX-JS (No Auth Key)
- */
- "deeplFreeMode": string;
- /**
- * Need Help? Check our documentation to know how to setup DeepLX-JS.
- */
- "deeplFreeModeDescription": string;
- /**
- * Deletion of all files queued
- */
- "deleteAllFilesQueued": string;
- /**
- * This is a system account
- */
- "systemAccountTitle": string;
- /**
- * This account is created and managed automatically by the system, and cannot be logged into.
- */
- "systemAccountDescription": string;
- /**
- * post is hidden by a filter
- */
- "postFiltered": string;
- /**
- * Enable favicon notification dot
- */
- "enableFaviconNotificationDot": string;
- /**
- * Check if the notification dot works on your instance
- */
- "verifyNotificationDotWorkingButton": string;
- /**
- * Unfortunately, this instance does not support the notification dot feature at this time.
- */
- "notificationDotNotWorking": string;
- /**
- * The notification dot is functioning properly on this instance.
- */
- "notificationDotWorking": string;
- /**
- * If the notification dot doesn't work, ask an admin to check our documentation {link}
- */
- "notificationDotNotWorkingAdvice": ParameterizedString<"link">;
- /**
- * Forward report to remote instance
- */
- "forwardReport": string;
- /**
- * Instead of your account, an anonymous system account will be displayed as reporter at the remote instance.
- */
- "forwardReportIsAnonymous": string;
- /**
- * Mark report as resolved
- */
- "abuseMarkAsResolved": string;
- /**
- * Sharkey specific changes are translated in its own {link}.
- */
- "i18nInfoSharkey": ParameterizedString<"link">;
- /**
- * Show instance ticker on replies
- */
- "showTickerOnReplies": string;
- /**
- * Disable cat speak
- */
- "disableCatSpeak": string;
- /**
- * Search Engine For Search MFM
- */
- "searchEngine": string;
- /**
- * Other
- */
- "searchEngineOther": string;
- /**
- * The custom URI must be input in the format like "https://www.google.com/search?q=\{query}" or "https://www.google.com/search?q=%s".
- */
- "searchEngineCustomURIDescription": string;
- /**
- * Custom URI
- */
- "searchEngineCusomURI": string;
- /**
- * Make public notes not indexable
- */
- "makeIndexable": string;
- /**
- * Stop note search from indexing your public notes.
- */
- "makeIndexableDescription": string;
- /**
- * Require approval for new users
- */
- "approvalRequiredForSignup": string;
- /**
- * Confirm your vote for "{choice}"?
- * You can choose more options after confirmation.
- */
- "voteConfirmMulti": ParameterizedString<"choice">;
- /**
- * There are users awaiting approval.
- */
- "pendingUserApprovals": string;
- /**
- * Approve
- */
- "approveAccount": string;
- /**
- * Deny & Delete
- */
- "denyAccount": string;
- /**
- * Approved
- */
- "approved": string;
- /**
- * Not Approved
- */
- "notApproved": string;
- /**
- * Approval Status
- */
- "approvalStatus": string;
- /**
- * Number of replies in a thread
- */
- "numberOfReplies": string;
- /**
- * Increasing this number will display more replies. Setting this too high can cause replies to be cramped and unreadable.
- */
- "numberOfRepliesDescription": string;
- /**
- * Boost Settings
- */
- "boostSettings": string;
- /**
- * Show Visibility Selector
- */
- "showVisibilitySelectorOnBoost": string;
- /**
- * Shows the visiblity selector if enabled when clicking boost, if disabled it will use the default visiblity defined below and the selector will not show up.
- */
- "showVisibilitySelectorOnBoostDescription": string;
- /**
- * Default boost visibility
- */
- "visibilityOnBoost": string;
- /**
- * Default like emoji
- */
- "defaultLike": string;
- /**
- * You can also support {host} directly by donating to your instance administration.
- */
- "pleaseDonateInstance": ParameterizedString<"host">;
- /**
- * Cancel
- */
- "thisPostIsMissingAltTextCancel": string;
- /**
- * Post anyway
- */
- "thisPostIsMissingAltTextIgnore": string;
- /**
- * One of the files attached to this post is missing alt text. Please ensure all the attachments have alt text.
- */
- "thisPostIsMissingAltText": string;
- /**
- * Collapse notes replied to
- */
- "collapseNotesRepliedTo": string;
- /**
- * Collapse files
- */
- "collapseFiles": string;
- /**
- * Uncollapse CWs on notes
- */
- "uncollapseCW": string;
- /**
- * Always expand long notes
- */
- "expandLongNote": string;
- /**
- * Load conversation on replies
- */
- "autoloadConversation": string;
- /**
- * This instance is only accepting users who specify a reason for registration.
- */
- "approvalRequiredToRegister": string;
- /**
- * Cat friend :3
- */
- "oneko": string;
- /**
- * Enable Achievements
- */
- "enableAchievements": string;
- /**
- * Turning this off will disable the achievement system
- */
- "turnOffAchievements": string;
- /**
- * Populate Hashtags with Bots
- */
- "enableBotTrending": string;
- /**
- * Turning this off will stop Bots from populating Hashtags
- */
- "turnOffBotTrending": string;
- /**
- * Click to open notes
- */
- "clickToOpen": string;
- /**
- * Show bots in timeline
- */
- "showBots": string;
- /**
- * Donate
- */
- "donation": string;
- /**
- * Donation URL
- */
- "donationUrl": string;
- /**
- * Show Below Avatar
- */
- "showBelowAvatar": string;
- /**
- * Break following relationships
- */
- "severAllFollowRelations": string;
- /**
- * Really break all follow relationships? This is irreversible! This will break {followingCount} following and {followersCount} follower relations on {instanceName}!
- */
- "severAllFollowRelationsConfirm": ParameterizedString<"followingCount" | "followersCount" | "instanceName">;
- /**
- * Severing all follow relations with {host} queued.
- */
- "severAllFollowRelationsQueued": ParameterizedString<"host">;
- /**
- * Pending follow requests
- */
- "pendingFollowRequests": string;
- /**
- * Show quotes
- */
- "showQuotes": string;
- /**
- * Show replies
- */
- "showReplies": string;
- /**
- * Show non-public
- */
- "showNonPublicNotes": string;
- /**
- * Allow clicking on pop-up notifications
- */
- "allowClickingNotifications": string;
- /**
- * Pinned
- */
- "pinnedOnly": string;
- /**
- * Blocking you
- */
- "blockingYou": string;
- /**
- * Show warning when opening external URLs
- */
- "warnExternalUrl": string;
- "_mfm": {
- /**
- * This is not a widespread feature, it may not display properly on most other fedi software, including other Misskey forks
- */
- "uncommonFeature": string;
- /**
- * MFM is a markup language used on Misskey, Sharkey, Firefish, Akkoma, and more that can be used in many places. Here you can view a list of all available MFM syntax.
- */
- "intro": string;
- /**
- * Sharkey expands the world of the Fediverse
- */
- "dummy": string;
- /**
- * Mention
- */
- "mention": string;
- /**
- * You can specify a user by using an At-Symbol and a username.
- */
- "mentionDescription": string;
- /**
- * Hashtag
- */
- "hashtag": string;
- /**
- * You can specify a hashtag using a number sign and text.
- */
- "hashtagDescription": string;
- /**
- * URL
- */
- "url": string;
- /**
- * URLs can be displayed.
- */
- "urlDescription": string;
- /**
- * Link
- */
- "link": string;
- /**
- * Specific parts of text can be displayed as a URL.
- */
- "linkDescription": string;
- /**
- * Bold
- */
- "bold": string;
- /**
- * Highlights letters by making them thicker.
- */
- "boldDescription": string;
- /**
- * Small
- */
- "small": string;
- /**
- * Displays content small and thin.
- */
- "smallDescription": string;
- /**
- * Center
- */
- "center": string;
- /**
- * Displays content centered.
- */
- "centerDescription": string;
- /**
- * Code (Inline)
- */
- "inlineCode": string;
- /**
- * Displays inline syntax highlighting for (program) code.
- */
- "inlineCodeDescription": string;
- /**
- * Code (Block)
- */
- "blockCode": string;
- /**
- * Displays syntax highlighting for multi-line (program) code in a block.
- */
- "blockCodeDescription": string;
- /**
- * Math (Inline)
- */
- "inlineMath": string;
- /**
- * Display math formulas (KaTeX) in-line
- */
- "inlineMathDescription": string;
- /**
- * Math (Block)
- */
- "blockMath": string;
- /**
- * Display math formulas (KaTeX) in a block
- */
- "blockMathDescription": string;
- /**
- * Quote
- */
- "quote": string;
- /**
- * Displays content as a quote.
- */
- "quoteDescription": string;
- /**
- * Custom Emoji
- */
- "emoji": string;
- /**
- * By surrounding a custom emoji name with colons, custom emoji can be displayed.
- */
- "emojiDescription": string;
- /**
- * Search
- */
- "search": string;
- /**
- * Displays a search box with pre-entered text.
- */
- "searchDescription": string;
- /**
- * Flip
- */
- "flip": string;
- /**
- * Flips content horizontally or vertically.
- */
- "flipDescription": string;
- /**
- * Animation (Jelly)
- */
- "jelly": string;
- /**
- * Gives content a jelly-like animation.
- */
- "jellyDescription": string;
- /**
- * Animation (Tada)
- */
- "tada": string;
- /**
- * Gives content a "Tada!"-like animation.
- */
- "tadaDescription": string;
- /**
- * Animation (Jump)
- */
- "jump": string;
- /**
- * Gives content a jumping animation.
- */
- "jumpDescription": string;
- /**
- * Animation (Bounce)
- */
- "bounce": string;
- /**
- * Gives content a bouncy animation.
- */
- "bounceDescription": string;
- /**
- * Animation (Shake)
- */
- "shake": string;
- /**
- * Gives content a shaking animation.
- */
- "shakeDescription": string;
- /**
- * Animation (Twitch)
- */
- "twitch": string;
- /**
- * Gives content a strongly twitching animation.
- */
- "twitchDescription": string;
- /**
- * Animation (Spin)
- */
- "spin": string;
- /**
- * Gives content a spinning animation.
- */
- "spinDescription": string;
- /**
- * Big
- */
- "x2": string;
- /**
- * Displays content bigger.
- */
- "x2Description": string;
- /**
- * Very big
- */
- "x3": string;
- /**
- * Displays content even bigger.
- */
- "x3Description": string;
- /**
- * Unbelievably big
- */
- "x4": string;
- /**
- * Displays content even bigger than bigger than big.
- */
- "x4Description": string;
- /**
- * Blur
- */
- "blur": string;
- /**
- * Blurs content. It will be displayed clearly when hovered over.
- */
- "blurDescription": string;
- /**
- * Font
- */
- "font": string;
- /**
- * Sets the font to display content in.
- */
- "fontDescription": string;
- /**
- * Rainbow
- */
- "rainbow": string;
- /**
- * Makes the content appear in rainbow colors.
- */
- "rainbowDescription": string;
- /**
- * Sparkle
- */
- "sparkle": string;
- /**
- * Gives content a sparkling particle effect.
- */
- "sparkleDescription": string;
- /**
- * Rotate
- */
- "rotate": string;
- /**
- * Turns content by a specified angle.
- */
- "rotateDescription": string;
- /**
- * Position
- */
- "position": string;
- /**
- * Move content by a specified amount.
- */
- "positionDescription": string;
- /**
- * Crop
- */
- "crop": string;
- /**
- * Crop content.
- */
- "cropDescription": string;
- /**
- * Follow Mouse
- */
- "followMouse": string;
- /**
- * Content will follow the mouse. On mobile it will follow wherever the user taps.
- */
- "followMouseDescription": string;
- /**
- * Scale
- */
- "scale": string;
- /**
- * Scale content by a specified amount.
- */
- "scaleDescription": string;
- /**
- * Foreground color
- */
- "foreground": string;
- /**
- * Change the foreground color of text.
- */
- "foregroundDescription": string;
- /**
- * Fade
- */
- "fade": string;
- /**
- * Fade text in and out.
- */
- "fadeDescription": string;
- /**
- * Background color
- */
- "background": string;
- /**
- * Change the background color of text.
- */
- "backgroundDescription": string;
- /**
- * Plain
- */
- "plain": string;
- /**
- * Deactivates the effects of all MFM contained within this MFM effect.
- */
- "plainDescription": string;
- };
- "_animatedMFM": {
- /**
- * Play MFM Animation
- */
- "play": string;
- /**
- * Stop MFM Animation
- */
- "stop": string;
- "_alert": {
- /**
- * Animated MFMs could include flashing lights and fast moving text/emojis.
- */
- "text": string;
- /**
- * Animate
- */
- "confirm": string;
- };
- };
- "_dataRequest": {
- /**
- * Request Data
- */
- "title": string;
- /**
- * Data requests are only possible every 3 days.
- */
- "warn": string;
- /**
- * Once the data is ready to download, an email will be sent to the email address registered to this account.
- */
- "text": string;
- /**
- * Request
- */
- "button": string;
- };
- "_externalNavigationWarning": {
- /**
- * Navigate to an external site
- */
- "title": string;
- /**
- * Leave {host} and go to an external site
- */
- "description": ParameterizedString<"host">;
- /**
- * Trust this domain on this device in the future
- */
- "trustThisDomain": string;
- };
- /**
- * Remote followers may have incomplete or outdated activity
- */
- "remoteFollowersWarning": string;
- /**
- * Select a follow relationship...
- */
- "selectFollowRelationship": string;
}
declare const locales: {
[lang: string]: Locale;
diff --git a/locales/index.js b/locales/index.js
index b08158e55d..650e552337 100644
--- a/locales/index.js
+++ b/locales/index.js
@@ -5,7 +5,7 @@
import * as fs from 'node:fs';
import * as yaml from 'js-yaml';
-export const merge = (...args) => args.reduce((a, c) => ({
+const merge = (...args) => args.reduce((a, c) => ({
...a,
...c,
...Object.entries(a)
@@ -49,21 +49,10 @@ const primaries = {
};
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
-//
-// also, we remove the backslashes in front of open braces (the
-// backslashes are only needed to tell `generateDTS.js` that the
-// braces do not represent parameters)
-const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '').replaceAll(new RegExp(/\\+\{/,'g'), '{');
+const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '');
export function build() {
- // vitestの挙動を調整するため、一度ローカル変数化する必要がある
- // https://github.com/vitest-dev/vitest/issues/3988#issuecomment-1686599577
- // https://github.com/misskey-dev/misskey/pull/14057#issuecomment-2192833785
- const metaUrl = import.meta.url;
- const sharkeyLocales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`../sharkey-locales/${c}.yml`, metaUrl), 'utf-8'))) || {}, a), {});
- const misskeyLocales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, metaUrl), 'utf-8'))) || {}, a), {});
- // merge sharkey and misskey's locales. the second argument (sharkey) overwrites the first argument (misskey).
- const locales = merge(misskeyLocales, sharkeyLocales);
+ const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {});
// 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す
const removeEmpty = (obj) => {
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index bcabf1bdb6..e304f7798c 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -1,6 +1,6 @@
---
_lang_: "Italiano"
-headlineMisskey: "Rete collegata tramite Note"
+headlineMisskey: "Rete collegata tramite note"
introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n\n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n\n👍 Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n\n🚀 Esplora un nuovo mondo insieme a noi!"
poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source Misskey ."
monthAndDay: "{day}/{month}"
@@ -8,9 +8,6 @@ search: "Cerca"
notifications: "Notifiche"
username: "Nome utente"
password: "Password"
-initialPasswordForSetup: "Password iniziale, per avviare le impostazioni"
-initialPasswordIsIncorrect: "Password iniziale, sbagliata."
-initialPasswordForSetupDescription: "Se hai installato Misskey di persona, usa la password che hai indicato nel file di configurazione.\nSe stai utilizzando un servizio di hosting Misskey, usa la password fornita dal gestore.\nSe non hai una password preimpostata, lascia il campo vuoto e continua."
forgotPassword: "Hai dimenticato la password?"
fetchingAsApObject: "Recuperando dal Fediverso..."
ok: "OK"
@@ -57,13 +54,13 @@ addToAntenna: "Aggiungi all'antenna"
sendMessage: "Invia messaggio"
copyRSS: "Copia RSS"
copyUsername: "Copia nome utente"
+openRemoteProfile: "Apri profilo remoto"
copyUserId: "Copia ID del profilo"
copyNoteId: "Copia ID della Nota"
copyFileId: "Copia ID del file"
copyFolderId: "Copia ID della cartella"
copyProfileUrl: "Copia URL del profilo"
searchUser: "Cerca profilo"
-searchThisUsersNotes: "Cerca le sue Note"
reply: "Rispondi"
loadMore: "Mostra di più"
showMore: "Espandi"
@@ -89,7 +86,7 @@ note: "Nota"
notes: "Note"
following: "Follow"
followers: "Follower"
-followsYou: "Follower"
+followsYou: "Segue"
createList: "Aggiungi una nuova lista"
manageLists: "Gestisci liste"
error: "Errore"
@@ -112,14 +109,11 @@ enterEmoji: "Inserisci emoji"
renote: "Rinota"
unrenote: "Elimina la Rinota"
renoted: "Rinotata!"
-renotedToX: "Rinota da {name}."
cantRenote: "È impossibile rinotare questa nota."
cantReRenote: "È impossibile rinotare una Rinota."
quote: "Citazione"
inChannelRenote: "Rinota nel canale"
inChannelQuote: "Cita nel canale"
-renoteToChannel: "Rinota al canale"
-renoteToOtherChannel: "Rinota a un altro canale"
pinnedNote: "Nota in primo piano"
pinned: "Fissa sul profilo"
you: "Tu"
@@ -141,12 +135,12 @@ deleteFile: "File da Drive eliminato"
markAsSensitive: "Segna come esplicito"
unmarkAsSensitive: "Non segnare come esplicito "
enterFileName: "Nome del file"
-mute: "Silenziare"
+mute: "Silenzia"
unmute: "Riattiva l'audio"
-renoteMute: "Silenziare le Rinota"
+renoteMute: "Silenzia le Rinota"
renoteUnmute: "Non silenziare le Rinota"
-block: "Bloccare"
-unblock: "Sbloccare"
+block: "Blocca"
+unblock: "Sblocca"
suspend: "Sospensione"
unsuspend: "Revoca la sospensione"
blockConfirm: "Vuoi davvero bloccare il profilo?"
@@ -158,7 +152,6 @@ editList: "Modifica Lista"
selectChannel: "Seleziona canale"
selectAntenna: "Scegli un'antenna"
editAntenna: "Modifica Antenna"
-createAntenna: "Crea Antenna"
selectWidget: "Seleziona il riquadro"
editWidgets: "Modifica i riquadri"
editWidgetsExit: "Conferma le modifiche"
@@ -185,10 +178,6 @@ addAccount: "Aggiungi profilo"
reloadAccountsList: "Ricarica l'elenco dei profili"
loginFailed: "Accesso non riuscito"
showOnRemote: "Leggi sull'istanza remota"
-continueOnRemote: "Continua da remoto"
-chooseServerOnMisskeyHub: "Scegli l'istanza sul sito Misskey Hub"
-specifyServerHost: "Indica l'indirizzo dell'istanza"
-inputHostName: "Digita il nome del dominio "
general: "Generali"
wallpaper: "Sfondo"
setWallpaper: "Imposta sfondo"
@@ -199,7 +188,6 @@ followConfirm: "Vuoi seguire {name}?"
proxyAccount: "Profilo proxy"
proxyAccountDescription: "Un profilo proxy funziona come follower per i profili remoti, sotto certe condizioni. Ad esempio, quando un profilo locale ne inserisce uno remoto in una lista (senza seguirlo), se nessun altro segue quel profilo remoto, le attività non possono essere distribuite. Dunque, il profilo proxy le seguirà per tutti."
host: "Host"
-selectSelf: "Segli me"
selectUser: "Seleziona profilo"
recipient: "Destinatario"
annotation: "Annotazione preventiva"
@@ -213,9 +201,8 @@ charts: "Grafici"
perHour: "orario"
perDay: "giornaliero"
stopActivityDelivery: "Interrompi la distribuzione di attività"
-blockThisInstance: "Bloccare l'istanza"
-silenceThisInstance: "Silenziare l'istanza"
-mediaSilenceThisInstance: "Silenzia i media dell'istanza"
+blockThisInstance: "Blocca questa istanza"
+silenceThisInstance: "Silenzia l'istanza"
operations: "Operazioni"
software: "Software"
version: "Versione"
@@ -237,11 +224,7 @@ blockedInstances: "Istanze bloccate"
blockedInstancesDescription: "Elenca le istanze che vuoi bloccare, una per riga. Esse non potranno più interagire con la tua istanza."
silencedInstances: "Istanze silenziate"
silencedInstancesDescription: "Elenca i nomi host delle istanze che vuoi silenziare. Tutti i profili nelle istanze silenziate vengono trattati come tali. Possono solo inviare richieste di follow e menzionare soltanto i profili locali che seguono. Le istanze bloccate non sono interessate."
-mediaSilencedInstances: "Istanze coi media silenziati"
-mediaSilencedInstancesDescription: "Elenca i nomi host delle istanze di cui vuoi silenziare i media, uno per riga. Tutti gli allegati dei profili nelle istanze silenziate per via degli allegati espliciti, verranno impostati come tali, le emoji personalizzate non saranno disponibili. Le istanze bloccate sono escluse."
-federationAllowedHosts: "Server a cui consentire la federazione"
-federationAllowedHostsDescription: "Indica gli host dei server a cui è consentita la federazione, uno per ogni linea."
-muteAndBlock: "Silenziare e bloccare"
+muteAndBlock: "Silenziati / Bloccati"
mutedUsers: "Profili silenziati"
blockedUsers: "Profili bloccati"
noUsers: "Non ci sono profili"
@@ -331,7 +314,6 @@ selectFile: "Scelta allegato"
selectFiles: "Scelta allegato"
selectFolder: "Seleziona cartella"
selectFolders: "Seleziona cartella"
-fileNotSelected: "Nessun file selezionato"
renameFile: "Rinomina file"
folderName: "Nome della cartella"
createFolder: "Nuova cartella"
@@ -339,7 +321,6 @@ renameFolder: "Rinomina cartella"
deleteFolder: "Elimina cartella"
folder: "Cartella"
addFile: "Allega"
-showFile: "Visualizza file"
emptyDrive: "Il Drive è vuoto"
emptyFolder: "La cartella è vuota"
unableToDelete: "Eliminazione impossibile"
@@ -420,7 +401,6 @@ name: "Nome"
antennaSource: "Fonte dell'antenna"
antennaKeywords: "Parole chiavi da ricevere"
antennaExcludeKeywords: "Parole chiavi da escludere"
-antennaExcludeBots: "Escludere i Bot"
antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)."
notifyAntenna: "Invia notifiche delle nuove note"
withFileAntenna: "Solo note con file in allegato"
@@ -431,7 +411,7 @@ withReplies: "Includere le risposte"
connectedTo: "Connessione ai seguenti profili:"
notesAndReplies: "Note e risposte"
withFiles: "Con allegati"
-silence: "Silenziare"
+silence: "Silenzia"
silenceConfirm: "Vuoi davvero silenziare questo profilo?"
unsilence: "Riattiva"
unsilenceConfirm: "Vuoi davvero riattivare questo profilo?"
@@ -454,7 +434,6 @@ totpDescription: "Puoi autenticarti inserendo un codice OTP tramite la tua App d
moderator: "Moderatore"
moderation: "moderazione"
moderationNote: "Promemoria di moderazione"
-moderationNoteDescription: "Puoi scrivere promemoria condivisi solo tra moderatori."
addModerationNote: "Aggiungi promemoria di moderazione"
moderationLogs: "Cronologia di moderazione"
nUsersMentioned: "{n} profili ne parlano"
@@ -462,7 +441,7 @@ securityKeyAndPasskey: "Chiave di sicurezza e accesso"
securityKey: "Chiave di sicurezza"
lastUsed: "Ultima attività"
lastUsedAt: "Uso più recente: {t}"
-unregister: "Rimuovi autenticazione a due fattori (2FA/MFA)"
+unregister: "Annulla l'iscrizione"
passwordLessLogin: "Accedi senza password"
passwordLessLoginDescription: "Accedi senza password, usando la chiave di sicurezza"
resetPassword: "Ripristina la password"
@@ -472,7 +451,7 @@ share: "Condividi"
notFound: "Non trovato"
notFoundDescription: "Nessuna pagina corrisponde all'URL indicata."
uploadFolder: "Destinazione caricamento predefinita"
-markAsReadAllNotifications: "Segnare tutte le notifiche come lette"
+markAsReadAllNotifications: "Segna tutte le notifiche come lette"
markAsReadAllUnreadNotes: "Segna tutte le note come lette"
markAsReadAllTalkMessages: "Segna tutte le chat come lette"
help: "Guida"
@@ -489,12 +468,10 @@ retype: "Conferma"
noteOf: "Note di {user}"
quoteAttached: "Citazione allegata"
quoteQuestion: "Vuoi aggiungere una citazione?"
-attachAsFileQuestion: "Il testo copiato eccede le dimensioni, vuoi allegarlo?"
noMessagesYet: "Ancora nessuna chat"
newMessageExists: "Hai ricevuto un nuovo messaggio"
onlyOneFileCanBeAttached: "È possibile allegare al messaggio soltanto uno file"
signinRequired: "Occorre avere un profilo registrato su questa istanza"
-signinOrContinueOnRemote: "Per continuare, devi accedere alla tua istanza o registrarti su questa e poi accedere"
invitations: "Invita"
invitationCode: "Codice di invito"
checking: "Confermando"
@@ -516,12 +493,8 @@ uiLanguage: "Lingua di visualizzazione dell'interfaccia"
aboutX: "Informazioni su {x}"
emojiStyle: "Stile emoji"
native: "Nativo"
-menuStyle: "Stile menu"
-style: "Stile"
-drawer: "Drawer"
-popup: "Popup"
+disableDrawer: "Non mostrare il menù sul drawer"
showNoteActionsOnlyHover: "Mostra le azioni delle Note solo al passaggio del mouse"
-showReactionsCount: "Visualizza il numero di reazioni su una nota"
noHistory: "Nessuna cronologia"
signinHistory: "Storico degli accessi al profilo"
enableAdvancedMfm: "Attiva MFM avanzati"
@@ -575,7 +548,7 @@ deleteAll: "Cancella cronologia"
showFixedPostForm: "Visualizzare la finestra di pubblicazione in cima alla timeline"
showFixedPostFormInChannel: "Per i canali, mostra il modulo di pubblicazione in cima alla timeline"
withRepliesByDefaultForNewlyFollowed: "Quando segui nuovi profili, includi le risposte in TL come impostazione predefinita"
-newNoteRecived: "Nuove Note da leggere"
+newNoteRecived: "Nuove note da leggere"
sounds: "Impostazioni suoni"
sound: "Suono"
listen: "Ascolta"
@@ -602,12 +575,10 @@ ascendingOrder: "Aumenta"
descendingOrder: "Diminuisce"
scratchpad: "ScratchPad"
scratchpadDescription: "Lo Scratchpad offre un ambiente per esperimenti di AiScript. È possibile scrivere, eseguire e confermare i risultati dell'interazione del codice con Misskey."
-uiInspector: "UI Inspector"
-uiInspectorDescription: "Puoi visualizzare un elenco di elementi UI presenti in memoria. I componenti dell'interfaccia utente vengono generati dalle funzioni Ui:C:."
output: "Uscita"
script: "Script"
disablePagesScript: "Disabilita AiScript nelle pagine"
-updateRemoteUser: "Aggiorna dati dal profilo remoto"
+updateRemoteUser: "Aggiorna le informazioni dal profilo remoto"
unsetUserAvatar: "Rimozione foto profilo"
unsetUserAvatarConfirm: "Vuoi davvero rimuovere la foto profilo?"
unsetUserBanner: "Rimuovi intestazione profilo"
@@ -617,7 +588,7 @@ deleteAllFilesConfirm: "Vuoi davvero eliminare tutti i file?"
removeAllFollowing: "Annulla tutti i follow"
removeAllFollowingDescription: "Cancella tutti i follows del server {host}. Per favore, esegui se, ad esempio, l'istanza non esiste più."
userSuspended: "L'utente è in sospensione"
-userSilenced: "Profilo silenziato"
+userSilenced: "Profilo silente."
yourAccountSuspendedTitle: "Questo profilo è sospeso"
yourAccountSuspendedDescription: "Questo profilo è stato sospeso a causa di una violazione del regolamento. Per informazioni, contattare l'amministrazione. Si prega di non creare un nuovo account."
tokenRevoked: "Il token non è valido"
@@ -687,7 +658,7 @@ wordMute: "Filtri parole"
hardWordMute: "Filtro parole forte"
regexpError: "errore regex"
regexpErrorDescription: "Si è verificato un errore nell'espressione regolare alla riga {line} della parola muta {tab}:"
-instanceMute: "Silenziare l'istanza"
+instanceMute: "Silenzia l'istanza"
userSaysSomething: "{name} ha parlato"
makeActive: "Attiva"
display: "Visualizza"
@@ -712,15 +683,18 @@ fileIdOrUrl: "ID o URL del file"
behavior: "Comportamento"
sample: "Esempio"
abuseReports: "Segnalazioni"
-reportAbuse: "Segnalare"
-reportAbuseRenote: "Segnalare la Rinota"
-reportAbuseOf: "Segnalare {name}"
+reportAbuse: "Segnala"
+reportAbuseRenote: "Segnala la Rinota"
+reportAbuseOf: "Segnala {name}"
fillAbuseReportDescription: "Per favore, spiegaci il motivo della segnalazione. Se riguarda una Nota precisa, indica anche l'indirizzo URL."
abuseReported: "La segnalazione è stata inviata. Grazie."
reporter: "il corrispondente"
-reporteeOrigin: "Segnalazione a"
-reporterOrigin: "Segnalazione da"
+reporteeOrigin: "Origine del segnalato"
+reporterOrigin: "Origine del segnalatore"
+forwardReport: "Inoltro di un report a un'istanza remota."
+forwardReportIsAnonymous: "L'istanza remota non vedrà le tue informazioni, apparirai come profilo di sistema, anonimo."
send: "Inviare"
+abuseMarkAsResolved: "Contrassegna la segnalazione come risolta"
openInNewTab: "Apri in una nuova scheda"
openInSideView: "Apri in vista laterale"
defaultNavigationBehaviour: "Navigazione preimpostata"
@@ -779,6 +753,8 @@ thisIsExperimentalFeature: "Questa è una funzionalità sperimentale. Potrebbe e
developer: "Sviluppatore"
makeExplorable: "Profilo visibile pubblicamente nella pagina \"Esplora\""
makeExplorableDescription: "Disabilitando questa opzione, il tuo profilo non verrà elencato nella pagina \"Esplora\"."
+makeIndexable: "Non indicizzare le note pubbliche"
+makeIndexableDescription: "Le tue note pubbliche non saranno cercabili"
showGapBetweenNotesInTimeline: "Mostrare un intervallo tra le note sulla timeline"
duplicate: "Duplica"
left: "Sinistra"
@@ -842,7 +818,7 @@ onlineStatus: "Stato di connessione"
hideOnlineStatus: "Modalità invisibile"
hideOnlineStatusDescription: "Attivando questa opzione potresti ridurre l'usabilità di alcune funzioni, come la ricerca."
online: "Online"
-active: "Attivo"
+active: "Attività"
offline: "Offline"
notRecommended: "Sconsigliato"
botProtection: "Protezione contro i bot"
@@ -857,7 +833,6 @@ administration: "Gestione"
accounts: "Profilo"
switch: "Cambia"
noMaintainerInformationWarning: "Mancano le informazioni sull'amministratore."
-noInquiryUrlWarning: "Non è stata impostata la URL di contatto"
noBotProtectionWarning: "Non è stata impostata alcuna protezione dai Bot"
configure: "Imposta"
postToGallery: "Pubblicare nella galleria"
@@ -889,7 +864,7 @@ troubleshooting: "Risoluzione problemi"
useBlurEffect: "Utilizza effetto sfocatura"
learnMore: "Più dettagli"
misskeyUpdated: "Misskey è stato aggiornato!"
-whatIsNew: "Informazioni sull'aggiornamento"
+whatIsNew: "Visualizza le informazioni sull'aggiornamento"
translate: "Traduci"
translatedFrom: "Traduzione da {x}"
accountDeletionInProgress: "È in corso l'eliminazione del profilo"
@@ -915,14 +890,13 @@ manageAccounts: "Gestisci i profili"
makeReactionsPublic: "Pubblicare la lista delle reazioni."
makeReactionsPublicDescription: "La lista delle reazioni che avete fatto è a disposizione di tutti."
classic: "Classico"
-muteThread: "Silenziare conversazione"
+muteThread: "Silenzia conversazione"
unmuteThread: "Riattiva la conversazione"
followingVisibility: "Visibilità dei profili seguiti"
followersVisibility: "Visibilità dei profili che ti seguono"
continueThread: "Altre conversazioni"
deleteAccountConfirm: "Così verrà eliminato il profilo. Vuoi procedere?"
incorrectPassword: "La password è errata."
-incorrectTotp: "Il codice OTP è sbagliato, oppure scaduto."
voteConfirm: "Votare per「{choice}」?"
hide: "Nascondere"
useDrawerReactionPickerForMobile: "Mostra sul drawer da dispositivo mobile"
@@ -998,11 +972,11 @@ shuffle: "Casuale"
account: "Account"
move: "Sposta"
pushNotification: "Notifiche Push"
-subscribePushNotification: "Attivare le notifiche push"
-unsubscribePushNotification: "Disattivare le notifiche push"
+subscribePushNotification: "Attiva le notifiche push"
+unsubscribePushNotification: "Disattiva le notifiche push"
pushNotificationAlreadySubscribed: "Le notifiche push sono già attivate"
pushNotificationNotSupported: "Il client o il server non supporta le notifiche push"
-sendPushNotificationReadMessage: "Eliminare le notifiche push dopo la relativa lettura"
+sendPushNotificationReadMessage: "Elimina le notifiche push dopo la relativa lettura"
sendPushNotificationReadMessageCaption: "Se possibile, verrà mostrata brevemente una notifica con il testo \"{emptyPushNotificationMessage}\". Potrebbe influire negativamente sulla durata della batteria."
windowMaximize: "Ingrandisci"
windowMinimize: "Contrai finestra"
@@ -1014,13 +988,13 @@ cannotLoad: "Caricamento impossibile"
numberOfProfileView: "Visualizzazioni profilo"
like: "Mi piace!"
unlike: "Non mi piace"
+defaultLike: "Emoji predefinita per \"mi piace\""
numberOfLikes: "Numero di Like"
show: "Visualizza"
neverShow: "Non mostrare più"
remindMeLater: "Rimanda"
didYouLikeMisskey: "Ti piace Misskey?"
pleaseDonate: "Misskey è il software libero utilizzato su {host}. Offrendo una donazione è più facile continuare a svilupparlo!"
-correspondingSourceIsAvailable: ""
roles: "Ruoli"
role: "Ruolo"
noRole: "Ruolo non trovato"
@@ -1048,7 +1022,6 @@ thisPostMayBeAnnoyingHome: "Pubblica sulla timeline principale"
thisPostMayBeAnnoyingCancel: "Annulla"
thisPostMayBeAnnoyingIgnore: "Pubblica lo stesso"
collapseRenotes: "Comprimi le Rinota già viste"
-collapseRenotesDescription: "Comprimi le Note con cui hai già interagito."
internalServerError: "Errore interno del server"
internalServerErrorDescription: "Si è verificato un errore imprevisto all'interno del server"
copyErrorInfo: "Copia le informazioni sull'errore"
@@ -1087,7 +1060,6 @@ retryAllQueuesConfirmTitle: "Vuoi ritentare adesso?"
retryAllQueuesConfirmText: "Potrebbe sovraccaricare il server temporaneamente."
enableChartsForRemoteUser: "Abilita i grafici per i profili remoti"
enableChartsForFederatedInstances: "Abilita i grafici per le istanze federate"
-enableStatsForFederatedInstances: "Informazioni statistiche sui server federati"
showClipButtonInNoteFooter: "Aggiungi il bottone Clip tra le azioni delle Note"
reactionsDisplaySize: "Grandezza delle reazioni"
limitWidthOfReaction: "Limita la larghezza delle reazioni e ridimensionale"
@@ -1123,8 +1095,6 @@ preservedUsernames: "Nomi utente riservati"
preservedUsernamesDescription: "Elenca, uno per linea, i nomi utente che non possono essere registrati durante la creazione del profilo. La restrizione non si applica agli amministratori. Inoltre, i profili già registrati sono esenti."
createNoteFromTheFile: "Crea Nota da questo file"
archive: "Archivio"
-archived: "Archiviato"
-unarchive: "Annulla archiviazione"
channelArchiveConfirmTitle: "Vuoi davvero archiviare {name}?"
channelArchiveConfirmDescription: "Un canale archiviato non compare nell'elenco canali, nemmeno nei risultati di ricerca. Non può ricevere nemmeno nuove Note."
thisChannelArchived: "Questo canale è stato archiviato."
@@ -1135,9 +1105,6 @@ preventAiLearning: "Impedisci l'apprendimento della IA"
preventAiLearningDescription: "Aggiungendo il campo \"noai\" alla risposta HTML, si indica ai Robot esterni di non usare testi e allegati per addestrare sistemi di Machine Learning (IA predittiva/generativa). Anche se è impossibile sapere se la richiesta venga onorata o semplicemente ignorata."
options: "Opzioni del ruolo"
specifyUser: "Profilo specifico"
-lookupConfirm: "Vuoi davvero richiedere informazioni?"
-openTagPageConfirm: "Vuoi davvero aprire la pagina dell'hashtag?"
-specifyHost: "Specifica l'host"
failedToPreviewUrl: "Anteprima non disponibile"
update: "Aggiorna"
rolesThatCanBeUsedThisEmojiAsReaction: "Ruoli che possono usare questa emoji come reazione"
@@ -1196,7 +1163,6 @@ showRenotes: "Includi le Rinota"
edited: "Modificato"
notificationRecieveConfig: "Preferenze di notifica"
mutualFollow: "Follow reciproco"
-followingOrFollower: "Following o Follower"
fileAttachedOnly: "Solo con allegati"
showRepliesToOthersInTimeline: "Risposte altrui nella TL"
hideRepliesToOthersInTimeline: "Nascondi Riposte altrui nella TL"
@@ -1206,12 +1172,6 @@ confirmShowRepliesAll: "Questa è una attività irreversibile. Vuoi davvero incl
confirmHideRepliesAll: "Questa è una attività irreversibile. Vuoi davvero escludere tutte le risposte dei following in TL?"
externalServices: "Servizi esterni"
sourceCode: "Codice sorgente"
-sourceCodeIsNotYetProvided: ""
-repositoryUrl: "URL della repository"
-repositoryUrlDescription: "Se esiste un repository il cui il codice sorgente è disponibile pubblicamente, inserisci il suo URL. Se stai utilizzando Misskey così com'è (senza alcuna modifica al codice sorgente), inserisci https://github.com/misskey-dev/misskey."
-repositoryUrlOrTarballRequired: "Se non disponi di un repository pubblico, dovrai fornire un file tarball (tar). Vedere .config/example.yml per i dettagli."
-feedback: "Feedback"
-feedbackUrl: "URL di feedback"
impressum: "Dichiarazione di proprietà"
impressumUrl: "URL della dichiarazione di proprietà"
impressumDescription: "La dichiarazione di proprietà, è obbligatoria in alcuni paesi come la Germania (Impressum)."
@@ -1243,12 +1203,10 @@ addMfmFunction: "Aggiungi decorazioni"
enableQuickAddMfmFunction: "Attiva il selettore di funzioni MFM"
bubbleGame: "Bubble Game"
sfx: "Effetti sonori"
-soundWillBePlayed: "Con musica ed effetti sonori"
+soundWillBePlayed: "Verrà riprodotto il suono"
showReplay: "Vedi i replay"
replay: "Replay"
replaying: "Replay in corso"
-endReplay: "Termina replay"
-copyReplayData: "Copia replay"
ranking: "Classifica"
lastNDays: "Ultimi {n} giorni"
backToTitle: "Torna al titolo"
@@ -1256,87 +1214,25 @@ hemisphere: "Geolocalizzazione"
withSensitive: "Mostra le Note con allegati espliciti"
userSaysSomethingSensitive: "Note da {name} con allegati espliciti"
enableHorizontalSwipe: "Trascina per invertire i tab"
-loading: "Caricamento"
-surrender: "Annulla"
-gameRetry: "Riprova"
-notUsePleaseLeaveBlank: "Lasciare vuoto, se non in uso"
-useTotp: "Usare il codice OTP"
-useBackupCode: "Usare il codice usa-e-getta"
-launchApp: "Esegui l'App"
-useNativeUIForVideoAudioPlayer: "Riprodurre audio/video usando le funzionalità del browser"
-keepOriginalFilename: "Mantieni il nome file originale"
-keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
-noDescription: "Manca la descrizione"
-alwaysConfirmFollow: "Richiedi conferma per i Follow"
-inquiry: "Contattaci"
-tryAgain: "Per favore riprova"
-confirmWhenRevealingSensitiveMedia: "Richiedi conferma prima di mostrare gli allegati espliciti"
-sensitiveMediaRevealConfirm: "Questo allegato è esplicito, vuoi vederlo?"
-createdLists: "Liste create"
-createdAntennas: "Antenne create"
-fromX: "Da {x}"
-genEmbedCode: "Ottieni il codice di incorporamento"
-noteOfThisUser: "Elenco di Note di questo profilo"
-clipNoteLimitExceeded: "Non è possibile aggiungere ulteriori Note a questa Clip."
-performance: "Prestazioni"
-modified: "Modificato"
-discard: "Scarta"
-thereAreNChanges: "Ci sono {n} cambiamenti"
-signinWithPasskey: "Accedi con passkey"
-unknownWebAuthnKey: "Questa è una passkey sconosciuta."
-passkeyVerificationFailed: "La verifica della passkey non è riuscita."
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verifica della passkey è riuscita, ma l'accesso senza password è disabilitato."
-messageToFollower: "Messaggio ai follower"
-target: "Riferimento"
-testCaptchaWarning: "Questa funzione è destinata al test CAPTCHA. Da non utilizzare in ambiente di produzione. "
-prohibitedWordsForNameOfUser: "Parole proibite (nome utente)"
-prohibitedWordsForNameOfUserDescription: "Il sistema rifiuta di rinominare un utente, se il nome contiene qualsiasi parola nell'elenco. Sono esenti i profili con privilegi di moderazione."
-yourNameContainsProhibitedWords: "Il nome che hai scelto contiene una o più parole vietate"
-yourNameContainsProhibitedWordsDescription: "Se desideri comunque utilizzare questo nome, contatta l''amministrazione."
-_abuseUserReport:
- forward: "Inoltra"
- forwardDescription: "Inoltra il report al server remoto, per mezzo di account di sistema, anonimo."
- resolve: "Risolvi"
- accept: "Approva"
- reject: "Rifiuta"
- resolveTutorial: "Se moderi una segnalazione legittima, scegli \"Approva\" per risolvere positivamente.\nSe la segnalazione non è legittima, seleziona \"Rifiuta\" per risolvere negativamente."
-_delivery:
- status: "Stato della consegna"
- stop: "Sospensione"
- resume: "Riprendi la consegna"
- _type:
- none: "Pubblicazione"
- manuallySuspended: "Sospesa manualmente"
- goneSuspended: "Sospensione server a causa dell'eliminazione"
- autoSuspendedForNotResponding: "Sospensione del server a causa di mancata risposta"
_bubbleGame:
howToPlay: "Come giocare"
- hold: "Tieni"
- _score:
- score: "Punteggio"
- scoreYen: "Capitale"
- highScore: "Punteggio migliore"
- maxChain: "Miglior combo"
- yen: "{yen}¥"
- estimatedQty: "{qty} punti"
- scoreSweets: "Onigiri {onigiriQtyWithUnit}"
_howToPlay:
- section1: "Scegli la posizione e rilascia l'oggetto nel contenitore."
- section2: "Se due oggetti dello stesso tipo si toccano, si trasformano in un oggetto diverso, aumentando il punteggio."
- section3: "Se gli oggetti escono dal limite superiore del contenitore, il gioco finisce. Cerca di ottenere un punteggio elevato fondendo gli oggetti, evitando che escano dal contenitore!"
+ section1: "Regola la posizione e rilascia l'oggetto nella casella."
+ section2: "Ottieni un punteggio, quando due oggetti dello stesso tipo si toccano e si trasformano in un oggetto diverso."
+ section3: "Se gli oggetti traboccano dalla scatola, il gioco finisce. Cerca di ottenere un punteggio elevato fondendo gli oggetti, evitando che escano dalla scatola!"
_announcement:
forExistingUsers: "Solo ai profili attuali"
forExistingUsersDescription: "L'annuncio sarà visibile solo ai profili esistenti in questo momento. Se disabilitato, sarà visibile anche ai profili che verranno creati dopo la pubblicazione di questo annuncio."
- needConfirmationToRead: "Conferma di lettura obbligatoria"
- needConfirmationToReadDescription: "I profili riceveranno una finestra di dialogo che richiede di accettare obbligatoriamente per procedere. Tale richiesta è esente da \"conferma tutte\"."
+ needConfirmationToRead: "Richiede la conferma di lettura"
+ needConfirmationToReadDescription: "Sarà visualizzata una finestra di dialogo che richiede la conferma di lettura. Inoltre, non è soggetto a conferme di lettura massicce."
end: "Archivia l'annuncio"
tooManyActiveAnnouncementDescription: "L'esperienza delle persone può peggiorare se ci sono troppi annunci attivi. Considera anche l'archiviazione degli annunci conclusi."
readConfirmTitle: "Segnare come già letto?"
readConfirmText: "Hai già letto \"{title}˝?"
shouldNotBeUsedToPresentPermanentInfo: "Ti consigliamo di utilizzare gli annunci per pubblicare informazioni tempestive e limitate nel tempo, anziché informazioni importanti a lungo andare nel tempo, poiché potrebbero risultare difficili da ritrovare e peggiorare la fruibilità del servizio, specialmente alle nuove persone iscritte."
dialogAnnouncementUxWarn: "Ti consigliamo di usarli con cautela, poiché è molto probabile che avere più di un annuncio in stile \"finestra di dialogo\" peggiori sensibilmente la fruibilità del servizio, specialmente alle nuove persone iscritte."
- silence: "Annuncio silenzioso"
- silenceDescription: "Attivando questa opzione, non invierai la notifica, evitando che debba essere contrassegnata come già letta."
+ silence: "Silenzia gli annunci"
+ silenceDescription: "Se attivi questa opzione, non riceverai notifiche sugli annunci, evitando di contrassegnarle come già lette."
_initialAccountSetting:
accountCreated: "Il tuo profilo è stato creato!"
letsStartAccountSetup: "Per iniziare, impostiamo il tuo profilo."
@@ -1354,7 +1250,7 @@ _initialAccountSetting:
skipAreYouSure: "Vuoi davvero saltare la configurazione iniziale?"
laterAreYouSure: "Vuoi davvero rimandare la configurazione iniziale?"
_initialTutorial:
- launchTutorial: "Inizia il tutorial"
+ launchTutorial: "Guarda il tutorial"
title: "Tutorial"
wellDone: "Ottimo lavoro!"
skipAreYouSure: "Vuoi davvero interrompere il tutorial?"
@@ -1364,26 +1260,26 @@ _initialTutorial:
_note:
title: "Cosa sono le Note?"
description: "Gli status su Misskey sono chiamati \"Note\". Le Note sono elencate in ordine cronologico nelle timeline e vengono aggiornate in tempo reale."
- reply: "Puoi rispondere alle Note, alle altre risposte e dialogare in conversazioni."
- renote: "Puoi ri-condividere le Note, ritorneranno sulla Timeline. Aggiungendo del testo, scriverai una Citazione."
- reaction: "Puoi aggiungere una reazione. Nella pagina successiva ti spiego come."
- menu: "Per altre attività, ad esempio, vedere i dettagli delle Note o copiare i collegamenti."
+ reply: "Puoi rispondere alle Note. Puoi anche rispondere alle risposte e continuare i dialoghi come un conversazioni."
+ renote: "Puoi ri-condividere le Note, facendole rifluire sulla Timeline. Puoi anche aggiungere testo e citare altri profili."
+ reaction: "Puoi aggiungere una reazione. Nella pagina successiva spiegheremo i dettagli."
+ menu: "Puoi svolgere varie attività, come visualizzare i dettagli delle Note o copiare i collegamenti."
_reaction:
title: "Cosa sono le Reazioni?"
- description: "Reazioni alle Note. Le sensazioni che non si possono descrivere con \"Mi piace\" si esprimono facilmente con le reazioni."
+ description: "Puoi reagire alle Note. Le sensazioni che non si riescono a trasmettere con i \"Mi piace\" si possono esprimere facilmente inviando una reazione."
letsTryReacting: "Puoi aggiungere una Reazione cliccando il bottone \"+\" (più) della relativa Nota. Prova ad aggiungerne una a questa Nota di esempio!"
reactToContinue: "Aggiungere la Reazione ti consentirà di procedere col tutorial."
reactNotification: "Quando qualcuno reagisce alle tue Note, ricevi una notifica in tempo reale."
- reactDone: "Annulla la tua Reazione premendo il bottone \"ー\" (meno)"
+ reactDone: "Puoi annullare la tua Reazione premendo il bottone \"ー\" (meno)"
_timeline:
title: "Come funziona la Timeline"
description1: "Misskey fornisce alcune Timeline (sequenze cronologiche di Note). Una di queste potrebbe essere stata disattivata dagli amministratori."
- home: "le Note provenienti dai profili che segui (follow)."
- local: "tutte le Note pubblicate dai profili di questa istanza."
- social: "sia le Note della Timeline Home che quelle della Timeline Locale, insieme!"
- global: "le Note da pubblicate da tutte le altre istanze federate con la nostra."
+ home: "Puoi vedere le Note provenienti dai profili che segui (follow)."
+ local: "Puoi vedere tutte le Note pubblicate dai profili di questa istanza."
+ social: "Puoi vedere sia le Note della Timeline Home che quelle della Timeline Locale, insieme!"
+ global: "Puoi vedere le Note da pubblicate da tutte le altre istanze federate con la nostra."
description2: "Nella parte superiore dello schermo, puoi scegliere una Timeline o l'altra in qualsiasi momento."
- description3: "Ci sono anche sequenze temporali di elenchi, sequenze temporali di canali, ecc. Per ulteriori dettagli, consultare la {link}.\nPuoi vedere anche Timeline delle liste di profili (se ne hai create), canali, ecc... Per i dettagli, c'è la {link}."
+ description3: "Ci sono anche sequenze temporali di elenchi, sequenze temporali di canali, ecc. Per ulteriori dettagli, consultare il {link}.\nPuoi vedere anche Timeline delle liste di profili (se ne hai create), canali, ecc... Per i dettagli, visita {link}."
_postNote:
title: "La Nota e le sue impostazioni"
description1: "Quando scrivi una Nota su Misskey, hai a disposizione varie opzioni. Il modulo di invio è simile a questo."
@@ -1405,13 +1301,13 @@ _initialTutorial:
useCases: "Utilizzalo per chiarire il contenuto della Nota, prima che sia letta. Come richiesto dal regolamento del server o per autoregolamentare spoiler e testi troppo espliciti."
_howToMakeAttachmentsSensitive:
title: "Come indicare che gli allegati sono espliciti?"
- description: "Si fa quando è richiesto dal regolamento del server o quando non devono essere visibili immediatamente."
+ description: "Contrassegnare gli allegati come espliciti, va fatto quando è richiesto dal regolamento del server o quando gli allegati non devono essere immediatamente visibili."
tryThisFile: "Prova a rendere esplicite le immagini allegate a questo modulo!"
_exampleNote:
- note: "AAA! Ho rotto il coperchio del natto... (fagioli di soia fermentati)"
- method: "Tocca il file, si aprirà il menu, scegli la voce \"Segna come esplicito\""
- sensitiveSucceeded: "Quando alleghi file, assicurati di indicare se è materiale esplicito in modo appropriato, decidi in base al regolamento dell'istanza."
- doItToContinue: "Imposta l'immagine come esplicita per procedere col tutorial."
+ note: "Ho fatto un errore aprendo il coperchio del natto... (fagioli di soia fermentati, particolarmente appiccicosi)"
+ method: "Per indicare che un allegato è esplicito, tocca il file per aprirne il menu e scegliere la voce \"Segna come esplicito\"."
+ sensitiveSucceeded: "Quando alleghi file, assicurati di indicare se è materiale esplicito, in modo appropriato, in base al regolamento del tuo server."
+ doItToContinue: "Impostando l'immagine come esplicita, potrai procedere col tutorial."
_done:
title: "Il tutorial è finito! 🎉"
description: "Queste sono solamente alcune delle funzionalità principali di Misskey. Per ulteriori informazioni, {link}."
@@ -1434,14 +1330,10 @@ _serverSettings:
fanoutTimelineDescription: "Attivando questa funzionalità migliori notevolmente la capacità delle Timeline di collezionare Note, riducendo il carico sul database. Tuttavia, aumenterà l'impiego di memoria RAM per Redis. Disattiva se il tuo server ha poca RAM o la funzionalità è irregolare."
fanoutTimelineDbFallback: "Elaborazione dati alternativa"
fanoutTimelineDbFallbackDescription: "Attivando l'elaborazione alternativa, verrà interrogato ulteriormente il database se la timeline non è nella cache. \nDisattivando, si può ridurre ulteriormente il carico del server, evitando l'elaborazione alternativa, ma limitando l'intervallo recuperabile delle timeline."
- reactionsBufferingDescription: "Attivando questa opzione, puoi migliorare significativamente le prestazioni durante la creazione delle reazioni e ridurre il carico sul database. Tuttavia, aumenterà l'impiego di memoria Redis."
- inquiryUrl: "URL di contatto"
- inquiryUrlDescription: "Specificare l'URL al modulo di contatto, oppure le informazioni con i dati di contatto dell'amministrazione."
- thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Per prevenire SPAM, questa impostazione verrà disattivata automaticamente, se non si rileva alcuna attività di moderazione durante un certo periodo di tempo."
_accountMigration:
moveFrom: "Migra un altro profilo dentro a questo"
moveFromSub: "Crea un alias verso un altro profilo remoto"
- moveFromLabel: "Profilo da cui migrare #{n}"
+ moveFromLabel: "Profilo da cui migrare:"
moveFromDescription: "Se desideri spostare i profili follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@istanza.it"
moveTo: "Migrare questo profilo verso un un altro"
moveToLabel: "Profilo verso cui migrare"
@@ -1745,7 +1637,6 @@ _role:
gtlAvailable: "Disponibilità della Timeline Federata"
ltlAvailable: "Disponibilità della Timeline Locale"
canPublicNote: "Scrivere Note con Visibilità Pubblica"
- mentionMax: "Numero massimo di menzioni in una nota"
canInvite: "Generare codici di invito all'istanza"
inviteLimit: "Limite di codici invito"
inviteLimitCycle: "Intervallo di emissione del codice di invito"
@@ -1754,7 +1645,6 @@ _role:
canManageAvatarDecorations: "Gestisce le decorazioni di immagini del profilo"
driveCapacity: "Capienza del Drive"
alwaysMarkNsfw: "Impostare sempre come esplicito (NSFW)"
- canUpdateBioMedia: "Può aggiornare foto profilo e di testata"
pinMax: "Quantità massima di Note in primo piano"
antennaMax: "Quantità massima di Antenne"
wordMuteMax: "Lunghezza massima del filtro parole"
@@ -1769,20 +1659,9 @@ _role:
canSearchNotes: "Ricercare nelle Note"
canUseTranslator: "Tradurre le Note"
avatarDecorationLimit: "Numero massimo di decorazioni foto profilo installabili"
- canImportAntennas: "Può importare Antenne"
- canImportBlocking: "Può importare Blocchi"
- canImportFollowing: "Può importare Following"
- canImportMuting: "Può importare Silenziati"
- canImportUserLists: "Può importare liste di Profili"
_condition:
- roleAssignedTo: "Assegnato a ruoli manualmente"
isLocal: "Profilo locale"
isRemote: "Profilo remoto"
- isCat: "È un gattino"
- isBot: "È un bot"
- isSuspended: "È sospeso"
- isLocked: "È in stato privato"
- isExplorable: "Autorizza la pubblicazione nei cataloghi"
createdLessThan: "Profilo creato da meno di N"
createdMoreThan: "Profilo creato da più di N"
followersLessThanOrEq: "Profilo con N follower o meno"
@@ -1852,7 +1731,6 @@ _plugin:
installWarn: "Si prega di installare soltanto estensioni che provengono da fonti affidabili."
manage: "Gestisci estensioni"
viewSource: "Visualizza sorgente"
- viewLog: "Mostra log"
_preferencesBackups:
list: "Elenco di impostazioni salvate in precedenza"
saveNew: "Nuovo salvataggio"
@@ -1882,8 +1760,6 @@ _aboutMisskey:
contributors: "Principali sostenitori"
allContributors: "Tutti i sostenitori"
source: "Codice sorgente"
- original: "Originale"
- thisIsModifiedVersion: "{name} sta usando una versione modificata diversa da Misskey originale."
translation: "Tradurre Misskey"
donate: "Sostieni Misskey"
morePatrons: "Apprezziamo sinceramente il supporto di tante altre persone. Grazie mille! 🥰"
@@ -1901,6 +1777,7 @@ _serverDisconnectedBehavior:
reload: "Ricarica automaticamente"
dialog: "Apri avviso in finestra"
quiet: "Visualizza avviso in modo discreto"
+ disabled: "Non visualizzare l'avviso"
_channel:
create: "Nuovo canale"
edit: "Gerisci canale"
@@ -1927,7 +1804,7 @@ _instanceMute:
instanceMuteDescription: "Disattiva tutte le note, le note di rinvio (condivisione) dell'istanza configurata, comprese le risposte agli utenti dell'istanza."
instanceMuteDescription2: "Impostazione separata da una nuova riga"
title: "Nasconde le note dell'istanza configurata."
- heading: "Istanze da silenziare"
+ heading: "Istanze da silenziare."
_theme:
explore: "Esplora temi"
install: "Installa un tema"
@@ -1991,6 +1868,7 @@ _theme:
buttonBg: "Sfondo del pulsante"
buttonHoverBg: "Sfondo del pulsante (sorvolato)"
inputBorder: "Inquadra casella di testo"
+ listItemHoverBg: "Sfondo della voce di elenco (sorvolato)"
driveFolderBg: "Sfondo della cartella di disco"
wallpaperOverlay: "Sovrapposizione dello sfondo"
badge: "Distintivo"
@@ -2002,6 +1880,8 @@ _sfx:
note: "Nota"
noteMy: "Mia nota"
notification: "Notifiche"
+ antenna: "Ricezione dell'antenna"
+ channel: "Notifiche di canale"
reaction: "Quando seleziono una reazione"
_soundSettings:
driveFile: "Suoni del Drive"
@@ -2010,7 +1890,6 @@ _soundSettings:
driveFileTypeWarnDescription: "Per favore, scegli un file di tipo audio"
driveFileDurationWarn: "La durata dell'audio è troppo lunga"
driveFileDurationWarnDescription: "Scegliere un audio lungo potrebbe interferire con l'uso di Misskey. Vuoi continuare lo stesso?"
- driveFileError: "Impossibile caricare l'audio. Si prega di modificare le impostazioni"
_ago:
future: "Futuro"
justNow: "Adesso"
@@ -2040,6 +1919,7 @@ _2fa:
registerTOTP: "Registra una App di autenticazione a due fattori (2FA/MFA)"
step1: "Innanzitutto, installa sul dispositivo un'App di autenticazione come {a} o {b}."
step2: "Quindi, tramite la App installata, scansiona questo codice QR."
+ step2Click: "Cliccando sul codice QR, puoi registrarlo con l'app di autenticazione o il portachiavi installato sul tuo dispositivo."
step2Uri: "Inserisci il seguente URL se desideri utilizzare una App per PC"
step3Title: "Inserisci il codice di verifica"
step3: "Inserite il token visualizzato nell'app e il gioco è fatto."
@@ -2063,7 +1943,6 @@ _2fa:
backupCodesDescription: "Puoi usare questi codici usa-e-getta per ottenere l'accesso al tuo profilo in caso sia impossibile usare l'App col codice OTP. Salvali in un posto sicuro."
backupCodeUsedWarning: "È stato usato un codice usa-e-getta. Per favore, riconfigura l'autenticazione a due fattori il prima possibile, nel caso la configurazione precedente abbia smesso di funzionare."
backupCodesExhaustedWarning: "Hai esaurito i codici usa-e-getta. Se l'App che genera il codice OTP non è più disponibile, non potrai più accedere al tuo profilo. Ripeti la configurazione per l'autenticazione a due fattori."
- moreDetailedGuideHere: "Informazioni dettagliate sull'autenticazione multi fattore (2FA/MFA)"
_permissions:
"read:account": "Visualizza le informazioni sul profilo"
"write:account": "Modifica le informazioni sul profilo"
@@ -2080,8 +1959,8 @@ _permissions:
"read:mutes": "Vedi i profili silenziati"
"write:mutes": "Gestisci i profili silenziati"
"write:notes": "Creare / Eliminare note"
- "read:notifications": "Visualizzare notifiche"
- "write:notifications": "Gestire notifiche"
+ "read:notifications": "Visualizza notifiche"
+ "write:notifications": "Gerisci notifiche"
"read:reactions": "Vedi reazioni"
"write:reactions": "Gerisci reazioni"
"write:votes": "Votare"
@@ -2114,6 +1993,7 @@ _permissions:
"read:admin:server-info": "Vedere le informazioni sul server"
"read:admin:show-moderation-log": "Vedere lo storico di moderazione"
"read:admin:show-user": "Vedere le informazioni private degli account utente"
+ "read:admin:show-users": "Vedere le informazioni private degli account utente"
"write:admin:suspend-user": "Sospendere i profili"
"write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili"
"write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili"
@@ -2203,7 +2083,7 @@ _widgets:
_userList:
chooseList: "Seleziona una lista"
clicker: "Cliccaggio"
- birthdayFollowings: "Compleanni del giorno"
+ birthdayFollowings: "Chi nacque oggi"
_cw:
hide: "Nascondere"
show: "Continua la lettura..."
@@ -2267,9 +2147,6 @@ _profile:
changeBanner: "Cambia intestazione"
verifiedLinkDescription: "Puoi verificare il tuo profilo mostrando una icona. Devi inserire la URL alla pagina che contiene un link al tuo profilo."
avatarDecorationMax: "Puoi aggiungere fino a {max} decorazioni."
- followedMessage: "Messaggio, quando qualcuno ti segue"
- followedMessageDescription: "Puoi impostare un breve messaggio da mostrare agli altri profili quando ti seguono."
- followedMessageDescriptionForLockedAccount: "Quando approvi una richiesta di follow, verrà visualizzato questo testo."
_exportOrImport:
allNotes: "Tutte le note"
favoritedNotes: "Note preferite"
@@ -2327,7 +2204,6 @@ _play:
title: "Titolo"
script: "Script"
summary: "Descrizione"
- visibilityDescription: "Impostarlo su privato significa che non verrà visualizzato sul tuo profilo, ma chiunque ha l'URL potrà comunque accedervi."
_pages:
newPage: "Crea pagina"
editPage: "Modifica pagina"
@@ -2362,7 +2238,6 @@ _pages:
eyeCatchingImageSet: "Imposta un'immagine attraente"
eyeCatchingImageRemove: "Elimina immagine attraente"
chooseBlock: "Aggiungi blocco"
- enterSectionTitle: "Inserisci il titolo della sezione"
selectType: "Seleziona tipo"
contentBlocks: "Contenuto"
inputBlocks: "Blocchi di input"
@@ -2373,8 +2248,6 @@ _pages:
section: "Sezione"
image: "Immagini"
button: "Pulsante"
- dynamic: "Riquadri dinamici"
- dynamicDescription: "Questo riquadro è obsoleto. Utilizza {play} da ora in poi."
note: "Nota integrata"
_note:
id: "ID nota"
@@ -2399,17 +2272,13 @@ _notification:
roleAssigned: "Ruolo assegnato"
emptyPushNotificationMessage: "Le notifiche push sono state aggiornate."
achievementEarned: "Obiettivo raggiunto"
- testNotification: "Provare la notifica"
- checkNotificationBehavior: "Provare il comportamento della notifica"
+ testNotification: "Prova la notifica"
+ checkNotificationBehavior: "Prova il comportamento della notifica"
sendTestNotification: "Spedisci una notifica di prova"
notificationWillBeDisplayedLikeThis: "La notifica apparirà così"
reactedBySomeUsers: "{n} reazioni"
- likedBySomeUsers: "{n} apprezzamenti"
renotedBySomeUsers: "{n} Rinota"
- followedBySomeUsers: "{n} follower"
- flushNotification: "Azzera le notifiche"
- exportOfXCompleted: "Abbiamo completato l'esportazione di {x}"
- login: "Autenticazione avvenuta"
+ followedBySomeUsers: "{n} nuovi follower"
_types:
all: "Tutto"
note: "Nuove Note"
@@ -2424,9 +2293,6 @@ _notification:
followRequestAccepted: "Richiesta di follow accettata"
roleAssigned: "Ruolo concesso"
achievementEarned: "Risultato raggiunto"
- exportCompleted: "Esportazione completata"
- login: "Accedi"
- test: "Prova la notifica"
app: "Notifiche da applicazioni"
_actions:
followBack: "Segui"
@@ -2436,7 +2302,6 @@ _deck:
alwaysShowMainColumn: "Mostra sempre la colonna principale"
columnAlign: "Allineare colonne"
addColumn: "Aggiungi colonna"
- newNoteNotificationSettings: "Preferenze per le notifiche di nuove Note"
configureColumn: "Impostazioni colonna"
swapLeft: "Sposta a sinistra"
swapRight: "Sposta a destra"
@@ -2465,8 +2330,8 @@ _deck:
direct: "Note Dirette"
roleTimeline: "Timeline Ruolo"
_dialog:
- charactersExceeded: "Hai superato il limite di {max} caratteri! ({current})"
- charactersBelow: "Sei al di sotto del minimo di {min} caratteri! ({current})"
+ charactersExceeded: "Hai superato il limite di {max} caratteri! ({corrente})"
+ charactersBelow: "Sei al di sotto del minimo di {min} caratteri! ({corrente})"
_disabledTimeline:
title: "Timeline disabilitata"
description: "Il ruolo in cui sei non ti permette di leggere questa timeline"
@@ -2475,10 +2340,9 @@ _drivecleaner:
orderByCreatedAtAsc: "Dal più vecchio al più recente"
_webhookSettings:
createWebhook: "Creazione Webhook"
- modifyWebhook: "Modifica Webhook"
name: "Nome"
secret: "Segreto"
- trigger: "Trigger"
+ events: "Quando eseguire il Webhook"
active: "Attivo"
_events:
follow: "Quando segui un profilo"
@@ -2488,29 +2352,6 @@ _webhookSettings:
renote: "Quando la Nota è Rinotata"
reaction: "Quando ricevo una reazione"
mention: "Quando mi menzionano"
- _systemEvents:
- abuseReport: "Quando arriva una segnalazione"
- abuseReportResolved: "Quando una segnalazione è risolta"
- userCreated: "Quando viene creato un profilo"
- inactiveModeratorsWarning: "Quando un profilo moderatore rimane inattivo per un determinato periodo"
- inactiveModeratorsInvitationOnlyChanged: "Quando la moderazione è rimasta inattiva per un determinato periodo e il sistema è cambiato in modalità \"solo inviti\""
- deleteConfirm: "Vuoi davvero eliminare il Webhook?"
- testRemarks: "Clicca il bottone a destra dell'interruttore, per provare l'invio di un webhook con dati fittizi."
-_abuseReport:
- _notificationRecipient:
- createRecipient: "Aggiungi destinatario della segnalazione"
- modifyRecipient: "Modifica destinatario della segnalazione"
- recipientType: "Tipo di notifica"
- _recipientType:
- mail: "Email"
- webhook: "Webhook"
- _captions:
- mail: "Quando ricevi un abuso, notifica l'amministrazione via email"
- webhook: "Spedire una notifica al SystemWebhook specificato (sia quando si riceve una segnalazione, che quando viene risolta)"
- keywords: "Parole chiave"
- notifiedUser: "Profili da notificare"
- notifiedWebhook: "Webhook da usare"
- deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?"
_moderationLogTypes:
createRole: "Ruolo creato"
deleteRole: "Ruolo eliminato"
@@ -2535,12 +2376,9 @@ _moderationLogTypes:
resetPassword: "Password azzerata"
suspendRemoteInstance: "Istanza remota sospesa"
unsuspendRemoteInstance: "Istanza remota riattivata"
- updateRemoteInstanceNote: "Aggiornamento del promemoria di moderazione per il server remoto"
markSensitiveDriveFile: "File nel Drive segnato come esplicito"
unmarkSensitiveDriveFile: "File nel Drive segnato come non esplicito"
resolveAbuseReport: "Segnalazione risolta"
- forwardAbuseReport: "Segnalazione inoltrata"
- updateAbuseReportNote: "Ha aggiornato la segnalazione"
createInvitation: "Genera codice di invito"
createAd: "Banner creato"
deleteAd: "Banner eliminato"
@@ -2550,16 +2388,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "Eliminazione decorazione della foto profilo"
unsetUserAvatar: "Rimossa foto profilo"
unsetUserBanner: "Rimossa intestazione profilo"
- createSystemWebhook: "Crea un SystemWebhook"
- updateSystemWebhook: "Modifica SystemWebhook"
- deleteSystemWebhook: "Elimina SystemWebhook"
- createAbuseReportNotificationRecipient: "Crea destinatario per le notifiche di segnalazioni"
- updateAbuseReportNotificationRecipient: "Aggiorna destinatario notifiche di segnalazioni"
- deleteAbuseReportNotificationRecipient: "Elimina destinatario notifiche di segnalazioni"
- deleteAccount: "Quando viene eliminato un profilo"
- deletePage: "Pagina eliminata"
- deleteFlash: "Play eliminato"
- deleteGalleryPost: "Eliminazione pubblicazione nella Galleria"
_fileViewer:
title: "Dettagli del file"
type: "Tipo di file"
@@ -2668,45 +2496,7 @@ _reversi:
opponentHasSettingsChanged: "L'avversario ha cambiato configurazione"
allowIrregularRules: "Regole inconsuete (completamente libere)"
disallowIrregularRules: "Impedire le regole inconsuete"
- showBoardLabels: "Mostra le coordinate del gioco"
- useAvatarAsStone: "Immagini profilo come pedine"
_offlineScreen:
title: "Scollegato. Impossibile connettersi al server"
header: "Impossibile connettersi al server"
-_urlPreviewSetting:
- title: "Impostazioni per l'anteprima delle URL"
- enable: "Attiva l'anteprima delle URL"
- timeout: "Timeout dell'anteprima in millisecondi"
- timeoutDescription: "Impegna al massimo il tempo indicato, altrimenti ignora l'anteprima"
- maximumContentLength: "Grandezza del contenuto (Content-Length in byte)"
- maximumContentLengthDescription: "Se la grandezza supera il valore, l'anteprima verrà ignorata."
- requireContentLength: "Genenerare l'anteprima solo quando è definito Content-Length"
- requireContentLengthDescription: "In assenza di questo parametro dal server remoto, l'anteprima verrà ignorata."
- userAgent: "User-Agent"
- userAgentDescription: "Definire con quale User-Agent si intende identificarsi durante l'acquisizione di un'anteprima. Se è vuoto, useremo il valore predefinito."
- summaryProxy: "Endpoint proxy che genera l'anteprima"
- summaryProxyDescription: "Genera anteprime utilizzando un proxy Summaly anziché Misskey."
- summaryProxyDescription2: "I parametri sono collegano al proxy come stringa query. Se il proxy non li supporta, verranno ignorati."
-_mediaControls:
- pip: "Sovraimpressione"
- playbackRate: "Velocità di riproduzione"
- loop: "Ripetizione infinita"
-_contextMenu:
- title: "Menu contestuale"
- app: "Applicazione"
- appWithShift: "Applicazione Shift+Tasto"
- native: "Interfaccia utente del browser"
-_embedCodeGen:
- title: "Personalizza il codice di incorporamento"
- header: "Mostra la testata"
- autoload: "Carica automaticamente di più (sconsigliato)"
- maxHeight: "Altezza massima"
- maxHeightDescription: "Specifica un valore per evitare che continui a crescere verticalmente. Il valore 0 disabilita il limite d'altezza."
- maxHeightWarn: "L'altezza massima è disabilitata (0). Se l'effetto è indesiderato, prova a impostare l'altezza massima a un valore specifico."
- previewIsNotActual: "Poiché supera l'intervallo che può essere visualizzato in anteprima, la visualizzazione vera e propria sarà diversa quando effettivamente incorporata."
- rounded: "Bordo arrotondato"
- border: "Aggiungi un bordo al contenitore"
- applyToPreview: "Applica all'anteprima"
- generateCode: "Crea il codice di incorporamento"
- codeGenerated: "Codice generato"
- codeGeneratedDescription: "Incolla il codice appena generato sul tuo sito web."
+
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index c448d4d50a..439210f45e 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1,16 +1,13 @@
_lang_: "日本語"
headlineMisskey: "ノートでつながるネットワーク"
-introMisskey: "ようこそ!Misskeyは、オープンソースの分散型マイクロブログサービスです。\n「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
-poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォームMisskey のサーバーのひとつです。"
+introMisskey: "ようこそ!Sharkeyは、オープンソースの分散型マイクロブログサービスです。\n「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
+poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォームSharkey のサーバーのひとつです。"
monthAndDay: "{month}月 {day}日"
search: "検索"
notifications: "通知"
username: "ユーザー名"
password: "パスワード"
-initialPasswordForSetup: "初期設定開始用パスワード"
-initialPasswordIsIncorrect: "初期設定開始用のパスワードが違います。"
-initialPasswordForSetupDescription: "Misskeyを自分でインストールした場合は、設定ファイルに入力したパスワードを使用してください。\nMisskeyのホスティングサービスなどを使用している場合は、提供されたパスワードを使用してください。\nパスワードを設定していない場合は、空欄にしたまま続行してください。"
forgotPassword: "パスワードを忘れた"
fetchingAsApObject: "連合に照会中"
ok: "OK"
@@ -18,7 +15,7 @@ gotIt: "わかった"
cancel: "キャンセル"
noThankYou: "やめておく"
enterUsername: "ユーザー名を入力"
-renotedBy: "{user}がリノート"
+renotedBy: "{user}がブースト"
noNotes: "ノートはありません"
noNotifications: "通知はありません"
instance: "サーバー"
@@ -37,6 +34,7 @@ signup: "新規登録"
uploading: "アップロード中"
save: "保存"
users: "ユーザー"
+approvals: "承認"
addUser: "ユーザーを追加"
favorite: "お気に入り"
favorites: "お気に入り"
@@ -48,22 +46,22 @@ pin: "ピン留め"
unpin: "ピン留め解除"
copyContent: "内容をコピー"
copyLink: "リンクをコピー"
-copyLinkRenote: "リノートのリンクをコピー"
+copyLinkRenote: "ブーストのリンクをコピー"
delete: "削除"
deleteAndEdit: "削除して編集"
-deleteAndEditConfirm: "このノートを削除してもう一度編集しますか?このノートへのリアクション、リノート、返信も全て削除されます。"
+deleteAndEditConfirm: "このノートを削除してもう一度編集しますか?このノートへのリアクション、ブースト、返信も全て削除されます。"
addToList: "リストに追加"
addToAntenna: "アンテナに追加"
sendMessage: "メッセージを送信"
copyRSS: "RSSをコピー"
copyUsername: "ユーザー名をコピー"
+openRemoteProfile: "リモートプロフィールを開く"
copyUserId: "ユーザーIDをコピー"
copyNoteId: "ノートIDをコピー"
copyFileId: "ファイルIDをコピー"
copyFolderId: "フォルダーIDをコピー"
copyProfileUrl: "プロフィールURLをコピー"
searchUser: "ユーザーを検索"
-searchThisUsersNotes: "ユーザーのノートを検索"
reply: "返信"
loadMore: "もっと見る"
showMore: "もっと見る"
@@ -109,17 +107,16 @@ followRequests: "フォロー申請"
unfollow: "フォロー解除"
followRequestPending: "フォロー許可待ち"
enterEmoji: "絵文字を入力"
-renote: "リノート"
-unrenote: "リノート解除"
-renoted: "リノートしました。"
-renotedToX: "{name} にリノートしました。"
-cantRenote: "この投稿はリノートできません。"
-cantReRenote: "リノートをリノートすることはできません。"
+renote: "ブースト"
+unrenote: "ブースト解除"
+renoted: "ブーストしました。"
+quoted: "引用。"
+rmboost: "ブースト解除しました。"
+cantRenote: "この投稿はブーストできません。"
+cantReRenote: "ブーストをブーストすることはできません。"
quote: "引用"
-inChannelRenote: "チャンネル内リノート"
+inChannelRenote: "チャンネル内ブースト"
inChannelQuote: "チャンネル内引用"
-renoteToChannel: "チャンネルにリノート"
-renoteToOtherChannel: "他のチャンネルにリノート"
pinnedNote: "ピン留めされたノート"
pinned: "ピン留め"
you: "あなた"
@@ -143,22 +140,25 @@ unmarkAsSensitive: "センシティブを解除する"
enterFileName: "ファイル名を入力"
mute: "ミュート"
unmute: "ミュート解除"
-renoteMute: "リノートをミュート"
-renoteUnmute: "リノートのミュートを解除"
+renoteMute: "ブーストをミュート"
+renoteUnmute: "ブーストのミュートを解除"
block: "ブロック"
unblock: "ブロック解除"
+markAsNSFW: "ユーザーのすべてのメディアをNSFWとしてマークする"
suspend: "凍結"
unsuspend: "解凍"
blockConfirm: "ブロックしますか?"
unblockConfirm: "ブロック解除しますか?"
+nsfwConfirm: "このアカウントからのすべてのメディアをNSFWとしてマークしてもよろしいですか?"
+unNsfwConfirm: "このアカウントのすべてのメディアをNSFWとしてマーク解除してもよろしいですか?"
suspendConfirm: "凍結しますか?"
+approveConfirm: "このアカウントを承認してもよろしいですか?"
unsuspendConfirm: "解凍しますか?"
selectList: "リストを選択"
editList: "リストを編集"
selectChannel: "チャンネルを選択"
selectAntenna: "アンテナを選択"
editAntenna: "アンテナを編集"
-createAntenna: "アンテナを作成"
selectWidget: "ウィジェットを選択"
editWidgets: "ウィジェットを編集"
editWidgetsExit: "編集を終了"
@@ -175,9 +175,11 @@ youCanCleanRemoteFilesCache: "ファイル管理の🗑️ボタンで全ての
cacheRemoteSensitiveFiles: "リモートのセンシティブなファイルをキャッシュする"
cacheRemoteSensitiveFilesDescription: "この設定を無効にすると、リモートのセンシティブなファイルはキャッシュせず直リンクするようになります。"
flagAsBot: "Botとして設定"
-flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Misskeyのシステム上での扱いがBotに合ったものになります。"
+flagAsBotDescription: "このアカウントがプログラムによって運用される場合は、このフラグをオンにします。オンにすると、反応の連鎖を防ぐためのフラグとして他の開発者に役立ったり、Sharkeyのシステム上での扱いがBotに合ったものになります。"
flagAsCat: "にゃああああああああああああああ!!!!!!!!!!!!"
flagAsCatDescription: "にゃにゃにゃ??"
+flagSpeakAsCat: "猫語で話す"
+flagSpeakAsCatDescription: "有効にすると、あなたの投稿の 「な」を「にゃ」にします。"
flagShowTimelineReplies: "タイムラインにノートへの返信を表示する"
flagShowTimelineRepliesDescription: "オンにすると、タイムラインにユーザーのノート以外にもそのユーザーの他のノートへの返信を表示します。"
autoAcceptFollowed: "フォロー中ユーザーからのフォロリクを自動承認"
@@ -185,10 +187,6 @@ addAccount: "アカウントを追加"
reloadAccountsList: "アカウントリストの情報を更新"
loginFailed: "ログインに失敗しました"
showOnRemote: "リモートで表示"
-continueOnRemote: "リモートで続行"
-chooseServerOnMisskeyHub: "Misskey Hubからサーバーを選択"
-specifyServerHost: "サーバーのドメインを直接指定"
-inputHostName: "ドメインを入力してください"
general: "全般"
wallpaper: "壁紙"
setWallpaper: "壁紙を設定"
@@ -199,7 +197,6 @@ followConfirm: "{name}をフォローしますか?"
proxyAccount: "プロキシアカウント"
proxyAccountDescription: "プロキシアカウントは、特定の条件下でユーザーのリモートフォローを代行するアカウントです。例えば、ユーザーがリモートユーザーをリストに入れたとき、リストに入れられたユーザーを誰もフォローしていないとアクティビティがサーバーに配達されないため、代わりにプロキシアカウントがフォローするようにします。"
host: "ホスト"
-selectSelf: "自分を選択"
selectUser: "ユーザーを選択"
recipient: "宛先"
annotation: "注釈"
@@ -213,9 +210,8 @@ charts: "チャート"
perHour: "1時間ごと"
perDay: "1日ごと"
stopActivityDelivery: "アクティビティの配送を停止"
-blockThisInstance: "このサーバーをブロック"
-silenceThisInstance: "サーバーをサイレンス"
-mediaSilenceThisInstance: "サーバーをメディアサイレンス"
+blockThisInstance: "このインスタンスをブロック"
+silenceThisInstance: "インスタンスをサイレンス"
operations: "操作"
software: "ソフトウェア"
version: "バージョン"
@@ -236,11 +232,7 @@ clearCachedFilesConfirm: "キャッシュされたリモートファイルをす
blockedInstances: "ブロックしたサーバー"
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定します。ブロックされたサーバーは、このインスタンスとやり取りできなくなります。"
silencedInstances: "サイレンスしたサーバー"
-silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定します。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになります。ブロックしたインスタンスには影響しません。"
-mediaSilencedInstances: "メディアサイレンスしたサーバー"
-mediaSilencedInstancesDescription: "メディアサイレンスしたいサーバーのホストを改行で区切って設定します。メディアサイレンスされたサーバーに所属するアカウントによるファイルはすべてセンシティブとして扱われ、カスタム絵文字が使用できないようになります。ブロックしたインスタンスには影響しません。"
-federationAllowedHosts: "連合を許可するサーバー"
-federationAllowedHostsDescription: "連合を許可するサーバーのホストを改行で区切って設定します。"
+silencedInstancesDescription: "サイレンスしたいインスタンスのホストを改行で区切って設定します。サイレンスされたインスタンスに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなります。ブロックしたインスタンスには影響しません。"
muteAndBlock: "ミュートとブロック"
mutedUsers: "ミュートしたユーザー"
blockedUsers: "ブロックしたユーザー"
@@ -248,7 +240,7 @@ noUsers: "ユーザーはいません"
editProfile: "プロフィールを編集"
noteDeleteConfirm: "このノートを削除しますか?"
pinLimitExceeded: "これ以上ピン留めできません"
-intro: "Misskeyのインストールが完了しました!管理者アカウントを作成しましょう。"
+intro: "Sharkeyのインストールが完了しました!管理者アカウントを作成しましょう。"
done: "完了"
processing: "処理中"
preview: "プレビュー"
@@ -331,7 +323,6 @@ selectFile: "ファイルを選択"
selectFiles: "ファイルを選択"
selectFolder: "フォルダーを選択"
selectFolders: "フォルダーを選択"
-fileNotSelected: "ファイルが選択されていません"
renameFile: "ファイル名を変更"
folderName: "フォルダー名"
createFolder: "フォルダーを作成"
@@ -339,7 +330,6 @@ renameFolder: "フォルダー名を変更"
deleteFolder: "フォルダーを削除"
folder: "フォルダー"
addFile: "ファイルを追加"
-showFile: "ファイルを表示"
emptyDrive: "ドライブは空です"
emptyFolder: "フォルダーは空です"
unableToDelete: "削除できません"
@@ -352,6 +342,7 @@ copyUrl: "URLをコピー"
rename: "名前を変更"
avatar: "アイコン"
banner: "バナー"
+background: "背景"
displayOfSensitiveMedia: "センシティブなメディアの表示"
whenServerDisconnected: "サーバーとの接続が失われたとき"
disconnectedFromServer: "サーバーから切断されました"
@@ -420,7 +411,6 @@ name: "名前"
antennaSource: "受信ソース"
antennaKeywords: "受信キーワード"
antennaExcludeKeywords: "除外キーワード"
-antennaExcludeBots: "Botアカウントを除外"
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
notifyAntenna: "新しいノートを通知する"
withFileAntenna: "ファイルが添付されたノートのみ"
@@ -444,7 +434,7 @@ exploreFediverse: "Fediverseを探索"
popularTags: "人気のタグ"
userList: "リスト"
about: "情報"
-aboutMisskey: "Misskeyについて"
+aboutMisskey: "Sharkeyについて"
administrator: "管理者"
token: "確認コード"
2fa: "二要素認証"
@@ -454,7 +444,6 @@ totpDescription: "認証アプリを使ってワンタイムパスワードを
moderator: "モデレーター"
moderation: "モデレーション"
moderationNote: "モデレーションノート"
-moderationNoteDescription: "モデレーター間でだけ共有されるメモを記入することができます。"
addModerationNote: "モデレーションノートを追加する"
moderationLogs: "モデログ"
nUsersMentioned: "{n}人が投稿"
@@ -487,14 +476,14 @@ enable: "有効にする"
next: "次"
retype: "再入力"
noteOf: "{user}のノート"
+expandAllCws: "すべての返信の内容を表示する"
+collapseAllCws: "すべての返信の内容を隠す"
quoteAttached: "引用付き"
quoteQuestion: "引用として添付しますか?"
-attachAsFileQuestion: "クリップボードのテキストが長いです。テキストファイルとして添付しますか?"
noMessagesYet: "まだチャットはありません"
newMessageExists: "新しいメッセージがあります"
onlyOneFileCanBeAttached: "メッセージに添付できるファイルはひとつです"
-signinRequired: "続行する前に、登録またはログインが必要です"
-signinOrContinueOnRemote: "続行するには、お使いのサーバーに移動するか、このサーバーに登録・ログインする必要があります"
+signinRequired: "続行する前に、サインアップまたはサインインが必要です"
invitations: "招待"
invitationCode: "招待コード"
checking: "確認しています"
@@ -516,12 +505,8 @@ uiLanguage: "UIの表示言語"
aboutX: "{x}について"
emojiStyle: "絵文字のスタイル"
native: "ネイティブ"
-menuStyle: "メニューのスタイル"
-style: "スタイル"
-drawer: "ドロワー"
-popup: "ポップアップ"
+disableDrawer: "メニューをドロワーで表示しない"
showNoteActionsOnlyHover: "ノートのアクションをホバー時のみ表示する"
-showReactionsCount: "ノートのリアクション数を表示する"
noHistory: "履歴はありません"
signinHistory: "ログイン履歴"
enableAdvancedMfm: "高度なMFMを有効にする"
@@ -534,6 +519,7 @@ createAccount: "アカウントを作成"
existingAccount: "既存のアカウント"
regenerate: "再生成"
fontSize: "フォントサイズ"
+cornerRadius: "コーナーの丸み"
mediaListWithOneImageAppearance: "画像が1枚のみのメディアリストの高さ"
limitTo: "{x}を上限に"
noFollowRequests: "フォロー申請はありません"
@@ -570,6 +556,8 @@ objectStorageUseProxy: "Proxyを利用する"
objectStorageUseProxyDesc: "API接続にproxyを利用しない場合はオフにしてください"
objectStorageSetPublicRead: "アップロード時に'public-read'を設定する"
s3ForcePathStyleDesc: "s3ForcePathStyleを有効にすると、バケット名をURLのホスト名ではなくパスの一部として指定することを強制します。セルフホストされたMinioなどの使用時に有効にする必要がある場合があります。"
+deeplFreeMode: "DeepLX-JS を使用する (認証キーなし)"
+deeplFreeModeDescription: "ヘルプが必要ですか? DeepLX-JSのセットアップ方法については、ドキュメントを参照してください。"
serverLogs: "サーバーログ"
deleteAll: "全て削除"
showFixedPostForm: "タイムライン上部に投稿フォームを表示する"
@@ -601,9 +589,7 @@ sort: "ソート"
ascendingOrder: "昇順"
descendingOrder: "降順"
scratchpad: "スクラッチパッド"
-scratchpadDescription: "スクラッチパッドは、AiScriptの実験環境を提供します。Misskeyと対話するコードの記述、実行、結果の確認ができます。"
-uiInspector: "UIインスペクター"
-uiInspectorDescription: "メモリ上に存在しているUIコンポーネントのインスタンスの一覧を見ることができます。UIコンポーネントはUi:C:系関数により生成されます。"
+scratchpadDescription: "スクラッチパッドは、AiScriptの実験環境を提供します。Sharkeyと対話するコードの記述、実行、結果の確認ができます。"
output: "出力"
script: "スクリプト"
disablePagesScript: "Pagesのスクリプトを無効にする"
@@ -713,14 +699,17 @@ behavior: "動作"
sample: "サンプル"
abuseReports: "通報"
reportAbuse: "通報"
-reportAbuseRenote: "リノートを通報"
+reportAbuseRenote: "ブーストを通報"
reportAbuseOf: "{name}を通報する"
-fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のノートやページなどがある場合はそのURLも記入してください。"
+fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のノートがある場合はそのURLも記入してください。"
abuseReported: "内容が送信されました。ご報告ありがとうございました。"
reporter: "通報者"
reporteeOrigin: "通報先"
reporterOrigin: "通報元"
+forwardReport: "リモートサーバーに通報を転送する"
+forwardReportIsAnonymous: "リモートサーバーからはあなたの情報は見れず、匿名のシステムアカウントとして表示されます。"
send: "送信"
+abuseMarkAsResolved: "対応済みにする"
openInNewTab: "新しいタブで開く"
openInSideView: "サイドビューで開く"
defaultNavigationBehaviour: "デフォルトのナビゲーション"
@@ -739,14 +728,14 @@ unclip: "クリップ解除"
confirmToUnclipAlreadyClippedNote: "このノートはすでにクリップ「{name}」に含まれています。ノートをこのクリップから除外しますか?"
public: "パブリック"
private: "非公開"
-i18nInfo: "Misskeyは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。"
+i18nInfo: "Sharkeyは有志によって様々な言語に翻訳されています。{link}で翻訳に協力できます。"
manageAccessTokens: "アクセストークンの管理"
accountInfo: "アカウント情報"
notesCount: "ノートの数"
repliesCount: "返信した数"
-renotesCount: "リノートした数"
+renotesCount: "ブーストした数"
repliedCount: "返信された数"
-renotedCount: "リノートされた数"
+renotedCount: "ブーストされた数"
followingCount: "フォロー数"
followersCount: "フォロワー数"
sentReactionsCount: "リアクションした数"
@@ -779,13 +768,15 @@ thisIsExperimentalFeature: "これは実験的な機能です。仕様が変更
developer: "開発者"
makeExplorable: "アカウントを見つけやすくする"
makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らなくなります。"
+makeIndexable: "公開ノートをインデックス不可にする"
+makeIndexableDescription: "ノート検索があなたの公開ノートをインデックス化しないようにします。"
showGapBetweenNotesInTimeline: "タイムラインのノートを離して表示"
duplicate: "複製"
left: "左"
center: "中央"
wide: "広い"
narrow: "狭い"
-reloadToApplySetting: "設定はページリロード後に反映されます。"
+reloadToApplySetting: "設定はページリロード後に反映されます。今すぐリロードしますか?"
needReloadToApply: "反映には再起動が必要です。"
showTitlebar: "タイトルバーを表示する"
clearCache: "キャッシュをクリア"
@@ -793,7 +784,7 @@ onlineUsersCount: "{n}人がオンライン"
nUsers: "{n}ユーザー"
nNotes: "{n}ノート"
sendErrorReports: "エラーリポートを送信"
-sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がMisskeyに共有され、ソフトウェアの品質向上に役立てることができます。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。"
+sendErrorReportsDescription: "オンにすると、問題が発生したときにエラーの詳細情報がSharkeyに共有され、ソフトウェアの品質向上に役立てることができます。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴などが含まれます。"
myTheme: "マイテーマ"
backgroundColor: "背景"
accentColor: "アクセント"
@@ -857,7 +848,6 @@ administration: "管理"
accounts: "アカウント"
switch: "切り替え"
noMaintainerInformationWarning: "管理者情報が設定されていません。"
-noInquiryUrlWarning: "問い合わせ先URLが設定されていません。"
noBotProtectionWarning: "Botプロテクションが設定されていません。"
configure: "設定する"
postToGallery: "ギャラリーへ投稿"
@@ -888,7 +878,7 @@ hashtags: "ハッシュタグ"
troubleshooting: "トラブルシューティング"
useBlurEffect: "UIにぼかし効果を使用"
learnMore: "詳しく"
-misskeyUpdated: "Misskeyが更新されました!"
+misskeyUpdated: "Sharkeyが更新されました!"
whatIsNew: "更新情報を見る"
translate: "翻訳"
translatedFrom: "{x}から翻訳"
@@ -908,6 +898,7 @@ itsOff: "オフになっています"
on: "オン"
off: "オフ"
emailRequiredForSignup: "アカウント登録にメールアドレスを必須にする"
+approvalRequiredForSignup: "新規ユーザーの承認が必要"
unread: "未読"
filter: "フィルタ"
controlPanel: "コントロールパネル"
@@ -922,8 +913,8 @@ followersVisibility: "フォロワーの公開範囲"
continueThread: "さらにスレッドを見る"
deleteAccountConfirm: "アカウントが削除されます。よろしいですか?"
incorrectPassword: "パスワードが間違っています。"
-incorrectTotp: "ワンタイムパスワードが間違っているか、期限切れになっています。"
voteConfirm: "「{choice}」に投票しますか?"
+voteConfirmMulti: "「{choice}」に投票しますか?\n 確認後、選択肢を増やすことができます。"
hide: "隠す"
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
welcomeBackWithName: "おかえりなさい、{name}さん"
@@ -959,6 +950,7 @@ recentNHours: "直近{n}時間"
recentNDays: "直近{n}日"
noEmailServerWarning: "メールサーバーの設定がされていません。"
thereIsUnresolvedAbuseReportWarning: "未対応の通報があります。"
+pendingUserApprovals: "承認待ちのユーザーがいる。"
recommended: "推奨"
check: "チェック"
driveCapOverrideLabel: "このユーザーのドライブ容量上限を変更"
@@ -967,9 +959,20 @@ requireAdminForView: "閲覧するには管理者アカウントでログイン
isSystemAccount: "システムにより自動で作成・管理されているアカウントです。"
typeToConfirm: "この操作を行うには {x} と入力してください"
deleteAccount: "アカウント削除"
+approveAccount: "承認する"
+denyAccount: "拒否と削除"
+approved: "承認済み"
+notApproved: "承認されていない"
+approvalStatus: "承認状況"
document: "ドキュメント"
numberOfPageCache: "ページキャッシュ数"
numberOfPageCacheDescription: "多くすると利便性が向上しますが、負荷とメモリ使用量が増えます。"
+numberOfReplies: "スレッド内の返信数"
+numberOfRepliesDescription: "この数値を大きくすると、より多くの返信が表示されます。この値を大きくしすぎると、返信が窮屈になり、読めなくなることがあります。"
+boostSettings: "ブースト設定"
+showVisibilitySelectorOnBoost: "可視性セレクタを表示"
+showVisibilitySelectorOnBoostDescription: "無効の場合、以下で定義されるデフォルトの可視性が使用され、セレクタは表示されません。"
+visibilityOnBoost: "デフォルトのブースト可視性の設定"
logoutConfirm: "ログアウトしますか?"
lastActiveDate: "最終利用日時"
statusbar: "ステータスバー"
@@ -1014,12 +1017,14 @@ cannotLoad: "読み込めません"
numberOfProfileView: "プロフィール表示回数"
like: "いいね!"
unlike: "いいねを解除"
+defaultLike: "絵文字のようなデフォルト"
numberOfLikes: "いいね数"
show: "表示"
neverShow: "今後表示しない"
remindMeLater: "また後で"
-didYouLikeMisskey: "Misskeyを気に入っていただけましたか?"
-pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!"
+didYouLikeMisskey: "Sharkeyを気に入っていただけましたか?"
+pleaseDonate: "Sharkeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!"
+pleaseDonateInstance: "インスタンス管理者への寄付によって{host}を直接サポートすることもできます。"
correspondingSourceIsAvailable: "対応するソースコードは{anchor}から利用可能です。"
roles: "ロール"
role: "ロール"
@@ -1047,8 +1052,12 @@ thisPostMayBeAnnoying: "この投稿は迷惑になる可能性があります
thisPostMayBeAnnoyingHome: "ホームに投稿"
thisPostMayBeAnnoyingCancel: "やめる"
thisPostMayBeAnnoyingIgnore: "このまま投稿"
-collapseRenotes: "リノートのスマート省略"
-collapseRenotesDescription: "リアクションやリノートをしたことがあるノートをたたんで表示します。"
+thisPostIsMissingAltTextCancel: "やめる"
+thisPostIsMissingAltTextIgnore: "このまま投稿"
+thisPostIsMissingAltText: "この投稿に添付されたファイルの 1 つに代替テキストがありません。すべての添付ファイルに代替テキストが含まれていることを確認してください。"
+collapseRenotes: "見たことのあるブーストを省略して表示"
+collapseFiles: "ファイルを折りたたむ"
+autoloadConversation: "返信に会話を読み込む"
internalServerError: "サーバー内部エラー"
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
copyErrorInfo: "エラー情報をコピー"
@@ -1059,6 +1068,7 @@ disableFederationConfirm: "連合なしにしますか?"
disableFederationConfirmWarn: "連合なしにしても投稿は非公開になりません。ほとんどの場合、連合なしにする必要はありません。"
disableFederationOk: "連合なしにする"
invitationRequiredToRegister: "現在このサーバーは招待制です。招待コードをお持ちの方のみ登録できます。"
+approvalRequiredToRegister: "このインスタンスは、登録理由を指定したユーザーのみを受け入れています。"
emailNotSupported: "このサーバーではメール配信はサポートされていません"
postToTheChannel: "チャンネルに投稿"
cannotBeChangedLater: "後から変更できません。"
@@ -1087,7 +1097,6 @@ retryAllQueuesConfirmTitle: "今すぐ再試行しますか?"
retryAllQueuesConfirmText: "一時的にサーバーの負荷が増大することがあります。"
enableChartsForRemoteUser: "リモートユーザーのチャートを生成"
enableChartsForFederatedInstances: "リモートサーバーのチャートを生成"
-enableStatsForFederatedInstances: "リモートサーバーの情報を取得"
showClipButtonInNoteFooter: "ノートのアクションにクリップを追加"
reactionsDisplaySize: "リアクションの表示サイズ"
limitWidthOfReaction: "リアクションの最大横幅を制限し、縮小して表示する"
@@ -1102,10 +1111,11 @@ accountMoved: "このユーザーは新しいアカウントに移行しまし
accountMovedShort: "このアカウントは移行されています"
operationForbidden: "この操作はできません"
forceShowAds: "常に広告を表示する"
+oneko: "猫友達 :3"
addMemo: "メモを追加"
editMemo: "メモを編集"
reactionsList: "リアクション一覧"
-renotesList: "リノート一覧"
+renotesList: "ブースト一覧"
notificationDisplay: "通知の表示"
leftTop: "左上"
rightTop: "右上"
@@ -1123,8 +1133,6 @@ preservedUsernames: "予約ユーザー名"
preservedUsernamesDescription: "予約するユーザー名を改行で列挙します。ここで指定されたユーザー名はアカウント作成時に使えなくなりますが、管理者によるアカウント作成時はこの制限を受けません。また、既に存在するアカウントも影響を受けません。"
createNoteFromTheFile: "このファイルからノートを作成"
archive: "アーカイブ"
-archived: "アーカイブ済み"
-unarchive: "アーカイブ解除"
channelArchiveConfirmTitle: "{name}をアーカイブしますか?"
channelArchiveConfirmDescription: "アーカイブすると、チャンネル一覧や検索結果に表示されなくなり、新たな書き込みもできなくなります。"
thisChannelArchived: "このチャンネルはアーカイブされています。"
@@ -1135,9 +1143,6 @@ preventAiLearning: "生成AIによる学習を拒否"
preventAiLearningDescription: "外部の文章生成AIや画像生成AIに対して、投稿したノートや画像などのコンテンツを学習の対象にしないように要求します。これはnoaiフラグをHTMLレスポンスに含めることによって実現されますが、この要求に従うかはそのAI次第であるため、学習を完全に防止するものではありません。"
options: "オプション"
specifyUser: "ユーザー指定"
-lookupConfirm: "照会しますか?"
-openTagPageConfirm: "ハッシュタグのページを開きますか?"
-specifyHost: "ホスト指定"
failedToPreviewUrl: "プレビューできません"
update: "更新"
rolesThatCanBeUsedThisEmojiAsReaction: "リアクションとして使えるロール"
@@ -1146,11 +1151,15 @@ rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロー
cancelReactionConfirm: "リアクションを取り消しますか?"
changeReactionConfirm: "リアクションを変更しますか?"
later: "あとで"
-goToMisskey: "Misskeyへ"
+goToMisskey: "Sharkeyへ"
additionalEmojiDictionary: "絵文字の追加辞書"
installed: "インストール済み"
branding: "ブランディング"
enableServerMachineStats: "サーバーのマシン情報を公開する"
+enableAchievements: "実績を有効にする"
+turnOffAchievements: "オフにすると実績システムは無効になります。"
+enableBotTrending: "botのハッシュタグ追加を許可する"
+turnOffBotTrending: "オフにするとボットがハッシュタグを入力しなくなります。"
enableIdenticonGeneration: "ユーザーごとのIdenticon生成を有効にする"
turnOffToImprovePerformance: "オフにするとパフォーマンスが向上します。"
createInviteCode: "招待コードを作成"
@@ -1181,22 +1190,23 @@ pastAnnouncements: "過去のお知らせ"
youHaveUnreadAnnouncements: "未読のお知らせがあります。"
useSecurityKey: "ブラウザまたはデバイスの指示に従って、セキュリティキーまたはパスキーを使用してください。"
replies: "返信"
-renotes: "リノート"
+renotes: "ブースト"
loadReplies: "返信を見る"
loadConversation: "会話を見る"
pinnedList: "ピン留めされたリスト"
keepScreenOn: "デバイスの画面を常にオンにする"
+clickToOpen: "クリックしてノートを開く"
+showBots: "ボットをタイムラインに表示"
verifiedLink: "このリンク先の所有者であることが確認されました"
notifyNotes: "投稿を通知"
unnotifyNotes: "投稿の通知を解除"
authentication: "認証"
authenticationRequiredToContinue: "続けるには認証を行ってください"
dateAndTime: "日時"
-showRenotes: "リノートを表示"
+showRenotes: "ブーストを表示"
edited: "編集済み"
notificationRecieveConfig: "通知の受信設定"
mutualFollow: "相互フォロー"
-followingOrFollower: "フォロー中またはフォロワー"
fileAttachedOnly: "ファイル付きのみ"
showRepliesToOthersInTimeline: "TLに他の人への返信を含める"
hideRepliesToOthersInTimeline: "TLに他の人への返信を含めない"
@@ -1218,6 +1228,8 @@ impressumDescription: "ドイツなどの一部の国と地域では表示が義
privacyPolicy: "プライバシーポリシー"
privacyPolicyUrl: "プライバシーポリシーURL"
tosAndPrivacyPolicy: "利用規約・プライバシーポリシー"
+donation: "寄付する"
+donationUrl: "寄付URL"
avatarDecorations: "アイコンデコレーション"
attach: "付ける"
detach: "外す"
@@ -1247,8 +1259,6 @@ soundWillBePlayed: "サウンドが再生されます"
showReplay: "リプレイを見る"
replay: "リプレイ"
replaying: "リプレイ中"
-endReplay: "リプレイを終了"
-copyReplayData: "リプレイデータをコピー"
ranking: "ランキング"
lastNDays: "直近{n}日"
backToTitle: "タイトルへ"
@@ -1256,73 +1266,9 @@ hemisphere: "お住まいの地域"
withSensitive: "センシティブなファイルを含むノートを表示"
userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿"
enableHorizontalSwipe: "スワイプしてタブを切り替える"
-loading: "読み込み中"
-surrender: "やめる"
-gameRetry: "リトライ"
-notUsePleaseLeaveBlank: "使用しない場合は空欄にしてください"
-useTotp: "ワンタイムパスワードを使う"
-useBackupCode: "バックアップコードを使う"
-launchApp: "アプリを起動"
-useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
-keepOriginalFilename: "オリジナルのファイル名を保持"
-keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられます。"
-noDescription: "説明文はありません"
-alwaysConfirmFollow: "フォローの際常に確認する"
-inquiry: "お問い合わせ"
-tryAgain: "もう一度お試しください。"
-confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示するとき確認する"
-sensitiveMediaRevealConfirm: "センシティブなメディアです。表示しますか?"
-createdLists: "作成したリスト"
-createdAntennas: "作成したアンテナ"
-fromX: "{x}から"
-genEmbedCode: "埋め込みコードを生成"
-noteOfThisUser: "このユーザーのノート一覧"
-clipNoteLimitExceeded: "これ以上このクリップにノートを追加できません。"
-performance: "パフォーマンス"
-modified: "変更あり"
-discard: "破棄"
-thereAreNChanges: "{n}件の変更があります"
-signinWithPasskey: "パスキーでログイン"
-unknownWebAuthnKey: "登録されていないパスキーです。"
-passkeyVerificationFailed: "パスキーの検証に失敗しました。"
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "パスキーの検証に成功しましたが、パスワードレスログインが無効になっています。"
-messageToFollower: "フォロワーへのメッセージ"
-target: "対象"
-testCaptchaWarning: "CAPTCHAのテストを目的とした機能です。本番環境で使用しないでください。 "
-prohibitedWordsForNameOfUser: "禁止ワード(ユーザーの名前)"
-prohibitedWordsForNameOfUserDescription: "このリストに含まれる文字列がユーザーの名前に含まれる場合、ユーザーの名前の変更を拒否します。モデレーター権限を持つユーザーはこの制限の影響を受けません。"
-yourNameContainsProhibitedWords: "変更しようとした名前に禁止された文字列が含まれています"
-yourNameContainsProhibitedWordsDescription: "名前に禁止されている文字列が含まれています。この名前を使用したい場合は、サーバー管理者にお問い合わせください。"
-
-_abuseUserReport:
- forward: "転送"
- forwardDescription: "匿名のシステムアカウントとして、リモートサーバーに通報を転送します。"
- resolve: "解決"
- accept: "是認"
- reject: "否認"
- resolveTutorial: "内容が正当である通報に対応した場合は「是認」を選択し、肯定的にケースが解決されたことをマークします。\n内容が正当でない通報の場合は「否認」を選択し、否定的にケースが解決されたことをマークします。"
-
-_delivery:
- status: "配信状態"
- stop: "配信停止"
- resume: "配信再開"
- _type:
- none: "配信中"
- manuallySuspended: "手動停止中"
- goneSuspended: "サーバー削除のため停止中"
- autoSuspendedForNotResponding: "サーバー応答なしのため停止中"
_bubbleGame:
howToPlay: "遊び方"
- hold: "ホールド"
- _score:
- score: "スコア"
- scoreYen: "稼いだ金額"
- highScore: "ハイスコア"
- maxChain: "最大チェーン数"
- yen: "{yen}円"
- estimatedQty: "{qty}個分"
- scoreSweets: "おにぎり {onigiriQtyWithUnit}"
_howToPlay:
section1: "位置を調整してハコにモノを落とします。"
section2: "同じ種類のモノがくっつくと別のモノに変化して、スコアが得られます。"
@@ -1354,7 +1300,7 @@ _initialAccountSetting:
pushNotificationDescription: "プッシュ通知を有効にすると{name}の通知をお使いのデバイスで受け取ることができます。"
initialAccountSettingCompleted: "初期設定が完了しました!"
haveFun: "{name}をお楽しみください!"
- youCanContinueTutorial: "このまま{name}(Misskey)の使い方についてのチュートリアルに進むこともできますが、ここで中断してすぐに使い始めることもできます。"
+ youCanContinueTutorial: "このまま{name}(Sharkey)の使い方についてのチュートリアルに進むこともできますが、ここで中断してすぐに使い始めることもできます。"
startTutorial: "チュートリアルを開始"
skipAreYouSure: "初期設定をスキップしますか?"
laterAreYouSure: "初期設定をあとでやり直しますか?"
@@ -1366,10 +1312,10 @@ _initialTutorial:
skipAreYouSure: "チュートリアルを終了しますか?"
_landing:
title: "チュートリアルへようこそ"
- description: "ここでは、Misskeyの基本的な使い方や機能を確認できます。"
+ description: "ここでは、Sharkeyの基本的な使い方や機能を確認できます。"
_note:
title: "ノートって何?"
- description: "Misskeyでの投稿は「ノート」と呼びます。ノートはタイムラインに時系列で並んでいて、リアルタイムで更新されていきます。"
+ description: "Sharkeyでの投稿は「ノート」と呼びます。ノートはタイムラインに時系列で並んでいて、リアルタイムで更新されていきます。"
reply: "返信することができます。返信に対しての返信も可能で、スレッドのように会話を続けることもできます。"
renote: "そのノートを自分のタイムラインに流して共有することができます。テキストを追加して引用することも可能です。"
reaction: "リアクションをつけることができます。詳しくは次のページで解説します。"
@@ -1383,7 +1329,7 @@ _initialTutorial:
reactDone: "「ー」ボタンを押すとリアクションを取り消すことができます。"
_timeline:
title: "タイムラインのしくみ"
- description1: "Misskeyには、使い方に応じて複数のタイムラインが用意されています(サーバーによってはいずれかが無効になっていることがあります)。"
+ description1: "Sharkeyには、使い方に応じて複数のタイムラインが用意されています(サーバーによってはいずれかが無効になっていることがあります)。"
home: "あなたがフォローしているアカウントの投稿を見られます。"
local: "このサーバーにいるユーザー全員の投稿を見られます。"
social: "ホームタイムラインとローカルタイムラインの投稿が両方表示されます。"
@@ -1392,12 +1338,12 @@ _initialTutorial:
description3: "その他にも、リストタイムラインやチャンネルタイムラインなどがあります。詳しくは{link}をご覧ください。"
_postNote:
title: "ノートの投稿設定"
- description1: "Misskeyにノートを投稿する際には、様々なオプションの設定が可能です。投稿フォームはこのようになっています。"
+ description1: "Sharkeyにノートを投稿する際には、様々なオプションの設定が可能です。投稿フォームはこのようになっています。"
_visibility:
description: "ノートを表示できる相手を制限できます。"
public: "すべてのユーザーに公開。"
- home: "ホームタイムラインのみに公開。フォロワー・プロフィールを見に来た人・リノートから、他のユーザーも見ることができます。"
- followers: "フォロワーにのみ公開。本人以外がリノートすることはできず、またフォロワー以外は閲覧できません。"
+ home: "ホームタイムラインのみに公開。フォロワー・プロフィールを見に来た人・ブーストから、他のユーザーも見ることができます。"
+ followers: "フォロワーにのみ公開。本人以外がブーストすることはできず、またフォロワー以外は閲覧できません。"
direct: "指定したユーザーにのみ公開され、また相手に通知が入ります。ダイレクトメッセージのかわりにお使いいただけます。"
doNotSendConfidencialOnDirect1: "機密情報は送信する際は注意してください。"
doNotSendConfidencialOnDirect2: "送信先のサーバーの管理者は投稿内容を見ることが可能なので、信頼できないサーバーのユーザーにダイレクト投稿を送信する場合は、機密情報の扱いに注意が必要です。"
@@ -1420,7 +1366,7 @@ _initialTutorial:
doItToContinue: "画像をセンシティブに設定すると先に進めるようになります。"
_done:
title: "チュートリアルは終了です🎉"
- description: "ここで紹介した機能はほんの一部にすぎません。Misskeyの使い方をより詳しく知るには、{link}をご覧ください。"
+ description: "ここで紹介した機能はほんの一部にすぎません。Sharkeyの使い方をより詳しく知るには、{link}をご覧ください。"
_timelineDescription:
home: "ホームタイムラインでは、あなたがフォローしているアカウントの投稿を見られます。"
@@ -1443,10 +1389,6 @@ _serverSettings:
fanoutTimelineDescription: "有効にすると、各種タイムラインを取得する際のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。サーバーのメモリ容量が少ない場合、または動作が不安定な場合は無効にすることができます。"
fanoutTimelineDbFallback: "データベースへのフォールバック"
fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
- reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
- inquiryUrl: "問い合わせ先URL"
- inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定します。"
- thisSettingWillAutomaticallyOffWhenModeratorsInactive: "一定期間モデレーターのアクティビティが検出されなかった場合、スパム防止のためこの設定は自動でオフになります。"
_accountMigration:
moveFrom: "別のアカウントからこのアカウントに移行"
@@ -1456,7 +1398,7 @@ _accountMigration:
moveTo: "このアカウントを新しいアカウントへ移行"
moveToLabel: "移行先のアカウント:"
moveCannotBeUndone: "アカウントを移行すると、取り消すことはできません。"
- moveAccountDescription: "新しいアカウントへ移行します。\n ・フォロワーが新しいアカウントを自動でフォローします\n ・このアカウントからのフォローは全て解除されます\n ・このアカウントではノートの作成などができなくなります\n\nフォロワーの移行は自動ですが、フォローの移行は手動で行う必要があります。移行前にこのアカウントでフォローエクスポートし、移行後すぐに移行先アカウントでインポートを行なってください。\nリスト・ミュート・ブロックについても同様ですので、手動で移行する必要があります。\n\n(この説明はこのサーバー(Misskey v13.12.0以降)の仕様です。Mastodonなどの他のActivityPubソフトウェアでは挙動が異なる場合があります。)"
+ moveAccountDescription: "新しいアカウントへ移行します。\n ・フォロワーが新しいアカウントを自動でフォローします\n ・このアカウントからのフォローは全て解除されます\n ・このアカウントではノートの作成などができなくなります\n\nフォロワーの移行は自動ですが、フォローの移行は手動で行う必要があります。移行前にこのアカウントでフォローエクスポートし、移行後すぐに移行先アカウントでインポートを行なってください。\nリスト・ミュート・ブロックについても同様ですので、手動で移行する必要があります。\n\n(この説明はこのサーバー(Sharkey v13.12.0以降)の仕様です。Mastodonなどの他のActivityPubソフトウェアでは挙動が異なる場合があります。)"
moveAccountHowTo: "アカウントの移行には、まずは移行先のアカウントでこのアカウントに対しエイリアスを作成します。\nエイリアス作成後、移行先のアカウントを次のように入力してください: @username@server.example.com"
startMigration: "移行する"
migrationConfirm: "本当にこのアカウントを {account} に移行しますか?一度移行すると取り消せず、二度とこのアカウントを元の状態で使用できなくなります。"
@@ -1468,9 +1410,9 @@ _achievements:
earnedAt: "獲得日時"
_types:
_notes1:
- title: "just setting up my msky"
+ title: "just setting up my shonk"
description: "初めてノートを投稿した"
- flavor: "良いMisskeyライフを!"
+ flavor: "良いSharkeyライフを!"
_notes10:
title: "いくつかのノート"
description: "ノートを10回投稿した"
@@ -1566,7 +1508,7 @@ _achievements:
_login1000:
title: "ノートマスターⅢ"
description: "通算ログイン日数が1,000日"
- flavor: "Misskeyを使ってくれてありがとう!"
+ flavor: "Sharkeyを使ってくれてありがとう!"
_noteClipped1:
title: "クリップせずにはいられないな"
description: "初めてノートをクリップした"
@@ -1626,9 +1568,9 @@ _achievements:
title: "実績好き"
description: "実績一覧を3分以上眺め続けた"
_iLoveMisskey:
- title: "I Love Misskey"
- description: "\"I ❤ #Misskey\"を投稿した"
- flavor: "Misskeyを使ってくださりありがとうございます! by 開発チーム"
+ title: "I Love Sharkey"
+ description: "\"I ❤ #Sharkey\"を投稿した"
+ flavor: "Sharkeyを使ってくださりありがとうございます! by 開発チーム"
_foundTreasure:
title: "宝探し"
description: "隠されたお宝を発見した"
@@ -1636,7 +1578,7 @@ _achievements:
title: "ひとやすみ"
description: "クライアントを起動してから30分以上経過した"
_client60min:
- title: "Misskeyの見すぎ"
+ title: "Sharkeyの見すぎ"
description: "クライアントを起動してから60分以上経過した"
_noteDeletedWithin1min:
title: "いまのなし"
@@ -1707,7 +1649,7 @@ _achievements:
title: "テスト過剰"
description: "通知のテストをごく短時間のうちに連続して行った"
_tutorialCompleted:
- title: "Misskey初心者講座 修了証"
+ title: "Sharkey初心者講座 修了証"
description: "チュートリアルを完了した"
_bubbleGameExplodingHead:
title: "🤯"
@@ -1755,9 +1697,10 @@ _role:
high: "高"
_options:
gtlAvailable: "グローバルタイムラインの閲覧"
+ btlAvailable: "バブルタイムラインの閲覧"
ltlAvailable: "ローカルタイムラインの閲覧"
canPublicNote: "パブリック投稿の許可"
- mentionMax: "ノート内の最大メンション数"
+ canImportNotes: "ノートのインポートが可能"
canInvite: "サーバー招待コードの発行"
inviteLimit: "招待コードの作成可能数"
inviteLimitCycle: "招待コードの発行間隔"
@@ -1766,7 +1709,6 @@ _role:
canManageAvatarDecorations: "アバターデコレーションの管理"
driveCapacity: "ドライブ容量"
alwaysMarkNsfw: "ファイルにNSFWを常に付与"
- canUpdateBioMedia: "アイコンとバナーの更新を許可"
pinMax: "ノートのピン留めの最大数"
antennaMax: "アンテナの作成可能数"
wordMuteMax: "ワードミュートの最大文字数"
@@ -1781,20 +1723,9 @@ _role:
canSearchNotes: "ノート検索の利用"
canUseTranslator: "翻訳機能の利用"
avatarDecorationLimit: "アイコンデコレーションの最大取付個数"
- canImportAntennas: "アンテナのインポートを許可"
- canImportBlocking: "ブロックのインポートを許可"
- canImportFollowing: "フォローのインポートを許可"
- canImportMuting: "ミュートのインポートを許可"
- canImportUserLists: "リストのインポートを許可"
_condition:
- roleAssignedTo: "マニュアルロールにアサイン済み"
isLocal: "ローカルユーザー"
isRemote: "リモートユーザー"
- isCat: "猫ユーザー"
- isBot: "botユーザー"
- isSuspended: "サスペンド済みユーザー"
- isLocked: "鍵アカウントユーザー"
- isExplorable: "「アカウントを見つけやすくする」が有効なユーザー"
createdLessThan: "アカウント作成から~以内"
createdMoreThan: "アカウント作成から~経過"
followersLessThanOrEq: "フォロワー数が~以下"
@@ -1833,6 +1764,8 @@ _signup:
almostThere: "ほとんど完了です"
emailAddressInfo: "あなたが使っているメールアドレスを入力してください。メールアドレスが公開されることはありません。"
emailSent: "入力されたメールアドレス({email})宛に確認のメールが送信されました。メールに記載されたリンクにアクセスすると、アカウントの作成が完了します。メールに記載されているリンクの有効期限は30分です。"
+ approvalPending: "アカウントが作成され、承認待ちの状態です。"
+ reasonInfo: "インスタンスに参加したい理由を入力してください。"
_accountDelete:
accountDelete: "アカウントの削除"
@@ -1874,7 +1807,6 @@ _plugin:
installWarn: "信頼できないプラグインはインストールしないでください。"
manage: "プラグインの管理"
viewSource: "ソースを表示"
- viewLog: "ログを表示"
_preferencesBackups:
list: "作成したバックアップ"
@@ -1903,14 +1835,16 @@ _registry:
createKey: "キーを作成"
_aboutMisskey:
- about: "Misskeyはsyuiloによって2014年から開発されている、オープンソースのソフトウェアです。"
- contributors: "コントリビューター"
+ about: "Sharkeyは、Misskeyをベースにしたオープンソースのソフトウェアです。"
+ contributors: "主なコントリビューター"
allContributors: "全てのコントリビューター"
source: "ソースコード"
- original: "オリジナル"
- thisIsModifiedVersion: "{name}はオリジナルのMisskeyを改変したバージョンを使用しています。"
- translation: "Misskeyを翻訳"
+ original: "Misskey オリジナル"
+ original_sharkey: "Sharkey オリジナル"
+ thisIsModifiedVersion: "{name}はオリジナルのSharkeyを改変したバージョンを使用しています。"
+ translation: "Sharkeyを翻訳"
donate: "Misskeyに寄付"
+ donate_sharkey: "Sharkeyに寄付"
morePatrons: "他にも多くの方が支援してくれています。ありがとうございます🥰"
patrons: "支援者"
projectMembers: "プロジェクトメンバー"
@@ -1929,6 +1863,7 @@ _serverDisconnectedBehavior:
reload: "自動でリロード"
dialog: "ダイアログで警告"
quiet: "控えめに警告"
+ disabled: "警告を無効にする"
_channel:
create: "チャンネルを作成"
@@ -1942,7 +1877,7 @@ _channel:
notesCount: "{n}投稿があります"
nameAndDescription: "名前と説明"
nameOnly: "名前のみ"
- allowRenoteToExternal: "チャンネル外へのリノートと引用リノートを許可する"
+ allowRenoteToExternal: "チャンネル外へのブーストと引用ブーストを許可する"
_menuDisplay:
sideFull: "横"
@@ -1956,7 +1891,7 @@ _wordMute:
muteWordsDescription2: "キーワードをスラッシュで囲むと正規表現になります。"
_instanceMute:
- instanceMuteDescription: "ミュートしたサーバーのユーザーへの返信を含めて、設定したサーバーの全てのノートとRenoteをミュートします。"
+ instanceMuteDescription: "ミュートしたサーバーのユーザーへの返信を含めて、設定したサーバーの全てのノートとブーストをミュートします。"
instanceMuteDescription2: "改行で区切って設定します"
title: "設定したサーバーのノートを隠します。"
heading: "ミュートするサーバー"
@@ -2010,7 +1945,7 @@ _theme:
hashtag: "ハッシュタグ"
mention: "メンション"
mentionMe: "あなた宛てメンション"
- renote: "Renote"
+ renote: "Boost"
modalBg: "モーダルの背景"
divider: "分割線"
scrollbarHandle: "スクロールバーの取っ手"
@@ -2025,6 +1960,7 @@ _theme:
buttonBg: "ボタンの背景"
buttonHoverBg: "ボタンの背景 (ホバー)"
inputBorder: "入力ボックスの縁取り"
+ listItemHoverBg: "リスト項目の背景 (ホバー)"
driveFolderBg: "ドライブフォルダーの背景"
wallpaperOverlay: "壁紙のオーバーレイ"
badge: "バッジ"
@@ -2037,6 +1973,8 @@ _sfx:
note: "ノート"
noteMy: "ノート(自分)"
notification: "通知"
+ antenna: "アンテナ受信"
+ channel: "チャンネル通知"
reaction: "リアクション選択時"
_soundSettings:
@@ -2046,7 +1984,6 @@ _soundSettings:
driveFileTypeWarnDescription: "音声ファイルを選択してください"
driveFileDurationWarn: "音声が長すぎます"
driveFileDurationWarnDescription: "長い音声を使用するとMisskeyの使用に支障をきたす可能性があります。それでも続行しますか?"
- driveFileError: "音声が読み込めませんでした。設定を変更してください"
_ago:
future: "未来"
@@ -2079,7 +2016,8 @@ _2fa:
alreadyRegistered: "既に設定は完了しています。"
registerTOTP: "認証アプリの設定を開始"
step1: "まず、{a}や{b}などの認証アプリをお使いのデバイスにインストールします。"
- step2: "次に、表示されているQRコードをアプリでスキャンするか、ボタンをクリックして端末上でアプリを開きます。"
+ step2: "次に、表示されているQRコードをアプリでスキャンします。"
+ step2Click: "QRコードをクリックすると、お使いの端末にインストールされている認証アプリやキーリングに登録できます。"
step2Uri: "デスクトップアプリを使用する場合は次のURIを入力します"
step3Title: "確認コードを入力"
step3: "アプリに表示されている確認コード(トークン)を入力します。"
@@ -2103,7 +2041,6 @@ _2fa:
backupCodesDescription: "認証アプリが使用できなくなった場合、以下のバックアップコードを使ってアカウントにアクセスできます。これらのコードは必ず安全な場所に保管してください。各コードは一回だけ使用できます。"
backupCodeUsedWarning: "バックアップコードが使用されました。認証アプリが使えなくなっている場合、なるべく早く認証アプリを再設定してください。"
backupCodesExhaustedWarning: "バックアップコードが全て使用されました。認証アプリを利用できない場合、これ以上アカウントにアクセスできなくなります。認証アプリを再登録してください。"
- moreDetailedGuideHere: "詳細なガイドはこちら"
_permissions:
"read:account": "アカウントの情報を見る"
@@ -2155,6 +2092,7 @@ _permissions:
"read:admin:server-info": "サーバーの情報を見る"
"read:admin:show-moderation-log": "モデレーションログを見る"
"read:admin:show-user": "ユーザーのプライベートな情報を見る"
+ "read:admin:show-users": "ユーザーのプライベートな情報を見る"
"write:admin:suspend-user": "ユーザーを凍結する"
"write:admin:unset-user-avatar": "ユーザーのアバターを削除する"
"write:admin:unset-user-banner": "ユーザーのバーナーを削除する"
@@ -2248,6 +2186,7 @@ _widgets:
_userList:
chooseList: "リストを選択"
clicker: "クリッカー"
+ search: "検索"
birthdayFollowings: "今日誕生日のユーザー"
_cw:
@@ -2278,6 +2217,7 @@ _poll:
remainingHours: "終了まであと{h}時間{m}分"
remainingMinutes: "終了まであと{m}分{s}秒"
remainingSeconds: "終了まであと{s}秒"
+ multiple: "複数の選択肢"
_visibility:
public: "パブリック"
@@ -2315,11 +2255,13 @@ _profile:
metadataContent: "内容"
changeAvatar: "アイコン画像を変更"
changeBanner: "バナー画像を変更"
+ updateBanner: "更新バナー"
+ removeBanner: "バナーを削除"
+ changeBackground: "背景を変更する"
+ updateBackground: "背景を更新する"
+ removeBackground: "背景を削除する"
verifiedLinkDescription: "内容にURLを設定すると、リンク先のWebサイトに自分のプロフィールへのリンクが含まれている場合に所有者確認済みアイコンを表示させることができます。"
avatarDecorationMax: "最大{max}つまでデコレーションを付けられます。"
- followedMessage: "フォローされた時のメッセージ"
- followedMessageDescription: "フォローされた時に相手に表示する短いメッセージを設定できます。"
- followedMessageDescriptionForLockedAccount: "フォローを承認制にしている場合、フォローリクエストを許可した時に表示されます。"
_exportOrImport:
allNotes: "全てのノート"
@@ -2382,7 +2324,6 @@ _play:
title: "タイトル"
script: "スクリプト"
summary: "説明"
- visibilityDescription: "非公開に設定するとプロフィールに表示されなくなりますが、URLを知っている人は引き続きアクセスできます。"
_pages:
newPage: "ページの作成"
@@ -2418,7 +2359,6 @@ _pages:
eyeCatchingImageSet: "アイキャッチ画像を設定"
eyeCatchingImageRemove: "アイキャッチ画像を削除"
chooseBlock: "ブロックを追加"
- enterSectionTitle: "セクションタイトルを入力"
selectType: "種類を選択"
contentBlocks: "コンテンツ"
inputBlocks: "入力"
@@ -2429,8 +2369,6 @@ _pages:
section: "セクション"
image: "画像"
button: "ボタン"
- dynamic: "動的ブロック"
- dynamicDescription: "このブロックは廃止されています。今後は{play}を利用してください。"
note: "ノート埋め込み"
_note:
@@ -2448,11 +2386,12 @@ _notification:
youGotMention: "{name}からのメンション"
youGotReply: "{name}からのリプライ"
youGotQuote: "{name}による引用"
- youRenoted: "{name}がRenoteしました"
+ youRenoted: "{name}がBoostしました"
youWereFollowed: "フォローされました"
youReceivedFollowRequest: "フォローリクエストが来ました"
yourFollowRequestAccepted: "フォローリクエストが承認されました"
pollEnded: "アンケートの結果が出ました"
+ edited: "投稿が編集されました"
newNote: "新しい投稿"
unreadAntennaNote: "アンテナ {name}"
roleAssigned: "ロールが付与されました"
@@ -2463,12 +2402,8 @@ _notification:
sendTestNotification: "テスト通知を送信する"
notificationWillBeDisplayedLikeThis: "通知はこのように表示されます"
reactedBySomeUsers: "{n}人がリアクションしました"
- likedBySomeUsers: "{n}人がいいねしました"
- renotedBySomeUsers: "{n}人がリノートしました"
+ renotedBySomeUsers: "{n}人がブーストしました"
followedBySomeUsers: "{n}人にフォローされました"
- flushNotification: "通知の履歴をリセットする"
- exportOfXCompleted: "{x}のエクスポートが完了しました"
- login: "ログインがありました"
_types:
all: "すべて"
@@ -2476,7 +2411,7 @@ _notification:
follow: "フォロー"
mention: "メンション"
reply: "リプライ"
- renote: "Renote"
+ renote: "Boost"
quote: "引用"
reaction: "リアクション"
pollEnded: "アンケートが終了"
@@ -2484,21 +2419,17 @@ _notification:
followRequestAccepted: "フォローが受理された"
roleAssigned: "ロールが付与された"
achievementEarned: "実績の獲得"
- exportCompleted: "エクスポートが完了した"
- login: "ログイン"
- test: "通知のテスト"
app: "連携アプリからの通知"
_actions:
followBack: "フォローバック"
reply: "返信"
- renote: "Renote"
+ renote: "Boost"
_deck:
alwaysShowMainColumn: "常にメインカラムを表示"
columnAlign: "カラムの寄せ"
addColumn: "カラムを追加"
- newNoteNotificationSettings: "新着ノート通知の設定"
configureColumn: "カラムの設定"
swapLeft: "左に移動"
swapRight: "右に移動"
@@ -2542,43 +2473,18 @@ _drivecleaner:
_webhookSettings:
createWebhook: "Webhookを作成"
- modifyWebhook: "Webhookを編集"
name: "名前"
secret: "シークレット"
- trigger: "トリガー"
+ events: "Webhookを実行するタイミング"
active: "有効"
_events:
follow: "フォローしたとき"
followed: "フォローされたとき"
note: "ノートを投稿したとき"
reply: "返信されたとき"
- renote: "Renoteされたとき"
+ renote: "Boostされたとき"
reaction: "リアクションがあったとき"
mention: "メンションされたとき"
- _systemEvents:
- abuseReport: "ユーザーから通報があったとき"
- abuseReportResolved: "ユーザーからの通報を処理したとき"
- userCreated: "ユーザーが作成されたとき"
- inactiveModeratorsWarning: "モデレーターが一定期間非アクティブになったとき"
- inactiveModeratorsInvitationOnlyChanged: "モデレーターが一定期間非アクティブだったため、システムにより招待制へと変更されたとき"
- deleteConfirm: "Webhookを削除しますか?"
- testRemarks: "スイッチの右にあるボタンをクリックするとダミーのデータを使用したテスト用Webhookを送信できます。"
-
-_abuseReport:
- _notificationRecipient:
- createRecipient: "通報の通知先を追加"
- modifyRecipient: "通報の通知先を編集"
- recipientType: "通知先の種類"
- _recipientType:
- mail: "メール"
- webhook: "Webhook"
- _captions:
- mail: "モデレーター権限を持つユーザーのメールアドレスに通知を送ります(通報を受けた時のみ)"
- webhook: "指定したSystemWebhookに通知を送ります(通報を受けた時と通報を解決した時にそれぞれ発信)"
- keywords: "キーワード"
- notifiedUser: "通知先ユーザー"
- notifiedWebhook: "使用するWebhook"
- deleteConfirm: "通知先を削除しますか?"
_moderationLogTypes:
createRole: "ロールを作成"
@@ -2586,13 +2492,14 @@ _moderationLogTypes:
updateRole: "ロールを更新"
assignRole: "ロールへアサイン"
unassignRole: "ロールのアサイン解除"
+ approve: "承認済み"
suspend: "凍結"
unsuspend: "凍結解除"
addCustomEmoji: "カスタム絵文字追加"
updateCustomEmoji: "カスタム絵文字更新"
deleteCustomEmoji: "カスタム絵文字削除"
updateServerSettings: "サーバー設定更新"
- updateUserNote: "ユーザーのモデレーションノート更新"
+ updateUserNote: "モデレーションノート更新"
deleteDriveFile: "ファイルを削除"
deleteNote: "ノートを削除"
createGlobalAnnouncement: "全体のお知らせを作成"
@@ -2604,12 +2511,9 @@ _moderationLogTypes:
resetPassword: "パスワードをリセット"
suspendRemoteInstance: "リモートサーバーを停止"
unsuspendRemoteInstance: "リモートサーバーを再開"
- updateRemoteInstanceNote: "リモートサーバーのモデレーションノート更新"
markSensitiveDriveFile: "ファイルをセンシティブ付与"
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
resolveAbuseReport: "通報を解決"
- forwardAbuseReport: "通報を転送"
- updateAbuseReportNote: "通報のモデレーションノート更新"
createInvitation: "招待コードを作成"
createAd: "広告を作成"
deleteAd: "広告を削除"
@@ -2619,16 +2523,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "アイコンデコレーションを削除"
unsetUserAvatar: "ユーザーのアイコンを解除"
unsetUserBanner: "ユーザーのバナーを解除"
- createSystemWebhook: "SystemWebhookを作成"
- updateSystemWebhook: "SystemWebhookを更新"
- deleteSystemWebhook: "SystemWebhookを削除"
- createAbuseReportNotificationRecipient: "通報の通知先を作成"
- updateAbuseReportNotificationRecipient: "通報の通知先を更新"
- deleteAbuseReportNotificationRecipient: "通報の通知先を削除"
- deleteAccount: "アカウントを削除"
- deletePage: "ページを削除"
- deleteFlash: "Playを削除"
- deleteGalleryPost: "ギャラリーの投稿を削除"
_fileViewer:
title: "ファイルの詳細"
@@ -2681,18 +2575,31 @@ _externalResourceInstaller:
title: "テーマのインストールに失敗しました"
description: "テーマのインストール中に問題が発生しました。もう一度お試しください。エラーの詳細はJavascriptコンソールをご覧ください。"
+_animatedMFM:
+ play: "MFMアニメーションを再生"
+ stop: "MFMアニメーション停止"
+ _alert:
+ text: "MFMアニメーションには、点滅するライトや高速で動くテキスト/絵文字を含まれる場合があります。"
+ confirm: "再生する"
+
+_dataRequest:
+ title: "データリクエスト"
+ warn: "データリクエストは3日ごとに可能です。"
+ text: "データの保存が完了すると、このアカウントに登録されているEメールアドレスにメールが送信されます。"
+ button: "リクエスト"
+
_dataSaver:
_media:
- title: "メディアの読み込みを無効化"
+ title: "メディアの読み込み"
description: "画像・動画が自動で読み込まれるのを防止します。隠れている画像・動画はタップすると読み込まれます。"
_avatar:
- title: "アイコン画像のアニメーションを無効化"
+ title: "アイコン画像"
description: "アイコン画像のアニメーションが停止します。アニメーション画像は通常の画像よりファイルサイズが大きいことがあるので、データ通信量をさらに削減できます。"
_urlPreview:
- title: "URLプレビューのサムネイルを非表示"
+ title: "URLプレビューのサムネイル"
description: "URLプレビューのサムネイル画像が読み込まれなくなります。"
_code:
- title: "コードハイライトを非表示"
+ title: "コードハイライト"
description: "MFMなどでコードハイライト記法が使われている場合、タップするまで読み込まれなくなります。コードハイライトではハイライトする言語ごとにその定義ファイルを読み込む必要がありますが、それらが自動で読み込まれなくなるため、通信量の削減が見込めます。"
_hemisphere:
@@ -2742,50 +2649,8 @@ _reversi:
opponentHasSettingsChanged: "相手が設定を変更しました"
allowIrregularRules: "変則許可 (完全フリー)"
disallowIrregularRules: "変則なし"
- showBoardLabels: "盤面に行・列番号を表示"
- useAvatarAsStone: "石をアイコンにする"
_offlineScreen:
title: "オフライン - サーバーに接続できません"
header: "サーバーに接続できません"
-_urlPreviewSetting:
- title: "URLプレビューの設定"
- enable: "URLプレビューを有効にする"
- timeout: "プレビュー取得時のタイムアウト(ms)"
- timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されません。"
- maximumContentLength: "Content-Lengthの最大値(byte)"
- maximumContentLengthDescription: "Content-Lengthがこの値を超えた場合、プレビューは生成されません。"
- requireContentLength: "Content-Lengthが取得できた場合のみプレビューを生成"
- requireContentLengthDescription: "相手サーバがContent-Lengthを返さない場合、プレビューは生成されません。"
- userAgent: "User-Agent"
- userAgentDescription: "プレビュー取得時に使用されるUser-Agentを設定します。空欄の場合、デフォルトのUser-Agentが使用されます。"
- summaryProxy: "プレビューを生成するプロキシのエンドポイント"
- summaryProxyDescription: "Misskey本体ではなく、サマリープロキシを使用してプレビューを生成します。"
- summaryProxyDescription2: "プロキシには下記パラメータがクエリ文字列として連携されます。プロキシ側がこれらをサポートしない場合、設定値は無視されます。"
-
-_mediaControls:
- pip: "ピクチャインピクチャ"
- playbackRate: "再生速度"
- loop: "ループ再生"
-
-_contextMenu:
- title: "コンテキストメニュー"
- app: "アプリケーション"
- appWithShift: "Shiftキーでアプリケーション"
- native: "ブラウザのUI"
-
-_embedCodeGen:
- title: "埋め込みコードをカスタマイズ"
- header: "ヘッダーを表示"
- autoload: "自動で続きを読み込む(非推奨)"
- maxHeight: "高さの最大値"
- maxHeightDescription: "0で最大値の設定が無効になります。ウィジェットが縦に伸び続けるのを防ぐために、何らかの値に指定してください。"
- maxHeightWarn: "高さの最大値制限が無効(0)になっています。これが意図した変更ではない場合は、高さの最大値を何らかの値に設定してください。"
- previewIsNotActual: "プレビュー画面で表示可能な範囲を超えたため、実際に埋め込んだ際とは表示が異なります。"
- rounded: "角丸にする"
- border: "外枠に枠線をつける"
- applyToPreview: "プレビューに反映"
- generateCode: "埋め込みコードを作成"
- codeGenerated: "コードが生成されました"
- codeGeneratedDescription: "生成されたコードをウェブサイトに貼り付けてご利用ください。"
diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml
index 0a8b3828f2..44393b42f0 100644
--- a/locales/ja-KS.yml
+++ b/locales/ja-KS.yml
@@ -1,8 +1,8 @@
---
_lang_: "日本語 (関西弁)"
headlineMisskey: "ノートでつながるネットワーク"
-introMisskey: "ようお越し!Misskeyは、オープンソースの分散型マイクロブログサービスやねん。\n「ノート」を作って、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「ツッコミ」機能で、皆のノートに素早く反応を追加したりもできるで✌\nほな、新しい世界を探検しよか🚀"
-poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォームMisskey のサーバーのひとつなんやで。"
+introMisskey: "ようお越し!Sharkeyは、オープンソースの分散型マイクロブログサービスやねん。\n「ノート」を作って、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「ツッコミ」機能で、皆のノートに素早く反応を追加したりもできるで✌\nほな、新しい世界を探検しよか🚀"
+poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォームSharkey のサーバーのひとつなんやで。"
monthAndDay: "{month}月 {day}日"
search: "探す"
notifications: "通知"
@@ -15,7 +15,7 @@ gotIt: "ほい"
cancel: "やめとく"
noThankYou: "やめとく"
enterUsername: "ユーザー名を入れてや"
-renotedBy: "{user}がリノートしたで"
+renotedBy: "{user}がブーストしたで"
noNotes: "ノートはあらへん"
noNotifications: "通知はあらへん"
instance: "サーバー"
@@ -45,10 +45,10 @@ pin: "ピン留めしとく"
unpin: "やっぱピン留めせん"
copyContent: "内容をコピー"
copyLink: "リンクをコピー"
-copyLinkRenote: "リノートのリンクをコピーするで?"
+copyLinkRenote: "ブーストのリンクをコピーするで?"
delete: "ほかす"
deleteAndEdit: "ほかして直す"
-deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、リノート、返信も全部消えるんやけどそれでもええん?"
+deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのツッコミ、ブースト、返信も全部消えるんやけどそれでもええん?"
addToList: "リストに入れたる"
addToAntenna: "アンテナに入れる"
sendMessage: "メッセージを送る"
@@ -60,7 +60,6 @@ copyFileId: "ファイルIDをコピー"
copyFolderId: "フォルダーIDをコピー"
copyProfileUrl: "プロフィールURLをコピー"
searchUser: "ユーザーを探す"
-searchThisUsersNotes: "ユーザーのノートを検索"
reply: "返事"
loadMore: "まだまだあるで!"
showMore: "まだまだあるで!"
@@ -106,17 +105,14 @@ followRequests: "フォロー申請"
unfollow: "フォローやめる"
followRequestPending: "フォロー許してくれるん待っとる"
enterEmoji: "絵文字を入れてや"
-renote: "リノート"
-unrenote: "リノートやめる"
-renoted: "リノートしたで。"
-renotedToX: "{name}にリノートしたで"
-cantRenote: "この投稿はリノートできへんっぽい。"
-cantReRenote: "リノート自体はリノートできへんで。"
+renote: "ブースト"
+unrenote: "ブーストやめる"
+renoted: "ブーストしたで。"
+cantRenote: "この投稿はブーストできへんっぽい。"
+cantReRenote: "ブースト自体はブーストできへんで。"
quote: "引用"
-inChannelRenote: "チャンネルの中でリノート"
+inChannelRenote: "チャンネルの中でブースト"
inChannelQuote: "チャンネル内引用"
-renoteToChannel: "チャンネルにリノート"
-renoteToOtherChannel: "他のチャンネルにリノート"
pinnedNote: "ピン留めされとるノート"
pinned: "ピン留めしとく"
you: "あんた"
@@ -140,8 +136,8 @@ unmarkAsSensitive: "そこまでアカンことないやろ"
enterFileName: "ファイル名を入れてや"
mute: "ミュート"
unmute: "ミュートやめたる"
-renoteMute: "リノートは見いひん"
-renoteUnmute: "リノートもやっぱ見るわ"
+renoteMute: "ブーストは見いひん"
+renoteUnmute: "ブーストもやっぱ見るわ"
block: "ブロック"
unblock: "ブロックやめたる"
suspend: "凍結"
@@ -155,7 +151,6 @@ editList: "リストいじる"
selectChannel: "チャンネルを選ぶ"
selectAntenna: "アンテナを選ぶ"
editAntenna: "アンテナいじる"
-createAntenna: "アンテナを作成"
selectWidget: "ウィジェットを選ぶ"
editWidgets: "ウィジェットをいじる"
editWidgetsExit: "いじるのをやめる"
@@ -172,9 +167,11 @@ youCanCleanRemoteFilesCache: "ファイル管理にある🗑️ボタンでキ
cacheRemoteSensitiveFiles: "リモートのきわどいファイルをキャッシュに突っ込む"
cacheRemoteSensitiveFilesDescription: "この設定を切ると、リモートのきわどいファイルはキャッシュせず直でリンクするようになるで。"
flagAsBot: "Botにするで"
-flagAsBotDescription: "もしこのアカウントをプログラム使うて運用するんやったら、このフラグをオンにしてや。オンにすれば、反応がバーッて連鎖せんように開発者が使うたり、Misskeyのシステム上での扱いがBotに合ったもんになるからな。"
+flagAsBotDescription: "もしこのアカウントをプログラム使うて運用するんやったら、このフラグをオンにしてや。オンにすれば、反応がバーッて連鎖せんように開発者が使うたり、Sharkeyのシステム上での扱いがBotに合ったもんになるからな。"
flagAsCat: "猫や。かわええな。"
flagAsCatDescription: "ネコになりたいんならこれつけとき。"
+flagSpeakAsCat: "猫語で話すで"
+flagSpeakAsCatDescription: "有効にすると、あなたの投稿の 「な」を「にゃ」にするでー。"
flagShowTimelineReplies: "タイムラインにノートへの返信を表示するで"
flagShowTimelineRepliesDescription: "オンにしたら、タイムラインにユーザーのノートの他にもそのユーザーの他のノートへの返信を表示するで。"
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストを勝手に許可しとく"
@@ -182,10 +179,6 @@ addAccount: "アカウントを追加"
reloadAccountsList: "アカウントリストの情報を更新"
loginFailed: "ログインに失敗してもうた…"
showOnRemote: "リモートで見る"
-continueOnRemote: "リモートで続行"
-chooseServerOnMisskeyHub: "Misskey Hubからサーバーを選択"
-specifyServerHost: "サーバーのドメインを直接指定"
-inputHostName: "ドメインを入力せえや"
general: "全般"
wallpaper: "壁紙"
setWallpaper: "壁紙を設定"
@@ -196,7 +189,6 @@ followConfirm: "{name}をフォローしてええか?"
proxyAccount: "プロキシアカウント"
proxyAccountDescription: "プロキシアカウントは、代わりにフォローしてくれるアカウントや。例えば、551に豚まんが無いときやったり、ユーザーがリモートユーザーをアカウントに入れたとき、リストに入れられたユーザーが誰からもフォローされてないと寂しいやん。寂しいし、アクティビティも配達されへんから、プロキシアカウントがフォローしてくれるで。ええやつやん…"
host: "ホスト"
-selectSelf: "自分を選択"
selectUser: "ユーザーを選ぶ"
recipient: "宛先"
annotation: "注釈"
@@ -212,7 +204,6 @@ perDay: "1日ごと"
stopActivityDelivery: "アクティビティの配送をやめる"
blockThisInstance: "このサーバーをブロックすんで"
silenceThisInstance: "サーバーサイレンスすんで?"
-mediaSilenceThisInstance: "サーバーをメディアサイレンス"
operations: "操作"
software: "ソフトウェア"
version: "バージョン"
@@ -234,8 +225,6 @@ blockedInstances: "ブロックしたサーバー"
blockedInstancesDescription: "ブロックしたいサーバーのホストを改行で区切って設定してな。ブロックされてもうたサーバーとはもう金輪際やり取りできひんくなるで。"
silencedInstances: "サーバーサイレンスされてんねん"
silencedInstancesDescription: "サイレンスしたいサーバーのホストを改行で区切って設定すんで。サイレンスされたサーバーに所属するアカウントはすべて「サイレンス」として扱われ、フォローがすべてリクエストになり、フォロワーでないローカルアカウントにはメンションできなくなんねん。ブロックしたインスタンスには影響せーへんで。"
-mediaSilencedInstances: "メディアサイレンスしたサーバー"
-mediaSilencedInstancesDescription: "メディアサイレンスしたいサーバーのホストを改行で区切って設定するで。メディアサイレンスされたサーバーに所属するアカウントによるファイルはすべてセンシティブとして扱われてな、カスタム絵文字が使えへんようになるで。ブロックしたインスタンスには影響せえへんで。"
muteAndBlock: "ミュートとブロック"
mutedUsers: "ミュートしとるユーザー"
blockedUsers: "ブロックしとるユーザー"
@@ -243,7 +232,7 @@ noUsers: "ユーザーはおらん"
editProfile: "プロフィールをいじる"
noteDeleteConfirm: "このノートをほかしてええか?"
pinLimitExceeded: "これ以上ピン留めできひん"
-intro: "Misskeyのインストールが完了したで!管理者アカウントを作ってや。"
+intro: "Sharkeyのインストールが完了したで!管理者アカウントを作ってや。"
done: "でけた"
processing: "処理しとる"
preview: "プレビュー"
@@ -326,7 +315,6 @@ selectFile: "ファイル選んでや"
selectFiles: "ファイル選んでや"
selectFolder: "フォルダ選んでや"
selectFolders: "フォルダ選んでや"
-fileNotSelected: "ファイルが選択されてへんで"
renameFile: "ファイル名をいらう"
folderName: "フォルダー名"
createFolder: "フォルダー作る"
@@ -414,7 +402,6 @@ name: "名前"
antennaSource: "受信ソース(このソースは食われへん)"
antennaKeywords: "受信キーワード"
antennaExcludeKeywords: "除外キーワード"
-antennaExcludeBots: "Botアカウントを除外"
antennaKeywordsDescription: "スペースで区切ったるとAND指定で、改行で区切ったるとOR指定や"
notifyAntenna: "新しいノートを通知すんで"
withFileAntenna: "なんか添付されたノートだけ"
@@ -438,7 +425,7 @@ exploreFediverse: "Fediverseを探ってみる"
popularTags: "人気のタグ"
userList: "リスト"
about: "情報"
-aboutMisskey: "Misskeyってなんや?"
+aboutMisskey: "Sharkeyってなんや?"
administrator: "管理者"
token: "確認コード"
2fa: "二要素認証"
@@ -482,12 +469,10 @@ retype: "もっかい入力"
noteOf: "{user}はんのノート"
quoteAttached: "引用付いとるで"
quoteQuestion: "引用として添付してもええか?"
-attachAsFileQuestion: "クリップボードのテキストが長すぎるからテキストファイルとして添付してもええか?"
noMessagesYet: "まだチャットはあらへんで"
newMessageExists: "新しいメッセージがきたで"
onlyOneFileCanBeAttached: "ごめんな、メッセージに添付できるファイルはひとつだけなんよ。"
signinRequired: "ログインしてくれへん?"
-signinOrContinueOnRemote: "続行するには、お使いのサーバーに移動するか、このサーバーに登録・ログインする必要があるで"
invitations: "来てや"
invitationCode: "招待コード"
checking: "確認しとるで"
@@ -509,8 +494,8 @@ uiLanguage: "UIの表示言語"
aboutX: "{x}について"
emojiStyle: "絵文字のスタイル"
native: "ネイティブ"
+disableDrawer: "メニューをドロワーで表示せえへん"
showNoteActionsOnlyHover: "ノートの操作部をホバー時のみ表示するで"
-showReactionsCount: "ノートのリアクション数を表示する"
noHistory: "履歴はないわ。"
signinHistory: "ログイン履歴"
enableAdvancedMfm: "ややこしいMFMもありにする"
@@ -574,7 +559,7 @@ popout: "ポップアウト"
volume: "やかましさ"
masterVolume: "全体のやかましさ"
notUseSound: "音出さへん"
-useSoundOnlyWhenActive: "Misskeyがアクティブなときだけ音出す"
+useSoundOnlyWhenActive: "Sharkeyがアクティブなときだけ音出す"
details: "もっと"
chooseEmoji: "絵文字を選ぶ"
unableToProcess: "なんか奥の方で詰まってもうた"
@@ -590,7 +575,7 @@ sort: "仕分ける"
ascendingOrder: "小さい順"
descendingOrder: "大きい順"
scratchpad: "スクラッチパッド"
-scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Misskeyに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
+scratchpadDescription: "スクラッチパッドではAiScriptを色々試すことができるんや。Sharkeyに対して色々できるコードを書いて動かしてみたり、結果を見たりできるで。"
output: "出力"
script: "スクリプト"
disablePagesScript: "Pagesのスクリプトを無効にしてや"
@@ -700,14 +685,17 @@ behavior: "動作"
sample: "サンプル"
abuseReports: "通報"
reportAbuse: "通報"
-reportAbuseRenote: "リノート苦情だすで?"
+reportAbuseRenote: "ブースト苦情だすで?"
reportAbuseOf: "{name}を通報する"
fillAbuseReportDescription: "細かい通報理由を書いてなー。対象ノートがある時はそのURLも書いといてなー。"
abuseReported: "無事内容が送信されたみたいやで。おおきに〜。"
reporter: "通報者"
reporteeOrigin: "通報先"
reporterOrigin: "通報元"
+forwardReport: "リモートサーバーに通報を転送するで"
+forwardReportIsAnonymous: "リモートサーバーからはあんたの情報は見えんなって、匿名のシステムアカウントとして表示されるで。"
send: "送信"
+abuseMarkAsResolved: "対応したで"
openInNewTab: "新しいタブで開く"
openInSideView: "サイドビューで開く"
defaultNavigationBehaviour: "デフォルトのナビゲーション"
@@ -726,14 +714,14 @@ unclip: "クリップやめとく"
confirmToUnclipAlreadyClippedNote: "このノートはもう「{name}」に含まれとるで。ノート、このクリップから外そか?"
public: "パブリック"
private: "非公開"
-i18nInfo: "Misskeyは有志がいろんな言語に訳しとるで。{link}で翻訳に協力したってやー。"
+i18nInfo: "Sharkeyは有志がいろんな言語に訳しとるで。{link}で翻訳に協力したってやー。"
manageAccessTokens: "アクセストークンの管理"
accountInfo: "アカウント情報"
notesCount: "ノートの数やで"
repliesCount: "返信した数やで"
-renotesCount: "リノートした数やで"
+renotesCount: "ブーストした数やで"
repliedCount: "返信された数やで"
-renotedCount: "リノートされた数やで"
+renotedCount: "ブーストされた数やで"
followingCount: "フォロー数やで"
followersCount: "フォロワー数やで"
sentReactionsCount: "ツッコんだ数"
@@ -780,7 +768,7 @@ onlineUsersCount: "{n}人が起きとるで"
nUsers: "{n}ユーザー"
nNotes: "{n}ノート"
sendErrorReports: "エラーリポートを送る"
-sendErrorReportsDescription: "オンにしたら、なんか変なことが起きたとき、詳しいのが全部Misskeyに送られて、ソフトウェアをもっと良うするで。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴なんかが含まれるな。"
+sendErrorReportsDescription: "オンにしたら、なんか変なことが起きたとき、詳しいのが全部Sharkeyに送られて、ソフトウェアをもっと良うするで。エラー情報には、OSのバージョン、ブラウザの種類、行動履歴なんかが含まれるな。"
myTheme: "マイテーマ"
backgroundColor: "背景"
accentColor: "アクセント"
@@ -844,7 +832,6 @@ administration: "管理"
accounts: "アカウント"
switch: "切り替え"
noMaintainerInformationWarning: "管理者情報が設定されてへんで"
-noInquiryUrlWarning: "問い合わせ先URLが設定されてへんで。"
noBotProtectionWarning: "Botプロテクションが設定されてへんで。"
configure: "設定する"
postToGallery: "ギャラリーへ投稿"
@@ -875,7 +862,7 @@ hashtags: "ハッシュタグ"
troubleshooting: "トラブルシューティング"
useBlurEffect: "UIにぼかし効果を使うで"
learnMore: "詳しく"
-misskeyUpdated: "Misskeyが更新されたで!\nモデレーターの人らに感謝せなあかんで"
+misskeyUpdated: "Sharkeyが更新されたで!\nモデレーターの人らに感謝せなあかんで"
whatIsNew: "更新情報を見るで"
translate: "翻訳"
translatedFrom: "{x}から翻訳するで"
@@ -1004,9 +991,8 @@ numberOfLikes: "いいね数"
show: "表示"
neverShow: "今後表示しない"
remindMeLater: "また後で"
-didYouLikeMisskey: "Misskey気に入ってくれた?"
-pleaseDonate: "Misskeyは{host}が使うとる無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。"
-correspondingSourceIsAvailable: "{anchor}"
+didYouLikeMisskey: "Sharkey気に入ってくれた?"
+pleaseDonate: "Sharkeyは{host}が使うとる無料のソフトウェアやで。これからも開発を続けれるように、寄付したってな~。"
roles: "ロール"
role: "ロール"
noRole: "ロールはありまへん"
@@ -1033,8 +1019,7 @@ thisPostMayBeAnnoying: "この投稿は迷惑かもしらんで。"
thisPostMayBeAnnoyingHome: "ホームに投稿"
thisPostMayBeAnnoyingCancel: "やめとく"
thisPostMayBeAnnoyingIgnore: "このまま投稿"
-collapseRenotes: "見たことあるリノートは飛ばして表示するで"
-collapseRenotesDescription: "リアクションやリノートをしたことがあるノートをたたんで表示するで。"
+collapseRenotes: "見たことあるブーストは飛ばして表示するで"
internalServerError: "サーバー内部エラー"
internalServerErrorDescription: "サーバーでなんか変なこと起こっとるわ。"
copyErrorInfo: "エラー情報をコピるで"
@@ -1058,8 +1043,6 @@ resetPasswordConfirm: "パスワード作り直すんでええな?"
sensitiveWords: "けったいな単語"
sensitiveWordsDescription: "設定した単語が入っとるノートの公開範囲をホームにしたるわ。改行で区切ったら複数設定できるで。"
sensitiveWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。"
-prohibitedWords: "禁止ワード"
-prohibitedWordsDescription: "設定した言葉が含まれるノートを投稿しようとしたら、エラーが出るようにするで。改行で区切って複数設定できるで。"
prohibitedWordsDescription2: "スペースで区切るとAND指定、キーワードをスラッシュで囲んだら正規表現や。"
hiddenTags: "見えてへんハッシュタグ"
hiddenTagsDescription: "設定したタグを最近流行りのとこに見えんようにすんで。複数設定するときは改行で区切ってな。"
@@ -1090,7 +1073,7 @@ forceShowAds: "いっつも広告を映す"
addMemo: "メモを足す"
editMemo: "メモをいらう"
reactionsList: "ツッコミ一覧"
-renotesList: "リノート一覧"
+renotesList: "ブースト一覧"
notificationDisplay: "通知見せる"
leftTop: "左上"
rightTop: "右上"
@@ -1108,8 +1091,6 @@ preservedUsernames: "予約ユーザー名"
preservedUsernamesDescription: "予約しとくユーザー名を行ごとに挙げるで。ここで指定されたユーザー名はアカウント作るときに使えへんくなるけど、管理者は例外や。あと、もうあるアカウントも例外やな。"
createNoteFromTheFile: "このファイル使うてノート作るで"
archive: "アーカイブ"
-archived: "アーカイブ済み"
-unarchive: "アーカイブ解除"
channelArchiveConfirmTitle: "{name}をアーカイブしてええか?"
channelArchiveConfirmDescription: "アーカイブしたら、チャンネル一覧とか検索結果からなくなるし、新しく書き込みもできへんなるで。"
thisChannelArchived: "このチャンネル、アーカイブされとるで。"
@@ -1120,9 +1101,6 @@ preventAiLearning: "生成AIの学習に使わんといて"
preventAiLearningDescription: "他の文章生成AIとか画像生成AIに、投稿したノートとか画像なんかを勝手に使わんように頼むで。具体的にはnoaiフラグをHTMLレスポンスに含めるんやけど、これ聞いてくれるんはAIの気分次第やから、使われる可能性もちょっとはあるな。"
options: "オプション"
specifyUser: "ユーザー指定"
-lookupConfirm: "照会するけどええか?"
-openTagPageConfirm: "ハッシュタグのページを開くんか?"
-specifyHost: "ホスト指定"
failedToPreviewUrl: "プレビューできへん"
update: "更新"
rolesThatCanBeUsedThisEmojiAsReaction: "ツッコミとして使えるロール"
@@ -1131,7 +1109,7 @@ rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "ロールは公開ロー
cancelReactionConfirm: "ツッコむんをやっぱやめるか?"
changeReactionConfirm: "ツッコミを別のに変えるか?"
later: "あとで"
-goToMisskey: "Misskeyへ"
+goToMisskey: "Sharkeyへ"
additionalEmojiDictionary: "絵文字の追加辞書"
installed: "インストールしとる"
branding: "ブランディング"
@@ -1166,7 +1144,7 @@ pastAnnouncements: "過去のお知らせやで"
youHaveUnreadAnnouncements: "あんたまだこのお知らせ読んどらんやろ。"
useSecurityKey: "ブラウザまたはデバイスの言う通りに、セキュリティキーまたはパスキーを使ってや。"
replies: "返事"
-renotes: "リノート"
+renotes: "ブースト"
loadReplies: "返信を見るで"
loadConversation: "会話を見るで"
pinnedList: "ピン留めしはったリスト"
@@ -1177,11 +1155,10 @@ unnotifyNotes: "投稿の通知やめる"
authentication: "認証"
authenticationRequiredToContinue: "続けるんなら認証してや。"
dateAndTime: "日時"
-showRenotes: "リノート出す"
+showRenotes: "ブースト出す"
edited: "いじったやつ"
notificationRecieveConfig: "通知もらうかの設定"
mutualFollow: "お互いフォローしてんで"
-followingOrFollower: "フォロー中またはフォロワー"
fileAttachedOnly: "ファイルのっけてあるやつだけ"
showRepliesToOthersInTimeline: "タイムラインに他の人への返信とかも入れるで"
hideRepliesToOthersInTimeline: "タイムラインに他の人への返信とかは入れへん"
@@ -1191,12 +1168,6 @@ confirmShowRepliesAll: "これは元に戻せへんから慎重に決めてや
confirmHideRepliesAll: "これは元に戻せへんから慎重に決めてや。本当にタイムラインに今フォローしとる全員の返信を入れへんのか?"
externalServices: "他のサイトのサービス"
sourceCode: "ソースコード"
-sourceCodeIsNotYetProvided: "ソースコードはまだ提供されてへんで。問題の修正について管理者に問い合わせてみ。"
-repositoryUrl: "リポジトリURL"
-repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入するで。Misskeyをそのまんま(ソースコードにいかなる変更も加えずに)使っとる場合は https://github.com/misskey-dev/misskey と記入するで。"
-repositoryUrlOrTarballRequired: "リポジトリを公開してへんなら、代わりにtarballを提供する必要があるで。詳細は.config/example.ymlを参照してな。"
-feedback: "フィードバック"
-feedbackUrl: "フィードバックURL"
impressum: "運営者の情報"
impressumUrl: "運営者の情報URL"
impressumDescription: "ドイツとかの一部んところではな、表示が義務付けられてんねん(Impressum)。"
@@ -1232,8 +1203,6 @@ soundWillBePlayed: "サウンドが再生されるで"
showReplay: "リプレイ見る"
replay: "リプレイ"
replaying: "リプレイ中"
-endReplay: "リプレイを終了"
-copyReplayData: "リプレイデータをコピー"
ranking: "ランキング"
lastNDays: "直近{n}日"
backToTitle: "タイトルへ"
@@ -1241,44 +1210,8 @@ hemisphere: "住んでる地域"
withSensitive: "センシティブなファイルを含むノートを表示"
userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿"
enableHorizontalSwipe: "スワイプしてタブを切り替える"
-loading: "読み込み中"
-surrender: "やめとく"
-gameRetry: "もういっちょ"
-notUsePleaseLeaveBlank: "使用せえへん場合は空欄にしてや"
-useTotp: "ワンタイムパスワードを使う"
-useBackupCode: "バックアップコードを使う"
-launchApp: "アプリを起動"
-useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
-keepOriginalFilename: "オリジナルのファイル名を保持"
-keepOriginalFilenameDescription: "この設定をオフにすると、アップロード時にファイル名が自動でランダム文字列に置き換えられるで。"
-noDescription: "説明文はあらへんで"
-alwaysConfirmFollow: "フォローの際常に確認する"
-inquiry: "問い合わせ"
-tryAgain: "もう一度試しいや。"
-confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示するとき確認する"
-sensitiveMediaRevealConfirm: "センシティブなメディアやで。表示するんか?"
-createdLists: "作成したリスト"
-createdAntennas: "作成したアンテナ"
-_delivery:
- status: "配信状態"
- stop: "配信せぇへん"
- resume: "配信再開"
- _type:
- none: "配信しとる"
- manuallySuspended: "手動停止中"
- goneSuspended: "サーバー削除のため停止中"
- autoSuspendedForNotResponding: "サーバー応答せえへんから停止中"
_bubbleGame:
howToPlay: "遊び方"
- hold: "ホールド"
- _score:
- score: "スコア"
- scoreYen: "稼いだ金額"
- highScore: "ハイスコア"
- maxChain: "最大チェーン数"
- yen: "{yen}円"
- estimatedQty: "{qty}個分"
- scoreSweets: "おにぎり {onigiriQtyWithUnit}"
_howToPlay:
section1: "位置を調整してハコにモノを落とすで。"
section2: "同じもんがくっついたら別のやつになって、スコアがもらえるで。"
@@ -1308,7 +1241,7 @@ _initialAccountSetting:
pushNotificationDescription: "プッシュ通知を有効にすると{name}の通知をあんたのデバイスで受け取れるで。"
initialAccountSettingCompleted: "初期設定終わりや!"
haveFun: "{name}、楽しんでな~"
- youCanContinueTutorial: "こんまま{name}(Misskey)の使い方のチュートリアルにも行けるけど、ここでやめてすぐに使い始めてもええで。"
+ youCanContinueTutorial: "こんまま{name}(Sharkey)の使い方のチュートリアルにも行けるけど、ここでやめてすぐに使い始めてもええで。"
startTutorial: "チュートリアルはじめる"
skipAreYouSure: "初期設定飛ばすか?"
laterAreYouSure: "初期設定あとでやり直すん?"
@@ -1319,10 +1252,10 @@ _initialTutorial:
skipAreYouSure: "チュートリアルやめるか?"
_landing:
title: "チュートリアルによう来たな"
- description: "ここでは、Misskeyのカンタンな使い方とか機能を確かめれんで。"
+ description: "ここでは、Sharkeyのカンタンな使い方とか機能を確かめれんで。"
_note:
title: "ノートってなんや?"
- description: "Misskeyでの投稿は「ノート」って呼ばれてんで。ノートは順々にタイムラインに載ってて、リアルタイムで新しくなってってんで。"
+ description: "Sharkeyでの投稿は「ノート」って呼ばれてんで。ノートは順々にタイムラインに載ってて、リアルタイムで新しくなってってんで。"
reply: "返信もできるで。返信の返信もできるから、スレッドっぽく会話をそのまま続けれもするで。"
renote: "そのノートを自分のタイムラインに流して共有できるで。テキスト入れて引用してもええな。"
reaction: "ツッコミをつけることもできるで。細かいことは次のページや。"
@@ -1336,7 +1269,7 @@ _initialTutorial:
reactDone: "「ー」ボタンでツッコミやめれるで。"
_timeline:
title: "タイムラインのしくみ"
- description1: "Misskeyには、いろいろタイムラインがあんで(ただ、サーバーによっては無効化されてるところもあるな)。"
+ description1: "Sharkeyには、いろいろタイムラインがあんで(ただ、サーバーによっては無効化されてるところもあるな)。"
home: "あんたがフォローしてるアカウントの投稿が見れんねん。"
local: "このサーバーの中におる全員の投稿が見れるで。"
social: "ホームタイムラインの投稿もローカルタイムラインのも一緒に見れるで。"
@@ -1345,12 +1278,12 @@ _initialTutorial:
description3: "その他にも、リストタイムラインとかチャンネルタイムラインとかがあんねん。詳しいのは{link}を見とき。"
_postNote:
title: "ノートの投稿設定"
- description1: "Misskeyにノートを投稿するとき、いろんなオプションが付けれるで。投稿画面はこんな感じや。"
+ description1: "Sharkeyにノートを投稿するとき、いろんなオプションが付けれるで。投稿画面はこんな感じや。"
_visibility:
description: "ノートを見れる相手を制限できるわ。"
public: "みんなに見せるで。"
- home: "ホームタイムラインにだけ見せるで。フォロワーとか、プロフィールを見に来た人、リノートからも見れるから、実質は全員見れるけどな。あんまし広がりにくいってことや。"
- followers: "フォロワーにだけ見せるで。自分以外はリノートできへんし、フォロワー以外は絶対に見れへん。"
+ home: "ホームタイムラインにだけ見せるで。フォロワーとか、プロフィールを見に来た人、ブーストからも見れるから、実質は全員見れるけどな。あんまし広がりにくいってことや。"
+ followers: "フォロワーにだけ見せるで。自分以外はブーストできへんし、フォロワー以外は絶対に見れへん。"
direct: "指定した人にだけ公開されて、ついでに通知も送るで。ダイレクトメールの代わりとして使ってな。"
doNotSendConfidencialOnDirect1: "機密情報を送るときは十分注意せえよ。"
doNotSendConfidencialOnDirect2: "送信先のサーバーの管理者は投稿内容が見れるから、信用できへんサーバーのひとにダイレクト投稿するときには、めっちゃ用心しとくんやで。"
@@ -1393,8 +1326,6 @@ _serverSettings:
fanoutTimelineDescription: "入れると、おのおのタイムラインを取得するときにめちゃめちゃ動きが良うなって、データベースが軽くなるわ。でも、Redisのメモリ使う量が増えるから注意な。サーバーのメモリが足りんときとか、動きが変なときは切れるで。"
fanoutTimelineDbFallback: "データベースにフォールバックする"
fanoutTimelineDbFallbackDescription: "有効にしたら、タイムラインがキャッシュん中に入ってないときにDBにもっかい問い合わせるフォールバック処理ってのをやっとくで。切ったらフォールバック処理をやらんからサーバーはもっと軽くなんねんけど、タイムラインの取得範囲がちょっと減るで。"
- inquiryUrl: "問い合わせ先URL"
- inquiryUrlDescription: "サーバー運営者へのお問い合わせフォームのURLや、運営者の連絡先等が記載されたWebページのURLを指定するで。"
_accountMigration:
moveFrom: "別のアカウントからこのアカウントに引っ越す"
moveFromSub: "別のアカウントへエイリアスを作る"
@@ -1416,7 +1347,7 @@ _achievements:
_notes1:
title: "まいど!"
description: "初めてノート投稿したった"
- flavor: "Misskeyを楽しんでな~"
+ flavor: "Sharkeyを楽しんでな~"
_notes10:
title: "ノートの天保山"
description: "ノートを10回投稿した"
@@ -1512,7 +1443,7 @@ _achievements:
_login1000:
title: "ノートマイスターⅢ"
description: "通算1,000日ログインした"
- flavor: "Misskeyようさん使てもろておおきにな!"
+ flavor: "Sharkeyようさん使てもろておおきにな!"
_noteClipped1:
title: "アカンどれもクリップしたいわ"
description: "初めてノートをクリップした"
@@ -1572,9 +1503,9 @@ _achievements:
title: "実績好き"
description: "実績一覧を3分以上眺め続けた"
_iLoveMisskey:
- title: "Misskey好きやねん"
- description: "\"I ❤ #Misskey\"を投稿した"
- flavor: "Misskeyを使ってくれておおきにな~ by 開発チーム"
+ title: "Sharkey好きやねん"
+ description: "\"I ❤ #Sharkey\"を投稿した"
+ flavor: "Sharkeyを使ってくれておおきにな~ by 開発チーム"
_foundTreasure:
title: "なんでも鑑定団"
description: "隠されたお宝を発見した"
@@ -1582,7 +1513,7 @@ _achievements:
title: "ねんね"
description: "クライアントを起動してから30分以上経過した"
_client60min:
- title: "Misskeyの見過ぎや!"
+ title: "Sharkeyの見過ぎや!"
description: "クライアント付けてから1時間経ってもうたで。"
_noteDeletedWithin1min:
title: "*おおっと*"
@@ -1653,7 +1584,7 @@ _achievements:
title: "心配性"
description: "通知のテストしすぎやって"
_tutorialCompleted:
- title: "Misskeyひよっこ講座 修了証"
+ title: "Sharkeyひよっこ講座 修了証"
description: "チュートリアル全部やった"
_bubbleGameExplodingHead:
title: "🤯"
@@ -1702,7 +1633,6 @@ _role:
gtlAvailable: "グローバルタイムライン見る"
ltlAvailable: "ローカルタイムライン見る"
canPublicNote: "パブリック投稿できるか"
- mentionMax: "ノート内の最大メンション数"
canInvite: "サーバー招待コード作る"
inviteLimit: "招待コード作れる数"
inviteLimitCycle: "招待コードの作れる間隔"
@@ -1711,7 +1641,6 @@ _role:
canManageAvatarDecorations: "アバターを飾るモンの管理"
driveCapacity: "ドライブ容量"
alwaysMarkNsfw: "勝手にファイルにNSFWをくっつける"
- canUpdateBioMedia: "アイコンとバナーの更新を許可"
pinMax: "ノートピン留めできる数"
antennaMax: "アンテナ作れる数"
wordMuteMax: "ワードミュートの最大文字数"
@@ -1727,14 +1656,8 @@ _role:
canUseTranslator: "翻訳使えるかどうか"
avatarDecorationLimit: "アイコンデコのいっちばんつけれる数"
_condition:
- roleAssignedTo: "マニュアルロールにアサイン済み"
isLocal: "ローカルユーザー"
isRemote: "リモートユーザー"
- isCat: "猫ユーザー"
- isBot: "botユーザー"
- isSuspended: "サスペンド済みユーザー"
- isLocked: "鍵アカウントユーザー"
- isExplorable: "「アカウントを見つけやすくする」が有効なユーザー"
createdLessThan: "アカウント作ってから~以内"
createdMoreThan: "アカウント作ってから~経過"
followersLessThanOrEq: "フォロワー数が~以下"
@@ -1804,7 +1727,6 @@ _plugin:
installWarn: "信頼できへんプラグインはインストールせんとってな"
manage: "プラグインの管理"
viewSource: "ソース見る"
- viewLog: "ログを表示"
_preferencesBackups:
list: "作ったバックアップ"
saveNew: "新しく保存"
@@ -1819,8 +1741,8 @@ _preferencesBackups:
deleteConfirm: "{name}を消すん?"
renameConfirm: "「{old}」を「{new}」に変えるん?"
noBackups: "バックアップはないで。「新しく保存」ってとこでこのクライアント設定を鯖に保存できるで。"
- createdAt: "作った日時: {date} {time}"
- updatedAt: "更新日時: {date} {time}"
+ createdAt: "作った日時:{date}{time}"
+ updatedAt: "更新日時:{date}{time}"
cannotLoad: "読み込みできへん..."
invalidFile: "ファイル形式が違うで?"
_registry:
@@ -1830,14 +1752,12 @@ _registry:
domain: "ドメイン"
createKey: "キーを作る"
_aboutMisskey:
- about: "Misskeyはsyuiloが2014年からずっと作ってはる、オープンソースなソフトウェアや。"
+ about: "Sharkeyは、Misskeyをベースにしたオープンソースなソフトウェアや。"
contributors: "主な貢献者"
allContributors: "全ての貢献者"
source: "ソースコード"
- original: "オリジナル"
- thisIsModifiedVersion: "{name}はオリジナルのMisskeyをいじったバージョンをつこうてるで。"
- translation: "Misskeyを翻訳"
- donate: "Misskeyに寄付"
+ translation: "Sharkeyを翻訳"
+ donate: "Sharkeyに寄付"
morePatrons: "他にもぎょうさんの人からサポートしてもろてんねん。ほんまおおきに🥰"
patrons: "支援者"
projectMembers: ""
@@ -1865,7 +1785,7 @@ _channel:
notesCount: "{n}こ投稿があるで"
nameAndDescription: "名前と説明"
nameOnly: "名前だけ"
- allowRenoteToExternal: "チャンネルの外にリノートできるようにする"
+ allowRenoteToExternal: "チャンネルの外にブーストできるようにする"
_menuDisplay:
sideFull: "横"
sideIcon: "横(アイコン)"
@@ -1943,6 +1863,7 @@ _theme:
buttonBg: "ボタンの背景"
buttonHoverBg: "ボタンの背景 (ホバー)"
inputBorder: "入力ボックスの縁取り"
+ listItemHoverBg: "リスト項目の背景 (ホバー)"
driveFolderBg: "ドライブフォルダーの背景"
wallpaperOverlay: "壁紙のオーバーレイ"
badge: "バッジ"
@@ -1954,6 +1875,8 @@ _sfx:
note: "ノート"
noteMy: "ノート(自分)"
notification: "通知"
+ antenna: "アンテナ受信"
+ channel: "チャンネル通知"
reaction: "ツッコミ選んどるとき"
_soundSettings:
driveFile: "ドライブん中の音使う"
@@ -1961,8 +1884,7 @@ _soundSettings:
driveFileTypeWarn: "このファイルは対応しとらへん"
driveFileTypeWarnDescription: "音声ファイルを選びや"
driveFileDurationWarn: "音が長すぎるわ"
- driveFileDurationWarnDescription: "長い音使うたらMisskey使うのに良うないかもしれへんで。それでもええか?"
- driveFileError: "音声が読み込めへんかったで。設定を変更せえや"
+ driveFileDurationWarnDescription: "長い音使うたらSharkey使うのに良うないかもしれへんで。それでもええか?"
_ago:
future: "未来"
justNow: "ついさっき"
@@ -1992,6 +1914,7 @@ _2fa:
registerTOTP: "認証アプリの設定はじめる"
step1: "ほんなら、{a}や{b}とかの認証アプリを使っとるデバイスにインストールしてな。"
step2: "次に、ここにあるQRコードをアプリでスキャンしてな~。"
+ step2Click: "QRコード押したら、今使とる端末に入っとる認証アプリとかキーリングに登録できるで。"
step2Uri: "デスクトップアプリを使う時は次のURIを入れるで"
step3Title: "確認コードを入れてーや"
step3: "アプリに映っとる確認コード(トークン)を入れて終わりや。"
@@ -2015,7 +1938,6 @@ _2fa:
backupCodesDescription: "認証アプリが使用できんなった場合、以下のバックアップコードを使ってアカウントにアクセスできるで。これらのコードは必ず安全な場所に置いときや。各コードは一回だけ使用できるで。"
backupCodeUsedWarning: "バックアップコードが使用されたで。認証アプリが使えなくなってるん場合、なるべく早く認証アプリを再設定しや。"
backupCodesExhaustedWarning: "バックアップコードが全て使用されたで。認証アプリを利用できん場合、これ以上アカウントにアクセスできなくなるで。認証アプリを再登録しや。"
- moreDetailedGuideHere: "詳細なガイドはこちら"
_permissions:
"read:account": "アカウントの情報を見るで"
"write:account": "アカウントの情報を変更するで"
@@ -2066,6 +1988,7 @@ _permissions:
"read:admin:server-info": "サーバーの情報見る"
"read:admin:show-moderation-log": "モデレーションログ見る"
"read:admin:show-user": "ユーザーのプライベートな情報見る"
+ "read:admin:show-users": "ユーザーのプライベートな情報見る"
"write:admin:suspend-user": "ユーザーを凍結"
"write:admin:unset-user-avatar": "ユーザーのアバターを削除"
"write:admin:unset-user-banner": "ユーザーのバナーを削除"
@@ -2276,7 +2199,6 @@ _play:
title: "タイトル"
script: "スクリプト"
summary: "説明"
- visibilityDescription: "非公開に設定するとプロフィールに表示されへんくなるけど、URLを知っとる人は引き続きアクセスできるで。"
_pages:
newPage: "ページを作る"
editPage: "ページの編集"
@@ -2321,8 +2243,6 @@ _pages:
section: "セクション"
image: "画像"
button: "ボタン"
- dynamic: "動的ブロック"
- dynamicDescription: "このブロックは廃止されとるで。今後は{play}を利用してや。"
note: "ノート埋め込み"
_note:
id: "ノートID"
@@ -2337,7 +2257,7 @@ _notification:
youGotMention: "{name}からのメンション"
youGotReply: "{name}からのリプライ"
youGotQuote: "{name}による引用"
- youRenoted: "{name}がリノートしたみたいやで"
+ youRenoted: "{name}がブーストしたみたいやで"
youWereFollowed: "フォローされたで"
youReceivedFollowRequest: "フォロー許可してほしいみたいやな"
yourFollowRequestAccepted: "フォローさせてもろたで"
@@ -2352,10 +2272,8 @@ _notification:
sendTestNotification: "テスト通知を送信するで"
notificationWillBeDisplayedLikeThis: "通知はこのように表示されるで"
reactedBySomeUsers: "{n}人がツッコんだで"
- likedBySomeUsers: "{n}人がいいねしたで"
- renotedBySomeUsers: "{n}人がリノートしたで"
+ renotedBySomeUsers: "{n}人がブーストしたで"
followedBySomeUsers: "{n}人にフォローされたで"
- flushNotification: "通知の履歴をリセットする"
_types:
all: "すべて"
note: "あんたらの新規投稿"
@@ -2370,7 +2288,6 @@ _notification:
followRequestAccepted: "フォローが受理されたで"
roleAssigned: "ロールが付与された"
achievementEarned: "実績の獲得"
- login: "ログイン"
app: "連携アプリからの通知や"
_actions:
followBack: "フォローバック"
@@ -2380,7 +2297,6 @@ _deck:
alwaysShowMainColumn: "いつもメインカラムを表示"
columnAlign: "カラムの寄せ"
addColumn: "カラムを追加"
- newNoteNotificationSettings: "新着ノート通知の設定"
configureColumn: "カラムの設定"
swapLeft: "左に移動"
swapRight: "右に移動"
@@ -2419,39 +2335,18 @@ _drivecleaner:
orderByCreatedAtAsc: "追加日の古い順"
_webhookSettings:
createWebhook: "Webhookをつくる"
- modifyWebhook: "Webhookを編集"
name: "名前"
secret: "シークレット"
- trigger: "トリガー"
+ events: "Webhookを投げるタイミング"
active: "有効"
_events:
follow: "フォローしたとき~!"
followed: "フォローもらったとき~!"
note: "ノートを投稿したとき~!"
reply: "返信があるとき~!"
- renote: "リノートされるとき~!"
+ renote: "ブーストされるとき~!"
reaction: "ツッコまれたとき~!"
mention: "メンションがあるとき~!"
- _systemEvents:
- abuseReport: "ユーザーから通報があったとき"
- abuseReportResolved: "ユーザーからの通報を処理したとき"
- userCreated: "ユーザーが作成されたとき"
- deleteConfirm: "ほんまにWebhookをほかしてもええんか?"
-_abuseReport:
- _notificationRecipient:
- createRecipient: "通報の通知先を追加"
- modifyRecipient: "通報の通知先を編集"
- recipientType: "通知先の種類"
- _recipientType:
- mail: "メール"
- webhook: "Webhook"
- _captions:
- mail: "モデレーター権限を持つユーザーのメアドに通知を送るで(通報を受けた時のみ)"
- webhook: "指定したSystemWebhookに通知を送るで(通報を受けた時と通報を解決した時にそれぞれ発信)"
- keywords: "キーワード"
- notifiedUser: "通知先ユーザー"
- notifiedWebhook: "使用するWebhook"
- deleteConfirm: "通知先を削除してもええか?"
_moderationLogTypes:
createRole: "ロールを追加すんで"
deleteRole: "ロールほかす"
@@ -2476,7 +2371,6 @@ _moderationLogTypes:
resetPassword: "パスワードをリセット"
suspendRemoteInstance: "リモートサーバーを止めんで"
unsuspendRemoteInstance: "リモートサーバーを再開すんで"
- updateRemoteInstanceNote: "リモートサーバーのモデレーションノート更新"
markSensitiveDriveFile: "ファイルをセンシティブ付与"
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
resolveAbuseReport: "苦情を解決"
@@ -2489,8 +2383,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "アイコンデコレーションを削除"
unsetUserAvatar: "この子のアイコン元に戻す"
unsetUserBanner: "この子のバナー元に戻す"
- createSystemWebhook: "SystemWebhookを作成"
- updateSystemWebhook: "SystemWebhookを更新"
_fileViewer:
title: "ファイルの詳しい情報"
type: "ファイルの種類"
@@ -2599,26 +2491,7 @@ _reversi:
opponentHasSettingsChanged: "相手が設定変えたで"
allowIrregularRules: "変則許可 (完全フリー)"
disallowIrregularRules: "変則なし"
- showBoardLabels: "盤面に行・列番号を表示"
- useAvatarAsStone: "石をアイコンにする"
_offlineScreen:
title: "オフライン - サーバーに接続できひんで"
header: "サーバーに接続できへんわ"
-_urlPreviewSetting:
- title: "URLプレビューの設定"
- enable: "URLプレビューを有効にする"
- timeout: "プレビュー取得時のタイムアウト(ms)"
- timeoutDescription: "プレビュー取得の所要時間がこの値を超えた場合、プレビューは生成されへんで。"
- maximumContentLength: "Content-Lengthの最大値(byte)"
- maximumContentLengthDescription: "Content-Lengthがこの値を超えた場合、プレビューは生成されへんで。"
- requireContentLength: "Content-Lengthが取得できた場合のみプレビューを生成"
- requireContentLengthDescription: "相手サーバがContent-Lengthを返さない場合、プレビューは生成されへんで。"
- userAgent: "User-Agent"
- userAgentDescription: "プレビュー取得時に使用されるUser-Agentを設定するで。空欄の場合、デフォルトのUser-Agentが使用されるで。"
- summaryProxy: "プレビューを生成するプロキシのエンドポイント"
- summaryProxyDescription: "Misskey本体やなく、サマリープロキシを使用してプレビューを生成するで。"
- summaryProxyDescription2: "プロキシには下記パラメータがクエリ文字列として連携されるで。プロキシ側がこれらをサポートせえへんときは、設定値は無視されるで。"
-_mediaControls:
- pip: "ピクチャインピクチャ"
- playbackRate: "再生速度"
- loop: "ループ再生"
+
diff --git a/locales/jbo-EN.yml b/locales/jbo-EN.yml
index d4fea291d7..297ca53dd7 100644
--- a/locales/jbo-EN.yml
+++ b/locales/jbo-EN.yml
@@ -1,3 +1,4 @@
---
_lang_: "la .lojban."
headlineMisskey: "lo se tcana noi jorne fi loi notci"
+
diff --git a/locales/kab-KAB.yml b/locales/kab-KAB.yml
index d4aa36fa70..b976f028f0 100644
--- a/locales/kab-KAB.yml
+++ b/locales/kab-KAB.yml
@@ -104,7 +104,4 @@ _deck:
_columns:
notifications: "Ilɣuyen"
list: "Tibdarin"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Imayl"
+
diff --git a/locales/kn-IN.yml b/locales/kn-IN.yml
index 222599572a..bb6d1ee242 100644
--- a/locales/kn-IN.yml
+++ b/locales/kn-IN.yml
@@ -77,8 +77,6 @@ _profile:
username: "ಬಳಕೆಹೆಸರು"
_notification:
youWereFollowed: "ಹಿಂಬಾಲಿಸಿದರು"
- _types:
- login: "ಪ್ರವೇಶ"
_actions:
reply: "ಉತ್ತರಿಸು"
_deck:
@@ -86,3 +84,4 @@ _deck:
notifications: "ಅಧಿಸೂಚನೆಗಳು"
tl: "ಸಮಯಸಾಲು"
mentions: "ಹೆಸರಿಸಿದ"
+
diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml
index 6c667b48da..b1702114be 100644
--- a/locales/ko-GS.yml
+++ b/locales/ko-GS.yml
@@ -16,8 +16,8 @@ cancel: "아이예"
noThankYou: "뎃어예"
enterUsername: "사용자 이럼 서기"
renotedBy: "{user}님이 리노트햇어예"
-noNotes: "노트가 어ᇝ십니다"
-noNotifications: "알림이 어ᇝ십니다"
+noNotes: "노트가 없십니다"
+noNotifications: "알림이 없십니다"
instance: "서버"
settings: "설정"
notificationSettings: "알림 설정"
@@ -26,7 +26,7 @@ otherSettings: "다린 설정"
openInWindow: "창서 옐기"
profile: "프로필"
timeline: "타임라인"
-noAccountDescription: "자기소개가 어ᇝ십니다"
+noAccountDescription: "자기소개가 없십니다"
login: "로그인"
loggingIn: "로그인하고 잇어예"
logout: "로그아웃"
@@ -80,7 +80,7 @@ unfollowConfirm: "{name}님얼 고마 팔로잉합니꺼?"
exportRequested: "내가기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다. 요청이 껕나모 ‘드라이브’에 옇십니다."
importRequested: "가오기 요청얼 햇십니다. 시간이 쪼매 걸릴 깁니다."
lists: "리스트"
-noLists: "리스트가 어ᇝ십니다"
+noLists: "리스트가 없십니다"
note: "노트"
notes: "노트"
following: "팔로잉"
@@ -161,7 +161,7 @@ youCanCleanRemoteFilesCache: "파일 간리으 🗑️ 모냥얼 누질리모
cacheRemoteSensitiveFiles: "웬겍으 수ᇚ힌 파일얼 캐시하기"
cacheRemoteSensitiveFilesDescription: "요 설정얼 꺼모 웬겍 수ᇚ힌 파일이 캐시하지 아이하고 바리 링크합니다."
flagAsBot: "자동 게정입니다"
-flagAsBotDescription: "요 게정얼 프로그램서 설라먼 키야 합니다. 키모 다런 개발자가 반엉얼 끋어ᇝ이 데풀이하지 몬 하게 도아 줄 수 잇고 Misskey으 시스템서 자동 게정이 뎁니다."
+flagAsBotDescription: "요 게정얼 프로그램서 설라먼 키야 합니다. 키모 다런 개발자가 반엉얼 끋없이 데풀이하지 몬 하게 도아 줄 수 잇고 Misskey으 시스템서 자동 게정이 뎁니다."
flagAsCat: "애웅애웅애웅애웅!"
flagAsCatDescription: "애옹?"
flagShowTimelineReplies: "타임라인서 노트으 답하기 보기"
@@ -176,7 +176,7 @@ wallpaper: "벡지"
setWallpaper: "벡지 설정"
removeWallpaper: "벡지 뭉캐기"
searchWith: "찾기: {q}"
-youHaveNoLists: "리스트가 어ᇝ십니다"
+youHaveNoLists: "리스트가 없십니다"
followConfirm: "{name}님얼 팔로잉합니꺼?"
proxyAccount: "프락시 게정"
proxyAccountDescription: "프락시 게정언 턱벨한 조겐서 웬겍 팔로잉얼 하넌 게정입니다. 사용자가 웬겍 사용자럴 리스트에 옇얼 때 리스트에 옇언 사용자럴 누도 팔로잉 아이하모 할동이 서버로 아이 오니께 요 게정이 아인 프락시 게정얼 팔로잉하게 합니다."
@@ -210,17 +210,17 @@ instanceInfo: "서버 정보"
statistics: "통게"
clearQueue: "대기옐 비우기"
clearQueueConfirmTitle: "대기옐얼 비웁니꺼?"
-clearQueueConfirmText: "대기옐에 잇넌 걸얼 아이 보냅니다. 흐이 요 동작언 할 필요가 어ᇝ십니다."
+clearQueueConfirmText: "대기옐에 잇넌 걸얼 아이 보냅니다. 흐이 요 동작언 할 필요가 없십니다."
clearCachedFiles: "캐시 비우기"
clearCachedFilesConfirm: "캐시한 웬겍 파일얼 말캉 뭉캡니꺼?"
blockedInstances: "차단한 서버"
blockedInstancesDescription: "차단할라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 차단한 서버넌 요 서버하고 교류 몬 합니다."
silencedInstances: "수ᇚ훈 서버"
-silencedInstancesDescription: "수ᇚ훌라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 수ᇚ훈 서버으 게정언 말캉 ‘수ᇚ후기’가 데서 팔로잉 요청만 데고 팔로워가 아인 로컬 게정서 멘션얼 몬 합니다. 차단한 서버넌 상간 어ᇝ십니다."
+silencedInstancesDescription: "수ᇚ훌라넌 서버으 호스트럴 줄 바꿈해서로 비이 줍니다. 수ᇚ훈 서버으 게정언 말캉 ‘수ᇚ후기’가 데서 팔로잉 요청만 데고 팔로워가 아인 로컬 게정서 멘션얼 몬 합니다. 차단한 서버넌 상간 없십니다."
muteAndBlock: "수ᇚ훔하고 차단"
mutedUsers: "수ᇚ훈 사용자"
blockedUsers: "차단한 사용자"
-noUsers: "사용자가 어ᇝ십니다"
+noUsers: "사용자가 없십니다"
editProfile: "프로필 적기"
noteDeleteConfirm: "요 노트럴 뭉캡니꺼?"
pinLimitExceeded: "더 몬 붙입니다"
@@ -230,15 +230,15 @@ processing: "처리하고 잇어예"
preview: "미리보기"
default: "기본값"
defaultValueIs: "기본값: {value}"
-noCustomEmojis: "이모지가 어ᇝ십니다"
-noJobs: "작업이 어ᇝ십니다"
+noCustomEmojis: "이모지가 없십니다"
+noJobs: "작업이 없십니다"
federating: "옌합하고 잇어예"
blocked: "차단햇어예"
suspended: "고만 보내예"
all: "말캉"
subscribing: "구독하고 잇어예"
publishing: "보내고 잇어예"
-notResponding: "답이 어ᇝ어예"
+notResponding: "답이 없어예"
instanceFollowing: "서버으 팔로잉"
instanceFollowers: "서버으 팔로워"
instanceUsers: "서버으 사용자"
@@ -275,7 +275,7 @@ uploadFromUrlRequested: "올리기럴 요청햇십니다"
uploadFromUrlMayTakeTime: "올리기가 껕날라먼 시간이 쪼매 걸릴 깁니다."
explore: "살펴보기"
messageRead: "이럿어예"
-noMoreHistory: "요카마 옛날 기록이 어ᇝ십니다"
+noMoreHistory: "요카마 엣날 기록이 없십니다"
startMessaging: "대화하기"
nUsersRead: "{n}멩이 이럿십니다"
agreeTo: "{0}에 동이하기"
@@ -432,28 +432,28 @@ securityKey: "보안키"
lastUsed: "마지막 쓰임"
lastUsedAt: "마지막 쓰임: {t}"
unregister: "맨걸기 무루기"
-passwordLessLogin: "비밀번호 어ᇝ이 로그인"
-passwordLessLoginDescription: "비밀번호 어ᇝ이 보안 키나 패스 키만 서서 로그인합니다."
+passwordLessLogin: "비밀번호 없시 로그인"
+passwordLessLoginDescription: "비밀번호 말고 보안키나 패스키 같은 것만 써 가 로그인합니다."
resetPassword: "비밀번호 재설정"
-newPasswordIs: "새 비밀번호넌 ‘{password}’입니다"
+newPasswordIs: "새 비밀번호는 \"{password}\" 입니다"
reduceUiAnimation: "화면 움직임 효과들을 수ᇚ후기"
share: "노누기"
notFound: "몬 찾앗십니다"
-notFoundDescription: "선 주소에 맞넌 페이지가 어ᇝ십니다."
-uploadFolder: "기본 올리기 위치"
-markAsReadAllNotifications: "모던 알림얼 읽엄 포시"
-markAsReadAllUnreadNotes: "모던 걸얼 읽엄 포시"
-markAsReadAllTalkMessages: "모던 대화 읽엄 포시"
+notFoundDescription: "고런 주소로 들어가는 하멘은 없십니다."
+uploadFolder: "기본 업로드 위치"
+markAsReadAllNotifications: "모든 알림 이럿다고 표시"
+markAsReadAllUnreadNotes: "모든 글 이럿다고 표시"
+markAsReadAllTalkMessages: "모든 대화 이럿다고 표시"
help: "도움말"
-inputMessageHere: "옇다 메시지럴 서이소"
-close: "꺼기"
+inputMessageHere: "여따가 메시지를 입력해주이소"
+close: "닫기"
invites: "초대하기"
-members: "구성원"
-transfer: "넘구기"
+members: "멤버"
+transfer: "양도"
title: "제목"
-text: "걸"
+text: "글"
enable: "키기"
-next: "다엄"
+next: "다음"
retype: "다시 서기"
noteOf: "{user}님으 노트"
quoteAttached: "따옴"
@@ -468,7 +468,6 @@ tooShort: "억수로 짜립니다"
tooLong: "억수로 집니다"
passwordMatched: "맞십니다"
passwordNotMatched: "안 맞십니다"
-signinWith: "{n}서 로그인"
signinFailed: "로그인 몬 했십니다. 고 이름이랑 비밀번호 제대로 썼는가 확인해 주이소."
or: "아니면"
language: "언어"
@@ -476,6 +475,7 @@ uiLanguage: "UI 표시 언어"
aboutX: "{x}에 대해서"
emojiStyle: "이모지 모양"
native: "기본"
+disableDrawer: "드로어 메뉴 쓰지 않기"
showNoteActionsOnlyHover: "마우스 올맀을 때만 노트 액션 버턴 보이기"
noHistory: "기록이 없십니다"
signinHistory: "로그인 기록"
@@ -512,13 +512,13 @@ useObjectStorage: "오브젝트 스토리지 키기"
objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "오브젝트 (미디어) 참조 링크 만들 때 쓰는 URL임다. CDN 내지 프락시를 쓴다 카멘은 그 URL을 갖다 늫고, 아이면 써먹을 서비스네 가이드를 봐봐가 공개적으로 접근할 수 있는 주소를 여 넣어 주이소. 그니께, 내가 AWS S3을 쓴다 카면은 'https://.s3.amazonaws.com', GCS를 쓴다 카면 'https://storage.googleapis.com/' 처럼 쓰믄 되입니더."
objectStorageBucket: "Bucket"
-objectStorageBucketDesc: "설 서비스으 버킷 이럼얼 서 주이소."
+objectStorageBucketDesc: "써먹을 서비스의 바께쓰 이름을 여 써 주이소."
objectStoragePrefix: "Prefix"
objectStoragePrefixDesc: "요 Prefix 디렉토리 안에다가 파일이 들어감다."
objectStorageEndpoint: "Endpoint"
-objectStorageEndpointDesc: "AWS S3넌 비아 두고 다런 것언 거 서비스으 엔드포인트럴 서 주이소. ‘’나 ‘:’맨치로 섭니다."
+objectStorageEndpointDesc: "AWS S3을 쓸라멘 요는 비워두고, 아이멘은 그 서비스 가이드에 맞게 endpoint를 넣어 주이소. '' 내지 ':'처럼 넣십니다."
objectStorageRegion: "Region"
-objectStorageRegionDesc: "‘xx-east-1’맨치로 리전 이럼얼 서 주이소. 설 서비스에 리전 개넴이 어ᇝ어먼 ‘us-east-1’라고 해 두이소. 에이더블유에스 설정 파일이나 환겡 벤수가 이ᇇ어면 비아 두이소."
+objectStorageRegionDesc: "'xx-east-1' 같은 region 이름을 옇어 주이소. 만약에 내 서비스엔 region 같은 개념이 읎다, 카면은 대신에 'us-east-1'라고 해 두이소. AWS 설정 파일이나 환경 변수를 끌어다 쓰겠다믄 요는 비워 두이소."
objectStorageUseSSL: "SSL 쓰기"
objectStorageUseSSLDesc: "API 호출할 때 HTTPS 안 쓸거면은 꺼 두이소"
objectStorageUseProxy: "연결에 프락시 사용"
@@ -534,7 +534,7 @@ newNoteRecived: "새 노트 있어예"
sounds: "소리"
sound: "소리"
listen: "듣기"
-none: "어ᇝ엄"
+none: "없음"
showInPage: "바닥서 보기"
popout: "새 창 열기"
volume: "음량"
@@ -542,13 +542,13 @@ masterVolume: "대빵 음량"
notUseSound: "음소거하기"
useSoundOnlyWhenActive: "Misskey가 활성화되어 있을 때만 소리 내기"
details: "자세히"
-chooseEmoji: "이모지 개리기"
+chooseEmoji: "이모지 선택"
unableToProcess: "작업 다 몬 했십니다"
recentUsed: "최근 쓴 놈"
install: "설치"
uninstall: "삭제"
installedApps: "설치된 애플리케이션"
-nothing: "어ᇝ어예"
+nothing: "뭣도 없어예"
installedDate: "설치한 날"
lastUsedDate: "마지막 사용"
state: "상태"
@@ -579,12 +579,8 @@ enableInfiniteScroll: "알아서 더 보기"
useCw: "내용 수ᇚ후기"
description: "설멩"
describeFile: "캡션 옇기"
-enterFileDescription: "캡션 서기"
author: "맨던 사람"
manage: "간리"
-large: "커게"
-medium: "엔갆게"
-small: "쪼맪게"
emailServer: "전자우펜 서버"
email: "전자우펜"
emailAddress: "전자우펜 주소"
@@ -601,7 +597,7 @@ reportAbuseOf: "{name}님얼 신고하기"
reporter: "신고한 사람"
reporteeOrigin: "신고덴 사람"
reporterOrigin: "신고한 곳"
-waitingFor: "{x}(얼)럴 지달리고 잇십니다"
+forwardReport: "웬겍 서버에 신고 보내기"
random: "무작이"
system: "시스템"
clip: "클립 맨걸기"
@@ -614,15 +610,10 @@ followersCount: "팔로워 수"
noteFavoritesCount: "질겨찾기한 노트 수"
clips: "클립 맨걸기"
clearCache: "캐시 비우기"
-nUsers: "{n} 사용자"
-typingUsers: "{users} 님이 서고 잇어예"
unlikeConfirm: "좋네예럴 무룹니꺼?"
info: "정보"
-selectAccount: "계정 개리기"
user: "사용자"
administration: "간리"
-middle: "엔갆게"
-translatedFrom: "{x}서 번옉"
on: "킴"
off: "껌"
hide: "수ᇚ후기"
@@ -634,9 +625,6 @@ oneDay: "하리"
oneWeek: "한 주"
oneMonth: "한 달"
file: "파일"
-typeToConfirm: "게속할라먼 {x}럴 누질라 주이소"
-pleaseSelect: "개리 주이소"
-remoteOnly: "웬겍만"
tools: "도구"
like: "좋네예!"
unlike: "좋네예 무루기"
@@ -644,22 +632,14 @@ numberOfLikes: "좋네예 수"
show: "보기"
roles: "옉할"
role: "옉할"
-noRole: "옉할이 어ᇝ십니다"
+noRole: "옉할이 없십니다"
thisPostMayBeAnnoyingCancel: "아이예"
likeOnly: "좋네예마"
-hiddenTags: "수ᇚ훈 해시태그"
myClips: "내 클립"
-preservedUsernames: "예약 사용자 이럼"
-specifyUser: "사용자 지정"
icon: "아바타"
replies: "답하기"
renotes: "리노트"
attach: "옇기"
-surrender: "아이예"
-_delivery:
- stop: "고만 보내예"
- _type:
- none: "보내고 잇어예"
_initialAccountSetting:
startTutorial: "길라잡이 하기"
_initialTutorial:
@@ -716,16 +696,6 @@ _achievements:
description: "0분 0초에 노트를 섰어예"
_tutorialCompleted:
description: "길라잡이럴 껕냇십니다"
-_role:
- displayOrder: "보기 순서"
- _priority:
- middle: "엔갆게"
- _options:
- canHideAds: "강고 수ᇚ후기"
- _condition:
- isRemote: "웬겍 사용자"
- isCat: "갱이 사용자"
- isBot: "자동 사용자"
_gallery:
my: "내 걸"
liked: "좋네예한 걸"
@@ -749,7 +719,6 @@ _theme:
_sfx:
note: "새 노트"
notification: "알림"
- reaction: "리액션 개리기"
_2fa:
step3Title: "학인 기호럴 서기"
renewTOTPCancel: "뎃어예"
@@ -774,9 +743,6 @@ _cw:
_visibility:
home: "덜머리"
followers: "팔로워"
-_postForm:
- _placeholders:
- e: "옇다 서 주이소"
_profile:
name: "이럼"
username: "사용자 이럼"
@@ -811,7 +777,6 @@ _notification:
mention: "멘션"
quote: "따오기"
reaction: "반엉"
- login: "로그인"
_actions:
reply: "답하기"
_deck:
@@ -823,10 +788,6 @@ _deck:
mentions: "받언 멘션"
_webhookSettings:
name: "이럼"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "전자우펜"
_moderationLogTypes:
suspend: "얼우기"
deleteNote: "노트 뭉캐기"
@@ -834,8 +795,5 @@ _moderationLogTypes:
resetPassword: "비밀번호 재설정"
resolveAbuseReport: "신고 해겔하기"
_reversi:
- reversi: "리버시"
- chooseBoard: "보드 개리기"
- black: "꺼멍"
- white: "허영"
- total: "합게"
+ total: "합계"
+
diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml
index 414202adab..c4646b6a86 100644
--- a/locales/ko-KR.yml
+++ b/locales/ko-KR.yml
@@ -8,9 +8,6 @@ search: "검색"
notifications: "알림"
username: "유저명"
password: "비밀번호"
-initialPasswordForSetup: "초기 설정용 비밀번호"
-initialPasswordIsIncorrect: "초기 설정용 비밀번호가 올바르지 않습니다."
-initialPasswordForSetupDescription: "Misskey를 직접 설치하는 경우, 설정 파일에 입력해둔 비밀번호를 사용하세요.\nMisskey 설치를 도와주는 호스팅 서비스 등을 사용하는 경우, 서비스 제공자로부터 받은 비밀번호를 사용하세요.\n비밀번호를 따로 설정하지 않은 경우, 아무것도 입력하지 않아도 됩니다."
forgotPassword: "비밀번호 재설정"
fetchingAsApObject: "연합에서 찾아보는 중"
ok: "확인"
@@ -41,9 +38,9 @@ addUser: "유저 추가"
favorite: "즐겨찾기"
favorites: "즐겨찾기"
unfavorite: "즐겨찾기에서 제거"
-favorited: "즐겨찾기에 등록했습니다."
-alreadyFavorited: "이미 즐겨찾기에 등록했습니다."
-cantFavorite: "즐겨찾기에 등록하지 못했습니다."
+favorited: "즐겨찾기에 등록했습니다"
+alreadyFavorited: "이미 즐겨찾기에 등록되어 있습니다"
+cantFavorite: "즐겨찾기에 등록하지 못했습니다"
pin: "프로필에 고정"
unpin: "프로필에서 고정 해제"
copyContent: "내용 복사"
@@ -56,14 +53,13 @@ addToList: "리스트에 추가"
addToAntenna: "안테나에 추가"
sendMessage: "메시지 보내기"
copyRSS: "RSS 복사"
-copyUsername: "유저명 복사"
-copyUserId: "유저 ID 복사"
+copyUsername: "사용자 이름 복사"
+copyUserId: "사용자 ID 복사"
copyNoteId: "노트 ID 복사"
copyFileId: "파일 ID 복사"
copyFolderId: "폴더 ID 복사"
copyProfileUrl: "프로필 URL 복사"
searchUser: "사용자 검색"
-searchThisUsersNotes: "사용자의 노트 검색"
reply: "답글"
loadMore: "더 보기"
showMore: "더 보기"
@@ -97,7 +93,7 @@ somethingHappened: "오류가 발생했습니다"
retry: "다시 시도"
pageLoadError: "페이지를 불러오지 못했습니다."
pageLoadErrorDescription: "네트워크 연결 또는 브라우저 캐시로 인해 발생했을 가능성이 높습니다. 캐시를 삭제하거나, 잠시 후 다시 시도해 주세요."
-serverIsDead: "서버가 응답하지 않습니다. 잠시 후 다시 시도해 주세요."
+serverIsDead: "서버로부터 응답이 없습니다. 잠시 후 다시 시도해주세요."
youShouldUpgradeClient: "이 페이지를 표시하려면 새로고침하여 새로운 버전의 클라이언트를 이용해 주십시오."
enterListName: "리스트 이름을 입력"
privacy: "프라이버시"
@@ -112,14 +108,11 @@ enterEmoji: "이모지 입력"
renote: "리노트"
unrenote: "리노트 취소"
renoted: "리노트했습니다"
-renotedToX: "{name}명이 리노트했습니다."
cantRenote: "이 게시물은 리노트 할 수 없습니다."
-cantReRenote: "리노트를 리노트 할 수 없습니다."
+cantReRenote: "리노트를 리노트할 수 없습니다."
quote: "인용"
inChannelRenote: "채널 내 리노트"
inChannelQuote: "채널 내 인용"
-renoteToChannel: "채널에 리노트"
-renoteToOtherChannel: "다른 채널에 리노트"
pinnedNote: "고정된 노트"
pinned: "고정하기"
you: "나"
@@ -129,8 +122,8 @@ add: "추가"
reaction: "리액션"
reactions: "리액션"
emojiPicker: "이모지 선택기"
-pinnedEmojisForReactionSettingDescription: "리액션을 할 때 이모지 선택기 상단에 표시할 이모지를 설정할 수 있습니다."
-pinnedEmojisSettingDescription: "이모지를 입력할 때 이모지 선택기 상단에 표시할 이모지를 설정할 수 있습니다."
+pinnedEmojisForReactionSettingDescription: "리액션을 할 때 프로필에 고정하여 표시할 이모지를 설정할 수 있습니다"
+pinnedEmojisSettingDescription: "이모지를 입력할 때 프로필에 고정하여 표시할 이모지를 설정할 수 있습니다"
emojiPickerDisplay: "선택기 표시"
overwriteFromPinnedEmojisForReaction: "리액션 설정을 덮어쓰기"
overwriteFromPinnedEmojis: "일반 설정을 덮어쓰기"
@@ -143,7 +136,7 @@ unmarkAsSensitive: "열람주의 해제"
enterFileName: "파일명을 입력"
mute: "뮤트"
unmute: "뮤트 해제"
-renoteMute: "리노트 뮤트"
+renoteMute: "리노트 뮤트하기"
renoteUnmute: "리노트 뮤트 해제"
block: "차단"
unblock: "차단 해제"
@@ -158,7 +151,6 @@ editList: "리스트 편집"
selectChannel: "채널 선택"
selectAntenna: "안테나 선택"
editAntenna: "안테나 편집"
-createAntenna: "안테나 만들기"
selectWidget: "위젯 선택"
editWidgets: "위젯 편집"
editWidgetsExit: "편집 종료"
@@ -177,21 +169,17 @@ cacheRemoteSensitiveFilesDescription: "이 설정을 비활성화하면 리모
flagAsBot: "나는 봇입니다"
flagAsBotDescription: "이 계정을 자동화된 수단으로 운용할 경우에 활성화해 주세요. 이 플래그를 활성화하면, 다른 봇이 이를 참고하여 봇 끼리의 무한 연쇄 반응을 회피하거나, 이 계정의 시스템 상에서의 취급이 Bot 운영에 최적화되는 등의 변화가 생깁니다."
flagAsCat: "미야아아아오오오오오오오오오옹!!!!!!!"
-flagAsCatDescription: "야옹?(이 계정이 고양이라면 눌러 주세요.)"
+flagAsCatDescription: "야옹?"
flagShowTimelineReplies: "타임라인에 노트의 답글을 표시하기"
flagShowTimelineRepliesDescription: "이 설정을 활성화하면 타임라인에 다른 유저 간의 답글을 표시합니다."
autoAcceptFollowed: "팔로우 중인 유저로부터의 팔로우 요청을 자동 수락"
addAccount: "계정 추가"
-reloadAccountsList: "계정 목록 새로고침"
+reloadAccountsList: "계정 리스트 정보 갱신"
loginFailed: "로그인에 실패했습니다"
showOnRemote: "리모트에서 보기"
-continueOnRemote: "리모트에서 계속"
-chooseServerOnMisskeyHub: "Misskey Hub에서 서버 찾아보기"
-specifyServerHost: "서버 도메인 직접 지정"
-inputHostName: "도메인을 입력하세요"
general: "일반"
wallpaper: "배경"
-setWallpaper: "배경 설정"
+setWallpaper: "배경화면 설정"
removeWallpaper: "배경 제거"
searchWith: "검색: {q}"
youHaveNoLists: "리스트가 없습니다"
@@ -199,7 +187,6 @@ followConfirm: "{name}님을 팔로우 하시겠습니까?"
proxyAccount: "프록시 계정"
proxyAccountDescription: "프록시 계정은 특정 조건 하에서 유저의 리모트 팔로우를 대행하는 계정입니다. 예를 들면, 유저가 리모트 유저를 리스트에 넣었을 때, 리스트에 들어간 유저를 아무도 팔로우한 적이 없다면 액티비티가 서버로 배달되지 않기 때문에, 대신 프록시 계정이 해당 유저를 팔로우하도록 합니다."
host: "호스트"
-selectSelf: "본인을 선택"
selectUser: "유저 선택"
recipient: "수신인"
annotation: "내용에 대한 주석"
@@ -215,7 +202,6 @@ perDay: "1일마다"
stopActivityDelivery: "액티비티 보내지 않기"
blockThisInstance: "이 서버를 차단"
silenceThisInstance: "서버를 사일런스"
-mediaSilenceThisInstance: "서버의 미디어를 사일런스"
operations: "작업"
software: "소프트웨어"
version: "버전"
@@ -237,10 +223,6 @@ blockedInstances: "차단된 서버"
blockedInstancesDescription: "차단하려는 서버의 호스트 이름을 줄바꿈으로 구분하여 설정합니다. 차단된 인스턴스는 이 인스턴스와 통신할 수 없게 됩니다."
silencedInstances: "사일런스한 서버"
silencedInstancesDescription: "사일런스하려는 서버의 호스트명을 한 줄에 하나씩 입력합니다. 사일런스된 서버에 소속된 유저는 모두 '사일런스'된 상태로 취급되며, 이 서버로부터의 팔로우가 프로필 설정과 무관하게 승인제로 변경되고, 팔로워가 아닌 로컬 유저에게는 멘션할 수 없게 됩니다. 정지된 서버에는 적용되지 않습니다."
-mediaSilencedInstances: "미디어를 사일런스한 서버"
-mediaSilencedInstancesDescription: "미디어를 사일런스 하려는 서버의 호스트를 한 줄에 하나씩 입력합니다. 미디어가 사일런스된 서버의 유저가 업로드한 파일은 모두 민감한 미디어로 처리되며, 커스텀 이모지를 사용할 수 없게 됩니다. 또한, 차단한 인스턴스에는 적용되지 않습니다."
-federationAllowedHosts: "연합을 허가하는 서버"
-federationAllowedHostsDescription: "연합을 허가하는 서버의 호스트를 엔터로 구분해서 설정합니다."
muteAndBlock: "뮤트 및 차단"
mutedUsers: "뮤트한 유저"
blockedUsers: "차단한 유저"
@@ -265,7 +247,7 @@ publishing: "배포 중"
notResponding: "응답 없음"
instanceFollowing: "서버의 팔로잉"
instanceFollowers: "서버의 팔로워"
-instanceUsers: "서버의 사용자"
+instanceUsers: "서버의 유저"
changePassword: "비밀번호 변경"
security: "보안"
retypedNotMatch: "입력이 일치하지 않습니다."
@@ -281,12 +263,12 @@ lookup: "찾아보기"
announcements: "공지사항"
imageUrl: "이미지 URL"
remove: "삭제"
-removed: "삭제했습니다"
+removed: "삭제하였습니다"
removeAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?"
deleteAreYouSure: "\"{x}\" 을(를) 삭제하시겠습니까?"
resetAreYouSure: "초기화 하시겠습니까?"
areYouSure: "계속 진행하시겠습니까?"
-saved: "저장했습니다"
+saved: "저장하였습니다"
messaging: "대화"
upload: "업로드"
keepOriginalUploading: "원본 이미지를 유지"
@@ -331,7 +313,6 @@ selectFile: "파일 선택"
selectFiles: "파일 선택"
selectFolder: "폴더 선택"
selectFolders: "폴더 선택"
-fileNotSelected: "파일을 선택하지 않았습니다"
renameFile: "파일 이름 변경"
folderName: "폴더 이름"
createFolder: "폴더 만들기"
@@ -339,7 +320,6 @@ renameFolder: "폴더 이름 바꾸기"
deleteFolder: "폴더 삭제"
folder: "폴더"
addFile: "파일 추가"
-showFile: "파일 표시하기"
emptyDrive: "드라이브가 비어 있습니다"
emptyFolder: "폴더가 비어 있습니다"
unableToDelete: "삭제할 수 없습니다"
@@ -385,12 +365,12 @@ registration: "등록"
enableRegistration: "신규 회원가입을 활성화"
invite: "초대"
driveCapacityPerLocalAccount: "로컬 유저 한 명당 드라이브 용량"
-driveCapacityPerRemoteAccount: "원격 사용자별 드라이브 용량"
+driveCapacityPerRemoteAccount: "리모트 유저 한 명당 드라이브 용량"
inMb: "메가바이트 단위"
bannerUrl: "배너 이미지 URL"
backgroundImageUrl: "배경 이미지 URL"
basicInfo: "기본 정보"
-pinnedUsers: "고정한 사용자"
+pinnedUsers: "고정된 유저"
pinnedUsersDescription: "\"발견하기\" 페이지 등에 고정하고 싶은 유저를 한 줄에 한 명씩 적습니다."
pinnedPages: "고정한 페이지"
pinnedPagesDescription: "서버의 대문에 고정하고 싶은 페이지의 경로를 한 줄에 하나씩 적습니다."
@@ -420,7 +400,6 @@ name: "이름"
antennaSource: "받을 소스"
antennaKeywords: "받을 검색어"
antennaExcludeKeywords: "제외할 검색어"
-antennaExcludeBots: "봇 계정 제외"
antennaKeywordsDescription: "공백으로 구분하는 경우 AND, 줄바꿈으로 구분하는 경우 OR로 지정됩니다"
notifyAntenna: "새로운 노트를 알림"
withFileAntenna: "파일이 첨부된 노트만"
@@ -435,11 +414,11 @@ silence: "사일런스"
silenceConfirm: "이 계정을 사일런스로 설정하시겠습니까?"
unsilence: "사일런스 해제"
unsilenceConfirm: "이 계정의 사일런스를 해제하시겠습니까?"
-popularUsers: "인기 사용자"
-recentlyUpdatedUsers: "최근에 활동한 사용자"
-recentlyRegisteredUsers: "최근에 가입한 사용자"
-recentlyDiscoveredUsers: "최근에 발견한 사용자"
-exploreUsersCount: "{count}명의 사용자가 있습니다"
+popularUsers: "인기 유저"
+recentlyUpdatedUsers: "최근 활동한 유저"
+recentlyRegisteredUsers: "최근 가입한 유저"
+recentlyDiscoveredUsers: "최근 발견한 유저"
+exploreUsersCount: "{count}명의 유저가 있습니다"
exploreFediverse: "연합우주를 탐색"
popularTags: "인기 태그"
userList: "리스트"
@@ -454,17 +433,16 @@ totpDescription: "인증 앱을 사용하여 일회성 비밀번호 입력"
moderator: "모더레이터"
moderation: "조정"
moderationNote: "조정 기록"
-moderationNoteDescription: "모더레이터 역할을 가진 유저만 보이는 메모를 적을 수 있습니다."
addModerationNote: "조정 기록 추가하기"
moderationLogs: "모더레이션 로그"
nUsersMentioned: "{n}명이 언급함"
-securityKeyAndPasskey: "보안 키 또는 패스키"
+securityKeyAndPasskey: "보안 키 또는 패스 키"
securityKey: "보안 키"
lastUsed: "마지막 사용"
lastUsedAt: "마지막 사용: {t}"
unregister: "등록 해제"
passwordLessLogin: "비밀번호 없이 로그인"
-passwordLessLoginDescription: "비밀번호 없이 보안 키 또는 패스키만 사용해서 로그인합니다."
+passwordLessLoginDescription: "비밀번호를 사용하지 않고 보안 키 또는 패스 키 등으로만 로그인합니다."
resetPassword: "비밀번호 재설정"
newPasswordIs: "새로운 비밀번호는 \"{password}\" 입니다"
reduceUiAnimation: "UI의 애니메이션을 줄이기"
@@ -489,12 +467,10 @@ retype: "다시 입력"
noteOf: "{user}의 노트"
quoteAttached: "인용함"
quoteQuestion: "인용해서 작성하시겠습니까?"
-attachAsFileQuestion: "붙여넣으려는 글이 너무 깁니다. 텍스트 파일로 첨부하시겠습니까?"
noMessagesYet: "아직 대화가 없습니다"
newMessageExists: "새 메시지가 있습니다"
onlyOneFileCanBeAttached: "메시지에 첨부할 수 있는 파일은 하나까지입니다"
-signinRequired: "진행하기 전에 로그인을 해 주세요"
-signinOrContinueOnRemote: "계속하려면 사용하는 서버로 이동하거나 이 서버에 로그인해야 합니다."
+signinRequired: "로그인 해주세요"
invitations: "초대"
invitationCode: "초대 코드"
checking: "확인하는 중입니다"
@@ -509,19 +485,15 @@ strongPassword: "강한 비밀번호"
passwordMatched: "일치합니다"
passwordNotMatched: "일치하지 않습니다"
signinWith: "{x}로 로그인"
-signinFailed: "로그인할 수 없습니다. 사용자 이름과 비밀번호를 확인해 주십시오."
+signinFailed: "로그인할 수 없습니다. 사용자명과 비밀번호를 확인하여 주십시오."
or: "혹은"
language: "언어"
uiLanguage: "UI 표시 언어"
aboutX: "{x}에 대하여"
emojiStyle: "이모지 스타일"
native: "기본"
-menuStyle: "메뉴 스타일"
-style: "스타일"
-drawer: "서랍"
-popup: "팝업"
-showNoteActionsOnlyHover: "마우스가 올라간 때에만 노트 동작 버튼을 표시하기"
-showReactionsCount: "노트의 반응 수를 표시하기"
+disableDrawer: "드로어 메뉴를 사용하지 않기"
+showNoteActionsOnlyHover: "노트 액션 버튼을 마우스를 올렸을 때에만 표시"
noHistory: "기록이 없습니다"
signinHistory: "로그인 기록"
enableAdvancedMfm: "고급 MFM을 활성화"
@@ -557,13 +529,13 @@ useObjectStorage: "오브젝트 스토리지를 사용"
objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "오브젝트 (미디어) 참조 URL 을 만들 때 사용되는 URL입니다. CDN 또는 프록시를 사용하는 경우 그 URL을 지정하고, 그 외의 경우 사용할 서비스의 가이드에 따라 공개적으로 액세스 할 수 있는 주소를 지정해 주세요. 예를 들어, AWS S3의 경우 'https://.s3.amazonaws.com', GCS등의 경우 'https://storage.googleapis.com/' 와 같이 지정합니다."
objectStorageBucket: "Bucket"
-objectStorageBucketDesc: "사용하는 서비스의 bucket 이름을 지정해 주세요."
+objectStorageBucketDesc: "사용 서비스의 bucket명을 지정해주세요."
objectStoragePrefix: "Prefix"
objectStoragePrefixDesc: "이 Prefix 의 디렉토리 아래에 파일이 저장됩니다."
objectStorageEndpoint: "Endpoint"
-objectStorageEndpointDesc: "AWS S3는 비워 두고 다른 서비스는 각 서비스의 endpoint를 설정해 주세요. ‘’ 혹은 ‘:’처럼 지정합니다."
+objectStorageEndpointDesc: "AWS S3의 경우 공란, 다른 서비스의 경우 각 서비스의 가이드에 맞게 endpoint를 설정해주세요. '' 혹은 ':' 와 같이 지정합니다."
objectStorageRegion: "Region"
-objectStorageRegionDesc: "‘xx-east-1’처럼 region을 지정해 주세요. 사용하는 서비스에 region 개념이 없으면 ‘us-east-1’처럼 설정해 주세요. AWS 설정 파일이나 환경 변수가 있으면 비워 주세요."
+objectStorageRegionDesc: "'xx-east-1'와 같이 region을 지정해 주세요. 사용하는 서비스에 region 개념이 없는 경우 'us-east-1'으로 설정해 주세요. AWS 설정 파일 또는 환경 변수를 참조할 경우에는 비워주세요."
objectStorageUseSSL: "SSL 사용"
objectStorageUseSSLDesc: "API 호출시 HTTPS 를 사용하지 않는 경우 OFF 로 설정해 주세요"
objectStorageUseProxy: "연결에 프록시를 사용"
@@ -585,7 +557,7 @@ popout: "새 창으로 열기"
volume: "음량"
masterVolume: "마스터 볼륨"
notUseSound: "음소거 하기"
-useSoundOnlyWhenActive: "Misskey를 활성화한 때에만 소리를 출력하기"
+useSoundOnlyWhenActive: "Misskey가 활성화 되어져 있을 때만 소리 출력하기"
details: "자세히"
chooseEmoji: "이모지 선택"
unableToProcess: "작업을 완료할 수 없습니다"
@@ -602,12 +574,10 @@ ascendingOrder: "오름차순"
descendingOrder: "내림차순"
scratchpad: "스크래치 패드"
scratchpadDescription: "스크래치 패드는 AiScript 의 테스트 환경을 제공합니다. Misskey 와 상호 작용하는 코드를 작성, 실행 및 결과를 확인할 수 있습니다."
-uiInspector: "UI 인스펙터"
-uiInspectorDescription: "메모리에 있는 UI 컴포넌트의 인스턴트 목록을 볼 수 있습니다. UI 컴포넌트는 Ui:C: 계열 함수로 만들어집니다."
output: "출력"
script: "스크립트"
disablePagesScript: "Pages 에서 AiScript 를 사용하지 않음"
-updateRemoteUser: "원격 사용자 정보 갱신"
+updateRemoteUser: "리모트 유저 정보 갱신"
unsetUserAvatar: "아바타 제거"
unsetUserAvatarConfirm: "아바타를 제거할까요?"
unsetUserBanner: "배너 제거"
@@ -616,7 +586,7 @@ deleteAllFiles: "모든 파일 삭제"
deleteAllFilesConfirm: "모든 파일을 삭제하시겠습니까?"
removeAllFollowing: "모든 팔로잉 해제"
removeAllFollowingDescription: "{host} 서버의 모든 팔로잉을 해제합니다. 해당 서버가 더 이상 존재하지 않는 경우 등에 실행해 주세요."
-userSuspended: "이 사용자는 정지되었습니다."
+userSuspended: "이 계정은 정지된 상태입니다."
userSilenced: "이 계정은 사일런스된 상태입니다."
yourAccountSuspendedTitle: "계정이 정지되었습니다"
yourAccountSuspendedDescription: "이 계정은 서버의 이용 약관을 위반하거나, 기타 다른 이유로 인해 정지되었습니다. 자세한 사항은 관리자에게 문의해 주십시오. 계정을 새로 생성하지 마십시오."
@@ -690,7 +660,7 @@ regexpErrorDescription: "{tab}단어 뮤트 {line}행의 정규 표현식에 오
instanceMute: "서버 뮤트"
userSaysSomething: "{name}님이 무언가를 말했습니다"
makeActive: "활성화"
-display: "보기"
+display: "표시"
copy: "복사"
metrics: "통계"
overview: "요약"
@@ -714,13 +684,16 @@ sample: "예시"
abuseReports: "신고"
reportAbuse: "신고"
reportAbuseRenote: "리노트 신고하기"
-reportAbuseOf: "{name} 신고하기"
+reportAbuseOf: "{name}을 신고하기"
fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요."
abuseReported: "신고를 보냈습니다. 신고해 주셔서 감사합니다."
reporter: "신고자"
reporteeOrigin: "피신고자"
reporterOrigin: "신고자"
+forwardReport: "리모트 서버에도 신고 내용 보내기"
+forwardReportIsAnonymous: "리모트 서버에서는 나의 정보를 볼 수 없으며, 익명의 시스템 계정으로 표시됩니다."
send: "전송"
+abuseMarkAsResolved: "해결됨으로 표시"
openInNewTab: "새 탭에서 열기"
openInSideView: "사이드뷰로 열기"
defaultNavigationBehaviour: "기본 탐색 동작"
@@ -736,7 +709,7 @@ createNew: "새로 만들기"
optional: "옵션"
createNewClip: "새 클립 만들기"
unclip: "클립 해제"
-confirmToUnclipAlreadyClippedNote: "이 노트는 ‘{name}’ 클립을 이미 포함합니다. 클립에서 제외하시겠습니까?"
+confirmToUnclipAlreadyClippedNote: "이 노트는 이미 \"{name}\" 클립에 포함되어 있습니다. 클립을 해제하시겠습니까?"
public: "공개"
private: "비공개"
i18nInfo: "Misskey는 자원봉사자들에 의해 다양한 언어로 번역되고 있습니다. {link}에서 번역에 참가할 수 있습니다."
@@ -749,13 +722,13 @@ repliedCount: "받은 답글 수"
renotedCount: "받은 리노트 수"
followingCount: "팔로우 수"
followersCount: "팔로워 수"
-sentReactionsCount: "반응 수"
-receivedReactionsCount: "받은 반응 수"
-pollVotesCount: "투표 수"
-pollVotedCount: "받은 투표 수"
+sentReactionsCount: "보낸 리액션 수"
+receivedReactionsCount: "받은 리액션 수"
+pollVotesCount: "투표한 횟수"
+pollVotedCount: "투표받은 횟수"
yes: "예"
no: "아니오"
-driveFilesCount: "드라이브에 있는 파일 수"
+driveFilesCount: "드라이브 파일 개수"
driveUsage: "드라이브 사용량"
noCrawle: "검색엔진의 인덱싱 거부"
noCrawleDescription: "검색엔진에 사용자 페이지, 노트, 페이지 등의 콘텐츠를 인덱싱되지 않게 합니다."
@@ -777,7 +750,7 @@ experimentalFeatures: "실험실"
experimental: "실험실"
thisIsExperimentalFeature: "이 기능은 실험적인 기능입니다. 사양이 변경되거나 정상적으로 동작하지 않을 가능성이 있습니다."
developer: "개발자"
-makeExplorable: "계정을 쉽게 발견하도록 하기"
+makeExplorable: "\"발견하기\"에 내 계정 보이기"
makeExplorableDescription: "비활성화하면 \"발견하기\"에 나의 계정을 표시하지 않습니다."
showGapBetweenNotesInTimeline: "타임라인의 노트 사이를 띄워서 표시"
duplicate: "복제"
@@ -790,7 +763,7 @@ needReloadToApply: "변경 사항은 새로고침하면 적용됩니다."
showTitlebar: "타이틀 바를 표시하기"
clearCache: "캐시 비우기"
onlineUsersCount: "{n}명이 접속 중"
-nUsers: "{n} 사용자"
+nUsers: "{n} 유저"
nNotes: "{n} 노트"
sendErrorReports: "오류 보고서 보내기"
sendErrorReportsDescription: "이 설정을 활성화하면, 문제가 발생했을 때 오류에 대한 상세 정보를 Misskey에 보내어 더 나은 소프트웨어를 만드는 데에 도움을 줄 수 있습니다."
@@ -823,7 +796,7 @@ emailNotification: "메일 알림"
publish: "게시"
inChannelSearch: "채널에서 검색"
useReactionPickerForContextMenu: "우클릭하여 리액션 선택기 열기"
-typingUsers: "{users}님이 입력 중"
+typingUsers: "{users} 님이 입력하고 있어요.."
jumpToSpecifiedDate: "특정 날짜로 이동"
showingPastTimeline: "과거의 타임라인을 표시하고 있어요"
clear: "지우기"
@@ -836,7 +809,7 @@ addDescription: "설명 추가"
userPagePinTip: "각 노트의 메뉴에서 「프로필에 고정」을 선택하는 것으로, 여기에 노트를 표시해 둘 수 있어요."
notSpecifiedMentionWarning: "수신자가 선택되지 않은 멘션이 있어요"
info: "정보"
-userInfo: "사용자 정보"
+userInfo: "유저 정보"
unknown: "알 수 없음"
onlineStatus: "온라인 상태"
hideOnlineStatus: "온라인 상태 숨기기"
@@ -857,7 +830,6 @@ administration: "관리"
accounts: "계정"
switch: "전환"
noMaintainerInformationWarning: "관리자 정보가 설정되어 있지 않습니다."
-noInquiryUrlWarning: "문의처 주소를 설정하지 않았습니다."
noBotProtectionWarning: "Bot 방어가 설정되어 있지 않습니다."
configure: "설정하기"
postToGallery: "갤러리에 업로드"
@@ -922,11 +894,10 @@ followersVisibility: "팔로워의 공개 범위"
continueThread: "글타래 더 보기"
deleteAccountConfirm: "계정이 삭제되고 되돌릴 수 없게 됩니다. 계속하시겠습니까? "
incorrectPassword: "비밀번호가 올바르지 않습니다."
-incorrectTotp: "OTP 번호가 틀렸거나 유효기간이 만료되어 있을 수 있습니다."
voteConfirm: "\"{choice}\"에 투표하시겠습니까?"
hide: "숨기기"
useDrawerReactionPickerForMobile: "모바일에서 드로어 메뉴로 표시"
-welcomeBackWithName: "{name}님, 환영합니다."
+welcomeBackWithName: "환영합니다, {name}님"
clickToFinishEmailVerification: "[{ok}]를 눌러 이메일 인증을 완료하세요."
overridedDeviceKind: "장치 유형"
smartphone: "스마트폰"
@@ -1020,7 +991,6 @@ neverShow: "다시 보지 않기"
remindMeLater: "나중에 알림"
didYouLikeMisskey: "Misskey가 마음에 드시나요?"
pleaseDonate: "Misskey는 {host} 서버의 무료 소프트웨어입니다. 앞으로도 개발을 이어 나가려면 후원이 절실히 필요합니다!"
-correspondingSourceIsAvailable: "소스 코드는 {anchor}에서 받아보실 수 있습니다."
roles: "역할"
role: "역할"
noRole: "역할이 없습니다"
@@ -1048,7 +1018,6 @@ thisPostMayBeAnnoyingHome: "홈에 게시"
thisPostMayBeAnnoyingCancel: "그만두기"
thisPostMayBeAnnoyingIgnore: "이대로 게시"
collapseRenotes: "이미 본 리노트를 간략화하기"
-collapseRenotesDescription: "반응이나 리노트를 한 노트를 접어서 표시합니다."
internalServerError: "내부 서버 오류"
internalServerErrorDescription: "내부 서버에서 예기치 않은 오류가 발생했습니다."
copyErrorInfo: "오류 정보 복사"
@@ -1087,7 +1056,6 @@ retryAllQueuesConfirmTitle: "지금 다시 시도하시겠습니까?"
retryAllQueuesConfirmText: "일시적으로 서버의 부하가 증가할 수 있습니다."
enableChartsForRemoteUser: "리모트 유저의 차트를 생성"
enableChartsForFederatedInstances: "리모트 서버의 차트를 생성"
-enableStatsForFederatedInstances: "리모트 서버 정보 받아오기"
showClipButtonInNoteFooter: "노트 동작에 클립을 추가"
reactionsDisplaySize: "리액션 표시 크기"
limitWidthOfReaction: "리액션의 최대 폭을 제한하고 작게 표시하기"
@@ -1119,15 +1087,13 @@ serverRules: "서버 규칙"
pleaseConfirmBelowBeforeSignup: "이 서버에 가입하기 전에 아래 사항을 확인하여 주십시오."
pleaseAgreeAllToContinue: "계속하시려면 모든 항목에 동의하십시오."
continue: "계속"
-preservedUsernames: "예약한 사용자 이름"
+preservedUsernames: "예약된 사용자명"
preservedUsernamesDescription: "예약할 사용자명을 한 줄에 하나씩 입력합니다. 여기에서 지정한 사용자명으로는 계정을 생성할 수 없게 됩니다. 단, 관리자 권한으로 계정을 생성할 때에는 해당되지 않으며, 이미 존재하는 계정도 영향을 받지 않습니다."
createNoteFromTheFile: "이 파일로 노트를 작성"
archive: "아카이브"
-archived: "아카이브 됨"
-unarchive: "보관 취소"
-channelArchiveConfirmTitle: "{name} 채널을 보존하시겠습니까?"
-channelArchiveConfirmDescription: "보존한 채널은 채널 목록과 검색 결과에 표시되지 않으며 새로운 노트도 작성할 수 없습니다."
-thisChannelArchived: "이 채널은 보존되었습니다."
+channelArchiveConfirmTitle: "{name} 을(를) 아카이브하시겠습니까?"
+channelArchiveConfirmDescription: "아카이브한 채널은 채널 목록과 검색 결과에 표시되지 않으며, 채널에 새로운 노트를 작성할 수 없게 됩니다."
+thisChannelArchived: "이 채널은 아카이브되었습니다."
displayOfNote: "노트 표시"
initialAccountSetting: "초기 설정"
youFollowing: "팔로잉"
@@ -1135,9 +1101,6 @@ preventAiLearning: "기계학습(생성형 AI)으로의 사용을 거부"
preventAiLearningDescription: "외부의 문장 생성 AI나 이미지 생성 AI에 대해 제출한 노트나 이미지 등의 콘텐츠를 학습의 대상으로 사용하지 않도록 요구합니다. 다만, 이 요구사항을 지킬 의무는 없기 때문에 학습을 완전히 방지하는 것은 아닙니다."
options: "옵션"
specifyUser: "사용자 지정"
-lookupConfirm: "조회 할까요?"
-openTagPageConfirm: "해시태그의 페이지를 열까요?"
-specifyHost: "호스트 지정"
failedToPreviewUrl: "미리 볼 수 없음"
update: "업데이트"
rolesThatCanBeUsedThisEmojiAsReaction: "이 이모지를 리액션으로 사용할 수 있는 역할"
@@ -1192,11 +1155,10 @@ unnotifyNotes: "새 노트 알림 끄기"
authentication: "인증"
authenticationRequiredToContinue: "계속하려면 인증하십시오"
dateAndTime: "일시"
-showRenotes: "리노트 보기"
+showRenotes: "리노트 표시"
edited: "수정됨"
notificationRecieveConfig: "알림 설정"
mutualFollow: "맞팔로우"
-followingOrFollower: "팔로 중이거나 팔로워"
fileAttachedOnly: "미디어를 포함한 노트만"
showRepliesToOthersInTimeline: "타임라인에 다른 사람에게 보내는 답글을 포함"
hideRepliesToOthersInTimeline: "타임라인에 다른 사람에게 보내는 답글을 포함하지 않음"
@@ -1206,12 +1168,6 @@ confirmShowRepliesAll: "이 조작은 되돌릴 수 없습니다. 정말로 타
confirmHideRepliesAll: "이 조작은 되돌릴 수 없습니다. 정말로 타임라인에 현재 팔로우 중인 사람 전원의 답글이 나오지 않게 하시겠습니까?"
externalServices: "외부 서비스"
sourceCode: "소스 코드"
-sourceCodeIsNotYetProvided: "소스 코드를 아직 제공하지 않습니다. 이 문제를 해결하려면 관리자에게 문의해 주세요."
-repositoryUrl: "저장소 URL"
-repositoryUrlDescription: "소스 코드를 공개한 저장소가 있는 경우, 그 URL을 적습니다. Misskey를 원본 그대로 (소스 코드를 어떤 식으로도 변경하지 않고) 쓰고 있는 경우 https://github.com/misskey-dev/misskey 라고 적습니다."
-repositoryUrlOrTarballRequired: "저장소를 공개하지 않은 경우 대신 tarball을 제공할 필요가 있습니다. 세부사항은 .config/example.yml을 참조해 주세요."
-feedback: "피드백"
-feedbackUrl: "피드백 URL"
impressum: "운영자 정보"
impressumUrl: "운영자 정보 URL"
impressumDescription: "독일 등의 일부 나라와 지역에서는 꼭 표시해야 합니다(Impressum)."
@@ -1247,79 +1203,15 @@ soundWillBePlayed: "소리가 재생됩니다"
showReplay: "리플레이 보기"
replay: "리플레이"
replaying: "리플레이 중"
-endReplay: "리플레이 종료"
-copyReplayData: "리플레이 데이터를 복사"
ranking: "랭킹"
lastNDays: "최근 {n}일"
backToTitle: "타이틀로 가기"
hemisphere: "거주 지역"
withSensitive: "민감한 파일이 포함된 노트 보기"
-userSaysSomethingSensitive: "{name} 같은 민감한 파일이 포함된 글"
+userSaysSomethingSensitive: "{name}의 민감한 파일이 포함된 게시물"
enableHorizontalSwipe: "스와이프하여 탭 전환"
-loading: "불러오는 중"
-surrender: "그만두기"
-gameRetry: "다시 시도"
-notUsePleaseLeaveBlank: "사용하지 않는 경우 비워두세요."
-useTotp: "일회용 비밀번호 사용"
-useBackupCode: "백업 코드 사용"
-launchApp: "앱 실행"
-useNativeUIForVideoAudioPlayer: "브라우저 UI에서 미디어 재생"
-keepOriginalFilename: "원본 파일 이름을 유지"
-keepOriginalFilenameDescription: "이 설정을 끄면 업로드를 할 때 파일 이름이 자동으로 무작위 문자열로 바뀝니다."
-noDescription: "설명문이 없습니다"
-alwaysConfirmFollow: "팔로우일 때 항상 확인하기"
-inquiry: "문의하기"
-tryAgain: "다시 시도해 주세요."
-confirmWhenRevealingSensitiveMedia: "민감한 미디어를 열 때 두 번 확인"
-sensitiveMediaRevealConfirm: "민감한 미디어입니다. 표시할까요?"
-createdLists: "만든 리스트"
-createdAntennas: "만든 안테나"
-fromX: "{x}부터"
-genEmbedCode: "임베디드 코드 만들기"
-noteOfThisUser: "이 유저의 노트 목록"
-clipNoteLimitExceeded: "더 이상 이 클립에 노트를 추가 할 수 없습니다."
-performance: "퍼포먼스"
-modified: "변경 있음"
-discard: "파기"
-thereAreNChanges: "{n}건 변경이 있습니다."
-signinWithPasskey: "패스키로 로그인"
-unknownWebAuthnKey: "등록되지 않은 패스키입니다."
-passkeyVerificationFailed: "패스키 검증을 실패했습니다."
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "패스키를 검증했으나, 비밀번호 없이 로그인하기가 꺼져 있습니다."
-messageToFollower: "팔로워에 보낼 메시지"
-target: "대상"
-testCaptchaWarning: "CAPTCHA를 테스트하기 위한 기능입니다. 실제 환경에서는 사용하지 마세요. "
-prohibitedWordsForNameOfUser: "금지 단어 (사용자 이름)"
-prohibitedWordsForNameOfUserDescription: "이 목록에 포함되는 키워드가 사용자 이름에 있는 경우, 일반 사용자는 이름을 바꿀 수 없습니다. 모더레이터 권한을 가진 사용자는 제한 대상에서 제외됩니다."
-yourNameContainsProhibitedWords: "바꾸려는 이름에 금지된 키워드가 포함되어 있습니다."
-yourNameContainsProhibitedWordsDescription: "이름에 금지된 키워드가 있습니다. 이름을 사용해야 하는 경우, 서버 관리자에 문의하세요."
-_abuseUserReport:
- forward: "전달"
- forwardDescription: "익명 시스템 계정을 사용하여 리모트 서버에 신고 내용을 전달할 수 있습니다."
- resolve: "해결됨"
- accept: "인용"
- reject: "기각"
- resolveTutorial: "적절한 신고 내용에 대응한 경우, \"인용\"을 선택하여 \"해결됨\"으로 기록합니다.\n적절하지 않은 신고를 받은 경우, \"기각\"을 선택하여 \"기각\"으로 기록합니다."
-_delivery:
- status: "전송 상태"
- stop: "정지됨"
- resume: "전송 다시 시작"
- _type:
- none: "배포 중"
- manuallySuspended: "수동 정지 중"
- goneSuspended: "서버 삭제를 이유로 정지 중"
- autoSuspendedForNotResponding: "서버 응답 없음을 이유로 정지 중"
_bubbleGame:
howToPlay: "설명"
- hold: "홀드"
- _score:
- score: "점수"
- scoreYen: "번 돈"
- highScore: "최고 점수"
- maxChain: "최대 콤보 수"
- yen: "{yen}엔"
- estimatedQty: "{qty}개"
- scoreSweets: "오니기리 {onigiriQtyWithUnit}"
_howToPlay:
section1: "위치를 조정하여 상자에 물건을 떨어뜨립니다."
section2: "같은 종류의 물건이 붙으면 다른 물건으로 바뀌면서 점수를 얻게 됩니다."
@@ -1332,7 +1224,7 @@ _announcement:
end: "공지에서 내리기"
tooManyActiveAnnouncementDescription: "공지사항이 너무 많을 경우, 사용자 경험에 영향을 끼칠 가능성이 있습니다. 오래된 공지사항은 아카이브하시는 것을 권장드립니다."
readConfirmTitle: "읽음으로 표시합니까?"
- readConfirmText: "〈{title}〉의 내용을 읽음으로 표시합니다."
+ readConfirmText: "\"{title}\"을(를) 읽음으로 표시합니다."
shouldNotBeUsedToPresentPermanentInfo: "신규 유저의 이용 경험에 악영향을 끼칠 수 있으므로, 일시적인 알림 수단으로만 사용하고 고정된 정보에는 사용을 지양하는 것을 추천합니다."
dialogAnnouncementUxWarn: "다이얼로그 형태의 알림이 동시에 2개 이상 존재하는 경우, 사용자 경험에 악영향을 끼칠 수 있으므로 신중히 결정하십시오."
silence: "조용히 알림"
@@ -1434,10 +1326,6 @@ _serverSettings:
fanoutTimelineDescription: "활성화하면 각종 타임라인을 가져올 때의 성능을 대폭 향상하며, 데이터베이스의 부하를 줄일 수 있습니다. 단, Redis의 메모리 사용량이 증가합니다. 서버의 메모리 용량이 작거나, 서비스가 불안정해지는 경우 비활성화할 수 있습니다."
fanoutTimelineDbFallback: "데이터베이스를 예비로 사용하기"
fanoutTimelineDbFallbackDescription: "활성화하면 타임라인의 캐시되어 있지 않은 부분에 대해 DB에 질의하여 정보를 가져옵니다. 비활성화하면 이를 실행하지 않음으로써 서버의 부하를 줄일 수 있지만, 타임라인에서 가져올 수 있는 게시물 범위가 한정됩니다."
- reactionsBufferingDescription: "활성화 한 경우, 리액션 작성 퍼포먼스가 대폭 향상되어 DB의 부하를 줄일 수 있으나, Redis의 메모리 사용량이 많아집니다."
- inquiryUrl: "문의처 URL"
- inquiryUrlDescription: "서버 운영자에게 보내는 문의 양식의 URL이나 운영자의 연락처 등이 적힌 웹 페이지의 URL을 설정합니다."
- thisSettingWillAutomaticallyOffWhenModeratorsInactive: "일정 기간동안 모더레이터의 활동이 감지되지 않는 경우, 스팸 방지를 위해 이 설정은 자동으로 꺼집니다."
_accountMigration:
moveFrom: "다른 계정에서 이 계정으로 이사"
moveFromSub: "다른 계정에 대한 별칭을 생성"
@@ -1617,7 +1505,7 @@ _achievements:
_iLoveMisskey:
title: "I Love Misskey"
description: "\"I ❤ #Misskey\"를 포스트했습니다"
- flavor: "Misskey를 이용해 주셔서 감사합니다! ― 개발 팀"
+ flavor: "Misskey를 이용해주셔서 감사합니다! - 개발팀 일동"
_foundTreasure:
title: "보물찾기"
description: "숨겨진 보물을 발견했습니다"
@@ -1655,10 +1543,10 @@ _achievements:
description: "3개 이상의 창을 열었습니다"
_driveFolderCircularReference:
title: "순환 참조"
- description: "드라이브 폴더에 스스로를 넣게 했습니다"
+ description: "드라이브 폴더를 자신을 가리키도록 만드려 시도했습니다"
_reactWithoutRead:
title: "읽고 답하긴 하시는 건가요?"
- description: "100자가 넘는 노트를 작성한 지 3초 안에 반응했어요"
+ description: "100자가 넘는 노트가 작성되고 3초 안에 반응했습니다"
_clickedClickHere:
title: "여기를 누르세요"
description: "여기를 눌렀습니다"
@@ -1745,7 +1633,6 @@ _role:
gtlAvailable: "글로벌 타임라인 보이기"
ltlAvailable: "로컬 타임라인 보이기"
canPublicNote: "공개 노트 허용"
- mentionMax: "노트에 넣을 수 있는 멘션 수"
canInvite: "서버 초대 코드 발행"
inviteLimit: "초대 한도"
inviteLimitCycle: "초대 발급 간격"
@@ -1754,43 +1641,31 @@ _role:
canManageAvatarDecorations: "아바타 꾸미기 관리"
driveCapacity: "드라이브 용량"
alwaysMarkNsfw: "파일을 항상 NSFW로 지정"
- canUpdateBioMedia: "아바타 및 배너 이미지 변경 허용"
pinMax: "고정할 수 있는 노트 수"
- antennaMax: "만들 수 있는 안테나 수"
+ antennaMax: "최대 안테나 생성 허용 수"
wordMuteMax: "단어 뮤트할 수 있는 문자 수"
- webhookMax: "만들 수 있는 Webhook 수"
- clipMax: "만들 수 있는 클립 수"
- noteEachClipsMax: "클립에 넣을 수 있는 노트 수"
- userListMax: "만들 수 있는 사용자 리스트 수"
- userEachUserListsMax: "사용자 리스트에 넣을 수 있는 사용자 수"
+ webhookMax: "생성할 수 있는 웹훅 수"
+ clipMax: "생성할 수 있는 클립 수"
+ noteEachClipsMax: "각 클립에 추가할 수 있는 노트 수"
+ userListMax: "생성할 수 있는 유저 리스트 수"
+ userEachUserListsMax: "유저 리스트당 최대 사용자 수"
rateLimitFactor: "요청 빈도 제한"
descriptionOfRateLimitFactor: "작을수록 제한이 완화되고, 클수록 제한이 강화됩니다."
canHideAds: "광고 숨기기"
canSearchNotes: "노트 검색 이용 가능 여부"
canUseTranslator: "번역 기능의 사용"
avatarDecorationLimit: "아바타 장식의 최대 붙임 개수"
- canImportAntennas: "안테나 가져오기 허용"
- canImportBlocking: "차단 목록 가져오기 허용"
- canImportFollowing: "팔로우 가져오기 허용"
- canImportMuting: "뮤트 목록 가져오기 허용"
- canImportUserLists: "리스트 목록 가져오기 허용"
_condition:
- roleAssignedTo: "수동 역할에 이미 할당됨"
isLocal: "로컬 사용자"
- isRemote: "원격 사용자"
- isCat: "고양이 사용자"
- isBot: "봇 사용자"
- isSuspended: "정지된 사용자"
- isLocked: "잠금 계정 사용자"
- isExplorable: "‘계정을 쉽게 발견하도록 하기’를 활성화한 사용자"
+ isRemote: "리모트 사용자"
createdLessThan: "가입한 지 다음 일수 이내인 유저"
createdMoreThan: "가입한 지 다음 일수 이상인 유저"
followersLessThanOrEq: "팔로워 수가 다음 이하인 유저"
- followersMoreThanOrEq: "팔로워 수가 다음보다 많은 사용자"
+ followersMoreThanOrEq: "팔로워 수가 다음 이상인 유저"
followingLessThanOrEq: "팔로잉 수가 다음 이하인 유저"
- followingMoreThanOrEq: "팔로잉 수가 다음보다 많은 사용자"
+ followingMoreThanOrEq: "팔로잉 수가 다음 이상인 유저"
notesLessThanOrEq: "노트 수가 다음 이하인 유저"
- notesMoreThanOrEq: "노트 수가 다음보다 많은 사용자"
+ notesMoreThanOrEq: "노트 수가 다음 이상인 유저"
and: "다음을 모두 만족"
or: "다음을 하나라도 만족"
not: "다음을 만족하지 않음"
@@ -1852,7 +1727,6 @@ _plugin:
installWarn: "신뢰할 수 없는 플러그인은 설치하지 않는 것이 좋습니다."
manage: "플러그인 관리"
viewSource: "소스 보기"
- viewLog: "로그 보기"
_preferencesBackups:
list: "생성한 백업"
saveNew: "새 백업 만들기"
@@ -1863,12 +1737,12 @@ _preferencesBackups:
cannotSave: "저장하지 못했습니다"
nameAlreadyExists: "\"{name}\" 백업이 이미 존재합니다. 다른 이름을 설정하여 주십시오."
applyConfirm: "\"{name}\" 백업을 현재 기기에 적용하시겠습니까? 현재 설정은 덮어 씌워집니다."
- saveConfirm: "{name} 백업을 덮어쓰시겠습니까?"
- deleteConfirm: "{name} 백업을 삭제하시겠습니까?"
- renameConfirm: "‘{old}’ 백업을 ‘{new}’ 백업으로 바꾸시겠습니까?"
+ saveConfirm: "{name} 을 덮어쓰시겠습니까?"
+ deleteConfirm: "{name} 을(를) 삭제하시겠습니까?"
+ renameConfirm: "\"{old}\" 백업을 \"{new}\"(으)로 바꾸시겠습니까?"
noBackups: "저장된 백업이 없습니다. \"새 백업 만들기\"를 눌러 현재 클라이언트 설정을 서버에 백업할 수 있습니다."
- createdAt: "만든 날짜: {date} {time}"
- updatedAt: "고친 날짜: {date} {time}"
+ createdAt: "생성 날짜: {date} {time}"
+ updatedAt: "갱신 날짜: {date} {time}"
cannotLoad: "가져오기에 실패했습니다"
invalidFile: "파일 형식이 올바르지 않습니다."
_registry:
@@ -1882,8 +1756,6 @@ _aboutMisskey:
contributors: "주요 기여자"
allContributors: "모든 기여자"
source: "소스 코드"
- original: "원본"
- thisIsModifiedVersion: "{name}에서는 원본 미스키를 수정한 버전을 사용하고 있습니다."
translation: "Misskey를 번역하기"
donate: "Misskey에 기부하기"
morePatrons: "이 외에도 다른 많은 분들이 도움을 주시고 계십니다. 감사합니다🥰"
@@ -1991,6 +1863,7 @@ _theme:
buttonBg: "버튼 배경"
buttonHoverBg: "버튼 배경 (호버)"
inputBorder: "입력 필드 테두리"
+ listItemHoverBg: "리스트 항목 배경 (호버)"
driveFolderBg: "드라이브 폴더 배경"
wallpaperOverlay: "배경화면 오버레이"
badge: "배지"
@@ -2002,15 +1875,16 @@ _sfx:
note: "새 노트"
noteMy: "내 노트"
notification: "알림"
+ antenna: "안테나 수신"
+ channel: "채널 알림"
reaction: "리액션 선택"
_soundSettings:
driveFile: "드라이브에 있는 오디오를 사용"
driveFileWarn: "드라이브에 있는 파일을 선택하세요."
- driveFileTypeWarn: "이 파이"
+ driveFileTypeWarn: "이 파일은 지원되지 않습니다."
driveFileTypeWarnDescription: "오디오 파일을 선택하세요."
driveFileDurationWarn: "오디오가 너무 깁니다"
driveFileDurationWarnDescription: "긴 오디오로 설정할 경우 미스키 사용에 지장이 갈 수도 있습니다. 그래도 괜찮습니까?"
- driveFileError: "오디오를 불러올 수 없습니다. 설정을 바꿔주세요."
_ago:
future: "미래"
justNow: "방금 전"
@@ -2040,6 +1914,7 @@ _2fa:
registerTOTP: "인증 앱 설정 시작"
step1: "먼저, {a}나 {b}등의 인증 앱을 사용 중인 디바이스에 설치합니다."
step2: "그 후, 표시되어 있는 QR코드를 앱으로 스캔합니다."
+ step2Click: "QR 코드를 클릭하면 기기에 설치된 인증 앱에 등록할 수 있습니다."
step2Uri: "데스크톱 앱을 사용하려면 다음 URI를 입력하십시오"
step3Title: "인증 코드 입력"
step3: "앱에 표시된 토큰을 입력하시면 완료됩니다."
@@ -2052,7 +1927,7 @@ _2fa:
securityKeyName: "키 이름 입력"
tapSecurityKey: "브라우저의 지시에 따라 보안 키 또는 패스키를 등록하여 주십시오"
removeKey: "보안 키를 삭제"
- removeKeyConfirm: "{name} 앱을 삭제하시겠습니까?"
+ removeKeyConfirm: "{name} 을(를) 삭제하시겠습니까?"
whyTOTPOnlyRenew: "보안 키가 등록되어 있는 경우 인증 앱을 해제할 수 없습니다."
renewTOTP: "인증 앱 재설정"
renewTOTPConfirm: "기존에 등록되어 있던 인증 키는 사용하지 못하게 됩니다."
@@ -2063,7 +1938,6 @@ _2fa:
backupCodesDescription: "인증 앱을 사용할 수 없게 된 경우 아래 백업 코드를 사용하여 계정에 액세스 할 수 있습니다.이 코드들은 반드시 안전한 장소에 보관하십시오.각 코드는 한 번만 사용할 수 있습니다."
backupCodeUsedWarning: "백업 코드가 사용되었습니다.인증 앱을 사용할 수 없게 된 경우, 조속히 인증 앱을 다시 설정해 주십시오."
backupCodesExhaustedWarning: "백업 코드가 모두 사용되었습니다.인증 앱을 사용할 수 없는 경우 더 이상 계정에 액세스하는 것이 불가능합니다.인증 앱을 다시 등록해 주세요."
- moreDetailedGuideHere: "여기에 자세한 설명이 있습니다"
_permissions:
"read:account": "계정의 정보를 봅니다"
"write:account": "계정의 정보를 변경합니다"
@@ -2114,6 +1988,7 @@ _permissions:
"read:admin:server-info": "서버 정보 보기"
"read:admin:show-moderation-log": "조정 기록 보기"
"read:admin:show-user": "사용자 개인정보 보기"
+ "read:admin:show-users": "사용자 개인정보 보기"
"write:admin:suspend-user": "사용자 정지하기"
"write:admin:unset-user-avatar": "사용자 아바타 삭제하기"
"write:admin:unset-user-banner": "사용자 배너 삭제하기"
@@ -2193,7 +2068,7 @@ _widgets:
postForm: "글 입력란"
slideshow: "슬라이드 쇼"
button: "버튼"
- onlineUsers: "온라인 사용자"
+ onlineUsers: "온라인 유저"
jobQueue: "작업 대기열"
serverMetric: "서버 통계"
aiscript: "AiScript 콘솔"
@@ -2255,7 +2130,7 @@ _postForm:
f: "작성해주시길 기다리고 있어요..."
_profile:
name: "이름"
- username: "사용자 이름"
+ username: "유저명"
description: "자기소개"
youCanIncludeHashtags: "해시 태그를 포함할 수 있습니다."
metadata: "추가 정보"
@@ -2267,9 +2142,6 @@ _profile:
changeBanner: "배너 이미지 변경"
verifiedLinkDescription: "내용에 자신의 프로필로 향하는 링크가 포함된 페이지의 URL을 삽입하면 소유자 인증 마크가 표시됩니다."
avatarDecorationMax: "최대 {max}개까지 장식을 할 수 있습니다."
- followedMessage: "팔로우 받았을 때 메시지"
- followedMessageDescription: "팔로우 받았을 때 상대방에게 보여줄 단문 메시지를 설정할 수 있습니다."
- followedMessageDescriptionForLockedAccount: "팔로우를 승인제로 한 경우, 팔로우 요청을 수락했을 때 보여줍니다."
_exportOrImport:
allNotes: "모든 노트"
favoritedNotes: "즐겨찾기한 노트"
@@ -2286,7 +2158,7 @@ _charts:
apRequest: "요청"
usersIncDec: "유저 수 증감"
usersTotal: "유저 수 합계"
- activeUsers: "활동 사용자 수"
+ activeUsers: "활성 유저 수"
notesIncDec: "노트 수 증감"
localNotesIncDec: "로컬 노트 수 증감"
remoteNotesIncDec: "리모트 노트 수 증감"
@@ -2297,8 +2169,8 @@ _charts:
storageUsageTotal: "스토리지 사용량 합계"
_instanceCharts:
requests: "요청"
- users: "사용자 수 차이"
- usersTotal: "누적 사용자 수"
+ users: "유저 수 증감"
+ usersTotal: "누적 유저 수"
notes: "노트 수 증감"
notesTotal: "누적 노트 수"
ff: "팔로잉/팔로워 증감"
@@ -2327,7 +2199,6 @@ _play:
title: "제목"
script: "스크립트"
summary: "설명"
- visibilityDescription: "비공개로 설정하면 프로필에 표시하지 않지만 URL을 아는 사람은 계속해서 접속할 수 있습니다."
_pages:
newPage: "페이지 만들기"
editPage: "페이지 수정"
@@ -2338,7 +2209,7 @@ _pages:
pageSetting: "페이지 설정"
nameAlreadyExists: "지정한 페이지 URL이 이미 존재합니다"
invalidNameTitle: "유효하지 않은 페이지 URL입니다"
- invalidNameText: "비어있는지 확인해 주세요"
+ invalidNameText: "비어있지 않은지 확인해주세요"
editThisPage: "이 페이지를 편집"
viewSource: "소스 보기"
viewPage: "페이지 보기"
@@ -2362,7 +2233,6 @@ _pages:
eyeCatchingImageSet: "아이캐치 이미지를 설정"
eyeCatchingImageRemove: "아이캐치 이미지를 삭제"
chooseBlock: "블록 추가"
- enterSectionTitle: "섹션 타이틀을 입력하기"
selectType: "종류 선택"
contentBlocks: "콘텐츠"
inputBlocks: "입력"
@@ -2373,8 +2243,6 @@ _pages:
section: "섹션"
image: "이미지"
button: "버튼"
- dynamic: "동적 블록"
- dynamicDescription: "이 블록은 폐지되었습니다. 이제부터 {play}에서 이용해 주세요."
note: "노트필기"
_note:
id: "노트 ID"
@@ -2404,29 +2272,22 @@ _notification:
sendTestNotification: "테스트 알림 보내기"
notificationWillBeDisplayedLikeThis: "알림이 이렇게 표시됩니다"
reactedBySomeUsers: "{n}명이 반응했습니다"
- likedBySomeUsers: "{n}명이 좋아요를 했습니다"
renotedBySomeUsers: "{n}명이 리노트했습니다"
followedBySomeUsers: "{n}명에게 팔로우됨"
- flushNotification: "알림 이력을 초기화"
- exportOfXCompleted: "{x} 추출에 성공했습니다."
- login: "로그인 알림이 있습니다"
_types:
all: "전부"
- note: "사용자의 새 글"
+ note: "유저의 새 게시물"
follow: "팔로잉"
mention: "멘션"
reply: "답글"
renote: "리노트"
quote: "인용"
- reaction: "반응"
+ reaction: "리액션"
pollEnded: "투표가 종료됨"
receiveFollowRequest: "팔로우 요청을 받았을 때"
followRequestAccepted: "팔로우 요청이 승인되었을 때"
roleAssigned: "역할이 부여 됨"
achievementEarned: "도전 과제 획득"
- exportCompleted: "추출을 성공함"
- login: "로그인"
- test: "알림 테스트"
app: "연동된 앱을 통한 알림"
_actions:
followBack: "팔로우"
@@ -2436,7 +2297,6 @@ _deck:
alwaysShowMainColumn: "메인 칼럼 항상 표시"
columnAlign: "칼럼 정렬"
addColumn: "칼럼 추가"
- newNoteNotificationSettings: "새 노트 알림 설정"
configureColumn: "칼럼 설정"
swapLeft: "왼쪽으로 이동"
swapRight: "오른쪽으로 이동"
@@ -2465,7 +2325,7 @@ _deck:
direct: "다이렉트"
roleTimeline: "역할 타임라인"
_dialog:
- charactersExceeded: "최대 글자수를 초과하였습니다! 현재 {current} / 최대 {max}"
+ charactersExceeded: "최대 글자수를 초과하였습니다! 현재 {current} / 최대 {min}"
charactersBelow: "최소 글자수 미만입니다! 현재 {current} / 최소 {min}"
_disabledTimeline:
title: "비활성화된 타임라인"
@@ -2475,10 +2335,9 @@ _drivecleaner:
orderByCreatedAtAsc: "등록일이 오래된 순"
_webhookSettings:
createWebhook: "Webhook 생성"
- modifyWebhook: "Webhook 수정"
name: "이름"
secret: "시크릿"
- trigger: "트리거"
+ events: "Webhook을 실행할 타이밍"
active: "활성화"
_events:
follow: "누군가를 팔로우했을 때"
@@ -2488,29 +2347,6 @@ _webhookSettings:
renote: "누군가 내 글을 리노트했을 때"
reaction: "누군가 내 노트에 리액션했을 때"
mention: "누군가 나를 멘션했을 때"
- _systemEvents:
- abuseReport: "유저롭"
- abuseReportResolved: "받은 신고를 처리했을 때"
- userCreated: "유저가 생성되었을 때"
- inactiveModeratorsWarning: "모더레이터가 일정 기간동안 활동하지 않은 경우"
- inactiveModeratorsInvitationOnlyChanged: "모더레이터가 일정 기간 활동하지 않아 시스템에 의해 초대제로 바뀐 경우"
- deleteConfirm: "Webhook을 삭제할까요?"
- testRemarks: "스위치 오른쪽에 있는 버튼을 클릭하여 더미 데이터를 사용한 테스트용 웹 훅을 보낼 수 있습니다."
-_abuseReport:
- _notificationRecipient:
- createRecipient: "신고 수신자 추가"
- modifyRecipient: "신고 수신자 편집"
- recipientType: "알림 종류"
- _recipientType:
- mail: "이메일"
- webhook: "Webhook"
- _captions:
- mail: "모더레이터 권한을 가진 사용자의 이메일 주소에 알림을 보냅니다 (신고를 받은 때에만)"
- webhook: "지정한 SystemWebhook에 알림을 보냅니다 (신고를 받은 때와 해결했을 때에 송신)"
- keywords: "키워드"
- notifiedUser: "알릴 사용자"
- notifiedWebhook: "사용할 Webhook"
- deleteConfirm: "수신자를 삭제하시겠습니까?"
_moderationLogTypes:
createRole: "역할 생성"
deleteRole: "역할 삭제"
@@ -2526,7 +2362,7 @@ _moderationLogTypes:
updateUserNote: "조정 기록 갱신"
deleteDriveFile: "파일 삭제"
deleteNote: "노트 삭제"
- createGlobalAnnouncement: "전역 공지사항 생성"
+ createGlobalAnnouncement: "모든 공지사항 만들기"
createUserAnnouncement: "사용자 공지사항 만들기"
updateGlobalAnnouncement: "모든 공지사항 수정"
updateUserAnnouncement: "사용자 공지사항 수정"
@@ -2535,12 +2371,9 @@ _moderationLogTypes:
resetPassword: "비밀번호 재설정"
suspendRemoteInstance: "리모트 서버를 정지"
unsuspendRemoteInstance: "리모트 서버의 정지를 해제"
- updateRemoteInstanceNote: "리모트 서버의 조정 기록 갱신"
markSensitiveDriveFile: "파일에 열람주의를 설정"
unmarkSensitiveDriveFile: "파일에 열람주의를 해제"
resolveAbuseReport: "신고 처리"
- forwardAbuseReport: "신고 전달"
- updateAbuseReportNote: "신고 조정 노트 갱신"
createInvitation: "초대 코드 생성"
createAd: "광고 생성"
deleteAd: "광고 삭제"
@@ -2550,16 +2383,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "아바타 장식 삭제"
unsetUserAvatar: "유저 아바타 제거"
unsetUserBanner: "유저 배너 제거"
- createSystemWebhook: "SystemWebhook을 생성"
- updateSystemWebhook: "SystemWebhook을 수정"
- deleteSystemWebhook: "SystemWebhook을 삭제"
- createAbuseReportNotificationRecipient: "신고 알림 수신자 생성"
- updateAbuseReportNotificationRecipient: "신고 알림 수신자 편집"
- deleteAbuseReportNotificationRecipient: "신고 알림 수신자 삭제"
- deleteAccount: "계정을 삭제"
- deletePage: "페이지를 삭제"
- deleteFlash: "Play를 삭제"
- deleteGalleryPost: "갤러리 포스트를 삭제"
_fileViewer:
title: "파일 상세"
type: "파일 유형"
@@ -2625,7 +2448,7 @@ _dataSaver:
_hemisphere:
N: "북반구"
S: "남반구"
- caption: "일부 클라이언트 설정에서 계절을 판단하려고 사용합니다."
+ caption: "일부 클라이언트 설정에서 계절을 판단하기 위해 사용합니다."
_reversi:
reversi: "리버시"
gameSettings: "대국 설정"
@@ -2633,80 +2456,42 @@ _reversi:
blackOrWhite: "선공/후공"
blackIs: "{name}님이 흑(선공)"
rules: "규칙"
- thisGameIsStartedSoon: "대국을 곧 시작합니다"
- waitingForOther: "상대의 준비가 끝나기를 기다리고 있습니다."
- waitingForMe: "나의 준비가 끝나기를 기다리고 있습니다."
+ thisGameIsStartedSoon: "대국이 곧 시작됩니다"
+ waitingForOther: "상대방의 준비가 완료되기를 기다리고 있습니다."
+ waitingForMe: "당신의 준비가 완료되기를 기다리고 있습니다."
waitingBoth: "준비하세요"
ready: "준비 완료"
- cancelReady: "준비되지 않음"
+ cancelReady: "준비 다시 시작"
opponentTurn: "상대의 차례입니다"
- myTurn: "나의 차례입니다"
- turnOf: "{name}님의 차례입니다"
- pastTurnOf: "{name}님의 차례"
+ myTurn: "당신의 차례입니다"
+ turnOf: "{name}의 차례입니다"
+ pastTurnOf: "{name}의 차례"
surrender: "기권"
- surrendered: "상대의 기권"
+ surrendered: "기권에 의해"
timeout: "시간 초과"
drawn: "무승부"
- won: "{name}님의 승리"
+ won: "{name}의 승리"
black: "흑"
white: "백"
total: "합계"
- turnCount: "{count}번째 수"
+ turnCount: "{count}턴 째"
myGames: "내 대국"
- allGames: "모든 대국"
+ allGames: "모두의 대국"
ended: "종료"
playing: "대국 중"
- isLlotheo: "돌이 적은 쪽이 승리(로세오)"
- loopedMap: "순환 지도"
- canPutEverywhere: "어디든 둘 수 있는 모드"
- timeLimitForEachTurn: "각 수의 시간 제한"
- freeMatch: "자유 대국"
- lookingForPlayer: "대국 상대를 찾고 있습니다"
+ isLlotheo: "돌이 적은 사람이 승리 (로세오)"
+ loopedMap: "루프 지도"
+ canPutEverywhere: "어디에도 둘 수 있는 모드"
+ timeLimitForEachTurn: "1턴의 시간 제한"
+ freeMatch: "프리매치"
+ lookingForPlayer: "상대를 찾고 있습니다"
gameCanceled: "대국이 취소되었습니다"
- shareToTlTheGameWhenStart: "대국이 시작할 때 타임라인에 공유"
- iStartedAGame: "대국을 시작하였습니다! #MisskeyReversi"
- opponentHasSettingsChanged: "상대가 설정을 변경했습니다"
- allowIrregularRules: "규칙 변경 허용(완전 자유)"
- disallowIrregularRules: "규칙 변경 없음"
- showBoardLabels: "판에 행·열 번호 표시"
- useAvatarAsStone: "돌을 아이콘으로 표시"
+ shareToTlTheGameWhenStart: "대국 시작 시 타임라인에 대국을 게시"
+ iStartedAGame: "대국이 시작되었습니다! #MisskeyReversi"
+ opponentHasSettingsChanged: "상대방이 설정을 변경했습니다"
+ allowIrregularRules: "규칙변경 허가 (완전 자유)"
+ disallowIrregularRules: "규칙변경 없음"
_offlineScreen:
title: "오프라인 - 서버에 접속할 수 없습니다"
header: "서버에 접속할 수 없습니다"
-_urlPreviewSetting:
- title: "URL 미리보기 설정"
- enable: "URL 미리보기 활성화"
- timeout: "미리보기를 불러올 때의 타임아웃 (ms)"
- timeoutDescription: "미리보기를 로딩하는데 걸리는 시간이 정한 시간보다 오래 걸리는 경우, 미리보기를 생성하지 않습니다."
- maximumContentLength: "Content-Length의 최대치 (byte)"
- maximumContentLengthDescription: "Content-Length가 이 값을 넘어서면 미리보기를 생성하지 않습니다."
- requireContentLength: "Content-Length를 받아온 경우에만 "
- requireContentLengthDescription: "상대 서버가 Content-Length를 되돌려주지 않는다면 미리보기를 만들지 않습니다."
- userAgent: "User-Agent"
- userAgentDescription: "미리보기를 얻을 때 사용한 User-Agent를 설정합니다. 비어 있다면 기본값의 User-Agent를 사용합니다."
- summaryProxy: "미리보기를 만든 프록시의 엔드포인트"
- summaryProxyDescription: "Misskey 본체를 사용하지 않고 서머리 프록시로 미리보기를 만듭니다."
- summaryProxyDescription2: "프록시는 아래의 파라미터를 쿼리 문자열로 연동합니다. 프록시 측이 이를 지원하지 않으면 설정값을 무시합니다."
-_mediaControls:
- pip: "화면 속 화면"
- playbackRate: "재생 속도"
- loop: "반복 재생"
-_contextMenu:
- title: "컨텍스트 메뉴"
- app: "애플리케이션"
- appWithShift: "Shift 키로 애플리케이션"
- native: "브라우저의 UI"
-_embedCodeGen:
- title: "임베디드 코드를 커스터마이즈"
- header: "해더를 표시"
- autoload: "자동으로 다음 코드를 실행 (비권장)"
- maxHeight: "최대 높이"
- maxHeightDescription: "최대 값을 무시하려면 0을 입력하세요. 위젯이 상하로 길어지는 것을 방지하려면, 임의의 값을 입력해 주세요."
- maxHeightWarn: "높이 최대 값이 설정되어져 있지 않습니다(0). 의도적으로 설정 하지 않았다면 임의의 값을 설정해주세요."
- previewIsNotActual: "미리보기로 표시할 수 있는 크기보다 큽니다. 실제로 넣은 코드의 표시가 다른 경우가 있습니다."
- rounded: "외곽선을 둥글게 하기"
- border: "외곽선에 테두리를 씌우기"
- applyToPreview: "미리보기에 반영"
- generateCode: "임베디드 코드를 만들기"
- codeGenerated: "코드를 만들었습니다."
- codeGeneratedDescription: "만들어진 코드를 웹 사이트에 붙여서 사용하세요."
+
diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml
index b100d0300f..6f03c914fd 100644
--- a/locales/lo-LA.yml
+++ b/locales/lo-LA.yml
@@ -18,15 +18,15 @@ enterUsername: "ປ້ອນຊື່ຜູ້ໃຊ້"
renotedBy: "Renoted ໂດຍ {user}"
noNotes: "ບໍ່ມີ note"
noNotifications: "ບໍ່ມີການແຈ້ງເຕືອນ"
-instance: "ເຊີຟເວີຣ໌"
-settings: "ຕັ້ງຄ່າ"
+instance: "ອີນສະແຕນ"
+settings: "ກຳນົດຄ່າ"
notificationSettings: "ຕັ້ງຄ່າການແຈ້ງເຕືອນ"
basicSettings: "ການຕັ້ງຄ່າພື້ນຖານ"
otherSettings: "ການຕັ້ງຄ່າອື່ນໆ"
-openInWindow: "ເປີດໃນ window"
-profile: "ໂປຣໄຟລ໌"
+openInWindow: "ເປີດໃນປ່ອງຢ້ຽມ"
+profile: "ໂພຼຟາຍ"
timeline: "ໄທມ໌ໄລນ໌"
-noAccountDescription: "ຜູ້ໃຊ້ຄົນນີ້ຍັງບໍ່ໄດ້ຂຽນຄຳແນະນຳໂຕ"
+noAccountDescription: "ຜູ້ໃຊ້ນີ້ຍັງບໍ່ໄດ້ຂຽນໃນຊີວະປະຫວັດຂອງເຂົາເຈົ້າເທື່ອ"
login: "ເຂົ້າສູ່ລະບົບ"
loggingIn: "ກຳລັງເຂົ້າສູ່ລະບົບ..."
logout: "ອອກຈາກລະບົບ"
@@ -37,7 +37,7 @@ users: "ຜູ້ໃຊ້"
addUser: "ເພີ່ມຜູ້ໃຊ້"
favorite: "ເພີ່ມໃສ່ລາຍການທີ່ມັກ"
favorites: "ລາຍການທີ່ມັກ"
-unfavorite: "ເອົາອອກຈາກລາຍການທີ່ມັກ"
+unfavorite: "ລຶບອອກຈາກລາຍການທີ່ມັກ"
favorited: "ເພີ່ມໃສ່ລາຍການທີ່ມັກແລ້ວ"
alreadyFavorited: "ເພີ່ມເຂົ້າໃນລາຍການທີ່ມັກແລ້ວ."
cantFavorite: "ບໍ່ສາມາດເພີ່ມໃສ່ລາຍການທີ່ມັກໄດ້."
@@ -48,41 +48,41 @@ copyLink: "ຄັດລອກລິ້ງ"
copyLinkRenote: "ຄັດລອກລິ້ງຂອງ renote"
delete: "ລຶບ"
deleteAndEdit: "ລຶບແລະແກ້ໄຂ"
-deleteAndEditConfirm: "ຕ້ອງການລຶບ note ນີ້ແລະແກ້ໄຂໃໝ່ແມ່ນບໍ່? reaction, renote ແລະການຕອບກັບຕໍ່ note ນີ້ ທັງເບິດຈະຖືກລຶບອອກ"
+deleteAndEditConfirm: "ເຈົ້າແນ່ໃຈບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບ note ນີ້ ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍ reaction, renote, ແລະການຕອບກັບທັງໝົດ"
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
addToAntenna: "ເພີ່ມໃສ່ເສົາອາກາດ"
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
-copyRSS: "ຄັດລອກ RSS"
-copyUsername: "ຄັດລອກຊື່ຜູ້ໃຊ້"
-copyUserId: "ຄັດລອກ ID ຜູ້ໃຊ້"
-copyNoteId: "ຄັດລອກ ID ຂອງ note"
-copyFileId: "ຄັດລອກ ID ໄຟລ໌"
-copyFolderId: "ຄັດລອກ ID ໂຟລ໌ເດີຣ໌"
-copyProfileUrl: "ຄັດລອກ URL ໂປຣໄຟລ໌"
+copyRSS: "ສຳເນົາ RSS"
+copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
+copyUserId: "ສຳເນົາ ID ຜູ້ໃຊ້"
+copyNoteId: "ສຳເນົາ ID ບັນທຶກ"
+copyFileId: "ສຳເນົາ ID ໄຟລ໌"
+copyFolderId: "ສຳເນົາ ID ໂຟນເດີ"
+copyProfileUrl: "ສຳເນົາ URL ໂປຣໄຟລ໌"
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
-reply: "ຕອບກັບ"
+reply: "ຕອບໄປທີ"
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
showMore: "ໂຫຼດເພີ່ມເຕີມ"
showLess: "ປິດ"
-youGotNewFollower: "ໄດ້ຕິດຕາມເຈົ້າ"
-receiveFollowRequest: "ມີຄຳຂໍຕິດຕາມສົ່ງມາ"
-followRequestAccepted: "ການຕິດຕາມໄດ້ຮັບອນຸຍາດແລ້ວ"
-mention: "ເວົ້າເຖີງ"
-mentions: "ເວົ້າເຖີງເຈົ້າ"
+youGotNewFollower: "ໄດ້ຕິດຕາມທ່ານ"
+receiveFollowRequest: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍທີ່ໄດ້ຮັບ"
+followRequestAccepted: "ຜູ້ຕິດຕາມໄດ້ຍອມຮັບຄໍາຮ້ອງຂໍຂອງທ່ານ"
+mention: "ກ່າວຖືງ"
+mentions: "ກ່າວເຖິງ"
directNotes: "ໂພສ Direct note"
importAndExport: "ນໍາເຂົ້າ / ສົ່ງອອກ"
import: "ນຳເຂົ້າ"
export: "ສົ່ງອອກ"
files: "ໄຟລ໌"
download: "ດາວໂຫລດ"
-driveFileDeleteConfirm: "ຕ້ອງການລຶບໄຟລ໌ “{name}” ແມ່ນບໍ່? Note ທີ່ແນບມາກັບໄຟລ໌ນີ້ຈະຖືກລຶບອອກ"
-unfollowConfirm: "ຕ້ອງການເລີກຕິດຕາມ {name} ແມ່ນບໍ່?"
-exportRequested: "ເຈົ້າໄດ້ຮ້ອງຂໍການສົ່ງອອກ ອາດໃຊ້ເວລາຈັກໜ່ອຍ ເມື່ອແລ້ວຈະຖືກເພີ່ມໃສ່ drive"
-importRequested: "ເຈົ້າໄດ້ຮ້ອງຂໍການນຳເຂົ້າ ການດຳເນິນການນີ້ອາດໃຊ້ເວລາຈັກໜ່ອຍ"
+driveFileDeleteConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບໄຟລ໌ \"{name}\"? note ທີ່ມີໄຟລ໌ແນບນີ້ຈະຖືກລຶບຖິ້ມ"
+unfollowConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການເຊົາຕິດຕາມ {name}?"
+exportRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການສົ່ງອອກ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ ແລະມັນຈະຖືກເພີ່ມໃສ່ drive ຂອງທ່ານເມື່ອມັນສຳເລັດແລ້ວ"
+importRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການນໍາເຂົ້າ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ"
lists: "ລາຍການ"
-noLists: "ບໍ່ມີລາຍການໃດໆ"
-note: "Note"
-notes: "Note"
+noLists: "ທ່ານບໍ່ມີລາຍການໃດໆ"
+note: "ບັນທຶກ"
+notes: "ບັນທຶກ"
following: "ກຳລັງຕິດຕາມ"
followers: "ຜູ້ຕິດຕາມ"
followsYou: "ຕິດຕາມເຈົ້າ"
@@ -124,11 +124,11 @@ reactions: "reaction"
attachCancel: "ເອົາໄຟລ໌ແນບ"
mute: "ປີດສຽງ"
unmute: "ເປີດສຽງ"
-block: "ບລັອກ"
-unblock: "ເລີກບລັອກ"
+block: "ບ໋ອກ"
+unblock: "ຍົກເລີກກາຮົບລັອກ"
suspend: "ລະງັບ"
unsuspend: "ເຊົາລະງັບ"
-selectList: "ເລືອກລາຍຊື່"
+selectList: "ເລືອກບັນຊີລາຍການ"
editList: "ແກ້ໄຂລາຍຊື່"
selectChannel: "ເລືອກຊ່ອງ"
selectAntenna: "ເລືອກເສົາອາກາດ"
@@ -151,30 +151,30 @@ flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບ
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
addAccount: "ເພີ່ມບັນຊີ"
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
-showOnRemote: "ເບິ່ງໃນເຊີຟເວີຣ໌ໄລຍະໄກ"
+showOnRemote: "ເບິ່ງຢູ່ໃນຕົວຢ່າງໄລຍະໄກ"
general: "ທົ່ວໄປ"
wallpaper: "ພາບພື້ນຫລັງ"
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
removeWallpaper: "ລຶບຮູບວໍເປເປີອອກ"
searchWith: "ຊອກຫາ: {q}"
-youHaveNoLists: "ເຈົ້າບໍ່ມີລາຍຊື່ໃດໆ"
+youHaveNoLists: "ທ່ານບໍ່ມີລາຍການໃດໆ"
proxyAccount: "ບັນຊີພຣັອກຊີ"
-host: "ໂຮສຕ໌"
+host: "ໂຮດສ"
selectUser: "ເລືອກຜູ້ໃຊ້"
recipient: "ເຖິງ"
annotation: "ຄຳເຫັນ"
federation: "ສະຫະພັນ"
-instances: "ເຊີຟເວີຣ໌"
+instances: "ອີນສະແຕນ"
registeredAt: "ລົງທະບຽນຢູ່"
storageUsage: "ບ່ອນຈັດເກັບຂໍ້ມູນທີ່ໃຊ້"
-charts: "ແຜນພູມ"
+charts: "ອັນດັບເພງ"
perHour: "ຕໍ່ຊົ່ວໂມງ"
perDay: "ຕໍ່ມື້"
stopActivityDelivery: "ຢຸດເຊົາການສົ່ງກິດຈະກໍາ"
blockThisInstance: "ຂັດຂວາງຕົວຢ່າງນີ້"
operations: "ການດຳເນີນງານ"
software: "ຊອບແວ"
-version: "ເວີຣ໌ຊັນ"
+version: "ສະບັບ"
metadata: "Metadata"
withNFiles: "{n} ໄຟລ໌(s)"
monitor: "ຈໍພາບ"
@@ -199,15 +199,15 @@ federating: "ສະຫະພັນ"
blocked: "ບລັອກແລ້ວ "
suspended: "ໂຈະ"
all: "ທັງໝົດ"
-subscribing: "ກຳລັງສະມັກສະມາຊິກ"
-publishing: "ກຳລັງເຜີຍແພ່"
+subscribing: "ສະໝັກສະມາຊິກແລັວ"
+publishing: "ການພິມເຜີຍແຜ່"
notResponding: "ບໍ່ຕອບສະໜອງ"
-instanceFollowing: "ກຳລັງຕິດຕາມບົນເຊີຟເວີຣ໌"
-instanceFollowers: "ຜູ້ຕິດຕາມຂອງເຊີຟເວີຣ໌"
-instanceUsers: "ຜູ້ໃຊ້ຂອງເຊີຟເວີຣ໌ນີ້"
+instanceFollowing: "ກຳລັງຕິດຕາມສຸດຕົວຢ່າງ"
+instanceFollowers: "ຜູ້ຕິດຕາມຕົວຢ່າງ"
+instanceUsers: "ຜູ້ຊົມໃຊ້ຂອງຕົວຢ່າງນີ້"
changePassword: "ປ່ຽນລະຫັດຜ່ານ"
security: "ຄວາມປອດໄພ"
-retypedNotMatch: "ປ້ອນຂໍ້ມູນບໍ່ກົງກັນ"
+retypedNotMatch: "ວັດສະດຸປ້ອນບໍ່ກົງກັນ"
currentPassword: "ລະຫັດຜ່ານປະຈຸບັນ"
newPassword: "ລະຫັດຜ່ານໃໝ່"
newPasswordRetype: "ໃສ່ລະຫັດຜ່ານໃໝ່ອີກເທື່ອໜຶ່ງ"
@@ -223,14 +223,14 @@ remove: "ລຶບ"
removed: "ລຶບແລ້ວ"
resetAreYouSure: "ຣີເຊັດບໍ?"
saved: "ບັນທຶກແລ້ວ"
-messaging: "ແຊັຕ"
+messaging: "ແຊ໋ດ"
upload: "ອັບໂຫຼດ"
keepOriginalUploading: "ຮັກສາຮູບພາບຕົ້ນສະບັບ"
fromDrive: "ຈາກ Drive"
fromUrl: "ຈາກ URL"
uploadFromUrl: "ອັບໂຫຼດຈາກ URL"
uploadFromUrlDescription: "URL ຂອງໄຟລ໌ທີ່ທ່ານຕ້ອງການອັບໂຫລດ"
-uploadFromUrlRequested: "ຮ້ອງຂໍການອັບໂຫລດແລ້ວ"
+uploadFromUrlRequested: "ຮ້ອງຂໍການອັບໂຫລດ"
explore: "ສຳຫຼວດ"
messageRead: "ອ່ານແລ້ວ"
startMessaging: "ເລີ່ມການສົນທະນາໃໝ່"
@@ -244,47 +244,47 @@ images: "ຮູບພາບ"
image: "ຮູບພາບ"
birthday: "ວັນເກີດ"
yearsOld: "{age} ປີ"
-registeredDate: "ວັນທີ່ລົງທະບຽນ"
+registeredDate: "ວັນທີ່ເປັນສະມາຊິກ"
location: "ທີ່ຕັ້ງ"
-theme: "Theme"
-themeForLightMode: "Theme ໃຊ້ໃນໂໝດສະຫວ່າງ"
-themeForDarkMode: "Theme ໃຊ້ໃນໂໝດມືດ"
+theme: "ແທ໋ມ"
+themeForLightMode: "ຮູບແບບສີສັນເພື່ອໃຊ້ໃນໂໝດແສງ"
+themeForDarkMode: "ຮູບແບບສີສັນທີ່ຈະໃຊ້ຢູ່ໃນໂໝດມືດ"
light: "ສະຫວ່າງ"
dark: "ມືດ"
lightThemes: "ຊຸດຮູບແບບສະຫວ່າງ"
darkThemes: "ຮູບແບບສີສັນມືດ"
syncDeviceDarkMode: "ຊິງຄ໌ໂໝດມືດກັບການຕັ້ງຄ່າທົ່ວອຸປະກອນ"
-drive: "Drive"
+drive: "ຂັບ"
fileName: "ຊື່ໄຟລ໌"
selectFile: "ເລືອກໄຟລ໌"
selectFiles: "ເລືອກໄຟລ໌"
selectFolder: "ເລືອກໂຟລເດີ"
selectFolders: "ເລືອກໂຟລເດີ"
renameFile: "ປ່ຽນຊື່ໄຟລ໌"
-folderName: "ຊື່ໂຟລເດີຣ໌"
+folderName: "ຊື່ໂຟນເດີ"
createFolder: "ສ້າງໂຟລເດີ"
renameFolder: "ປ່ຽນຊື່ໂຟນເດີນີ້"
deleteFolder: "ລົບໂຟລເດີ"
addFile: "ເພີ່ມໄຟລ໌"
emptyDrive: "Drive ຂອງທ່ານຫວ່າງເປົ່າ"
-emptyFolder: "ໂຟລເດີຣ໌ນີ້ວ່າງເປົ່າ"
+emptyFolder: "ໂຟນເດີນີ້ເປົ່າຫວ່າງ"
unableToDelete: "ບໍ່ສາມາດລົບໄດ້"
inputNewFileName: "ໃສ່ຊື່ໄຟລ໌ໃໝ່"
inputNewDescription: "ໃສ່ຄຳບັນຍາຍໃໝ່"
inputNewFolderName: "ໃສ່ຊື່ໂຟນເດີໃໝ່"
circularReferenceFolder: "ໂຟນເດີປາຍທາງແມ່ນໂຟນເດີຍ່ອຍຂອງໂຟນເດີທີ່ທ່ານຕ້ອງການຍ້າຍ"
rename: "ປ່ຽນຊື່"
-doNothing: "ຢ່າມັນ"
-watch: "ເພັ່ງເລັງ"
-unwatch: "ຢຸດເພັ່ງເລັງ"
+doNothing: "ບໍ່ສົນໃຈ"
+watch: "ເບິ່ງ"
+unwatch: "ຢຸດເບິ່ງ"
accept: "ອະນຸຍາດ"
reject: "ປະຕິເສດ"
normal: "ປົກກະຕິ"
instanceName: "ຊື່ເຊີເວີ້"
-instanceDescription: "ຄຳອະທິບາຍແນະນຳເຊີຟເວີຣ໌"
+instanceDescription: "ຄໍາອະທິບາຍຕົວຢ່າງ"
maintainerName: "ຜູ້ດູແລ"
-maintainerEmail: "ອີເມລຜູ້ດູແລ"
-tosUrl: " URL ເງື່ອນໄຂການໃຫ້ບໍລິການ"
+maintainerEmail: "ອີເມວ admin"
+tosUrl: "ເງື່ອນໄຂການໃຫ້ບໍລິການ URL"
thisYear: "ປີນີ້"
thisMonth: "ເດືອນນີ້"
today: "ມື້ນີ້"
@@ -292,34 +292,34 @@ dayX: "ວັນ {day}"
monthX: "ເດືອນ {month}"
yearX: "ປີ {year}"
pages: "ໜ້າ"
-integration: "ເຊື່ອມໂຍງ"
+integration: "ຄວາມສຳພັນຂອງ"
connectService: "ເຊື່ອມຕໍ່"
disconnectService: "ຕັດການເຊື່ອມຕໍ່"
enableLocalTimeline: "ເປີດໃຊ້ທາມລາຍທ້ອງຖິ່ນ"
enableGlobalTimeline: "ເປີດໃຊ້ທາມລາຍທົ່ວໂລກ"
-disablingTimelinesInfo: "ຜູ້ດູແລລະບບແລະຜູ້ຄວບຄຸມຈະສາມາດເຂົ້າເຖີງໄທມ໌ໄລນ໌ທັ້ງເບີດ ເຖີງວ່າຈະບໍ່ໄດ້ເປີດໃຊ້ງານກໍ່ຕາມ"
+disablingTimelinesInfo: "ຜູ້ເບິ່ງແຍງລະບົບ ແລະຜູ້ຄວບຄຸມຈະມີການເຂົ້າເຖິງທຸກກຳນົດເວລາ, ເຖິງແມ່ນວ່າຈະບໍ່ໄດ້ເປີດໃຊ້ງານກໍຕາມ"
registration: "ລົງທະບຽນ"
enableRegistration: "ເປີດໃຊ້ການລົງທະບຽນຜູ້ໃຊ້ໃໝ່"
invite: "ເຊີນ"
-driveCapacityPerLocalAccount: "ຄວາມຈຸຂອງ drive ຕໍ່ຜູ້ໃຊ້ທ້ອງຖິ່ນ"
-driveCapacityPerRemoteAccount: "ຄວາມຈຸຂອງ drive ຕໍ່ຜູ້ໃຊ້ໄລຍະໄກ"
+driveCapacityPerLocalAccount: "ຄວາມອາດສາມາດຂັບຕໍ່ຜູ້ໃຊ້ທ້ອງຖິ່ນ"
+driveCapacityPerRemoteAccount: "ໄດຣຟ໌ຄວາມອາດສາມາດຕໍ່ຜູ້ໃຊ້ທາງໄກ"
basicInfo: "ຂໍ້ມຸນເບື້ອງຕົ້ນ"
-pinnedNotes: "Note ທີ່ປັກໝຸດໄວ້"
-hcaptchaSiteKey: "Site key"
-hcaptchaSecretKey: "Secret key"
-mcaptchaSiteKey: "Site key"
-mcaptchaSecretKey: "Secret Key"
+pinnedNotes: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
+hcaptchaSiteKey: "ກະແຈໄຊທ໌"
+hcaptchaSecretKey: "ກະແຈລັບ"
+mcaptchaSiteKey: "ກະແຈໄຊທ໌"
+mcaptchaSecretKey: "ກະແຈລັບ"
recaptcha: "reCAPTCHA"
-enableRecaptcha: "ເປີດໃຊ້ງານ reCAPTCHA"
-recaptchaSiteKey: "Site key"
-recaptchaSecretKey: "Secret key"
-turnstileSiteKey: "Site key"
-turnstileSecretKey: "Secret key"
+enableRecaptcha: "ເປີດໃຊ້ງານລີແຄ໋ບຈາ"
+recaptchaSiteKey: "ກະແຈໄຊທ໌"
+recaptchaSecretKey: "ກະແຈລັບ"
+turnstileSiteKey: "ກະແຈໄຊທ໌"
+turnstileSecretKey: "ກະແຈລັບ"
name: "ຊື່"
userList: "ລາຍການ"
about: "ກ່ຽວກັບ"
aboutMisskey: "ກ່ຽວກັບ Misskey"
-administrator: "ຜູ້ດູແລ"
+administrator: "ຜູ້ບໍລິຫານ"
token: "ໂທເຄັນ"
share: "ແບ່ງປັນ"
notFound: "ບໍ່ພົບ"
@@ -332,27 +332,27 @@ title: "ຫົວຂໍ້"
text: "ຂໍ້ຄວາມ"
enable: "ເປີດໃຊ້"
next: "ຕໍ່ໄປ"
-retype: "ລອງພິມລະຫັດອີກເທື່ອໜຶ່ງ"
-quoteAttached: "ອ້າງອິງ"
+retype: "ເຂົ້າໄປອີກຄັ້ງ"
+quoteAttached: "ວົງຢືມ"
invitations: "ເຊີນ"
unavailable: "ບໍ່ສາມາດໃຊ້ໄດ້"
language: "ພາສາ"
aboutX: "ກ່ຽວກັບ {x}"
emojiStyle: "ຮູບແບບອີໂມຈິ"
native: "ພາສາແມ່"
-noHistory: "ບໍ່ມີປະຫວັດ"
+noHistory: "ບໍ່ມີລາຍການຢູ່ບ່ອນນີ້"
doing: "ກຳລັງປະມວນຜົນ..."
category: "ຫມວດຫມູ່"
-tags: "Aliases"
+tags: "ແທ໋ກ"
createAccount: "ສ້າງບັນຊີ"
-existingAccount: "ບັນຊີທີ່ມີຢູ່ແລ້ວ"
-dashboard: "Dashboard"
+existingAccount: "ທີ່ມີຢູ່"
+dashboard: "ໜ້າປັດ"
local: "ທ້ອງຖິ່ນ"
numberOfDays: "ຈຳນວນມື້"
objectStorageBucket: "Bucket"
objectStoragePrefix: "Prefix"
objectStorageEndpoint: "Endpoint"
-objectStorageRegion: "ພູມິພາກ"
+objectStorageRegion: "ພາກພື້ນ"
deleteAll: "ລຶບທັງໝົດ"
sounds: "ສຽງ"
sound: "ສຽງ"
@@ -365,11 +365,11 @@ state: "ສະຖານະ"
sort: "ຈັດຮຽງໂດຍ"
ascendingOrder: "ນ້ອຍໄປຫາໃຫຍ່"
descendingOrder: "ໃຫຍ່ຫານ້ອຍ"
-output: "Output"
-script: "Script"
+output: "ຜົນຜະລິດ"
+script: "ບົດຄວາມ"
menu: "ເມນູ"
-rearrange: "ຈັດລຽງໃໝ່"
-poll: "Poll"
+rearrange: "ຈັດລຽງຄືນ"
+poll: "ການພູນ"
description: "ລາຍລະອຽດ"
author: "ຜູ້ຂຽນ"
manage: "ການຈັດການ"
@@ -383,7 +383,7 @@ permission: "ການອະນຸຍາດ"
notificationType: "ປະເພດການແຈ້ງເຕືອນ"
edit: "ແກ້ໄຂ"
email: "ອີເມວ"
-smtpHost: "ໂຮສຕ໌"
+smtpHost: "ໂຮດສ"
smtpUser: "ຊື່ຜູ້ໃຊ້"
smtpPass: "ລະຫັດຜ່ານ"
clearCache: "ລຶບລ້າງແຄສ"
@@ -393,12 +393,8 @@ administration: "ການຈັດການ"
middle: "ປານກາງ"
searchByGoogle: "ຄົ້ນຫາ"
file: "ໄຟລ໌"
-replies: "ຕອບກັບ"
+replies: "ຕອບໄປທີ"
renotes: "Renote"
-_delivery:
- stop: "ໂຈະ"
- _type:
- none: "ກຳລັງເຜີຍແພ່"
_role:
_priority:
middle: "ປານກາງ"
@@ -416,8 +412,8 @@ _sfx:
_2fa:
renewTOTPCancel: "ບໍ່ແມ່ນຕອນນີ້"
_widgets:
- profile: "ໂປຣໄຟລ໌"
- instanceInfo: "ຂໍ້ມູລເຊີຟເວີຣ໌"
+ profile: "ໂພຼຟາຍ"
+ instanceInfo: "ອີນສະແຕນ"
notifications: "ການແຈ້ງເຕືອນ"
timeline: "ເສັ້ນກຳນົດເວລາ"
activity: "ກິດຈະກຳ"
@@ -436,29 +432,28 @@ _profile:
_exportOrImport:
followingList: "ກຳລັງຕິດຕາມ"
muteList: "ປີດສຽງ"
- blockingList: "ບລັອກ"
+ blockingList: "ບ໋ອກ"
userLists: "ລາຍການ"
_charts:
federation: "ສະຫະພັນ"
_timelines:
home: "ໜ້າຫຼັກ"
_play:
- script: "Script"
+ script: "ບົດຄວາມ"
summary: "ລາຍລະອຽດ"
_pages:
blocks:
image: "ຮູບພາບ"
_notification:
- youWereFollowed: "ໄດ້ຕິດຕາມເຈົ້າ"
+ youWereFollowed: "ໄດ້ຕິດຕາມທ່ານ"
_types:
follow: "ກຳລັງຕິດຕາມ"
- mention: "ໄດ້ກ່າວເຖິງ"
+ mention: "ໄດ້ກ່າວມາ"
renote: "Renote"
- quote: "ອ້າງອີງ"
- reaction: "Reaction"
- login: "ເຂົ້າສູ່ລະບົບ"
+ quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
+ reaction: "ປະຕິກິລິຍາ"
_actions:
- reply: "ຕອບກັບ"
+ reply: "ຕອບໄປທີ"
renote: "Renote"
_deck:
_columns:
@@ -466,12 +461,9 @@ _deck:
tl: "ເສັ້ນກຳນົດເວລາ"
list: "ລາຍການ"
channel: "ຊ່ອງ"
- mentions: "ກ່າວເຖິງເຈົ້າ"
+ mentions: "ກ່າວເຖິງ"
_webhookSettings:
name: "ຊື່"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "ອີເມວ"
_moderationLogTypes:
suspend: "ລະງັບ"
+
diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml
index dde3035357..42fbf183be 100644
--- a/locales/nl-NL.yml
+++ b/locales/nl-NL.yml
@@ -427,12 +427,8 @@ windowMaximize: "Maximaliseren"
windowRestore: "Herstellen"
loggedInAsBot: "Momenteel als bot ingelogd"
icon: "Avatar"
-replies: "Antwoord"
+replies: "Antwoorden"
renotes: "Herdelen"
-_delivery:
- stop: "Opgeschort"
- _type:
- none: "Publiceren"
_email:
_follow:
title: "volgde jou"
@@ -486,7 +482,6 @@ _notification:
renote: "Herdelen"
quote: "Quote"
reaction: "Reacties"
- login: "Inloggen"
_actions:
reply: "Antwoord"
renote: "Herdelen"
@@ -502,3 +497,4 @@ _webhookSettings:
_moderationLogTypes:
suspend: "Opschorten"
resetPassword: "Wachtwoord terugzetten"
+
diff --git a/locales/no-NO.yml b/locales/no-NO.yml
index c5f61db745..85ccd62566 100644
--- a/locales/no-NO.yml
+++ b/locales/no-NO.yml
@@ -463,9 +463,6 @@ options: "Alternativ"
icon: "Avatar"
replies: "Svar"
renotes: "Renote"
-surrender: "Avbryt"
-_delivery:
- stop: "Suspendert"
_initialAccountSetting:
theseSettingsCanEditLater: "Du kan endre disse innstillingene senere."
_achievements:
@@ -701,7 +698,6 @@ _notification:
renote: "Renotes"
quote: "Sitater"
reaction: "Reaksjoner"
- login: "Logg inn"
_actions:
reply: "Svar"
renote: "Renote"
@@ -722,9 +718,6 @@ _deck:
direct: "Direkte"
_webhookSettings:
name: "Navn"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "E-post"
_moderationLogTypes:
suspend: "Suspender"
+
diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml
index d7afd57760..3f9fa5f5f1 100644
--- a/locales/pl-PL.yml
+++ b/locales/pl-PL.yml
@@ -20,7 +20,6 @@ noNotes: "Brak wpisów"
noNotifications: "Brak powiadomień"
instance: "Instancja"
settings: "Ustawienia"
-notificationSettings: "Powiadomienia"
basicSettings: "Podstawowe ustawienia"
otherSettings: "Pozostałe ustawienia"
openInWindow: "Otwórz w oknie"
@@ -45,20 +44,13 @@ pin: "Przypnij do profilu"
unpin: "Odepnij z profilu"
copyContent: "Skopiuj zawartość"
copyLink: "Skopiuj odnośnik"
-copyLinkRenote: "Skopiuj link renote'a"
delete: "Usuń"
deleteAndEdit: "Usuń i edytuj"
deleteAndEditConfirm: "Czy na pewno chcesz usunąć ten wpis i zedytować go? Utracisz wszystkie reakcje, udostępnienia i odpowiedzi do tego wpisu."
addToList: "Dodaj do listy"
-addToAntenna: "Dodaj do anteny"
sendMessage: "Wyślij wiadomość"
copyRSS: "Kopiuj RSS"
copyUsername: "Kopiuj nazwę użytkownika"
-copyUserId: "Kopiuj ID użytkownika"
-copyNoteId: "Kopiuj ID notatki"
-copyFileId: "Kopiuj ID pliku"
-copyFolderId: "Kopiuj ID folderu"
-copyProfileUrl: "Kopiuj URL profilu"
searchUser: "Wyszukiwanie użytkowników"
reply: "Odpowiedz"
loadMore: "Załaduj więcej"
@@ -111,8 +103,6 @@ renoted: "Udostępniono."
cantRenote: "Ten wpis nie może zostać udostępniony."
cantReRenote: "Udostępnienie nie może zostać udostępnione."
quote: "Cytuj"
-inChannelRenote: "Renote tylko na kanale"
-inChannelQuote: "Cytat tylko na kanale"
pinnedNote: "Przypięty wpis"
pinned: "Przypnij do profilu"
you: "Ty"
@@ -121,23 +111,14 @@ sensitive: "NSFW"
add: "Dodaj"
reaction: "Reakcja"
reactions: "Reakcja"
-emojiPicker: "Selektor Emoji"
-pinnedEmojisForReactionSettingDescription: "Ustaw emotikony które powinny być przypięte i od razu wyświetlone podczas reagowania."
-pinnedEmojisSettingDescription: "Ustaw emotikony które powinny być przypięte i wyświetlone podczas przeglądania selektora Emoji"
-emojiPickerDisplay: "Wyświetlanie selektora Emoji"
-overwriteFromPinnedEmojisForReaction: "Zastąp z ustawień reakcji"
-overwriteFromPinnedEmojis: "Zastąp z ogólnych ustawień"
reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć, naciśnij „+” aby dodać"
rememberNoteVisibility: "Zapamiętuj ustawienia widoczności wpisu"
attachCancel: "Usuń załącznik"
-deleteFile: "Usuń plik"
markAsSensitive: "Oznacz jako NSFW"
unmarkAsSensitive: "Cofnij NSFW"
enterFileName: "Wprowadź nazwę pliku"
mute: "Wycisz"
unmute: "Cofnij wyciszenie"
-renoteMute: "Wycisz renote'y"
-renoteUnmute: "Wyłącz wyciszenie renote'ów"
block: "Zablokuj"
unblock: "Odblokuj"
suspend: "Zawieś"
@@ -147,10 +128,8 @@ unblockConfirm: "Czy na pewno chcesz odblokować to konto?"
suspendConfirm: "Czy na pewno chcesz zawiesić to konto?"
unsuspendConfirm: "Czy na pewno chcesz cofnąć zawieszenie tego konta?"
selectList: "Wybierz listę"
-editList: "Edytuj listę"
selectChannel: "Wybierz kanał"
selectAntenna: "Wybierz Antennę"
-editAntenna: "Edytuj antenę"
selectWidget: "Wybierz widżet"
editWidgets: "Edytuj widżety"
editWidgetsExit: "Gotowe"
@@ -163,15 +142,11 @@ addEmoji: "Dodaj emoji"
settingGuide: "Proponowana konfiguracja"
cacheRemoteFiles: "Przechowuj zdalne pliki w pamięci podręcznej"
cacheRemoteFilesDescription: "Gdy ta opcja jest wyłączona, zdalne pliki są ładowane bezpośrednio ze zdalnych instancji. Wyłączenie the opcji zmniejszy użycie powierzchni dyskowej, ale zwiększy transfer, ponieważ miniaturki nie będą generowane."
-youCanCleanRemoteFilesCache: "Możesz wyczyścić cache poprzez kliknięcie przycisku 🗑️ w widoku menedżera plików."
-cacheRemoteSensitiveFiles: "Przechowuj wrażliwe zdalne pliki w pamięci podręcznej"
-cacheRemoteSensitiveFilesDescription: "Gdy ta opcja jest wyłączona, wrażliwe pliki zdalne są wczytywane bezpośrednio ze zdalnej instancji bez cacheowania."
flagAsBot: "To konto jest botem"
flagAsBotDescription: "Jeżeli ten kanał jest kontrolowany przez jakiś program, ustaw tę opcję. Jeżeli włączona, będzie działać jako flaga informująca innych programistów, aby zapobiegać nieskończonej interakcji z różnymi botami i dostosowywać wewnętrzne systemy Misskey, traktując konto jako bota."
flagAsCat: "To konto jest kotem"
flagAsCatDescription: "Przełącz tę opcję, aby konto było oznaczone jako kot."
flagShowTimelineReplies: "Pokazuj odpowiedzi na osi czasu"
-flagShowTimelineRepliesDescription: "Gdy włączone, pokazuje odpowiedzi użytkowników na notatki innych użytkowników w osi czasu."
autoAcceptFollowed: "Automatycznie przyjmuj prośby o możliwość obserwacji od użytkowników, których obserwujesz"
addAccount: "Dodaj konto"
reloadAccountsList: "Odśwież listę kont"
@@ -201,7 +176,6 @@ perHour: "co godzinę"
perDay: "co dzień"
stopActivityDelivery: "Przestań przesyłać aktywności"
blockThisInstance: "Zablokuj tę instancję"
-silenceThisInstance: "Wycisz tę instancję"
operations: "Działania"
software: "Oprogramowanie"
version: "Wersja"
@@ -221,8 +195,6 @@ clearCachedFiles: "Wyczyść pamięć podręczną"
clearCachedFilesConfirm: "Czy na pewno chcesz usunąć wszystkie zdalne pliki z pamięci podręcznej?"
blockedInstances: "Zablokowane instancje"
blockedInstancesDescription: "Wypisz nazwy hostów instancji, które powinny zostać zablokowane. Wypisane instancje nie będą mogły dłużej komunikować się z tą instancją."
-silencedInstances: "Wyciszone instancje"
-silencedInstancesDescription: "Wypisz nazwy hostów instancji, które chcesz wyciszyć. Wszystkie konta wymienionych instancji będą traktowane jako wyciszone, będą mogły jedynie wysyłać prośby o obserwację i nie będą mogły wspominać kont lokalnych, jeśli nie będą obserwowane. Nie będzie to miało wpływu na zablokowane instancje."
muteAndBlock: "Wycisz / Zablokuj"
mutedUsers: "Wyciszeni użytkownicy"
blockedUsers: "Zablokowani użytkownicy"
@@ -267,12 +239,10 @@ removed: "Pomyślnie usunięto"
removeAreYouSure: "Czy na pewno chcesz usunąć „{x}”?"
deleteAreYouSure: "Czy na pewno chcesz usunąć „{x}”?"
resetAreYouSure: "Czy na pewno chcesz zresetować?"
-areYouSure: "Na pewno?"
saved: "Zapisano"
messaging: "Wiadomości"
upload: "Wyślij"
keepOriginalUploading: "Zachowaj oryginalny obraz"
-keepOriginalUploadingDescription: "Zapisuje oryginalnie przesłany obraz w niezmienionej postaci. Jeśli ta opcja jest wyłączona, po przesłaniu zostanie wygenerowana wersja do wyświetlenia w Internecie."
fromDrive: "Z dysku"
fromUrl: "Z adresu URL"
uploadFromUrl: "Wyślij z adresu URL"
@@ -285,10 +255,7 @@ noMoreHistory: "Nie ma dalszej historii"
startMessaging: "Rozpocznij czat"
nUsersRead: "przeczytano przez {n}"
agreeTo: "Wyrażam zgodę na {0}"
-agree: "Zatwierdź"
agreeBelow: "Zaakceptuj poniżej"
-basicNotesBeforeCreateAccount: "Ważne notatki"
-termsOfService: "Warunki usługi"
start: "Rozpocznij"
home: "Strona główna"
remoteUserCaution: "Te informacje mogą nie być aktualne, ponieważ użytkownik pochodzi ze zdalnej instancji."
@@ -318,7 +285,6 @@ folderName: "Nazwa katalogu"
createFolder: "Utwórz katalog"
renameFolder: "Zmień nazwę katalogu"
deleteFolder: "Usuń ten katalog"
-folder: "Folder"
addFile: "Dodaj plik"
emptyDrive: "Dysk jest pusty"
emptyFolder: "Ten katalog jest pusty"
@@ -332,7 +298,6 @@ copyUrl: "Skopiuj adres URL"
rename: "Zmień nazwę"
avatar: "Awatar"
banner: "Baner"
-displayOfSensitiveMedia: "Wyświetlanie wrażliwej zawartości"
whenServerDisconnected: "Po utracie połączenia z serwerem"
disconnectedFromServer: "Utracono połączenie z serwerem."
reload: "Odśwież"
@@ -380,11 +345,8 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Włącz hCaptcha"
hcaptchaSiteKey: "Klucz strony"
hcaptchaSecretKey: "Tajny klucz"
-mcaptcha: "mCaptcha"
-enableMcaptcha: "Włącz mCaptcha"
mcaptchaSiteKey: "Klucz strony"
mcaptchaSecretKey: "Tajny klucz"
-mcaptchaInstanceUrl: "URL instancji mCaptcha"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Włącz reCAPTCHA"
recaptchaSiteKey: "Klucz strony"
@@ -427,19 +389,15 @@ aboutMisskey: "O Misskey"
administrator: "Admin"
token: "Token"
2fa: "Klucz 2FA "
-setupOf2fa: "Skonfiguruj dwuetapową autentykację"
totp: "Klucz aplikacji uwierzytelniającej (totp)"
totpDescription: "Opis klucza czasowego"
moderator: "Moderator"
moderation: "Moderacja"
-moderationNote: "Notka moderacyjna"
-addModerationNote: "Dodaj notkę moderacyjną"
-moderationLogs: "Logi moderacyjne"
nUsersMentioned: "{n} wspomnianych użytkowników"
securityKeyAndPasskey: "Klucz bezpieczeństwa i klucze Passkey"
securityKey: "Klucz bezpieczeństwa"
lastUsed: "Ostatnio używane"
-lastUsedAt: "Ostatnio używane: {t}"
+lastUsedAt: "Ostatnio używane w"
unregister: "Cofnij rejestrację"
passwordLessLogin: "Skonfiguruj logowanie bez użycia hasła"
passwordLessLoginDescription: "Opis logowania bez użycia hasła"
@@ -492,12 +450,9 @@ uiLanguage: "Język wyświetlania UI"
aboutX: "O {x}"
emojiStyle: "Styl emoji"
native: "Natywny"
-showNoteActionsOnlyHover: "Pokazuj akcje notatek tylko po najechaniu myszką"
-showReactionsCount: "Wyświetl liczbę reakcji na notatkę"
+disableDrawer: "Nie używaj menu w stylu szuflady"
noHistory: "Brak historii"
signinHistory: "Historia logowania"
-enableAdvancedMfm: "Włącz zaawansowane MFM"
-enableAnimatedMfm: "Włącz animowane MFM"
doing: "Przetwarzanie..."
category: "Kategoria"
tags: "Tagi"
@@ -506,8 +461,6 @@ createAccount: "Utwórz konto"
existingAccount: "Istniejące konto"
regenerate: "Wygeneruj ponownie"
fontSize: "Rozmiar czcionki"
-mediaListWithOneImageAppearance: "Wysokość list multimediów z tylko jednym obrazem"
-limitTo: "Limituj do {x}"
noFollowRequests: "Nie masz żadnych oczekujących próśb o możliwość obserwacji"
openImageInNewTab: "Otwórz obraz w nowej karcie"
dashboard: "Kokpit"
@@ -527,7 +480,6 @@ showFeaturedNotesInTimeline: "Pokazuj wyróżnione wpisy w osi czasu"
objectStorage: "Pamięć obiektowa"
useObjectStorage: "Używaj pamięci obiektowej"
objectStorageBaseUrl: "Podstawowy URL"
-objectStorageBaseUrlDesc: "Adres URL używany jako odniesienie. Podaj adres URL swojego CDN lub Proxy, gdy używasz któregokolwiek z nich.\nDla S3 użyj 'https://.s3.amazonaws.com' a dla GCS lub równej usługi użyj 'https://storage.googleapis.com/', itd."
objectStorageBucket: "Bucket"
objectStorageBucketDesc: "Podaj nazwę „wiadra” używaną przez konfigurowaną usługę."
objectStoragePrefix: "Prefiks"
@@ -540,13 +492,9 @@ objectStorageUseSSL: "Użyj SSL"
objectStorageUseSSLDesc: "Wyłącz, jeżeli nie zamierzasz używać HTTPS dla połączenia z API"
objectStorageUseProxy: "Połącz przez proxy"
objectStorageUseProxyDesc: "Wyłącz, jeżeli nie zamierzasz używać proxy dla połączenia z pamięcią blokową"
-objectStorageSetPublicRead: "Ustaw opcję \"public-read\" przy przesyłaniu"
-s3ForcePathStyleDesc: "Jeśli opcja s3ForcePathStyle jest włączona, nazwa Bucket'u musi być zawarta w ścieżce adresu URL, a nie w nazwie hosta adresu URL. Włączenie tego ustawienia może być konieczne w przypadku użycia usług takich jak self-hosted instancja Minio."
serverLogs: "Dziennik zdarzeń"
deleteAll: "Usuń wszystkie"
showFixedPostForm: "Wyświetlaj formularz tworzenia wpisu w górnej części osi czasu"
-showFixedPostFormInChannel: "Wyświetl formularz postowania w górnej części osi czasu (Kanały)"
-withRepliesByDefaultForNewlyFollowed: "Domyślnie uwzględnij odpowiedzi nowo obserwowanych użytkowników w osi czasu"
newNoteRecived: "Masz nowy wpis"
sounds: "Dźwięk"
sound: "Dźwięki"
@@ -556,8 +504,6 @@ showInPage: "Pokaż na stronie"
popout: "Popout"
volume: "Głośność"
masterVolume: "Głośność główna"
-notUseSound: "Wyłącz dźwięk"
-useSoundOnlyWhenActive: "Puszczaj dźwięki tylko, gdy Misskey jest aktywne."
details: "Szczegóły"
chooseEmoji: "Wybierz emoji"
unableToProcess: "Nie udało się dokończyć działania."
@@ -578,10 +524,6 @@ output: "Wyjście"
script: "Skrypt"
disablePagesScript: "Wyłącz AiScript na Stronach"
updateRemoteUser: "Aktualizuj zdalne dane o użytkowniku"
-unsetUserAvatar: "Usuń awatar"
-unsetUserAvatarConfirm: "Czy na pewno chcesz usunąć awatar tego użytkownika?"
-unsetUserBanner: "Usuń baner"
-unsetUserBannerConfirm: "Czy na pewno chcesz usunąć baner?"
deleteAllFiles: "Usuń wszystkie pliki"
deleteAllFilesConfirm: "Czy na pewno chcesz usunąć wszystkie pliki?"
removeAllFollowing: "Przestań obserwować"
@@ -597,7 +539,6 @@ accountDeletedDescription: "Opis konta usuniętego"
menu: "Menu"
divider: "Rozdzielacz"
addItem: "Dodaj element"
-rearrange: "Posortuj"
relays: "Przekaźniki"
addRelay: "Dodaj przekaźnik"
inboxUrl: "Adres URL skrzynki nadawczej"
@@ -632,7 +573,6 @@ medium: "Średnie"
small: "Małe"
generateAccessToken: "Generuj token dostępu"
permission: "Uprawnienia"
-adminPermission: "Uprawnienia administracyjne"
enableAll: "Włącz wszystko"
disableAll: "Wyłącz wszystko"
tokenRequested: "Przydziel dostęp do konta"
@@ -650,12 +590,9 @@ smtpPort: "Port"
smtpUser: "Nazwa użytkownika"
smtpPass: "Hasło"
emptyToDisableSmtpAuth: "Pozostaw adres e-mail i hasło puste, aby wyłączyć weryfikację SMTP"
-smtpSecure: "Użyj niejawnego SSL/TLS dla połączeń SMTP"
smtpSecureInfo: "Wyłącz, jeżeli używasz STARTTLS"
testEmail: "Przetestuj dostarczanie wiadomości e-mail"
wordMute: "Wyciszenie słowa"
-regexpError: "Błąd wyrażenia regularnego"
-regexpErrorDescription: "Wystąpił błąd w wyrażeniu regularnym w linii {line} twoich {tab} wyciszeń:"
instanceMute: "Wyciszone instancje"
userSaysSomething: "{name} powiedział(-a) coś"
makeActive: "Aktywuj"
@@ -675,21 +612,20 @@ useGlobalSettingDesc: "Jeżeli włączone, zostaną wykorzystane ustawienia powi
other: "Inne"
regenerateLoginToken: "Generuj token logowania ponownie"
regenerateLoginTokenDescription: "Regeneruje token używany wewnętrznie podczas logowania. Zazwyczaj nie jest to konieczne. Po regeneracji wszystkie urządzenia zostaną wylogowane."
-theKeywordWhenSearchingForCustomEmoji: "To jest słowo kluczowe używane podczas wyszukiwania customowych Emoji."
setMultipleBySeparatingWithSpace: "Możesz ustawić wiele, oddzielając je spacjami."
fileIdOrUrl: "ID pliku albo URL"
behavior: "Zachowanie"
sample: "Przykład"
abuseReports: "Zgłoszenia"
reportAbuse: "Zgłoś"
-reportAbuseRenote: "Zgłoś renote"
reportAbuseOf: "Zgłoś {name}"
fillAbuseReportDescription: "Wypełnij szczegóły zgłoszenia. Jeżeli dotyczy ono określonego wpisu, uwzględnij jego adres URL."
abuseReported: "Twoje zgłoszenie zostało wysłane. Dziękujemy."
-reporter: "Zgłaszający"
reporteeOrigin: "Pochodzenie zgłoszonego"
reporterOrigin: "Pochodzenie zgłaszającego"
+forwardReport: "Przekaż zgłoszenie do innej instancji"
send: "Wyślij"
+abuseMarkAsResolved: "Oznacz zgłoszenie jako rozwiązane"
openInNewTab: "Otwórz w nowej karcie"
openInSideView: "Otwórz w bocznym widoku"
defaultNavigationBehaviour: "Domyślne zachowanie nawigacji"
@@ -732,7 +668,6 @@ lockedAccountInfo: "Dopóki nie ustawisz widoczności wpisu na \"Obserwujący\",
alwaysMarkSensitive: "Oznacz domyślnie jako NSFW"
loadRawImages: "Wyświetlaj zdjęcia w załącznikach w całości zamiast miniatur"
disableShowingAnimatedImages: "Nie odtwarzaj animowanych obrazów"
-highlightSensitiveMedia: "Podkreśl wrażliwą zawartość"
verificationEmailSent: "Wiadomość weryfikacyjna została wysłana. Odwiedź uwzględniony odnośnik, aby ukończyć weryfikację."
notSet: "Nie ustawiono"
emailVerified: "Adres e-mail został potwierdzony"
@@ -743,8 +678,6 @@ contact: "Kontakt"
useSystemFont: "Używaj domyślnej czcionki systemu"
clips: "Klipy"
experimentalFeatures: "Eksperymentalne funkcje"
-experimental: "Eksperymentalne"
-thisIsExperimentalFeature: "Ta funkcja jest eksperymentalna. Jej funkcjonalność może ulec zmianie, i może ona nie funkcjonować tak, jak zamierzono."
developer: "Programista"
makeExplorable: "Pokazuj konto na stronie „Eksploruj”"
makeExplorableDescription: "Jeżeli wyłączysz tę opcję, Twoje konto nie będzie wyświetlać się w sekcji „Eksploruj”."
@@ -762,14 +695,12 @@ onlineUsersCount: "{n} osób jest online"
nUsers: "{n} użytkowników"
nNotes: "{n} wpisów"
sendErrorReports: "Wyślij raporty o błędach"
-sendErrorReportsDescription: "Gdy włączone, jeśli wystąpi problem, szczegółowe informacje o błędach będą udostępniane Misskey, pomagając ulepszyć jakość Misskey.\nBędzie to zawierało informacje takie jak wersja twojego systemu operacyjnego, jakiej przeglądarki używasz, twoja aktywność w Misskey, itd."
myTheme: "Mój motyw"
backgroundColor: "Tło"
accentColor: "Akcent"
textColor: "Tekst"
saveAs: "Zapisz jako…"
advanced: "Zaawansowane"
-advancedSettings: "Zaawansowane ustawienia"
value: "Wartość"
createdAt: "Utworzono"
updatedAt: "Zaktualizowano"
@@ -829,14 +760,12 @@ noMaintainerInformationWarning: "Informacje o administratorze nie są skonfiguro
noBotProtectionWarning: "Zabezpieczenie przed botami nie jest skonfigurowane."
configure: "Skonfiguruj"
postToGallery: "Opublikuj w galerii"
-postToHashtag: "Postuj do tego hashtagu"
gallery: "Galeria"
recentPosts: "Ostatnie wpisy"
popularPosts: "Popularne wpisy"
shareWithNote: "Udostępnij z wpisem"
ads: "Reklamy"
expiration: "Ankieta kończy się"
-startingperiod: "Początek"
memo: "Notatki"
priority: "Priorytet"
high: "Wysoki"
@@ -863,19 +792,13 @@ translatedFrom: "Przetłumaczone z {x}"
accountDeletionInProgress: "Trwa usuwanie konta"
usernameInfo: "Nazwa, która identyfikuje Twoje konto spośród innych na tym serwerze. Możesz użyć alfabetu (a~z, A~Z), cyfr (0~9) lub podkreślników (_). Nazwy użytkownika nie mogą być później zmieniane."
aiChanMode: "Tryb Ai"
-devMode: "Tryb programisty"
keepCw: "Zostaw ostrzeżenia o zawartości"
pubSub: "Konta Pub/Sub"
-lastCommunication: "Ostatnia komunikacja"
resolved: "Rozwiązane"
unresolved: "Nierozwiązane"
breakFollow: "Usuń obserwującego"
-breakFollowConfirm: "Czy na pewno usunąć tego obserwującego?"
itsOn: "Włączone"
itsOff: "Wyłączone"
-on: "Włączone"
-off: "Wyłączone"
-emailRequiredForSignup: "Wymagaj adresu e-mail do rejestracji"
unread: "Nieodczytane"
filter: "Filtr"
controlPanel: "Panel sterowania"
@@ -885,8 +808,6 @@ makeReactionsPublicDescription: "To spowoduje, że lista wszystkich Twoich dotyc
classic: "Klasyczny"
muteThread: "Wycisz wątek"
unmuteThread: "Wyłącz wyciszenie wątku"
-followingVisibility: "Widoczność obserwacji"
-followersVisibility: "Widoczność obserwujących"
continueThread: "Pokaż kontynuację wątku"
deleteAccountConfirm: "Spowoduje to nieodwracalne usunięcie Twojego konta. Kontynuować?"
incorrectPassword: "Nieprawidłowe hasło."
@@ -899,14 +820,9 @@ overridedDeviceKind: "Typ urządzenia"
smartphone: "Smartfon"
tablet: "Tablet"
auto: "Automatycznie"
-themeColor: "Motyw kolorystyczny"
size: "Rozmiar"
numberOfColumn: "Liczba kolumn"
searchByGoogle: "Szukaj"
-instanceDefaultLightTheme: "Domyślny motyw dla trybu jasnego"
-instanceDefaultDarkTheme: "Domyślny motyw dla trybu ciemnego"
-instanceDefaultThemeDescription: "Opis domyślnego motywu instancji"
-mutePeriod: "Okres wyciszenia"
period: "Ankieta kończy się"
indefinitely: "Nigdy"
tenMinutes: "10 minut"
@@ -915,50 +831,29 @@ oneDay: "1 dzień"
oneWeek: "1 tydzień"
oneMonth: "jeden miesiąc"
failedToFetchAccountInformation: "Nie udało się uzyskać informacji o koncie"
-rateLimitExceeded: "Limit szybkości przekroczony"
-cropImage: "Przytnij obraz"
-cropImageAsk: "Czy chcesz przyciąć obrazek?"
-cropYes: "Tak, przytnij"
-cropNo: "Nie chce przycinać"
file: "Pliki"
-recentNHours: "W ciągu ostatnich {n} godzin"
-recentNDays: "W ciągu ostatnich {n} dni"
-noEmailServerWarning: "Serwer Email nie jest skonfigurowany"
recommended: "Zalecane"
check: "Zweryfikuj"
-driveCapOverrideLabel: "Zmień limit pojemności dysku użytkownika"
-requireAdminForView: "Aby to zobaczyć, musisz być administratorem"
-isSystemAccount: "To jest konto stworzone i zarządzane przez system"
-typeToConfirm: "Wprowadź {x}, aby potwierdzić"
deleteAccount: "Usuń konto"
document: "Dokumentacja"
numberOfPageCache: "Ilość stron w cache"
-numberOfPageCacheDescription: "Zwiększenie tej liczby polepszy wygodę, ale spowoduje większe obciążenie jako użycie pamięci na urządzeniu użytkownika."
logoutConfirm: "Czy na pewno chcesz się wylogować?"
lastActiveDate: "Ostatnio użyte w"
statusbar: "Pasek stanu"
pleaseSelect: "Wybierz opcję"
reverse: "Odwróć"
colored: "Kolorowe"
-refreshInterval: "Okres aktualizacji"
label: "Etykieta"
type: "Typ"
speed: "Prędkość"
-slow: "Wolny"
-fast: "Szybki"
-sensitiveMediaDetection: "Detekcja wrażliwej zawartości"
localOnly: "Lokalne tylko"
-remoteOnly: "Tylko zdalne instancje"
failedToUpload: "Przesyłanie nie powiodło się"
cannotUploadBecauseInappropriate: "Nie można przesłać tego pliku, ponieważ jego części zostały wykryte jako potencjalnie nieodpowiednie."
cannotUploadBecauseNoFreeSpace: "Przesyłanie nie powiodło się z powodu braku miejsca na dysku."
-cannotUploadBecauseExceedsFileSizeLimit: "Nie można przesłać pliku, ponieważ wykracza on poza limit wielkości pliku."
beta: "Beta"
enableAutoSensitive: "Automatyczne oznaczanie NSFW"
enableAutoSensitiveDescription: "Umożliwia automatyczne wykrywanie i oznaczanie zawartości NSFW za pomocą uczenia maszynowego. Nawet jeśli ta opcja jest wyłączona, może być włączona w całej instancji."
-activeEmailValidationDescription: "Włącza bardziej restrykcyjną walidację adresów e-mail, co obejmuje sprawdzanie adresów jednorazowych i czy komunikacja z tym adresem jest możliwa. Gdy wyłączone, tylko format adresu e-mail jest sprawdzany."
navbar: "Pasek nawigacyjny"
-shuffle: "Mieszaj"
account: "Konta"
move: "Przenieś"
pushNotification: "Powiadomienia"
@@ -968,74 +863,22 @@ pushNotificationAlreadySubscribed: "Powiadomienia push są włączone"
pushNotificationNotSupported: "Przeglądarka lub instancja nie obsługuje powiadomień push"
sendPushNotificationReadMessage: "Usuń powiadomienia push po przeczytaniu powiadomień i wiadomości."
sendPushNotificationReadMessageCaption: "Chwilowo pojawi się powiadomienie \"{emptyPushNotificationMessage}\". Może wzrosnąć zużycie baterii urządzenia."
-windowMaximize: "Maksymalizuj"
-windowMinimize: "Minimalizuj"
-windowRestore: "Przywróć"
-caption: "Legenda"
loggedInAsBot: "Jesteś obecnie zalogowany/a jako bot"
-tools: "Narzędzia"
-cannotLoad: "Nie można wczytać"
-numberOfProfileView: "Wyświetlenia profilu"
like: "Polub"
-unlike: "Usuń polubienie"
-numberOfLikes: "Liczba polubień"
show: "Wyświetlanie"
-neverShow: "Nie pokazuj ponownie"
-remindMeLater: "Przypomnij później"
-didYouLikeMisskey: "Czy Misskey się tobie spodobało?"
-pleaseDonate: "{host} używa darmowego oprogramowania — Misskey. Bylibyśmy bardzo wdzięczni za datki, które pozwolą na kontynuację rozwoju Misskey!"
-correspondingSourceIsAvailable: "Odpowiedni kod źródłowy jest dostępny pod {anchor}."
-roles: "Role"
-role: "Rola"
-noRole: "Rola nie znaleziona"
-normalUser: "Normalny użytkownik"
-undefined: "Niezdefiniowane"
-assign: "Przydziel"
-unassign: "Cofnij przydzielenie"
color: "Kolor"
-manageCustomEmojis: "Zarządzaj niestandardowymi Emoji"
-manageAvatarDecorations: "Zarządzaj dekoracjami awatara"
-invalidParamError: "Błąd parametrów"
-permissionDeniedError: "Odrzucono operacje"
-permissionDeniedErrorDescription: "Konto nie posiada uprawnień"
-preset: "Konfiguracja"
-selectFromPresets: "Wybierz konfiguracje"
-achievements: "Osiągnięcia"
-thisPostMayBeAnnoyingCancel: "Odrzuć"
-internalServerError: "Wewnętrzny błąd serwera"
-internalServerErrorDescription: "Niespodziewany błąd po stronie serwera"
-copyErrorInfo: "Kopiuj informacje o błędzie"
-joinThisServer: "Dołącz do chaty"
-disableFederationOk: "Wyłącz federacje"
-invitationRequiredToRegister: "Ten serwer wymaga zaproszenia. Tylko osoby z zaproszeniem mogą się zarejestrować"
-emailNotSupported: "Wysyłanie wiadomości E-mail nie jest obsługiwane na tym serwerze"
-postToTheChannel: "Publikuj na kanale"
youFollowing: "Śledzeni"
icon: "Awatar"
-replies: "Odpowiedz"
-renotes: "Udostępnij"
+replies: "Odpowiedzi"
+renotes: "Udostępnień"
sourceCode: "Kod źródłowy"
flip: "Odwróć"
-lastNDays: "W ciągu ostatnich {n} dni"
-surrender: "Odrzuć"
-gameRetry: "Spróbuj ponownie"
-_delivery:
- stop: "Zawieszono"
- _type:
- none: "Publikowanie"
-_bubbleGame:
- _score:
- score: "Wynik"
_role:
- assignTarget: "Przydziel"
priority: "Priorytet"
_priority:
low: "Niski"
middle: "Średnie"
high: "Wysoki"
- _options:
- canManageCustomEmojis: "Zarządzaj niestandardowymi Emoji"
- canManageAvatarDecorations: "Zarządzaj dekoracjami awatara"
_sensitiveMediaDetection:
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy obciążenie serwera."
setSensitiveFlagAutomatically: "Oznacz jako NSFW"
@@ -1205,6 +1048,7 @@ _theme:
buttonBg: "Tło przycisku"
buttonHoverBg: "Tło przycisku (po najechaniu)"
inputBorder: "Obramowanie pola wejścia"
+ listItemHoverBg: "Tło elementu listy (po najechaniu)"
driveFolderBg: "Tło folderu na dysku"
wallpaperOverlay: "Nakładka tapety"
badge: "Odznaka"
@@ -1216,6 +1060,8 @@ _sfx:
note: "Wpisy"
noteMy: "Mój wpis"
notification: "Powiadomienia"
+ antenna: "Anteny"
+ channel: "Powiadomienia kanału"
_ago:
future: "W przyszłości"
justNow: "Przed chwilą"
@@ -1505,7 +1351,6 @@ _notification:
reaction: "Reakcja"
receiveFollowRequest: "Otrzymano prośbę o możliwość obserwacji"
followRequestAccepted: "Przyjęto prośbę o możliwość obserwacji"
- login: "Zaloguj się"
app: "Powiadomienia z aplikacji"
_actions:
followBack: "zaobserwował cię z powrotem"
@@ -1540,6 +1385,7 @@ _webhookSettings:
createWebhook: "Stwórz Webhook"
name: "Nazwa"
secret: "Sekret"
+ events: "Uruchomienie Webhooka"
active: "Właczono"
_events:
follow: "Po zaobserwowaniu użytkownika"
@@ -1549,12 +1395,9 @@ _webhookSettings:
renote: "Po udostępnieniu wpisu"
reaction: "Po otrzymaniu reakcji"
mention: "Po zostaniu wspomnianym"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Adres e-mail"
_moderationLogTypes:
suspend: "Zawieś"
resetPassword: "Zresetuj hasło"
_reversi:
total: "Łącznie"
+
diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml
index 9039fd2141..795f947c74 100644
--- a/locales/pt-PT.yml
+++ b/locales/pt-PT.yml
@@ -2,14 +2,14 @@
_lang_: "Português"
headlineMisskey: "Uma rede ligada por notas"
introMisskey: "Bem-vindo! O Misskey é um serviço de microblog descentralizado de código aberto.\nCrie \"notas\" para compartilhar o que está acontecendo agora ou para se expressar com todos à sua volta 📡\nVocê também pode adicionar rapidamente reações às notas de outras pessoas usando a função \"Reações\" 👍\nVamos explorar um novo mundo 🚀"
-poweredByMisskeyDescription: "{name} é uma instância da plataforma de código aberto Misskey ."
+poweredByMisskeyDescription: "{name} é um dos servidores da plataforma de código aberto Misskey ."
monthAndDay: "{day}/{month}"
search: "Pesquisar"
notifications: "Notificações"
username: "Nome de usuário"
password: "Senha"
forgotPassword: "Esqueci-me da senha"
-fetchingAsApObject: "Buscando no Fediverso..."
+fetchingAsApObject: "Buscando no Fediverso"
ok: "OK"
gotIt: "Entendi"
cancel: "Cancelar"
@@ -60,7 +60,6 @@ copyFileId: "Copiar o ID do arquivo"
copyFolderId: "Copiar o ID da pasta"
copyProfileUrl: "Copiar a URL do perfil"
searchUser: "Pesquisar usuário"
-searchThisUsersNotes: "Pesquisar as notas desse usuário"
reply: "Responder"
loadMore: "Carregar mais"
showMore: "Ver mais"
@@ -82,7 +81,7 @@ exportRequested: "A sua solicitação de exportação foi enviada. Isso pode lev
importRequested: "A sua solicitação de importação foi enviada. Isso pode levar algum tempo."
lists: "Listas"
noLists: "Não possui nenhuma lista"
-note: "Publicar"
+note: "Post"
notes: "Posts"
following: "Seguindo"
followers: "Seguidores"
@@ -100,7 +99,7 @@ enterListName: "Insira um nome para a lista"
privacy: "Privacidade"
makeFollowManuallyApprove: "Pedidos de seguidores precisam ser aprovados"
defaultNoteVisibility: "Visibilidade padrão"
-follow: "Seguir"
+follow: "Seguindo"
followRequest: "Enviar pedido de seguidor"
followRequests: "Pedidos de seguidor"
unfollow: "Deixar de seguir"
@@ -109,14 +108,11 @@ enterEmoji: "Inserir emoji"
renote: "Repostar"
unrenote: "Remover repostagem"
renoted: "Repostado"
-renotedToX: "Repostar em {name}."
cantRenote: "Não é possível repostar esta postagem"
cantReRenote: "Não pode repostar este repost"
quote: "Citar"
inChannelRenote: "Repostar no canal"
inChannelQuote: "Citar no canal"
-renoteToChannel: "Repostar em canal"
-renoteToOtherChannel: "Repostar em outro canal"
pinnedNote: "Nota fixada"
pinned: "Fixar no perfil"
you: "Você"
@@ -125,16 +121,9 @@ sensitive: "Conteúdo sensível"
add: "Adicionar"
reaction: "Reações"
reactions: "Reações"
-emojiPicker: "Seleção de emoji"
-pinnedEmojisForReactionSettingDescription: "Selecionar os emojis que serão fixados e exibidos ao reagir."
-pinnedEmojisSettingDescription: "Selecionar os emojis que serão fixos e exibidos na seleção de emoji."
-emojiPickerDisplay: "Janela de seleção de emoji"
-overwriteFromPinnedEmojisForReaction: "Sobrescrever as opções de reação"
-overwriteFromPinnedEmojis: "Sobrescrever as opções gerais"
reactionSettingDescription2: "Arraste para reordenar, clique para excluir, pressione + para adicionar."
rememberNoteVisibility: "Lembrar das configurações de visibilidade de notas"
attachCancel: "Remover anexo"
-deleteFile: "Excluir arquivo"
markAsSensitive: "Marcar como sensível"
unmarkAsSensitive: "Desmarcar como sensível"
enterFileName: "Digite o nome do arquivo"
@@ -155,7 +144,6 @@ editList: "Editar lista"
selectChannel: "Selecionar canal"
selectAntenna: "Selecione uma antena"
editAntenna: "Editar antena"
-createAntenna: "Criar uma antena"
selectWidget: "Selecione um widget"
editWidgets: "Editar widgets"
editWidgetsExit: "Pronto"
@@ -182,21 +170,16 @@ addAccount: "Adicionar Conta"
reloadAccountsList: "Recarregar lista de contas"
loginFailed: "Falha ao logar"
showOnRemote: "Exibir remotamente"
-continueOnRemote: ""
-chooseServerOnMisskeyHub: "Escolher um servidor da Misskey Hub"
-specifyServerHost: "Especificar uma instância diretamente"
-inputHostName: "Insira o domínio"
general: "Geral"
wallpaper: "Papel de parede"
setWallpaper: "Definir papel de parede"
removeWallpaper: "Remover papel de parede"
searchWith: "Buscar: {q}"
youHaveNoLists: "Não tem nenhuma lista"
-followConfirm: "Tem certeza que quer seguir {name}?"
+followConfirm: "Tem certeza que quer deixar de seguir {name}?"
proxyAccount: "Conta proxy"
proxyAccountDescription: "Uma conta de proxy é uma conta que assume o acompanhamento remoto de um usuário sob certas condições específicas. Por exemplo, quando um usuário inclui um usuário remoto em uma lista, mas ninguém na lista está seguindo o usuário remoto, a atividade não é entregue ao servidor. Nesse caso, a conta de proxy entra em ação para seguir o usuário remoto em vez disso."
host: "Host"
-selectSelf: "Escolher manualmente"
selectUser: "Selecionar usuário"
recipient: "Destinatário"
annotation: "Anotação"
@@ -211,8 +194,6 @@ perHour: "Por Hora"
perDay: "Por dia"
stopActivityDelivery: "Parar a entrega de atividades"
blockThisInstance: "Bloquear esta instância"
-silenceThisInstance: "Silenciar essa instância"
-mediaSilenceThisInstance: "Silenciar a mídia dessa instância"
operations: "Operações"
software: "Software"
version: "Versão"
@@ -232,10 +213,6 @@ clearCachedFiles: "Limpar o cache"
clearCachedFilesConfirm: "Deseja excluir todos os arquivos remotos em cache?"
blockedInstances: "Instância bloqueada"
blockedInstancesDescription: "Configure os hosts dos servidores que deseja bloquear, separando-os por quebras de linha. Os servidores bloqueados não poderão interagir com este servidor, incluindo os subdomínios."
-silencedInstances: "Instâncias silenciadas"
-silencedInstancesDescription: "Liste o nome de hospedagem dos servidores que você deseja silenciar, separados por linha. Todas as contas desses servidores serão silenciada e poderão enviar solicitações para seguir, mas não poderão mencionar usuários locais sem segui-los. Isso não afetará servidores bloqueados."
-mediaSilencedInstances: "Instâncias com mídia silenciadas"
-mediaSilencedInstancesDescription: "Liste o nome de hospedagem dos servidores cuja mídia você deseja silenciar, separados por linha. Todas as contas desses servidores serão consideradas sensíveis e não poderão utilizar emojis personalizados. Isso não afetará servidores bloqueados."
muteAndBlock: "Silenciar e bloquear"
mutedUsers: "Usuários silenciados"
blockedUsers: "Usuários bloqueados"
@@ -272,7 +249,7 @@ more: "Mais!"
featured: "Destaques"
usernameOrUserId: "Nome de usuário ou ID do usuário"
noSuchUser: "Usuário não encontrado"
-lookup: "Consultar"
+lookup: "Buscando"
announcements: "Avisos"
imageUrl: "URL da imagem"
remove: "Remover"
@@ -280,7 +257,6 @@ removed: "Removido"
removeAreYouSure: "Deseja excluir \"{x}\"?"
deleteAreYouSure: "Deseja excluir \"{x}\"?"
resetAreYouSure: "Deseja reiniciar?"
-areYouSure: "Tem certeza?"
saved: "Salvo"
messaging: "Chat"
upload: "Fazer upload"
@@ -296,7 +272,7 @@ explore: "Explorar"
messageRead: "Lida"
noMoreHistory: "Não existe histórico anterior"
startMessaging: "Iniciar conversação"
-nUsersRead: "{n} pessoas leram"
+nUsersRead: "{n} Pessoas leem"
agreeTo: "Eu concordo com {0}"
agree: "Concordar"
agreeBelow: "Eu concordo com o seguinte"
@@ -312,7 +288,7 @@ birthday: "Aniversário"
yearsOld: "{age} anos"
registeredDate: "Data de registro"
location: "Localização"
-theme: "Tema"
+theme: "tema"
themeForLightMode: "Temas usados no modo de luz"
themeForDarkMode: "Temas usados no modo escuro"
light: "Claro"
@@ -326,13 +302,11 @@ selectFile: "Selecione os arquivos"
selectFiles: "Selecione os arquivos"
selectFolder: "Selecionar uma pasta"
selectFolders: "Selecionar uma pasta"
-fileNotSelected: "Nenhuma pasta selecionada"
renameFile: "Renomear ficheiro"
folderName: "Nome da pasta"
createFolder: "Criar pasta"
renameFolder: "Renomear Pasta"
deleteFolder: "Excluir pasta"
-folder: "Pasta"
addFile: "Adicionar arquivo"
emptyDrive: "O drive está vazio"
emptyFolder: "A pasta está vazia"
@@ -394,11 +368,8 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Ativar hCaptcha"
hcaptchaSiteKey: "Chave do sítio ‘web’"
hcaptchaSecretKey: "Chave secreta"
-mcaptcha: "mCaptcha"
-enableMcaptcha: "Habilitar mCaptcha"
mcaptchaSiteKey: "Chave do sítio ‘web’"
mcaptchaSecretKey: "Chave secreta"
-mcaptchaInstanceUrl: "URL do servidor mCaptcha"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Habilitar reCAPTCHA"
recaptchaSiteKey: "Chave do sítio ‘web’"
@@ -414,7 +385,6 @@ name: "Nome"
antennaSource: "Origem de entrada"
antennaKeywords: "Palavras-chave recebidas"
antennaExcludeKeywords: "Palavras-chave negativas"
-antennaExcludeBots: "Ignorar contas de bot"
antennaKeywordsDescription: "Se você separá-lo com um espaço, será uma especificação AND, e se você separá-lo com uma quebra de linha, será uma especificação OR."
notifyAntenna: "Notificar novas notas"
withFileAntenna: "Apenas notas com arquivos anexados"
@@ -447,9 +417,6 @@ totp: "Aplicativo Autenticador"
totpDescription: "Digite a senha de uso único informado pelo aplicativo autenticador"
moderator: "Moderador"
moderation: "Moderação"
-moderationNote: "Nota de moderação"
-addModerationNote: "Adicionar nota de moderação"
-moderationLogs: "Logs de moderação"
nUsersMentioned: "Postado por {n} pessoas"
securityKeyAndPasskey: "Chave de segurança / Chave de acesso"
securityKey: "Chave de segurança"
@@ -482,12 +449,10 @@ retype: "Digite novamente"
noteOf: "Publicação de {user}"
quoteAttached: "Com citação"
quoteQuestion: "Anexar como citação?"
-attachAsFileQuestion: "O texto na área de transferência é muito longo. Você gostaria de anexá-lo como um arquivo de texto?"
noMessagesYet: "Sem conversas até o momento"
newMessageExists: "Há uma nova mensagem"
onlyOneFileCanBeAttached: "Apenas um arquivo pode ser anexado a uma mensagem"
signinRequired: "É necessário se inscrever ou fazer login antes de continuar"
-signinOrContinueOnRemote: "Para continuar, você precisa mover o seu servidor ou entrar/cadastrar-se nesse servidor."
invitations: "Convidar"
invitationCode: "Código de convite"
checking: "Verificando..."
@@ -509,8 +474,8 @@ uiLanguage: "Idioma de exibição da interface "
aboutX: "Sobre {x}"
emojiStyle: "Estilo de emojis"
native: "Nativo"
+disableDrawer: "Não mostrar o menu em formato de gaveta"
showNoteActionsOnlyHover: "Exibir as ações da nota somente ao passar o cursor sobre ela"
-showReactionsCount: "Ver o número de reações nas notas"
noHistory: "Ainda não há histórico"
signinHistory: "Histórico de acesso"
enableAdvancedMfm: "Habilitar MFM avançado"
@@ -559,11 +524,10 @@ objectStorageUseProxy: "Usar proxy"
objectStorageUseProxyDesc: "Se você não usa proxy para conexão de API, desative-o."
objectStorageSetPublicRead: "Definir 'public-read' ao fazer o upload"
s3ForcePathStyleDesc: "Ao habilitar s3ForcePathStyle, o nome do bucket é especificado como parte do caminho em vez de ser o nome do host na URL. Isso pode ser necessário ao usar serviços auto-hospedados como o Minio."
-serverLogs: "Logs do servidor"
+serverLogs: "Registro do servidor"
deleteAll: "Excluir tudo"
showFixedPostForm: "Exibir o formulário de postagem na parte superior da linha do tempo"
showFixedPostFormInChannel: "Exibir o campo de postagem na parte superior da linha do tempo (canais)"
-withRepliesByDefaultForNewlyFollowed: "Incluir respostas por usuários recém-seguidos na linha do tempo por padrão"
newNoteRecived: "Nova nota recebida"
sounds: "Sons"
sound: "Sons"
@@ -573,8 +537,6 @@ showInPage: "Ver na página"
popout: "Sair"
volume: "Volume"
masterVolume: "volume principal"
-notUseSound: "Desabilitar som"
-useSoundOnlyWhenActive: "Apenas reproduzir sons quando Misskey estiver aberto."
details: "Detalhes"
chooseEmoji: "Selecione um emoji"
unableToProcess: "Não é possível concluir a operação"
@@ -595,10 +557,6 @@ output: "Resultado"
script: "Script"
disablePagesScript: "Desabilitar scripts nas páginas"
updateRemoteUser: "Atualizar informações do usuário remoto"
-unsetUserAvatar: "Remover avatar"
-unsetUserAvatarConfirm: "Você tem certeza de que deseja remover o avatar?"
-unsetUserBanner: "Remover banner"
-unsetUserBannerConfirm: "Você tem certeza de que deseja remover o banner?"
deleteAllFiles: "Excluir todos os arquivos"
deleteAllFilesConfirm: "Deseja excluir todos os arquivos?"
removeAllFollowing: "Deseja remover todos os seguidores?"
@@ -649,7 +607,6 @@ medium: "Médio"
small: "Pequeno"
generateAccessToken: "Gerar token de acesso"
permission: "Permissões"
-adminPermission: "Permissões de administrador"
enableAll: "Habilitar tudo"
disableAll: "Desabilitar tudo"
tokenRequested: "Autorização de acesso à conta"
@@ -671,7 +628,6 @@ smtpSecure: "Use SSL/TLS implícito para conexões SMTP"
smtpSecureInfo: "Desative esta opção ao utilizar STARTTLS."
testEmail: "Testar envio de e-mail"
wordMute: "Silenciar palavras"
-hardWordMute: "SIlenciamento pesado de palavra"
regexpError: "Erro na expressão regular"
regexpErrorDescription: "Ocorreu um erro na expressão regular na linha {line} da palavra mutada {tab}:"
instanceMute: "Instâncias silenciadas"
@@ -693,13 +649,12 @@ useGlobalSettingDesc: "Ao ativar, serão utilizadas as configurações de notifi
other: "Outros"
regenerateLoginToken: "Gerar novo token de login"
regenerateLoginTokenDescription: "Gera novamente o token interno usado para o login. Normalmente, isso não é necessário. Ao regenerar, você será desconectado de todos os dispositivos."
-theKeywordWhenSearchingForCustomEmoji: "Essa é a palavra-chave ao pesquisar por emojis personalizados"
setMultipleBySeparatingWithSpace: "Você pode configurar vários itens separando-os por espaço."
fileIdOrUrl: "ID do arquivo ou URL"
behavior: "Comportamento"
sample: "Exemplo"
abuseReports: "Denúncias"
-reportAbuse: "Denunciar"
+reportAbuse: "Denúncias"
reportAbuseRenote: "Reportar repostagem"
reportAbuseOf: "Denunciar {name}"
fillAbuseReportDescription: "Por favor, forneça detalhes sobre o motivo da denúncia. Se houver uma nota específica envolvida, inclua também a URL dela."
@@ -707,7 +662,10 @@ abuseReported: "Denúncia enviada. Obrigado por sua ajuda."
reporter: "Denunciante"
reporteeOrigin: "Origem da denúncia"
reporterOrigin: "Origem do denunciante"
+forwardReport: "Encaminhar a denúncia para o servidor remoto"
+forwardReportIsAnonymous: "No servidor remoto, suas informações não serão visíveis, e você será apresentado como uma conta do sistema anônima."
send: "Enviar"
+abuseMarkAsResolved: "Marcar denúncia como resolvida"
openInNewTab: "Abrir em nova aba"
openInSideView: "Abrir em visão lateral"
defaultNavigationBehaviour: "Navegação padrão"
@@ -750,7 +708,6 @@ lockedAccountInfo: "Mesmo que você defina a aprovação para seguir, a menos qu
alwaysMarkSensitive: "Marcar como sensível por padrão"
loadRawImages: "Exibir as imagens originais ao invés de miniaturas"
disableShowingAnimatedImages: "Não reproduzir imagens animadas"
-highlightSensitiveMedia: "Destacar mídia sensível"
verificationEmailSent: "Um e-mail de confirmação foi enviado. Siga o link no e-mail para concluir a verificação."
notSet: "Não definido"
emailVerified: "O endereço de e-mail foi confirmado"
@@ -764,7 +721,7 @@ experimentalFeatures: "Funcionalidades Experimentais"
experimental: "Experimental"
thisIsExperimentalFeature: "Este é um recurso experimental. As funções podem mudar ou pode não funcionar corretamente."
developer: "Programador"
-makeExplorable: "Deixe a sua conta encontrável em \"Explorar\"."
+makeExplorable: "Deixe a sua conta mais fácil de encontrar."
makeExplorableDescription: "Se você desativá-lo, outros usuários não poderão encontrar a sua conta na aba Descoberta."
showGapBetweenNotesInTimeline: "Mostrar um espaço entre as notas na linha de tempo"
duplicate: "Duplicar"
@@ -776,9 +733,9 @@ reloadToApplySetting: "As configurações serão refletidas após recarregar a p
needReloadToApply: "É necessário recarregar a página para refletir as alterações."
showTitlebar: "Exibir barra de título"
clearCache: "Limpar o cache"
-onlineUsersCount: "{n} Pessoas Online"
-nUsers: "{n} Usuários"
-nNotes: "{n} Notas"
+onlineUsersCount: "Pessoas Online"
+nUsers: "Usuários"
+nNotes: "Notas"
sendErrorReports: "Enviar relatórios de erro"
sendErrorReportsDescription: "Ao ativar essa opção, informações detalhadas de erro serão compartilhadas com o Misskey em caso de problemas, o que pode ajudar a melhorar a qualidade do software. As informações de erro podem incluir a versão do sistema operacional, o tipo de navegador e o sua atividade no Misskey."
myTheme: "Meu tema"
@@ -810,7 +767,7 @@ emailNotification: "Notificações por e-mail"
publish: "Publicar"
inChannelSearch: "Pesquisar no canal"
useReactionPickerForContextMenu: "Clique com o botão direito do mouse para abrir o seletor de reações."
-typingUsers: "{users} pessoas digitando"
+typingUsers: "digitando"
jumpToSpecifiedDate: "Pular para uma data específica"
showingPastTimeline: "Visualizar linha de tempo anterior"
clear: "Limpar"
@@ -839,12 +796,11 @@ switchAccount: "Trocar conta"
enabled: "Ativado"
disabled: "Desativado"
quickAction: "Ações rápidas"
-user: "Usuário"
+user: "Usuários"
administration: "Administrar"
accounts: "Contas"
switch: "Trocar"
noMaintainerInformationWarning: "A informação de administrador não foi configurada."
-noInquiryUrlWarning: "URL de consulta não está definida"
noBotProtectionWarning: "A proteção contra bots não foi configurada."
configure: "Configurar"
postToGallery: "Criar publicação em galeria"
@@ -878,7 +834,7 @@ learnMore: "Saiba mais"
misskeyUpdated: "Misskey foi atualizado!"
whatIsNew: "Ver atualizações"
translate: "Traduzir"
-translatedFrom: "Traduzido de {x}"
+translatedFrom: "Traduzido de"
accountDeletionInProgress: "Encerramento de conta em andamento"
usernameInfo: "O nome para identificar exclusivamente a sua conta no servidor. Pode conter letras (az, AZ), números (0~9) e sublinhados (_). O nome de usuário não pode ser alterado posteriormente."
aiChanMode: "Modo AI-chan"
@@ -904,8 +860,6 @@ makeReactionsPublicDescription: "Isto vai deixar o histórico de todas as suas r
classic: "Clássico"
muteThread: "Silenciar esta conversa"
unmuteThread: "Desativar silêncio desta conversa"
-followingVisibility: "Visibilidade dos usuários seguidos"
-followersVisibility: "Visibilidade dos seguidores"
continueThread: "Ver mais desta conversa"
deleteAccountConfirm: "Deseja realmente excluir a conta?"
incorrectPassword: "Senha inválida."
@@ -971,33 +925,21 @@ fast: "Rápido"
sensitiveMediaDetection: "Detecção de conteúdo sensível"
localOnly: "Apenas local"
remoteOnly: "Apenas remoto"
-failedToUpload: "Falha ao enviar"
-cannotUploadBecauseInappropriate: "Esse arquivo não pôde ser enviado porque partes dele foram detectadas como potencialmente inapropriadas."
-cannotUploadBecauseNoFreeSpace: "Envio falhou devido à falta de capacidade no Drive."
cannotUploadBecauseExceedsFileSizeLimit: "Não é possível realizar o upload deste arquivo porque ele excede o tamanho máximo permitido."
beta: "Beta"
enableAutoSensitive: "Marcar automaticamente como conteúdo sensível"
enableAutoSensitiveDescription: "Quando disponível, a marcação de mídia sensível será automaticamente atribuído ao conteúdo de mídia usando aprendizado de máquina. Mesmo que você desative essa função, em alguns servidores, isso pode ser configurado automaticamente."
activeEmailValidationDescription: "A validação do endereço de e-mail do usuário será realizada de forma mais rigorosa, considerando se é um endereço descartável ou se é possível realizar comunicação efetiva. Se desativado, apenas a validade do formato do endereço será verificada como uma sequência de caracteres."
-navbar: "Barra de navegação"
shuffle: "Aleatório"
account: "Contas"
move: "Mover"
pushNotification: "Notificações Push"
subscribePushNotification: "Ativar notificações push"
unsubscribePushNotification: "Desativar notificações push"
-pushNotificationAlreadySubscribed: "Notificações push já estão habilitadas"
-pushNotificationNotSupported: "Seu navegador ou instância não tem suporte às notificações push"
-sendPushNotificationReadMessage: "Apagar notificações push quando elas foram lidas"
-sendPushNotificationReadMessageCaption: "Pode aumentar o consumo de energia do dispositivo."
-windowMaximize: "Maximizar"
windowMinimize: "Minimizar"
windowRestore: "Restaurar"
caption: "legenda"
-loggedInAsBot: "Atualmente conectado como bot"
tools: "Ferramentas"
-cannotLoad: "Não foi possível carregar"
-numberOfProfileView: "Visualizações do perfil"
like: "Curtir"
unlike: "Remover curtida"
numberOfLikes: "Número de curtidas"
@@ -1006,7 +948,6 @@ neverShow: "Não exibir novamente"
remindMeLater: "Lembrar mais tarde"
didYouLikeMisskey: "Você gostou do Misskey?"
pleaseDonate: "O Misskey é um software gratuito utilizado por {host}. Para que possamos continuar o desenvolvimento, pedimos que considerem fazer doações. A sua contribuição é muito importante!"
-correspondingSourceIsAvailable: "O código-fonte correspondente está disponível em {anchor}"
roles: "Cargos"
role: "Cargo"
noRole: "Nenhum cargo"
@@ -1016,7 +957,6 @@ assign: "Atribuir"
unassign: "Remover"
color: "Cor"
manageCustomEmojis: "Gerenciar Emojis customizados"
-manageAvatarDecorations: "Gerenciar decorações de avatar"
youCannotCreateAnymore: "Você atingiu o limite de criação."
cannotPerformTemporary: "Ação temporariamente indisponível"
cannotPerformTemporaryDescription: "Esta ação não pôde ser concluída devido ao excesso de pedidos em sucessão. Tente novamente em alguns momentos."
@@ -1034,635 +974,213 @@ thisPostMayBeAnnoyingHome: "Postar na linha do tempo inicial"
thisPostMayBeAnnoyingCancel: "Cancelar"
thisPostMayBeAnnoyingIgnore: "Postar mesmo assim"
collapseRenotes: "Ocultar repostagens já visualizadas"
-collapseRenotesDescription: "Colapsar notas em que você reagiu ou repostou."
internalServerError: "Erro interno de servidor"
-internalServerErrorDescription: "Houve um erro inesperado no servidor."
-copyErrorInfo: "Copiar detalhes de erro"
-joinThisServer: "Cadastrar-se na instância"
-exploreOtherServers: "Buscar outra instância"
-letsLookAtTimeline: "Dar uma olhada na linha do tempo"
-disableFederationConfirm: "Realmente desabilitar a federação?"
-disableFederationConfirmWarn: "Mesmo se defederado, publicações continuarão sendo públicas, a menos que seja definido o contrário. Você geralmente não precisa disso."
-disableFederationOk: "Desabilitar"
-invitationRequiredToRegister: "Essa instância é apenas para convidados. Você precisa inserir um código válido para se cadastrar."
emailNotSupported: "O envio de e-mails não é suportado nesta instância"
-postToTheChannel: "Publicar ao canal"
-cannotBeChangedLater: "Isso não pode ser alterado."
-reactionAcceptance: "Aceitação de Reações"
likeOnly: "Apenas curtidas"
likeOnlyForRemote: "Tudo (somente curtidas remotas)"
-nonSensitiveOnly: "Apenas não-sensível"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "Apenas não sensíveis (somente curtidas remotas)"
rolesAssignedToMe: "Cargos atribuídos a mim"
-resetPasswordConfirm: "Deseja realmente mudar a sua senha?"
-sensitiveWords: "Palavras sensíveis"
-sensitiveWordsDescription: "A visibilidade de todas as notas contendo as palavras configuradas será colocadas como \"Início\" automaticamente. Você pode listar várias delas separando-as por linha."
-sensitiveWordsDescription2: "Utilizar espaços irá criar expressões aditivas (AND) e cercar palavras-chave com barras irá transformá-las em expressões regulares (RegEx)"
-prohibitedWords: "Palavras proibidas"
-prohibitedWordsDescription: "Habilita um erro ao tentar publicar uma nota contendo as palavras escolhidas. Várias palavras podem ser escolhidas, separando-as por linha."
-prohibitedWordsDescription2: "Utilizar espaços irá criar expressões aditivas (AND) e cercar palavras-chave com barras irá transformá-las em expressões regulares (RegEx)"
-hiddenTags: "Hashtags escondidas"
-hiddenTagsDescription: "Selecione tags que não serão exibidas na lista de destaques. Várias tags podem ser escolhidas, separadas por linha."
-notesSearchNotAvailable: "A pesquisa de notas está indisponível."
-license: "Licença"
unfavoriteConfirm: "Deseja realmente remover dos favoritos?"
-myClips: "Meus clipes"
drivecleaner: "Limpeza do drive"
-retryAllQueuesNow: "Tentar novamente todas as pendências"
retryAllQueuesConfirmTitle: "Gostaria de tentar novamente agora?"
-retryAllQueuesConfirmText: "Isso irá temporariamente aumentar a carga do servidor."
-enableChartsForRemoteUser: "Gerar gráficos estatísticos de usuários remotos"
-enableChartsForFederatedInstances: "Gerar gráficos estatísticos de instâncias remotas"
-showClipButtonInNoteFooter: "Adicionar \"Clip\" ao menu de ação de notas"
reactionsDisplaySize: "Tamanho de exibição das reações"
-limitWidthOfReaction: "Limita o comprimento máximo de reações e as exibe em tamanho reduzido"
-noteIdOrUrl: "ID ou URL de nota"
-video: "Vídeo"
-videos: "Vídeos"
-audio: "Áudio"
-audioFiles: "Áudio"
-dataSaver: "Economia de Dados"
-accountMigration: "Migração da Conta"
-accountMoved: "Esse usuário moveu-se para uma nova conta:"
-accountMovedShort: "Essa conta foi migrada."
-operationForbidden: "Operação proibída"
-forceShowAds: "Sempre mostrar propagandas"
-addMemo: "Adicionar memorando"
-editMemo: "Editar memorando"
reactionsList: "Reações"
renotesList: "Repostagens"
-notificationDisplay: "Notificações"
leftTop: "Superior esquerdo"
rightTop: "Superior direito"
leftBottom: "Inferior esquerdo"
rightBottom: "Inferior direito"
-stackAxis: "Eixo de empilhamento"
vertical: "Vertical"
horizontal: "Exibir painel lateral inteiro"
position: "Posição"
serverRules: "Regras do servidor"
-pleaseConfirmBelowBeforeSignup: "Para cadastrar-se no servidor, você precisa ler e concordar como seguinte:"
-pleaseAgreeAllToContinue: "Você precisa concordar com todos os campos acima para continuar."
continue: "Continuar"
-preservedUsernames: "Nomes de usuário reservados"
preservedUsernamesDescription: "Liste os nomes de usuário que deseja reservar, separando-os por quebras de linha. Os nomes de usuário especificados aqui não poderão ser utilizados durante a criação de contas. No entanto, esta restrição não se aplica quando a conta é criada por um administrador. Além disso, as contas que já existem não serão afetadas."
-createNoteFromTheFile: "Compor nota a partir desse arquivo"
archive: "Arquivo"
-archived: "Arquivado"
-unarchive: "Desarquivar"
channelArchiveConfirmTitle: "Deseja realmente arquivar {name}?"
-channelArchiveConfirmDescription: "Um canal arquivado não irá aparecer na lista de canais e nem resultados de pesquisa. Novas publicações não poderão mais ser adicionadas."
-thisChannelArchived: "Esse canal foi arquivado."
-displayOfNote: "Exibição de nota"
-initialAccountSetting: "Configuração inicial do perfil"
youFollowing: "Seguindo"
-preventAiLearning: "Rejeitar uso de Aprendizado de Máquina (IA Generativa)"
preventAiLearningDescription: "Solicita-se que o conteúdo de notas e imagens enviadas não seja usado como objeto de aprendizado por sistemas externos de geração de texto ou imagens. Isso é alcançado incluindo a flag 'noai' na resposta HTML. No entanto, o cumprimento dessa solicitação depende do próprio sistema de IA, portanto, não é garantia total de prevenção de aprendizado."
options: "Opções"
-specifyUser: "Usuário específico"
-lookupConfirm: "Deseja buscar?"
-openTagPageConfirm: "Deseja abrir a uma página de hashtag?"
-specifyHost: "Especificar um hospedeiro"
-failedToPreviewUrl: "Não foi possível carregar prévia"
-update: "Atualizar"
rolesThatCanBeUsedThisEmojiAsReaction: "Cargos que podem utilizar este emoji como reação"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Se nenhum cargo for especificado, qualquer pessoa pode usar este emoji como reação."
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Estes cargos devem ser públicos."
-cancelReactionConfirm: "Realmente excluir a sua reação?"
-changeReactionConfirm: "Realmente mudar a sua reação?"
-later: "Talvez mais tarde"
-goToMisskey: "Ao Misskey"
-additionalEmojiDictionary: "Dicionários adicionais de emoji"
-installed: "Instalado"
-branding: "Marca"
-enableServerMachineStats: "Publicar estatísticas do hardware do servidor"
-enableIdenticonGeneration: "Habilitar geração de identicon de usuário"
-turnOffToImprovePerformance: "Desligar isso pode melhorar o desempenho."
-createInviteCode: "Gerar convite"
-createWithOptions: "Criar com opções"
-createCount: "Número de convites"
-inviteCodeCreated: "Convite gerado"
-inviteLimitExceeded: "Você excedeu o limite de convites que podem ser gerados."
-createLimitRemaining: "Limite de convites: {limit}"
-inviteLimitResetCycle: "Esse limite irá tornar-se {limit} em {time}."
-expirationDate: "Data de expiração"
-noExpirationDate: "Sem expiração"
-inviteCodeUsedAt: "Código de convite usado em"
-registeredUserUsingInviteCode: "Convite usado por"
waitingForMailAuth: "Verificação de e-mail pendente "
-inviteCodeCreator: "Convite criado por"
-usedAt: "Usado em"
-unused: "Não foi usado"
-used: "Usado"
-expired: "Expirado"
-doYouAgree: "Concorda?"
-beSureToReadThisAsItIsImportant: "Por favor, leia essa informação importante."
-iHaveReadXCarefullyAndAgree: "Eu li o texto \"{x}\" e concordo."
-dialog: "Diálogo"
icon: "Avatar"
-forYou: "Para você"
-currentAnnouncements: "Anúncios atuais"
-pastAnnouncements: "Anúncios passados"
-youHaveUnreadAnnouncements: "Há anúncios não lidos."
-useSecurityKey: "Por favor, siga as instruções do seu navegador ou dispositivo para utilizar uma chave de acesso."
-replies: "Responder"
-renotes: "Repostar"
-loadReplies: "Mostrar respostas"
-loadConversation: "Mostrar conversa"
-pinnedList: "Lista fixada"
+replies: "Respostas"
+renotes: "Repostagens"
keepScreenOn: "Manter a tela do dispositivo sempre ligada"
-verifiedLink: "A autoria do link foi verificada"
-notifyNotes: "Notificar sobre novas notas"
-unnotifyNotes: "Deixar de notificar sobre novas notas"
-authentication: "Autenticação"
-authenticationRequiredToContinue: "Por favor, autentique-se para continuar"
-dateAndTime: "Data e Hora"
-showRenotes: "Exibir reposts"
-edited: "Editado"
-notificationRecieveConfig: "Configurações de Notificação"
-mutualFollow: "Seguidor mútuo"
-followingOrFollower: "Seguidor ou usuário seguido"
-fileAttachedOnly: "Apenas notas com arquivos"
-showRepliesToOthersInTimeline: "Mostrar respostas aos outros na linha do tempo"
-hideRepliesToOthersInTimeline: "Esconder respostas dos outros na linha do tempo"
-showRepliesToOthersInTimelineAll: "Mostrar respostas aos outros, mas apenas de quem você segue, na linha do tempo"
-hideRepliesToOthersInTimelineAll: "Esconder respostas de todos que você segue na linha do tempo"
-confirmShowRepliesAll: "Essa operação é irreversível. Você gostaria de mostrar respostas a todos que você segue na sua linha do tempo?"
-confirmHideRepliesAll: "Essa operação é irreversível. Você gostaria de esconder respostas a todos que você segue na sua linha do tempo?"
-externalServices: "Serviços Externos"
-sourceCode: "Código-fonte"
-sourceCodeIsNotYetProvided: "Código-fonte está indisponível. Contate o administrador para resolver esse problema."
-repositoryUrl: "URL do repositório"
-repositoryUrlDescription: "Se você estiver utilizando Misskey como está (sem mudanças no código-fonte), insira https://github.com/misskey-dev/misskey"
-repositoryUrlOrTarballRequired: "Se você não publicou um repositório, você precisa providenciar uma tarball em seu lugar. Veja .config/example.yml para mais informações."
-feedback: "Feedback"
-feedbackUrl: "Link para Feedback"
-impressum: "Impressum"
-impressumUrl: "URL de 'Impressum'"
-impressumDescription: "Em alguns países, como a Alemanha, a inclusão de informação de contato do operador de um serviço é legalmente exigida para websites comerciais."
-privacyPolicy: "Política de Privacidade"
-privacyPolicyUrl: "URL da Política de Privacidade"
-tosAndPrivacyPolicy: "Termos de Serviço e Política de Privacidade"
-avatarDecorations: "Decorações de avatar"
-attach: "Anexar"
-detach: "Remover"
-detachAll: "Remover Tudo"
-angle: "Ângulo"
flip: "Inversão"
-showAvatarDecorations: "Exibir decorações de avatar"
-releaseToRefresh: "Solte para atualizar"
-refreshing: "Atualizando..."
-pullDownToRefresh: "Puxe para baixo para atualizar"
-disableStreamingTimeline: "Desabilitar atualizações em tempo real da linha do tempo"
-useGroupedNotifications: "Agrupar notificações"
-signupPendingError: "Houve um problema ao verificar o endereço de email. O link pode ter expirado."
-cwNotationRequired: "Se \"Esconder conteúdo\" está habilitado, uma descrição deve ser adicionada."
-doReaction: "Adicionar reação"
-code: "Código"
-reloadRequiredToApplySettings: "É necessário reiniciar para aplicar as configurações."
-remainingN: "Restante: {n}"
-overwriteContentConfirm: "Você tem certeza de que deseja sobrescrever o conteúdo atual?"
-seasonalScreenEffect: "Efeito de Tela Sazonal"
-decorate: "Decorar"
-addMfmFunction: "Adicionar MFM"
-enableQuickAddMfmFunction: "Exibir seleção avançada de MFM"
-bubbleGame: "Bubble Game"
-sfx: "Efeitos Sonoros"
-soundWillBePlayed: "Sons serão reproduzidos"
-showReplay: "Ver Replay"
-replay: "Replay"
-replaying: "Mostrando Replay"
-endReplay: "Sair do Replay"
-copyReplayData: "Copiar dados de Replay"
-ranking: "Ranking"
lastNDays: "Últimos {n} dias"
-backToTitle: "Voltar à página inicial"
-hemisphere: "Onde você se localiza"
-withSensitive: "Incluir notas com arquivos sensíveis"
-userSaysSomethingSensitive: "Publicação de {name} contém conteúdo sensível"
-enableHorizontalSwipe: "Arraste para mudar de aba"
-loading: "Carregando"
-surrender: "Cancelar"
-gameRetry: "Tentar Novamente"
-notUsePleaseLeaveBlank: "Deixe em branco caso inutilizado"
-useTotp: "Digite a senha de uso único"
-useBackupCode: "Usar códigos de “backup”"
-launchApp: "Iniciar aplicação"
-useNativeUIForVideoAudioPlayer: "Utilizar UI do navegador ao reproduzir vídeo e áudio"
-keepOriginalFilename: "Manter nome original do arquivo"
-keepOriginalFilenameDescription: "Se você desabilitar essa opção, os nomes de arquivos serão substituídos por uma sequência aleatória ao enviar arquivos."
-noDescription: "Não há descrição"
-alwaysConfirmFollow: "Sempre confirmar ao seguir"
-inquiry: "Contato"
-tryAgain: "Por favor, tente novamente mais tarde"
-confirmWhenRevealingSensitiveMedia: "Confirmar ao revelar mídia sensível"
-sensitiveMediaRevealConfirm: "Essa mídia pode ser sensível. Deseja revelá-la?"
-createdLists: "Listas criadas"
-createdAntennas: "Antenas criadas"
-clipNoteLimitExceeded: "Não é possível adicionar mais notas ao clipe."
-_delivery:
- status: "Estado de entrega"
- stop: "Suspenso"
- resume: "Continuar entrega"
- _type:
- none: "Publicando"
- manuallySuspended: "Suspenso manualmente"
- goneSuspended: "Servidor foi suspenso devido ao seu apagamento"
- autoSuspendedForNotResponding: "Servidor foi suspenso por não responder"
-_bubbleGame:
- howToPlay: "Como jogar"
- hold: "Próximos"
- _score:
- score: "Pontuação"
- scoreYen: "Dinheiro recebido"
- highScore: "Melhor pontuação"
- maxChain: "Número máximo de encadeamentos"
- yen: "{yen} Yen"
- estimatedQty: "{qty} Peças"
- scoreSweets: "{onigiriQtyWithUnit} Onigiri"
- _howToPlay:
- section1: "Ajuste a posição e solte o objeto na caixa."
- section2: "Quando dois objetos do mesmo tipo tocam-se, eles tornam-se outro objeto e você ganha pontos."
- section3: "O jogo acaba quando objetos transbordam da caixa. Busque uma pontuação alta ao fundir objetos enquanto evita transbordar a caixa."
-_announcement:
- forExistingUsers: "Apenas aos usuários existente"
- forExistingUsersDescription: "Se habilitado, esse anúncio será exibido apenas para usuários existentes no tempo de publicação. Se desabilitado, novos usuários também o receberão. "
- needConfirmationToRead: "Exigir confirmação de leitura"
- needConfirmationToReadDescription: "Um lembrete adicional será exibido para confirmar a leitura do anúncio. Esse anúncio também será excluído de qualquer forma de \"Marcar tudo como lido\"."
- end: "Arquivar anúncio"
- tooManyActiveAnnouncementDescription: "O excesso de anúncios pode atrapalhar a experiência do usuário. Considere arquivar anúncios obsoletos."
- readConfirmTitle: "Marcar como lido?"
- readConfirmText: "Isso marcará o conteúdo de \"{title}\" como lido."
- shouldNotBeUsedToPresentPermanentInfo: "É preferível utilizar anúncios para publicar informações atuais e de curto prazo, e não informações que serão relevantes por muito tempo."
- dialogAnnouncementUxWarn: "O uso de duas ou mais notificações de diálogo simultaneamente pode impactar significativamente a experiência de usuário. Portanto, utilize-as cuidadosamente."
- silence: "Sem notificação"
- silenceDescription: "Habilitar isso irá pular a notificação desse anúncio e o usuário não precisará lê-lo."
_initialAccountSetting:
- accountCreated: "A sua conta foi criada com sucesso!"
- letsStartAccountSetup: "Em primeiro lugar, vamos configurar o seu perfil."
- letsFillYourProfile: "Primeiramente, vamos configurar o seu perfil."
- profileSetting: "Configurações do perfil"
- privacySetting: "Configurações de privacidade"
- theseSettingsCanEditLater: "Você pode alterar estas configurações mais tarde."
- youCanEditMoreSettingsInSettingsPageLater: "Há mais configurações na página \"Configurações\". Não se esqueça de visitá-la mais tarde."
followUsers: "Siga usuários que lhe interessam para criar a sua linha do tempo."
- pushNotificationDescription: "Habilitar notificações push o possibilitará receber notificações de {name} diretamente no seu dispositivo."
- initialAccountSettingCompleted: "Configuração de perfil completa!"
- haveFun: "Aproveite {name}!"
- youCanContinueTutorial: "Você pode iniciar um tutorial de como utilizar {name} (Misskey) ou pode sair da configuração e começar o uso imediatamente."
- startTutorial: "Iniciar Tutorial"
- skipAreYouSure: "Deseja pular a configuração de perfil?"
- laterAreYouSure: "Deseja adiar a configuração de perfil?"
-_initialTutorial:
- launchTutorial: "Iniciar Tutorial"
- title: "Tutorial"
- wellDone: "Ótimo!"
- skipAreYouSure: "Sair do Tutorial?"
- _landing:
- title: "Bem-vindo ao Tutorial!"
- description: "Aqui, você pode aprender o básico de como usar o Misskey e as suas funções."
- _note:
- title: "O que é uma Nota?"
- description: "Publicações no Misskey chamam-se 'Notas'. Notas são organizadas cronologicamente na linha do tempo e atualizam em tempo real."
- reply: "Clique nesse botão para responder a uma mensagem. Também é possível responder respostas, continuando a conversa como uma \"thread\"."
- renote: "Você pode compartilhar essa nota na sua linha do tempo. Você também pode citá-la com os seus comentários."
- reaction: "Você pode adicionar reações à nota. Mais detalhes serão explicados na próxima página."
- menu: "Você pode ver detalhes da nota, copiar links e realizar outras ações."
- _reaction:
- title: "O que são Reações?"
- description: "É possível reagir às notas com diversos emojis. Reações permitem que você expresse sutilezas que não são possíveis apenas com uma curtida."
- letsTryReacting: "Reações podem ser adicionadas clicando no botão \"+\". Tente reagir à nota de exemplo."
- reactToContinue: "Adicione uma reação para continuar."
- reactNotification: "Você receberá notificações em tempo real quando alguém reagir à sua nota."
- reactDone: "Você pode desfazer uma reação ao selecionar o botão \"-\"."
- _timeline:
- title: "O Conceito das Linhas do Tempo"
- description1: "Misskey providencia diversas linhas do tempo baseadas na sua utilidade (algumas podem não estar disponíveis a partir das configurações da instância)."
- home: "Você pode ver as notas das contas seguidas. "
- local: "Você pode ver notas de todos os usuários dessa instância."
- social: "Notas da linha do tempo Início e Local serão exibidas."
- global: "Você pode ver notas de todos os servidores conectados."
- description2: "Você pode alterar dentre as linhas do tempo no todo da tela a qualquer momento."
- description3: "Adicionalmente, há \"listas\" e \"canais\". Para mais informações, acesse {link}."
- _postNote:
- title: "Opções de Postagem de Nota"
- description1: "Ao postar uma nota no Misskey, diversas opções estão disponíveis. A ficha de publicação parece com isto: "
- _visibility:
- description: "Você pode limitar quem vê a sua nota."
- public: "Sua nota será visível a todos os usuários."
- home: "Publicar apenas na linha do tempo Início. Pessoas visitando seu perfil, seja seguindo ou por um repost poderão vê-los."
- followers: "Visível apenas para seguidores. Apenas seguidores podem vê-la e mais ninguém, e ela não pode ser repostada pelos demais."
- direct: "Visível apenas para usuários específicos, e o destinatário será notificado. Pode ser usado como uma alternativa às mensagens diretas."
- doNotSendConfidencialOnDirect1: "Tenha cuidado ao enviar informações sensíveis!"
- doNotSendConfidencialOnDirect2: "Administradores do servidor podem ver o que foi escrito. Cuidado, também, ao enviar notas diretas a usuários de servidores não confiáveis."
- localOnly: "Publicar com essa opção não federará a nota com outros servidores. Usuários desses servidores não poderão ver essas notas diretamente, independente das opções de visibilidade acima. "
- _cw:
- title: "Aviso de Conteúdo"
- description: "Ao invés do corpo do texto, o conteúdo escrito na caixa \"anotação\" será exibido. Apertar \"Carregar mais\" irá revelar o corpo."
- _exampleNote:
- cw: "Isso irá te esfomear!"
- note: "Acabei de comer um donut coberto de chocolate! 🍩😋"
- useCases: "Isso pode ser usado caso seja exigido, pelas diretrizes do servidor, o cuidado com algum tópico ou ao publicar conteúdo sensível ou spoilers."
- _howToMakeAttachmentsSensitive:
- title: "Como Marcar Anexos como Sensíveis?"
- description: "Para anexos cujo conteúdo é considerado sensível pelas diretrizes do servidor ou quando pretende-se esconder o seu conteúdo, adicione o sinal \"sensível\"."
- tryThisFile: "Tente marcar a imagem anexada como sensível!"
- _exampleNote:
- note: "Opa, me atrapalhei abrindo a tampa do natô..."
- method: "Para marcar um anexo como sensível, clique na sua miniatura, abra o menu e clique \"Marcar como sensível\"."
- sensitiveSucceeded: "Ao anexar arquivos, por favor atribua uma sensibilidade coerente com as diretrizes da instância."
- doItToContinue: "Marque o anexo como sensível para prosseguir."
- _done:
- title: "Você completou o tutorial! 🎉"
- description: "As funções apresentadas aqui são apenas uma pequena parte. Para um conhecimento mais detalhado do uso do Misskey, acesse {link}."
-_timelineDescription:
- home: "Na linha do tempo Início, você verá notas dos usuários que você segue."
- local: "Na linha do tempo Local, você verá notas de todos os usuários da instância."
- social: "Na linha do tempo Social, você verá notas do Início e Local."
- global: "Na linha do tempo Global, você verá notas de todas as instâncias conectadas."
-_serverRules:
- description: "Um grupo de regras a ser exibido antes de um cadastro. É recomendado que se faça um resumo dos Termos de Serviço."
_serverSettings:
iconUrl: "URL do ícone"
- appIconDescription: "Especifica o ícone utilizado quando {host} é exibido como um app."
- appIconUsageExample: "Exemplo: Como PWA, ou quando exibido num marcador de páginas ou na tela inicial de um celular"
- appIconStyleRecommendation: "Como o ícone pode ser cortado para um quadrado ou círculo, é recomendado adicionar um fundo colorido na imagem."
- appIconResolutionMustBe: "A resolução mínima é {resolution}."
- manifestJsonOverride: "Sobrescrever manifest.json"
- shortName: "Abreviação"
- shortNameDescription: "Uma abreviação do nome da instância que pode ser exibido caso o nome oficial completo seja muito longo."
- fanoutTimelineDescription: "Melhora significativamente a performance do retorno da linha do tempo e reduz o impacto no banco de dados quando habilitado. Em contrapartida, o uso de memória do Redis aumentará. Considere desabilitar em casos de baixa disponibilidade de memória ou instabilidade do servidor."
- fanoutTimelineDbFallback: "\"Fallback\" ao banco de dados"
- fanoutTimelineDbFallbackDescription: "Quando habilitado, a linha do tempo irá recuar ao banco de dados caso consultas adicionais sejam feitas e ela não estiver em cache. Quando desabilitado, o impacto no servidor será reduzido ao eliminar o recuo, mas limita a quantidade de linhas do tempo que podem ser recebidas."
- inquiryUrl: "URL de inquérito"
- inquiryUrlDescription: "Especifique um URL para um formulário de inquérito para a administração ou uma página web com informações de contato."
_accountMigration:
- moveFrom: "Migrar outra conta para essa"
- moveFromSub: "Criar um 'alias' a outra conta"
- moveFromLabel: "Conta original #{n}"
moveFromDescription: "Se você deseja migrar de outra conta para esta, é necessário criar um alias aqui. Por favor, insira a conta de origem da migração no seguinte formato: @username@server.example.com. Para excluir o alias, deixe o campo em branco e clique em salvar (não recomendado)."
- moveTo: "Migrar dessa conta para outra"
- moveToLabel: "Conta para a qual se mover:"
- moveCannotBeUndone: "A migração de conta não pode ser desfeita."
moveAccountDescription: "Você está migrando para uma nova conta.\n ・Seus seguidores irão automaticamente seguir a nova conta.\n ・Todas as suas conexões de seguidores nesta conta serão removidas.\n ・Você não poderá mais criar novas notas nesta conta.\n\nA migração dos seguidores é automática, mas a migração das pessoas que você segue deve ser feita manualmente. Antes de migrar, exporte quem você está seguindo nesta conta e, assim que migrar, importe essa lista na nova conta.\nO mesmo se aplica para listas, silenciamentos e bloqueios, que também devem ser migrados manualmente.\n\n(Esta descrição se refere ao comportamento do servidor Misskey v13.12.0 ou posterior. Outros softwares ActivityPub, como Mastodon, podem ter comportamentos diferentes.)"
moveAccountHowTo: "Para realizar a migração da conta, primeiro crie um alias para esta conta no destino da migração. Após criar o alias, insira a conta de destino da migração no seguinte formato: @username@server.example.com."
- startMigration: "Migrar"
migrationConfirm: "Tem certeza de que deseja migrar esta conta para '{account}'? Uma vez migrada, não poderá ser desfeita e não será possível usar esta conta novamente em seu estado original."
- movedAndCannotBeUndone: "Essa conta foi migrada. A migração não pode ser desfeita."
postMigrationNote: "A remoção dos seguidores desta conta será realizada 24 horas após a operação de migração. O número de seguidores e seguidos desta conta se tornará zero. Os seguidores não serão removidos, portanto, eles continuarão a ver as postagens destinadas aos seguidores desta conta."
- movedTo: "Conta para a qual se mover:"
_achievements:
earnedAt: "Data de aquisição"
_types:
_notes1:
title: "Configurando o meu misskey"
- description: "Poste uma nota pela primeira vez"
+ description: "Postou uma nota pela primeira vez"
flavor: "Divirta-se com o Misskey!"
_notes10:
title: "Algumas notas"
- description: "Poste 10 notas"
+ description: "Postou 10 notas"
_notes100:
title: "Um monte de notas"
- description: "Poste 100 notas"
+ description: "Postou 100 notas"
_notes500:
title: "Coberto por notas"
- description: "Poste 500 notas"
+ description: "Postou 500 notas"
_notes1000:
title: "Uma montanha de notas"
- description: "Poste 1 000 notas"
+ description: "Postou 1000 notas"
_notes5000:
title: "Enxurrada de notas"
- description: "Poste 5000 notas"
+ description: "Postou 5000 notas"
_notes10000:
- title: "Supernota"
- description: "Poste 10 000 notas"
+ title: "Super nota"
+ description: "Postou 10000 notas"
_notes20000:
title: "Preciso... de mais... notas..."
- description: "Poste 20 000 notas"
+ description: "Postou 20000 notas"
_notes30000:
title: "Notas, Notas, NOTAS!"
- description: "Poste 30 000 notas"
+ description: "Postou 30000 notas"
_notes40000:
title: "Fábrica de notas"
- description: "Poste 40 000 notas"
+ description: "Postou 40000 notas"
_notes50000:
title: "Planeta de notas"
- description: "Poste 50 000 notas"
+ description: "Postou 50000 notas"
_notes60000:
title: "Quasar de notas"
- description: "Poste 60 000 notas"
+ description: "Postou 60000 notas"
_notes70000:
title: "Buraco negro de notas"
- description: "Poste 70 000 notas"
+ description: "Postou 70000 notas"
_notes80000:
title: "Galáxia de notas"
- description: "Poste 80 000 notas"
+ description: "Postou 80000 notas"
_notes90000:
title: "Universo de notas"
- description: "Poste 90 000 notas"
+ description: "Postou 90000 notas"
_notes100000:
title: "ALL YOUR NOTE ARE BELONG TO US"
- description: "Poste 100 000 notas"
+ description: "Postou 100000 notas"
flavor: "Você realmente tem muita coisa para escrever"
_login3:
title: "Iniciante I"
- description: "Faça login por um total de 3 dias"
+ description: "Fez login por um total de 3 dias"
flavor: "De hoje em diante, me chame apenas de Misskist"
_login7:
title: "Iniciante II"
- description: "Faça login por um total de 7 dias"
+ description: "Fez login por um total de 7 dias"
flavor: "Pegando o jeito da coisa?"
_login15:
title: "Iniciante III"
- description: "Faça login por um total de 15 dias"
+ description: "Fez login por um total de 15 dias"
_login30:
title: "Misskist I"
- description: "Faça login por um total de 30 dias"
+ description: "Fez login por um total de 30 dias"
_login60:
title: "Misskist II"
- description: "Faça login por um total de 60 dias"
+ description: "Fez login por um total de 60 dias"
_login100:
title: "Misskist III"
- description: "Faça login por um total de 100 dias"
+ description: "Fez login por um total de 100 dias"
flavor: "Misskist violento"
_login200:
title: "Freguês I"
- description: "Faça login por um total de 200 dias"
+ description: "Fez login por um total de 200 dias"
_login300:
title: "Freguês II"
- description: "Faça login por um total de 300 dias"
+ description: "Fez login por um total de 300 dias"
_login400:
title: "Freguês III"
- description: "Faça login por um total de 400 dias"
+ description: "Fez login por um total de 400 dias"
_login500:
title: "Veterano I"
- description: "Faça login por um total de 500 dias"
+ description: "Fez login por um total de 500 dias"
flavor: "Cavalheiros, tudo o que peço são notas"
_login600:
title: "Veterano II"
- description: "Faça login por um total de 600 dias"
+ description: "Fez login por um total de 600 dias"
_login700:
title: "Veterano III"
- description: "Faça login por um total de 700 dias"
+ description: "Fez login por um total de 700 dias"
_login800:
- title: "Mestre das Notas I"
- description: "Faça login por um total de 800 dias"
+ title: "Mestre das notas I"
+ description: "Fez login por um total de 800 dias"
_login900:
- title: "Mestre das Notas II"
- description: "Faça login por um total de 900 dias"
+ title: "Mestre das notas II"
+ description: "Fez login por um total de 900 dias"
_login1000:
- title: "Mestre das Notas III"
- description: "Faça login por um total de 1 000 dias"
+ title: "Mestre das notas III"
+ description: "Fez login por um total de 1000 dias"
flavor: "Obrigado por utilizar o Misskey!"
_noteClipped1:
- title: "Preciso... clipar..."
- description: "Adicione a um clipe a sua primeira nota"
+ title: "Não posso deixar de adicionar ao clipe"
+ description: "Adicionou a um clipe a sua primeira nota"
_noteFavorited1:
- title: "Astrônomo Amador"
- description: "Adicione uma nota aos favoritos pela primeira vez"
+ title: "Astrônomo amador"
+ description: "Adicionou uma nota aos favoritos pela primeira vez"
_myNoteFavorited1:
title: "Cabeça nas estrelas"
- description: "Tenha uma das suas notas adicionada aos favoritos de alguém"
+ description: "Teve uma das suas notas adicionada aos favoritos de alguém"
_profileFilled:
- title: "Tudo Pronto"
- description: "Configure o seu perfil"
+ title: "Tudo pronto"
+ description: "Configurou o seu perfil"
_markedAsCat:
title: "Eu Sou Um Gato"
- description: "Marque a sua conta como um gato"
+ description: "Marcou a sua conta como um gato"
flavor: "Ainda não tenho um nome."
_following1:
title: "Primeira vez seguindo alguém"
- description: "Siga um usuário pela primeira vez"
+ description: "Seguiu um usuário pela primeira vez"
_following10:
title: "Circulando, circulando"
- description: "Siga 10 usuários"
+ description: "Seguiu 10 usuários"
_following50:
title: "Muitos amigos"
- description: "Siga 50 usuários"
+ description: "Seguiu 50 usuários"
_following100:
- title: "100 Amigos"
- description: "Siga 100 usuários"
+ title: "100 amigos"
+ description: "Seguiu 100 usuários"
_following300:
title: "Sobrecarga de amigos"
- description: "Siga 300 usuários"
+ description: "Seguiu 300 usuários"
_followers1:
title: "Primeiro seguidor"
- description: "Ganhe o seu primeiro seguidor"
+ description: "Ganhou o seu primeiro seguidor"
_followers10:
title: "Sigam-me os bons!"
- description: "Ganhe 10 seguidores"
+ description: "Ganhou 10 seguidores"
_followers50:
title: "Aos montes"
- description: "Ganhe 50 seguidores"
+ description: "Ganhou 50 seguidores"
_followers100:
title: "Popular"
- description: "Ganhe 100 seguidores"
+ description: "Ganhou 100 seguidores"
_followers300:
title: "Em fila única, por favor"
- description: "Ganhe 300 seguidores"
+ description: "Ganhou 300 seguidores"
_followers500:
title: "Torre de celular"
- description: "Ganhe 500 seguidores"
+ description: "Ganhou 500 seguidores"
_followers1000:
title: "Influencer"
- description: "Ganhe 1 000 seguidores"
- _collectAchievements30:
- title: "Coletor de Conquistas"
- description: "Ganhe 30 conquistas"
- _viewAchievements3min:
- title: "Curte Conquistas"
- description: "Olhe para a sua lista de conquistas por pelo menos 3 minutos"
- _iLoveMisskey:
- title: "Eu Amo Misskey"
- description: "Poste \"I ❤ #Misskey\""
- flavor: "A equipe de desenvolvimento do Misskey aprecia profundamente o seu apoio!"
- _foundTreasure:
- title: "Caça ao Tesouro"
- description: "Você achou o tesouro escondido"
- _client30min:
- title: "Pausinha"
- description: "Deixe o Misskey aberto por pelo menos 30 minutos"
- _client60min:
- title: "Sem falta"
- description: "Deixe o Misskey aberto por pelo menos 60 minutos"
+ description: "Ganhou 1000 seguidores"
_noteDeletedWithin1min:
title: "Deixa pra lá"
- description: "Exclua a postagem dentro de 1 minuto após a ter publicado"
- _postedAtLateNight:
- title: "Noturno"
- description: "Poste uma nota tarde da noite"
- flavor: "Tá na hora de ir dormir."
- _postedAt0min0sec:
- title: "Relógio Falante"
- description: "Poste uma nota à meia-noite em ponto"
- flavor: "Tic-Tac-Tic-Tac"
- _selfQuote:
- title: "Autorreferência"
- description: "Cite sua própria nota"
- _htl20npm:
- title: "Linha do Tempo Fluida"
- description: "Faça a velocidade da linha do tempo exceder 20 npm (notas por minuto)"
- _viewInstanceChart:
- title: "Analista"
- description: "Veja os infográficos da instância"
- _outputHelloWorldOnScratchpad:
- title: "Olá, Mundo!"
- description: "Produza \"hello world\" no Scratchpad"
- _open3windows:
- title: "Múlti-Janelas"
- description: "Tenha ao mínimo 3 janelas abertas simultaneamente."
+ description: "Excluí a postagem dentro de 1 minuto após ter publicado"
_driveFolderCircularReference:
title: "Referência circular"
- description: "Tente criar uma pasta recursiva no Drive."
- _reactWithoutRead:
- title: "Você leu tudo isso?"
- description: "Reaja a uma nota com mais de 100 caracteres dentro de 3 segundos após a sua publicação."
- _clickedClickHere:
- title: "Clique aqui"
- description: "Você clicou aqui"
- _justPlainLucky:
- title: "Pura Sorte"
- description: "Tem uma chance de ser obtido com uma probabilidade de 0.005% a cada 10 segundos."
- _setNameToSyuilo:
- title: "Complexo de Deus"
- description: "Colocar seu nome como \"syuilo\""
- _passedSinceAccountCreated1:
- title: "Aniversário de Um Ano"
- description: "Um ano passou-se desde a criação da conta"
- _passedSinceAccountCreated2:
- title: "Aniversário de Dois Anos"
- description: "Dois anos passaram-se desde a criação da conta"
- _passedSinceAccountCreated3:
- title: "Aniversário de Três Anos"
- description: "Três anos passaram-se desde a criação da conta"
- _loggedInOnBirthday:
- title: "Feliz Aniversário"
- description: "Entre no dia do seu aniversário"
- _loggedInOnNewYearsDay:
- title: "Feliz Ano Novo!"
- description: "Entre no primeiro dia do ano"
- flavor: "Para outro ótimo ano nessa instância"
- _cookieClicked:
- title: "Um jogo onde você clica em cookies"
- description: "Clicou o cookie"
- flavor: "Pera, você tá no website correto?"
- _brainDiver:
- title: "Brain Diver"
- description: "Poste o link do Brain Diver"
- flavor: "Misskey-Misskey La-Tu-Ma"
- _smashTestNotificationButton:
- title: "Teste de Transbordamento"
- description: "Ative o teste de notificações repetidamente dentro de um curto período de tempo"
- _tutorialCompleted:
- title: "Diploma de Ensino Fundamental Misskey"
- description: "Complete o tutorial"
- _bubbleGameExplodingHead:
- title: "🤯"
- description: "O maior objeto no Bubble Game"
- _bubbleGameDoubleExplodingHead:
- title: "🤯 Duplo"
- description: "Dois dos maiores objetos do Bubble Game ao mesmo tempo."
- flavor: "Dá para encher uma lancheira com esses 🤯🤯."
_role:
new: "Novo cargo"
edit: "Editar cargo"
@@ -1672,10 +1190,8 @@ _role:
descriptionOfPermission: "Moderador permite que você execute operações básicas relacionadas à moderação.\nAdministradores podem alterar todas as configurações do servidor."
assignTarget: "Atribuir"
descriptionOfAssignTarget: "Manual para gerenciar manualmente quem está incluído neste cargo.\nCondicional define uma condição e os usuários que corresponderem a ela serão incluídos automaticamente."
- manual: "Manual"
- manualRoles: "Cargos manuais"
+ manual: "Documentação"
conditional: "Condicional"
- conditionalRoles: "Cargos condicionais"
condition: "Condição"
isConditionalRole: "Este é um cargo condicional."
isPublic: "Cargo público"
@@ -1703,16 +1219,13 @@ _role:
gtlAvailable: "Visualizar Linha do Tempo Global"
ltlAvailable: "Visualizar Linha do Tempo Local"
canPublicNote: "Permitir postagem pública"
- mentionMax: "Número máximo de menções em uma nota"
canInvite: "Permitir a criação de códigos de convites para a instância"
inviteLimit: "Limite de códigos de convite"
inviteLimitCycle: "Intervalo de emissão do código de convite"
inviteExpirationTime: "Prazo de validade do código de convite"
canManageCustomEmojis: "Permitir gerenciar emojis personalizados"
- canManageAvatarDecorations: "Gerenciar decorações de avatar"
driveCapacity: "Capacidade do drive"
alwaysMarkNsfw: "Sempre marcar arquivos como NSFW"
- canUpdateBioMedia: "Permitir a edição de ícone ou imagem do banner."
pinMax: "Número máximo de notas fixadas"
antennaMax: "Número máximo de antenas"
wordMuteMax: "Número máximo de caracteres nas palavras silenciadas"
@@ -1725,17 +1238,9 @@ _role:
descriptionOfRateLimitFactor: "Valores menores são menos restritivos, valores maiores são mais restritivos."
canHideAds: "Permitir ocultar anúncios"
canSearchNotes: "Permitir a busca de notas"
- canUseTranslator: "Uso do tradutor"
- avatarDecorationLimit: "Número máximo de decorações de avatar que podem ser aplicadas"
_condition:
- roleAssignedTo: "Atribuído a cargos manuais"
isLocal: "Usuário local"
isRemote: "Usuário remoto"
- isCat: "Usuários Gatinho"
- isBot: "Usuários Bot"
- isSuspended: "Usuário suspenso"
- isLocked: "Contas privadas"
- isExplorable: "Encontrável em \"Explorar\""
createdLessThan: "Menos de X passados desde a criação da conta"
createdMoreThan: "Mais de X passados desde a criação da conta"
followersLessThanOrEq: "Possui X ou menos seguidores"
@@ -1749,19 +1254,13 @@ _role:
not: "Não ~ (Condicional)"
_sensitiveMediaDetection:
description: "Use o aprendizado de máquina para detectar automaticamente mídias sensíveis para moderação. Isso pode aumentar ligeiramente a carga no servidor."
- sensitivity: "Detecção de sensibilidade"
sensitivityDescription: "Ao reduzir a sensibilidade, as detecções incorretas (falsos positivos) diminuem. Ao aumentar a sensibilidade, as falhas de detecção (falsos negativos) diminuem."
- setSensitiveFlagAutomatically: "Marcar como sensível"
- setSensitiveFlagAutomaticallyDescription: "Os resultados da detecção interna serão mantidos mesmo se essa opção estiver desligada."
- analyzeVideos: "Habilitar análise de vídeos"
- analyzeVideosDescription: "Analisa vídeos em adição a imagens. Isso irá aumentar levemente a carga do servidor."
_emailUnavailable:
used: "O endereço de e-mail informado já está sendo utilizado"
format: "Formado de e-mail inválido"
disposable: "Endereços de e-mail descartáveis não devem ser utilizados"
mx: "O servidor de informado é inválido"
smtp: "O servidor de e-mail não está respondendo"
- banned: "Você não pode se cadastrar com esse endereço de email"
_ffVisibility:
public: "Público"
followers: "Visível apenas para seguidores"
@@ -1781,17 +1280,10 @@ _ad:
back: "Voltar"
reduceFrequencyOfThisAd: "Diminuir frequência deste anúncio"
hide: "Não exibir anúncios"
- timezoneinfo: "O dia da semana é determinado pelo fuso horário do servidor."
- adsSettings: "Configurações de propaganda"
- notesPerOneAd: "Intervalo de notas entre o anúncio nas atualizações em tempo real."
- setZeroToDisable: "Selecione o valor 0 para desabilitar anúncios nas atualizações em tempo real."
- adsTooClose: "O intervalo atual de anúncio pode impactar negativamente a experiência de usuário por ser muito baixo."
_forgotPassword:
enterEmail: "Por favor, insira o endereço de e-mail usado no cadastro de sua conta. Um link para redefinição de senha será enviado para esse endereço."
ifNoEmail: "Caso você não tenha registrado um endereço de e-mail, por favor, entre em contato com o administrador."
- contactAdmin: "Essa instância não possui suporte ao uso de endereços de email, contate seu administrador para mudar a sua senha."
_gallery:
- my: "Minha Galeria"
liked: "Postagens curtidas"
like: "Curtir"
unlike: "Remover curtida"
@@ -1800,223 +1292,40 @@ _email:
title: "Você tem um novo seguidor"
_receiveFollowRequest:
title: "Você recebeu um pedido de seguidor"
-_plugin:
- install: "Instalar plugins"
- installWarn: "Por favor, não instale plugins duvidosos."
- manage: "Gerenciar plugins"
- viewSource: "Ver código-fonte"
- viewLog: "Mostrar registo"
_preferencesBackups:
- list: "Backups criados"
- saveNew: "Salvar novo backup"
- loadFile: "Carregar de arquivo"
- apply: "Aplicar a este dispositivo"
- save: "Salvar mudanças"
- inputName: "Insira um nome para esse backup"
cannotSave: "Não foi possível salvar"
- nameAlreadyExists: "Um backup chamado \"{name}\" já existe. Por favor, insira outro nome."
applyConfirm: "Deseja aplicar o backup '{name}' ao dispositivo atual? As configurações atuais do dispositivo serão perdidas."
- saveConfirm: "Salvar backup como \"{name}\"?"
deleteConfirm: "Deseja excluir {name}?"
- renameConfirm: "Renomear esse backup de \"{old}\" para \"{new}\"?"
- noBackups: "Não há backups. Você pode configurar suas configurações de cliente nesse servidor ao selecionar \"Criar novo backup\"."
- createdAt: "Criado em: {date} {time}"
- updatedAt: "Atualizado em: {date} {time}"
cannotLoad: "Não foi possível carregar"
- invalidFile: "Formato de arquivo inválido"
-_registry:
- scope: "Escopo"
- key: "Chave"
- keys: "Chave"
- domain: "Domínio"
- createKey: "Criar chave"
-_aboutMisskey:
- about: "Misskey é um software de código aberto desenvolvido por syulio desde 2014."
- contributors: "Contribuidores principais"
- allContributors: "Todos os contribuidores"
- source: "Código-fonte"
- original: "Original"
- thisIsModifiedVersion: "{name} utiliza uma versão modificada do Misskey original."
- translation: "Traduza o Misskey"
- donate: "Doe para o Misskey"
- morePatrons: "Nós apreciamos o apoio de vários outros apoiadores não listados aqui. Obrigado! 🥰"
- patrons: "Apoiadores"
- projectMembers: "Membros do projeto"
-_displayOfSensitiveMedia:
- respect: "Esconder mídia marcada como sensível"
- ignore: "Exibir mídia marcada como sensível"
- force: "Esconder toda mídia"
-_instanceTicker:
- none: "Nunca mostrar"
- remote: "Mostrar para usuários remotos"
- always: "Sempre mostrar"
-_serverDisconnectedBehavior:
- reload: "Recarregar automaticamente"
- dialog: "Exibir diálogo de aviso de conteúdo"
- quiet: "Exibir aviso de conteúdo discreto"
_channel:
- create: "Criar canal"
- edit: "Editar canal"
- setBanner: "Definir banner"
- removeBanner: "Remover banner"
featured: "Destaques"
- owned: "Autoral"
following: "Seguindo"
- usersCount: "{n} usuários ativos"
- notesCount: "{n} notas"
+ usersCount: "usuários ativos"
+ notesCount: "notas"
nameAndDescription: "Nome e descrição"
- nameOnly: "Apenas o nome"
- allowRenoteToExternal: "Permitir repostagens e citações de fora do canal"
_menuDisplay:
sideFull: "Exibir painel lateral inteiro"
- sideIcon: "Lateral (Ícones)"
top: "Exibir barra superior"
hide: "Ocultar"
-_wordMute:
- muteWords: "Palavras silenciadas"
- muteWordsDescription: "Separe com espaços para uma condicional AND (&&) ou por linha para uma condicional OR (||)."
- muteWordsDescription2: "Cercar palavras-chave com barras para usar expressões regulares (RegEx)."
_instanceMute:
instanceMuteDescription: "Todas as notas e repostagens do servidor configurado serão silenciados, incluindo respostas aos usuários do servidor mutado."
- instanceMuteDescription2: "Separar por linha"
- title: "Esconder notas das instâncias listadas. "
- heading: "Lista de instâncias a serem silenciadas"
_theme:
- explore: "Explorar Temas"
- install: "Instalar um tema"
- manage: "Gerenciar temas"
- code: "Código do tema"
description: "Descrição"
- installed: "{name} foi instalado"
- installedThemes: "Temas instalados"
- builtinThemes: "Temas nativos"
- alreadyInstalled: "Esse tema já foi instalado"
- invalid: "O formato desse tema é invalido"
- make: "Fazer um tema"
- base: "Base"
- addConstant: "Adicionar constante"
- constant: "Constante"
- defaultValue: "Valor padrão"
- color: "Cor"
- refProp: "Referenciar uma propriedade"
- refConst: "Referenciar uma constante"
- key: "Chave"
- func: "Funções"
- funcKind: "Tipo de função"
- argument: "Argumento"
- basedProp: "Propriedade referenciada"
alpha: "Opacidade"
- darken: "Escurecer"
- lighten: "Esclarecer"
- inputConstantName: "Insira um nome para essa constante"
- importInfo: "Se você inserir o código do tema aqui, você pode importá-lo no editor de temas"
deleteConstantConfirm: "Confirma a exclusão da constante {const}?"
keys:
- accent: "Cor de destaque"
- bg: "Plano de fundo"
- fg: "Texto"
- focus: "Foco"
- indicator: "Indicador"
- panel: "Painel"
- shadow: "Sombra"
- header: "Cabeçalho"
- navBg: "Plano de fundo da barra lateral"
- navFg: "Texto da barra lateral"
- navHoverFg: "Texto da coluna lateral (Selecionado)"
- navActive: "Texto da coluna lateral (Ativa)"
- navIndicator: "Indicador da coluna lateral"
- link: "Link"
- hashtag: "Hashtag"
mention: "Menção"
- mentionMe: "Menciona (a mim)"
renote: "Repostar"
- modalBg: "Plano de fundo modal"
divider: "Separador"
- scrollbarHandle: "Alça da barra de rolagem (Selecionada)"
- scrollbarHandleHover: "Alça da barra de rolagem (Selecionada)"
- dateLabelFg: "Texto do rótulo de data"
- infoBg: "Plano de fundo de informações"
- infoFg: "Texto de informações"
- infoWarnBg: "Plano de fundo de avisos"
- infoWarnFg: "Texto de avisos"
- toastBg: "Plano de fundo de notificações"
- toastFg: "Texto da notificação"
- buttonBg: "Plano de fundo de botão"
- buttonHoverBg: "Plano de fundo de botão (Selecionado)"
- inputBorder: "Borda de campo digitável"
- driveFolderBg: "Plano de fundo da pasta no Drive"
- wallpaperOverlay: "Sobreposição do papel de parede."
- badge: "Emblema"
- messageBg: "Plano de fundo do chat"
- accentDarken: "Cor de destaque (Escurecida)"
- accentLighten: "Cor de destaque (Esclarecida)"
- fgHighlighted: "Texto Destacado"
_sfx:
note: "Posts"
- noteMy: "Própria nota"
notification: "Notificações"
- reaction: "Ao selecionar uma reação"
-_soundSettings:
- driveFile: "Usar um arquivo de áudio do Drive."
- driveFileWarn: "Selecione um arquivo de áudio do Drive."
- driveFileTypeWarn: "Esse arquivo não é compatível"
- driveFileTypeWarnDescription: "Selecione um arquivo de áudio"
- driveFileDurationWarn: "O áudio é muito longo."
- driveFileDurationWarnDescription: "Áudios longos podem atrapalhar o funcionamento do Misskey. Deseja continuar?"
- driveFileError: "Não foi possível carregar o som. Por favor, altere a configuração."
_ago:
- future: "Futuro"
- justNow: "Agora mesmo"
- secondsAgo: "{n}s atrás"
- minutesAgo: "{n}m atrás"
- hoursAgo: "{n}h atrás"
- daysAgo: "{n}d atrás"
- weeksAgo: "{n} semanas atrás"
- monthsAgo: "{n} meses atrás"
- yearsAgo: "{n} anos atrás"
invalid: "Não há nada aqui"
-_timeIn:
- seconds: "Em {n}s"
- minutes: "Em {n}m"
- hours: "Em {n}h"
- days: "Em {n}d"
- weeks: "Em {n} semanas"
- months: "Em {n} meses"
- years: "Em {n} anos"
-_time:
- second: "Segundo(s)"
- minute: "Minuto(s)"
- hour: "Hora(s)"
- day: "Dia(s)"
_2fa:
- alreadyRegistered: "Você já cadastrou um dispositivo de autenticação de dois fatores."
- registerTOTP: "Cadastrar aplicativo autenticador"
- step1: "Inicialmente, instale um aplicativo autenticador (como {a} ou {b}) em seu dispositivo."
- step2: "Então, escaneie o código QR exibido na tela."
- step2Uri: "Acesse o seguinte URI se você estiver utilizando um aplicativo no computador"
- step3Title: "Insira o código de autenticação"
- step3: "Insira o código de autenticação (token) providenciado pelo seu aplicativo para terminar a configuração."
- setupCompleted: "Configuração completa"
- step4: "De agora em diante, quaisquer solicitações de entrada pedirão pelo código."
- securityKeyNotSupported: "O seu navegador não é compatível com chaves de segurança."
- registerTOTPBeforeKey: "Por favor, configure um aplicativo autenticador para registrar uma chave de segurança."
securityKeyInfo: "Além da autenticação por impressão digital ou PIN, você também pode configurar a autenticação por chaves de segurança de hardware compatível com FIDO2 para proteger ainda mais a sua conta."
- registerSecurityKey: "Registre um código de segurança"
- securityKeyName: "Insira um nome para a chave"
- tapSecurityKey: "Por favor, siga as instruções do navegador para registrar o código de segurança"
- removeKey: "Remover código de segurança"
removeKeyConfirm: "Deseja excluir {name}?"
- whyTOTPOnlyRenew: "O autenticador não pode ser removido enquanto há códigos de segurança registrados."
- renewTOTP: "Reconfigurar autenticador"
- renewTOTPConfirm: "Isso interromperá o funcionamento dos códigos de aplicativos anteriores "
- renewTOTPOk: "Reconfigurar"
renewTOTPCancel: "Não, obrigado"
- checkBackupCodesBeforeCloseThisWizard: "Antes de fechar essa janela, anote os códigos de backup a seguir."
- backupCodes: "Códigos de backup"
- backupCodesDescription: "Você pode utilizar esses códigos para ganhar acesso à conta caso sua autenticação de dois fatores esteja indisponível. Cada código pode ser utilizado apenas uma vez. Por favor, guarde-os em um local seguro."
- backupCodeUsedWarning: "Um código de backup foi utilizado. Por favor, reconfigure a autenticação de dois fatores o quanto antes, caso não consiga utilizá-la."
- backupCodesExhaustedWarning: "Todos os códigos de backup foram utilizados. Caso perca acesso à autenticação de dois fatores, você perderá o acesso à conta. Por favor, reconfigure a autenticação de dois fatores."
- moreDetailedGuideHere: "Aqui está um guia detalhado"
_permissions:
"read:account": "Visualizar informações da conta"
"write:account": "Editar informações da conta"
@@ -2050,82 +1359,6 @@ _permissions:
"write:gallery": "Editar sua galeria"
"read:gallery-likes": "Visualizar a sua lista de curtidas da galeria"
"write:gallery-likes": "Editar a sua lista de curtidas da galeria"
- "read:flash": "Ver Play"
- "write:flash": "Editar Plays"
- "read:flash-likes": "Ver lista de Plays curtidas"
- "write:flash-likes": "Editar lista de Plays curtidas"
- "read:admin:abuse-user-reports": "Ver relatórios de usuário"
- "write:admin:delete-account": "Excluir conta de usuário"
- "write:admin:delete-all-files-of-a-user": "Excluir todos os arquivos de um usuário"
- "read:admin:index-stats": "Ver estatísticas do índice do banco de dados"
- "read:admin:table-stats": "Ver estatísticas da tabela do banco de dados"
- "read:admin:user-ips": "Ver endereços IP do usuário"
- "read:admin:meta": "Ver metadados da instância"
- "write:admin:reset-password": "Mudar a senha do usuário"
- "write:admin:resolve-abuse-user-report": "Resolver relatório de usuário"
- "write:admin:send-email": "Enviar email"
- "read:admin:server-info": "Ver informações do servidor"
- "read:admin:show-moderation-log": "Ver log de moderação"
- "read:admin:show-user": "Ver informações privadas do usuário"
- "write:admin:suspend-user": "Suspender usuário"
- "write:admin:unset-user-avatar": "Remover avatar do usuário"
- "write:admin:unset-user-banner": "Remover banner do usuário"
- "write:admin:unsuspend-user": "Cancelar a suspensão do usuário"
- "write:admin:meta": "Gerenciar os metadados da instância"
- "write:admin:user-note": "Gerenciar a nota de moderação"
- "write:admin:roles": "Gerenciar cargos"
- "read:admin:roles": "Ver cargos"
- "write:admin:relays": "Gerenciar relays"
- "read:admin:relays": "Ver relays"
- "write:admin:invite-codes": "Gerenciar códigos de convite"
- "read:admin:invite-codes": "Ver códigos de convite"
- "write:admin:announcements": "Gerenciar anúncios"
- "read:admin:announcements": "Ver anúncios"
- "write:admin:avatar-decorations": "Gerenciar decorações de avatar"
- "read:admin:avatar-decorations": "Ver decorações de avatar"
- "write:admin:federation": "Gerenciar dados de federação"
- "write:admin:account": "Gerenciar conta de usuário"
- "read:admin:account": "Ver conta de usuário"
- "write:admin:emoji": "Gerenciar emoji"
- "read:admin:emoji": "Ver emoji"
- "write:admin:queue": "Gerenciar trabalhos pendentes"
- "read:admin:queue": "Ver informações de trabalhos pendentes"
- "write:admin:promo": "Gerenciar notas de promoção"
- "write:admin:drive": "Gerenciar Drive de usuário"
- "read:admin:drive": "Ver informações de Drive de usuário"
- "read:admin:stream": "Utilizar WebSocket API para Admin"
- "write:admin:ad": "Gerenciar propagandas"
- "read:admin:ad": "Ver propagandas"
- "write:invite-codes": "Criar códigos de convite"
- "read:invite-codes": "Obter códigos de convite"
- "write:clip-favorite": "Gerenciar clipes favoritados"
- "read:clip-favorite": "Ver Clipes favoritados"
- "read:federation": "Ver dados de federação"
- "write:report-abuse": "Reportar violação"
-_auth:
- shareAccessTitle: "Conceder permissões do aplicativo"
- shareAccess: "Você gostaria de autorizar \"{name}\" para acessar essa conta?"
- shareAccessAsk: "Você tem certeza de que gostaria de conceder ao aplicativo o acesso à conta?"
- permission: "{name} solicita as seguintes permissões"
- permissionAsk: "O aplicativo solicita as seguintes permissões"
- pleaseGoBack: "Por favor, volte ao aplicativo"
- callback: "Retornando ao aplicativo"
- denied: "Acesso negado"
- pleaseLogin: "Por favor, entre para autorizar aplicativos."
-_antennaSources:
- all: "Todas as notas"
- homeTimeline: "Notas de usuários seguidos"
- users: "Notas de usuários específicos"
- userList: "Notas de uma lista específica de usuários"
- userBlacklist: "Todas as notas, exceto as de um ou mais usuários específicos"
-_weekday:
- sunday: "Domingo"
- monday: "Segunda-feira"
- tuesday: "Terça-feira"
- wednesday: "Quarta-feira"
- thursday: "Quinta-feira"
- friday: "Sexta-feira"
- saturday: "Sábado"
_widgets:
profile: "Perfil"
instanceInfo: "Informações da instância"
@@ -2156,112 +1389,29 @@ _widgets:
_userList:
chooseList: "Selecione uma lista"
clicker: "Clicker"
- birthdayFollowings: "Usuários de aniversário hoje"
_cw:
- hide: "Esconder"
show: "Carregar mais"
- chars: "{count} caracteres"
- files: "{count} arquivo(s)"
_poll:
- noOnlyOneChoice: "São necessárias, no mínimo, duas escolhas"
- choiceN: "Escolha {n}"
- noMore: "Você não pode adicionar mais escolhas"
canMultipleVote: "Permitir múltipla seleção"
- expiration: "Encerrar enquete"
- infinite: "Nunca"
- at: "Terminar em..."
- after: "Terminar após..."
- deadlineDate: "Data de término"
- deadlineTime: "Tempo"
- duration: "Duração"
- votesCount: "{n} votos"
- totalVotes: "{n} votos totais"
vote: "Votar em enquetes"
- showResult: "Ver resultados"
- voted: "Votada"
- closed: "Encerrada"
- remainingDays: "{d} dia(s) {h} hora(s) restantes"
- remainingHours: "{h} hora(s) {m} minuto(s) restantes"
- remainingMinutes: "{m} minuto(s) {s} segundo(s) restantes"
- remainingSeconds: "{s} segundo(s) restantes"
_visibility:
- public: "Público"
- publicDescription: "Sua nota será visível para todos os usuários"
home: "Início"
- homeDescription: "Publicar apenas na linha do tempo Início"
followers: "Seguidores"
followersDescription: "Tornar visível apenas para os meus seguidores"
- specified: "Mensagem Direta"
- specifiedDescription: "Tornar visível apenas para usuários específicos"
- disableFederation: "Defederar"
- disableFederationDescription: "Não transmitir às outras instâncias"
-_postForm:
- replyPlaceholder: "Responder a essa nota..."
- quotePlaceholder: "Citar essa nota..."
- channelPlaceholder: "Postar em canal..."
- _placeholders:
- a: "Como vão as coisas?"
- b: "O que está rolando por aí?"
- c: "No que está pensando?"
- d: "Do que você quer falar?"
- e: "Comece a digitar..."
- f: "Esperando você digitar..."
_profile:
name: "Nome"
username: "Nome de usuário"
- description: "Bio"
- youCanIncludeHashtags: "Você pode incluir hashtags em sua bio."
- metadata: "Informações Adicionais"
- metadataEdit: "Editar informações adicionais"
- metadataDescription: "Aqui, você pode exibir campos adicionais de informação no seu perfil."
- metadataLabel: "Rótulo"
- metadataContent: "Conteúdo"
- changeAvatar: "Mudar avatar"
- changeBanner: "Mudar banner"
- verifiedLinkDescription: "Ao inserir um URL que contém um link para essa conta, um ícone de verificação será exibido ao lado do campo"
- avatarDecorationMax: "Você pode adicionar até {max} decorações."
_exportOrImport:
- allNotes: "Todas as notas"
favoritedNotes: "Notas nos favoritos"
clips: "Clipe"
followingList: "Seguindo"
muteList: "Silenciar"
blockingList: "Bloquear"
userLists: "Listas"
- excludeMutingUsers: "Excluir usuários silenciados"
- excludeInactiveUsers: "Excluir usuários inativos"
- withReplies: "Incluir respostas de usuários importados na linha do tempo"
_charts:
federation: "União"
- apRequest: "Solicitações"
- usersIncDec: "Diferença no número de usuários"
- usersTotal: "Número total de usuários"
- activeUsers: "Usuários ativos"
- notesIncDec: "Diferença no número de notas"
- localNotesIncDec: "Diferença no número de notas locais"
- remoteNotesIncDec: "Diferença no número de notas remotas"
- notesTotal: "Número total de notas"
- filesIncDec: "Diferença no número de arquivos"
- filesTotal: "Número total de arquivos"
- storageUsageIncDec: "Diferença no uso de armazenamento"
- storageUsageTotal: "Uso total de armazenamento"
-_instanceCharts:
- requests: "Solicitações"
- users: "Diferença no número de usuários"
- usersTotal: "Número cumulativo de usuários"
- notes: "Diferença no número de notas"
- notesTotal: "Número cumulativo de notas"
- ff: "Diferença entre número de usuários seguidos/seguidores"
- ffTotal: "Número cumulativo de usuários seguidos/seguidores"
- cacheSize: "Diferença do tamanho do cache"
- cacheSizeTotal: "Tamanho cumulativo do cache"
- files: "Diferença no número de arquivos"
- filesTotal: "Número cumulativo de arquivos"
_timelines:
home: "Início"
- local: "Local"
- social: "Social"
- global: "Global"
_play:
new: "Criar Play"
edit: "Editar Play"
@@ -2270,66 +1420,18 @@ _play:
deleted: "Play foi excluído"
pageSetting: "Configurações do Play"
editThisPage: "Editar este Play"
- viewSource: "Ver fonte"
my: "Meus Plays"
liked: "Plays curtidos"
- featured: "Popular"
- title: "Título"
script: "Script"
summary: "Descrição"
- visibilityDescription: "Pôr em privado significa que ele não será visível no perfil, mas qualquer um com o URL poderá acessar"
_pages:
- newPage: "Criar uma Página"
- editPage: "Editar essa Página"
- readPage: "Ver a fonte dessa Página"
- created: "Página criada com sucesso"
- updated: "Página atualizada com sucesso"
deleted: "Página excluída com sucesso"
- pageSetting: "Configurações da página"
- nameAlreadyExists: "O URL de Página especificado já existe"
- invalidNameTitle: "O URL de Página especificado é inválido"
- invalidNameText: "Confira se o título da Página não está vazio"
- editThisPage: "Editar essa Página"
- viewSource: "Ver código-fonte"
viewPage: "Visualizar as suas páginas"
like: "Curtir"
unlike: "Remover curtida"
- my: "Minhas Páginas"
liked: "Páginas curtidas"
- featured: "Populares"
- inspector: "Inspetor"
- contents: "Conteúdo"
- content: "Bloco da Página"
- variables: "Variáveis"
- title: "Título"
- url: "URL da Página"
- summary: "Resumo da página"
- alignCenter: "Centralizar elementos"
- hideTitleWhenPinned: "Esconder título da Página quando fixado em perfil"
- font: "Fonte"
- fontSerif: "Serif"
- fontSansSerif: "Sans Serif"
- eyeCatchingImageSet: "Escolher miniatura"
- eyeCatchingImageRemove: "Excluir miniatura"
- chooseBlock: "Adicionar bloco"
- enterSectionTitle: "Insira um título à seção"
- selectType: "Selecionar um tipo"
- contentBlocks: "Conteúdo"
- inputBlocks: "Inserir"
- specialBlocks: "Especial"
blocks:
- text: "Texto"
- textarea: "Área do texto"
- section: "Seção"
image: "imagem"
- button: "Botão"
- dynamic: "Blocos Dinâmicos"
- dynamicDescription: "Esse bloco foi abolido. Por favor, use {play} de agora em diante."
- note: "Nota embutida"
- _note:
- id: "ID da nota"
- idDescription: "Você também pode colar o URL da nota aqui."
- detailed: "Visão detalhada"
_relayStatus:
requesting: "Pendente"
accepted: "Aprovado"
@@ -2344,35 +1446,18 @@ _notification:
youReceivedFollowRequest: "Você recebeu um pedido de seguidor"
yourFollowRequestAccepted: "Seu pedido de seguidor foi aceito"
pollEnded: "Os resultados da enquete agora estão disponíveis"
- newNote: "Nova nota"
- unreadAntennaNote: "Antena {name}"
- roleAssigned: "Cargo dado"
emptyPushNotificationMessage: "As notificações de alerta foram atualizadas"
- achievementEarned: "Conquista desbloqueada"
- testNotification: "Notificação teste"
- checkNotificationBehavior: "Verificar aparência da notificação"
- sendTestNotification: "Enviar notificação de teste"
- notificationWillBeDisplayedLikeThis: "Notificações se parecem com isso"
- reactedBySomeUsers: "{n} usuários reagiram"
- likedBySomeUsers: "{n} usuários gostaram da nota"
- renotedBySomeUsers: "{n} usuários repostaram a nota"
- followedBySomeUsers: "{n} usuários te seguiram"
- flushNotification: "Limpar notificações"
_types:
all: "Todas"
- note: "Novas notas"
follow: "Seguindo"
mention: "Menção"
reply: "Respostas"
renote: "Repostar"
- quote: "Citações"
+ quote: "Citar"
reaction: "Reações"
pollEnded: "Enquetes terminando"
receiveFollowRequest: "Recebeu pedidos de seguidor"
followRequestAccepted: "Aceitou pedidos de seguidor"
- roleAssigned: "Cargo dado"
- achievementEarned: "Conquista desbloqueada"
- login: "Iniciar sessão"
app: "Notificações de aplicativos conectados"
_actions:
followBack: "te seguiu de volta"
@@ -2382,23 +1467,13 @@ _deck:
alwaysShowMainColumn: "Sempre mostrar a coluna principal"
columnAlign: "Alinhar colunas"
addColumn: "Adicionar coluna"
- newNoteNotificationSettings: "Opções de notificação para novas notas"
- configureColumn: "Configurar coluna"
swapLeft: "Trocar de posição com a coluna à esquerda"
swapRight: "Trocar de posição com a coluna à direita"
swapUp: "Trocar de posição com a coluna acima"
swapDown: "Trocar de posição com a coluna abaixo"
- stackLeft: "Empilhar na coluna à esquerda"
popRight: "Acoplar coluna à direita"
profile: "Perfil"
- newProfile: "Novo perfil"
deleteProfile: "Remover perfil"
- introduction: "Crie a interface perfeita para você arranjando as colunas livremente!"
- introduction2: "Clique no + à direita da tela para adicionar novas colunas quando quiser."
- widgetsIntroduction: "Por favor, selecione \"Editar widgets\" no menu em coluna e adicione um widget."
- useSimpleUiForNonRootPages: "Usar UI simples para páginas navegadas"
- usedAsMinWidthWhenFlexible: "A largura mínima será usada para isso quando o \"Ajuste automático da largura\" estiver ativado"
- flexible: "Ajuste automático da largura"
_columns:
main: "Principal"
widgets: "Widgets"
@@ -2410,230 +1485,19 @@ _deck:
mentions: "Menções"
direct: "Notas diretas"
roleTimeline: "Linha do tempo do cargo"
-_dialog:
- charactersExceeded: "Você excedeu o limite de caracteres! Atualmente em {current} de {max}."
- charactersBelow: "Você está abaixo do limite mínimo de caracteres! Atualmente em {current} of {min}."
-_disabledTimeline:
- title: "Linha do tempo desabilitada"
- description: "Você não pode acessar essa linha do tempo sob o seu cargo atual."
_drivecleaner:
orderBySizeDesc: "Tamanho descendente"
orderByCreatedAtAsc: "Data ascendente"
_webhookSettings:
- createWebhook: "Criar Webhook"
- modifyWebhook: "Modificar Webhook"
name: "Nome"
- secret: "Segredo"
- trigger: "Gatilho"
active: "Ativado"
_events:
follow: "Quando seguindo um usuário"
followed: "Quando sendo seguido"
- note: "Ao postar uma nota"
- reply: "Quando receber uma resposta"
renote: "Quando repostado"
- reaction: "Quando receber uma reação"
- mention: "Quando for mencionado"
- _systemEvents:
- abuseReport: "Quando receber um relatório de abuso"
- abuseReportResolved: "Quando relatórios de abuso forem resolvidos "
- userCreated: "Quando um usuário é criado"
- deleteConfirm: "Você tem certeza de que deseja excluir o Webhook?"
-_abuseReport:
- _notificationRecipient:
- createRecipient: "Adicionar destinatário para relatórios de abuso"
- modifyRecipient: "Editar destinatários para relatórios de abuso"
- recipientType: "TIpo de notificação"
- _recipientType:
- mail: "E-mail"
- webhook: "Webhook"
- _captions:
- mail: "Enviar o email aos endereços dos moderadores ao receber relatório de abuso."
- webhook: "Enviar uma notificação ao SystemWebhook quando você receber um resolver um relatório de abuso."
- keywords: "Palavras-chave"
- notifiedUser: "Usuários para notificar"
- notifiedWebhook: "Webhook usado"
- deleteConfirm: "Você tem certeza de que quer excluir o destinatário da notificação?"
_moderationLogTypes:
- createRole: "Cargo criado"
- deleteRole: "Cargo excluído"
- updateRole: "Cargo atualizado"
- assignRole: "Cargo atribuído"
- unassignRole: "Cargo removido"
suspend: "Suspender"
- unsuspend: "Suspensão cancelada"
- addCustomEmoji: "Emoji personalizado adicionado"
- updateCustomEmoji: "Emoji personalizado atualizado"
- deleteCustomEmoji: "Emoji personalizado removido"
- updateServerSettings: "Configurações de servidor atualizadas"
- updateUserNote: "Nota de moderação atualizada"
- deleteDriveFile: "Arquivo excluído"
- deleteNote: "Nota excluída"
- createGlobalAnnouncement: "Anúncio global criado"
- createUserAnnouncement: "Anúncio de usuário criado"
- updateGlobalAnnouncement: "Anúncio global atualizado"
- updateUserAnnouncement: "Anúncio de usuário atualizado"
- deleteGlobalAnnouncement: "Anúncio global excluído"
- deleteUserAnnouncement: "Anúncio de usuário excluído"
resetPassword: "Redefinir senha"
- suspendRemoteInstance: "Instância remota suspensa"
- unsuspendRemoteInstance: "Suspensão de instância remota removida"
- updateRemoteInstanceNote: "Nota de moderação atualizada para instância remota."
- markSensitiveDriveFile: "Arquivo marcado como sensível"
- unmarkSensitiveDriveFile: "Arquivo desmarcado como sensível"
- resolveAbuseReport: "Relatório resolvido"
- createInvitation: "Convite gerado"
- createAd: "Propaganda criada"
- deleteAd: "Propaganda excluída"
- updateAd: "Propaganda atualizada"
- createAvatarDecoration: "Decoração de avatar criada"
- updateAvatarDecoration: "Decoração de avatar atualizada"
- deleteAvatarDecoration: "Decoração de avatar removida"
- unsetUserAvatar: "Remover avatar de usuário"
- unsetUserBanner: "Remover banner de usuário"
- createSystemWebhook: "Criar SystemWebhook"
- updateSystemWebhook: "Atualizar SystemWebhook"
- deleteSystemWebhook: "Remover SystemWebhook"
- createAbuseReportNotificationRecipient: "Criar um destinatário para relatórios de abuso"
- updateAbuseReportNotificationRecipient: "Atualizar destinatários para relatórios de abuso"
- deleteAbuseReportNotificationRecipient: "Remover um destinatário para relatórios de abuso"
- deleteAccount: "Remover conta"
- deletePage: "Remover página"
- deleteFlash: "Remover Play"
- deleteGalleryPost: "Remover a publicação da galeria"
-_fileViewer:
- title: "Detalhes do arquivo"
- type: "Tipo de arquivo"
- size: "Tamanho do arquivo"
- url: "URL"
- uploadedAt: "Adicionado em"
- attachedNotes: "Notas anexadas"
- thisPageCanBeSeenFromTheAuthor: "Essa página só pode ser vista pelo usuário que enviou esse arquivo."
-_externalResourceInstaller:
- title: "Instalar de site externo"
- checkVendorBeforeInstall: "Tenha certeza de que o distribuidor desse recurso é confiável antes da instalação."
- _plugin:
- title: "Deseja instalar esse plugin?"
- metaTitle: "Informações do plugin"
- _theme:
- title: "Deseja instalar esse tema?"
- metaTitle: "Informações do tema"
- _meta:
- base: "Paleta de cores base"
- _vendorInfo:
- title: "Informações do distribuidor"
- endpoint: "Endpoint referenciado"
- hashVerify: "Verificação de hashes"
- _errors:
- _invalidParams:
- title: "Parâmetros inválidos"
- description: "Não há informações suficientes para carregar dados do site externo. Por favor, confirme o URL inserido."
- _resourceTypeNotSupported:
- title: "Esse recurso externo é incompatível"
- description: "Esse tipo de recuso externo é incompatível. Por favor, comunique o administrador do site."
- _failedToFetch:
- title: "Não foi possível obter dados"
- fetchErrorDescription: "Houve um erro ao comunicar com o site externo. Se tentar novamente não resolver o problema, contate o administrador do site."
- parseErrorDescription: "Houve um erro processando os dados do site externo. Por favor, contate o administrador do site."
- _hashUnmatched:
- title: "Verificação de dados falhou"
- description: "Houve um erro verificando a integridade do conteúdo obtido. Como medida de segurança, a instalação foi interrompida. Por favor, contate o administrador do site."
- _pluginParseFailed:
- title: "Erro AiScript"
- description: "Os dados solicitados foram obtidos com sucesso, mas houve um erro na leitura do AiScript. Por favor, contate o autor do plugin. Detalhes de erro podem ser vistos no console Javascript."
- _pluginInstallFailed:
- title: "A instalação do plugin falhou."
- description: "Houve um problema na instalação do plugin. Por favor, tente novamente. Detalhes de erro podem ser vistos no console Javascript."
- _themeParseFailed:
- title: "Erro na leitura do tema"
- description: "Os dados solicitados foram obtidos com sucesso, mas houve um erro na leitura do tema. Por favor, contate o autor do tema. Detalhes de erro podem ser vistos no console Javascript."
- _themeInstallFailed:
- title: "Falha ao instalar tema"
- description: "Houve um problema na instalação do tema. Por favor, tente novamente. Detalhes do erro podem ser vistos no console Javascript."
-_dataSaver:
- _media:
- title: "Carregando mídia"
- description: "Previne que mídia seja carregada automaticamente. Mídias escondidas serão carregadas quando selecionadas."
- _avatar:
- title: "Imagem do avatar"
- description: "Parar animação de avatares. Imagens animadas podem ter um arquivo mais pesado do que imagens normais, potencialmente levando a reduções no tráfego de dados."
- _urlPreview:
- title: "Miniaturas na prévia de URLs"
- description: "Miniaturas na prévia de URLs não serão mais carregadas."
- _code:
- title: "Destaque de código"
- description: "Se as notações de formatação de código forem utilizadas em MFM, elas não irão carregar até serem selecionadas. Destaque de código exige baixar arquivos de alta definição para cada linguagem de programação. Logo, desabilitar o carregamento automático desses arquivos diminui a quantidade de informação comunicada."
-_hemisphere:
- N: "Hemisfério Norte"
- S: "Hemisfério Sul"
- caption: "Utilizado em algumas configurações de aplicativo para determinar a estação do ano."
_reversi:
- reversi: "Reversi"
- gameSettings: "Configurações de jogo"
- chooseBoard: "Escolha um tabuleiro"
- blackOrWhite: "Preto/Branco"
- blackIs: "{name} é as peças Pretas"
- rules: "Regras"
- thisGameIsStartedSoon: "O jogo começará em breve"
- waitingForOther: "Esperando o turno do oponente"
- waitingForMe: "Esperando o seu turno"
- waitingBoth: "Prepare-se"
- ready: "Pronto"
- cancelReady: "Não pronto"
- opponentTurn: "Turno do oponente"
- myTurn: "Seu turno"
- turnOf: "É o turno de {name}"
- pastTurnOf: "Turno de {name}"
- surrender: "Desistir"
- surrendered: "Desistiu"
- timeout: "Fim do tempo"
- drawn: "Empate"
- won: "{name} venceu"
- black: "Preto"
- white: "Branco"
total: "Total"
- turnCount: "Turno {count}"
- myGames: "Meus jogos"
- allGames: "Todos os jogos"
- ended: "Terminado"
- playing: "Atualmente jogando"
- isLlotheo: "Aquele com menos pedras vence (Llotheo)"
- loopedMap: "Mapa em ‘loop’"
- canPutEverywhere: "É possível pôr em qualquer lugar"
- timeLimitForEachTurn: "Tempo limite por turno"
- freeMatch: "Partida Livre"
- lookingForPlayer: "À procura de adversários..."
- gameCanceled: "A partida foi cancelada."
- shareToTlTheGameWhenStart: "Compartilhar jogo na linha do tempo ao iniciar"
- iStartedAGame: "O jogo começou! #MisskeyReversi"
- opponentHasSettingsChanged: "O oponente alterou as configurações dele"
- allowIrregularRules: "Regras irregulares (completamente livre)"
- disallowIrregularRules: "Sem regras irregulares"
- showBoardLabels: "Exibir numeração de linha e coluna no tabuleiro"
- useAvatarAsStone: "Utilizar avatares de usuário como as pedras"
-_offlineScreen:
- title: "Offline - não foi possível conectar ao servidor"
- header: "Não foi possível conectar ao servidor"
-_urlPreviewSetting:
- title: "Configurações da prévia de URL"
- enable: "Habilitar prévia de URL"
- timeout: "Tempo máximo para obter a prévia (ms)"
- timeoutDescription: "Se demorar mais que esse valor para obter uma prévia, ela não será gerada."
- maximumContentLength: "Content-Length máximo (em bytes)"
- maximumContentLengthDescription: "Se o Content-Length for maior que esse valor, a prévia não será gerada."
- requireContentLength: "Gerar previu apenas se houver cabeçalho Content-Length disponível na solicitação"
- requireContentLengthDescription: "Se o outro servidor não retornar um cabeçalho Content-Length, a prévia não será gerada."
- userAgent: "User-Agent"
- userAgentDescription: "Define o User-Agent a ser usado ao gerar prévias. Se for deixado em branco, será usado o User-Agent padrão."
- summaryProxy: "Endpoints do Proxy que geram prévias"
- summaryProxyDescription: "Fora do Misskey, gerar prévias usando o Sumally Proxy."
- summaryProxyDescription2: "Os parâmetros a seguir são vinculados ao proxy como um 'query string'. Se o proxy não os suportar, os valores serão ignorados."
-_mediaControls:
- pip: "Picture-in-Picture"
- playbackRate: "Velocidade de Reprodução"
- loop: "Reprodução em Loop"
-_contextMenu:
- title: "Menu de contexto"
- app: "Aplicativo"
- appWithShift: "Aplicativo com a tecla shift"
- native: "Nativo"
+
diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml
index 3cc09aa5c2..e45b8b75ec 100644
--- a/locales/ro-RO.yml
+++ b/locales/ro-RO.yml
@@ -453,6 +453,7 @@ or: "Sau"
language: "Limbă"
uiLanguage: "Limba interfeței"
aboutX: "Despre {x}"
+disableDrawer: "Nu folosi meniuri în stil sertar"
noHistory: "Nu există istoric"
signinHistory: "Istoric autentificări"
doing: "Se procesează..."
@@ -625,7 +626,10 @@ abuseReported: "Raportul tău a fost trimis. Mulțumim."
reporter: "Raportorul"
reporteeOrigin: "Originea raportatului"
reporterOrigin: "Originea raportorului"
+forwardReport: "Redirecționează raportul către instanța externă"
+forwardReportIsAnonymous: "În locul contului tău, va fi afișat un cont anonim, de sistem, ca raportor către instanța externă."
send: "Trimite"
+abuseMarkAsResolved: "Marchează raportul ca rezolvat"
openInNewTab: "Deschide în tab nou"
openInSideView: "Deschide în vedere laterală"
defaultNavigationBehaviour: "Comportament de navigare implicit"
@@ -645,12 +649,8 @@ searchByGoogle: "Caută"
file: "Fișiere"
show: "Arată"
icon: "Avatar"
-replies: "Răspunde"
+replies: "Răspunsuri"
renotes: "Re-notează"
-_delivery:
- stop: "Suspendat"
- _type:
- none: "Publicare"
_role:
_priority:
middle: "Mediu"
@@ -711,7 +711,6 @@ _notification:
renote: "Re-notează"
quote: "Citează"
reaction: "Reacție"
- login: "Autentifică-te"
_actions:
reply: "Răspunde"
renote: "Re-notează"
@@ -725,12 +724,9 @@ _deck:
mentions: "Mențiuni"
_webhookSettings:
name: "Nume"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Email"
_moderationLogTypes:
suspend: "Suspendă"
resetPassword: "Resetează parola"
_reversi:
total: "Total"
+
diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml
index 70178ec2fd..6141eba5f0 100644
--- a/locales/ru-RU.yml
+++ b/locales/ru-RU.yml
@@ -2,7 +2,7 @@
_lang_: "Русский"
headlineMisskey: "Сеть, сплетённая из заметок"
introMisskey: "Добро пожаловать! Misskey — это децентрализованный сервис микроблогов с открытым исходным кодом.\nПишите «заметки» — делитесь со всеми происходящим вокруг или рассказывайте о себе 📡\nСтавьте «реакции» — выражайте свои чувства и эмоции от заметок других 👍\nОткройте для себя новый мир 🚀"
-poweredByMisskeyDescription: "{name} – сервис на платформе с открытым исходным кодом Misskey , называемый экземпляром Misskey."
+poweredByMisskeyDescription: "{name} – сервис на платформе с открытым исходным кодом Misskey , называемый инстансом Misskey."
monthAndDay: "{day}.{month}"
search: "Поиск"
notifications: "Уведомления"
@@ -10,15 +10,15 @@ username: "Имя пользователя"
password: "Пароль"
forgotPassword: "Забыли пароль?"
fetchingAsApObject: "Приём с других сайтов"
-ok: "Подтвердить"
+ok: "Окей"
gotIt: "Ясно!"
cancel: "Отмена"
noThankYou: "Нет, спасибо"
enterUsername: "Введите имя пользователя"
-renotedBy: "{user} репостнул(а)"
+renotedBy: "{user} делится"
noNotes: "Нет ни одной заметки"
-noNotifications: "Нет уведомлений"
-instance: "Экземпляр"
+noNotifications: "Нет ни одного уведомления"
+instance: "Инстанс"
settings: "Настройки"
notificationSettings: "Настройки уведомлений"
basicSettings: "Основные настройки"
@@ -45,24 +45,22 @@ pin: "Закрепить в профиле"
unpin: "Открепить от профиля"
copyContent: "Скопировать содержимое"
copyLink: "Скопировать ссылку"
-copyLinkRenote: "Скопировать ссылку на репост"
delete: "Удалить"
deleteAndEdit: "Удалить и отредактировать"
-deleteAndEditConfirm: "Удалить этот пост и отредактировать заново? Все реакции, репосты и ответы на него также будут удалены."
+deleteAndEditConfirm: "Удалить эту заметку и создать отредактированную? Все реакции, ссылки и ответы на существующую будут будут потеряны."
addToList: "Добавить в список"
addToAntenna: "Добавить к антенне"
sendMessage: "Отправить сообщение"
copyRSS: "Скопировать RSS"
copyUsername: "Скопировать имя пользователя"
-copyUserId: "Скопировать ID пользователя"
-copyNoteId: "Скопировать ID поста"
+copyUserId: "Скопировать идентификатор пользователя"
+copyNoteId: "Скопировать идентификатор заметки"
copyFileId: "Скопировать ID файла"
copyFolderId: "Скопировать ID папки"
-copyProfileUrl: "Скопировать ссылку на профиль"
+copyProfileUrl: "Скопировать URL профиля "
searchUser: "Поиск людей"
-searchThisUsersNotes: "Искать по заметкам пользователя"
reply: "Ответ"
-loadMore: "Загрузить ещё"
+loadMore: "Показать еще"
showMore: "Показать ещё"
showLess: "Закрыть"
youGotNewFollower: "Новый подписчик"
@@ -109,14 +107,11 @@ enterEmoji: "Введите эмодзи"
renote: "Репост"
unrenote: "Отмена репоста"
renoted: "Репост совершён."
-renotedToX: "Репостнуть в {name}."
cantRenote: "Это нельзя репостить."
cantReRenote: "Невозможно репостить репост."
quote: "Цитата"
inChannelRenote: "В канале"
inChannelQuote: "Заметки в канале"
-renoteToChannel: "Репостнуть в канал"
-renoteToOtherChannel: "Репостнуть в другой канал"
pinnedNote: "Закреплённая заметка"
pinned: "Закрепить в профиле"
you: "Вы"
@@ -134,7 +129,6 @@ overwriteFromPinnedEmojis: "Заменить на эмодзи из общего
reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»."
rememberNoteVisibility: "Запоминать видимость заметок"
attachCancel: "Удалить вложение"
-deleteFile: "Удалить файл"
markAsSensitive: "Отметить как «не для всех»"
unmarkAsSensitive: "Снять отметку «не для всех»"
enterFileName: "Введите имя файла"
@@ -155,7 +149,6 @@ editList: "Редактировать список"
selectChannel: "Выберите канал"
selectAntenna: "Выберите антенну"
editAntenna: "Редактировать антенну"
-createAntenna: "Создать антенну"
selectWidget: "Выберите виджет"
editWidgets: "Редактировать виджеты"
editWidgetsExit: "Готово"
@@ -163,12 +156,11 @@ customEmojis: "Собственные эмодзи"
emoji: "Эмодзи"
emojis: "Эмодзи"
emojiName: "Название эмодзи"
-emojiUrl: "Ссылка на эмодзи"
+emojiUrl: "URL эмодзи"
addEmoji: "Добавить эмодзи"
settingGuide: "Рекомендуемые настройки"
cacheRemoteFiles: "Кешировать внешние файлы"
cacheRemoteFilesDescription: "Когда эта настройка отключена, файлы с других сайтов будут загружаться прямо оттуда. Это сэкономит место на сервере, но увеличит трафик, так как не будут создаваться эскизы."
-youCanCleanRemoteFilesCache: "Вы можете очистить кэш, нажав на кнопку 🗑️ в меню управления файлами."
cacheRemoteSensitiveFiles: "Кэшировать внешние файлы «не для всех»"
cacheRemoteSensitiveFilesDescription: "Если отключено, файлы «не для всех» загружаются непосредственно с удалённых серверов, не кэшируясь."
flagAsBot: "Аккаунт бота"
@@ -182,10 +174,6 @@ addAccount: "Добавить учётную запись"
reloadAccountsList: "Обновить список учётных записей"
loginFailed: "Неудачная попытка входа"
showOnRemote: "Перейти к оригиналу на сайт"
-continueOnRemote: "Продолжить на удалённом сервере"
-chooseServerOnMisskeyHub: "Выбрать сервер с Misskey Hub"
-specifyServerHost: "Укажите сервер напрямую"
-inputHostName: "Введите домен"
general: "Общее"
wallpaper: "Обои"
setWallpaper: "Установить обои"
@@ -196,7 +184,6 @@ followConfirm: "Подписаться на {name}?"
proxyAccount: "Учётная запись прокси"
proxyAccountDescription: "Учетная запись прокси предназначена служить подписчиком на пользователей с других сайтов. Например, если пользователь добавит кого-то с другого сайта а список, деятельность того не отобразится, пока никто с этого же сайта не подписан на него. Чтобы это стало возможным, на него подписывается прокси."
host: "Хост"
-selectSelf: "Выбрать себя"
selectUser: "Выберите пользователя"
recipient: "Кому"
annotation: "Описание"
@@ -211,7 +198,6 @@ perHour: "По часам"
perDay: "По дням"
stopActivityDelivery: "Остановить отправку обновлений активности"
blockThisInstance: "Блокировать этот инстанс"
-silenceThisInstance: "Заглушить этот инстанс"
operations: "Операции"
software: "Программы"
version: "Версия"
@@ -231,7 +217,6 @@ clearCachedFiles: "Очистить кэш"
clearCachedFilesConfirm: "Удалить все закэшированные файлы с других сайтов?"
blockedInstances: "Заблокированные инстансы"
blockedInstancesDescription: "Введите список инстансов, которые хотите заблокировать. Они больше не смогут обмениваться с вашим инстансом."
-silencedInstances: "Заглушённые инстансы"
muteAndBlock: "Скрытие и блокировка"
mutedUsers: "Скрытые пользователи"
blockedUsers: "Заблокированные пользователи"
@@ -250,7 +235,7 @@ noJobs: "Нет заданий"
federating: "Федерируется"
blocked: "Заблокировано"
suspended: "Заморожено"
-all: "Все"
+all: "Всё"
subscribing: "Подписка"
publishing: "Публикация"
notResponding: "Нет ответа"
@@ -282,7 +267,7 @@ messaging: "Сообщения"
upload: "Загрузить"
keepOriginalUploading: "Сохранить исходное изображение"
keepOriginalUploadingDescription: "Сохраняет исходную версию при загрузке изображений. Если выключить, то при загрузке браузер генерирует изображение для публикации."
-fromDrive: "С Диска"
+fromDrive: "С «диска»"
fromUrl: "По ссылке"
uploadFromUrl: "Загрузить по ссылке"
uploadFromUrlDescription: "Ссылка на файл, который хотите загрузить"
@@ -322,13 +307,11 @@ selectFile: "Выберите файл"
selectFiles: "Выберите файлы"
selectFolder: "Выберите папку"
selectFolders: "Выберите папки"
-fileNotSelected: "Файл не выбран"
renameFile: "Переименовать файл"
folderName: "Имя папки"
createFolder: "Создать папку"
renameFolder: "Переименовать папку"
deleteFolder: "Удалить папку"
-folder: "Папка"
addFile: "Добавить файл"
emptyDrive: "Диск пуст"
emptyFolder: "Папка пуста"
@@ -374,8 +357,8 @@ disablingTimelinesInfo: "У администраторов и модератор
registration: "Регистрация"
enableRegistration: "Разрешить регистрацию"
invite: "Пригласить"
-driveCapacityPerLocalAccount: "Объём Диска на одного локального пользователя"
-driveCapacityPerRemoteAccount: "Объём Диска на одного пользователя с другого экземпляра"
+driveCapacityPerLocalAccount: "Объём диска на одного локального пользователя"
+driveCapacityPerRemoteAccount: "Объём диска на одного пользователя с другого сайта"
inMb: "В мегабайтах"
bannerUrl: "Ссылка на изображение в шапке"
backgroundImageUrl: "Ссылка на фоновое изображение"
@@ -390,11 +373,8 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Включить hCaptcha"
hcaptchaSiteKey: "Ключ сайта"
hcaptchaSecretKey: "Секретный ключ"
-mcaptcha: "mCaptcha"
-enableMcaptcha: "Включить mCaptcha"
mcaptchaSiteKey: "Ключ сайта"
mcaptchaSecretKey: "Секретный ключ"
-mcaptchaInstanceUrl: "Ссылка на сервер mCaptcha"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Включить reCAPTCHA"
recaptchaSiteKey: "Ключ сайта"
@@ -409,8 +389,7 @@ manageAntennas: "Настройки антенн"
name: "Название"
antennaSource: "Источник антенны"
antennaKeywords: "Ключевые слова"
-antennaExcludeKeywords: "Чёрный список слов"
-antennaExcludeBots: "Исключать ботов"
+antennaExcludeKeywords: "Исключения"
antennaKeywordsDescription: "Пишите слова через пробел в одной строке, чтобы ловить их появление вместе; на отдельных строках располагайте слова, или группы слов, чтобы ловить любые из них."
notifyAntenna: "Уведомлять о новых заметках"
withFileAntenna: "Только заметки с вложениями"
@@ -443,7 +422,6 @@ totp: "Приложение-аутентификатор"
totpDescription: "Описание приложения-аутентификатора"
moderator: "Модератор"
moderation: "Модерация"
-moderationLogs: "Журнал модерации"
nUsersMentioned: "Упомянуло пользователей: {n}"
securityKeyAndPasskey: "Ключ безопасности и парольная фраза"
securityKey: "Ключ безопасности"
@@ -476,12 +454,10 @@ retype: "Введите ещё раз"
noteOf: "Что пишет {user}"
quoteAttached: "Цитата"
quoteQuestion: "Хотите добавить цитату?"
-attachAsFileQuestion: "Текста в буфере обмена слишком много. Прикрепить как текстовый файл?"
noMessagesYet: "Пока ни одного сообщения"
newMessageExists: "Новое сообщение"
onlyOneFileCanBeAttached: "К сообщению можно прикрепить только один файл"
signinRequired: "Пожалуйста, войдите"
-signinOrContinueOnRemote: "Чтобы продолжить, вам необходимо войти в аккаунт на своём сервере или зарегистрироваться / войти в аккаунт на этом."
invitations: "Приглашения"
invitationCode: "Код приглашения"
checking: "Проверка"
@@ -491,7 +467,7 @@ usernameInvalidFormat: "Можно использовать только лат
tooShort: "Слишком короткий"
tooLong: "Слишком длинный"
weakPassword: "Слабый пароль"
-normalPassword: "Хороший пароль"
+normalPassword: "Годный пароль"
strongPassword: "Надёжный пароль"
passwordMatched: "Совпали"
passwordNotMatched: "Не совпадают"
@@ -503,8 +479,8 @@ uiLanguage: "Язык интерфейса"
aboutX: "Описание {x}"
emojiStyle: "Стиль эмодзи"
native: "Системные"
+disableDrawer: "Не использовать выдвижные меню"
showNoteActionsOnlyHover: "Показывать кнопки у заметок только при наведении"
-showReactionsCount: "Видеть количество реакций на заметках"
noHistory: "История пока пуста"
signinHistory: "Журнал посещений"
enableAdvancedMfm: "Включить расширенный MFM"
@@ -566,8 +542,6 @@ showInPage: "Показать страницу"
popout: "Развернуть"
volume: "Громкость"
masterVolume: "Основная регулировка громкости"
-notUseSound: "Выключить звук"
-useSoundOnlyWhenActive: "Воспроизводить звук только когда Misskey активен."
details: "Подробнее"
chooseEmoji: "Выберите эмодзи"
unableToProcess: "Не удаётся завершить операцию"
@@ -588,10 +562,6 @@ output: "Выходы"
script: "Скрипт"
disablePagesScript: "Отключить скрипты на «Страницах»"
updateRemoteUser: "Обновить данные пользователя с его сервера"
-unsetUserAvatar: "Убрать аватар"
-unsetUserAvatarConfirm: "Вы точно хотите убрать аватар?"
-unsetUserBanner: "Убрать баннер"
-unsetUserBannerConfirm: "Вы точно хотите убрать баннер?"
deleteAllFiles: "Удалить все файлы"
deleteAllFilesConfirm: "Вы хотите удалить все файлы?"
removeAllFollowing: "Удалить всех подписчиков"
@@ -621,7 +591,7 @@ poll: "Опрос"
useCw: "Скрывать содержимое под предупреждением"
enablePlayer: "Включить проигрыватель"
disablePlayer: "Выключить проигрыватель"
-expandTweet: "Развернуть заметку"
+expandTweet: "Развернуть твит"
themeEditor: "Редактор темы оформления"
description: "Описание"
describeFile: "Добавить подпись"
@@ -633,7 +603,7 @@ plugins: "Расширения"
preferencesBackups: "Резервная копия"
deck: "Пульт"
undeck: "Покинуть пульт"
-useBlurEffectForModal: "Размытие за формой ввода заметки"
+useBlurEffectForModal: "Размывка под формой поверх всего"
useFullReactionPicker: "Полнофункциональный выбор реакций"
width: "Ширина"
height: "Высота"
@@ -642,7 +612,6 @@ medium: "Средне"
small: "Мелко"
generateAccessToken: "Создать токен доступа"
permission: "Разрешения"
-adminPermission: "Доступ администратора"
enableAll: "Включить все"
disableAll: "Выключить всё"
tokenRequested: "Открыть доступ к учётной записи"
@@ -664,7 +633,6 @@ smtpSecure: "Использовать SSL/TLS для SMTP-соединений"
smtpSecureInfo: "Выключите при использовании STARTTLS."
testEmail: "Проверка доставки электронной почты"
wordMute: "Скрытие слов"
-hardWordMute: "Строгое скрытие слов"
regexpError: "Ошибка в регулярном выражении"
regexpErrorDescription: "В списке {tab} скрытых слов, в строке {line} обнаружена синтаксическая ошибка:"
instanceMute: "Глушение инстансов"
@@ -700,7 +668,10 @@ abuseReported: "Жалоба отправлена. Большое спасибо
reporter: "Сообщивший"
reporteeOrigin: "О ком сообщено"
reporterOrigin: "Кто сообщил"
+forwardReport: "Отправить жалобу на инстанс автора."
+forwardReportIsAnonymous: "Жалоба на удалённый инстанс будет отправлена анонимно. Вместо ваших данных у получателя будет отображена системная учётная запись."
send: "Отправить"
+abuseMarkAsResolved: "Отметить жалобу как решённую"
openInNewTab: "Открыть в новой вкладке"
openInSideView: "Открывать в боковой колонке"
defaultNavigationBehaviour: "Поведение навигации по умолчанию"
@@ -743,7 +714,6 @@ lockedAccountInfo: "Даже если вы вручную подтверждае
alwaysMarkSensitive: "Отмечать файлы как «содержимое не для всех» по умолчанию"
loadRawImages: "Сразу показывать изображения в полном размере"
disableShowingAnimatedImages: "Не проигрывать анимацию"
-highlightSensitiveMedia: "Выделять содержимое не для всех"
verificationEmailSent: "Вам отправлено письмо для подтверждения. Пройдите, пожалуйста, по ссылке из письма, чтобы завершить проверку."
notSet: "Не настроено"
emailVerified: "Адрес электронной почты подтверждён."
@@ -761,7 +731,7 @@ makeExplorable: "Опубликовать профиль в «Обзоре»."
makeExplorableDescription: "Если выключить, ваш профиль не будет показан в разделе «Обзор»."
showGapBetweenNotesInTimeline: "Показывать разделитель между заметками в ленте"
duplicate: "Дубликат"
-left: "Слева"
+left: "Влево"
center: "По центру"
wide: "Толстый"
narrow: "Тонкий"
@@ -840,7 +810,7 @@ noMaintainerInformationWarning: "Не заполнены сведения об
noBotProtectionWarning: "Ботозащита не настроена"
configure: "Настроить"
postToGallery: "Опубликовать в галерею"
-postToHashtag: "Написать заметку с этим хештегом"
+postToHashtag: "Написать заметку с этим хэштегом"
gallery: "Галерея"
recentPosts: "Недавние публикации"
popularPosts: "Популярные публикации"
@@ -857,13 +827,13 @@ emailNotConfiguredWarning: "Не указан адрес электронной
ratio: "Соотношение"
previewNoteText: "Предварительный просмотр"
customCss: "Индивидуальный CSS"
-customCssWarn: "Используйте эту настройку только если знаете, что делаете. Ошибки здесь чреваты тем, что у вас перестанет нормально работать сайт."
+customCssWarn: "Используйте эту настройку только если знаете, что делаете. Ошибки здесь чреваты тем, что сайт перестанет нормально работать у вас."
global: "Всеобщая"
squareAvatars: "Квадратные аватарки"
sent: "Отправить"
received: "Получено"
searchResult: "Результаты поиска"
-hashtags: "Хештеги"
+hashtags: "Хэштег"
troubleshooting: "Разрешение проблем"
useBlurEffect: "Размытие в интерфейсе"
learnMore: "Подробнее"
@@ -875,7 +845,7 @@ accountDeletionInProgress: "В настоящее время выполняет
usernameInfo: "Имя, которое отличает вашу учетную запись от других на этом сервере. Вы можете использовать алфавит (a~z, A~Z), цифры (0~9) или символы подчеркивания (_). Имена пользователей не могут быть изменены позже."
aiChanMode: "Режим Ай"
devMode: "Режим разработчика"
-keepCw: "Сохраняйте предупреждения о содержимом"
+keepCw: "Сохраняйте Предупреждения о содержимом"
pubSub: "Учётные записи Pub/Sub"
lastCommunication: "Последнее сообщение"
resolved: "Решено"
@@ -896,8 +866,6 @@ makeReactionsPublicDescription: "Список сделанных вами реа
classic: "Классика"
muteThread: "Скрыть цепочку"
unmuteThread: "Отменить сокрытие цепочки"
-followingVisibility: "Видимость подписок"
-followersVisibility: "Видимость подписчиков"
continueThread: "Показать следующие ответы"
deleteAccountConfirm: "Учётная запись будет безвозвратно удалена. Подтверждаете?"
incorrectPassword: "Пароль неверен."
@@ -1007,7 +975,6 @@ assign: "Назначить"
unassign: "Отменить назначение"
color: "Цвет"
manageCustomEmojis: "Управлять пользовательскими эмодзи"
-manageAvatarDecorations: "Управление украшениями аватара"
youCannotCreateAnymore: "Вы достигли лимита создания."
cannotPerformTemporary: "Временно недоступен"
cannotPerformTemporaryDescription: "Это действие временно невозможно выполнить из-за превышения лимита выполнения."
@@ -1024,8 +991,7 @@ thisPostMayBeAnnoying: "Это сообщение может быть непри
thisPostMayBeAnnoyingHome: "Этот пост может быть отправлен на главную"
thisPostMayBeAnnoyingCancel: "Этот пост не может быть отменен."
thisPostMayBeAnnoyingIgnore: "Этот пост может быть проигнорирован "
-collapseRenotes: "Сворачивать увиденные репосты"
-collapseRenotesDescription: "Сворачивать посты с которыми вы взаимодействовали."
+collapseRenotes: "Свернуть репосты"
internalServerError: "Внутренняя ошибка сервера"
internalServerErrorDescription: "Внутри сервера произошла непредвиденная ошибка."
copyErrorInfo: "Скопировать код ошибки"
@@ -1049,10 +1015,7 @@ resetPasswordConfirm: "Сбросить пароль?"
sensitiveWords: "Чувствительные слова"
sensitiveWordsDescription: "Установите общедоступный диапазон заметки, содержащей заданное слово, на домашний. Можно сделать несколько настроек, разделив их переносами строк."
sensitiveWordsDescription2: "Разделение пробелом создаёт спецификацию AND, а разделение косой чертой создаёт регулярное выражение."
-prohibitedWords: "Запрещённые слова"
-prohibitedWordsDescription: "Включает вывод ошибки при попытке опубликовать пост, содержащий указанное слово/набор слов.\nМножество слов может быть указано, разделяемые новой строкой."
prohibitedWordsDescription2: "Разделение пробелом создаёт спецификацию AND, а разделение косой чертой создаёт регулярное выражение."
-hiddenTags: "Скрытые хештеги"
notesSearchNotAvailable: "Поиск заметок недоступен"
license: "Лицензия"
unfavoriteConfirm: "Удалить избранное?"
@@ -1063,14 +1026,9 @@ retryAllQueuesConfirmTitle: "Хотите попробовать ещё раз?"
retryAllQueuesConfirmText: "Нагрузка на сервер может увеличиться"
enableChartsForRemoteUser: "Создание диаграмм для удалённых пользователей"
enableChartsForFederatedInstances: "Создание диаграмм для удалённых серверов"
-showClipButtonInNoteFooter: "Показать кнопку добавления в подборку в меню действий с заметкой"
-reactionsDisplaySize: "Размер реакций"
-limitWidthOfReaction: "Ограничить максимальную ширину реакций и отображать их в уменьшенном размере."
noteIdOrUrl: "ID или ссылка на заметку"
video: "Видео"
videos: "Видео"
-audio: "Звук"
-audioFiles: "Звуковые файлы"
dataSaver: "Экономия трафика"
accountMigration: "Перенос учётной записи"
accountMoved: "Учётная запись перенесена"
@@ -1082,13 +1040,12 @@ editMemo: "Изменить памятку"
reactionsList: "Список реакций"
renotesList: "Репосты"
notificationDisplay: "Отображение уведомлений"
-leftTop: "Слева вверху"
-rightTop: "Справа сверху"
-leftBottom: "Слева внизу"
-rightBottom: "Справа внизу"
-stackAxis: "Положение уведомлений"
-vertical: "Вертикально"
-horizontal: "Горизонтально"
+leftTop: "Влево вверх"
+rightTop: "Вправо вверх"
+leftBottom: "Влево вниз"
+rightBottom: "Вправо вниз"
+vertical: "Вертикальная"
+horizontal: "Сбоку"
position: "Позиция"
serverRules: "Правила сервера"
pleaseConfirmBelowBeforeSignup: "Для регистрации на данном сервере, необходимо согласится с нижеследующими положениями."
@@ -1100,114 +1057,51 @@ createNoteFromTheFile: "Создать заметку из этого файла
archive: "Архив"
channelArchiveConfirmTitle: "Переместить {name} в архив?"
channelArchiveConfirmDescription: "Архивированные каналы перестанут отображаться в списке каналов или результатах поиска. В них также нельзя будет добавлять новые записи."
-thisChannelArchived: "Этот канал находится в архиве."
displayOfNote: "Отображение заметок"
initialAccountSetting: "Настройка профиля"
youFollowing: "Подписки"
preventAiLearning: "Отказаться от использования в машинном обучении (Генеративный ИИ)"
-preventAiLearningDescription: "Запросить краулеров не использовать опубликованный текст или изображения и т.д. для машинного обучения (Прогнозирующий / Генеративный ИИ) датасетов. Это достигается путём добавления \"noai\" HTTP-заголовка в ответ на соответствующий контент. Полного предотвращения через этот заголовок не избежать, так как он может быть просто проигнорирован."
options: "Настройки ролей"
specifyUser: "Указанный пользователь"
-openTagPageConfirm: "Открыть страницу этого хештега?"
-specifyHost: "Указать сайт"
failedToPreviewUrl: "Предварительный просмотр недоступен"
update: "Обновить"
rolesThatCanBeUsedThisEmojiAsReaction: "Роли тех, кому можно использовать эти эмодзи как реакцию"
rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "Если здесь ничего не указать, в качестве реакции эту эмодзи сможет использовать каждый."
-rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "Эти роли должны быть общедоступными."
-cancelReactionConfirm: "Вы действительно хотите удалить свою реакцию?"
later: "Позже"
goToMisskey: "К Misskey"
additionalEmojiDictionary: "Дополнительные словари эмодзи"
installed: "Установлено"
branding: "Бренд"
-enableServerMachineStats: "Опубликовать характеристики сервера"
enableIdenticonGeneration: "Включить генерацию иконки пользователя"
turnOffToImprovePerformance: "Отключение этого параметра может повысить производительность."
-createInviteCode: "Создать код приглашения"
-createCount: "Количество приглашений"
expirationDate: "Дата истечения"
-noExpirationDate: "Бессрочно"
-unused: "Неиспользованное"
-used: "Использован"
+unused: "Неиспользуемый"
expired: "Срок действия приглашения истёк"
doYouAgree: "Согласны?"
icon: "Аватар"
replies: "Ответы"
renotes: "Репост"
loadReplies: "Показать ответы"
-pinnedList: "Закреплённый список"
-keepScreenOn: "Держать экран включённым"
-showRenotes: "Показывать репосты"
-mutualFollow: "Взаимные подписки"
-followingOrFollower: "Подписки или подписчики"
-fileAttachedOnly: "Только заметки с файлами"
-showRepliesToOthersInTimeline: "Показывать ответы в ленте"
-showRepliesToOthersInTimelineAll: "Показывать в ленте ответы пользователей, на которых вы подписаны"
-hideRepliesToOthersInTimelineAll: "Скрывать в ленте ответы пользователей, на которых вы подписаны"
sourceCode: "Исходный код"
-sourceCodeIsNotYetProvided: "Исходный код пока не доступен. Свяжитесь с администратором, чтобы исправить эту проблему."
-repositoryUrl: "Ссылка на репозиторий"
-repositoryUrlDescription: "Если вы используете Misskey как есть (без изменений в исходном коде), введите https://github.com/misskey-dev/misskey"
-privacyPolicy: "Политика Конфиденциальности"
-privacyPolicyUrl: "Ссылка на Политику Конфиденциальности"
-attach: "Прикрепить"
-angle: "Угол"
flip: "Переворот"
-disableStreamingTimeline: "Отключить обновление ленты в режиме реального времени"
-useGroupedNotifications: "Отображать уведомления сгруппировано"
-doReaction: "Добавить реакцию"
-code: "Код"
-remainingN: "Остаётся: {n}"
-seasonalScreenEffect: "Эффект времени года на экране"
-decorate: "Украсить"
-addMfmFunction: "Добавить MFM"
lastNDays: "Последние {n} сут"
-hemisphere: "Место проживания"
-enableHorizontalSwipe: "Смахните в сторону, чтобы сменить вкладки"
-surrender: "Этот пост не может быть отменен."
-useNativeUIForVideoAudioPlayer: "Использовать интерфейс браузера при проигрывании видео и звука"
-keepOriginalFilename: "Сохранять исходное имя файла"
-keepOriginalFilenameDescription: "Если вы выключите данную настройку, имена файлов будут автоматически заменены случайной строкой при загрузке."
-alwaysConfirmFollow: "Всегда подтверждать подписку"
-inquiry: "Связаться"
-_delivery:
- stop: "Заморожено"
- _type:
- none: "Публикация"
-_announcement:
- tooManyActiveAnnouncementDescription: "Большое количество оповещений может ухудшить пользовательский опыт. Рассмотрите архивирование неактуальных оповещений. "
_initialAccountSetting:
accountCreated: "Аккаунт успешно создан!"
letsStartAccountSetup: "Давайте настроим вашу учётную запись."
profileSetting: "Настройки профиля"
privacySetting: "Настройки конфиденциальности"
initialAccountSettingCompleted: "Первоначальная настройка успешно завершена!"
- startTutorial: "Пройти Обучение"
skipAreYouSure: "Пропустить настройку?"
_initialTutorial:
- launchTutorial: "Пройти обучение"
_note:
description: "Посты в Misskey называются 'Заметками.' Заметки отсортированы в хронологическом порядке в ленте и обновляются в режиме реального времени."
- _reaction:
- reactToContinue: "Добавьте реакцию, чтобы продолжить."
- _postNote:
- _visibility:
- public: "Твоя заметка будет видна всем."
- doNotSendConfidencialOnDirect2: "Администратор целевого сервера может видеть что вы отправляете. Будьте осторожны с конфиденциальной информацией, когда отправляете личные заметки пользователям с ненадёжных серверов."
_timelineDescription:
home: "В персональной ленте располагаются заметки тех, на которых вы подписаны."
- local: "Местная лента показывает заметки всех пользователей этого экземпляра."
+ local: "Местная лента показывает заметки всех пользователей этого сайта."
social: "В социальной ленте собирается всё, что есть в персональной и местной лентах."
- global: "В глобальную ленту попадает вообще всё со связанных экземпляров."
+ global: "В глобальную ленту попадает вообще всё со связанных инстансов."
_serverSettings:
iconUrl: "Адрес на иконку роли"
-_accountMigration:
- moveFrom: "Перенести другую учётную запись сюда"
- moveTo: "Перенести учётную запись на другой сервер"
- moveAccountDescription: "Это действие перенесёт ваш аккаунт на другой сервер.\n ・Подписчики с этого аккаунта автоматически подпишутся на новый\n ・Этот аккаунт отпишется от всех пользователей, на которых подписан сейчас\n ・Вы не сможете создавать новые заметки и т.д. на этом аккаунте\n\nТогда как перенос подписчиков происходит автоматически, вы должны будете подготовиться, сделав некоторые шаги, чтобы перенести список пользователей, на которых вы подписаны. Чтобы сделать это, экспортируйте список подписчиков в файл, который затем импортируете на новом аккаунте в меню настроек. То же самое необходимо будет сделать со списками, также как и со скрытыми и заблокированными пользователями.\n\n(Это объяснение применяется к Misskey v13.12.0 и выше. Другое ActivityPub программное обеспечение, такое, как Mastodon, может работать по-другому."
- startMigration: "Перенести"
- movedAndCannotBeUndone: "Аккаунт был перемещён. Это действие необратимо."
_achievements:
earnedAt: "Разблокировано в"
_types:
@@ -1483,7 +1377,6 @@ _role:
canPublicNote: "Может публиковать общедоступные заметки"
canInvite: "Может создавать пригласительные коды"
canManageCustomEmojis: "Управлять пользовательскими эмодзи"
- canManageAvatarDecorations: "Управление украшениями аватара"
driveCapacity: "Доступное пространство на «диске»"
alwaysMarkNsfw: "Всегда отмечать файлы как «не для всех»"
pinMax: "Доступное количество закреплённых заметок"
@@ -1594,11 +1487,6 @@ _aboutMisskey:
donate: "Пожертвование на Misskey"
morePatrons: "Большое спасибо и многим другим, кто принял участие в этом проекте! 🥰"
patrons: "Материальная поддержка"
- projectMembers: "Участники проекта"
-_displayOfSensitiveMedia:
- respect: "Скрывать содержимое не для всех"
- ignore: "Показывать содержимое не для всех"
- force: "Скрывать всё содержимое"
_instanceTicker:
none: "Не показывать"
remote: "Только для других сайтов"
@@ -1627,7 +1515,7 @@ _wordMute:
muteWordsDescription: "Пишите слова через пробел в одной строке, чтобы фильтровать их появление вместе; а если хотите фильтровать любое из них, пишите в отдельных строках."
muteWordsDescription2: "Здесь можно использовать регулярные выражения — просто заключите их между двумя дробными чертами (/)."
_instanceMute:
- instanceMuteDescription: "Любые активности, затрагивающие инстансы из данного списка, будут скрыты."
+ instanceMuteDescription: "Заметки и репосты с указанных здесь инстансов, а также ответы пользователям оттуда же не будут отображаться."
instanceMuteDescription2: "Пишите каждый инстанс на отдельной строке"
title: "Скрывает заметки с заданных инстансов."
heading: "Список скрытых инстансов"
@@ -1676,7 +1564,7 @@ _theme:
navActive: "Текст на боковой панели (активирован)"
navIndicator: "Индикатор на боковой панели"
link: "Ссылка"
- hashtag: "Хештег"
+ hashtag: "Хэштег"
mention: "Упоминание"
mentionMe: "Упоминания вас"
renote: "Репост"
@@ -1694,6 +1582,7 @@ _theme:
buttonBg: "Фон кнопки"
buttonHoverBg: "Текст кнопки"
inputBorder: "Рамка поля ввода"
+ listItemHoverBg: "Фон пункта списка (под указателем)"
driveFolderBg: "Фон папки «Диска»"
wallpaperOverlay: "Слой обоев"
badge: "Значок"
@@ -1705,10 +1594,8 @@ _sfx:
note: "Заметки"
noteMy: "Собственные заметки"
notification: "Уведомления"
- reaction: "При выборе реакции"
-_soundSettings:
- driveFile: "Использовать аудиофайл с Диска."
- driveFileWarn: "Выбрать аудиофайл с Диска."
+ antenna: "Антенна"
+ channel: "Канал"
_ago:
future: "Из будущего"
justNow: "Только что"
@@ -1738,6 +1625,7 @@ _2fa:
registerTOTP: "Начните настраивать приложение-аутентификатор"
step1: "Прежде всего, установите на устройство приложение для аутентификации, например, {a} или {b}."
step2: "Далее отсканируйте отображаемый QR-код при помощи приложения."
+ step2Click: "Нажав на QR-код, вы можете зарегистрироваться с помощью приложения для аутентификации или брелка для ключей, установленного на вашем устройстве."
step3Title: "Введите проверочный код"
step3: "И наконец, введите код, который покажет приложение."
step4: "Теперь при каждом входе на сайт вам нужно будет вводить код из приложения аналогичным образом."
@@ -1787,7 +1675,6 @@ _permissions:
"write:gallery": "Редактирование галереи"
"read:gallery-likes": "Просмотр списка понравившегося в галерее"
"write:gallery-likes": "Изменение списка понравившегося в галерее"
- "write:admin:reset-password": "Сбросить пароль пользователю"
_auth:
shareAccessTitle: "Разрешения для приложений"
shareAccess: "Дать доступ для «{name}» к вашей учётной записи?"
@@ -1841,7 +1728,6 @@ _widgets:
_userList:
chooseList: "Выберите список"
clicker: "Счётчик щелчков"
- birthdayFollowings: "Пользователи, у которых сегодня день рождения"
_cw:
hide: "Спрятать"
show: "Показать"
@@ -1895,7 +1781,7 @@ _profile:
name: "Имя"
username: "Имя пользователя"
description: "О себе"
- youCanIncludeHashtags: "Можете использовать здесь хештеги."
+ youCanIncludeHashtags: "Можете использовать здесь хэштеги"
metadata: "Дополнительные сведения"
metadataEdit: "Редактировать дополнительные сведения"
metadataDescription: "Можно добавить до четырёх дополнительных граф в профиль."
@@ -1903,8 +1789,6 @@ _profile:
metadataContent: "Содержимое"
changeAvatar: "Поменять аватар"
changeBanner: "Поменять изображение в шапке"
- verifiedLinkDescription: "Указывая здесь URL, содержащий ссылку на профиль, иконка владения ресурсом может быть отображена рядом с полем"
- avatarDecorationMax: "Вы можете добавить до {max} украшений."
_exportOrImport:
allNotes: "Все заметки\n"
favoritedNotes: "Избранное"
@@ -2027,9 +1911,6 @@ _notification:
unreadAntennaNote: "Антенна {name}"
emptyPushNotificationMessage: "Обновлены push-уведомления"
achievementEarned: "Получено достижение"
- checkNotificationBehavior: "Проверить внешний вид уведомления"
- sendTestNotification: "Отправить тестовое уведомление"
- flushNotification: "Очистить уведомления"
_types:
all: "Все"
follow: "Подписки"
@@ -2042,7 +1923,6 @@ _notification:
receiveFollowRequest: "Получен запрос на подписку"
followRequestAccepted: "Запрос на подписку одобрен"
achievementEarned: "Получение достижений"
- login: "Войти"
app: "Уведомления из приложений"
_actions:
followBack: "отвечает взаимной подпиской"
@@ -2082,57 +1962,16 @@ _dialog:
_disabledTimeline:
title: "Лента отключена"
description: "Ваша текущая роль не позволяет пользоваться этой лентой."
-_drivecleaner:
- orderBySizeDesc: "Размеры файлов по убыванию"
- orderByCreatedAtAsc: "По увеличению даты"
_webhookSettings:
createWebhook: "Создать вебхук"
- modifyWebhook: "Изменить Вебхук"
name: "Название"
- secret: "Секрет"
- trigger: "Условие срабатывания"
active: "Вкл."
- _events:
- follow: "Когда подписались на пользователя"
- followed: "Когда на вас подписались"
- note: "Когда создали заметку"
- reply: "Когда получили ответ на заметку"
- renote: "Когда вас репостнули"
- reaction: "Когда получили реакцию"
- mention: "Когда вас упоминают"
- _systemEvents:
- abuseReport: "Когда приходит жалоба"
- abuseReportResolved: "Когда разрешается жалоба"
- userCreated: "Когда создан пользователь"
- deleteConfirm: "Вы уверены, что хотите удалить этот Вебхук?"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Электронная почта"
- webhook: "Вебхук"
- _captions:
- webhook: "Отправить уведомление Системному Вебхуку при получении или разрешении жалоб."
- notifiedWebhook: "Используемый Вебхук"
_moderationLogTypes:
suspend: "Заморозить"
addCustomEmoji: "Добавлено эмодзи"
updateCustomEmoji: "Изменено эмодзи"
deleteCustomEmoji: "Удалено эмодзи"
- deleteDriveFile: "Файл удалён"
resetPassword: "Сброс пароля:"
- createInvitation: "Создать код приглашения"
- createSystemWebhook: "Создать Системный Вебхук"
- updateSystemWebhook: "Обновить Системый Вебхук"
- deleteSystemWebhook: "Удалить Системный Вебхук"
-_fileViewer:
- url: "Ссылка"
- attachedNotes: "Закреплённые заметки"
-_dataSaver:
- _code:
- title: "Подсветка кода"
-_hemisphere:
- N: "Северное полушарие"
- S: "Южное полушарие"
- caption: "Используется для некоторых настроек клиента для определения сезона."
_reversi:
total: "Всего"
+
diff --git a/locales/si-LK.yml b/locales/si-LK.yml
index c43f3d860d..cd21505a47 100644
--- a/locales/si-LK.yml
+++ b/locales/si-LK.yml
@@ -1,22 +1,2 @@
---
-_lang_: "සිංහල"
-monthAndDay: "{month}-{day}"
-username: "පරිශීලක නාමය"
-password: "මුරපදය"
-cancel: "අවලංගු කරන්න"
-instance: "සර්වර්"
-login: "පිවිසෙන්න"
-users: "පරිශීලක"
-note: "නෝට්"
-notes: "නෝට්"
-instances: "සර්වර්"
-smtpUser: "පරිශීලක නාමය"
-smtpPass: "මුරපදය"
-user: "පරිශීලක"
-_sfx:
- note: "නෝට්"
-_profile:
- username: "පරිශීලක නාමය"
-_notification:
- _types:
- login: "පිවිසෙන්න"
+
diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml
index 60ce45a6b9..f280f91270 100644
--- a/locales/sk-SK.yml
+++ b/locales/sk-SK.yml
@@ -454,6 +454,7 @@ uiLanguage: "Jazyk používateľského prostredia"
aboutX: "O {x}"
emojiStyle: "Štýl emoji"
native: "Natívne"
+disableDrawer: "Nepoužívať šuflíkové menu"
showNoteActionsOnlyHover: "Ovládacie prvky poznámky sa zobrazujú len po nabehnutí myši"
noHistory: "Žiadna história"
signinHistory: "História prihlásení"
@@ -631,7 +632,10 @@ abuseReported: "Vaše nahlásenie je odoslané. Veľmi pekne ďakujeme."
reporter: "Nahlásil"
reporteeOrigin: "Pôvod nahláseného"
reporterOrigin: "Pôvod nahlasovača"
+forwardReport: "Preposlať nahlásenie na server"
+forwardReportIsAnonymous: "Namiesto vášho účtu bude zobrazený anonymný systémový účet na vzdialenom serveri ako autor nahlásenia."
send: "Poslať"
+abuseMarkAsResolved: "Označiť nahlásenia ako vyriešené"
openInNewTab: "Otvoriť v novom tabe"
openInSideView: "Otvoriť v bočnom paneli"
defaultNavigationBehaviour: "Predvolené správanie navigácie"
@@ -913,15 +917,11 @@ color: "Farba"
horizontal: "Strana"
youFollowing: "Sledované"
icon: "Avatar"
-replies: "Odpovedať"
+replies: "Odpovede"
renotes: "Preposlať"
sourceCode: "Zdrojový kód"
flip: "Preklopiť"
lastNDays: "Posledných {n} dní"
-_delivery:
- stop: "Zmrazené"
- _type:
- none: "Zverejňovanie"
_role:
priority: "Priorita"
_priority:
@@ -1108,6 +1108,7 @@ _theme:
buttonBg: "Pozadie tlačidla"
buttonHoverBg: "Pozadie tlačidla (pod kurzorom)"
inputBorder: "Okraj vstupného poľa"
+ listItemHoverBg: "Pozadie položky zoznamu (pod kurzorom)"
driveFolderBg: "Pozadie priečinu disku"
wallpaperOverlay: "Vrstvenie pozadia"
badge: "Odznak"
@@ -1119,6 +1120,8 @@ _sfx:
note: "Poznámky"
noteMy: "Vlastná poznámka"
notification: "Oznámenia"
+ antenna: "Antény"
+ channel: "Upozornenia kanála"
_ago:
future: "Budúcnosť"
justNow: "Teraz"
@@ -1405,7 +1408,6 @@ _notification:
pollEnded: "Hlasovanie skončilo"
receiveFollowRequest: "Doručené žiadosti o sledovanie"
followRequestAccepted: "Schválené žiadosti o sledovanie"
- login: "Prihlásiť sa"
app: "Oznámenia z prepojených aplikácií"
_actions:
followBack: "Sledovať späť\n"
@@ -1441,12 +1443,9 @@ _deck:
_webhookSettings:
name: "Názov"
active: "Zapnuté"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Email"
_moderationLogTypes:
suspend: "Zmraziť"
resetPassword: "Resetovať heslo"
_reversi:
total: "Celkom"
+
diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml
index 5a0de660e8..76b9bc90b7 100644
--- a/locales/sv-SE.yml
+++ b/locales/sv-SE.yml
@@ -486,12 +486,8 @@ pleaseDonate: "Misskey är en gratis programvara som används på {host}. Donera
resetPasswordConfirm: "Återställ verkligen ditt lösenord?"
dataSaver: "Databesparing"
icon: "Profilbild"
-replies: "Svara"
+replies: "Svar"
renotes: "Omnotera"
-_delivery:
- stop: "Suspenderad"
- _type:
- none: "Publiceras"
_achievements:
_types:
_open3windows:
@@ -512,6 +508,7 @@ _theme:
_sfx:
note: "Noter"
notification: "Notifikationer"
+ antenna: "Antenner"
_2fa:
renewTOTPCancel: "Nej tack"
_antennaSources:
@@ -562,7 +559,6 @@ _notification:
renote: "Omnotera"
quote: "Citat"
reaction: "Reaktioner"
- login: "Logga in"
_actions:
reply: "Svara"
renote: "Omnotera"
@@ -577,10 +573,7 @@ _deck:
_webhookSettings:
name: "Namn"
active: "Aktiverad"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "E-post"
_moderationLogTypes:
suspend: "Suspendera"
resetPassword: "Återställ Lösenord"
+
diff --git a/locales/th-TH.yml b/locales/th-TH.yml
index c70d448e2b..f250104ed6 100644
--- a/locales/th-TH.yml
+++ b/locales/th-TH.yml
@@ -2,23 +2,23 @@
_lang_: "ภาษาไทย"
headlineMisskey: "เชื่อมต่อเครือข่ายโดยโน้ต"
introMisskey: "ยินดีต้อนรับทุกคนจ้า! Misskey คือ ซอฟต์แวร์โอเพนซอร์สสำหรับบริการไมโครบล็อกกิ้ง (MicroBlogging) แบบกระจายศูนย์อำนาจ (Decentralized) \n\nเขียน “โน้ต (Note)” เพื่อส่งต่อเรื่องราวของคุณให้ทั้งโลกได้รับรู้📡\nและอย่าลืมที่จะ “รีแอคชั่น” กับเรื่องราวของคนอื่น ๆ ด้วยนะ! 👍\n\nท่องสำรวจโลกใบใหม่กันเถอะ🚀"
-poweredByMisskeyDescription: "{name} เป็นหนึ่งในเซิร์ฟเวอร์ของแพลตฟอร์มโอเพ่นซอร์ส Misskey "
+poweredByMisskeyDescription: "{name} เป็นส่วนหนึ่งในบริการที่ถูกขับเคลื่อนโดยแพลตฟอร์มโอเพ่นซอร์ส Misskey (เรียกว่า \"อินสแตนซ์ Misskey\")"
monthAndDay: "{month}/{day}"
search: "ค้นหา"
-notifications: "เเจ้งเตือน"
+notifications: "การเเจ้งเตือน"
username: "ชื่อผู้ใช้"
password: "รหัสผ่าน"
-forgotPassword: "ลืมรหัสผ่าน"
+forgotPassword: "ลืมรหัสผ่านใช่ไหม"
fetchingAsApObject: "กำลังดึงข้อมูลจากสหพันธ์..."
ok: "ตกลง"
gotIt: "เข้าใจแล้ว !"
cancel: "ยกเลิก"
-noThankYou: "ไม่เอาดีกว่า"
+noThankYou: "ไม่เป็นไร"
enterUsername: "กรอกชื่อผู้ใช้"
renotedBy: "รีโน้ตโดย {user}"
noNotes: "ไม่มีโน้ต"
noNotifications: "ไม่มีการแจ้งเตือน"
-instance: "เซิร์ฟเวอร์"
+instance: "อินสแตนซ์"
settings: "การตั้งค่า"
notificationSettings: "ตั้งค่าการแจ้งเตือน"
basicSettings: "การตั้งค่าพื้นฐาน"
@@ -31,16 +31,16 @@ login: "เข้าสู่ระบบ"
loggingIn: "กำลังเข้าสู่ระบบ"
logout: "ออกจากระบบ"
signup: "สร้างบัญชีผู้ใช้"
-uploading: "กำลังอัปโหลด"
+uploading: "กำลังอัพโหลด..."
save: "บันทึก"
-users: "ผู้ใช้"
+users: "ผู้ใช้งาน"
addUser: "เพิ่มผู้ใช้"
favorite: "รายการโปรด"
favorites: "รายการโปรด"
unfavorite: "ลบออกจากรายการโปรด"
-favorited: "เพิ่มลงรายการโปรดแล้ว"
-alreadyFavorited: "เพิ่มลงรายการโปรดอยู่แล้ว"
-cantFavorite: "ไม่สามารถเพิ่มลงรายการโปรดได้"
+favorited: "เพิ่มแล้วในรายการโปรด"
+alreadyFavorited: "เพิ่มในรายการโปรดอยู่แล้ว"
+cantFavorite: "ไม่สามารถเพิ่มในรายการโปรดได้"
pin: "ปักหมุด"
unpin: "เลิกปักหมุด"
copyContent: "คัดลอกเนื้อหา"
@@ -48,7 +48,7 @@ copyLink: "คัดลอกลิงก์"
copyLinkRenote: "คัดลอกลิงก์รีโน้ต"
delete: "ลบ"
deleteAndEdit: "ลบและแก้ไข"
-deleteAndEditConfirm: "ต้องการลบโน้ตนี้และแก้ไขใหม่ใช่ไหม? รีแอคชั่น รีโน้ต และการตอบกลับต่อโน้ตนี้ทั้งหมดจะถูกลบออกด้วย"
+deleteAndEditConfirm: "คุณต้องการลบโน้ตนี้และแก้ไขใหม่ใช่ไหม? รีแอคชั่น รีโน้ต และการตอบกลับต่อโน้ตนี้ทั้งหมดจะถูกลบออกด้วย"
addToList: "เพิ่มลงรายชื่อ"
addToAntenna: "เพิ่มไปยังเสาอากาศ"
sendMessage: "ส่งข้อความ"
@@ -60,24 +60,23 @@ copyFileId: "คัดลอกไฟล์ ID"
copyFolderId: "คัดลอกโฟลเดอร์ ID"
copyProfileUrl: "คัดลอกโปรไฟล์ URL"
searchUser: "ค้นหาผู้ใช้"
-searchThisUsersNotes: "ค้นหาโน้ตของผู้ใช้"
reply: "ตอบกลับ"
loadMore: "แสดงเพิ่มเติม"
showMore: "แสดงเพิ่มเติม"
showLess: "ปิด"
youGotNewFollower: "ได้ติดตามคุณ"
-receiveFollowRequest: "มีคำขอติดตามส่งมาหา"
-followRequestAccepted: "การติดตามได้รับการอนุมัติแล้ว"
+receiveFollowRequest: "คำขอผู้ติดตามที่ได้รับ"
+followRequestAccepted: "อนุมัติการติดตามแล้ว"
mention: "กล่าวถึง"
-mentions: "กล่าวถึงคุณ"
-directNotes: "โพสต์แบบไดเร็กต์"
+mentions: "พูดถึง"
+directNotes: "ไดเร็คโน้ต"
importAndExport: "นำเข้า / ส่งออก"
import: "นำเข้า"
export: "ส่งออก"
files: "ไฟล์"
download: "ดาวน์โหลด"
-driveFileDeleteConfirm: "ต้องการลบไฟล์ “{name}” ใช่ไหม? โน้ตที่แนบมากับไฟล์นี้ก็จะถูกลบไปด้วย"
-unfollowConfirm: "ต้องการเลิกติดตาม {name} ใช่ไหม?"
+driveFileDeleteConfirm: "ต้องการลบไฟล์ “{name}” ใช่หรือไม่? โน้ตที่แนบมากับไฟล์นี้ก็จะถูกลบไปด้วย"
+unfollowConfirm: "ต้องการเลิกติดตาม {name}?"
exportRequested: "คุณได้ร้องขอการส่งออก อาจใช้เวลาสักครู่ และจะถูกเพิ่มในไดรฟ์ของคุณเมื่อเสร็จสิ้นแล้ว"
importRequested: "คุณได้ร้องขอการนำเข้า การดำเนินการนี้อาจใช้เวลาสักครู่"
lists: "รายชื่อ"
@@ -93,7 +92,7 @@ error: "ผิดพลาด!"
somethingHappened: "อุ๊ย ! มีอะไรบางอย่างผิดพลาด"
retry: "ลองใหม่อีกครั้ง"
pageLoadError: "เกิดข้อผิดพลาดในการโหลดหน้านี้"
-pageLoadErrorDescription: "ปัญหานี้มักเกิดจากแคชของเครือข่ายหรือเบราว์เซอร์ ควรล้างแคช, รอสักครู่ แล้วลองใหม่อีกครั้ง"
+pageLoadErrorDescription: "โดยปกติแล้วมักจะเกิดจากข้อผิดพลาดของเครือข่ายหรือแคชของเบราว์เซอร์ ลองล้างแคชแล้วลองใหม่อีกครั้งหลังจากรอสักครู่ "
serverIsDead: "เซิร์ฟเวอร์นี้ไม่มีการตอบสนอง โปรดกรุณารอสักครู่แล้วลองใหม่อีกครั้ง"
youShouldUpgradeClient: "หากต้องการดูหน้านี้ กรุณาโหลดหน้าใหม่เพื่ออัปเดตไคลเอ็นต์ของคุณ"
enterListName: "ป้อนนามเรียกของรายชื่อชุดนี้"
@@ -109,14 +108,11 @@ enterEmoji: "พิมพ์เอโมจิ"
renote: "รีโน้ต"
unrenote: "เลิกรีโน้ต"
renoted: "รีโน้ตแล้ว"
-renotedToX: "รีโน้ตให้ {name} แล้ว"
cantRenote: "โพสต์นี้ไม่สามารถรีโน้ตใหม่ได้"
cantReRenote: "รีโน้ตไม่สามารถรีโน้ตซ้ำได้"
quote: "อ้างอิง"
inChannelRenote: "รีโน้ตในช่องเท่านั้น"
inChannelQuote: "อ้างอิงในช่องเท่านั้น"
-renoteToChannel: "รีโน้ตไปที่ช่อง"
-renoteToOtherChannel: "รีโน้ตไปยังช่องอื่น"
pinnedNote: "โน้ตที่ปักหมุดไว้"
pinned: "ปักหมุด"
you: "คุณ"
@@ -132,9 +128,9 @@ emojiPickerDisplay: "แสดงตัวจิ้มเอโมจิ"
overwriteFromPinnedEmojisForReaction: "เขียนทับการตั้งค่ารีแอคชั่น"
overwriteFromPinnedEmojis: "เขียนทับการตั้งค่าทั่วไป"
reactionSettingDescription2: "ลากเพื่อจัดลำดับใหม่ คลิกที่เอโมจินั้นเพื่อลบ กด “+” เพื่อเพิ่ม"
-rememberNoteVisibility: "จำการตั้งค่าการมองเห็นโน้ต"
-attachCancel: "ยกเลิกแนบไฟล์"
-deleteFile: "ลบไฟล์ออก"
+rememberNoteVisibility: "จดจำการตั้งค่าการมองเห็นตัวโน้ต"
+attachCancel: "ลบไฟล์ออกที่แนบมา"
+deleteFile: "ลบไฟล์ออกแล้ว"
markAsSensitive: "ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน"
unmarkAsSensitive: "ยกเลิกทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน"
enterFileName: "พิมพ์ชื่อไฟล์"
@@ -142,20 +138,19 @@ mute: "ปิดเสียง"
unmute: "ยกเลิกการปิดเสียง"
renoteMute: "ปิดเสียงรีโน้ต"
renoteUnmute: "เปิดเสียง รีโน้ต"
-block: "บล็อก"
-unblock: "เลิกบล็อก"
-suspend: "ระงับ"
-unsuspend: "เลิกระงับ"
-blockConfirm: "ต้องการบล็อกบัญชีนี้ใช่ไหม?"
-unblockConfirm: "ต้องการเลิกบล็อกบัญชีนี้ใช่ไหม?"
-suspendConfirm: "ต้องการระงับบัญชีนี้ใช่ไหม?"
-unsuspendConfirm: "ต้องการยกเลิกการระงับบัญชีนี้ใช่ไหม?"
+block: "บล็อค"
+unblock: "เลิกปิดกั้น"
+suspend: "ถูกระงับ"
+unsuspend: "ยกเลิกระงับ"
+blockConfirm: "ต้องการบล็อกบัญชีนี้?"
+unblockConfirm: "ต้องการปลดบล็อคบัญชีนี้?"
+suspendConfirm: "ต้องการระงับบัญชีนี้?"
+unsuspendConfirm: "ต้องการยกเลิกการระงับบัญชีนี้?"
selectList: "เลือกรายชื่อ"
editList: "แก้ไขรายชื่อ"
selectChannel: "เลือกช่อง"
selectAntenna: "เลือกเสาอากาศ"
editAntenna: "แก้ไขเสาอากาศ"
-createAntenna: "สร้างเสาอากาศ"
selectWidget: "เลือกวิดเจ็ต"
editWidgets: "แก้ไขวิดเจ็ต"
editWidgetsExit: "เรียบร้อย"
@@ -167,52 +162,46 @@ emojiUrl: "URL ของเอโมจิ"
addEmoji: "แทรกเอโมจิ"
settingGuide: "การตั้งค่าที่แนะนำ"
cacheRemoteFiles: "แคชไฟล์ระยะไกล"
-cacheRemoteFilesDescription: "หากเปิดใช้งาน ไฟล์ระยะไกลจะถูกแคชไว้ ทำให้แสดงภาพเร็วขึ้น แต่ก็ใช้พื้นที่เก็บข้อมูลของเซิร์ฟเวอร์มากขึ้นเช่นกัน สำหรับขีดจำกัดที่ผู้ใช้ระยะไกลถูกแคชไว้จะขึ้นอยู่กับความจุไดรฟ์ตามบทบาทของเขา เมื่อเกินแล้วไฟล์เก่าจะถูกลบออกและเก็บเป็นลิงก์แทน หากปิดใช้งาน ไฟล์ระยะไกลจะถูกเก็บเป็นลิงก์ตั้งแต่ต้น เราแนะนำให้ตั้งค่า proxyRemoteFiles ใน default.yml เป็น true เพื่อสร้างธัมบ์เนลและปกป้องความเป็นส่วนตัวของผู้ใช้"
-youCanCleanRemoteFilesCache: "สามารถลบแคชทั้งหมดได้โดยใช้ปุ่ม 🗑️ ในหน้าการจัดการไฟล์"
-cacheRemoteSensitiveFiles: "แคชไฟล์ระยะไกลที่มีเนื้อหาละเอียดอ่อน"
-cacheRemoteSensitiveFilesDescription: "เมื่อปิดการใช้งานการตั้งค่านี้ ไฟล์ระยะไกลที่มีเนื้อหาละเอียดอ่อนจะถูกโหลดโดยตรงจากเซิร์ฟเวอร์ระยะไกลโดยไม่มีการแคช"
-flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอต"
-flagAsBotDescription: "เปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยโปรแกรม เมื่อเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นในการป้องกันการสร้างห่วงโซ่การโต้ตอบแบบอนันต์กับบอตตัวอื่น และปรับระบบภายในของ Misskey เพื่อจัดการบัญชีนี้ในฐานะบอต"
-flagAsCat: "เมี้ยววววววววววววววว!!!!!!!!!!!"
+cacheRemoteFilesDescription: "เมื่อปิดใช้งานการตั้งค่านี้ ไฟล์ระยะไกลนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกล แต่กรณีการปิดใช้งานนี้จะช่วยลดปริมาณการใช้พื้นที่จัดเก็บข้อมูล แต่เพิ่มปริมาณการใช้งาน เพราะเนื่องจากจะไม่มีการสร้างภาพขนาดย่อ"
+youCanCleanRemoteFilesCache: "คุณสามารถล้างแคชได้โดยคลิกที่ปุ่ม 🗑️ ในมุมมองการจัดการไฟล์"
+cacheRemoteSensitiveFiles: "แคชไฟล์ระยะไกลที่มีเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน"
+cacheRemoteSensitiveFilesDescription: "เมื่อปิดการใช้งานการตั้งค่านี้ ไฟล์ระยะไกลที่มีเครื่องหมายว่ามีเนื้อหาละเอียดอ่อนนั้นจะถูกโหลดโดยตรงจากอินสแตนซ์ระยะไกลโดยที่ไม่มีการแคช"
+flagAsBot: "ทำเครื่องหมายบอกว่าบัญชีนี้เป็นบอท"
+flagAsBotDescription: "การเปิดใช้งานตัวเลือกนี้หากบัญชีนี้ถูกควบคุมโดยนักเขียนโปรแกรม หรือ ถ้าหากเปิดใช้งาน มันจะทำหน้าที่เป็นแฟล็กสำหรับนักพัฒนารายอื่นๆ และเพื่อป้องกันการโต้ตอบแบบไม่มีที่สิ้นสุดกับบอทตัวอื่นๆ และยังสามารถปรับเปลี่ยนระบบภายในของ Misskey เพื่อปฏิบัติต่อบัญชีนี้เป็นบอท"
+flagAsCat: "เมี้ยววววววว!!!!!!!!!!! (ทำเครื่องหมายว่าบัญชีนี้เป็นแมว)"
flagAsCatDescription: "เหมียวเหมียวเมี้ยว??"
-flagShowTimelineReplies: "แสดงตอบกลับโน้ตลงไทม์ไลน์"
-flagShowTimelineRepliesDescription: "เมื่อเปิดใช้งาน จะแสดงการตอบกลับของผู้ใช้คนนั้นต่อโน้ตอื่นๆ ในไทม์ไลน์ด้วย"
-autoAcceptFollowed: "อนุมัติคำขอติดตามจากผู้ใช้ที่คุณติดตามอยู่โดยอัตโนมัติ"
+flagShowTimelineReplies: "แสดงตอบกลับ ในไทม์ไลน์"
+flagShowTimelineRepliesDescription: "แสดงการตอบกลับของผู้ใช้งานไปยังโน้ตของผู้ใช้งานรายอื่นๆในไทม์ไลน์หากได้เปิดเอาไว้"
+autoAcceptFollowed: "อนุมัติคำขอติดตามโดยอัตโนมัติทันที จากผู้ใช้งานที่คุณกำลังติดตาม"
addAccount: "เพิ่มบัญชี"
reloadAccountsList: "รีโหลดรายการบัญชีใหม่"
loginFailed: "การเข้าสู่ระบบไม่สำเร็จ"
-showOnRemote: "ดูบนเซิร์ฟเวอร์ฝั่งระยะไกล"
-continueOnRemote: "ดำเนินการต่อบนเซิร์ฟเวอร์ฝั่งระยะไกล"
-chooseServerOnMisskeyHub: "เลือกเซิร์ฟเวอร์จาก Misskey Hub"
-specifyServerHost: "ระบุโดเมนของเซิร์ฟเวอร์โดยตรง"
-inputHostName: "โปรดป้อนโดเมน"
+showOnRemote: "ดูบนอินสแตนซ์ระยะไกล"
general: "ทั่วไป"
wallpaper: "ภาพพื้นหลัง"
setWallpaper: "ตั้งค่าภาพพื้นหลัง"
-removeWallpaper: "นำภาพพื้นหลังออก"
+removeWallpaper: "น้ำภาพพื้นหลังออก"
searchWith: "ค้นหา: {q}"
youHaveNoLists: "คุณไม่มีรายชื่อใดๆ "
followConfirm: "ต้องการติดตาม {name} ใช่ไหม?"
proxyAccount: "บัญชีพร็อกซี่"
-proxyAccountDescription: "บัญชีพร็อกซี คือ บัญชีที่ทำหน้าที่ติดตาม(ผู้ใช้)ระยะไกลภายใต้เงื่อนไขบางประการ ตัวอย่างเช่น เมื่อผู้ใช้ท้องถิ่นเพิ่มผู้ใช้ระยะไกลลงรายชื่อ หากไม่มีใครติดตามผู้ใช้ระยะไกลในรายชื่อนั้น กิจกรรมก็จะไม่ถูกส่งมายังเซิร์ฟเวอร์ ดังนั้นจึงมีบัญชีพร็อกซีไว้ติดตามผู้ใช้ระยะไกลเหล่านั้น"
+proxyAccountDescription: "บัญชีพร็อกซี่ คือ บัญชีที่จะทำหน้าที่เป็นผู้ติดตามระยะไกลสำหรับผู้ใช้งานที่อยู่ภายใต้ด้วยเงื่อนไขบางอย่าง ยกตัวอย่าง เช่น เมื่อมีผู้ใช้งานนั้นได้เพิ่มผู้ใช้งานจากระยะไกลลงในรายการ แต่กิจกรรมของผู้ใช้ในระยะไกลนั้นจะไม่ถูกส่งไปยังอินสแตนซ์หากไม่มีผู้ใช้งานในพื้นที่ติดตามผู้ใช้รายนั้น ดังนั้นบัญชีพร็อกซีนี้จะติดตามแทน"
host: "โฮสต์"
-selectSelf: "เลือกตัวเอง"
selectUser: "เลือกผู้ใช้งาน"
recipient: "ผู้รับ"
-annotation: "หมายเหตุประกอบ"
+annotation: "ความคิดเห็น"
federation: "สหพันธ์"
-instances: "เซิร์ฟเวอร์"
-registeredAt: "วันที่ลงทะเบียน"
-latestRequestReceivedAt: "คำขอล่าสุดที่ได้รับ"
+instances: "อินสแตนซ์"
+registeredAt: "จดทะเบียนที่"
+latestRequestReceivedAt: "ได้รับคำขอล่าสุดไปแล้ว"
latestStatus: "สถานะล่าสุด"
storageUsage: "พื้นที่จัดเก็บข้อมูลที่ใช้ไป"
-charts: "แผนภูมิ"
-perHour: "ต่อชั่วโมง"
+charts: "โดดเด่น"
+perHour: "ทุกชั่วโมง"
perDay: "ต่อวัน"
stopActivityDelivery: "หยุดส่งกิจกรรม"
-blockThisInstance: "บล็อกเซิร์ฟเวอร์นี้"
-silenceThisInstance: "ปิดปากเซิร์ฟเวอร์นี้"
-mediaSilenceThisInstance: "ปิดปากสื่อของเซิร์ฟเวอร์นี้"
+blockThisInstance: "บล็อกอินสแตนซ์นี้"
+silenceThisInstance: "ปิดปากอินสแตนซ์นี้"
operations: "ดำเนินการ"
software: "ซอฟต์แวร์"
version: "เวอร์ชั่น"
@@ -223,25 +212,23 @@ jobQueue: "คิวงาน"
cpuAndMemory: "ซีพียู และ หน่วยความจำ"
network: "เครือข่าย"
disk: "ดิสก์"
-instanceInfo: "ข้อมูลเซิร์ฟเวอร์"
+instanceInfo: "ข้อมูลอินสแตนซ์"
statistics: "สถิติการใช้งาน"
clearQueue: "ล้างคิว"
-clearQueueConfirmTitle: "ต้องการล้างคิวใช่ไหม?"
+clearQueueConfirmTitle: "คุณแน่ใจแล้วหรอว่าต้องการที่จะล้างคิว?"
clearQueueConfirmText: "โพสต์ที่ยังค้างในคิวจะไม่ถูกจัดส่งอีกต่อไป โดยปกติแล้วการดำเนินการนี้ไม่จำเป็น"
clearCachedFiles: "ล้างแคช"
-clearCachedFilesConfirm: "ต้องการลบไฟล์ระยะไกลที่แคชไว้ทั้งหมดใช่ไหม?"
-blockedInstances: "เซิร์ฟเวอร์ที่ถูกบล็อก"
-blockedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการบล็อก คั่นด้วยการขึ้นบรรทัดใหม่ เซิร์ฟเวอร์ที่ถูกบล็อกจะไม่สามารถติดต่อกับอินสแตนซ์นี้ได้"
-silencedInstances: "ปิดปากเซิร์ฟเวอร์นี้แล้ว"
-silencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการปิดปาก คั่นด้วยการขึ้นบรรทัดใหม่, บัญชีทั้งหมดของเซิร์ฟเวอร์ดังกล่าวจะถือว่าถูกปิดปากเช่นกัน ทำได้เฉพาะคำขอติดตามเท่านั้น และไม่สามารถกล่าวถึงบัญชีในเซิร์ฟเวอร์นี้ได้หากไม่ได้ถูกติดตามกลับ | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
-mediaSilencedInstances: "เซิร์ฟเวอร์ที่ถูกปิดปากสื่อ"
-mediaSilencedInstancesDescription: "ระบุโฮสต์ของเซิร์ฟเวอร์ที่ต้องการปิดปากสื่อ คั่นด้วยการขึ้นบรรทัดใหม่, ไฟล์ที่ถูกส่งจากบัญชีของเซิร์ฟเวอร์ดังกล่าวจะถือว่าถูกปิดปาก แล้วจะถูกติดเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน และเอโมจิแบบกำหนดเองก็จะใช้ไม่ได้ด้วย | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
+clearCachedFilesConfirm: "ต้องการลบไฟล์ระยะไกลที่แคชไว้ทั้งหมด?"
+blockedInstances: "อินสแตนซ์ที่ถูกบล็อก"
+blockedInstancesDescription: "ระบุชื่อโฮสต์ของอินสแตนซ์ที่คุณต้องการบล็อก อินสแตนซ์ที่อยู่ในรายการนั้นจะไม่สามารถพูดคุยกับอินสแตนซ์นี้ได้อีกต่อไป"
+silencedInstances: "ปิดปากอินสแตนซ์นี้แล้ว"
+silencedInstancesDescription: "ตั้งค่ารายชื่อโฮสต์ของอินสแตนซ์ที่คุณต้องการปิดปาก บัญชีทั้งหมดของอินสแตนซ์ที่อยู่ในรายชื่อนั้นๆ จะถือว่าถูกปิดปากเช่นกัน ทำได้เฉพาะคำขอติดตามเท่านั้น และไม่สามารถกล่าวถึงบัญชีในพื้นที่ได้หากไม่ได้ติดตาม | สิ่งนี้ไม่มีผลต่ออินสแตนซ์ที่ถูกบล็อก"
muteAndBlock: "ปิดเสียงและบล็อก"
mutedUsers: "ผู้ใช้ที่ถูกปิดเสียง"
blockedUsers: "ผู้ใช้ที่ถูกบล็อก"
noUsers: "ไม่พบผู้ใช้งาน"
editProfile: "แก้ไขโปรไฟล์"
-noteDeleteConfirm: "ต้องการลบโน้ตนี้ใช่ไหม?"
+noteDeleteConfirm: "ต้องการลบโน้ตนี้?"
pinLimitExceeded: "คุณไม่สามารถปักหมุดโน้ตเพิ่มเติมใดๆได้อีก"
intro: "การติดตั้ง Misskey เสร็จสิ้นแล้วนะ! โปรดสร้างผู้ใช้งานที่เป็นผู้ดูแลระบบ"
done: "เสร็จสิ้น"
@@ -250,17 +237,17 @@ preview: "แสดงตัวอย่าง"
default: "ค่าเริ่มต้น"
defaultValueIs: "ค่าเริ่มต้น: {value}"
noCustomEmojis: "ไม่มีเอโมจิ"
-noJobs: "ไม่มีงาน"
+noJobs: "ไม่มีชิ้นงาน"
federating: "สหพันธ์"
blocked: "ถูกบล็อก"
-suspended: "ระงับการส่ง"
+suspended: "ถูกระงับ"
all: "ทั้งหมด"
-subscribing: "กำลังสมัครสมาชิก"
+subscribing: "สมัครแล้ว"
publishing: "กำลังเผยแพร่"
notResponding: "ไม่มีการตอบสนอง"
-instanceFollowing: "กำลังติดตามบนเซิร์ฟเวอร์"
-instanceFollowers: "ผู้ติดตามของเซิร์ฟเวอร์"
-instanceUsers: "ผู้ใช้ของเซิร์ฟเวอร์นี้"
+instanceFollowing: "กำลังติดตามบนอินสแตนซ์"
+instanceFollowers: "ผู้ติดตามของอินสแตนซ์"
+instanceUsers: "ผู้ใช้งานของอินสแตนซ์นี้"
changePassword: "เปลี่ยนรหัสผ่าน"
security: "ความปลอดภัย"
retypedNotMatch: "ทั้งสองป้อนข้อมูลไม่สอดคล้องกัน"
@@ -274,11 +261,11 @@ usernameOrUserId: "ชื่อผู้ใช้หรือรหัสผู
noSuchUser: "ไม่พบผู้ใช้"
lookup: "การค้นหา"
announcements: "ประกาศ"
-imageUrl: "URL รูปภาพ"
+imageUrl: "url รูปภาพ"
remove: "ลบ"
removed: "ถูกลบไปแล้ว"
-removeAreYouSure: "ต้องการลบ “{x}” ใช่ไหม?"
-deleteAreYouSure: "ต้องการลบ “{x}” ใช่ไหม?"
+removeAreYouSure: "ต้องการที่จะลบ “{x}” ออก?"
+deleteAreYouSure: "ต้องการลบ {x} หรือไม่คะ?"
resetAreYouSure: "รีเซ็ตเลยไหม?"
areYouSure: "แน่ใจแล้วใช่ไหมคะ?"
saved: "บันทึกแล้ว"
@@ -288,7 +275,7 @@ keepOriginalUploading: "เก็บภาพต้นฉบับ"
keepOriginalUploadingDescription: "เก็บภาพต้นฉบับไว้เมื่ออัปโหลดภาพ หากปิด รูปภาพสำหรับการเผยแพร่ทางเว็บจะถูกสร้างขึ้นในเบราว์เซอร์เมื่อทำการอัปโหลด"
fromDrive: "จากไดรฟ์"
fromUrl: "จาก URL"
-uploadFromUrl: "อัปโหลดจาก URL"
+uploadFromUrl: "อัพโหลดจาก URL"
uploadFromUrlDescription: "URL ของไฟล์ที่คุณต้องการอัปโหลด"
uploadFromUrlRequested: "ร้องขอการอัปโหลดแล้ว"
uploadFromUrlMayTakeTime: "การอัปโหลดอาจใช้เวลาสักครู่จึงจะเสร็จสมบูรณ์"
@@ -297,20 +284,20 @@ messageRead: "อ่านแล้ว"
noMoreHistory: "ไม่มีประวัติเพิ่มเติม"
startMessaging: "เริ่มการสนทนา"
nUsersRead: "อ่านโดย {n}"
-agreeTo: "ฉันยอมรับ {0}"
+agreeTo: "ฉันยอมรับที่จะ {0}"
agree: "ยอมรับ"
-agreeBelow: "ยอมรับตามที่ระบุด้านล่าง"
+agreeBelow: "ฉันยอมรับถึงด้านล่าง"
basicNotesBeforeCreateAccount: "หมายเหตุสำคัญ"
termsOfService: "เงื่อนไขการให้บริการ"
-start: "เริ่ม"
-home: "หน้าหลัก"
-remoteUserCaution: "ข้อมูลอาจไม่สมบูรณ์เนื่องจากผู้ใช้รายนี้มาจากเซิร์ฟเวอร์ระยะไกล"
+start: "เริ่มต้นใช้งาน"
+home: "หน้าแรก"
+remoteUserCaution: "ข้อมูลอาจไม่สมบูรณ์เนื่องจากผู้ใช้รายนี้มาจากอินสแตนซ์ระยะไกล"
activity: "กิจกรรม"
images: "รูปภาพ"
image: "รูปภาพ"
birthday: "วันเกิด"
yearsOld: "{age} ปี"
-registeredDate: "วันที่ลงทะเบียน"
+registeredDate: "วันที่สมัครสมาชิก"
location: "ตำแหน่งที่ตั้ง"
theme: "ธีม"
themeForLightMode: "ธีมที่จะใช้ในโหมดสว่าง"
@@ -326,7 +313,6 @@ selectFile: "เลือกไฟล์"
selectFiles: "เลือกไฟล์"
selectFolder: "เลือกโฟลเดอร์"
selectFolders: "เลือกโฟลเดอร์"
-fileNotSelected: "ยังไม่ได้เลือกไฟล์"
renameFile: "เปลี่ยนชื่อไฟล์"
folderName: "ชื่อโฟลเดอร์"
createFolder: "สร้างโฟลเดอร์"
@@ -347,21 +333,21 @@ rename: "เปลี่ยนชื่อ"
avatar: "ไอคอน"
banner: "แบนเนอร์"
displayOfSensitiveMedia: "แสดงสื่อที่มีเนื้อหาละเอียดอ่อน"
-whenServerDisconnected: "เมื่อสูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์"
-disconnectedFromServer: "การเชื่อมต่อเซิร์ฟเวอร์ถูกตัด"
+whenServerDisconnected: "สูญเสียการเชื่อมต่อกับเซิร์ฟเวอร์"
+disconnectedFromServer: "ถูกตัดการเชื่อมต่อออกจากเซิร์ฟเวอร์"
reload: "รีโหลด"
-doNothing: "ช่างมัน"
-reloadConfirm: "รีโหลดเลยไหม?"
-watch: "เพ่งเล็ง"
-unwatch: "เลิกเพ่งเล็ง"
+doNothing: "เมิน"
+reloadConfirm: "นายต้องการรีเฟรชไทม์ไลน์หรือป่าว?"
+watch: "ดู"
+unwatch: "หยุดดู"
accept: "ยอมรับ"
reject: "ปฏิเสธ"
normal: "ปกติ"
-instanceName: "ชื่อเซิร์ฟเวอร์"
-instanceDescription: "คำอธิบายแนะนำเซิร์ฟเวอร์"
+instanceName: "ชื่ออินสแตนซ์"
+instanceDescription: "คำอธิบายอินสแตนซ์"
maintainerName: "ผู้ดูแล"
maintainerEmail: "อีเมลผู้ดูแลระบบ"
-tosUrl: "URL เงื่อนไขการให้บริการ"
+tosUrl: "เงื่อนไขการให้บริการ URL"
thisYear: "ปีนี้"
thisMonth: "เดือนนี้"
today: "วันนี้"
@@ -369,25 +355,25 @@ dayX: "{day}"
monthX: "เดือน {month}"
yearX: "{year}"
pages: "หน้าเพจ"
-integration: "เชื่อมโยง"
+integration: "รวบรวม"
connectService: "เชื่อมต่อ"
disconnectService: "ตัดการเชื่อมต่อ"
-enableLocalTimeline: "เปิดใช้งานไทม์ไลน์ท้องถิ่น"
+enableLocalTimeline: "เปิดใช้งานไทม์ไลน์ในพื้นที่"
enableGlobalTimeline: "เปิดใช้งานไทม์ไลน์ทั่วโลก"
disablingTimelinesInfo: "ผู้ดูแลระบบและผู้ควบคุมจะสามารถเข้าถึงไทม์ไลน์ทั้งหมด ถึงแม้ว่าจะไม่ได้เปิดใช้งานก็ตาม"
registration: "ลงทะเบียน"
enableRegistration: "เปิดใช้งานการลงทะเบียนผู้ใช้ใหม่"
invite: "คำเชิญ"
-driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ท้องถิ่น"
+driveCapacityPerLocalAccount: "ความจุของไดรฟ์ต่อผู้ใช้ภายในเครื่อง"
driveCapacityPerRemoteAccount: "ความจุของไดรฟ์ต่อผู้ใช้ระยะไกล"
inMb: "เป็นเมกะไบต์"
bannerUrl: "URL รูปภาพแบนเนอร์"
backgroundImageUrl: "URL ภาพพื้นหลัง"
basicInfo: "ข้อมูลเบื้องต้น"
-pinnedUsers: "ผู้ใช้ที่ถูกปักหมุด"
+pinnedUsers: "ผู้ใช้งานที่ได้รับการปักหมุด"
pinnedUsersDescription: "ป้อนชื่อผู้ใช้ที่คุณต้องการปักหมุดในหน้า “ค้นพบ” ฯลฯ คั่นด้วยการขึ้นบรรทัดใหม่"
pinnedPages: "หน้าเพจที่ปักหมุด"
-pinnedPagesDescription: "ป้อนเส้นทางของหน้าเพจที่คุณต้องการปักหมุดไว้ที่หน้าแรกของเซิร์ฟเวอร์นี้ คั่นด้วยการขึ้นบรรทัดใหม่"
+pinnedPagesDescription: "ป้อนเส้นทางของหน้าเพจที่คุณต้องการปักหมุดไว้ที่หน้าแรกของอินสแตนซ์นี้ คั่นด้วยขึ้นบรรทัดใหม่"
pinnedClipId: "ID ของคลิปที่จะปักหมุด"
pinnedNotes: "โน้ตที่ปักหมุดไว้"
hcaptcha: "hCaptcha"
@@ -403,19 +389,18 @@ recaptcha: "reCAPTCHA"
enableRecaptcha: "เปิดใช้ reCAPTCHA"
recaptchaSiteKey: "คีย์ไซต์"
recaptchaSecretKey: "คีย์ลับ"
-turnstile: "Turnstile"
-enableTurnstile: "เปิดใช้งาน Turnstile"
+turnstile: "เทิร์น'สไทล"
+enableTurnstile: "เปิดใช้งาน เทิร์น'สไทล"
turnstileSiteKey: "คีย์ไซต์"
turnstileSecretKey: "คีย์ลับ"
-avoidMultiCaptchaConfirm: "การใช้ Captcha หลายตัวอาจทำให้เกิดการรบกวนหรือข้อผิดพลาดได้ ต้องการที่จะปิดการใช้งาน Captcha ตัวอื่นเลยไหม? หากต้องการให้เปิดใช้งานต่อไป ให้กดยกเลิก"
+avoidMultiCaptchaConfirm: "การใช้ระบบ Captcha หลายระบบอาจทำให้เกิดการรบกวนหรืออาจจะเกิดข้อผิดพลาดได้ หากต้องการที่จะปิดการใช้งานระบบ Captcha อื่น ๆ แนะนำให้ปิดตัวอื่นๆก่อน ถ้าหากคุณต้องการให้เปิดใช้งานต่อไป ให้ กด ยกเลิก"
antennas: "เสาอากาศ"
manageAntennas: "จัดการเสาอากาศ"
name: "ชื่อ"
antennaSource: "แหล่งเสาอากาศ"
antennaKeywords: "คีย์เวิร์ดที่ควรฟัง"
antennaExcludeKeywords: "คีย์เวิร์ดที่จะยกเว้น"
-antennaExcludeBots: "ยกเว้นบัญชีบอต"
-antennaKeywordsDescription: "คั่นด้วยเว้นวรรคสำหรับเงื่อนไข AND, หรือขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
+antennaKeywordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
notifyAntenna: "แจ้งเตือนเกี่ยวกับโน้ตใหม่"
withFileAntenna: "เฉพาะโน้ตที่มีไฟล์"
enableServiceworker: "เปิดใช้งานการแจ้งเตือนแบบพุชไปยังเบราว์เซอร์ของคุณ"
@@ -424,16 +409,16 @@ caseSensitive: "อักษรพิมพ์ใหญ่-พิมพ์เล
withReplies: "รวมตอบกลับ"
connectedTo: "บัญชีดังต่อไปนี้มีการเชื่อมต่อกัน"
notesAndReplies: "โพสต์และการตอบกลับ"
-withFiles: "มีไฟล์"
+withFiles: "รวบรวมไฟล์"
silence: "ถูกปิดปาก"
-silenceConfirm: "ต้องการปิดปากผู้ใช้รายนี้ใช่ไหม?"
+silenceConfirm: "ต้องการที่จะ ปิดปาก ผู้ใช้รายนี้?"
unsilence: "ยกเลิกการปิดปาก"
-unsilenceConfirm: "ต้องการเลิกปิดปากผู้ใช้รายนี้ใช่ไหม?"
+unsilenceConfirm: "ต้องการยกเลิกปิดปากผู้ใช้รายนี้?"
popularUsers: "ผู้ใช้ที่เป็นที่นิยม"
recentlyUpdatedUsers: "ผู้ใช้ที่เพิ่งใช้งานล่าสุด"
recentlyRegisteredUsers: "ผู้ใช้ที่เข้าร่วมใหม่"
-recentlyDiscoveredUsers: "ผู้ใช้ที่เพิ่งค้นพบล่าสุด"
-exploreUsersCount: "มีผู้ใช้ {count} ราย"
+recentlyDiscoveredUsers: "ผู้ใช้ที่เพิ่งค้นพบใหม่"
+exploreUsersCount: "มีผู้ใช้ {จำนวน} ราย"
exploreFediverse: "สำรวจสหพันธ์"
popularTags: "แท็กยอดนิยม"
userList: "ลิสต์"
@@ -449,8 +434,8 @@ moderator: "ผู้ควบคุม"
moderation: "การกลั่นกรอง"
moderationNote: "โน้ตการกลั่นกรอง"
addModerationNote: "เพิ่มโน้ตการกลั่นกรอง"
-moderationLogs: "ปูมการควบคุมดูแล"
-nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} ราย"
+moderationLogs: "ปูมการแก้ไข"
+nUsersMentioned: "กล่าวถึงโดยผู้ใช้ {n} รายนี้"
securityKeyAndPasskey: "ความปลอดภัยและรหัสผ่าน"
securityKey: "กุญแจความปลอดภัย"
lastUsed: "ใช้ล่าสุด"
@@ -464,7 +449,7 @@ reduceUiAnimation: "ลดภาพเคลื่อนไหว UI"
share: "แบ่งปัน"
notFound: "ไม่พบหน้าที่ต้องการ"
notFoundDescription: "ไม่พบหน้าตาม URL ที่ระบุ"
-uploadFolder: "โฟลเดอร์เริ่มต้นสำหรับอัปโหลด"
+uploadFolder: "โฟลเดอร์เริ่มต้นสำหรับอัพโหลด"
markAsReadAllNotifications: "ทำเครื่องหมายการแจ้งเตือนทั้งหมดว่าอ่านแล้ว"
markAsReadAllUnreadNotes: "ทำเครื่องหมายโน้ตทั้งหมดว่าอ่านแล้ว"
markAsReadAllTalkMessages: "ทำเครื่องหมายข้อความทั้งหมดว่าอ่านแล้ว"
@@ -479,48 +464,46 @@ text: "ข้อความ"
enable: "เปิดใช้งาน"
next: "ถัดไป"
retype: "พิมพ์รหัสอีกครั้ง"
-noteOf: "โน้ตของ {user}"
+noteOf: "โน้ต โดย {user}"
quoteAttached: "อ้างอิง"
quoteQuestion: "ต้องการที่จะแนบมันเพื่ออ้างอิงใช่ไหม?"
-attachAsFileQuestion: "ข้อความในคลิปบอร์ดยาวเกินไป คุณต้องการแนบเป็นไฟล์ข้อความหรือไม่?"
noMessagesYet: "ยังไม่มีข้อความ"
newMessageExists: "คุณมีข้อความใหม่"
onlyOneFileCanBeAttached: "สามารถแนบไฟล์ได้เพียงไฟล์เดียวต่อ 1 ข้อความ"
-signinRequired: "ก่อนดำเนินการต่อ กรุณาลงทะเบียนหรือเข้าสู่ระบบ"
-signinOrContinueOnRemote: "เพื่อดำเนินการต่อได้ คุณต้องไปที่เซิร์ฟเวอร์ที่คุณใช้งานอยู่ หรือลงทะเบียน/เข้าสู่ระบบเซิร์ฟเวอร์นี้"
+signinRequired: "กรุณาลงทะเบียนหรือลงชื่อเข้าใช้ก่อนดำเนินการต่อ"
invitations: "คำเชิญ"
-invitationCode: "รหัสเชิญ"
+invitationCode: "รหัสคำเชิญ"
checking: "Checking"
available: "พร้อมใช้งาน"
unavailable: "ไม่พร้อมใช้"
-usernameInvalidFormat: "สามารถใช้ a~z A~Z 0~9 และ _ ได้"
+usernameInvalidFormat: "คุณสามารถใช้อักษรตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก ตัวเลข และขีดล่างได้นะ ( a-z , A-Z , 0-9 , รวมไปถึงอักษรพิเศษเช่น + * / , . - อื่นๆเป็นต้น )"
tooShort: "สั้นเกินไปนะ"
tooLong: "ยาวเกินไปนะ"
-weakPassword: "รหัสผ่านแย่มาก"
+weakPassword: "รหัสผ่าน แย่มาก"
normalPassword: "รหัสผ่านปกติ"
strongPassword: "รหัสผ่านรัดกุมมาก"
passwordMatched: "ถูกต้อง!"
passwordNotMatched: "ไม่ถูกต้อง"
-signinWith: "เข้าสู่ระบบด้วย {x}"
-signinFailed: "ไม่สามารถเข้าสู่ระบบได้ กรุณาตรวจสอบชื่อผู้ใช้และรหัสผ่าน"
+signinWith: "ลงชื่อเข้าใช้ด้วย {x}"
+signinFailed: "ไม่สามารถลงชื่อผู้เข้าใช้ได้ เนื่องจาก ชื่อผู้ใช้หรือรหัสผ่านที่คุณป้อนนั้นไม่ถูกต้องนะ"
or: "หรือ"
language: "ภาษา"
uiLanguage: "ภาษาอินเทอร์เฟซผู้ใช้งาน"
aboutX: "เกี่ยวกับ {x}"
-emojiStyle: "สไตล์ของเอโมจิ"
+emojiStyle: "สไตล์เอโมจิ"
native: "ภาษาแม่"
-showNoteActionsOnlyHover: "แสดงการดำเนินการโน้ตเมื่อโฮเวอร์(วางเมาส์เหนือ)เท่านั้น"
-showReactionsCount: "แสดงจำนวนรีแอกชั่นในโน้ต"
+disableDrawer: "อย่าใช้ลิ้นชักสไตล์เมนู"
+showNoteActionsOnlyHover: "แสดงการดำเนินการเฉพาะโน้ตเมื่อโฮเวอร์"
noHistory: "ไม่มีประวัติ"
signinHistory: "ประวัติการเข้าสู่ระบบ"
enableAdvancedMfm: "เปิดใช้งาน MFM ขั้นสูง"
-enableAnimatedMfm: "เปิดการใช้งาน MFM แบบเคลื่อนไหว"
+enableAnimatedMfm: "เปิดการใช้งาน MFM ด้วยแอนิเมชั่น"
doing: "กำลังประมวลผล......"
category: "หมวดหมู่"
tags: "นามแฝง"
docSource: "ที่มาของเอกสารนี้"
createAccount: "สร้างบัญชี"
-existingAccount: "บัญชีที่มีอยู่แล้ว"
+existingAccount: "บัญชีที่มีอยู่"
regenerate: "สร้างอีกครั้ง"
fontSize: "ขนาดตัวอักษร"
mediaListWithOneImageAppearance: "ความสูงของรายการสื่อที่มีเพียงรูปเดียว"
@@ -528,11 +511,11 @@ limitTo: "จำกัดไว้ที่ {x}"
noFollowRequests: "คุณไม่มีคำขอติดตามที่รอดำเนินการ"
openImageInNewTab: "เปิดรูปภาพในแท็บใหม่"
dashboard: "หน้ากระดานหลัก"
-local: "ท้องถิ่น"
+local: "ในพื้นที่"
remote: "ระยะไกล"
total: "รวมทั้งหมด"
-weekOverWeekChanges: "เทียบกับสัปดาห์ก่อน"
-dayOverDayChanges: "เทียบกับเมื่อวาน"
+weekOverWeekChanges: "เปลี่ยนแปลงไปเมื่อสัปดาห์ที่แล้ว"
+dayOverDayChanges: "เปลี่ยนแปลงไปเมื่อวานนี้"
appearance: "ภาพลักษณ์"
clientSettings: "การตั้งค่าไคลเอนต์"
accountSettings: "ตั้งค่าบัญชี"
@@ -546,19 +529,19 @@ useObjectStorage: "ใช้การจัดเก็บในรูปแบ
objectStorageBaseUrl: "Base URL"
objectStorageBaseUrlDesc: "URL ที่ใช้เป็นข้อมูลอ้างอิง ระบุ URL ของ CDN หรือ Proxy ถ้าหากคุณใช้อย่างใดอย่างหนึ่ง\n สำหรับการใช้งาน S3 'https://.s3.amazonaws.com' และสำหรับ GCS หรือบริการที่เทียบเท่าใช้ 'https://storage.googleapis.com/', เป็นต้น"
objectStorageBucket: "Bucket"
-objectStorageBucketDesc: "โปรดระบุชื่อบัคเก็ตของบริการที่ใช้อยู่"
+objectStorageBucketDesc: "โปรดระบุชื่อที่เก็บข้อมูลที่ใช้กับผู้ให้บริการของคุณ"
objectStoragePrefix: "คำนำหน้า"
objectStoragePrefixDesc: "ไฟล์ทั้งหมดจะถูกเก็บไว้ภายใต้ไดเร็กทอรีที่มีคำนำหน้านี้"
objectStorageEndpoint: "ปลายทาง"
objectStorageEndpointDesc: "เว้นว่างไว้หากคุณใช้ AWS S3 หรือระบุปลายทางเป็น '' หรือ ':' ทั้งนี้ขึ้นอยู่กับผู้ให้บริการที่คุณใช้อยู่ด้วย"
objectStorageRegion: "ภูมิภาค"
-objectStorageRegionDesc: "ระบุภูมิภาค เช่น ‘xx-east-1’ หากบริการของคุณไม่แยกภูมิภาค ให้ระบุเป็น ‘us-east-1’ หรือเว้นวางไว้หากใช้ AWS configuration files / environment variables"
+objectStorageRegionDesc: "ระบุภูมิภาค เช่น 'xx-east-1' ถ้าหากบริการของคุณไม่ได้แยกความแตกต่างระหว่างภูมิภาคก็ให้ เว้นว่างไว้หรือป้อน 'us-east-1'"
objectStorageUseSSL: "ใช้ SSL"
objectStorageUseSSLDesc: "ปิดการทำงานนี้ไว้ ถ้าหากคุณจะไม่ใช้ HTTPS สำหรับการเชื่อมต่อ API"
objectStorageUseProxy: "เชื่อมต่อผ่านพร็อกซี"
objectStorageUseProxyDesc: "ปิดสิ่งนี้ไว้ถ้าหากคุณจะไม่ใช้ Proxy สำหรับการเชื่อมต่อ API"
objectStorageSetPublicRead: "ตั้งค่าเป็น “public-read” เมื่ออัปโหลด"
-s3ForcePathStyleDesc: "เมื่อเปิดใช้งาน s3ForcePathStyle จะบังคับให้ ระบุชื่อบัคเก็ตเป็นส่วนหนึ่งของพาธ แทนที่จะเป็นชื่อโฮสต์ใน URL, อาจจำเป็นต้องเปิดใช้งานตัวเลือกนี้เมื่อใช้กับ Minio ที่โฮสต์เองหรือบริการที่คล้ายกัน"
+s3ForcePathStyleDesc: "ถ้าหากเปิดใช้งาน s3ForcePathStyle ชื่อบัคเก็ตนั้นอาจจะต้องรวมอยู่ในเส้นทางของ URL ซึ่งตรงข้ามกับชื่อโฮสต์ของ URL คุณอาจจะต้องเปิดใช้งานการตั้งค่านี้เมื่อใช้บริการต่างๆ เช่น อินสแตนซ์ Minio ที่โฮสต์เองนะ"
serverLogs: "ปูมของเซิร์ฟเวอร์"
deleteAll: "ลบทั้งหมด"
showFixedPostForm: "แสดงแบบฟอร์มการโพสต์ที่ด้านบนสุดของไทม์ไลน์"
@@ -574,7 +557,7 @@ popout: "ป๊อปเอาต์"
volume: "ระดับเสียง"
masterVolume: "ระดับเสียงหลัก"
notUseSound: "ไม่ใช้เสียง"
-useSoundOnlyWhenActive: "มีเสียงออกเฉพาะตอนกำลังใช้ Misskey อยู่เท่านั้น"
+useSoundOnlyWhenActive: "มีเสียงออกเฉพาะเมื่อ Misskey ทำงานอยู่"
details: "รายละเอียด"
chooseEmoji: "เลือกเอโมจิ"
unableToProcess: "ไม่สามารถดำเนินการให้เสร็จสิ้นได้"
@@ -587,37 +570,37 @@ installedDate: "วันที่ติดตั้ง"
lastUsedDate: "ใช้งานครั้งล่าสุด"
state: "สถานะ"
sort: "เรียงลำดับ"
-ascendingOrder: "เรียงลำดับขึ้น"
-descendingOrder: "เรียงลำดับลง"
+ascendingOrder: "เรียงจากน้อยไปมาก"
+descendingOrder: "เรียงจากมากไปน้อย"
scratchpad: "Scratchpad"
-scratchpadDescription: "Scratchpad ให้สภาพแวดล้อมสำหรับการทดลอง AiScript คุณสามารถเขียนโค้ด/สั่งดำเนินการ/ตรวจสอบผลลัพธ์ ของการโต้ตอบกับ Misskey ได้"
+scratchpadDescription: "Scratchpad เป็นการจัดเตรียมสภาพแวดล้อมสำหรับการทดลอง AiScript แต่คุณสามารถเขียน ดำเนินการ และตรวจสอบผลลัพธ์ของการโต้ตอบกับ Misskey มันได้ด้วยนะ"
output: "เอาท์พุต"
script: "สคริปต์"
disablePagesScript: "ปิดการใช้งาน AiScript บนเพจ"
updateRemoteUser: "อัปเดตข้อมูลผู้ใช้งานระยะไกล"
unsetUserAvatar: "เลิกตั้งอวตาร"
-unsetUserAvatarConfirm: "ต้องการเลิกตั้งอวตารใข่ไหม?"
+unsetUserAvatarConfirm: "ต้องการเลิกตั้งอวตาร?"
unsetUserBanner: "เลิกตั้งแบนเนอร์"
unsetUserBannerConfirm: "ต้องการเลิกตั้งแบนเนอร์?"
deleteAllFiles: "ลบไฟล์ทั้งหมด"
-deleteAllFilesConfirm: "ต้องการลบไฟล์ทั้งหมดใช่ไหม?"
+deleteAllFilesConfirm: "ต้องการลบไฟล์ทั้งหมดหรือไม่?"
removeAllFollowing: "เลิกติดตามผู้ใช้ที่ติดตามทั้งหมด"
-removeAllFollowingDescription: "จะเลิกติดตามทั้งหมดจาก {host} โปรดดำเนินการสิ่งนี้เมื่อเซิร์ฟเวอร์ดังกล่าวได้สูญหายตายจากไปแล้ว"
+removeAllFollowingDescription: "เลิกติดตามทั้งหมดจาก {host} โปรดเรียกใช้สิ่งนี้เมื่ออินสแตนซ์ดังกล่าวได้สูญหายตายจากไปแล้ว"
userSuspended: "ผู้ใช้รายนี้ถูกระงับการใช้งาน"
-userSilenced: "ผู้ใช้รายนี้ถูกปิดปากอยู่"
+userSilenced: "ผู้ใช้รายนี้กำลังถูกปิดกั้น"
yourAccountSuspendedTitle: "บัญชีนี้นั้นถูกระงับ"
yourAccountSuspendedDescription: "บัญชีนี้ถูกระงับ เนื่องจากละเมิดข้อกำหนดในการให้บริการของเซิร์ฟเวอร์หรืออาจจะละเมิดหลักเกณฑ์ชุมชน หรือ อาจจะโดนร้องเรียนเรื่องการละเมิดลิขสิทธิ์และอื่นๆอย่างต่อเนื่องซ้ำๆ หากคุณคิดว่าไม่ได้ทำผิดจริงๆหรือตัดสินผิดพลาด ได้โปรดกรุณาติดต่อผู้ดูแลระบบหากคุณต้องการทราบเหตุผลโดยละเอียดเพิ่มเติม และขอความกรุณาอย่าสร้างบัญชีใหม่"
tokenRevoked: "โทเค็นไม่ถูกต้อง"
-tokenRevokedDescription: "โทเค็นการเข้าสู่ระบบหมดอายุ กรุณาเข้าสู่ระบบใหม่อีกครั้ง"
+tokenRevokedDescription: "โทเค็นนี้หมดอายุแล้วนะค่ะกรุณาเข้าสู่ระบบอีกครั้งนะ"
accountDeleted: "ลบบัญชีแล้ว"
-accountDeletedDescription: "บัญชีนี้ถูกลบแล้ว"
+accountDeletedDescription: "บัญชีนี้ถูกลบไปแล้วนะ"
menu: "เมนู"
divider: "ตัวแบ่ง"
addItem: "เพิ่มรายการ"
rearrange: "จัดใหม่"
relays: "รีเลย์"
addRelay: "เพิ่มรีเลย์"
-inboxUrl: "URL ของอินบ็อกซ์"
+inboxUrl: "อินบ็อกซ์ URL"
addedRelays: "เพิ่มรีเลย์แล้ว"
serviceworkerInfo: "ต้องเปิดใช้งานสำหรับการแจ้งเตือนแบบพุช"
deletedNote: "โน้ตที่ถูกลบ"
@@ -630,14 +613,14 @@ enablePlayer: "เปิดเครื่องเล่นวิดีโอ"
disablePlayer: "ปิดเครื่องเล่นวิดีโอ"
expandTweet: "ขยายทวีต"
themeEditor: "ตัวแก้ไขธีม"
-description: "คำอธิบาย"
+description: "รายละเอียด"
describeFile: "เพิ่มแคปชั่น"
enterFileDescription: "ใส่แคปชั่น"
author: "ผู้เขียน"
-leaveConfirm: "มีการเปลี่ยนแปลงที่ยังไม่ได้บันทึก ต้องการละทิ้งมันใช่ไหม?"
+leaveConfirm: "คุณมีการเปลี่ยนแปลงที่ไม่ได้บันทึกนะ นายต้องการทิ้งการเปลี่ยนแปลงเหล่านั้นหรอ?"
manage: "การจัดการ"
plugins: "ปลั๊กอิน"
-preferencesBackups: "สำรองการตั้งค่า"
+preferencesBackups: "ตั้งค่าการสำรองข้อมูล"
deck: "เด็ค"
undeck: "ออกจากเด็ค"
useBlurEffectForModal: "ใช้เอฟเฟกต์เบลอสำหรับโมดอล"
@@ -647,21 +630,21 @@ height: "ความสูง"
large: "ใหญ่"
medium: "ปานกลาง"
small: "เล็ก"
-generateAccessToken: "สร้างโทเค็นการเข้าถึง"
-permission: "สิทธิ์"
+generateAccessToken: "สร้างการเข้าถึงโทเค็น"
+permission: "การอนุญาต"
adminPermission: "สิทธิ์ของผู้ดูแลระบบ"
enableAll: "เปิดใช้งานทั้งหมด"
disableAll: "ปิดการใช้งานทั้งหมด"
tokenRequested: "ให้สิทธิ์การเข้าถึงบัญชี"
-pluginTokenRequestedDescription: "ปลั๊กอินนี้จะใช้สิทธิ์ตามที่ตั้งค่าไว้ที่นี่"
+pluginTokenRequestedDescription: "ปลั๊กอินนี้จะสามารถใช้การอนุญาตที่ตั้งค่าไว้ที่นี่นะ"
notificationType: "ประเภทการแจ้งเตือน"
edit: "แก้ไข"
-emailServer: "เซิร์ฟเวอร์ของอีเมล"
+emailServer: "อีเมลเซิร์ฟเวอร์"
enableEmail: "เปิดใช้งานการกระจายอีเมล"
-emailConfigInfo: "ใช้สำหรับการยืนยันอีเมลหรือการรีเซ็ตรหัสผ่าน"
+emailConfigInfo: "ใช้เพื่อยืนยันอีเมลของคุณระหว่างการสมัครหรือถ้าหากคุณลืมรหัสผ่าน"
email: "อีเมล"
emailAddress: "ที่อยู่อีเมล"
-smtpConfig: "ตั้งค่าเซิร์ฟเวอร์ SMTP"
+smtpConfig: "กำหนดค่าเซิร์ฟเวอร์ SMTP"
smtpHost: "โฮสต์"
smtpPort: "พอร์ต"
smtpUser: "ชื่อผู้ใช้"
@@ -671,17 +654,17 @@ smtpSecure: "ใช้โดยนัย SSL/TLS สำหรับการเ
smtpSecureInfo: "ปิดสิ่งนี้เมื่อใช้ STARTTLS"
testEmail: "ทดสอบการส่งอีเมล"
wordMute: "ปิดเสียงคำ"
-hardWordMute: "ปิดเสียงคำแบบแข็งโป๊ก"
-regexpError: "เกิดข้อผิดพลาดใน regular expression"
-regexpErrorDescription: "เกิดข้อผิดพลาดใน regular expression บรรทัดที่ {line} ของการปิดเสียงคำ {tab} :"
-instanceMute: "ปิดเสียงเซิร์ฟเวอร์"
+hardWordMute: "ปิดเสียงคำยาก"
+regexpError: "ข้อผิดพลาดของนิพจน์ทั่วไป"
+regexpErrorDescription: "เกิดข้อผิดพลาดในนิพจน์ทั่วไปในบรรทัดที่ {line} ของการปิดเสียงคำ {tab} ของคุณ:"
+instanceMute: "ปิดเสียง อินสแตนซ์"
userSaysSomething: "{name} พูดอะไรบางอย่าง"
makeActive: "เปิดใช้งาน"
display: "แสดงผล"
copy: "คัดลอก"
metrics: "เมตริก"
overview: "ภาพรวม"
-logs: "ปูม"
+logs: "บันทึกข้อมูลระบบ"
delayed: "ดีเลย์"
database: "ฐานข้อมูล"
channel: "ช่อง"
@@ -689,31 +672,34 @@ create: "สร้าง"
notificationSetting: "ตั้งค่าการแจ้งเตือน"
notificationSettingDesc: "เลือกประเภทการแจ้งเตือนที่ต้องการจะแสดง"
useGlobalSetting: "ใช้การตั้งค่าส่วนกลาง"
-useGlobalSettingDesc: "เมื่อเปิดใช้งาน ใช้การตั้งค่าการแจ้งเตือนจากบัญชีคุณ เมื่อปิดใช้งาน สามารถตั้งค่าได้อย่างอิสระ"
+useGlobalSettingDesc: "หากเปิดไว้ ระบบจะใช้การตั้งค่าการแจ้งเตือนของบัญชีของคุณ หากปิดอยู่ สามารถทำการกำหนดค่าแต่ละรายการได้นะ"
other: "อื่น ๆ"
regenerateLoginToken: "สร้างโทเค็นการเข้าสู่ระบบอีกครั้ง"
regenerateLoginTokenDescription: "สร้างโทเค็นใหม่ที่ใช้ภายในระหว่างการเข้าสู่ระบบ โดยตามหลักปกติแล้วการดำเนินการนี้ไม่จำเป็น หากสร้างใหม่ อุปกรณ์ทั้งหมดจะถูกออกจากระบบนะ"
-theKeywordWhenSearchingForCustomEmoji: "คีย์เวิร์ดสำหรับใช้ค้นหาเอโมจิที่กำหนดเอง"
+theKeywordWhenSearchingForCustomEmoji: "คีย์เวิร์ดสำหรับใช้ค้นหาอีโมจิที่กำหนดเอง"
setMultipleBySeparatingWithSpace: "คั่นหลายรายการด้วยช่องว่าง"
-fileIdOrUrl: "ID ของไฟล์ หรือ URL"
+fileIdOrUrl: "ไฟล์ ID หรือ URL"
behavior: "พฤติกรรม"
sample: "ตัวอย่าง"
abuseReports: "รายงาน"
reportAbuse: "รายงาน"
reportAbuseRenote: "รายงานรีโน้ต"
-reportAbuseOf: "รายงาน {name}"
+reportAbuseOf: "รายงาน {ชื่อ}"
fillAbuseReportDescription: "กรุณากรอกรายละเอียดเกี่ยวกับรายงานนี้ หากเป็นเรื่องเกี่ยวกับโน้ตโดยเฉพาะ ได้โปรดระบุ URL"
abuseReported: "เราได้ส่งรายงานของคุณไปแล้ว ขอบคุณมากๆนะ"
-reporter: "ผู้รายงาน"
-reporteeOrigin: "ปลายทางรายงาน"
-reporterOrigin: "แหล่งผู้รายงาน"
+reporter: "นักข่าว"
+reporteeOrigin: "รายงานต้นทาง"
+reporterOrigin: "นักข่าวต้นทาง"
+forwardReport: "ส่งต่อรายงานไปยังอินสแตนซ์ระยะไกล"
+forwardReportIsAnonymous: "แทนที่จะเป็นบัญชีของคุณ บัญชีระบบที่ไม่ระบุตัวตนจะแสดงเป็นนักข่าวที่อินสแตนซ์ระยะไกล"
send: "ส่ง"
+abuseMarkAsResolved: "ทำเครื่องหมายรายงานว่าแก้ไขแล้ว"
openInNewTab: "เปิดในแท็บใหม่"
openInSideView: "เปิดในมุมมองด้านข้าง"
defaultNavigationBehaviour: "พฤติกรรมการนำทางที่เป็นค่าเริ่มต้น"
editTheseSettingsMayBreakAccount: "การแก้ไขการตั้งค่าเหล่านี้อาจทำให้บัญชีของคุณเสียหายนะ"
-instanceTicker: "ข้อมูลเซิร์ฟเวอร์ของโน้ต"
-waitingFor: "กำลังรอ {x}"
+instanceTicker: "ข้อมูลอินสแตนซ์ของโน้ต"
+waitingFor: "กำลังรอคอย {x}"
random: "สุ่มค่า"
system: "ระบบ"
switchUi: "สลับ UI"
@@ -723,7 +709,7 @@ createNew: "สร้างใหม่"
optional: "ไม่บังคับ"
createNewClip: "สร้างคลิปใหม่"
unclip: "ลบคลิป"
-confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป “{name}” อยู่แล้ว ต้องการนำมันออกจากคลิปใช่ไหม?"
+confirmToUnclipAlreadyClippedNote: "โน้ตนี้เป็นส่วนหนึ่งของคลิป \"{name}\" แล้ว คุณต้องการลบออกจากคลิปนี้แทนอย่างงั้นหรอ?"
public: "สาธารณะ"
private: "ส่วนตัว"
i18nInfo: "Misskey กำลังได้รับการแปลเป็นภาษาต่างๆ โดยอาสาสมัคร คุณสามารถช่วยเหลือได้ที่ {link}"
@@ -746,12 +732,12 @@ driveFilesCount: "จำนวนไฟล์ไดรฟ์"
driveUsage: "การใช้พื้นที่ไดรฟ์"
noCrawle: "ปฏิเสธการจัดทำดัชนีของโปรแกรมรวบรวมข้อมูล"
noCrawleDescription: "ขอให้เครื่องมือค้นหาไม่จัดทำดัชนีหน้าโปรไฟล์ โน้ต หน้าเพจ ฯลฯ"
-lockedAccountInfo: "แม้ว่าการอนุมัติการติดตามถูกเปิดใช้งานอยู่ทุกคนก็ยังคงสามารถเห็นโน้ตของคุณได้ เว้นแต่ว่าคุณจะเปลี่ยนการเปิดเผยโน้ตของคุณเป็น “เฉพาะผู้ติดตาม”"
+lockedAccountInfo: "เว้นแต่ว่าคุณจะต้องตั้งค่าการเปิดเผยโน้ตเป็น \"ผู้ติดตามเท่านั้น\" โน้ตย่อของคุณจะปรากฏแก่ทุกคน ถึงแม้ว่าคุณจะเป็นกำหนดให้ผู้ติดตามต้องได้รับการอนุมัติด้วยตนเองก็ตาม"
alwaysMarkSensitive: "ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อนเป็นค่าเริ่มต้น"
loadRawImages: "โหลดภาพต้นฉบับแทนการแสดงภาพขนาดย่อ"
disableShowingAnimatedImages: "ไม่ต้องเล่นภาพเคลื่อนไหว"
highlightSensitiveMedia: "ไฮไลท์สื่อที่มีเนื้อหาละเอียดอ่อน"
-verificationEmailSent: "ได้ส่งอีเมลยืนยันแล้ว กรุณาเข้าลิงก์ที่ระบุในอีเมลเพื่อทำการตั้งค่าให้เสร็จสิ้น"
+verificationEmailSent: "ส่งอีเมลยืนยันแล้วนะ ได้โปรดกรุณาไปที่ลิงก์ที่รวมไว้เพื่อทำการตรวจสอบให้เสร็จสิ้น"
notSet: "ไม่ได้ตั้งค่า"
emailVerified: "อีเมลได้รับการยืนยันแล้ว"
noteFavoritesCount: "จำนวนโน้ตที่ชื่นชอบ"
@@ -762,7 +748,7 @@ useSystemFont: "ใช้ฟอนต์เริ่มต้นของระ
clips: "คลิป"
experimentalFeatures: "ฟังก์ชั่นทดสอบ"
experimental: "ทดลอง"
-thisIsExperimentalFeature: "นี่เป็นฟีเจอร์ทดลอง ซึ่งอาจมีการเปลี่ยนแปลงการทำงาน และอาจไม่ทำงานตามที่ตั้งใจไว้"
+thisIsExperimentalFeature: "นี่คือฟีเจอร์ทดลองนะค่ะ ฟังก์ชันการทำงานบางอย่างอาจเปลี่ยนแปลงได้ และอาจไม่ทำงานหรือไม่เสถียรตามที่ตั้งใจไว้นะ"
developer: "สำหรับนักพัฒนา"
makeExplorable: "ทำให้บัญชีมองเห็นใน “สำรวจ”"
makeExplorableDescription: "ถ้าหากคุณปิดการทำงานนี้ บัญชีของคุณนั้นจะไม่แสดงในส่วน “สำรวจ”"
@@ -773,39 +759,39 @@ center: "กึ่งกลาง"
wide: "กว้าง"
narrow: "ชิด"
reloadToApplySetting: "การตั้งค่านี้จะมีผลหลังจากโหลดหน้าซ้ำเท่านั้น ต้องการที่จะโหลดใหม่เลยไหม?"
-needReloadToApply: "ต้องรีโหลดเพื่อให้การเปลี่ยนแปลงมีผล"
+needReloadToApply: "จำเป็นต้องโหลดซ้ำถึงจะมีผลนะ"
showTitlebar: "แสดงแถบชื่อ"
clearCache: "ล้างแคช"
-onlineUsersCount: "{n} รายกำลังออนไลน์"
+onlineUsersCount: "{n} ผู้ใช้คนนี้กำลังออนไลน์"
nUsers: "{n} ผู้ใช้งาน"
nNotes: "{n} โน้ต"
-sendErrorReports: "ส่งรายงานข้อผิดพลาด"
-sendErrorReportsDescription: "เมื่อเปิดใช้งาน การแจ้งข้อผิดพลาดจะถูกแชร์กับ Misskey เมื่อเกิดปัญหา ซึ่งช่วยในการปรับปรุงคุณภาพของซอฟต์แวร์ ข้อมูลข้อผิดพลาดอาจรวมถึงเวอร์ชันของระบบปฏิบัติการ ประเภทของเบราว์เซอร์ และประวัติการใช้งาน ฯลฯ"
+sendErrorReports: "ส่งรายงานว่าข้อผิดพลาด"
+sendErrorReportsDescription: "เมื่อเปิดใช้งาน ข้อมูลข้อผิดพลาดโดยรายละเอียดนั้นจะถูกแชร์ให้กับ Misskey เมื่อเกิดปัญหา ซึ่งช่วยปรับปรุงคุณภาพของ Misskey\nซึ่งจะรวมถึงข้อมูล เช่น เวอร์ชั่นของระบบปฏิบัติการ เบราว์เซอร์ที่คุณใช้ กิจกรรมของคุณใน Misskey เป็นต้น"
myTheme: "ธีมของฉัน"
-backgroundColor: "สีพื้นหลัง"
-accentColor: "สีหลัก"
+backgroundColor: "ภาพพื้นหลัง"
+accentColor: "รูปแบบสี"
textColor: "สีข้อความ"
saveAs: "บันทึกเป็น..."
advanced: "ขั้นสูง"
advancedSettings: "การตั้งค่าขั้นสูง"
value: "ค่า"
createdAt: "สร้างเมื่อ"
-updatedAt: "อัปเดตล่าสุด"
+updatedAt: "อัพเดทล่าสุด"
saveConfirm: "บันทึกเปลี่ยนแปลงมั้ย?"
-deleteConfirm: "ต้องการลบใช่ไหม?"
+deleteConfirm: "ลบจริงๆเหรอ?"
invalidValue: "ค่านี้ไม่ถูกต้อง"
registry: "ทะเบียน"
closeAccount: "ปิด บัญชี"
currentVersion: "เวอร์ชั่นปัจจุบัน"
-latestVersion: "เวอร์ชั่นล่าสุด"
+latestVersion: "รุ่นปัจจุบัน"
youAreRunningUpToDateClient: "คุณกำลังใช้ไคลเอ็นต์เวอร์ชันใหม่ล่าสุดนะ"
newVersionOfClientAvailable: "มีไคลเอ็นต์เวอร์ชันใหม่กว่าของคุณพร้อมใช้งานนะ"
usageAmount: "การใช้งาน"
capacity: "ความจุ"
inUse: "ใช้แล้ว"
editCode: "แก้ไขโค้ด"
-apply: "นำไปใช้"
-receiveAnnouncementFromInstance: "รับการแจ้งเตือนจากเซิร์ฟเวอร์นี้"
+apply: "ตกลง"
+receiveAnnouncementFromInstance: "รับการแจ้งเตือนจากอินสแตนซ์นี้"
emailNotification: "การแจ้งเตือนทางอีเมล"
publish: "เผยแพร่"
inChannelSearch: "ค้นหาในช่อง"
@@ -816,7 +802,7 @@ showingPastTimeline: "กำลังแสดงผลไทม์ไลน์
clear: "ล้าง"
markAllAsRead: "ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว"
goBack: "ย้อนกลับ"
-unlikeConfirm: "ต้องการเลิกถูกใจใช่ไหม?"
+unlikeConfirm: "เลิกถูกใจจริงๆ หรือ?"
fullView: "มุมมองแบบเต็ม"
quitFullView: "ออกจากมุมมองแบบเต็ม"
addDescription: "เพิ่มคำอธิบาย"
@@ -827,26 +813,25 @@ userInfo: "ข้อมูลผู้ใช้"
unknown: "ไม่ทราบสถานะ"
onlineStatus: "สถานะออนไลน์"
hideOnlineStatus: "ซ่อนสถานะออนไลน์"
-hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์อาจทำให้ฟังก์ชันบางอย่าง เช่น การค้นหา สะดวกน้อยลง"
+hideOnlineStatusDescription: "การซ่อนสถานะออนไลน์ของคุณช่วยลดความสะดวกของคุณสมบัติบางอย่าง เช่น การค้นหา อ่ะนะ"
online: "ออนไลน์"
active: "ใช้งานอยู่"
offline: "ออฟไลน์"
notRecommended: "ไม่แนะนำ"
-botProtection: "การป้องกัน Bot"
-instanceBlocking: "เซิร์ฟเวอร์ที่ถูกบล็อก/ปิดปาก"
+botProtection: "การป้องกัน Bot (or AI)"
+instanceBlocking: "อินสแตนซ์ที่ถูกบล็อก"
selectAccount: "เลือกบัญชี"
switchAccount: "สลับบัญชีผู้ใช้"
enabled: "เปิดใช้งาน"
disabled: "ปิดการใช้งาน"
quickAction: "ปุ่มลัด"
-user: "ผู้ใช้"
+user: "ผู้ใช้งาน"
administration: "การจัดการ"
accounts: "บัญชีผู้ใช้"
switch: "สลับ"
-noMaintainerInformationWarning: "ยังไม่ได้ตั้งค่าข้อมูลของผู้ดูแลระบบ"
-noInquiryUrlWarning: "ยังไม่ได้ตั้งค่า URL สำหรับการติดต่อสอบถาม"
-noBotProtectionWarning: "ยังไม่ได้ตั้งค่าการป้องกันบอต"
-configure: "ตั้งค่า"
+noMaintainerInformationWarning: "ข้อมูลผู้ดูแลไม่ได้รับการกำหนดค่านะ"
+noBotProtectionWarning: "ไม่ได้กำหนดค่าการป้องกันบอทนะ"
+configure: "กำหนดค่า"
postToGallery: "สร้างโพสต์แกลเลอรี่ใหม่"
postToHashtag: "โพสต์ไปที่แฮชแท็กนี้"
gallery: "แกลเลอรี่"
@@ -883,7 +868,7 @@ accountDeletionInProgress: "กำลังดำเนินการลบบ
usernameInfo: "ชื่อที่ระบุบัญชีของคุณจากผู้อื่นในเซิร์ฟเวอร์นี้ คุณสามารถใช้ตัวอักษร (a~z, A~Z), ตัวเลข (0~9) หรือขีดล่าง (_) ชื่อผู้ใช้ไม่สามารถเปลี่ยนแปลงได้ในภายหลัง"
aiChanMode: "โหมด Ai "
devMode: "โหมดนักพัฒนา"
-keepCw: "คงการเตือนเนื้อหาไว้"
+keepCw: "เก็บคำเตือนเนื้อหา"
pubSub: "บัญชี Pub/Sub"
lastCommunication: "การสื่อสารครั้งสุดท้ายล่าสุด"
resolved: "คลี่คลายแล้ว"
@@ -895,7 +880,7 @@ itsOff: "ปิดใช้งาน"
on: "เปิด"
off: "ปิด"
emailRequiredForSignup: "จำเป็นต้องการใช้ที่อยู่อีเมลสำหรับการสมัคร"
-unread: "ยังไม่ได้อ่าน"
+unread: "ไม่ได้อ่าน"
filter: "กรอง"
controlPanel: "แผงควบคุม"
manageAccounts: "จัดการบัญชี"
@@ -903,13 +888,13 @@ makeReactionsPublic: "ตั้งค่าประวัติการรี
makeReactionsPublicDescription: "การทำเช่นนี้จะทำให้รายการรีแอคชั่นของคุณที่ผ่านมาทั้งหมดปรากฏต่อสาธารณะ"
classic: "คลาสสิค"
muteThread: "ปิดเสียงเธรด"
-unmuteThread: "เลิกปิดเสียงเธรด"
+unmuteThread: "เปิดเสียงเธรด"
followingVisibility: "การมองเห็นที่เรากำลังติดตาม"
followersVisibility: "การมองเห็นผู้ที่กำลังติดตามเรา"
continueThread: "ดูความต่อเนื่องเธรด"
deleteAccountConfirm: "การดำเนินการนี้จะลบบัญชีของคุณอย่างถาวรเลยนะ แน่ใจหรอดำเนินการ?"
incorrectPassword: "รหัสผ่านไม่ถูกต้อง"
-voteConfirm: "ต้องการโหวต “{choice}” ใช่ไหม?"
+voteConfirm: "ยืนยันการโหวต “{choice}” ไหม?"
hide: "ซ่อน"
useDrawerReactionPickerForMobile: "แสดง ตัวจิ้มรีแอคชั่น เป็นแบบลิ้นชัก เมื่อใช้บนมือถือ"
welcomeBackWithName: "ยินดีต้อนรับการกลับมานะคะ, คุณ{name}"
@@ -922,8 +907,8 @@ themeColor: "สีธีม"
size: "ขนาด"
numberOfColumn: "จำนวนคอลัมน์"
searchByGoogle: "ค้นหา"
-instanceDefaultLightTheme: "ธีมสว่างตามค่าเริ่มต้นของเซิร์ฟเวอร์"
-instanceDefaultDarkTheme: "ธีมมืดตามค่าเริ่มต้นของเซิร์ฟเวอร์"
+instanceDefaultLightTheme: "ธีมสว่างตามค่าเริ่มต้นของอินสแตนซ์"
+instanceDefaultDarkTheme: "ธีมมืดตามค่าเริ่มต้นของอินสแตนซ์"
instanceDefaultThemeDescription: "ป้อนรหัสธีมในรูปแบบออบเจ็กต์"
mutePeriod: "ระยะเวลาปิดเสียง"
period: "ระยะเวลา"
@@ -943,7 +928,7 @@ cropNo: "ใช้ตามที่เป็นอยู่"
file: "ไฟล์"
recentNHours: "ล่าสุด {n} ชั่วโมงที่แล้ว"
recentNDays: "ล่าสุด {n} วันที่แล้ว"
-noEmailServerWarning: "ยังไม่ได้ตั้งค่าเซิร์ฟเวอร์ของอีเมล"
+noEmailServerWarning: "ไม่ได้กำหนดค่าเซิร์ฟเวอร์อีเมลนี้"
thereIsUnresolvedAbuseReportWarning: "มีรายงานที่ยังไม่ได้แก้ไข"
recommended: "แนะนำ"
check: "ตรวจสอบ"
@@ -956,13 +941,13 @@ deleteAccount: "ลบบัญชี"
document: "เอกสาร"
numberOfPageCache: "จำนวนหน้าเพจที่แคช"
numberOfPageCacheDescription: "การเพิ่มจำนวนนี้จะช่วยเพิ่มความสะดวกให้กับผู้ใช้งาน แต่จะทำให้เซิร์ฟเวอร์โหลดมากขึ้นและต้องใช้หน่วยความจำมากขึ้นอีกด้วย"
-logoutConfirm: "ต้องการออกจากระบบใช่ไหม?"
-lastActiveDate: "ใช้งานล่าสุดเมื่อ"
+logoutConfirm: "ต้องการออกจากระบบ?"
+lastActiveDate: "ใช้งานล่าสุดที่"
statusbar: "แถบสถานะ"
pleaseSelect: "ตัวเลือก"
-reverse: "พลิก"
+reverse: "ย้อนกลับ"
colored: "สี"
-refreshInterval: "ความถี่ในการอัปเดต"
+refreshInterval: "รอบการอัพเดต"
label: "ป้ายชื่อ"
type: "รูปแบบ"
speed: "ความเร็ว"
@@ -978,7 +963,7 @@ cannotUploadBecauseExceedsFileSizeLimit: "ไม่สามารถอัป
beta: "เบต้า"
enableAutoSensitive: "ทำเครื่องหมายว่ามีเนื้อหาที่ละเอียดอ่อนโดยอัตโนมัติ"
enableAutoSensitiveDescription: "อนุญาตให้ตรวจหาและทำเครื่องหมายสื่อว่ามีเนื้อหาโดยละเอียดอ่อนโดยอัตโนมัติ ผ่าน Machine Learning หากเป็นไปได้ แม้ว่าคุณจะปิดคุณสมบัตินี้ ก็อาจถูกตั้งค่าโดยอัตโนมัติ ทั้งนี้ขึ้นอยู่กับเซิร์ฟเวอร์"
-activeEmailValidationDescription: "การตรวจสอบอีเมลของผู้ใช้จะเข้มงวดมากขึ้น โดยพิจารณาว่าเป็นอีเมลชั่วคราวหรือไม่ และสามารถติดต่อได้จริงหรือไม่ หากปิดการตรวจสอบนี้ จะตรวจสอบเพียงว่ารูปแบบอีเมลที่ถูกต้องหรือไม่เท่านั้น"
+activeEmailValidationDescription: "เปิดใช้งานการตรวจสอบที่อยู่อีเมลให้มีความเข้มงวดยิ่งขึ้น ซึ่งอาจจะรวมไปถึงการตรวจสอบที่อยู่อีเมล์ที่ใช้แล้วทิ้งและโดยให้พิจารณาว่าสามารถสื่อสารด้วยได้หรือไม่ เมื่อไม่เลือกระบบจะตรวจสอบเฉพาะรูปแบบของอีเมลเท่านั้น"
navbar: "แถบนำทาง"
shuffle: "สลับ"
account: "บัญชีผู้ใช้"
@@ -987,10 +972,10 @@ pushNotification: "การแจ้งเตือนแบบพุช"
subscribePushNotification: "เปิดการแจ้งเตือนแบบพุช"
unsubscribePushNotification: "ปิดการแจ้งเตือนแบบพุช"
pushNotificationAlreadySubscribed: "การแจ้งเตือนแบบพุชได้เปิดใช้งานแล้ว"
-pushNotificationNotSupported: "เบราว์เซอร์หรือเซิร์ฟเวอร์ไม่รองรับการแจ้งเตือนแบบพุช"
+pushNotificationNotSupported: "เบราว์เซอร์หรืออินสแตนซ์ของคุณนั้นไม่รองรับการแจ้งเตือนแบบพุช"
sendPushNotificationReadMessage: "ลบการแจ้งเตือนแบบพุชเมื่ออ่านการแจ้งเตือนหรือข้อความที่เกี่ยวข้องแล้ว"
-sendPushNotificationReadMessageCaption: "อาจทำให้อุปกรณ์ของคุณใช้พลังงานมากขึ้น"
-windowMaximize: "ขยายใหญ่สุด"
+sendPushNotificationReadMessageCaption: "การแจ้งเตือนที่มีข้อความ \"{emptyPushNotificationMessage}\" จะแสดงขึ้นมาในช่วงระยะเวลาสั้นๆ การดำเนินการนี้อาจทำให้เพิ่มการใช้งานแบตเตอรี่ของอุปกรณ์ถ้าหากมีนะ"
+windowMaximize: "ขยายใหญ่สุดแล้ว"
windowMinimize: "ย่อเล็กที่สุด"
windowRestore: "เลิกทำ"
caption: "คำอธิบาย"
@@ -1006,7 +991,6 @@ neverShow: "ไม่ต้องแสดงข้อความนี้อ
remindMeLater: "ไว้ครั้งหน้าแล้วกัน"
didYouLikeMisskey: "คุณชอบ Misskey ไหม?"
pleaseDonate: "Misskey เป็นซอฟต์แวร์ฟรีที่ใช้งานโดย {host} เราขอขอบคุณการสนับสนุนของคุณอย่างสูงเพื่อให้การพัฒนา Misskey สามารถดำเนินต่อไปได้!"
-correspondingSourceIsAvailable: "ซอร์สโค้ดที่เกี่ยวข้องมีอยู่ที่ {anchor}"
roles: "บทบาท"
role: "บทบาท"
noRole: "ไม่พบบทบาท"
@@ -1030,37 +1014,36 @@ achievements: "ความสำเร็จ"
gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
thisPostMayBeAnnoying: "โน้ตนี้อาจจะเป็นการรบกวนผู้อื่นนะคะ"
-thisPostMayBeAnnoyingHome: "โพสต์ลงไทม์ไลน์หลักเท่านั้น"
-thisPostMayBeAnnoyingCancel: "ยกเลิก"
-thisPostMayBeAnnoyingIgnore: "โพสต์ไปเลย ไม่ต้องปรับการมองเห็น"
+thisPostMayBeAnnoyingHome: "โพสต์ไปยังไทม์ไลน์หน้าแรก"
+thisPostMayBeAnnoyingCancel: "เลิก"
+thisPostMayBeAnnoyingIgnore: "โพสต์ยังไงก็แล้วแต่"
collapseRenotes: "ยุบรีโน้ตที่คุณเคยเห็นแล้ว"
-collapseRenotesDescription: "พับย่อโน้ตที่เคยตอบสนองหรือรีโน้ตแล้ว"
internalServerError: "เซิร์ฟเวอร์ภายในเกิดข้อผิดพลาด"
-internalServerErrorDescription: "เกิดข้อผิดพลาดที่ไม่คาดคิดภายในเซิร์ฟเวอร์"
+internalServerErrorDescription: "เซิร์ฟเวอร์รันค้นพบข้อผิดพลาดที่ไม่คาดคิด"
copyErrorInfo: "คัดลอกรายละเอียดข้อผิดพลาด"
-joinThisServer: "ลงทะเบียนในเซิร์ฟเวอร์นี้"
-exploreOtherServers: "มองหาเซิร์ฟเวอร์อื่น"
+joinThisServer: "ลงชื่อสมัครใช้ในอินสแตนซ์นี้"
+exploreOtherServers: "มองหาอินสแตนซ์อื่น"
letsLookAtTimeline: "มาดูไทม์ไลน์กัน"
-disableFederationConfirm: "ปิดใช้งานสหพันธ์เลยใช่ไหม?"
+disableFederationConfirm: "ปิดใช้งานสหพันธ์จริงๆหรอแน่ใจแล้วนะ?"
disableFederationConfirmWarn: "โพสต์จะยังคงเป็นสาธารณะต่อไป เว้นแต่จะตั้งค่าเป็นอย่างอื่น"
disableFederationOk: "ปิดการใช้งาน"
-invitationRequiredToRegister: "เซิร์ฟเวอร์นี้เป็นแบบรับเชิญ เฉพาะผู้มีรหัสเชิญเท่านั้นถึงสามารถลงทะเบียนได้"
-emailNotSupported: "เซิร์ฟเวอร์นี้ไม่รองรับการส่งอีเมล"
+invitationRequiredToRegister: "อินสแตนซ์นี้เป็นแบบรับเชิญ เฉพาะผู้ที่มีรหัสเชิญเท่านั้นที่สามารถลงทะเบียนได้"
+emailNotSupported: "อินสแตนซ์นี้ไม่รองรับการส่งอีเมล"
postToTheChannel: "โพสต์ลงช่อง"
cannotBeChangedLater: "สิ่งนี้ไม่สามารถเปลี่ยนแปลงได้ในภายหลังนะ"
reactionAcceptance: "การยอมรับรีแอคชั่น"
likeOnly: "ที่ถูกใจเท่านั้น"
-likeOnlyForRemote: "ทั้งหมด (เฉพาะการถูกใจจากเซิร์ฟเวอร์ระยะไกล)"
+likeOnlyForRemote: "ทั้งหมด (เฉพาะการถูกใจจากอินสแตนซ์ระยะไกล)"
nonSensitiveOnly: "เฉพาะไม่มีเนื้อหาละเอียดอ่อน"
nonSensitiveOnlyForLocalLikeOnlyForRemote: "เฉพาะไม่มีเนื้อหาละเอียดอ่อน (เฉพาะการถูกใจจากระยะไกลเท่านั้น)"
rolesAssignedToMe: "บทบาทที่ได้รับมอบหมายให้ฉัน"
-resetPasswordConfirm: "ต้องการรีเซ็ตรหัสผ่านใช่ไหม?"
+resetPasswordConfirm: "รีเซ็ตรหัสผ่านของคุณจริงๆหรอ?"
sensitiveWords: "คำที่มีเนื้อหาละเอียดอ่อน"
-sensitiveWordsDescription: "โน้ตที่มีคำที่ระบุไว้จะถูกตั้งค่าการมองเห็นของให้แสดงเฉพาะในหน้าหลักเท่านั้น คั่นคำด้วยการขึ้นบรรทัดใหม่"
-sensitiveWordsDescription2: "ถ้าแยกด้วยเว้นวรรคจะเป็นการระบุ AND และถ้าล้อมคำด้วยสแลช (/) จะเป็นการใช้ regular expression"
+sensitiveWordsDescription: "การเปิดเผยโน้ตทั้งหมดที่มีคำที่กำหนดค่าไว้จะถูกตั้งค่าเป็น \"หน้าแรก\" โดยอัตโนมัติ คุณยังสามารถแสดงหลายรายการได้โดยแยกรายการโดยใช้ตัวแบ่งบรรทัดได้นะ"
+sensitiveWordsDescription2: "การใช้ช่องว่างนั้นอาจจะสร้างนิพจน์ AND และคำหลักที่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ"
prohibitedWords: "คำต้องห้าม"
prohibitedWordsDescription: "จะแจ้งเตือนว่าเกิดข้อผิดพลาดเมื่อพยายามโพสต์โน้ตที่มีคำที่กำหนดไว้ สามารถตั้งได้หลายคำด้วยการขึ้นบรรทัดใหม่"
-prohibitedWordsDescription2: "ถ้าแยกด้วยเว้นวรรคจะเป็นการระบุ AND และถ้าล้อมคำด้วยสแลช (/) จะเป็นการใช้ regular expression"
+prohibitedWordsDescription2: "การใช้ช่องว่างนั้นอาจจะสร้างนิพจน์ AND และคำหลักที่มีเครื่องหมายทับล้อมรอบจะเปลี่ยนเป็นนิพจน์ทั่วไปนะ"
hiddenTags: "แฮชแท็กที่ซ่อนอยู่"
hiddenTagsDescription: "เลือกแท็กที่จะไม่แสดงในรายการเทรนด์ สามารถลงทะเบียนหลายแท็กได้โดยขึ้นบรรทัดใหม่"
notesSearchNotAvailable: "การค้นหาโน้ตไม่พร้อมใช้งาน"
@@ -1072,11 +1055,11 @@ retryAllQueuesNow: "ลองเรียกใช้คิวทั้งหม
retryAllQueuesConfirmTitle: "ลองใหม่ทั้งหมดจริงๆหรอแน่ใจนะ?"
retryAllQueuesConfirmText: "สิ่งนี้จะเพิ่มการโหลดเซิร์ฟเวอร์ชั่วคราวนะ"
enableChartsForRemoteUser: "สร้างแผนภูมิข้อมูลผู้ใช้ระยะไกล"
-enableChartsForFederatedInstances: "สร้างแผนภูมิของเซิร์ฟเวอร์ระยะไกล"
+enableChartsForFederatedInstances: "สร้างแผนภูมิข้อมูลอินสแตนซ์ระยะไกล"
showClipButtonInNoteFooter: "เพิ่ม “คลิป” ไปยังเมนูสั่งการของโน้ต"
reactionsDisplaySize: "ขนาดของรีแอคชั่น"
limitWidthOfReaction: "จำกัดความกว้างสูงสุดของรีแอคชั่นและแสดงให้เล็กลง"
-noteIdOrUrl: "ID ของโน้ต หรือ URL"
+noteIdOrUrl: "โน้ต ID หรือ URL"
video: "วีดีโอ"
videos: "วีดีโอ"
audio: "เสียง"
@@ -1091,45 +1074,40 @@ addMemo: "เพิ่มเมโม"
editMemo: "แก้ไขเมโม"
reactionsList: "รายการรีแอคชั่น"
renotesList: "รายการรีโน้ต"
-notificationDisplay: "การแสดงการแจ้งเตือน"
+notificationDisplay: "การแจ้งเตือน"
leftTop: "บนซ้าย"
rightTop: "บนขวา"
leftBottom: "ล่างซ้าย"
rightBottom: "ล่างขวา"
stackAxis: "ทิศทางการซ้อน"
vertical: "แนวตั้ง"
-horizontal: "แนวนอน"
+horizontal: "ด้านข้าง"
position: "ตำแหน่ง"
serverRules: "กฎของเซิร์ฟเวอร์"
-pleaseConfirmBelowBeforeSignup: "หากต้องการลงทะเบียนในเซิร์ฟเวอร์นี้ คุณต้องตรวจสอบและยอมรับสิ่งต่อไปนี้"
+pleaseConfirmBelowBeforeSignup: "โปรดยืนยันที่ด้านล่างก่อนสมัครใช้งาน"
pleaseAgreeAllToContinue: "คุณต้องยอมรับทุกช่องตรงด้านบนเพื่อดำเนินการต่อค่ะ"
continue: "ดำเนินการต่อ"
preservedUsernames: "ชื่อผู้ใช้ที่สงวนไว้"
preservedUsernamesDescription: "ระบุชื่อผู้ใช้ที่จะสงวนชื่อไว้ คั่นด้วยการขึ้นบรรทัดใหม่ ชื่อผู้ใช้ที่ระบุที่นี่จะไม่สามารถใช้งานได้อีกต่อไปเมื่อสร้างบัญชีใหม่ ยกเว้นเมื่อผู้ดูแลระบบสร้างบัญชี นอกจากนี้ บัญชีที่มีอยู่แล้วจะไม่ได้รับผลกระทบ"
createNoteFromTheFile: "เรียบเรียงโน้ตจากไฟล์นี้"
archive: "เก็บถาวร"
-archived: "เก็บถาวรแล้ว"
-unarchive: "เลิกการเก็บถาวร"
channelArchiveConfirmTitle: "ต้องการเก็บถาวรเจ้า {name} ใช่ไหม?"
channelArchiveConfirmDescription: "เมื่อเก็บถาวรแล้ว จะไม่ปรากฏในรายการช่องหรือผลการค้นหาอีกต่อไป และจะไม่สามารถโพสต์ใหม่ได้อีกต่อไป"
thisChannelArchived: "ช่องนี้ถูกเก็บถาวรแล้วนะ"
displayOfNote: "การแสดงโน้ต"
initialAccountSetting: "ตั้งค่าโปรไฟล์"
youFollowing: "ติดตามแล้ว"
-preventAiLearning: "ปฏิเสธการเรียนรู้ด้วย generative AI"
-preventAiLearningDescription: "ส่งคำร้องขอไม่ให้ใช้ ข้อความในโน้ตที่โพสต์, หรือเนื้อหารูปภาพ ฯลฯ ในการเรียนรู้ของเครื่อง(machine learning) / Predictive AI / Generative AI โดยการเพิ่มแฟล็ก “noai” ลง HTML-Response ให้กับเนื้อหาที่เกี่ยวข้อง แต่ทั้งนี้ ไม่ได้ป้องกัน AI จากการเรียนรู้ได้อย่างสมบูรณ์ เนื่องจากมี AI บางตัวเท่านั้นที่จะเคารพคำขอดังกล่าว"
+preventAiLearning: "ปฏิเสธการใช้งาน ในการเรียนรู้ของเครื่อง (Generative AI)"
+preventAiLearningDescription: "การส่งคำร้องขอโปรแกรมรวบรวมข้อมูลไม่ให้ใช้ข้อความที่โพสต์หรือรูปภาพ ฯลฯ ในชุดข้อมูลแมชชีนเลิร์นนิง (Predictive / Generative AI) สิ่งนี้นั้นทำได้โดยการเพิ่มแฟล็กการตอบสนอง \"noai\" HTML ให้กับเนื้อหาที่เกี่ยวข้อง แต่อย่างไรก็ตามแล้ว การป้องกันโดยสมบูรณ์นั้นไม่สามารถทำได้ผ่านแฟล็กนี้เนื่องจากอาจจะทำให้ถูกเพิกเฉยได้"
options: "ตัวเลือกบทบาท"
specifyUser: "ผู้ใช้เฉพาะ"
-lookupConfirm: "ต้องการเรียกดูข้อมูลใช่ไหม?"
-openTagPageConfirm: "ต้องการเปิดหน้าแฮชแท็กใช่ไหม?"
-specifyHost: "ระบุโฮสต์"
failedToPreviewUrl: "ไม่สามารถดูตัวอย่างได้"
update: "อัปเดต"
rolesThatCanBeUsedThisEmojiAsReaction: "บทบาทที่สามารถใช้เอโมจินี้เป็นรีแอคชั่นได้"
-rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ถ้าหากไม่ได้ระบุบทบาท ใคร ๆ ก็สามารถใช้เอโมจินี้เพื่อรีแอคชั่นได้"
+rolesThatCanBeUsedThisEmojiAsReactionEmptyDescription: "ถ้าหากไม่ได้ระบุบทบาท ทุกคนนั้นก็สามารถใช้เอโมจินี้เพื่อรีแอคชั่นได้นะ"
rolesThatCanBeUsedThisEmojiAsReactionPublicRoleWarn: "บทบาทเหล่านี้ต้องเป็นสาธารณะ"
-cancelReactionConfirm: "ต้องการลบรีแอคชั่นใช่ไหม?"
-changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นใช่ไหม?"
+cancelReactionConfirm: "ต้องการลบรีแอคชั่นของคุณจริงๆหรอ?"
+changeReactionConfirm: "ต้องการเปลี่ยนรีแอคชั่นของคุณจริงๆหรอ?"
later: "ไว้ทีหลัง"
goToMisskey: "ถึง Misskey"
additionalEmojiDictionary: "พจนานุกรมเอโมจิเพิ่มเติม"
@@ -1138,20 +1116,20 @@ branding: "แบรนดิ้ง"
enableServerMachineStats: "เผยแพร่สถานะฮาร์ดแวร์ของเซิร์ฟเวอร์"
enableIdenticonGeneration: "เปิดใช้งานผู้ใช้สร้างตัวระบุ"
turnOffToImprovePerformance: "การปิดส่วนนี้สามารถเพิ่มประสิทธิภาพได้"
-createInviteCode: "สร้างรหัสเชิญ"
+createInviteCode: "สร้างคำเชิญ"
createWithOptions: "สร้างด้วยตัวเลือก"
-createCount: "จำนวนรหัสเชิญ"
-inviteCodeCreated: "สร้างรหัสเชิญแล้ว"
-inviteLimitExceeded: "จำนวนรหัสเชิญที่สามารถสร้างได้ถึงขีดจำกัดแล้ว"
-createLimitRemaining: "รหัสเชิญที่สามารถสร้างได้: เหลืออยู่ {limit} รหัส"
-inviteLimitResetCycle: "สามารถสร้างรหัสเชิญได้อีกสูงสุด {limit} รหัส ภายใน {time}"
+createCount: "จำนวนการเชิญ"
+inviteCodeCreated: "สร้างคำเชิญแล้ว"
+inviteLimitExceeded: "คุณสร้างคำเชิญเกินถึงขีดจำกัดแล้วนะ"
+createLimitRemaining: "ขีดจำกัดการเชิญ: {limit} ที่เหลืออยู่"
+inviteLimitResetCycle: "ขีดจำกัดนี้จะถูกรีเซ็ตเป็น {limit} ที่ {time}."
expirationDate: "วันที่หมดอายุ"
noExpirationDate: "ไม่มีหมดอายุ"
-inviteCodeUsedAt: "วันเวลาที่ใช้รหัสเชิญ"
-registeredUserUsingInviteCode: "ผู้ใช้ที่ใช้รหัสเชิญ"
+inviteCodeUsedAt: "รหัสคำเชิญใช้แล้วที่"
+registeredUserUsingInviteCode: "ใช้คำเชิญแล้วโดย"
waitingForMailAuth: "กำลังรอการยืนยันอีเมล"
-inviteCodeCreator: "ผู้ใช้ที่สร้างรหัสเชิญ"
-usedAt: "วันเวลาที่ถูกใช้"
+inviteCodeCreator: "สร้างการเชิญแล้วโดย"
+usedAt: "ใช้แล้วที่"
unused: "ยังไม่ได้ใช้"
used: "ถูกใช้แล้ว"
expired: "หมดอายุแล้ว"
@@ -1170,33 +1148,26 @@ renotes: "รีโน้ต"
loadReplies: "แสดงการตอบกลับ"
loadConversation: "แสดงบทสนทนา"
pinnedList: "รายชื่อที่ปักหมุดไว้"
-keepScreenOn: "เปิดหน้าจออุปกรณ์ค้างไว้"
+keepScreenOn: "เปิดหน้าจอไว้"
verifiedLink: "ความเป็นเจ้าของลิงก์ได้รับการยืนยันแล้ว"
notifyNotes: "แจ้งเตือนเกี่ยวกับโพสต์ใหม่"
unnotifyNotes: "หยุดการแจ้งเตือนเกี่ยวกับโน้ตใหม่"
authentication: "การตรวจสอบสิทธิ์"
authenticationRequiredToContinue: "กรุณายืนยันตัวตนทางอิเล็กทรอนิกส์เพื่อดำเนินการต่อ"
-dateAndTime: "วันเวลา"
+dateAndTime: "เวลาประทับ"
showRenotes: "แสดงรีโน้ต"
edited: "แก้ไขแล้ว"
notificationRecieveConfig: "การตั้งค่าการแจ้งเตือน"
mutualFollow: "ติดตามซึ่งกันและกัน"
-followingOrFollower: "กำลังติดตามหรือผู้ติดตาม"
fileAttachedOnly: "เฉพาะโน้ตที่มีไฟล์เท่านั้น"
showRepliesToOthersInTimeline: "แสดงการตอบกลับผู้อื่นลงในไทม์ไลน์"
hideRepliesToOthersInTimeline: "ไม่แสดงการตอบกลับผู้อื่นลงในไทม์ไลน์"
showRepliesToOthersInTimelineAll: "รวมตอบกลับจากทุกคนที่คุณติดตามไว้ในไทม์ไลน์ของคุณ"
hideRepliesToOthersInTimelineAll: "ซ่อนตอบกลับจากทุกคนที่คุณติดตามไปจากไทม์ไลน์ของคุณ"
-confirmShowRepliesAll: "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณต้องการแสดงการตอบกลับผู้อื่นจากผู้ใช้ทุกคนที่คุณติดตามอยู่ ใส่ลงไทม์ไลน์ใช่ไหม?"
-confirmHideRepliesAll: "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณต้องการซ่อนการตอบกลับผู้อื่นจากผู้ใช้ทุกคนที่คุณติดตามอยู่ ไปจากไทม์ไลน์ใช่ไหม?"
+confirmShowRepliesAll: "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณต้องการแสดงการตอบกลับผู้อื่นจากผู้ใช้ทุกคนที่คุณติดตามอยู่ในไทม์ไลน์ของคุณหรือไม่?"
+confirmHideRepliesAll: "การดำเนินการนี้ไม่สามารถย้อนกลับได้ คุณต้องการซ่อนการตอบกลับผู้อื่นจากผู้ใช้ทุกคนที่คุณติดตามอยู่ในไทม์ไลน์ของคุณหรือไม่?"
externalServices: "บริการภายนอก"
sourceCode: "ซอร์สโค้ด"
-sourceCodeIsNotYetProvided: "ซอร์สโค้ดยังไม่พร้อมใช้งาน โปรดติดต่อผู้ดูแลระบบเพื่อแก้ไขปัญหานี้"
-repositoryUrl: "URL ของ repository"
-repositoryUrlDescription: "หากมีที่เก็บซอร์สโค้ดที่เปิดเผยต่อสาธารณะ ให้ป้อน URL ที่เก็บซอร์สโค้ดนั้น แต่หากคุณใช้ Misskey ตามต้นฉบับ (ไม่มีการเปลี่ยนแปลงซอร์สโค้ด) ให้ป้อน https://github.com/misskey-dev/misskey"
-repositoryUrlOrTarballRequired: "หากคุณไม่มี repository สาธารณะ คุณจะต้องจัดเตรียม tarball แทน ดู .config/example.yml สำหรับรายละเอียด"
-feedback: "ฟีดแบ็ก"
-feedbackUrl: "URLของฟีดแบ็ก"
impressum: "อิมเพรสชั่น"
impressumUrl: "URL อิมเพรสชั่น"
impressumDescription: "การติดป้ายกำกับ (Impressum) มีผลบังคับใช้ในบางประเทศและภูมิภาค เช่น ประเทศเยอรมนี"
@@ -1208,7 +1179,7 @@ attach: "แนบ"
detach: "นำออก"
detachAll: "เอาออกทั้งหมด"
angle: "แองเกิล"
-flip: "พลิก"
+flip: "ย้อนกลับ"
showAvatarDecorations: "แสดงตกแต่งอวตาร"
releaseToRefresh: "ปล่อยเพื่อรีเฟรช"
refreshing: "กำลังรีเฟรช..."
@@ -1232,79 +1203,41 @@ soundWillBePlayed: "จะมีการเล่นเอฟเฟกต์เ
showReplay: "ดูรีเพลย์"
replay: "รีเพลย์"
replaying: "กำลังรีเพลย์"
-endReplay: "ออกจากรีเพลย์"
-copyReplayData: "คัดลอกข้อมูลรีเพลย์"
ranking: "อันดับ"
lastNDays: "ล่าสุด {n} วันที่แล้ว"
backToTitle: "กลับไปหน้าไตเติ้ล"
hemisphere: "พื้นที่ที่อาศัยอยู่"
-withSensitive: "แสดงโน้ตที่มีไฟล์เนื้อหาละเอียดอ่อน"
+withSensitive: "แสดงโน้ตที่มีไฟล์ที่ระบุว่ามีเนื้อหาละเอียดอ่อน"
userSaysSomethingSensitive: "โพสต์ที่มีไฟล์เนื้อหาละเอียดอ่อนของ {name}"
enableHorizontalSwipe: "ปัดเพื่อสลับแท็บ"
-loading: "กำลังโหลด"
-surrender: "ยอมแพ้"
-gameRetry: "เริ่มเกมใหม่"
-notUsePleaseLeaveBlank: "หากไม่ได้ใช้กรุณาเว้นว่างไว้"
-useTotp: "ใช้รหัสผ่านแบบใช้ครั้งเดียว (TOTP)"
-useBackupCode: "ใช้รหัสแบ๊กอัป"
-launchApp: "เริ่มแอป"
-useNativeUIForVideoAudioPlayer: "ใช้ UI ของเบราว์เซอร์เพื่อเล่นวิดีโอ/เสียง"
-keepOriginalFilename: "คงชื่อไฟล์เดิมไว้"
-keepOriginalFilenameDescription: "หากปิดการตั้งค่านี้ ในระหว่างการอัปโหลดชื่อไฟล์จะถูกแทนที่ด้วยสตริงแบบสุ่มโดยอัตโนมัติ"
-noDescription: "ไม่มีข้อความอธิบาย"
-alwaysConfirmFollow: "แสดงข้อความยืนยันเมื่อกดติดตาม"
-inquiry: "ติดต่อเรา"
-tryAgain: "โปรดลองอีกครั้ง"
-confirmWhenRevealingSensitiveMedia: "ตรวจสอบก่อนแสดงสื่อที่มีเนื้อหาละเอียดอ่อน"
-sensitiveMediaRevealConfirm: "สื่อนี้มีเนื้อหาละเอียดอ่อน, ต้องการแสดงใช่ไหม?"
-createdLists: "รายชื่อที่ถูกสร้าง"
-createdAntennas: "เสาอากาศที่ถูกสร้าง"
-_delivery:
- status: "สถานะการจัดส่ง"
- stop: "ระงับการส่ง"
- resume: "จัดส่งต่อ"
- _type:
- none: "กำลังเผยแพร่"
- manuallySuspended: "หยุดชั่วคราวด้วยตนเอง"
- goneSuspended: "เซิร์ฟเวอร์ถูกระงับเนื่องจากมีการลบเซิร์ฟเวอร์นี้"
- autoSuspendedForNotResponding: "เซิร์ฟเวอร์ถูกระงับเนื่องจากไม่ตอบสนอง"
_bubbleGame:
howToPlay: "วิธีเล่น"
- hold: "ถือไว้"
- _score:
- score: "คะแนน"
- scoreYen: "จำนวนเงินที่ได้รับ"
- highScore: "คะแนนสูงสุด"
- maxChain: "จำนวน chain สูงสุด"
- yen: "{yen} เยน"
- estimatedQty: "{qty} อัน"
- scoreSweets: "โอนิงิริ {onigiriQtyWithUnit}"
_howToPlay:
section1: "ขยับตำแหน่งและวางวัตถุลงในกล่อง"
section2: "เมื่อวัตถุประเภทเดียวกันมารวมกัน พวกมันจะกลายเป็นวัตถุใหม่และคุณจะได้รับคะแนน"
section3: "หากวัตถุล้นออกมาจากกล่อง เกมก็จะจบลง ตั้งเป้าทำคะแนนให้สูงด้วยการหลอมวัตถุต่าง ๆ โดยไม่ทำให้ล้นกล่อง!"
_announcement:
- forExistingUsers: "ผู้ใช้งานที่มีอยู่ตอนนี้เท่านั้น"
- forExistingUsersDescription: "หากเปิดใช้งาน การประกาศนี้จะแสดงเฉพาะกับผู้ใช้ที่สร้างบัญชีก่อน/ที่มีอยู่ในขณะที่สร้างประกาศนี้เท่านั้น หากปิดใช้งาน การประกาศนี้จะแสดงกับผู้ใช้ที่สร้างบัญชีหลังจากสร้างประกาศนี้ด้วย"
- needConfirmationToRead: "จำเป็นต้องยืนยันว่าอ่านแล้ว"
- needConfirmationToReadDescription: "กล่องโต้ตอบการยืนยันจะปรากฏขึ้นเมื่อจะทำเครื่องหมายว่าอ่านแล้ว นอกจากนี้ยังทำให้ประกาศนี้ยังไม่ถูกอ่านเมื่อใช้ฟังก์ชั่น “ทำเครื่องหมายฯ ทั้งหมดว่าอ่านแล้ว”"
+ forExistingUsers: "ผู้ใช้งานที่มีอยู่เท่านั้น"
+ forExistingUsersDescription: "การประกาศนี้จะแสดงต่อผู้ใช้ที่มีอยู่ ณ จุดที่เผยแพร่นั้นๆถ้าหากเปิดใช้งาน ถ้าหากปิดใช้งานผู้ที่กำลังสมัครใหม่หลังจากโพสต์แล้วนั้นก็จะเห็นเช่นกัน"
+ needConfirmationToRead: "จำเป็นต้องยืนยันเพื่อทำเครื่องหมายบอกว่าอ่านแล้ว"
+ needConfirmationToReadDescription: "ข้อความแจ้งแยก ถ้าหากต้องการเพื่อยืนยันว่ากำลังทำเครื่องหมายประกาศนี้ว่าอ่านแล้วจะแสดงขึ้นถ้าหากเปิดใช้งาน การประกาศนั้นจะไม่รวมอยู่ในฟังก์ชั่นว่า \"ทำเครื่องหมายทั้งหมดว่าอ่านแล้ว\""
end: "เก็บประกาศ"
- tooManyActiveAnnouncementDescription: "เนื่องจากมีการประกาศที่ยังใช้งานอยู่จำนวนมาก อาจทำให้ UX ลดลง แนะนำให้พิจารณาการเก็บประกาศที่สิ้นสุดไปแล้ว"
- readConfirmTitle: "ทำเครื่องหมายว่าอ่านแล้วเลยไหม?"
- readConfirmText: "จะทำเครื่องหมายใส่ “{title}” ว่าอ่านแล้ว"
- shouldNotBeUsedToPresentPermanentInfo: "เนื่องจากมีความเป็นไปได้สูงที่จะส่งผลเสียต่อง UX ของผู้ใช้ใหม่ จึงขอแนะนำให้ใช้ประกาศสำหรับข้อมูลที่ต้องการการตอบสนองในทันที ไม่ใช่ข้อมูลที่ต้องการแสดงตลอดเวลา"
+ tooManyActiveAnnouncementDescription: "การมีประกาศที่ใช้งานมากเกินไปนั้นอาจจะทำให้ประสบการณ์ของผู้ใช้งานนั้นดูแย่ลง โปรดกรุณาพิจารณาการเก็บประกาศที่ล้าสมัยด้วยนะค่ะ"
+ readConfirmTitle: "ทำเครื่องหมายบอกว่าอ่านแล้วเลยมั้ย?"
+ readConfirmText: "การดำเนินการนี้จะทำเครื่องหมายเนื้อหาของ \"{title}\" บอกว่าอ่านแล้วนะ"
+ shouldNotBeUsedToPresentPermanentInfo: "เราขอแนะนำให้ใช้ประกาศเพื่อโพสต์ข้อมูลแบบ flow มากกว่าข้อมูลแบบ stock เนื่องจากมีแนวโน้มที่จะส่งผลเสียต่อ UX โดยเฉพาะสำหรับผู้ใช้ใหม่"
dialogAnnouncementUxWarn: "เราขอแนะนำให้ใช้ด้วยความระมัดระวัง เนื่องจากการแจ้งเตือนแบบกล่องโต้ตอบตั้งแต่ 2 รายการขึ้นไปพร้อมกันอาจส่งผลเสียต่อ UX ได้อย่างมาก"
silence: "ไม่มีการแจ้งเตือน"
- silenceDescription: "หากเปิดใช้งาน จะไม่มีการแจ้งเตือนประกาศนี้ และผู้ใช้จะไม่จำเป็นต้องทำเครื่องหมายว่าอ่านแล้ว"
+ silenceDescription: "หากเปิดใช้งาน จะไม่ได้แจ้งเตือนประกาศนี้ และผู้ใช้จะไม่จำเป็นต้องอ่าน"
_initialAccountSetting:
- accountCreated: "สร้างบัญชีเสร็จสมบูรณ์!"
+ accountCreated: "คุณได้สร้างบัญชีของคุณสำเร็จเรียบร้อยแล้ว!"
letsStartAccountSetup: "สำหรับผู้เริ่มต้นมาตั้งค่าโปรไฟล์ของคุณกันเถอะ"
letsFillYourProfile: "ก่อนอื่นมาตั้งค่าโปรไฟล์ของคุณ"
profileSetting: "ตั้งค่าโปรไฟล์"
privacySetting: "ตั้งค่าความเป็นส่วนตัว"
theseSettingsCanEditLater: "คุณสามารถเปลี่ยนการตั้งค่าเหล่านี้ได้ในภายหลังได้ตลอดเวลานะ"
- youCanEditMoreSettingsInSettingsPageLater: "สามารถตั้งค่าเพิ่มเติมได้ที่หน้า “การตั้งค่า” อย่าลืมไปเยี่ยมชมภายหลังด้วย"
- followUsers: "ลองติดตามผู้ใช้ที่สนใจเพื่อสร้างไทม์ไลน์ดูสิ"
+ youCanEditMoreSettingsInSettingsPageLater: "ยังมีการตั้งค่าอื่นๆ อีกมากมายที่คุณนั้นสามารถกำหนดค่าได้จาก \"การตั้งค่า\" เพื่อให้แน่ใจว่าได้เยี่ยมชมมันได้ภายหลังนะ"
+ followUsers: "ลองติดตามผู้ใช้บางคนที่คุณอาจจะสนใจเพื่อสร้างไทม์ไลน์ของคุณสิ !"
pushNotificationDescription: "กำลังเปิดใช้งานการแจ้งเตือนแบบพุชจะช่วยให้คุณได้รับการแจ้งเตือนจาก {name} โดยตรงบนอุปกรณ์ของคุณนะ"
initialAccountSettingCompleted: "ตั้งค่าโปรไฟล์เสร็จสมบูรณ์แล้ว!"
haveFun: "ขอให้สนุกกับ {name}!"
@@ -1339,7 +1272,7 @@ _initialTutorial:
description1: "Misskey มีหลายไทม์ไลน์ขึ้นอยู่กับวิธีการใช้งานของคุณ (บางไทม์ไลน์อาจไม่สามารถใช้ได้ขึ้นอยู่กับนโยบายของเซิร์ฟเวอร์)"
home: "คุณสามารถดูโพสต์จากบัญชีที่คุณติดตามได้"
local: "คุณสามารถดูโพสต์จากผู้ใช้ทั้งหมดบนเซิร์ฟเวอร์นี้"
- social: "จะแสดงโพสต์ทั้งจากไทม์ไลน์หลักและไทม์ไลน์ท้องถิ่น"
+ social: "โพสต์จากทั้งไทม์ไลน์หน้าแรกและไทม์ไลน์ในพื้นที่ของคุณจะปรากฏขึ้น"
global: "คุณสามารถดูโพสต์จากเซิร์ฟเวอร์ที่เชื่อมต่ออื่นๆ ทั้งหมดได้"
description2: "คุณสามารถสลับระหว่างแต่ละไทม์ไลน์ได้ตลอดเวลาได้ที่บริเวณด้านบนของหน้าจอ"
description3: "นอกจากนี้ยังมีรายการไทม์ไลน์ ไทม์ไลน์ของช่อง ฯลฯ โปรดดู {link} สำหรับรายละเอียดเพิ่มเติม"
@@ -1349,7 +1282,7 @@ _initialTutorial:
_visibility:
description: "คุณสามารถจำกัดผู้ที่สามารถดูโน้ตของคุณได้นะ"
public: "โน้ตของคุณนั้นจะปรากฏแก่ผู้ใช้งานทุกคน"
- home: "เผยแพร่บนไทม์ไลน์หลักเท่านั้น แต่ผู้ติดตาม ผู้ที่เข้ามาดูโปรไฟล์ และผู้ที่เห็นจากรีโน้ตยังสามารถดูโพสต์นี้ได้"
+ home: "เผยแพร่บนไทม์ไลน์หน้าแรกเท่านั้น ผู้คนที่เข้าชมโปรไฟล์ของคุณ ผ่านผู้ติดตาม และผ่านการรีโน้ตสามารถเห็นได้"
followers: "มองเห็นได้เฉพาะผู้ติดตามเท่านั้น ไม่มีใครอื่นนอกจากตัวคุณเองที่สามารถรีโน้ตได้ และมีเพียงผู้ติดตามของคุณเท่านั้นที่สามารถดูได้"
direct: "เปิดให้เห็นเฉพาะผู้ใช้ที่ระบุเท่านั้น และพวกเขาจะได้รับแจ้งเตือนด้วย คุณสามารถใช้มันแทนข้อความโดยตรง (dm)"
doNotSendConfidencialOnDirect1: "โปรดใช้ความระมัดระวังในการส่งข้อมูลที่ละเอียดอ่อน"
@@ -1357,9 +1290,9 @@ _initialTutorial:
localOnly: "การโพสต์ด้วย flag นี้จะไม่รวมโน้ตไปยังเซิร์ฟเวอร์อื่น ผู้ใช้บนเซิร์ฟเวอร์อื่นจะไม่สามารถดูโน้ตเหล่านี้ได้โดยตรง โดยไม่คำนึงถึงการตั้งค่าการแสดงผลข้างต้น"
_cw:
title: "คำเตือนเกี่ยวกับเนื้อหา"
- description: "เนื้อหาที่เขียนใน “คำอธิบายประกอบ” จะแสดงแทนเนื้อหาหลัก ต้องคลิก “ดูเพิ่มเติม” เพื่อให้เนื้อหาหลักแสดง"
+ description: "เนื้อหาที่เขียนด้วย “คำอธิบายประกอบ” จะแสดงแทนข้อความหลัก คลิก “ดูเพิ่มเติม” เพื่อแสดงข้อความเต็ม"
_exampleNote:
- cw: " ห้ามดู ระวังหิว"
+ cw: "นี่อาจจะทำให้คุณหิวอย่างแน่นอน!"
note: "เพิ่งไปกินโดนัทเคลือบช็อคโกแลตมา 🍩😋"
useCases: "ใช้สิ่งนี้เพื่อระบุโน้ตที่ต้องตามแนวทางปฏิบัติของเซิร์ฟเวอร์ หรือเพื่อควบคุมการสปอยล์และข้อความที่ละเอียดอ่อนด้วยตนเอง"
_howToMakeAttachmentsSensitive:
@@ -1375,17 +1308,17 @@ _initialTutorial:
title: "บทเรียนจบลงแล้วจ้า เย่เย่เย่ 🎉"
description: "คุณสมบัติที่แนะนำในที่นี่เป็นเพียงบางส่วนเท่านั้น หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับวิธีใช้ Misskey โปรดไปที่ {link}"
_timelineDescription:
- home: "บนไทม์ไลน์หลัก คุณสามารถดูโพสต์จากบัญชีที่ติดตามอยู่ได้"
- local: "ไทม์ไลน์ท้องถิ่นช่วยให้เห็นโพสต์จากผู้ใช้ทั้งหมดบนเซิร์ฟเวอร์นี้"
- social: "ไทม์ไลน์โซเชียลจะแสดงโพสต์จากทั้งไทม์ไลน์หลักและไทม์ไลน์ท้องถิ่น"
+ home: "บนไทม์ไลน์หน้าแรก คุณสามารถดูโพสต์จากบัญชีที่คุณติดตามได้"
+ local: "ไทม์ไลน์ในพื้นที่ช่วยให้คุณเห็นโพสต์จากผู้ใช้ทั้งหมดบนเซิร์ฟเวอร์นี้"
+ social: "ไทม์ไลน์โซเชียลจะแสดงโพสต์จากทั้งไทม์ไลน์หน้าแรกและไทม์ไลน์ในพื้นที่"
global: "ในไทม์ไลน์ทั่วโลก คุณสามารถดูโน้ตจากเซิร์ฟเวอร์ที่เชื่อมต่อทั้งหมดได้"
_serverRules:
description: "ชุดของกฎที่จะแสดงก่อนการลงทะเบียนเราขอแนะนำให้ตั้งค่าสรุปข้อกำหนดในการให้บริการ"
_serverSettings:
- iconUrl: "URL ไอคอน"
+ iconUrl: "ไอคอน URL"
appIconDescription: "ระบุไอคอนที่จะใช้เมื่อ {host} แสดงเป็นแอป"
- appIconUsageExample: "ตัวอย่างเช่น เมื่อถูกเพิ่มเป็น PWA หรือบุ๊กมาร์กบนหน้าจอหลักในสมาร์ทโฟน"
- appIconStyleRecommendation: "เนื่องจากอาจถูกครอบตัดเป็นสี่เหลี่ยมหรือวงกลม จึงแนะนำให้ใช้ภาพที่เผื่อพื้นที่รอบๆ ตัวโลโก้ไอคอนไว้"
+ appIconUsageExample: "E.g. เป็น PWA หรือเมื่อแสดงผลเป็นบุ๊กมาร์กหน้าจอหลักบนโทรศัพท์"
+ appIconStyleRecommendation: "เนื่องจากไอคอนอาจถูกครอบตัดเป็นสี่เหลี่ยมจัตุรัสหรือวงกลม จึงแนะนำให้ใช้ไอคอนที่มีขอบสีรอบๆ เนื้อหา"
appIconResolutionMustBe: "ความละเอียดขั้นต่ำไว้คือ {resolution}."
manifestJsonOverride: "เขียนทับ manifest.json"
shortName: "ชื่อย่อ"
@@ -1393,29 +1326,27 @@ _serverSettings:
fanoutTimelineDescription: "เพิ่มประสิทธิภาพการดึงข้อมูลไทม์ไลน์อย่างมาก และลดภาระในฐานข้อมูลเมื่อเปิดใช้งาน ในทางกลับกัน การใช้หน่วยความจำของ Redis จะเพิ่มขึ้น ลองปิดการใช้งานนี้ในกรณีที่หน่วยความจำเซิร์ฟเวอร์เหลือน้อยหรือเซิร์ฟเวอร์ไม่เสถียร"
fanoutTimelineDbFallback: "ฟอลแบ๊กกลับฐานข้อมูล"
fanoutTimelineDbFallbackDescription: "เมื่อเปิดใช้งาน หากไม่ได้แคชไทม์ไลน์ ไทม์ไลน์จะฟอลแบ๊กไปยังฐานข้อมูลสำหรับการ query เพิ่มเติม การปิดใช้งานจะช่วยลดภาระของเซิร์ฟเวอร์ด้วยการกำจัดกระบวนฟอลแบ๊ก แต่มันก็จะจำกัดช่วงเวลาไทม์ไลน์ที่สามารถดึงข้อมูลได้"
- inquiryUrl: "URL สำหรับการติดต่อสอบถาม"
- inquiryUrlDescription: "ระบุ URL ของหน้าเว็บที่มีแบบฟอร์มสำหรับติดต่อผู้ดูแลเซิร์ฟเวอร์ หรือข้อมูลการติดต่อของผู้ดูแลเซิร์ฟเวอร์"
_accountMigration:
- moveFrom: "ย้ายจากบัญชีอื่นมาที่บัญชีนี้"
+ moveFrom: "ย้ายข้อมูลบัญชีอื่นไปยังอีกบัญชีนี้หนึ่ง"
moveFromSub: "สร้างนามแฝงไปยังบัญชีอื่น"
- moveFromLabel: "บัญชีที่จะย้ายจาก #{n}"
- moveFromDescription: "หากต้องการโอนข้อมูลจากบัญชีอื่นมายังบัญชีนี้ จำเป็นต้องสร้างบัญชีนามแฝง (alias) ไว้ที่นี่ด้วย\nกรุณากรอกบัญชีเดิมในรูปแบบ: @username@server.example.com\nหากต้องการลบ alias, ให้เว้นว่างไว้แล้วบันทึก (ไม่แนะนำ)"
- moveTo: "ย้ายบัญชีนี้ไปยังบัญชีใหม่"
+ moveFromLabel: "บัญชีที่จะย้ายจาก:"
+ moveFromDescription: "ถ้าหากคุณต้องการโอนข้อมูล คุณจำเป็นต้องสร้างบัญชีสำรองสำหรับการย้ายบัญชี หลังจากนั้นป้อนบัญชีที่จะย้ายไปในรูปแบบต่อไปนี้: @person@instance.com"
+ moveTo: "ย้ายข้อมูลบัญชีนี้ไปยังบัญชีอีกหนึ่ง"
moveToLabel: "บัญชีที่จะย้ายไปที่:"
moveCannotBeUndone: "ไม่สามารถยกเลิกการโอนย้ายบัญชีได้"
moveAccountDescription: "การดำเนินการนี้จะย้ายบัญชีของคุณไปยังบัญชีอื่น\n・ผู้ที่กำลังติดตามคุณจากบัญชีนี้จะถูกย้ายไปยังบัญชีใหม่โดยอัตโนมัติ\n・บัญชีนี้จะเลิกติดตามผู้ใช้ทั้งหมดที่กำลังติดตามอยู่\n・คุณจะไม่สามารถสร้างโน้ต ฯลฯ ในบัญชีนี้ได้\n\nแม้ว่าการย้ายผู้ที่ติดตามคุณจะเป็นไปโดยอัตโนมัติ แต่คุณต้องเตรียมขั้นตอนบางอย่างด้วยตนเอง เพื่อย้ายรายชื่อผู้ใช้ที่คุณกำลังติดตาม โดยดำเนินการส่งออกรายชื่อแล้วค่อยนำเข้ามาภายหลังในเมนูการตั้งค่าของบัญชีใหม่ ใช้ขั้นตอนเดียวกันนี้ใช้รายชื่อผู้ใช้ที่ถูกปิดเสียงและถูกบล็อก\n\n(คำอธิบายนี้ใช้กับ Misskey v13.12.0 ขึ้นไป, ซอฟต์แวร์ ActivityPub อื่นๆ เช่น Mastodon อาจทำงานแตกต่างออกไป)"
- moveAccountHowTo: "การย้ายบัญชีจะเริ่มต้นโดยการสร้างบัญชีนามแฝง (alias) ของบัญชีนี้ ณ บัญชีที่เป็นปลายทาง หลังจากสร้างนามแฝงแล้ว ให้ป้อนบัญชีปลายทางในรูปแบบดังนี้: @username@server.example.com"
+ moveAccountHowTo: "หากต้องการย้ายข้อมูลก่อนอื่นให้สร้างชื่อแทนสำหรับบัญชีนี้ ในบัญชีที่จะต้องการย้ายไป\nหลังจากที่คุณสร้างนามแฝงนั้นแล้ว ให้ป้อนบัญชีที่ต้องการจะย้ายไปในรูปแบบดังต่อไปนี้: @username@server.example.com"
startMigration: "โอนย้าย"
migrationConfirm: "ยืนยันการย้ายข้อมูลบัญชีนี้ไปที่ {account} เมื่อเริ่มแล้วจะไม่สามารถหยุดหรือนำกลับคืนมาได้ และคุณจะไม่สามารถใช้บัญชีนี้ในสถานะดั้งเดิมได้อีกต่อไป\n\nนอกจากนี้ คุณจำเป็นต้องสร้างบัญชีสำรองสำหรับการย้ายบัญชี"
- movedAndCannotBeUndone: "\nบัญชีนี้ถูกโอนย้ายไปแล้ว\nไม่สามารถยกเลิกการโอนย้ายได้"
- postMigrationNote: "บัญชีนี้จะดำเนินการยกเลิกการติดตามทั้งหมดหลังจากการย้ายข้อมูลไปแล้ว 24 ชั่วโมง จำนวนกำลังติดตามและจำนวนผู้ติดตามของบัญชีนี้จะเป็น 0 และเพื่อหลีกเลี่ยงไม่ให้ผู้ติดตามคุณนั้นไม่สามารถเห็นโพสต์เฉพาะผู้ติดตามฯได้ การยกเลิกการติดตามจะไม่กระทบกับผู้ติดตามคุณ ดังนั้นผู้ติดตามคุณยังคงสามารถดูโพสต์ของบัญชีนี้ได้"
- movedTo: "บัญชีที่จะย้ายไป:"
+ movedAndCannotBeUndone: "\nบัญชีนี้ถูกโอนย้ายไปแล้ว\nไม่สามารถย้อนกลับโอนย้ายข้อมูลได้"
+ postMigrationNote: "บัญชีนี้จะถูกเลิกติดตามบัญชีทั้งหมดที่กำลังติดตามภายใน 24 ชั่วโมงหลังจากการย้ายข้อมูลนั้นเสร็จสิ้น ทั้งจำนวนผู้ติดตามและผู้ติดตามนั้นจะกลายเป็นศูนย์ เพื่อหลีกเลี่ยงป้องกันไม่ให้ผู้ติดตามของคุณนั้นไม่สามารถเห็นโพสต์เฉพาะผู้ติดตามของบัญชีนี้ได้ แต่อย่างไรก็ตามแล้วพวกเขาจะยังคงติดตามบัญชีนี้ต่อไป"
+ movedTo: "บัญชีที่จะย้ายไปที่:"
_achievements:
earnedAt: "ได้รับเมื่อ"
_types:
_notes1:
- title: "just setting up my msky"
- description: "โพสต์โน้ตเป็นครั้งแรก"
+ title: "just setting up my shonk"
+ description: "โพสต์โน้ตแรกของคุณ"
flavor: "ขอให้มีช่วงเวลาที่ดีกับ Misskey นะคะ!"
_notes10:
title: "โน้ตไม่กี่ชิ้น"
@@ -1475,15 +1406,15 @@ _achievements:
title: "มือใหม่ III"
description: "เข้าสู่ระบบเป็นเวลารวม 15 วัน"
_login30:
- title: "มิสคิสต์ I"
+ title: "มิสคิสท์ I"
description: "เข้าสู่ระบบเป็นเวลารวม 30 วัน"
_login60:
- title: "มิสคิสต์ II"
+ title: "มิสคิสท์ II"
description: "เข้าสู่ระบบเป็นเวลารวม 60 วัน"
_login100:
- title: "มิสคิสต์ III"
+ title: "มิสคิสท์ III"
description: "เข้าสู่ระบบเป็นเวลารวม 100 วัน"
- flavor: "Violent Misskist (ทำไมเหมือนชื่อหนังสักเรื่องจังเลยนะ)"
+ flavor: "มิสคิสต์หัวรุนแรง"
_login200:
title: "ลูกค้าประจำ I"
description: "เข้าสู่ระบบเป็นเวลารวม 200 วัน"
@@ -1515,19 +1446,19 @@ _achievements:
flavor: "ขอบคุณที่ใช้ Misskey นะ !"
_noteClipped1:
title: "อดไม่ได้ที่จะต้องคลิปมันเอาไว้"
- description: "คลิปโน้ตเป็นครั้งแรก"
+ description: "คลิปโน้ตตัวแรกของคุณ"
_noteFavorited1:
title: "สตาร์เกเซอร์"
- description: "ใส่โน้ตเป็นรายการโปรดเป็นครั้งแรก"
+ description: "ชื่นชอบโน้ตแรกของคุณ"
_myNoteFavorited1:
title: "แสวงหาดวงดาว"
- description: "โน้ตตัวเองถูกคนอื่นเพิ่มลงรายการโปรดของเขา"
+ description: "มีคนอื่นๆที่ชื่นชอบหนึ่งในโน้ตของคุณ"
_profileFilled:
title: "เตรียมตัวอย่างดี"
- description: "ตั้งค่าโปรไฟล์"
+ description: "ตั้งค่าโปรไฟล์ของคุณ"
_markedAsCat:
title: "ฉันเป็นแมว"
- description: "ตั้งค่าบัญชีเป็นแมวเมี้ยวเมี้ยว"
+ description: "ทำเครื่องหมายบัญชีของคุณว่าเป็นแมว"
flavor: "แมวน้อยไร้ชื่อ"
_following1:
title: "ก้าวแรกสู่...กดติดตาม"
@@ -1570,7 +1501,7 @@ _achievements:
description: "ได้รับความสำเร็จ 30 ครั้ง"
_viewAchievements3min:
title: "ชอบบรรลุความสําเร็จ"
- description: "มองดูรายการความสำเร็จเป็นเวลานานกว่า 3 นาที"
+ description: "มองดูรายการความสำเร็จของคุณเป็นเวลาอย่างน้อย 3 นาที"
_iLoveMisskey:
title: "ฉันรัก Misskey"
description: "โพสต์ “I ❤ #Misskey”"
@@ -1597,13 +1528,13 @@ _achievements:
flavor: "โป๊ะ โป๊ะ โป๊ะ ปิ้งงงงง"
_selfQuote:
title: "อ้างอิงตนเอง"
- description: "อ้างอิงโน้ตตัวเอง"
+ description: "อ้างโน้ตของคุณเอง"
_htl20npm:
title: "ไทม์ไลน์ไหล"
- description: "มีการทำความเร็วของไทม์ไลน์หลักเกิน 20 npm (โน้ตต่อนาที)"
+ description: "มีการทำความเร็วของไทม์ไลน์หน้าแรกเกิน 20 npm (โน้ตต่อนาที)"
_viewInstanceChart:
title: "วิเคราะห์"
- description: "ดูแผนภูมิของเซิร์ฟเวอร์"
+ description: "ดูแผนภูมิอินสแตนซ์ของคุณ"
_outputHelloWorldOnScratchpad:
title: "หวัดดีชาวโลก!"
description: "เอาพุต \"hello world\" ใน Scratchpad"
@@ -1624,16 +1555,16 @@ _achievements:
description: "มีโอกาสที่จะได้รับด้วยความน่าจะเป็นไปได้ 0.005% ทุก ๆ 10 วินาที"
_setNameToSyuilo:
title: "คอมเพล็กซ์ของพระเจ้า"
- description: "ตั้งชื่อเป็น “syuilo”"
+ description: "ตั้งชื่อของคุณเป็น “syuilo”"
_passedSinceAccountCreated1:
title: "ครบรอบหนึ่งปี"
- description: "ผ่านไป 1 ปีนับตั้งแต่สร้างบัญชี"
+ description: "ผ่านไปหนึ่งปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ"
_passedSinceAccountCreated2:
title: "ครบรอบสองปี"
- description: "ผ่านไป 2 ปีนับตั้งแต่สร้างบัญชี"
+ description: "ผ่านไปสองปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ"
_passedSinceAccountCreated3:
title: "ครบรอบสามปี"
- description: "ผ่านไป 3 ปีนับตั้งแต่สร้างบัญชี"
+ description: "ผ่านไปสามปีแล้วนะตั้งแต่บัญชีของคุณถูกสร้างขึ้นมาน่ะ"
_loggedInOnBirthday:
title: "สุขสันต์วันเกิด"
description: "เข้าสู่ระบบในวันเกิดของคุณ"
@@ -1668,11 +1599,11 @@ _role:
name: "ชื่อบทบาท"
description: "คำอธิบายบทบาท"
permission: "สิทธิ์ตามบทบาท"
- descriptionOfPermission: "ผู้ควบคุม สามารถดำเนินการดูแลขั้นพื้นฐานได้\nผู้ดูแลระบบ สามารถเปลี่ยนการตั้งค่าทั้งหมดของเซิร์ฟเวอร์ได้"
+ descriptionOfPermission: "ผู้ควบคุม สามารถดำเนินการดูแลขั้นพื้นฐานได้\nผู้ดูแลระบบ สามารถเปลี่ยนการตั้งค่าทั้งหมดของอินสแตนซ์ได้"
assignTarget: "มอบหมาย"
descriptionOfAssignTarget: "แบบปรับเอง เพิ่มถอนบทบาทนี้แก่ผู้ใช้ด้วยตัวเอง\nแบบมีเงื่อนไข เพิ่มถอนบทบาทนี้แก่ผู้ใช้โดยอัตโนมัติหากเข้าเงื่อนไขใดต่อไปนี้"
manual: "ปรับเอง"
- manualRoles: "บทบาทแบบทำมือ"
+ manualRoles: "บทบาทแบบทำเอง"
conditional: "มีเงื่อนไข"
conditionalRoles: "บทบาทแบบมีเงื่อนไข"
condition: "เงื่อนไข"
@@ -1681,16 +1612,16 @@ _role:
descriptionOfIsPublic: "บทบาทจะปรากฏบนโปรไฟล์ของผู้ใช้และเปิดเผยต่อสาธารณะ (ทุกคนสามารถเห็นได้ว่าผู้ใช้รายนี้มีบทบาทนี้)"
options: "ตัวเลือกบทบาท"
policies: "นโยบาย"
- baseRole: "แม่แบบบทบาท"
- useBaseValue: "ใช้ตามแม่แบบบทบาท"
+ baseRole: "เทมเพลตบทบาท"
+ useBaseValue: "ใช้ตามเทมเพลตบทบาท"
chooseRoleToAssign: "เลือกบทบาทที่ต้องการกำหนด"
- iconUrl: "URL ไอคอน"
+ iconUrl: "ไอคอน URL"
asBadge: "แสดงเป็นตรา"
descriptionOfAsBadge: "เมื่อเปิดใช้งาน ไอคอนบทบาทจะปรากฏถัดจากชื่อผู้ใช้"
isExplorable: "ค้นหาผู้ใช้ได้ง่ายขึ้นโดยดูจากบทบาท"
descriptionOfIsExplorable: "เมื่อเปิดใช้งาน ไทมไลน์บทบาทนี้และสมาชิกที่มีบทบาทนี้จะเปิดเผยเป็นสาธารณะ"
- displayOrder: "ลำดับการแสดงผล"
- descriptionOfDisplayOrder: "เลขที่สูงกว่าจะแสดงบน UI ก่อน"
+ displayOrder: "ตำแหน่ง"
+ descriptionOfDisplayOrder: "ยิ่งตัวเลขสูง ตำแหน่ง UI ก็ยิ่งสูงขึ้นนะ"
canEditMembersByModerator: "อนุญาตให้ผู้ควบคุมแก้ไขสมาชิก"
descriptionOfCanEditMembersByModerator: "เมื่อเปิดใช้ นอกเหนือจากผู้ควบคุมและผู้ดูแลระบบแล้ว จะสามารถเพิ่มถอนบทบาทนี้แก่ผู้ใช้ได้ แต่เมื่อปิดใช้ จะมีเฉพาะผู้ดูแลระบบเท่านั้นที่จะสามารถดำเนินการได้"
priority: "ลำดับความสำคัญ"
@@ -1699,11 +1630,10 @@ _role:
middle: "ปานกลาง"
high: "สูง"
_options:
- gtlAvailable: "สามารถดูไทม์ไลน์ทั่วโลกได้"
- ltlAvailable: "สามารถดูไทม์ไลน์ท้องถิ่นได้"
+ gtlAvailable: "การดูไทม์ไลน์ทั่วโลก"
+ ltlAvailable: "การดูไทม์ไลน์ในท้องถิ่น"
canPublicNote: "สามารถโพสต์แบบสาธารณะ"
- mentionMax: "จำนวนการกล่าวถึงสูงสุดต่อโน้ต"
- canInvite: "สร้างรหัสเชิญเข้าเซิร์ฟเวอร์"
+ canInvite: "สร้างรหัสเชิญอินสแตนซ์"
inviteLimit: "จำกัดการเชิญ"
inviteLimitCycle: "คูลดาวน์ในการเชิญ"
inviteExpirationTime: "วันหมดอายุของรหัสการเชิญ"
@@ -1711,7 +1641,6 @@ _role:
canManageAvatarDecorations: "จัดการตกแต่งอวตาร"
driveCapacity: "ความจุของไดรฟ์"
alwaysMarkNsfw: "ทำเครื่องหมายไฟล์ว่าเป็น NSFW เสมอ"
- canUpdateBioMedia: "อนุญาตให้ปรับปรุงไอคอนและแบนเนอร์"
pinMax: "จํานวนสูงสุดของโน้ตที่ปักหมุดไว้"
antennaMax: "จำนวนสูงสุดของเสาอากาศ"
wordMuteMax: "จำนวนอักขระสูงสุดที่อนุญาตในการปิดเสียงคำ"
@@ -1727,14 +1656,8 @@ _role:
canUseTranslator: "การใช้งานแปล"
avatarDecorationLimit: "จำนวนการตกแต่งไอคอนสูงสุดที่สามารถติดตั้งได้"
_condition:
- roleAssignedTo: "มอบหมายให้มีบทบาทแบบทำมือ"
- isLocal: "ผู้ใช้ท้องถิ่น"
+ isLocal: "ผู้ใช้ในพื้นที่"
isRemote: "ผู้ใช้ระยะไกล"
- isCat: "ผู้ใช้ที่เป็นแมว"
- isBot: "ผู้ใช้ที่เป็นบอต"
- isSuspended: "ผู้ใช้ที่ถูกระงับ"
- isLocked: "ผู้ใช้บัญชีไม่เปิดเผยสาธารณะ"
- isExplorable: "ผู้ใช้ที่เปิดใช้งาน “ทำให้บัญชีของฉันค้นหาได้ง่ายขึ้น”"
createdLessThan: "สร้างน้อยกว่า"
createdMoreThan: "สร้างมากกว่า"
followersLessThanOrEq: "จำนวนผู้ติดตามน้อยกว่าหรือเท่ากับ\n"
@@ -1762,13 +1685,13 @@ _emailUnavailable:
smtp: "เซิร์ฟเวอร์อีเมลนี้ไม่มีการตอบสนอง"
banned: "คุณไม่สามารถลงทะเบียนด้วยที่อยู่อีเมลนี้ได้"
_ffVisibility:
- public: "สาธารณะ"
+ public: "เผยแพร่"
followers: "ปรากฏให้แก่ผู้ติดตามเท่านั้น"
private: "ส่วนตัว"
_signup:
almostThere: "เกือบจะเสร็จแล้ว"
emailAddressInfo: "กรุณากรอกที่อยู่อีเมลที่คุณใช้ ที่อยู่อีเมลของคุณจะไม่ถูกเผยแพร่สู่สาธารณชน"
- emailSent: "อีเมลยืนยันได้ถูกส่งไปยังที่อยู่อีเมลที่คุณป้อน ({email}) แล้ว กรุณาติดตามลิงก์ในอีเมลเพื่อสร้างบัญชีให้เสร็จสมบูรณ์ ลิงก์ที่ให้ไว้จะหมดอายุใน 30 นาที"
+ emailSent: "เราได้ส่งอีเมลยืนยันไปยังที่อยู่อีเมลของคุณแล้วนะ ({email}) โปรดคลิกลิงก์ที่รวมไว้เพื่อสร้างบัญชีให้เสร็จสิ้น"
_accountDelete:
accountDelete: "ลบบัญชีผู้ใช้"
mayTakeTime: "เนื่องจากการลบบัญชีนี้จะเป็นกระบวนการที่ต้องใช้ทรัพยากรมาก จึงอาจจะต้องใช้เวลาสักครู่ถึงจะเสร็จสมบูรณ์ ทั้งนี้ขึ้นอยู่กับจำนวนเนื้อหาที่คุณสร้างและจำนวนไฟล์ที่คุณอัปโหลดนะ"
@@ -1787,8 +1710,8 @@ _ad:
adsTooClose: "เนื่องจากช่วงเวลาการแสดงโฆษณาสั้นมาก ประสบการณ์ผู้ใช้จึงอาจลดลงอย่างมาก"
_forgotPassword:
enterEmail: "ป้อนที่อยู่อีเมลที่คุณเคยใช้ในการลงทะเบียนไว้ ลิงก์ที่คุณสามารถรีเซ็ตรหัสผ่านได้นั้นจะถูกส่งไปนะ"
- ifNoEmail: "หากลงทะเบียนแบบไม่ใช้อีเมล โปรดติดต่อผู้ดูแลระบบ"
- contactAdmin: "เนื่องจากเซิร์ฟเวอร์นี้ไม่รองรับการส่งอีเมล หากต้องการรีเซ็ตรหัสผ่าน กรุณาติดต่อผู้ดูแลระบบ"
+ ifNoEmail: "ถ้าหากคุณไม่ได้ใช้อีเมลระหว่างการลงทะเบียน กรุณาติดต่อผู้ดูแลระบบอินสแตนซ์แทนนะ"
+ contactAdmin: "อินสแตนซ์นี้ไม่รองรับการใช้งานที่อยู่อีเมลนี้ กรุณาติดต่อผู้ดูแลระบบอินสแตนซ์เพื่อรีเซ็ตรหัสผ่านของคุณแทน"
_gallery:
my: "แกลลอรี่ของฉัน"
liked: "โพสต์ที่ถูกใจ"
@@ -1804,25 +1727,24 @@ _plugin:
installWarn: "กรุณาอย่าติดตั้งปลั๊กอินที่ไม่น่าเชื่อถือนะคะ"
manage: "จัดการปลั๊กอิน"
viewSource: "ดูต้นฉบับ"
- viewLog: "แสดงปูม"
_preferencesBackups:
- list: "การตั้งค่าที่สำรองไว้"
- saveNew: "บันทึกการตั้งค่าสำรองใหม่"
+ list: "สร้างการสำรองข้อมูล"
+ saveNew: "บันทึกใหม่"
loadFile: "โหลดจากไฟล์"
apply: "นำไปใช้กับอุปกรณ์นี้"
save: "บันทึก"
- inputName: "กรุณาป้อนชื่อการตั้งค่าสำรองนี้"
+ inputName: "กรุณาป้อนชื่อสำหรับข้อมูลสำรองนี้"
cannotSave: "การบันทึกล้มเหลว"
- nameAlreadyExists: "มีการตั้งค่าสำรองชื่อ “{name}” อยู่แล้ว กรุณาป้อนชื่ออื่น"
- applyConfirm: "ต้องการใช้การตั้งค่าสำรอง “{name}” กับอุปกรณ์นี้ใช่ไหม? การตั้งค่าที่มีอยู่บนอุปกรณ์นี้จะถูกเขียนทับ"
- saveConfirm: "บันทึกการตั้งค่าสำรองเป็น {name} ใช่ไหม?"
- deleteConfirm: "ต้องการลบ {name} ใช่ไหม?"
- renameConfirm: "ต้องการเปลี่ยนชื่อจาก “{old}” เป็น “{new}” ใช่ไหม?"
- noBackups: "ไม่มีการตั้งค่าสำรอง สามารถบันทึกการตั้งค่าไคลเอนต์ปัจจุบันไปยังเซิร์ฟเวอร์ด้วย “บันทึกการตั้งค่าสำรองใหม่”"
+ nameAlreadyExists: "มีข้อมูลสำรองชื่อ \"{name}\" นี้อยู่แล้ว กรุณาป้อนชื่ออื่นนะ"
+ applyConfirm: "คุณต้องการใช้ข้อมูลสำรอง \"{name}\" กับอุปกรณ์นี้อย่างงั้นจริงหรอ การตั้งค่าที่มีอยู่ของอุปกรณ์นี้จะถูกเขียนทับนะ"
+ saveConfirm: "บันทึกข้อมูลสำรองเป็น {name} มั้ย?"
+ deleteConfirm: "ลบข้อมูลสำรอง {name} มั้ย?"
+ renameConfirm: "เปลี่ยนชื่อข้อมูลสำรองนี้จาก \"{old}\" เป็น \"{new}\" หรือไม่?"
+ noBackups: "ไม่มีข้อมูลสำรองนะ คุณสามารถสำรองข้อมูลการตั้งค่าไคลเอนต์ของคุณบนเซิร์ฟเวอร์นี้โดยใช้ \"สร้างการสำรองข้อมูลใหม่\"ได้นะ"
createdAt: "สร้างเมื่อ: {date} {time}"
updatedAt: "อัปเดตเมื่อ: {date} {time}"
cannotLoad: "การโหลดล้มเหลว"
- invalidFile: "รูปแบบไฟล์ไม่ถูกต้อง"
+ invalidFile: "รูปแบบไฟล์ไม่ถูกต้องนะ"
_registry:
scope: "สโคป"
key: "คีย์"
@@ -1834,16 +1756,14 @@ _aboutMisskey:
contributors: "ผู้สนับสนุนหลัก"
allContributors: "ผู้มีส่วนร่วมทั้งหมด"
source: "ซอร์สโค้ด"
- original: "ต้นฉบับ"
- thisIsModifiedVersion: "{name} ใช้ Misskey เวอร์ชันดัดแปลง"
translation: "แปลภาษา Misskey"
donate: "บริจาคให้กับ Misskey"
- morePatrons: "และอีกหลายท่านที่ไม่ได้เอ่ยนาม ขอบคุณที่ร่วมช่วยเหลือตลอดมานะคะ 🥰"
- patrons: "ผู้อุปถัมภ์"
+ morePatrons: " ขอบคุณทุกท่านที่ร่วมกันช่วยเหลือตลอดมานะคะ 🥰"
+ patrons: "สมาชิกพันธมิตร"
projectMembers: "สมาชิกในโครงการ"
_displayOfSensitiveMedia:
- respect: "ซ่อนสื่อที่มีเนื้อหาละเอียดอ่อน"
- ignore: "แสดงสื่อที่มีเนื้อหาละเอียดอ่อน"
+ respect: "ซ่อนสื่อที่ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน"
+ ignore: "แสดงสื่อที่ทำเครื่องหมายว่ามีเนื้อหาละเอียดอ่อน"
force: "ซ่อนสื่อทั้งหมด"
_instanceTicker:
none: "ไม่ต้องแสดง"
@@ -1873,13 +1793,13 @@ _menuDisplay:
hide: "ซ่อน"
_wordMute:
muteWords: "ปิดเสียงคำ"
- muteWordsDescription: "คั่นด้วยเว้นวรรคสำหรับเงื่อนไข AND, หรือขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR"
+ muteWordsDescription: "คั่นด้วยช่องว่างสำหรับเงื่อนไข AND หรือด้วยการขึ้นบรรทัดใหม่สำหรับเงื่อนไข OR นะ"
muteWordsDescription2: "ล้อมรอบคีย์เวิร์ดด้วยเครื่องหมายทับเพื่อใช้นิพจน์ทั่วไป"
_instanceMute:
- instanceMuteDescription: "ปิดเสียง “โน้ต/รีโน้ต” ทั้งหมดจากเซิร์ฟเวอร์ที่ระบุไว้ รวมถึงโน้ตของผู้ใช้ที่ตอบกลับผู้ใช้จากเซิร์ฟเวอร์ที่ถูกปิดเสียง"
+ instanceMuteDescription: "การดำเนินการนี้จะปิดเสียง\"โน้ต/รีโน้ต\"จากอินสแตนซ์ที่อยู่ในรายการ รวมถึงบันทึกของผู้ใช้ที่ตอบกลับผู้ใช้จากอินสแตนซ์ที่ปิดเสียง"
instanceMuteDescription2: "คั่นด้วยการขึ้นบรรทัดใหม่"
- title: "ซ่อนโน้ตจากเซิร์ฟเวอร์ที่มีระบุไว้"
- heading: "เซิร์ฟเวอร์ที่ถูกปิดเสียง"
+ title: "ซ่อนโน้ตจากอินสแตนซ์ที่มีอยู่ในรายชื่อ"
+ heading: "รายชื่ออินสแตนซ์ที่ถูกปิดเสียง"
_theme:
explore: "สำรวจธีม"
install: "ติดตั้งธีม"
@@ -1911,8 +1831,8 @@ _theme:
importInfo: "ถ้าหากต้องการป้อนโค้ดที่นี่ คุณยังสามารถนำเข้าไปยังโปรแกรมแก้ไขธีมได้"
deleteConstantConfirm: "คุณต้องการลบค่าคงที่ {const} หรือป่าว?"
keys:
- accent: "สีหลัก"
- bg: "พื้นหลัง"
+ accent: "เน้น"
+ bg: "ภาพพื้นหลัง"
fg: "ข้อความ"
focus: "โฟกัส"
indicator: "ตัวบ่งชี้"
@@ -1943,17 +1863,20 @@ _theme:
buttonBg: "ปุ่มพื้นหลัง"
buttonHoverBg: "ปุ่มพื้นหลัง (โฮเวอร์)"
inputBorder: "เส้นขอบของช่องป้อนข้อมูล"
+ listItemHoverBg: "รายการไอเทมพื้นหลัง (โฮเวอร์)"
driveFolderBg: "พื้นหลังโฟลเดอร์ไดรฟ์"
wallpaperOverlay: "วอลล์เปเปอร์ซ้อนทับ"
badge: "ตรา"
messageBg: "พื้นหลังแชท"
- accentDarken: "สีหลัก (มืด)"
- accentLighten: "สีหลัก (สว่าง)"
+ accentDarken: "เน้น (มืด)"
+ accentLighten: "เน้น (สว่าง)"
fgHighlighted: "ข้อความที่ไฮไลต์"
_sfx:
- note: "โน้ต"
+ note: "หมายเหตุ"
noteMy: "โน้ตของตัวเอง"
notification: "การเเจ้งเตือน"
+ antenna: "เสาอากาศ"
+ channel: "การแจ้งเตือนช่อง"
reaction: "เมื่อเลือกรีแอคชั่น"
_soundSettings:
driveFile: "ใช้เสียงจากไดรฟ์"
@@ -1961,8 +1884,7 @@ _soundSettings:
driveFileTypeWarn: "ไม่รองรับไฟล์นี้"
driveFileTypeWarnDescription: "กรุณาเลือกไฟล์เสียง"
driveFileDurationWarn: "เสียงยาวเกินไป"
- driveFileDurationWarnDescription: "การใช้เสียงที่ยาว อาจรบกวนการใช้งาน Misskey, ต้องการดำเนินการต่อใช่ไหม?"
- driveFileError: "ไม่สามารถโหลดไฟล์เสียงได้ กรุณาเปลี่ยนแปลงการตั้งค่า"
+ driveFileDurationWarnDescription: "การใช้เสียงที่ยาวอาจรบกวนการใช้งาน Misskey, ต้องการดำเนินการต่อหรือไม่?"
_ago:
future: "อนาคต"
justNow: "เมื่อกี๊นี้"
@@ -1992,6 +1914,7 @@ _2fa:
registerTOTP: "ลงทะเบียนแอพตัวตรวจสอบสิทธิ์"
step1: "ขั้นตอนแรก ติดตั้งแอปยืนยันตัวตน (เช่น {a} หรือ {b}) บนอุปกรณ์ของคุณ"
step2: "จากนั้นสแกนรหัส QR ที่แสดงบนหน้าจอนี้"
+ step2Click: "การคลิกที่รหัส QR นี้จะช่วยให้คุณนั้นสามารถลงทะเบียน 2FA กับคีย์ความปลอดภัยหรือแอปตรวจสอบความถูกต้องของโทรศัพท์ได้"
step2Uri: "ป้อนใส่ URL ดังต่อไปนี้ถ้าหากคุณใช้โปรแกรมเดสก์ท็อป"
step3Title: "ป้อนรหัสยืนยัน"
step3: "ป้อนโทเค็นที่แอปของคุณให้มาเพื่อเสร็จสิ้นการตั้งค่า"
@@ -2006,78 +1929,78 @@ _2fa:
removeKey: "ลบคีย์ความปลอดภัยออก"
removeKeyConfirm: "ลบข้อมูลสำรอง {name} มั้ย?"
whyTOTPOnlyRenew: "ไม่สามารถลบแอปตัวรับรองความถูกต้องได้ตราบใดที่มีการลงทะเบียนคีย์ความปลอดภัยไว้แล้ว"
- renewTOTP: "ตั้งค่าแอปยืนยันตัวตน"
+ renewTOTP: "กำหนดค่าแอพตัวตรวจสอบสิทธิ์ใหม่"
renewTOTPConfirm: "วิธีการแบบนี้จะทําให้รหัสยืนยันจากแอพก่อนหน้าของคุณหยุดทํางานเลยนะ"
renewTOTPOk: "ตั้งค่าคอนฟิกใหม่"
renewTOTPCancel: "ไม่เป็นไร"
- checkBackupCodesBeforeCloseThisWizard: "โปรดตรวจสอบรหัสแบ๊กอัปด้านล่างก่อนที่จะปิดวิซาร์ดนี้"
- backupCodes: "รหัสแบ๊กอัป"
+ checkBackupCodesBeforeCloseThisWizard: "โปรดตรวจสอบรหัสสำรองด้านล่างก่อนที่จะปิดวิซาร์ดนี้"
+ backupCodes: "รหัสสำรองข้อมูล"
backupCodesDescription: "หากแอปยืนยันตัวตนของคุณไม่พร้อมใช้งาน คุณสามารถใช้รหัสสำรองด้านล่างเพื่อเข้าถึงบัญชีของคุณได้ อย่าลืมเก็บรหัสเหล่านี้ไว้ในที่ปลอดภัย แต่ละรหัสสามารถใช้ได้เพียงครั้งเดียวเท่านั้น"
- backupCodeUsedWarning: "รหัสแบ๊กอัปถูกใช้งานแล้ว หากแอปพลิเคชันการยืนยันตัวตนไม่สามารถใช้งานได้ ให้รีบทำการตั้งค่าแอปฯใหม่โดยเร็วที่สุด"
- backupCodesExhaustedWarning: "รหัสแบ๊กอัปทั้งหมดถูกใช้งานแล้ว หากยังไม่สามารถใช้แอปพลิเคชันการยืนยันตัวตนได้ก็จะไม่สามารถเข้าถึงบัญชีนี้ได้อีกต่อไป กรุณาลงทะเบียนแอปพลิเคชันการยืนยันตัวตนใหม่"
- moreDetailedGuideHere: "คลิกที่นี่เพื่อดูคำแนะนำโดยละเอียด"
+ backupCodeUsedWarning: "มีการใช้รหัสสำรองแล้ว โปรดกรุณากำหนดค่าการตรวจสอบสิทธิ์แบบสองปัจจัยโดยเร็วที่สุดถ้าหากคุณยังไม่สามารถใช้งานได้อีก"
+ backupCodesExhaustedWarning: "รหัสสำรองทั้งหมดถูกใช้แล้ว ถ้าหากคุณยังสูญเสียการเข้าถึงแอปการตรวจสอบสิทธิ์แบบสองปัจจัยคุณจะยังไม่สามารถเข้าถึงบัญชีนี้ได้ กรุณากำหนดค่าการรับรองความถูกต้องด้วยการยืนยันสองชั้น"
_permissions:
- "read:account": "ดูข้อมูลบัญชี"
- "write:account": "แก้ไขข้อมูลบัญชี"
- "read:blocks": "ดูรายชื่อผู้ใช้ที่ถูกบล็อก"
- "write:blocks": "แก้ไขรายชื่อผู้ใช้ที่ถูกบล็อก"
- "read:drive": "เข้าถึงไดรฟ์"
- "write:drive": "จัดการไดรฟ์"
+ "read:account": "ดูข้อมูลบัญชีของคุณ"
+ "write:account": "แก้ไขข้อมูลบัญชีของคุณ"
+ "read:blocks": "ดูรายชื่อผู้ใช้ที่ถูกบล็อกของคุณ"
+ "write:blocks": "แก้ไขรายชื่อผู้ใช้ที่ถูกบล็อกของคุณ"
+ "read:drive": "เข้าถึงไฟล์และโฟลเดอร์ในไดรฟ์ของคุณ"
+ "write:drive": "แก้ไขหรือลบไฟล์และโฟลเดอร์ในไดรฟ์ของคุณ"
"read:favorites": "ดูรายการโปรด"
"write:favorites": "แก้ไขรายการโปรด"
"read:following": "ดูข้อมูลว่าใครที่คุณติดตาม"
"write:following": "ติดตามหรือเลิกติดตามบัญชีอื่น"
- "read:messaging": "ดูแชท"
+ "read:messaging": "ดูแชทของคุณ"
"write:messaging": "เขียนหรือลบข้อความแชท"
- "read:mutes": "ดูรายชื่อผู้ใช้ที่ถูกปิดเสียง"
+ "read:mutes": "ดูรายชื่อผู้ใช้ที่ปิดเสียงของคุณ"
"write:mutes": "แก้ไขรายชื่อผู้ใช้ที่ถูกปิดเสียง"
"write:notes": "เขียนหรือลบโน้ต"
- "read:notifications": "ดูการแจ้งเตือน"
- "write:notifications": "จัดการแจ้งเตือน"
- "read:reactions": "ดูรีแอคชั่น"
- "write:reactions": "แก้ไขรีแอคชั่น"
+ "read:notifications": "ดูการแจ้งเตือนของคุณ"
+ "write:notifications": "จัดการแจ้งเตือนของคุณ"
+ "read:reactions": "ดูรีแอคชั่นของคุณ"
+ "write:reactions": "แก้ไขรีแอคชั่นของคุณ"
"write:votes": "โหวตบนสำรวจความคิดเห็น"
- "read:pages": "ดูหน้าเพจ"
- "write:pages": "แก้ไขหรือลบเพจ"
+ "read:pages": "ดหน้าเพจ"
+ "write:pages": "แก้ไขหรือลบเพจของคุณ"
"read:page-likes": "ดูรายการเพจที่ถูกใจไว้"
"write:page-likes": "แก้ไขรายการเพจที่ถูกใจ"
- "read:user-groups": "ดูกลุ่มผู้ใช้"
- "write:user-groups": "แก้ไขหรือลบกลุ่มผู้ใช้"
- "read:channels": "ดูช่อง"
- "write:channels": "แก้ไขช่อง"
+ "read:user-groups": "ดูกลุ่มผู้ใช้ของคุณ"
+ "write:user-groups": "แก้ไขหรือลบกลุ่มผู้ใช้ของคุณ"
+ "read:channels": "ดูแชนแนลของคุณ"
+ "write:channels": "แก้ไขแชนแนลของคุณ"
"read:gallery": "ดูแกลเลอรี่"
- "write:gallery": "แก้ไขแกลเลอรี"
- "read:gallery-likes": "ดูแกลเลอรีที่ถูกใจไว้"
- "write:gallery-likes": "จัดการแกลเลอรีที่ถูกใจไว้"
- "read:flash": "ดู Play"
- "write:flash": "แก้ไข Play"
+ "write:gallery": "แก้ไขแกลเลอรี่ของคุณ"
+ "read:gallery-likes": "ดูรายการโพสต์แกลเลอรีที่ถูกใจไว้"
+ "write:gallery-likes": "แก้ไขรายการโพสต์แกลเลอรีที่ถูกใจไว้"
+ "read:flash": "วิว เพลย์"
+ "write:flash": "แก้ไขเพลย์"
"read:flash-likes": "ดูรายการ play ที่ถูกใจไว้"
"write:flash-likes": "แก้ไขรายการ play ที่ถูกใจไว้"
"read:admin:abuse-user-reports": "ดูรายงานจากผู้ใช้"
"write:admin:delete-account": "ลบบัญชีผู้ใช้"
"write:admin:delete-all-files-of-a-user": "ลบไฟล์ทั้งหมดของผู้ใช้"
"read:admin:index-stats": "ดูข้อมูลเกี่ยวกับดัชนีฐานข้อมูล"
- "read:admin:table-stats": "ดูข้อมูลเกี่ยวกับตารางในฐานข้อมูล"
+ "read:admin:table-stats": "ดูข้อมูลเกี่ยวกับตารางฐานข้อมูล"
"read:admin:user-ips": "ดูที่อยู่ IP ของผู้ใช้"
- "read:admin:meta": "ดูข้อมูลอภิพันธุ์ของอินสแตนซ์"
+ "read:admin:meta": "ดูข้อมูลเมตาของอินสแตนซ์"
"write:admin:reset-password": "รีเซ็ตรหัสผ่านของผู้ใช้"
"write:admin:resolve-abuse-user-report": "แก้ไขรายงานจากผู้ใช้"
"write:admin:send-email": "ส่งอีเมล"
"read:admin:server-info": "ดูข้อมูลเซิร์ฟเวอร์"
- "read:admin:show-moderation-log": "ดูปูมการควบคุมดูแล"
+ "read:admin:show-moderation-log": "ดูปูมการแก้ไข"
"read:admin:show-user": "ดูข้อมูลส่วนตัวของผู้ใช้"
+ "read:admin:show-users": "ดูข้อมูลส่วนตัวของผู้ใช้"
"write:admin:suspend-user": "ระงับผู้ใช้"
"write:admin:unset-user-avatar": "ลบอวตารผู้ใช้"
"write:admin:unset-user-banner": "ลบแบนเนอร์ผู้ใช้"
"write:admin:unsuspend-user": "ยกเลิกการระงับผู้ใช้"
- "write:admin:meta": "จัดการข้อมูลอภิพันธุ์ของอินสแตนซ์"
+ "write:admin:meta": "จัดการข้อมูลเมตาของอินสแตนซ์"
"write:admin:user-note": "จัดการโน้ตการกลั่นกรอง"
"write:admin:roles": "จัดการบทบาท"
"read:admin:roles": "ดูบทบาท"
"write:admin:relays": "จัดการรีเลย์"
"read:admin:relays": "ดูรีเลย์"
- "write:admin:invite-codes": "จัดการรหัสเชิญ"
- "read:admin:invite-codes": "ดูรหัสเชิญ"
+ "write:admin:invite-codes": "จัดการคำเชิญ"
+ "read:admin:invite-codes": "ดูรหัสคำเชิญ"
"write:admin:announcements": "จัดการประกาศ"
"read:admin:announcements": "ดูประกาศ"
"write:admin:avatar-decorations": "จัดการการตกแต่งอวตาร"
@@ -2095,16 +2018,16 @@ _permissions:
"read:admin:stream": "ใช้ Websocket API สำหรับผู้ดูแลระบบ"
"write:admin:ad": "จัดการโฆษณา"
"read:admin:ad": "ดูโฆษณา"
- "write:invite-codes": "สร้างรหัสเชิญ"
+ "write:invite-codes": "สร้างรหัสคำเชิญ"
"read:invite-codes": "รับรหัสเชิญ"
- "write:clip-favorite": "จัดการคลิปที่ถูกใจ"
- "read:clip-favorite": "ดูคลิปที่ถูกใจ"
+ "write:clip-favorite": "ควบคุมการถูกใจของคลิป"
+ "read:clip-favorite": "ดูการถูกใจของคลิป"
"read:federation": "รับข้อมูลเกี่ยวกับสหพันธ์"
"write:report-abuse": "รายงานการละเมิด"
_auth:
shareAccessTitle: "การให้สิทธิ์แอปพลิเคชัน"
shareAccess: "คุณต้องการอนุญาตให้ \"{name}\" เข้าถึงบัญชีนี้เลยมั้ย?"
- shareAccessAsk: "ต้องการอนุญาตให้แอปพลิเคชันนี้เข้าถึงบัญชีของคุณใช่ไหม?"
+ shareAccessAsk: "ต้องการอนุญาตให้แอปพลิเคชันนี้เข้าถึงบัญชีของคุณหรือไม่?"
permission: "{name} ได้ขอสิทธิ์การเข้าถึงดังต่อไปนี้"
permissionAsk: "แอปพลิเคชันนี้ขอสิทธิ์ดังต่อไปนี้"
pleaseGoBack: "กรุณากลับไปที่แอปพลิเคชัน"
@@ -2127,7 +2050,7 @@ _weekday:
saturday: "วันเสาร์"
_widgets:
profile: "โปรไฟล์"
- instanceInfo: "ข้อมูลเซิร์ฟเวอร์"
+ instanceInfo: "ข้อมูล อินสแตนซ์"
memo: "โน้ตแปะ"
notifications: "การเเจ้งเตือน"
timeline: "ไทม์ไลน์"
@@ -2141,16 +2064,16 @@ _widgets:
digitalClock: "นาฬิกาดิจิตอล"
unixClock: "นาฬิกา UNIX"
federation: "สหพันธ์"
- instanceCloud: "กลุ่มเมฆเซิร์ฟเวอร์"
+ instanceCloud: "อินสแตนซ์คลาวด์"
postForm: "แบบฟอร์มการโพสต์"
slideshow: "แสดงภาพนิ่ง"
button: "ปุ่ม"
onlineUsers: "ผู้ใช้ที่ออนไลน์"
jobQueue: "คิวงาน"
serverMetric: "ตัวชี้วัดเซิร์ฟเวอร์"
- aiscript: " คอนโซล AiScript"
- aiscriptApp: "แอป AiScript"
- aichan: "藍 (ไอ)"
+ aiscript: "AiScript คอนโซล"
+ aiscriptApp: "AiScript แอพ"
+ aichan: "ไอ"
userList: "รายชื่อผู้ใช้"
_userList:
chooseList: "เลือกรายชื่อ"
@@ -2163,47 +2086,47 @@ _cw:
files: "{count} ไฟล์"
_poll:
noOnlyOneChoice: "จำเป็นต้องมีอย่างน้อยสองตัวเลือก"
- choiceN: "ตัวเลือกที่ {n}"
- noMore: "เพิ่มตัวเลือกอีกไม่ได้แล้ว"
+ choiceN: "ตัวเลือก {n}"
+ noMore: "คุณไม่สามารถเพิ่มตัวเลือกอื่นได้"
canMultipleVote: "สามารถตอบได้หลายคำตอบ"
- expiration: "สิ้นสุดโพล"
- infinite: "ไม่กำหนดระยะเวลา"
- at: "ระบุวันเวลา"
- after: "ระบุระยะเวลา"
+ expiration: "สิ้นสุดการสำรวจความคิดเห็น"
+ infinite: "ไม่ต้องเลย"
+ at: "จบที่..."
+ after: "สิ้นสุดหลัง..."
deadlineDate: "วันสิ้นสุด"
- deadlineTime: "เวลา"
+ deadlineTime: "ชั่วโมง"
duration: "ระยะเวลา"
votesCount: "{n} คะแนนเสียง"
- totalVotes: "ทั้งหมด {n} คะแนนเสียง"
+ totalVotes: "{n} คะแนนเสียงทั้งหมด"
vote: "โหวต"
showResult: "ดูผลลัพธ์"
voted: "โหวตแล้ว"
closed: "สิ้นสุดแล้ว"
- remainingDays: "เหลืออีก {d} วัน {h} ชั่วโมง"
- remainingHours: "เหลืออีก {h} ชั่วโมง {m} นาที"
- remainingMinutes: "เหลืออีก {m} นาที {s} วินาที"
- remainingSeconds: "เหลืออีก {s} วินาที"
+ remainingDays: "จะเสร็จสิ้นในอีก {d} วัน {h} ชั่วโมง"
+ remainingHours: "{h} ชั่วโมง(s) {m} นาที(s) ที่เหลืออยู่"
+ remainingMinutes: "{m} นาที(s) {s} วินาที(s) ที่เหลืออยู่"
+ remainingSeconds: "{s} นาที(s) ที่เหลืออยู่"
_visibility:
public: "สาธารณะ"
publicDescription: "โน้ตของคุณจะปรากฏแก่ผู้ใช้ทุกคน"
- home: "หน้าหลัก"
- homeDescription: "โพสต์ลงไทม์ไลน์หลักเท่านั้น"
+ home: "หน้าแรก"
+ homeDescription: "โพสลงไทม์ไลน์ที่บ้านเท่านั้น"
followers: "ผู้ติดตาม"
- followersDescription: "เฉพาะผู้ติดตามเท่านั้นที่มองเห็นได้"
+ followersDescription: "ทำให้ผู้ติดตามนั้นมองเห็นแค่คุณเท่านั้น"
specified: "ไดเร็ค"
specifiedDescription: "ทำให้มองเห็นได้เฉพาะผู้ใช้ที่ระบุเท่านั้น"
- disableFederation: "การปิดใช้งานสหพันธ์"
- disableFederationDescription: "อย่าส่งข้อมูลไปยังเซิร์ฟเวอร์อื่น"
+ disableFederation: "ไม่มีสหพันธ์"
+ disableFederationDescription: "อย่าส่งไปยังอินสแตนซ์อื่น"
_postForm:
replyPlaceholder: "ตอบกลับโน้ตนี้..."
quotePlaceholder: "อ้างโน้ตนี้..."
channelPlaceholder: "โพสต์ลงช่อง..."
_placeholders:
- a: "ตอนนี้เป็นยังไงบ้าง?"
- b: "มีอะไรเกิดขึ้นหรือเปล่า?"
- c: "กำลังคิดอะไรอยู่?"
- d: "ต้องการจะพูดอะไรไหม?"
- e: "มาเขียนกันเถอะ"
+ a: "คุณเป็นอะไรไปหรอ?"
+ b: "เกิดอะไรขึ้นรอบตัวคุณ?"
+ c: "คุณกำลังคิดอะไรอยู่?"
+ d: "คุณต้องการจะพูดอะไร?"
+ e: "เริ่มเขียน..."
f: "กำลังรอให้คุณเขียน..."
_profile:
name: "ชื่อ"
@@ -2217,11 +2140,11 @@ _profile:
metadataContent: "เนื้อหา"
changeAvatar: "เปลี่ยนอวาตาร์"
changeBanner: "เปลี่ยนแบนเนอร์"
- verifiedLinkDescription: "หากป้อน URL ที่มีลิงก์ไปยังโปรไฟล์ของคุณ ไอคอนการยืนยันความเป็นเจ้าของจะแสดงถัดจากฟิลด์นั้น ๆ"
+ verifiedLinkDescription: "โดยการป้อน URL ที่มีลิงก์ไปยังโปรไฟล์ของคุณตรงนี้ ส่วนไอคอนการยืนยันความเป็นเจ้าของนั้นก็สามารถแสดงถัดจากฟิลด์ได้นะ"
avatarDecorationMax: "คุณสามารถเพิ่มการตกแต่งได้สูงสุด {max}"
_exportOrImport:
allNotes: "โน้ตทั้งหมด"
- favoritedNotes: "โน้ตที่ถูกใจไว้"
+ favoritedNotes: "บันทึกที่ชื่นชอบ"
clips: "คลิป"
followingList: "กำลังติดตาม"
muteList: "ปิดเสียง"
@@ -2229,37 +2152,37 @@ _exportOrImport:
userLists: "รายชื่อ"
excludeMutingUsers: "ยกเว้นผู้ใช้ที่ปิดเสียง"
excludeInactiveUsers: "ยกเว้นผู้ใช้ที่ไม่ได้ใช้งาน"
- withReplies: "รวมการตอบกลับจากผู้ใช้ที่ถูกนำเข้า ลงไทม์ไลน์"
+ withReplies: "รวมการตอบกลับจากผู้ใช้ที่นำเข้าไว้ในไทม์ไลน์"
_charts:
federation: "สหพันธ์"
apRequest: "คำขอ"
- usersIncDec: "การเพิ่มลดของจำนวนผู้ใช้"
+ usersIncDec: "ความแตกต่างของจำนวนผู้ใช้งาน"
usersTotal: "จำนวนผู้ใช้งานทั้งหมด"
activeUsers: "จำนวนผู้ใช้งานที่ยังมีความเคลื่อนไหวอยู่"
- notesIncDec: "การเพิ่มลดของจำนวนโน้ต"
- localNotesIncDec: "การเพิ่มลดของจำนวนโน้ตท้องถิ่น"
- remoteNotesIncDec: "การเพิ่มลดของจำนวนโน้ตระยะไกล"
+ notesIncDec: "ความแตกต่างของจำนวนโน้ต"
+ localNotesIncDec: "ความแตกต่างของจำนวนโน้ตท้องถิ่น"
+ remoteNotesIncDec: "ความแตกต่างของจำนวนโน้ตระยะไกล"
notesTotal: "จำนวนโน้ตทั้งหมด"
- filesIncDec: "การเพิ่มลดของจำนวนไฟล์"
+ filesIncDec: "ความแตกต่างของจำนวนไฟล์"
filesTotal: "จำนวนไฟล์ทั้งหมด"
- storageUsageIncDec: "การเพิ่มลดในการใช้พื้นที่เก็บข้อมูล"
+ storageUsageIncDec: "ความแตกต่างในการใช้พื้นที่เก็บข้อมูล"
storageUsageTotal: "การใช้พื้นที่เก็บข้อมูลทั้งหมด"
_instanceCharts:
requests: "คำขอ"
- users: "การเพิ่มลดของจำนวนผู้ใช้งาน"
+ users: "ความแตกต่างของจำนวนผู้ใช้งาน"
usersTotal: "จำนวนผู้ใช้งานสะสม"
- notes: "การเพิ่มลดของจำนวนโน้ต"
+ notes: "ความแตกต่างของจำนวนโน้ต"
notesTotal: "จำนวนโน้ตสะสม"
- ff: "การเพิ่มลดของการติดตาม/ผู้ติดตาม"
- ffTotal: "จำนวนสะสมของการติดตาม/ผู้ติดตาม"
- cacheSize: "การเพิ่มลดขนาดของแคช"
- cacheSizeTotal: "ขนาดแคชสะสม"
- files: "การเพิ่มลดของจำนวนไฟล์"
+ ff: "ความแตกต่างของจำนวนผู้ใช้ที่ติดตาม / ผู้ติดตาม"
+ ffTotal: "จำนวนผู้ใช้งานที่ติดตามสะสม / ผู้ติดตาม"
+ cacheSize: "ความแตกต่างในขนาดของแคช"
+ cacheSizeTotal: "ขนาดแคชรวมที่สะสม"
+ files: "ความแตกต่างของจำนวนไฟล์"
filesTotal: "จำนวนไฟล์สะสม"
_timelines:
- home: "หน้าหลัก"
- local: "ท้องถิ่น"
- social: "โซเชียล"
+ home: "หน้าแรก"
+ local: "ในพื้นที่"
+ social: "โซเชี่ยล"
global: "ทั่วโลก"
_play:
new: "สร้าง Play"
@@ -2275,8 +2198,7 @@ _play:
featured: "เป็นที่นิยม"
title: "หัวข้อ"
script: "สคริปต์"
- summary: "คำอธิบาย"
- visibilityDescription: "หากตั้งค่าเป็นส่วนตัว มันจะไม่ปรากฏในโปรไฟล์อีกต่อไป แต่ผู้ที่ทราบ URL ของมันจะยังสามารถเข้าถึงได้"
+ summary: "รายละเอียด"
_pages:
newPage: "สร้างหน้าเพจใหม่"
editPage: "แก้ไขหน้าเพจ"
@@ -2305,7 +2227,7 @@ _pages:
summary: "สรุปเพจ"
alignCenter: "เซ็นเตอร์"
hideTitleWhenPinned: "ซ่อนชื่อหน้าเพจเมื่อปักหมุดไว้ที่โปรไฟล์"
- font: "แบบอักษร"
+ font: "ตัวอักษร"
fontSerif: "Serif"
fontSansSerif: "Sans Serif"
eyeCatchingImageSet: "ตั้งค่าภาพขนาดย่อ"
@@ -2321,8 +2243,6 @@ _pages:
section: "ประเภท"
image: "รูปภาพ"
button: "ปุ่ม"
- dynamic: "บล็อกแบบไดนามิก"
- dynamicDescription: "บล็อกนี้ล้าสมัยแล้ว โปรดใช้ {play} แทน นับจากนี้เป็นต้นไป"
note: "โน้ตที่ฝังตัว"
_note:
id: "โน้ต ID"
@@ -2333,29 +2253,27 @@ _relayStatus:
accepted: "ได้รับการอนุมัติ"
rejected: "ถูกปฏิเสธ"
_notification:
- fileUploaded: "ไฟล์ถูกอัปโหลดแล้ว"
+ fileUploaded: "ไฟล์ถูกอัพโหลดแล้วน่ะ"
youGotMention: "{name} กล่าวถึงคุณ"
youGotReply: "{name} ตอบกลับถึงคุณ"
- youGotQuote: "{name} อ้างอิงคุณ"
+ youGotQuote: "{name} อ้างถึงคุณ"
youRenoted: "รีโน้ตจาก {name}"
youWereFollowed: "ได้ติดตามคุณ"
- youReceivedFollowRequest: "ได้รับคำขอติดตาม"
- yourFollowRequestAccepted: "คำขอติดตามได้รับการอนุมัติแล้ว"
- pollEnded: "ผลโพลออกมาแล้ว"
+ youReceivedFollowRequest: "คุณมีคำขอติดตามใหม่น่ะ"
+ yourFollowRequestAccepted: "คำขอติดตามของคุณได้รับการยอมรับแล้วน่ะ"
+ pollEnded: "โพลสำรวจความคิดเห็นผลลัพธ์มีพร้อมใช้งาน"
newNote: "โพสต์ใหม่"
unreadAntennaNote: "เสาอากาศ {name}"
roleAssigned: "ได้รับบทบาท"
- emptyPushNotificationMessage: "อัปเดตการแจ้งเตือนแบบพุชแล้ว"
+ emptyPushNotificationMessage: "การแจ้งเตือนแบบพุชได้รับการอัพเดทแล้ว"
achievementEarned: "รับความสำเร็จ"
testNotification: "ทดสอบการแจ้งเตือน"
checkNotificationBehavior: "กดเพื่อดูลักษณะการแจ้งเตือน"
sendTestNotification: "ส่งทดสอบการแจ้งเตือน"
notificationWillBeDisplayedLikeThis: "การแจ้งเตือนมีลักษณะแบบนี้"
reactedBySomeUsers: "ถูกรีแอคชั่นโดยผู้ใช้ {n} ราย"
- likedBySomeUsers: "{n} คนถูกใจ"
- renotedBySomeUsers: "รีโน้ตจากผู้ใช้ {n} ราย"
+ renotedBySomeUsers: "Renote จากผู้ใช้จำนวน {n} ราย"
followedBySomeUsers: "มีผู้ติดตาม {n} ราย"
- flushNotification: "ล้างประวัติการแจ้งเตือน"
_types:
all: "ทั้งหมด"
note: "โน้ตใหม่"
@@ -2363,14 +2281,13 @@ _notification:
mention: "กล่าวถึง"
reply: "ตอบกลับ"
renote: "รีโน้ต"
- quote: "อ้างอิง"
+ quote: "อ้างคำพูด"
reaction: "รีแอคชั่น"
- pollEnded: "โพลสิ้นสุดแล้ว"
- receiveFollowRequest: "ได้รับคำร้องขอติดตาม"
- followRequestAccepted: "อนุมัติให้ติดตามแล้ว"
+ pollEnded: "โพลนี้สิ้นสุดลงแล้ว"
+ receiveFollowRequest: "ได้รับคำขอติดตาม\n"
+ followRequestAccepted: "ยอมรับคำขอติดตาม"
roleAssigned: "ให้บทบาท"
achievementEarned: "ปลดล็อกความสำเร็จแล้ว"
- login: "เข้าสู่ระบบ"
app: "การแจ้งเตือนจากแอปที่มีลิงก์"
_actions:
followBack: "ติดตามกลับด้วย"
@@ -2380,7 +2297,6 @@ _deck:
alwaysShowMainColumn: "แสดงคอลัมน์หลักเสมอ"
columnAlign: "จัดแนวคอลัมน์"
addColumn: "เพิ่มคอลัมน์"
- newNoteNotificationSettings: "ตั้งค่าการแจ้งเตือนเมื่อมีโน้ตใหม่"
configureColumn: "ตั้งค่าคอลัมน์"
swapLeft: "ขยับไปทางซ้าย"
swapRight: "ขยับไปทางขวา"
@@ -2405,8 +2321,8 @@ _deck:
antenna: "เสาอากาศ"
list: "รายการ"
channel: "ช่อง"
- mentions: "กล่าวถึงคุณ"
- direct: "ไดเร็กต์"
+ mentions: "พูดถึง"
+ direct: "ไดเร็ค"
roleTimeline: "บทบาทไทม์ไลน์"
_dialog:
charactersExceeded: "คุณกำลังมีตัวอักขระเกินขีดจำกัดสูงสุดแล้วนะ! ปัจจุบันอยู่ที่ {current} จาก {max}"
@@ -2419,10 +2335,9 @@ _drivecleaner:
orderByCreatedAtAsc: "วันที่จากน้อยไปหามาก"
_webhookSettings:
createWebhook: "สร้าง Webhook"
- modifyWebhook: "แก้ไข Webhook"
name: "ชื่อ"
secret: "ความลับ"
- trigger: "ทริกเกอร์"
+ events: "อีเว้นท์ Webhook"
active: "เปิดใช้งาน"
_events:
follow: "เมื่อกำลังติดตามผู้ใช้"
@@ -2432,34 +2347,14 @@ _webhookSettings:
renote: "รีโน้ตแล้วเมื่อ"
reaction: "เมื่อได้รับรีแอคชั่น"
mention: "เมื่อกำลังถูกกล่าวถึง"
- _systemEvents:
- abuseReport: "เมื่อมีการรายงานจากผู้ใช้"
- abuseReportResolved: "เมื่อมีการจัดการกับการรายงานจากผู้ใช้"
- userCreated: "เมื่อผู้ใช้ถูกสร้างขึ้น"
- deleteConfirm: "ต้องการลบ Webhook ใช่ไหม?"
-_abuseReport:
- _notificationRecipient:
- createRecipient: "เพิ่มปลายทางการแจ้งเตือนการรายงาน"
- modifyRecipient: "แก้ไขปลายทางการแจ้งเตือนการรายงาน"
- recipientType: "ประเภทของปลายทางการแจ้งเตือน\n"
- _recipientType:
- mail: "อีเมล"
- webhook: "Webhook"
- _captions:
- mail: "ส่งการแจ้งเตือนไปยังที่อยู่อีเมลของผู้ควบคุม (เฉพาะเมื่อได้รับการรายงาน)"
- webhook: "ส่งการแจ้งเตือนไปยัง SystemWebhook ที่กำหนด (จะส่งเมื่อได้รับการรายงานและเมื่อการรายงานได้รับการแก้ไข)"
- keywords: "คีย์เวิร์ด"
- notifiedUser: "ผู้ใช้ที่ได้รับการแจ้งเตือน"
- notifiedWebhook: "Webhook ที่ใช้"
- deleteConfirm: "ต้องการลบปลายทางการแจ้งเตือนใช่ไหม?"
_moderationLogTypes:
createRole: "สร้างบทบาทแล้ว"
deleteRole: "ลบบทบาทแล้ว"
updateRole: "อัปเดตบทบาทแล้ว"
assignRole: "ได้รับมอบหมายบทบาท"
unassignRole: "ถอดออกจากบทบาทแล้ว"
- suspend: "ระงับ"
- unsuspend: "เลิกระงับ"
+ suspend: "ถูกระงับ"
+ unsuspend: "เลิกถูกระงับ"
addCustomEmoji: "เพิ่มเอโมจิที่กำหนดเองแล้ว"
updateCustomEmoji: "อัปเดตเอโมจิที่กำหนดเองแล้ว"
deleteCustomEmoji: "ลบเอโมจิที่กำหนดเองออกแล้ว"
@@ -2474,13 +2369,12 @@ _moderationLogTypes:
deleteGlobalAnnouncement: "ลบประกาศทั่วโลกออกแล้ว"
deleteUserAnnouncement: "ลบประกาศผู้ใช้ออกแล้ว"
resetPassword: "รีเซ็ตรหัสผ่าน"
- suspendRemoteInstance: "ระงับเซิร์ฟเวอร์ระยะไกล"
- unsuspendRemoteInstance: "เลิกระงับเซิร์ฟเวอร์ระยะไกล"
- updateRemoteInstanceNote: "อัปเดตโน้ตการกลั่นกรองสำหรับเซิร์ฟเวอร์ระยะไกลแล้ว"
+ suspendRemoteInstance: "อินสแตนซ์ระยะไกลถูกระงับ"
+ unsuspendRemoteInstance: "อินสแตนซ์ระยะไกลเลิกการระงับ"
markSensitiveDriveFile: "ทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
unmarkSensitiveDriveFile: "ยกเลิกทำเครื่องหมายไฟล์ว่ามีเนื้อหาละเอียดอ่อน"
resolveAbuseReport: "รายงานได้รับการแก้ไขแล้ว"
- createInvitation: "สร้างรหัสเชิญ"
+ createInvitation: "สร้างคำเชิญ"
createAd: "สร้างโฆษณาแล้ว"
deleteAd: "ลบโฆษณาออกแล้ว"
updateAd: "อัปเดตโฆษณาแล้ว"
@@ -2489,12 +2383,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "ลบการตกแต่งไอคอนแล้ว"
unsetUserAvatar: "ลบไอคอนผู้ใช้"
unsetUserBanner: "ลบแบนเนอร์ผู้ใช้"
- createSystemWebhook: "สร้าง SystemWebhook"
- updateSystemWebhook: "อัปเดต SystemWebhook"
- deleteSystemWebhook: "ลบ SystemWebhook"
- createAbuseReportNotificationRecipient: "สร้างปลายทางการแจ้งเตือนการรายงาน"
- updateAbuseReportNotificationRecipient: "อัปเดตปลายทางการแจ้งเตือนการรายงาน"
- deleteAbuseReportNotificationRecipient: "ลบปลายทางการแจ้งเตือนการรายงาน"
_fileViewer:
title: "รายละเอียดไฟล์"
type: "ประเภทไฟล์"
@@ -2507,10 +2395,10 @@ _externalResourceInstaller:
title: "ติดตั้งจากไซต์ภายนอก"
checkVendorBeforeInstall: "โปรดตรวจสอบให้แน่ใจว่าแหล่งแจกหน่ายมีความน่าเชื่อถือก่อนทำการติดตั้ง"
_plugin:
- title: "ต้องการติดตั้งปลั๊กอินนี้ใช่ไหม?"
+ title: "ต้องการติดตั้งปลั๊กอินนี้หรือไม่?"
metaTitle: "ข้อมูลส่วนเสริม"
_theme:
- title: "ต้องการติดตั้งธีมนี้ใช่ไหม?"
+ title: "ต้องการติดตั้งธีมนี้หรือไม่?"
metaTitle: "ข้อมูลธีม"
_meta:
base: "โทนสีพื้นฐาน"
@@ -2546,7 +2434,7 @@ _externalResourceInstaller:
description: "เกิดปัญหาระหว่างการติดตั้งธีม กรุณาลองอีกครั้ง. รายละเอียดข้อผิดพลาดสามารถดูได้ในคอนโซล Javascript"
_dataSaver:
_media:
- title: "โหลดสื่อ"
+ title: "โหลดมีเดีย"
description: "กันไม่ให้ภาพและวิดีโอโหลดโดยอัตโนมัติ แตะรูปภาพ/วิดีโอที่ซ่อนอยู่เพื่อโหลด"
_avatar:
title: "รูปไอคอน"
@@ -2603,31 +2491,7 @@ _reversi:
opponentHasSettingsChanged: "อีกฝ่ายเปลี่ยนการตั้งค่า"
allowIrregularRules: "อนุญาตกฎที่ไม่ปรกติ (โหมดฟรีทุกอย่าง)"
disallowIrregularRules: "ไม่อนุญาตกฎที่ไม่ปรกติ"
- showBoardLabels: "แสดงหมายเลขแถว/คอลัมน์บนกระดาน"
- useAvatarAsStone: "ใช้รูปอวตารเป็นหมาก"
_offlineScreen:
title: "ออฟไลน์ - ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้"
header: "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้"
-_urlPreviewSetting:
- title: "การตั้งค่าการแสดงตัวอย่าง URL"
- enable: "เปิดใช้งานการแสดงตัวอย่าง URL"
- timeout: "เวลาจำกัดในการโหลดตัวอย่าง URL (ms)"
- timeoutDescription: "หากเวลาที่ใช้ในการโหลดเกินค่านี้ จะไม่มีการสร้างการแสดงตัวอย่าง"
- maximumContentLength: "ค่าสูงสุดของ Content-Length (byte)"
- maximumContentLengthDescription: "หาก Content-Length เกินค่านี้ จะไม่มีการสร้างการแสดงตัวอย่าง"
- requireContentLength: "สร้างการแสดงตัวอย่างเฉพาะในกรณีที่รับ Content-Length ไหว"
- requireContentLengthDescription: "หากเซิร์ฟเวอร์อื่นไม่ส่งคืน Content-Length จะไม่มีการสร้างการแสดงตัวอย่าง"
- userAgent: "User-Agent"
- userAgentDescription: "ตั้งค่า User-Agent ที่ใช้ในการรับการแสดงตัวอย่าง หากเว้นว่างไว้ ระบบจะใช้ User-Agent เริ่มต้น"
- summaryProxy: "endpoint ของพร็อกซีที่สร้างการแสดงตัวอย่าง"
- summaryProxyDescription: "สร้างการแสดงตัวอย่างด้วย summary Proxy แทนที่จะใช้เนื้อหา Misskey"
- summaryProxyDescription2: "พารามิเตอร์ต่อไปนี้จะถูกใช้เป็นสตริงการสืบค้นเพื่อเชื่อมต่อกับพร็อกซี หากฝั่งพร็อกซีไม่รองรับการตั้งค่าเหล่านี้จะถูกละเว้น"
-_mediaControls:
- pip: "รูปภาพในรูปภาม"
- playbackRate: "ความเร็วในการเล่น"
- loop: "เล่นวนซ้ำ"
-_contextMenu:
- title: "เมนูเนื้อหา"
- app: "แอปพลิเคชัน"
- appWithShift: "แอปฟลิเคชันด้วยปุ่มยกแคร่ (Shift)"
- native: "UI ของเบราว์เซอร์"
+
diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml
index fe2f158ff6..e93a6e43e1 100644
--- a/locales/tr-TR.yml
+++ b/locales/tr-TR.yml
@@ -378,10 +378,6 @@ addMemo: "Kısa not ekle"
icon: "Avatar"
replies: "yanıt"
renotes: "vazgeçme"
-_delivery:
- stop: "Askıya alınmış"
- _type:
- none: "Paylaşım"
_accountDelete:
started: "Silme işlemi başlatıldı"
_email:
@@ -446,7 +442,6 @@ _notification:
reaction: "Tepkiler"
receiveFollowRequest: "Takip isteği alındı"
followRequestAccepted: "Takip isteği kabul edildi"
- login: "Giriş Yap "
_actions:
reply: "yanıt"
renote: "vazgeçme"
@@ -460,3 +455,4 @@ _deck:
_moderationLogTypes:
suspend: "askıya al"
resetPassword: "Şifre sıfırlama"
+
diff --git a/locales/ug-CN.yml b/locales/ug-CN.yml
index fef26040a5..e06cee11a2 100644
--- a/locales/ug-CN.yml
+++ b/locales/ug-CN.yml
@@ -17,6 +17,4 @@ _2fa:
renewTOTPCancel: "ئۇنى توختىتىڭ"
_widgets:
profile: "profile"
-_notification:
- _types:
- login: "كىرىش"
+
diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml
index f2262cd71f..df36f43c06 100644
--- a/locales/uk-UA.yml
+++ b/locales/uk-UA.yml
@@ -452,6 +452,7 @@ language: "Мова"
uiLanguage: "Мова інтерфейсу"
aboutX: "Про {x}"
native: "місцевий"
+disableDrawer: "Не використовувати висувні меню"
noHistory: "Історія порожня"
signinHistory: "Історія входів"
enableAdvancedMfm: "Увімкнути розширений MFM"
@@ -630,7 +631,10 @@ abuseReported: "Дякуємо, вашу скаргу було відправл
reporter: "Репортер"
reporteeOrigin: "Про кого повідомлено"
reporterOrigin: "Хто повідомив"
+forwardReport: "Переслати звіт на віддалений інстанс"
+forwardReportIsAnonymous: "Замість вашого облікового запису анонімний системний обліковий запис буде відображатися як доповідач на віддаленому інстансі"
send: "Відправити"
+abuseMarkAsResolved: "Позначити скаргу як вирішену"
openInNewTab: "Відкрити в новій вкладці"
openInSideView: "Відкрити збоку"
defaultNavigationBehaviour: "Поведінка навігації за замовчуванням"
@@ -910,10 +914,6 @@ renotes: "Поширити"
sourceCode: "Вихідний код"
flip: "Перевернути"
lastNDays: "Останні {n} днів"
-_delivery:
- stop: "Призупинено"
- _type:
- none: "Публікація"
_achievements:
earnedAt: "Відкрито"
_types:
@@ -1302,6 +1302,7 @@ _theme:
buttonBg: "Фон кнопки"
buttonHoverBg: "Фон кнопки (при наведенні)"
inputBorder: "Край поля вводу"
+ listItemHoverBg: "Фон елементу в списку (при наведенні)"
driveFolderBg: "Фон папки на диску"
wallpaperOverlay: "Накладання шпалер"
badge: "Значок"
@@ -1313,6 +1314,8 @@ _sfx:
note: "Нотатки"
noteMy: "Мої нотатки"
notification: "Сповіщення"
+ antenna: "Прийом антени"
+ channel: "Повідомлення каналу"
_ago:
future: "Майбутнє"
justNow: "Щойно"
@@ -1583,7 +1586,6 @@ _notification:
reaction: "Реакції"
receiveFollowRequest: "Запити на підписку"
followRequestAccepted: "Прийняті підписки"
- login: "Увійти"
app: "Сповіщення від додатків"
_actions:
reply: "Відповісти"
@@ -1616,12 +1618,9 @@ _deck:
_webhookSettings:
name: "Ім'я"
active: "Увімкнено"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "E-mail"
_moderationLogTypes:
suspend: "Призупинити"
resetPassword: "Скинути пароль"
_reversi:
total: "Всього"
+
diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml
index 37a550008a..a79a76066a 100644
--- a/locales/uz-UZ.yml
+++ b/locales/uz-UZ.yml
@@ -471,6 +471,7 @@ uiLanguage: "Interfeys tili"
aboutX: "{x} haqida"
emojiStyle: "Emoji ko'rinishi"
native: "Mahalliy"
+disableDrawer: "Slayd menyusidan foydalanmang"
showNoteActionsOnlyHover: "Eslatma amallarini faqat sichqonchani olib borganda ko‘rsatish"
noHistory: "Tarix yo'q"
signinHistory: "kirish tarixi"
@@ -629,7 +630,10 @@ abuseReported: "Shikoyatingiz yetkazildi. Ma'lumot uchun rahmat."
reporter: "Shikoyat qiluvchi"
reporteeOrigin: "Xabarning kelib chiqishi"
reporterOrigin: "Xabarchining joylashuvi"
+forwardReport: "Xabarni masofadagi serverga yuborish"
+forwardReportIsAnonymous: "Sizning yuborayotgan xabaringiz o'z akkountingiz emas balki anonim tarzda qoladi"
send: "Yuborish"
+abuseMarkAsResolved: "Yuborilgan xabarni hal qilingan deb belgilash"
openInNewTab: "Yangi tab da ochish"
openInSideView: "Yon panelda ochish"
defaultNavigationBehaviour: "Standart navigatsiya harakati"
@@ -839,13 +843,9 @@ rolesAssignedToMe: "Mening rollarim"
resetPasswordConfirm: "Qayta parol o'rnatmoqchimisiz?"
sensitiveWords: "Ta'sirchan so'zlar"
icon: "Avatar"
-replies: "Javob berish"
+replies: "Javoblar"
renotes: "Qayta qayd etish"
flip: "Teskari"
-_delivery:
- stop: "To'xtatilgan"
- _type:
- none: "Yuborilmoqda"
_achievements:
_types:
_viewInstanceChart:
@@ -1054,7 +1054,6 @@ _notification:
quote: "Iqtibos keltirish"
reaction: "Reaktsiyalar"
receiveFollowRequest: "Qabul qilingan kuzatuv so'rovlari"
- login: "Kirish"
_actions:
reply: "Javob berish"
renote: "Qayta qayd qilish"
@@ -1086,12 +1085,9 @@ _webhookSettings:
_events:
renote: "Qayta qayd qilinganda"
mention: "Eslanganda"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Email"
_moderationLogTypes:
suspend: "To'xtatish"
resetPassword: "Parolni tiklash"
_reversi:
total: "Jami"
+
diff --git a/locales/verify.js b/locales/verify.js
deleted file mode 100644
index 63b47c6525..0000000000
--- a/locales/verify.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import locales from './index.js';
-
-const showUntranslated = process.argv[2] == '-v';
-
-let valid = true;
-
-function writeError(type, lang, tree, data) {
- process.stderr.write(JSON.stringify({ type, lang, tree, data }));
- process.stderr.write('\n');
- valid = false;
-}
-
-function verify(expected, actual, lang, trace) {
- for (let key in expected) {
- if (!Object.prototype.hasOwnProperty.call(actual, key)) {
- continue;
- }
- if (typeof expected[key] === 'object') {
- if (typeof actual[key] !== 'object') {
- writeError('mismatched_type', lang, trace ? `${trace}.${key}` : key, { expected: 'object', actual: typeof actual[key] });
- continue;
- }
- verify(expected[key], actual[key], lang, trace ? `${trace}.${key}` : key);
- } else if (typeof expected[key] === 'string') {
- switch (typeof actual[key]) {
- case 'object':
- writeError('mismatched_type', lang, trace ? `${trace}.${key}` : key, { expected: 'string', actual: 'object' });
- break;
- case 'undefined':
- continue;
- case 'string':
- const expectedParameters = new Set(expected[key].match(/\{[^}]+\}/g)?.map((s) => s.slice(1, -1)));
- const actualParameters = new Set(actual[key].match(/\{[^}]+\}/g)?.map((s) => s.slice(1, -1)));
- for (let parameter of expectedParameters) {
- if (!actualParameters.has(parameter)) {
- writeError('missing_parameter', lang, trace ? `${trace}.${key}` : key, { parameter });
- }
- }
-
- if (showUntranslated && actual[key] == expected[key]) {
- writeError('untranslated', lang, trace ? `${trace}.${key}` : key, { original: expected[key] });
- }
- }
- }
- }
-}
-
-const { ['ja-JP']: original, ...verifiees } = locales;
-
-for (let lang in verifiees) {
- if (!Object.prototype.hasOwnProperty.call(locales, lang)) {
- continue;
- }
- verify(original, verifiees[lang], lang);
-}
-
-if (!valid) {
- process.exit(1);
-}
diff --git a/locales/version.d.ts b/locales/version.d.ts
deleted file mode 100644
index 54ceec7443..0000000000
--- a/locales/version.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export const localesVersion: string;
diff --git a/locales/version.js b/locales/version.js
deleted file mode 100644
index e84414b74d..0000000000
--- a/locales/version.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { createHash } from 'crypto';
-import locales from './index.js';
-
-// MD5 is acceptable because we don't need cryptographic security.
-const hash = createHash('md5');
-
-// Derive the version hash from locale content exclusively.
-// This avoids the problem of "stuck" translations after modifying locale files.
-const localesText = JSON.stringify(locales);
-hash.update(localesText, 'utf8');
-
-// We can't use regular base64 since this becomes part of a filename.
-// Base64URL avoids special characters that would cause an issue.
-export const localesVersion = hash.digest().toString('base64url');
diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml
index 235497d844..f92578d6c0 100644
--- a/locales/vi-VN.yml
+++ b/locales/vi-VN.yml
@@ -121,11 +121,9 @@ sensitive: "Nhạy cảm"
add: "Thêm"
reaction: "Biểu cảm"
reactions: "Biểu cảm"
-emojiPicker: "Bộ chọn biểu tượng cảm xúc"
reactionSettingDescription2: "Kéo để sắp xếp, nhấn để xóa, nhấn \"+\" để thêm."
rememberNoteVisibility: "Lưu kiểu tút mặc định"
attachCancel: "Gỡ tập tin đính kèm"
-deleteFile: "Xoá tệp tin"
markAsSensitive: "Đánh dấu là nhạy cảm"
unmarkAsSensitive: "Bỏ đánh dấu nhạy cảm"
enterFileName: "Nhập tên tập tin"
@@ -259,7 +257,6 @@ removed: "Đã xóa"
removeAreYouSure: "Bạn có chắc muốn gỡ \"{x}\"?"
deleteAreYouSure: "Bạn có chắc muốn xóa \"{x}\"?"
resetAreYouSure: "Bạn có chắc muốn đặt lại?"
-areYouSure: "Bạn chắc chứ?"
saved: "Đã lưu"
messaging: "Trò chuyện"
upload: "Tải lên"
@@ -310,7 +307,6 @@ folderName: "Tên thư mục"
createFolder: "Tạo thư mục"
renameFolder: "Đổi tên thư mục"
deleteFolder: "Xóa thư mục"
-folder: "Thư mục"
addFile: "Thêm tập tin"
emptyDrive: "Ổ đĩa của bạn trống trơn"
emptyFolder: "Thư mục trống"
@@ -372,11 +368,8 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Bật hCaptcha"
hcaptchaSiteKey: "Khóa của trang"
hcaptchaSecretKey: "Khóa bí mật"
-mcaptcha: "mCaptcha"
-enableMcaptcha: "Bật mCaptcha"
mcaptchaSiteKey: "Khóa của trang"
mcaptchaSecretKey: "Khóa bí mật"
-mcaptchaInstanceUrl: "URL mCaptcha máy chủ"
recaptcha: "reCAPTCHA"
enableRecaptcha: "Bật reCAPTCHA"
recaptchaSiteKey: "Khóa của trang"
@@ -392,7 +385,6 @@ name: "Tên"
antennaSource: "Nguồn trạm phát sóng"
antennaKeywords: "Từ khóa để nghe"
antennaExcludeKeywords: "Từ khóa để lọc ra"
-antennaExcludeBots: "Loại trừ các tài khoản bot"
antennaKeywordsDescription: "Phân cách bằng dấu cách cho điều kiện AND hoặc bằng xuống dòng cho điều kiện OR."
notifyAntenna: "Thông báo có tút mới"
withFileAntenna: "Chỉ những tút có media"
@@ -427,7 +419,6 @@ moderator: "Kiểm duyệt viên"
moderation: "Kiểm duyệt"
moderationNote: "Ghi chú kiểm duyệt"
addModerationNote: "Thêm ghi chú kiểm duyệt"
-moderationLogs: "Nhật kí quản trị"
nUsersMentioned: "Dùng bởi {n} người"
securityKeyAndPasskey: "Mã bảo mật・Passkey"
securityKey: "Khóa bảo mật"
@@ -460,7 +451,6 @@ retype: "Nhập lại"
noteOf: "Tút của {user}"
quoteAttached: "Trích dẫn"
quoteQuestion: "Trích dẫn lại?"
-attachAsFileQuestion: "Văn bản ở trong bộ nhớ tạm rất dài. Bạn có muốn đăng nó dưới dạng một tệp văn bản không?"
noMessagesYet: "Chưa có tin nhắn"
newMessageExists: "Bạn có tin nhắn mới"
onlyOneFileCanBeAttached: "Bạn chỉ có thể đính kèm một tập tin"
@@ -486,6 +476,7 @@ uiLanguage: "Ngôn ngữ giao diện"
aboutX: "Giới thiệu {x}"
emojiStyle: "Kiểu cách Emoji"
native: "Bản xứ"
+disableDrawer: "Không dùng menu thanh bên"
showNoteActionsOnlyHover: "Chỉ hiển thị các hành động ghi chú khi di chuột"
noHistory: "Không có dữ liệu"
signinHistory: "Lịch sử đăng nhập"
@@ -546,7 +537,6 @@ showInPage: "Hiện trong trang"
popout: "Pop-out"
volume: "Âm lượng"
masterVolume: "Âm thanh chung"
-notUseSound: "Tắt tiếng"
details: "Chi tiết"
chooseEmoji: "Chọn emoji"
unableToProcess: "Không thể hoàn tất hành động"
@@ -567,10 +557,6 @@ output: "Nguồn ra"
script: "Kịch bản"
disablePagesScript: "Tắt AiScript trên Trang"
updateRemoteUser: "Cập nhật thông tin người dùng ở máy chủ khác"
-unsetUserAvatar: "Gỡ ảnh đại diện"
-unsetUserAvatarConfirm: "Bạn có chắc muốn gỡ ảnh đại diện?"
-unsetUserBanner: "Gỡ ảnh bìa"
-unsetUserBannerConfirm: "Bạn có chắc muốn gỡ ảnh bìa?"
deleteAllFiles: "Xóa toàn bộ tập tin"
deleteAllFilesConfirm: "Bạn có chắc xóa toàn bộ tập tin?"
removeAllFollowing: "Ngưng theo dõi tất cả mọi người"
@@ -675,7 +661,10 @@ abuseReported: "Báo cáo đã được gửi. Cảm ơn bạn nhiều."
reporter: "Người báo cáo"
reporteeOrigin: "Bị báo cáo"
reporterOrigin: "Máy chủ người báo cáo"
+forwardReport: "Chuyển tiếp báo cáo cho máy chủ từ xa"
+forwardReportIsAnonymous: "Thay vì tài khoản của bạn, một tài khoản hệ thống ẩn danh sẽ được hiển thị dưới dạng người báo cáo ở máy chủ từ xa."
send: "Gửi"
+abuseMarkAsResolved: "Đánh dấu đã xử lý"
openInNewTab: "Mở trong tab mới"
openInSideView: "Mở trong thanh bên"
defaultNavigationBehaviour: "Thao tác điều hướng mặc định"
@@ -870,8 +859,6 @@ makeReactionsPublicDescription: "Điều này sẽ hiển thị công khai danh
classic: "Cổ điển"
muteThread: "Không quan tâm nữa"
unmuteThread: "Quan tâm tút này"
-followingVisibility: "Hiển thị lượt theo dõi"
-followersVisibility: "Hiển thị người theo dõi"
continueThread: "Tiếp tục xem chuỗi tút"
deleteAccountConfirm: "Điều này sẽ khiến tài khoản bị xóa vĩnh viễn. Vẫn tiếp tục?"
incorrectPassword: "Sai mật khẩu."
@@ -981,7 +968,6 @@ assign: "Phân công"
unassign: "Hủy phân công"
color: "Màu sắc"
manageCustomEmojis: "Quản lý CustomEmoji"
-manageAvatarDecorations: "Quản lý trang trí ảnh đại diện"
youCannotCreateAnymore: "Bạn đã tới giới hạn tạo."
cannotPerformTemporary: "Tạm thời không sử dụng được"
cannotPerformTemporaryDescription: "Tạm thời không sử dụng được vì lần số điều kiện quá giới hạn. Thử lại sau mọt lát nữa."
@@ -1005,24 +991,18 @@ copyErrorInfo: "Sao chép thông tin lỗi"
joinThisServer: "Đăng ký trên chủ máy này"
exploreOtherServers: "Tìm chủ máy khác"
letsLookAtTimeline: "Thử xem Timeline"
-disableFederationOk: "Vô hiệu hoá"
emailNotSupported: "Máy chủ này không hỗ trợ gửi email"
postToTheChannel: "Đăng lên kênh"
cannotBeChangedLater: "Không thể thay đổi sau này."
-likeOnly: "Chỉ lượt thích"
rolesAssignedToMe: "Vai trò được giao cho tôi"
resetPasswordConfirm: "Bạn thực sự muốn đặt lại mật khẩu?"
sensitiveWords: "Các từ nhạy cảm"
-prohibitedWords: "Các từ bị cấm"
license: "Giấy phép"
unfavoriteConfirm: "Bạn thực sự muốn xoá khỏi mục yêu thích?"
-retryAllQueuesConfirmTitle: "Bạn có muốn thử lại?"
retryAllQueuesConfirmText: "Điều này sẽ tạm thời làm tăng mức độ tải của máy chủ."
enableChartsForRemoteUser: "Tạo biểu đồ người dùng từ xa"
video: "Video"
videos: "Các video"
-audio: "Âm thanh"
-audioFiles: "Âm thanh"
dataSaver: "Tiết kiệm dung lượng"
accountMigration: "Chuyển tài khoản"
accountMoved: "Người dùng này đã chuyển sang một tài khoản mới:"
@@ -1039,88 +1019,35 @@ vertical: "Dọc"
horizontal: "Thanh bên"
position: "Vị trí"
serverRules: "Luật của máy chủ"
-pleaseConfirmBelowBeforeSignup: "Để đăng ký trên máy chủ này, bạn phải xem xét và đồng ý với những điều sau."
-pleaseAgreeAllToContinue: "Bạn phải đồng ý tất cả điều trên để tiếp tục."
-continue: "Tiếp tục"
-archive: "Lưu trữ"
-thisChannelArchived: "Kênh này đã được lưu trữ."
-initialAccountSetting: "Thiết lập hồ sơ"
youFollowing: "Đang theo dõi"
-preventAiLearning: "Từ chối sử dụng công nghệ Máy Học (AI Sáng Tạo)"
-options: "Tùy chọn"
-specifyUser: "Người dùng chỉ định"
-failedToPreviewUrl: "Không thể xem trước"
-update: "Cập nhật"
later: "Để sau"
goToMisskey: "Tới Misskey"
installed: "Đã tải xuống"
branding: "Thương hiệu"
turnOffToImprovePerformance: "Tắt mục này có thể cải thiện hiệu năng."
-createInviteCode: "Tạo lời mời"
-createWithOptions: "Tạo cùng tùy chọn"
-createCount: "Số lượng mời"
-inviteCodeCreated: "Lời mời đã được tạo"
-inviteLimitExceeded: "Bạn đã vượt quá số lượng mời mà bạn có thể tạo."
-createLimitRemaining: "Giới hạn lượt mời: Còn lại {limit}"
-inviteLimitResetCycle: "Giới hạn này sẽ được đặt lại về {limit} lúc {time}."
expirationDate: "Ngày hết hạn"
noExpirationDate: "Vô thời hạn"
-inviteCodeUsedAt: "Mã mời đã được sử dụng lúc"
-registeredUserUsingInviteCode: "Lời mời đã được sử dụng bởi"
waitingForMailAuth: "Đang chờ xác nhận email"
-inviteCodeCreator: "Lời mời đã được tạo bởi"
-usedAt: "Sử dụng vào lúc"
unused: "Chưa được sử dụng"
used: "Đã được sử dụng"
expired: "Đã hết hạn"
doYouAgree: "Đồng ý?"
-beSureToReadThisAsItIsImportant: "Hãy đọc kỹ vì nó rất quan trọng."
-iHaveReadXCarefullyAndAgree: "Tôi đã đọc và đồng ý với \"{x}\"."
+iHaveReadXCarefullyAndAgree: "Tôi đã đọc và đồng ý với \"x\"."
dialog: "Hộp thoại"
icon: "Ảnh đại diện"
forYou: "Dành cho bạn"
currentAnnouncements: "Thông báo hiện tại"
pastAnnouncements: "Thông báo trước đó"
youHaveUnreadAnnouncements: "Có thông báo chưa đọc."
-useSecurityKey: "Làm theo hướng dẫn trên trình duyệt hoặc thiết bị của bạn để sử dụng khóa bảo mật hoặc mật mã."
replies: "Trả lời"
renotes: "Đăng lại"
loadReplies: "Hiển thị các trả lời"
-loadConversation: "Xem cuộc trò chuyện"
pinnedList: "Các mục đã được ghim"
keepScreenOn: "Giữ màn hình luôn bật"
verifiedLink: "Chúng tôi đã xác nhận bạn là chủ sở hữu của đường dẫn này"
-authentication: "Xác thực"
-authenticationRequiredToContinue: "Vui lòng xác thực để tiếp tục"
-dateAndTime: "Ngày và giờ"
-edited: "Đã chỉnh sửa"
-notificationRecieveConfig: "Cài đặt thông báo"
-mutualFollow: "Theo dõi lẫn nhau"
-followingOrFollower: "Đang theo dõi hoặc người theo dõi"
-externalServices: "Các dịch vụ bên ngoài"
sourceCode: "Mã nguồn"
-feedback: "Phản hồi"
-feedbackUrl: "URL phản hồi"
-privacyPolicy: "Chính sách bảo mật"
-privacyPolicyUrl: "URL Chính sách bảo mật"
-tosAndPrivacyPolicy: "Điều khoản sử dụng và Chính sách bảo mật"
-avatarDecorations: "Trang trí ảnh đại diện"
-attach: "Mặc"
-detach: "Bỏ"
-detachAll: "Bỏ tất cả"
-angle: "Góc"
flip: "Lật"
-showAvatarDecorations: "Hiển thị trang trí ảnh đại diện"
-releaseToRefresh: "Thả để làm mới"
-refreshing: "Đang làm mới"
-pullDownToRefresh: "Kéo xuống để làm mới"
-cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
lastNDays: "{n} ngày trước"
-surrender: "Từ chối"
-_delivery:
- stop: "Đã vô hiệu hóa"
- _type:
- none: "Đang đăng"
_announcement:
forExistingUsers: "Chỉ những người dùng đã tồn tại"
forExistingUsersDescription: "Nếu được bật, thông báo này sẽ chỉ hiển thị với những người dùng đã tồn tại vào lúc thông báo được tạo. Nếu tắt đi, những tài khoản mới đăng ký sau khi thông báo được đăng lên cũng sẽ thấy nó."
@@ -1159,7 +1086,7 @@ _achievements:
earnedAt: "Ngày thu nhận"
_types:
_notes1:
- title: "just setting up my msky"
+ title: "just setting up my shonk"
description: "Lần đầu tiên đăng bài"
flavor: "Chúc bạn trên Miskey vui vẻ nha!!"
_notes10:
@@ -1352,7 +1279,6 @@ _role:
ltlAvailable: "Xem Timeline trong máy chủ này"
canPublicNote: "Cho phép đăng bài công khai"
canManageCustomEmojis: "Quản lý CustomEmoji"
- canManageAvatarDecorations: "Quản lý trang trí ảnh đại diện"
driveCapacity: "Dữ liệu Drive"
pinMax: "Giới hạn ghim bài viết"
antennaMax: "Giới hạn tạo ăng ten"
@@ -1546,6 +1472,7 @@ _theme:
buttonBg: "Nền nút"
buttonHoverBg: "Nền nút (Chạm)"
inputBorder: "Đường viền khung soạn thảo"
+ listItemHoverBg: "Nền mục liệt kê (Chạm)"
driveFolderBg: "Nền thư mục Ổ đĩa"
wallpaperOverlay: "Lớp phủ hình nền"
badge: "Huy hiệu"
@@ -1557,6 +1484,8 @@ _sfx:
note: "Tút"
noteMy: "Tút của tôi"
notification: "Thông báo"
+ antenna: "Trạm phát sóng"
+ channel: "Kênh"
_ago:
future: "Tương lai"
justNow: "Vừa xong"
@@ -1578,6 +1507,7 @@ _2fa:
registerTOTP: "Đăng ký ứng dụng xác thực"
step1: "Trước tiên, hãy cài đặt một ứng dụng xác minh (chẳng hạn như {a} hoặc {b}) trên thiết bị của bạn."
step2: "Sau đó, quét mã QR hiển thị trên màn hình này."
+ step2Click: "Quét mã QR trên ứng dụng xác thực (Authy, Google authenticator, v.v.)"
step3Title: "Nhập mã xác thực"
step3: "Nhập mã token do ứng dụng của bạn cung cấp để hoàn tất thiết lập."
step4: "Kể từ bây giờ, những lần đăng nhập trong tương lai sẽ yêu cầu mã token đăng nhập đó."
@@ -1859,7 +1789,7 @@ _notification:
youReceivedFollowRequest: "Bạn vừa có một yêu cầu theo dõi"
yourFollowRequestAccepted: "Yêu cầu theo dõi của bạn đã được chấp nhận"
pollEnded: "Cuộc bình chọn đã kết thúc"
- unreadAntennaNote: "Ăng ten {name}"
+ unreadAntennaNote: "Ăng ten"
emptyPushNotificationMessage: "Đã cập nhật thông báo đẩy"
achievementEarned: "Hoàn thành Achievement"
_types:
@@ -1874,7 +1804,6 @@ _notification:
receiveFollowRequest: "Yêu cầu theo dõi"
followRequestAccepted: "Yêu cầu theo dõi được chấp nhận"
achievementEarned: "Hoàn thành Achievement"
- login: "Đăng nhập"
app: "Từ app liên kết"
_actions:
followBack: "đã theo dõi lại bạn"
@@ -1914,17 +1843,14 @@ _webhookSettings:
createWebhook: "Tạo Webhook"
name: "Tên"
secret: "Mã bí mật"
+ events: "Sự kiện Webhook"
active: "Đã bật"
_events:
reaction: "Khi nhận được sự kiện"
mention: "Khi có người nhắc tới bạn"
-_abuseReport:
- _notificationRecipient:
- _recipientType:
- mail: "Email"
_moderationLogTypes:
suspend: "Vô hiệu hóa"
resetPassword: "Đặt lại mật khẩu"
- createInvitation: "Tạo lời mời"
_reversi:
total: "Tổng cộng"
+
diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml
index b81018cc1f..d0891f0678 100644
--- a/locales/zh-CN.yml
+++ b/locales/zh-CN.yml
@@ -8,9 +8,6 @@ search: "搜索"
notifications: "通知"
username: "用户名"
password: "密码"
-initialPasswordForSetup: "初始化密码"
-initialPasswordIsIncorrect: "初始化密码不正确"
-initialPasswordForSetupDescription: "如果是自己安装的 Misskey,请输入配置文件里设好的密码。\n如果使用的是 Misskey 的托管服务等,请输入服务商提供的密码。\n如果没有设置密码,请留空并继续。"
forgotPassword: "忘记密码"
fetchingAsApObject: "在联邦宇宙查询中..."
ok: "OK"
@@ -61,9 +58,8 @@ copyUserId: "复制用户 ID"
copyNoteId: "复制帖子 ID"
copyFileId: "复制文件ID"
copyFolderId: "复制文件夹ID"
-copyProfileUrl: "复制个人资料URL"
+copyProfileUrl: "复制配置文件URL"
searchUser: "搜索用户"
-searchThisUsersNotes: "搜索用户帖子"
reply: "回复"
loadMore: "查看更多"
showMore: "查看更多"
@@ -93,7 +89,7 @@ followsYou: "正在关注你"
createList: "创建列表"
manageLists: "管理列表"
error: "错误"
-somethingHappened: "出错了"
+somethingHappened: "出现了一些问题!"
retry: "重试"
pageLoadError: "页面加载失败。"
pageLoadErrorDescription: "这通常是由于网络或浏览器缓存的原因。请清除缓存或等待片刻后重试。"
@@ -112,14 +108,11 @@ enterEmoji: "输入表情符号"
renote: "转发"
unrenote: "取消转发"
renoted: "已转发。"
-renotedToX: "转帖给 {name}"
cantRenote: "该帖无法转发。"
cantReRenote: "转发无法被再次转发。"
quote: "引用"
inChannelRenote: "在频道内转发"
inChannelQuote: "在频道内引用"
-renoteToChannel: "转帖至频道"
-renoteToOtherChannel: "转帖至其它频道"
pinnedNote: "已置顶的帖子"
pinned: "置顶"
you: "您"
@@ -158,7 +151,6 @@ editList: "编辑列表"
selectChannel: "选择频道"
selectAntenna: "选择天线"
editAntenna: "编辑天线"
-createAntenna: "创建天线"
selectWidget: "选择小工具"
editWidgets: "编辑部件"
editWidgetsExit: "完成编辑"
@@ -170,7 +162,7 @@ emojiUrl: "emoji 地址"
addEmoji: "添加表情符号"
settingGuide: "推荐配置"
cacheRemoteFiles: "缓存远程文件"
-cacheRemoteFilesDescription: "启用此设定时,将在此服务器上缓存远程文件。虽然可以加快图片显示的速度,但是相对的会消耗大量的服务器存储空间。用户角色内的网盘容量决定了这个远程用户能在服务器上保留多少缓存。当超出了这个限制时,旧的文件将从缓存中被删除,成为链接。当禁用此设定时,则是从一开始就将远程文件保留为链接。此时推荐将 default.yml 的 proxyRemoteFiles 设置为 true 以优化缩略图生成及保护用户隐私。"
+cacheRemoteFilesDescription: "启用此设定时,将在此服务器上缓存远程文件。虽然可以加快图片显示的速度,但是相对的会消耗大量的服务器存储空间。用户角色内的网盘容量决定了这个远程用户能在服务器上保留保留多少缓存。当超出了这个限制时,旧的文件将从缓存中被删除,成为链接。当禁用此设定时,则是从一开始就将远程文件保留为链接。此时推荐将 default.yml 的 proxyRemoteFiles 设置为 true 以优化缩略图生成及保护用户隐私。"
youCanCleanRemoteFilesCache: "可以使用文件管理的🗑️按钮来删除所有的缓存。"
cacheRemoteSensitiveFiles: "缓存远程敏感媒体文件"
cacheRemoteSensitiveFilesDescription: "如果禁用这项设定,远程服务器的敏感媒体将不会被缓存,而是直接链接。"
@@ -185,10 +177,6 @@ addAccount: "添加账户"
reloadAccountsList: "更新账户列表"
loginFailed: "登录失败"
showOnRemote: "转到所在服务器显示"
-continueOnRemote: "转到所在服务器继续"
-chooseServerOnMisskeyHub: "从 Misskey Hub 选择服务器"
-specifyServerHost: "直接输入服务器域名"
-inputHostName: "请输入域名"
general: "常规设置"
wallpaper: "壁纸"
setWallpaper: "设置壁纸"
@@ -199,7 +187,6 @@ followConfirm: "你确定要关注 {name} 吗?"
proxyAccount: "代理账户"
proxyAccountDescription: "代理账户是在某些情况下替代用户进行远程关注用的账户。 例如说,当用户将一位远程用户放入一个列表中时,如果本地服务器上没有任何人关注这位远程用户,则这位远程用户的账户活动将不会被送到本地服务器上。作为替代,此时将使用代理账户进行关注。"
host: "主机名"
-selectSelf: "选择自己"
selectUser: "选择用户"
recipient: "收件人"
annotation: "注解"
@@ -215,7 +202,6 @@ perDay: "每天"
stopActivityDelivery: "停止发送活动"
blockThisInstance: "阻止此服务器向本服务器推流"
silenceThisInstance: "使服务器静音"
-mediaSilenceThisInstance: "隐藏此服务器的媒体文件"
operations: "操作"
software: "软件"
version: "版本"
@@ -234,13 +220,9 @@ clearQueueConfirmText: "未送达的帖子将不会被投递。 通常无需执
clearCachedFiles: "清除缓存"
clearCachedFilesConfirm: "确定要清除所有缓存的远程文件?"
blockedInstances: "被封锁的服务器"
-blockedInstancesDescription: "设定要封锁的服务器,以换行分隔。被封锁的服务器将无法与本服务器进行交换通讯。子域名也同样会被封锁。"
+blockedInstancesDescription: "设定要封锁的服务器,以换行来进行分割。被封锁的服务器将无法与本服务器进行交换通讯。子域名也同样会被封锁。"
silencedInstances: "被静音的服务器"
-silencedInstancesDescription: "设置要静音的服务器,以换行分隔。被静音的服务器内所有的账户将默认处于「静音」状态,仅能发送关注请求,并且在未关注状态下无法提及本地账户。被阻止的实例不受影响。"
-mediaSilencedInstances: "已隐藏媒体文件的服务器"
-mediaSilencedInstancesDescription: "设置要隐藏媒体文件的服务器,以换行分隔。被设置为隐藏媒体文件服务器内所有账号的文件均按照「敏感内容」处理,且将无法使用自定义表情符号。被阻止的实例不受影响。"
-federationAllowedHosts: "允许联合的服务器"
-federationAllowedHostsDescription: "设定允许联合的服务器,以换行分隔。"
+silencedInstancesDescription: "设置要静音的服务器,以换行符分隔。被静音的服务器内所有的账户将默认处于「静音」状态,仅能发送关注请求,并且在未关注状态下无法提及本地账户。被阻止的实例不受影响。"
muteAndBlock: "静音/拉黑"
mutedUsers: "已静音用户"
blockedUsers: "已拉黑的用户"
@@ -331,7 +313,6 @@ selectFile: "选择文件"
selectFiles: "选择文件"
selectFolder: "选择文件夹"
selectFolders: "选择多个文件夹"
-fileNotSelected: "未选择文件"
renameFile: "重命名文件"
folderName: "文件夹名称"
createFolder: "创建文件夹"
@@ -339,7 +320,6 @@ renameFolder: "重命名文件夹"
deleteFolder: "删除文件夹"
folder: "文件夹"
addFile: "添加文件"
-showFile: "显示文件"
emptyDrive: "网盘中无文件"
emptyFolder: "此文件夹中无文件"
unableToDelete: "无法删除"
@@ -356,7 +336,7 @@ displayOfSensitiveMedia: "显示敏感媒体"
whenServerDisconnected: "与服务器连接中断时"
disconnectedFromServer: "已和服务器断开连接"
reload: "重新加载"
-doNothing: "关闭"
+doNothing: "关闭弹窗"
reloadConfirm: "确定要重新加载吗?"
watch: "关注"
unwatch: "取消关注"
@@ -367,7 +347,7 @@ instanceName: "服务器名称"
instanceDescription: "服务器简介"
maintainerName: "管理员名称"
maintainerEmail: "管理员电子邮箱"
-tosUrl: "服务条款地址"
+tosUrl: "服务条款 URL"
thisYear: "今年"
thisMonth: "本月"
today: "今天"
@@ -420,7 +400,6 @@ name: "名称"
antennaSource: "接收来源"
antennaKeywords: "包含关键字"
antennaExcludeKeywords: "排除关键字"
-antennaExcludeBots: "排除机器人账户"
antennaKeywordsDescription: "AND 条件用空格分隔,OR 条件用换行符分隔。"
notifyAntenna: "开启通知"
withFileAntenna: "仅带有附件的帖子"
@@ -449,12 +428,11 @@ administrator: "管理员"
token: "Token (令牌)"
2fa: "双因素认证"
setupOf2fa: "设置双因素认证"
-totp: "验证器"
-totpDescription: "使用验证器输入一次性密码"
+totp: "身份验证应用"
+totpDescription: "使用认证应用输入一次性密码。"
moderator: "监察员"
moderation: "管理"
moderationNote: "管理笔记"
-moderationNoteDescription: "可以用来记录仅在管理员之间共享的笔记。"
addModerationNote: "添加管理笔记"
moderationLogs: "管理日志"
nUsersMentioned: "{n} 被提到"
@@ -489,12 +467,10 @@ retype: "重新输入"
noteOf: "{user} 的帖子"
quoteAttached: "已引用"
quoteQuestion: "是否引用此链接内容?"
-attachAsFileQuestion: "剪贴板内的文字过长。要转换为文本文件并添加吗?"
noMessagesYet: "现在没有新的聊天"
newMessageExists: "新信息"
onlyOneFileCanBeAttached: "只能添加一个附件"
signinRequired: "请先登录"
-signinOrContinueOnRemote: "若要继续,需要转到您所使用的实例,或者在此服务器上注册或登录。"
invitations: "邀请"
invitationCode: "邀请码"
checking: "正在确认"
@@ -516,12 +492,8 @@ uiLanguage: "显示语言"
aboutX: "关于 {x}"
emojiStyle: "表情符号的样式"
native: "原生"
-menuStyle: "菜单样式"
-style: "样式"
-drawer: "抽屉"
-popup: "弹窗"
+disableDrawer: "不显示抽屉菜单"
showNoteActionsOnlyHover: "仅在悬停时显示帖子操作"
-showReactionsCount: "显示帖子的回应数"
noHistory: "没有历史记录"
signinHistory: "登录历史"
enableAdvancedMfm: "启用扩展 MFM"
@@ -602,8 +574,6 @@ ascendingOrder: "升序"
descendingOrder: "降序"
scratchpad: "AiScript 控制台"
scratchpadDescription: "AiScript 控制台为 AiScript 提供了实验环境。您可以编写代码与 Misskey 交互,运行并查看结果。"
-uiInspector: "UI 检查器"
-uiInspectorDescription: "查看所有内存中由 UI 组件生成出的实例。UI 组件由 UI:C 系列函数所生成。"
output: "输出"
script: "脚本"
disablePagesScript: "禁用页面脚本"
@@ -644,7 +614,7 @@ disablePlayer: "关闭播放器"
expandTweet: "展开帖子"
themeEditor: "主题编辑器"
description: "描述"
-describeFile: "添加描述"
+describeFile: "添加标题"
enterFileDescription: "输入标题"
author: "作者"
leaveConfirm: "存在未保存的更改。要放弃更改吗?"
@@ -720,7 +690,10 @@ abuseReported: "内容已发送。感谢您提交信息。"
reporter: "举报者"
reporteeOrigin: "举报来源"
reporterOrigin: "举报者来源"
+forwardReport: "将该举报信息转发给远程服务器"
+forwardReportIsAnonymous: "在远程实例上显示的报告者是匿名的系统账号,而不是您的账号。"
send: "发送"
+abuseMarkAsResolved: "处理完毕"
openInNewTab: "在新标签页中打开"
openInSideView: "在侧边栏中打开"
defaultNavigationBehaviour: "默认导航"
@@ -857,7 +830,6 @@ administration: "管理"
accounts: "账户"
switch: "切换"
noMaintainerInformationWarning: "管理人员信息未设置。"
-noInquiryUrlWarning: "尚未设置联络地址。"
noBotProtectionWarning: "Bot 防御未设置。"
configure: "设置"
postToGallery: "发送到图库"
@@ -869,7 +841,7 @@ shareWithNote: "在帖子中分享"
ads: "广告"
expiration: "截止时间"
startingperiod: "开始时间"
-memo: "备注"
+memo: "便笺"
priority: "优先级"
high: "高"
middle: "中"
@@ -922,7 +894,6 @@ followersVisibility: "关注者的公开范围"
continueThread: "查看更多帖子"
deleteAccountConfirm: "将要删除账户。是否确认?"
incorrectPassword: "密码错误"
-incorrectTotp: "一次性密码不正确或已过期"
voteConfirm: "确定投给 “{choice}” ?"
hide: "隐藏"
useDrawerReactionPickerForMobile: "在移动设备上使用抽屉显示"
@@ -1020,7 +991,6 @@ neverShow: "不再显示"
remindMeLater: "稍后提醒我"
didYouLikeMisskey: "您喜欢 Misskey 吗?"
pleaseDonate: "Misskey 是 {host} 所使用的免费软件。为了今后也能够维持 Misskey 的开发,请在有余力的情况下进行捐助!"
-correspondingSourceIsAvailable: "对应的源代码可在{anchor}找到"
roles: "角色"
role: "角色"
noRole: "角色不存在"
@@ -1048,7 +1018,6 @@ thisPostMayBeAnnoyingHome: "发到首页"
thisPostMayBeAnnoyingCancel: "取消"
thisPostMayBeAnnoyingIgnore: "就这样发布"
collapseRenotes: "省略显示已经看过的转发内容"
-collapseRenotesDescription: "将回应过或转贴过的贴子折叠表示。"
internalServerError: "内部服务器错误"
internalServerErrorDescription: "内部服务器发生了预期外的错误"
copyErrorInfo: "复制错误信息"
@@ -1073,7 +1042,6 @@ sensitiveWords: "敏感词"
sensitiveWordsDescription: "将包含设置词的帖子的可见范围设置为首页。可以通过用换行符分隔来设置多个。"
sensitiveWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。"
prohibitedWords: "禁用词"
-prohibitedWordsDescription: "发布包含设定词汇的帖子时将出错。可用换行设定多个关键字"
prohibitedWordsDescription2: "AND 条件用空格分隔,正则表达式用斜线包裹。"
hiddenTags: "隐藏标签"
hiddenTagsDescription: "设定的标签将不会在时间线上显示。可使用换行来设置多个标签。"
@@ -1087,7 +1055,6 @@ retryAllQueuesConfirmTitle: "要再尝试一次吗?"
retryAllQueuesConfirmText: "可能会使服务器负荷在一定时间内增加"
enableChartsForRemoteUser: "生成远程用户的图表"
enableChartsForFederatedInstances: "生成远程服务器的图表"
-enableStatsForFederatedInstances: "获取远程服务器的信息"
showClipButtonInNoteFooter: "在贴文下方显示便签按钮"
reactionsDisplaySize: "回应显示大小"
limitWidthOfReaction: "限制回应的最大宽度,并将其缩小显示"
@@ -1123,8 +1090,6 @@ preservedUsernames: "保留的用户名"
preservedUsernamesDescription: "列出需要保留的用户名,使用换行来作为分割。被指定的用户名在建立账户时无法使用,但由管理员所创建的账户不受该限制。此外,现有的账户也不会受到影响。"
createNoteFromTheFile: "从文件创建帖子"
archive: "归档"
-archived: "已归档"
-unarchive: "取消归档"
channelArchiveConfirmTitle: "要将 {name} 归档吗?"
channelArchiveConfirmDescription: "归档后,在频道列表与搜索结果中不会显示,也无法发布新的贴文。"
thisChannelArchived: "该频道已被归档。"
@@ -1135,9 +1100,6 @@ preventAiLearning: "拒绝接受生成式 AI 的学习"
preventAiLearningDescription: "要求文章生成 AI 或图像生成 AI 不能够以发布的帖子和图像等内容作为学习对象。这是通过在 HTML 响应中包含 noai 标志来实现的,这不能完全阻止 AI 学习你的发布内容,并不是所有 AI 都会遵守这类请求。"
options: "选项"
specifyUser: "用户指定"
-lookupConfirm: "确定查询?"
-openTagPageConfirm: "确定打开话题标签页面?"
-specifyHost: "指定主机名"
failedToPreviewUrl: "无法预览"
update: "更新"
rolesThatCanBeUsedThisEmojiAsReaction: "可以使用表情作为回应的角色"
@@ -1153,7 +1115,7 @@ branding: "品牌"
enableServerMachineStats: "公开服务器硬件统计信息"
enableIdenticonGeneration: "启用生成用户 Identicon"
turnOffToImprovePerformance: "关闭该选项可以提高性能。"
-createInviteCode: "生成邀请码"
+createInviteCode: "发行邀请码"
createWithOptions: "使用选项来创建"
createCount: "发行数"
inviteCodeCreated: "已创建邀请码"
@@ -1165,7 +1127,7 @@ noExpirationDate: "不设置有效日期"
inviteCodeUsedAt: "邀请码被使用的日期和时间"
registeredUserUsingInviteCode: "使用了邀请码的用户"
waitingForMailAuth: "等待验证电子邮件"
-inviteCodeCreator: "生成邀请码的用户"
+inviteCodeCreator: "发行邀请码的用户"
usedAt: "使用时间"
unused: "未使用"
used: "已使用"
@@ -1196,22 +1158,15 @@ showRenotes: "显示转帖"
edited: "已编辑"
notificationRecieveConfig: "通知接收设置"
mutualFollow: "互相关注"
-followingOrFollower: "关注中或关注者"
fileAttachedOnly: "仅限媒体"
showRepliesToOthersInTimeline: "在时间线中包含给别人的回复"
hideRepliesToOthersInTimeline: "在时间线中隐藏给别人的回复"
-showRepliesToOthersInTimelineAll: "在时间线中显示所有现在关注的人的回复"
-hideRepliesToOthersInTimelineAll: "在时间线中隐藏所有现在关注的人的回复"
-confirmShowRepliesAll: "此操作不可撤销。确认要在时间线中显示所有现在关注的人的回复吗?"
-confirmHideRepliesAll: "此操作不可撤销。确认要在时间线中隐藏所有现在关注的人的回复吗?"
+showRepliesToOthersInTimelineAll: "在时间线中包含现在关注的所有人的回复"
+hideRepliesToOthersInTimelineAll: "在时间线中隐藏现在关注的所有人的回复"
+confirmShowRepliesAll: "此操作不可撤销。确认要在时间线中包含现在关注的所有人的回复吗?"
+confirmHideRepliesAll: "此操作不可撤销。确认要在时间线中隐藏现在关注的所有人的回复吗?"
externalServices: "外部服务"
sourceCode: "源代码"
-sourceCodeIsNotYetProvided: "还未提供源代码。要解决此问题请联系管理员。"
-repositoryUrl: "仓库地址"
-repositoryUrlDescription: "若源代码所在的仓库是公开的,请填入对应的 URL。若并未追加或者修改 Misskey 的代码,请填入 https://github.com/misskey-dev/misskey。"
-repositoryUrlOrTarballRequired: "若仓库并未公开,则需要提供 tarball 作为替代。详情请看 .config/example.yml。"
-feedback: "反馈"
-feedbackUrl: "反馈地址"
impressum: "运营商信息"
impressumUrl: "运营商信息地址"
impressumDescription: "德国等国家和地区有义务展示此类信息(Impressum)。"
@@ -1237,18 +1192,15 @@ code: "代码"
reloadRequiredToApplySettings: "需要重新载入来使设置生效"
remainingN: "剩余:{n}"
overwriteContentConfirm: "将覆盖现有内容。确定吗?"
-seasonalScreenEffect: "符合当前季节的画面效果"
+seasonalScreenEffect: "应景的画面效果"
decorate: "装饰"
addMfmFunction: "添加装饰"
enableQuickAddMfmFunction: "显示高级 MFM 选择器"
-bubbleGame: "泡泡游戏"
sfx: "音效"
soundWillBePlayed: "声音将会播放"
-showReplay: "观看回放"
+showReplay: "查看重播"
replay: "重播"
replaying: "重播中"
-endReplay: "结束回放"
-copyReplayData: "复制回放数据"
ranking: "排行榜"
lastNDays: "最近 {n} 天"
backToTitle: "返回标题"
@@ -1256,70 +1208,8 @@ hemisphere: "居住地区"
withSensitive: "显示包含敏感媒体的帖子"
userSaysSomethingSensitive: "含 {name} 敏感文件的帖子"
enableHorizontalSwipe: "滑动切换标签页"
-loading: "读取中"
-surrender: "取消"
-gameRetry: "重试"
-notUsePleaseLeaveBlank: "如不使用请留空"
-useTotp: "使用一次性代码"
-useBackupCode: "使用备用代码"
-launchApp: "启动应用"
-useNativeUIForVideoAudioPlayer: "使用浏览器的 UI 播放动画及音频"
-keepOriginalFilename: "保持原文件名"
-keepOriginalFilenameDescription: "若关闭此设置,上传文件时文件名将被替换为随机字符。"
-noDescription: "没有描述"
-alwaysConfirmFollow: "总是确认关注"
-inquiry: "联系我们"
-tryAgain: "请再试一次"
-confirmWhenRevealingSensitiveMedia: "显示敏感内容前需要确认"
-sensitiveMediaRevealConfirm: "这是敏感内容。是否显示?"
-createdLists: "已创建的列表"
-createdAntennas: "已创建的天线"
-fromX: "从 {x}"
-genEmbedCode: "生成嵌入代码"
-noteOfThisUser: "此用户的帖子"
-clipNoteLimitExceeded: "无法再往此便签内添加更多帖子"
-performance: "性能"
-modified: "有变更"
-discard: "取消"
-thereAreNChanges: "有 {n} 处更改"
-signinWithPasskey: "使用通行密钥登录"
-unknownWebAuthnKey: "此通行密钥未注册。"
-passkeyVerificationFailed: "验证通行密钥失败。"
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "通行密钥验证成功,但账户未开启无密码登录。"
-messageToFollower: "给关注者的消息"
-target: "对象"
-testCaptchaWarning: "此功能为测试 CAPTCHA 用。请勿在正式环境中使用。 "
-prohibitedWordsForNameOfUser: "用户名中禁止的词"
-prohibitedWordsForNameOfUserDescription: "更改用户名时,如果用户名中包含此列表里的词汇,用户的改名请求将被拒绝。持有管理员权限的用户不受此限制。"
-yourNameContainsProhibitedWords: "目标用户名包含违禁词"
-yourNameContainsProhibitedWordsDescription: "用户名内含有违禁词。若想使用此用户名,请联系服务器管理员。"
-_abuseUserReport:
- forward: "转发"
- forwardDescription: "目标是匿名系统账户,将把举报转发给远程服务器。"
- resolve: "解决"
- accept: "确认"
- reject: "拒绝"
- resolveTutorial: "如果举报内容有理且已解决,选择「确认」将案件以肯定的态度标记为已解决。\n如果举报内容站不住脚,选择「拒绝」将案件以否定的态度标记为已解决。"
-_delivery:
- status: "投递状态"
- stop: "停止投递"
- resume: "继续投递"
- _type:
- none: "投递中"
- manuallySuspended: "手动停止中"
- goneSuspended: "因服务器被删除而停止"
- autoSuspendedForNotResponding: "因服务器无应答而停止"
_bubbleGame:
howToPlay: "游戏说明"
- hold: "抓住"
- _score:
- score: "得分"
- scoreYen: "赚到的钱"
- highScore: "最高分"
- maxChain: "最高连击数"
- yen: "{yen} 日元"
- estimatedQty: "约 {qty} 个"
- scoreSweets: "相当于 {onigiriQtyWithUnit} 饭团"
_howToPlay:
section1: "对准位置将Emoji投入盒子。"
section2: "相同的Emoji相互接触合成后会得到新的Emoji,以此获得分数。"
@@ -1408,8 +1298,8 @@ _initialTutorial:
description: "对于服务器方针所要求要求的,又或者不适合直接展示的附件,请添加「敏感」标记。\n"
tryThisFile: "试试看,将附加到此窗口的图像标注为敏感!"
_exampleNote:
- note: "拆纳豆包装时出错了…"
- method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击“标记为敏感内容”。"
+ note: "不该打开纳豆的盖子的……"
+ method: "要标注附件为敏感内容,请单击该文件以打开菜单,然后单击“设置为敏感”。"
sensitiveSucceeded: "附加文件时,请遵循服务器的条款来设置正确敏感设定。\n"
doItToContinue: "将图像标记为敏感后才能够继续"
_done:
@@ -1434,14 +1324,10 @@ _serverSettings:
fanoutTimelineDescription: "当启用时,可显著提高获取各种时间线时的性能,并减轻数据库的负荷。但是相对的 Redis 的内存使用量将会增加。如果服务器的内存不是很大,又或者运行不稳定的话可以把它关掉。"
fanoutTimelineDbFallback: "回退到数据库"
fanoutTimelineDbFallbackDescription: "当启用时,若时间线未被缓存,则将额外查询数据库。禁用该功能可通过不执行回退处理进一步减少服务器负载,但会限制可检索的时间线范围。"
- reactionsBufferingDescription: "开启时可显著提高发送回应时的性能,及减轻数据库负荷。但 Redis 的内存用量会相应增加。"
- inquiryUrl: "联络地址"
- inquiryUrlDescription: "用来指定诸如向服务运营商咨询的论坛地址,或记载了运营商联系方式之类的网页地址。"
- thisSettingWillAutomaticallyOffWhenModeratorsInactive: "若在一段时间内没有检测到管理活动,为防止垃圾信息,此设定将自动关闭。"
_accountMigration:
moveFrom: "从别的账号迁移到此账户"
moveFromSub: "为另一个账户建立别名"
- moveFromLabel: "迁移前的账户 #{n}"
+ moveFromLabel: "迁移前的账户"
moveFromDescription: "如果迁移时需要继承其他账户的关注者,你需要创建一个别名。此操作需要在迁移前完成!\n请像这样输入要迁移的账户:@username@server.example.com\n如果要删除,请将输入字段留空,并保存(不推荐)。"
moveTo: "把这个账户迁移到新的账户"
moveToLabel: "迁移后的账户"
@@ -1637,7 +1523,7 @@ _achievements:
_postedAt0min0sec:
title: "报时"
description: "在 0 点发布一篇帖子"
- flavor: "嘟 · 嘟 · 嘟 · 哔——"
+ flavor: "嘣 嘣 嘣 Biu——!"
_selfQuote:
title: "自我引用"
description: "引用了自己的帖子"
@@ -1686,8 +1572,8 @@ _achievements:
flavor: "今年也请对本服务器多多指教!"
_cookieClicked:
title: "点击饼干小游戏"
- description: "点击了饼干"
- flavor: "用错软件了?"
+ description: "点击了可疑的饼干"
+ flavor: "是不是软件有问题?"
_brainDiver:
title: "Brain Diver"
description: "发布了包含 Brain Diver 链接的帖子"
@@ -1704,7 +1590,6 @@ _achievements:
_bubbleGameDoubleExplodingHead:
title: "两个🤯"
description: "你合成出了2个游戏里最大的Emoji"
- flavor: "大约能 装满 这些便当盒 🤯 🤯 (比划)"
_role:
new: "创建角色"
edit: "编辑角色"
@@ -1734,8 +1619,8 @@ _role:
descriptionOfIsExplorable: "打开后将公开角色时间线。如果角色不是公开的,就无法公开时间线。"
displayOrder: "显示顺序"
descriptionOfDisplayOrder: "数字越大,显示位置越靠前。"
- canEditMembersByModerator: "允许监察员编辑成员"
- descriptionOfCanEditMembersByModerator: "如果选中,监察员和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
+ canEditMembersByModerator: "允许监察者编辑成员"
+ descriptionOfCanEditMembersByModerator: "如果选中,监察者和管理员都能够为用户分配/取消分配角色。如果未选中,则只有管理员可以执行此操作。"
priority: "优先级"
_priority:
low: "低"
@@ -1745,16 +1630,14 @@ _role:
gtlAvailable: "查看全局时间线"
ltlAvailable: "查看本地时间线"
canPublicNote: "允许公开发帖"
- mentionMax: "帖子内最多提及数"
canInvite: "发放服务器邀请码"
- inviteLimit: "可生成邀请码的数量"
+ inviteLimit: "可发行邀请码的数量"
inviteLimitCycle: "邀请码的发行间隔"
inviteExpirationTime: "邀请码的有效日期"
canManageCustomEmojis: "管理自定义表情符号"
canManageAvatarDecorations: "管理头像挂件"
driveCapacity: "网盘容量"
alwaysMarkNsfw: "总是将文件标记为 NSFW"
- canUpdateBioMedia: "可以更新头像和横幅"
pinMax: "帖子置顶数量限制"
antennaMax: "可创建的最大天线数量"
wordMuteMax: "屏蔽词的字数限制"
@@ -1769,20 +1652,9 @@ _role:
canSearchNotes: "是否可以搜索帖子"
canUseTranslator: "使用翻译功能"
avatarDecorationLimit: "可添加头像挂件的最大个数"
- canImportAntennas: "允许导入天线"
- canImportBlocking: "允许导入拉黑列表"
- canImportFollowing: "允许导入关注列表"
- canImportMuting: "允许导入屏蔽列表"
- canImportUserLists: "允许导入用户列表"
_condition:
- roleAssignedTo: "已分配给手动角色"
isLocal: "是本地用户"
isRemote: "是远程用户"
- isCat: "猫猫用户"
- isBot: "机器人用户"
- isSuspended: "停用的用户"
- isLocked: "锁推用户"
- isExplorable: "启用“使账号可见”的用户"
createdLessThan: "账户创建时间少于"
createdMoreThan: "账户创建时间超过"
followersLessThanOrEq: "关注者不多于"
@@ -1852,7 +1724,6 @@ _plugin:
installWarn: "请不要安装不可信的插件。"
manage: "管理插件..."
viewSource: "查看源代码"
- viewLog: "显示日志"
_preferencesBackups:
list: "已创建的备份"
saveNew: "另存为"
@@ -1882,8 +1753,6 @@ _aboutMisskey:
contributors: "主要贡献者"
allContributors: "全体贡献者"
source: "源代码"
- original: "原版"
- thisIsModifiedVersion: "{name}正在使用修改后的 Misskey。"
translation: "翻译 Misskey"
donate: "赞助 Misskey"
morePatrons: "还有很多其它的人也在支持我们,非常感谢🥰"
@@ -1991,6 +1860,7 @@ _theme:
buttonBg: "按钮背景"
buttonHoverBg: "按钮背景(悬停)"
inputBorder: "输入框边框"
+ listItemHoverBg: "下拉列表项目背景(悬停)"
driveFolderBg: "网盘的文件夹背景"
wallpaperOverlay: "壁纸叠加层"
badge: "徽章"
@@ -2002,6 +1872,8 @@ _sfx:
note: "帖子"
noteMy: "我的帖子"
notification: "通知"
+ antenna: "天线接收"
+ channel: "频道通知"
reaction: "选择回应时"
_soundSettings:
driveFile: "使用网盘内的音频"
@@ -2010,7 +1882,6 @@ _soundSettings:
driveFileTypeWarnDescription: "请选择音频文件"
driveFileDurationWarn: "音频过长"
driveFileDurationWarnDescription: "使用长音频可能会影响 Misskey 的使用。即使这样也要继续吗?"
- driveFileError: "无法读取声音。请更改设置。"
_ago:
future: "未来"
justNow: "最近"
@@ -2037,33 +1908,33 @@ _time:
day: "日"
_2fa:
alreadyRegistered: "此设备已被注册"
- registerTOTP: "开始设置验证器"
+ registerTOTP: "开始设置认证应用"
step1: "首先,在您的设备上安装验证应用,例如 {a} 或 {b}。"
step2: "然后,扫描屏幕上显示的二维码。"
+ step2Click: "通过点击二维码,您可以使用设备上安装的身份验证器应用程序或密钥环进行注册"
step2Uri: "如果使用桌面应用程序的话,请输入下面的 URI"
step3Title: "输入验证码"
step3: "输入您的应用提供的动态口令以完成设置。"
setupCompleted: "设置完成"
step4: "从现在开始,任何登录操作都将要求您提供动态口令。"
securityKeyNotSupported: "您的浏览器不支持安全密钥。"
- registerTOTPBeforeKey: "要注册安全密钥或 Passkey,请先设置验证器。"
+ registerTOTPBeforeKey: "要注册安全密钥或 Passkey,请先设置验证器应用程序。"
securityKeyInfo: "注册兼容 WebAuthn 的密钥,例如支持 FIDO2 的硬件安全密钥、设备上的生物识别功能、PIN 码以及 Passkey 等。"
registerSecurityKey: "注册安全密钥或 Passkey"
securityKeyName: "输入密钥名称"
tapSecurityKey: "请按照浏览器说明操作来注册安全密钥或 Passkey。"
removeKey: "删除安全密钥"
removeKeyConfirm: "您确定要删除 {name} 吗?"
- whyTOTPOnlyRenew: "当注册了安全密钥时,无法取消使用验证器。"
- renewTOTP: "重置验证器"
- renewTOTPConfirm: "当前验证器的验证码及备用代码已失效"
+ whyTOTPOnlyRenew: "如果注册了安全密钥,则无法取消验证器应用程序上的设置。"
+ renewTOTP: "重置验证器应用程序"
+ renewTOTPConfirm: "当前验证器应用程序的验证码将不再有效"
renewTOTPOk: "重新配置"
renewTOTPCancel: "不用,谢谢"
checkBackupCodesBeforeCloseThisWizard: "在关闭此窗口前,请确认下面的备用代码"
backupCodes: "备用代码"
- backupCodesDescription: "如果无法使用验证器,可以使用以下的备用代码来访问账户。请务必将这些代码保存在安全的地方。每个代码仅可使用一次。"
- backupCodeUsedWarning: "已使用备用代码。若验证器无法使用,请尽快重置验证器。"
- backupCodesExhaustedWarning: "已使用完所有的备用代码。若验证器无法使用,则无法再访问您的账户。请重置验证器。"
- moreDetailedGuideHere: "此处为详细指南"
+ backupCodesDescription: "如果无法使用认证应用,可以使用以下的备用代码来访问账户。请务必将这些代码保存在安全的地方。每个代码仅可使用一次。"
+ backupCodeUsedWarning: "已使用备用代码。如果无法使用认证应用,请尽快重新设定。"
+ backupCodesExhaustedWarning: "已使用完所有的备用代码。如果无法使用认证应用,将无法再访问您的账户。请再次设定认证应用。"
_permissions:
"read:account": "查看账户信息"
"write:account": "更改帐户信息"
@@ -2114,6 +1985,7 @@ _permissions:
"read:admin:server-info": "查看服务器信息"
"read:admin:show-moderation-log": "查看管理日志"
"read:admin:show-user": "查看用户的非公开信息"
+ "read:admin:show-users": "查看用户的非公开信息"
"write:admin:suspend-user": "冻结用户"
"write:admin:unset-user-avatar": "删除用户头像"
"write:admin:unset-user-banner": "删除用户横幅"
@@ -2143,7 +2015,7 @@ _permissions:
"read:admin:stream": "使用管理员用的 Websocket API"
"write:admin:ad": "编辑广告"
"read:admin:ad": "查看广告"
- "write:invite-codes": "生成邀请码"
+ "write:invite-codes": "发行邀请码"
"read:invite-codes": "获取已发行的邀请码"
"write:clip-favorite": "编辑便签的点赞"
"read:clip-favorite": "查看便签的点赞"
@@ -2267,9 +2139,6 @@ _profile:
changeBanner: "修改横幅"
verifiedLinkDescription: "如果将内容设置为 URL,当链接所指向的网页内包含自己的个人资料链接时,可以显示一个已验证图标。"
avatarDecorationMax: "最多可添加 {max} 个挂件"
- followedMessage: "被关注时显示的消息"
- followedMessageDescription: "可以设置被关注时向对方显示的短消息。"
- followedMessageDescriptionForLockedAccount: "需要批准才能关注的情况下,消息是在请求被批准后显示。"
_exportOrImport:
allNotes: "所有帖子"
favoritedNotes: "收藏的帖子"
@@ -2327,7 +2196,6 @@ _play:
title: "标题"
script: "脚本"
summary: "描述"
- visibilityDescription: "设置为不公开后资料将不再显示,但知道 URL 的人仍可继续访问。"
_pages:
newPage: "创建页面"
editPage: "编辑页面"
@@ -2362,7 +2230,6 @@ _pages:
eyeCatchingImageSet: "设置封面图片"
eyeCatchingImageRemove: "删除封面图片"
chooseBlock: "添加块"
- enterSectionTitle: "输入会话标题"
selectType: "选择类型"
contentBlocks: "内容"
inputBlocks: "输入"
@@ -2373,8 +2240,6 @@ _pages:
section: "章节"
image: "图片"
button: "按钮"
- dynamic: "动态区块"
- dynamicDescription: "这个区块已经废弃。以后请使用{play}。"
note: "嵌入的帖子"
_note:
id: "帖子 ID"
@@ -2404,12 +2269,8 @@ _notification:
sendTestNotification: "发送测试通知"
notificationWillBeDisplayedLikeThis: "通知将会这样表示"
reactedBySomeUsers: "{n} 人回应了"
- likedBySomeUsers: "{n}人赞了你的帖子"
renotedBySomeUsers: "{n} 人转发了"
followedBySomeUsers: "被 {n} 人关注"
- flushNotification: "重置通知历史"
- exportOfXCompleted: "已完成 {x} 个导出"
- login: "有新的登录"
_types:
all: "全部"
note: "用户的新帖子"
@@ -2424,9 +2285,6 @@ _notification:
followRequestAccepted: "关注请求已通过"
roleAssigned: "授予的角色"
achievementEarned: "取得的成就"
- exportCompleted: "已完成导出"
- login: "登录"
- test: "测试通知"
app: "关联应用的通知"
_actions:
followBack: "回关"
@@ -2436,7 +2294,6 @@ _deck:
alwaysShowMainColumn: "总是显示主列"
columnAlign: "列对齐"
addColumn: "添加列"
- newNoteNotificationSettings: "新帖子通知设定"
configureColumn: "列设置"
swapLeft: "向左移动"
swapRight: "向右移动"
@@ -2475,10 +2332,9 @@ _drivecleaner:
orderByCreatedAtAsc: "按添加日期降序排列"
_webhookSettings:
createWebhook: "创建 Webhook"
- modifyWebhook: "编辑 webhook"
name: "名称"
secret: "密钥"
- trigger: "触发器"
+ events: "何时运行 Webhook"
active: "已启用"
_events:
follow: "关注时"
@@ -2488,29 +2344,6 @@ _webhookSettings:
renote: "被转发时"
reaction: "被回应时"
mention: "被提及时"
- _systemEvents:
- abuseReport: "当收到举报时"
- abuseReportResolved: "当举报被处理时"
- userCreated: "当用户被创建时"
- inactiveModeratorsWarning: "当管理员在一段时间内不活跃时"
- inactiveModeratorsInvitationOnlyChanged: "当因为管理员在一段时间内不活跃,导致服务器变为邀请制时"
- deleteConfirm: "要删除 webhook 吗?"
- testRemarks: "点击开关右侧的按钮,可以发送使用假数据的测试 Webhook。"
-_abuseReport:
- _notificationRecipient:
- createRecipient: "新建举报通知"
- modifyRecipient: "编辑举报通知"
- recipientType: "通知类型"
- _recipientType:
- mail: "邮箱"
- webhook: "Webhook"
- _captions:
- mail: "当收到新举报时,向持有监察员权限的用户发送通知邮件"
- webhook: "当收到新举报及举报被处理时,使用指定的 SystemWebhook 发送通知"
- keywords: "关键字"
- notifiedUser: "通知的用户"
- notifiedWebhook: "使用的 webhook"
- deleteConfirm: "要删除通知吗?"
_moderationLogTypes:
createRole: "创建角色"
deleteRole: "删除角色"
@@ -2535,13 +2368,10 @@ _moderationLogTypes:
resetPassword: "重置密码"
suspendRemoteInstance: "停止远程服务器"
unsuspendRemoteInstance: "恢复远程服务器"
- updateRemoteInstanceNote: "更新远程服务器的管理笔记"
markSensitiveDriveFile: "标记网盘文件为敏感媒体"
unmarkSensitiveDriveFile: "取消标记网盘文件为敏感媒体"
resolveAbuseReport: "处理举报"
- forwardAbuseReport: "转发举报"
- updateAbuseReportNote: "更新举报用管理笔记"
- createInvitation: "生成邀请码"
+ createInvitation: "发行邀请码"
createAd: "创建了广告"
deleteAd: "删除了广告"
updateAd: "更新了广告"
@@ -2550,16 +2380,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "删除头像挂件"
unsetUserAvatar: "清除用户头像"
unsetUserBanner: "清除用户横幅"
- createSystemWebhook: "新建了 SystemWebhook"
- updateSystemWebhook: "更新了 SystemWebhook"
- deleteSystemWebhook: "删除了 SystemWebhook"
- createAbuseReportNotificationRecipient: "新建了举报通知"
- updateAbuseReportNotificationRecipient: "更新了举报通知"
- deleteAbuseReportNotificationRecipient: "删除了举报通知"
- deleteAccount: "删除了账户"
- deletePage: "删除了页面"
- deleteFlash: "删除了 Play"
- deleteGalleryPost: "删除了图库稿件"
_fileViewer:
title: "文件信息"
type: "文件类型"
@@ -2629,7 +2449,6 @@ _hemisphere:
_reversi:
reversi: "黑白棋"
gameSettings: "对局设置"
- chooseBoard: "选择棋盘"
blackOrWhite: "先手/后手"
blackIs: "{name}执黑(先手)"
rules: "规则"
@@ -2643,8 +2462,6 @@ _reversi:
myTurn: "你的回合"
turnOf: "{name}的回合"
pastTurnOf: "{name}的回合"
- surrender: "认输"
- surrendered: "已认输"
timeout: "超时"
drawn: "平局"
won: "{name}获胜"
@@ -2656,8 +2473,6 @@ _reversi:
allGames: "所有对局"
ended: "结束"
playing: "对局中"
- isLlotheo: "落子少的一方获胜(又名奥赛罗)"
- loopedMap: "循环棋盘"
canPutEverywhere: "无限制放置模式"
timeLimitForEachTurn: "1回合的时间限制"
freeMatch: "自由匹配"
@@ -2668,45 +2483,7 @@ _reversi:
opponentHasSettingsChanged: "对手更改了设定"
allowIrregularRules: "允许非常规规则(完全自由)"
disallowIrregularRules: "禁止非常规规则"
- showBoardLabels: "显示行号和列号"
- useAvatarAsStone: "用头像作为棋子"
_offlineScreen:
title: "离线——无法连接到服务器"
header: "无法连接到服务器"
-_urlPreviewSetting:
- title: "设置 URL 预览"
- enable: "启用 URL 预览"
- timeout: "超时阈值(ms)"
- timeoutDescription: "如果获取预览所用时间超过这个值,则不生成预览。"
- maximumContentLength: "Content-Length 的最大值(byte)"
- maximumContentLengthDescription: "如果 Content-Length 超过这个值,则不生成预览。"
- requireContentLength: "仅在能取得 Content-Length 时生成预览"
- requireContentLengthDescription: "如果目标服务器不返回 Content-Length,则不生成预览。"
- userAgent: "User-Agent"
- userAgentDescription: "设定获取预览时使用的 User-Agent。留空时将使用默认的 User-Agent。"
- summaryProxy: "用来生成预览的代理的 endpoint。"
- summaryProxyDescription: "不使用 Misskey 本体,而是通过 Summaly Proxy 生成预览。"
- summaryProxyDescription2: "下面的参数将作为查询字符串发送至代理。代理侧如果不支持此设置,则忽略设定值。"
-_mediaControls:
- pip: "画中画"
- playbackRate: "播放速度"
- loop: "循环播放"
-_contextMenu:
- title: "上下文菜单"
- app: "应用"
- appWithShift: "Shift 键应用"
- native: "浏览器的用户界面"
-_embedCodeGen:
- title: "自定义嵌入代码"
- header: "显示标题"
- autoload: "连续加载(不推荐)"
- maxHeight: "最大高度"
- maxHeightDescription: "若将最大值设为 0 则不限制最大高度。为防止小工具无限增高,建议设置一下。"
- maxHeightWarn: "最大高度限制已禁用(0)。若这不是您想要的效果,请将最大高度设一个值。"
- previewIsNotActual: "由于超出了预览画面可显示的范围,因此显示内容会与实际嵌入时有所不同。"
- rounded: "圆角"
- border: "外边框"
- applyToPreview: "应用预览"
- generateCode: "生成嵌入代码"
- codeGenerated: "已生成代码"
- codeGeneratedDescription: "将生成的代码贴到网站上来使用。"
+
diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml
index de18342bbf..2762a612f5 100644
--- a/locales/zh-TW.yml
+++ b/locales/zh-TW.yml
@@ -8,9 +8,6 @@ search: "搜尋"
notifications: "通知"
username: "使用者名稱"
password: "密碼"
-initialPasswordForSetup: "初始設定用的密碼"
-initialPasswordIsIncorrect: "初始設定用的密碼錯誤。"
-initialPasswordForSetupDescription: "如果您自己安裝了 Misskey,請使用您在設定檔中輸入的密碼。\n如果您使用 Misskey 的託管服務之類的服務,請使用提供的密碼。\n如果您尚未設定密碼,請將其留空並繼續。"
forgotPassword: "忘記密碼"
fetchingAsApObject: "從聯邦宇宙取得中..."
ok: "OK"
@@ -63,7 +60,6 @@ copyFileId: "複製檔案 ID"
copyFolderId: "複製資料夾ID"
copyProfileUrl: "複製個人資料網址"
searchUser: "搜尋使用者"
-searchThisUsersNotes: "搜尋這個使用者的貼文"
reply: "回覆"
loadMore: "載入更多"
showMore: "載入更多"
@@ -112,14 +108,11 @@ enterEmoji: "輸入表情符號"
renote: "轉發"
unrenote: "取消轉發"
renoted: "轉發成功。"
-renotedToX: "轉發給 {name} 了。"
cantRenote: "無法轉發此貼文。"
cantReRenote: "無法轉發之前已經轉發過的內容。"
quote: "引用"
inChannelRenote: "在頻道內轉發"
inChannelQuote: "在頻道內引用"
-renoteToChannel: "轉發至頻道"
-renoteToOtherChannel: "轉發至其他頻道"
pinnedNote: "已置頂的貼文"
pinned: "置頂"
you: "您"
@@ -158,7 +151,6 @@ editList: "編輯清單"
selectChannel: "選擇頻道"
selectAntenna: "選擇天線"
editAntenna: "編輯天線"
-createAntenna: "建立天線"
selectWidget: "選擇小工具"
editWidgets: "編輯小工具"
editWidgetsExit: "完成"
@@ -177,7 +169,7 @@ cacheRemoteSensitiveFilesDescription: "若停用這個設定,則不會快取
flagAsBot: "此使用者是機器人"
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整 Misskey 內部系統將本帳戶識別為機器人。"
flagAsCat: "此帳戶是一隻貓,喵~~~!!!"
-flagAsCatDescription: "喵喵喵??"
+flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示"
flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
flagShowTimelineRepliesDescription: "啟用後,時間軸除了顯示使用者的貼文以外,還會顯示使用者對其他貼文的回覆。"
autoAcceptFollowed: "自動允許來自追隨中使用者的追隨請求"
@@ -185,10 +177,6 @@ addAccount: "新增帳戶"
reloadAccountsList: "更新帳戶清單的資訊"
loginFailed: "登入失敗"
showOnRemote: "轉到所在實例顯示"
-continueOnRemote: "在遠端伺服器繼續"
-chooseServerOnMisskeyHub: "從 Misskey Hub 選擇伺服器"
-specifyServerHost: "直接指定伺服器網域"
-inputHostName: "請輸入域名"
general: "一般"
wallpaper: "桌布"
setWallpaper: "設定桌布"
@@ -199,7 +187,6 @@ followConfirm: "你真的要追隨{name}嗎?"
proxyAccount: "代理帳戶"
proxyAccountDescription: "代理帳戶是在特定條件下充當遠端追隨者的帳戶。例如,當使用者新增遠端使用者至其列表時,若沒有本地使用者追隨該遠端使用者,則其活動將不會傳送至伺服器,此時便會由代理帳戶代為追隨以解決問題。"
host: "主機"
-selectSelf: "選擇自己"
selectUser: "選取使用者"
recipient: "收件人"
annotation: "註解"
@@ -215,11 +202,10 @@ perDay: "每日"
stopActivityDelivery: "停止發送活動"
blockThisInstance: "封鎖此伺服器"
silenceThisInstance: "禁言此伺服器"
-mediaSilenceThisInstance: "將這個伺服器的媒體設為禁言"
operations: "操作"
software: "軟體"
version: "版本"
-metadata: "詮釋資料"
+metadata: "元資料"
withNFiles: "{n} 個檔案"
monitor: "監視器"
jobQueue: "佇列"
@@ -237,10 +223,6 @@ blockedInstances: "已封鎖的伺服器"
blockedInstancesDescription: "請逐行輸入需要封鎖的伺服器。已封鎖的伺服器將無法與本伺服器進行通訊。"
silencedInstances: "被禁言的伺服器"
silencedInstancesDescription: "設定要禁言的伺服器主機名稱,以換行分隔。隸屬於禁言伺服器的所有帳戶都將被視為「禁言帳戶」,只能發出「追隨請求」,而且無法提及未追隨的本地帳戶。這不會影響已封鎖的實例。"
-mediaSilencedInstances: "媒體被禁言的伺服器"
-mediaSilencedInstancesDescription: "設定您想要對媒體設定禁言的伺服器,以換行符號區隔。來自被媒體禁言的伺服器所屬帳戶的所有檔案都會被視為敏感檔案,且自訂表情符號不能使用。被封鎖的伺服器不受影響。"
-federationAllowedHosts: "允許聯邦通訊的伺服器"
-federationAllowedHostsDescription: "設定允許聯邦通訊的伺服器主機,以換行符號分隔。"
muteAndBlock: "靜音和封鎖"
mutedUsers: "被靜音的使用者"
blockedUsers: "被封鎖的使用者"
@@ -258,10 +240,10 @@ noCustomEmojis: "沒有自訂的表情符號"
noJobs: "沒有任務"
federating: "聯邦運作中"
blocked: "已封鎖"
-suspended: "停止發送"
+suspended: "已凍結"
all: "全部"
subscribing: "訂閱中"
-publishing: "發送中"
+publishing: "直播中"
notResponding: "沒有回應"
instanceFollowing: "追隨的伺服器"
instanceFollowers: "伺服器的追隨者"
@@ -331,7 +313,6 @@ selectFile: "選擇檔案"
selectFiles: "選擇檔案"
selectFolder: "選擇資料夾"
selectFolders: "選擇資料夾"
-fileNotSelected: "尚未選擇檔案"
renameFile: "重新命名檔案"
folderName: "資料夾名稱"
createFolder: "新增資料夾"
@@ -339,7 +320,6 @@ renameFolder: "重新命名資料夾"
deleteFolder: "刪除資料夾"
folder: "資料夾"
addFile: "加入附件"
-showFile: "瀏覽文件"
emptyDrive: "雲端硬碟為空"
emptyFolder: "資料夾為空"
unableToDelete: "無法刪除"
@@ -359,7 +339,7 @@ reload: "重新整理"
doNothing: "無視"
reloadConfirm: "確定要重新整理嗎?"
watch: "關注"
-unwatch: "取消關注"
+unwatch: "取消追隨"
accept: "接受"
reject: "拒絕"
normal: "正常"
@@ -386,7 +366,7 @@ enableRegistration: "開放新使用者註冊"
invite: "邀請"
driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
-inMb: "以 MB 為單位"
+inMb: "以Mbps為單位"
bannerUrl: "橫幅圖片URL"
backgroundImageUrl: "背景圖片的來源網址 "
basicInfo: "基本資訊"
@@ -398,12 +378,12 @@ pinnedClipId: "置頂的摘錄ID"
pinnedNotes: "已置頂的貼文"
hcaptcha: "hCaptcha"
enableHcaptcha: "啟用 hCaptcha"
-hcaptchaSiteKey: "hcaptchaSiteKey"
-hcaptchaSecretKey: "hcaptchaSecretKey"
+hcaptchaSiteKey: "網站金鑰"
+hcaptchaSecretKey: "金鑰"
mcaptcha: "mCaptcha"
enableMcaptcha: "啟用 mCaptcha"
mcaptchaSiteKey: "網站金鑰"
-mcaptchaSecretKey: "私密金鑰"
+mcaptchaSecretKey: "金鑰"
mcaptchaInstanceUrl: "mCaptcha 的實例網址"
recaptcha: "reCAPTCHA"
enableRecaptcha: "啟用 reCAPTCHA"
@@ -411,8 +391,8 @@ recaptchaSiteKey: "網站金鑰"
recaptchaSecretKey: "金鑰"
turnstile: "Turnstile"
enableTurnstile: "啟用 Turnstile"
-turnstileSiteKey: "turnstileSiteKey"
-turnstileSecretKey: "turnstileSecretKey"
+turnstileSiteKey: "網站金鑰"
+turnstileSecretKey: "金鑰"
avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要關閉其他驗證方式嗎?您可以按「取消」保留多種驗證方式。"
antennas: "天線"
manageAntennas: "管理天線"
@@ -420,7 +400,6 @@ name: "名稱"
antennaSource: "接收來源"
antennaKeywords: "包含關鍵字"
antennaExcludeKeywords: "排除關鍵字"
-antennaExcludeBots: "排除機器人帳戶"
antennaKeywordsDescription: "空格代表「以及」(AND),換行代表「或者」(OR)"
notifyAntenna: "通知有新貼文"
withFileAntenna: "僅帶有附件的貼文"
@@ -454,7 +433,6 @@ totpDescription: "以驗證應用程式輸入一次性密碼"
moderator: "審查員"
moderation: "審查"
moderationNote: "管理筆記"
-moderationNoteDescription: "您可以編寫僅在審查員之間共用的註解。"
addModerationNote: "新增管理筆記"
moderationLogs: "管理日誌"
nUsersMentioned: "被 {n} 個人提及"
@@ -485,16 +463,14 @@ title: "標題"
text: "文字"
enable: "啟用"
next: "下一步"
-retype: "重新輸入"
+retype: "再次輸入"
noteOf: "{user}的貼文"
quoteAttached: "引用"
quoteQuestion: "是否要引用?"
-attachAsFileQuestion: "剪貼簿的文字較長。請問是否要將其以文字檔的方式附加呢?"
noMessagesYet: "沒有訊息"
newMessageExists: "有新的訊息"
onlyOneFileCanBeAttached: "只能加入一個附件"
signinRequired: "請先登入"
-signinOrContinueOnRemote: "若要繼續,需前往您所在的伺服器,或者註冊並登入此伺服器"
invitations: "邀請"
invitationCode: "邀請碼"
checking: "確認中"
@@ -516,12 +492,8 @@ uiLanguage: "介面語言"
aboutX: "關於{x}"
emojiStyle: "表情符號的風格"
native: "原生"
-menuStyle: "選單風格"
-style: "風格"
-drawer: "側邊欄"
-popup: "彈出式視窗"
-showNoteActionsOnlyHover: "僅在游標停留時顯示貼文的"
-showReactionsCount: "顯示貼文的反應數目"
+disableDrawer: "不顯示下拉式選單"
+showNoteActionsOnlyHover: "僅在游標停留時顯示貼文的操作選項"
noHistory: "沒有歷史紀錄"
signinHistory: "登入歷史"
enableAdvancedMfm: "啟用進階 MFM"
@@ -602,8 +574,6 @@ ascendingOrder: "昇冪"
descendingOrder: "降冪"
scratchpad: "暫存記憶體"
scratchpadDescription: "AiScript 控制臺為 AiScript 的實驗環境。您可以在此編寫、執行和確認程式碼與 Misskey 互動的結果。"
-uiInspector: "UI 檢查"
-uiInspectorDescription: "您可以看到記憶體中存在的 UI 元件實例的清單。 UI 元件由 Ui:C: 系列函數產生。"
output: "輸出"
script: "腳本"
disablePagesScript: "停用頁面的 AiScript 腳本"
@@ -630,7 +600,7 @@ addItem: "新增項目"
rearrange: "排序方式"
relays: "中繼器"
addRelay: "新增中繼器"
-inboxUrl: "收件夾 URL"
+inboxUrl: "收件夾URL"
addedRelays: "已加入的中繼器"
serviceworkerInfo: "如要使用推播通知,需要啟用此選項並設定金鑰。"
deletedNote: "已刪除的貼文"
@@ -720,7 +690,10 @@ abuseReported: "檢舉完成。感謝您的報告。"
reporter: "檢舉者"
reporteeOrigin: "檢舉來源"
reporterOrigin: "檢舉者來源"
+forwardReport: "將報告轉送給遠端伺服器"
+forwardReportIsAnonymous: "在遠端實例上看不到您的資訊,顯示的報告者是匿名的系统帳戶。"
send: "發送"
+abuseMarkAsResolved: "處理完畢"
openInNewTab: "在新分頁中開啟"
openInSideView: "在側欄中開啟"
defaultNavigationBehaviour: "預設導航"
@@ -777,7 +750,7 @@ experimentalFeatures: "實驗中的功能"
experimental: "實驗性"
thisIsExperimentalFeature: "這是實驗性的功能。可能會有變更規格和不能正常動作的可能性。"
developer: "開發者"
-makeExplorable: "使自己的帳戶更容易被找到"
+makeExplorable: "使自己的帳戶能夠在「探索」頁面中顯示"
makeExplorableDescription: "如果關閉,帳戶將不會被顯示在「探索」頁面中。"
showGapBetweenNotesInTimeline: "分開顯示時間軸上的貼文"
duplicate: "複製"
@@ -816,7 +789,7 @@ newVersionOfClientAvailable: "新版本的客戶端可用。"
usageAmount: "使用量"
capacity: "容量"
inUse: "已使用"
-editCode: "編輯程式碼"
+editCode: "編輯代碼"
apply: "套用"
receiveAnnouncementFromInstance: "接收來自伺服器的通知"
emailNotification: "郵件通知"
@@ -857,7 +830,6 @@ administration: "管理"
accounts: "帳戶"
switch: "切換"
noMaintainerInformationWarning: "尚未設定管理員訊息。"
-noInquiryUrlWarning: "尚未設定聯絡表單網址。"
noBotProtectionWarning: "尚未設定 Bot 防護。"
configure: "設定"
postToGallery: "發佈到相簿"
@@ -922,7 +894,6 @@ followersVisibility: "追隨者的可見性"
continueThread: "查看更多貼文"
deleteAccountConfirm: "將要刪除帳戶。是否確定?"
incorrectPassword: "密碼錯誤。"
-incorrectTotp: "一次性密碼錯誤,或者已過期。"
voteConfirm: "確定投給「{choice}」?"
hide: "隱藏"
useDrawerReactionPickerForMobile: "在移動設備上使用抽屜顯示"
@@ -1019,8 +990,7 @@ show: "檢視"
neverShow: "不再顯示"
remindMeLater: "以後再說"
didYouLikeMisskey: "您喜歡 Misskey 嗎?"
-pleaseDonate: "Misskey是由{host}使用的免費軟體。請贊助我們,讓開發的工作能夠持續!"
-correspondingSourceIsAvailable: "對應的原始碼可以在 {anchor} 處找到。"
+pleaseDonate: "Misskey 是由 {host} 使用的免費軟體。請贊助我們,讓開發得以持續!"
roles: "角色"
role: "角色"
noRole: "沒有角色"
@@ -1048,7 +1018,6 @@ thisPostMayBeAnnoyingHome: "發佈到首頁"
thisPostMayBeAnnoyingCancel: "退出"
thisPostMayBeAnnoyingIgnore: "直接發佈貼文"
collapseRenotes: "省略顯示已看過的轉發貼文"
-collapseRenotesDescription: "將已做過反應和轉發的貼文折疊顯示。"
internalServerError: "內部伺服器錯誤"
internalServerErrorDescription: "內部伺服器出現意外錯誤。"
copyErrorInfo: "複製錯誤資訊"
@@ -1087,11 +1056,10 @@ retryAllQueuesConfirmTitle: "要現在重試嗎?"
retryAllQueuesConfirmText: "伺服器的負荷可能會暫時增加。"
enableChartsForRemoteUser: "生成遠端使用者的圖表"
enableChartsForFederatedInstances: "生成遠端伺服器的圖表"
-enableStatsForFederatedInstances: "取得遠端伺服器資訊"
showClipButtonInNoteFooter: "新增摘錄按鈕至貼文"
reactionsDisplaySize: "反應的顯示尺寸"
limitWidthOfReaction: "限制反應的最大寬度,並縮小顯示尺寸。"
-noteIdOrUrl: "貼文 ID 或 URL"
+noteIdOrUrl: "貼文ID或URL"
video: "影片"
videos: "影片"
audio: "音效"
@@ -1106,7 +1074,7 @@ addMemo: "新增備註"
editMemo: "編輯備註"
reactionsList: "反應列表"
renotesList: "轉發貼文列表"
-notificationDisplay: "通知"
+notificationDisplay: "通知的顯示"
leftTop: "左上"
rightTop: "右上"
leftBottom: "左下"
@@ -1123,8 +1091,6 @@ preservedUsernames: "保留的使用者名稱"
preservedUsernamesDescription: "換行列舉要保留的使用者名稱。此處出現的名稱將在註冊時禁用,但由管理者建立帳戶則不受此限。此外,既有的帳戶也不受影響。"
createNoteFromTheFile: "由此檔案建立貼文"
archive: "封存"
-archived: "已封存"
-unarchive: "取消封存"
channelArchiveConfirmTitle: "要封存{name}嗎?"
channelArchiveConfirmDescription: "封存後,將不會在頻道列表與搜尋結果中顯示,也無法發佈新貼文。"
thisChannelArchived: "這個頻道已被封存。"
@@ -1135,9 +1101,6 @@ preventAiLearning: "拒絕接受生成式AI的訓練"
preventAiLearningDescription: "要求站外生成式 AI 不使用您發佈的內容訓練模型。此功能會使伺服器於 HTML 回應新增「noai」標籤,而因為要視乎 AI 會否遵守該標籤,所以此功能無法完全阻止所有 AI 使用您的內容。"
options: "選項"
specifyUser: "指定使用者"
-lookupConfirm: "要查詢嗎?"
-openTagPageConfirm: "要開啟標籤的頁面嗎?"
-specifyHost: "指定主機"
failedToPreviewUrl: "無法預覽"
update: "更新"
rolesThatCanBeUsedThisEmojiAsReaction: "可以使用此表情符號為反應的角色"
@@ -1196,8 +1159,7 @@ showRenotes: "顯示其他人的轉發貼文"
edited: "已編輯"
notificationRecieveConfig: "接受通知的設定"
mutualFollow: "互相追隨"
-followingOrFollower: "追隨中或者追隨者"
-fileAttachedOnly: "只顯示包含附件的貼文"
+fileAttachedOnly: "顯示包含附件的貼文"
showRepliesToOthersInTimeline: "顯示給其他人的回覆"
hideRepliesToOthersInTimeline: "在時間軸上隱藏給其他人的回覆"
showRepliesToOthersInTimelineAll: "在時間軸包含追隨中所有人的回覆"
@@ -1206,22 +1168,16 @@ confirmShowRepliesAll: "進行此操作後無法復原。您真的希望時間
confirmHideRepliesAll: "進行此操作後無法復原。您真的希望時間軸「不包含」您目前追隨的所有人的回覆嗎?"
externalServices: "外部服務"
sourceCode: "原始碼"
-sourceCodeIsNotYetProvided: "尚未提供原始碼,請洽詢管理員解決這個問題。"
-repositoryUrl: "儲存庫 URL"
-repositoryUrlDescription: "如果存在可公開取得原始碼的儲存庫,請輸入其 URL。 如果您按原樣使用 Misskey(不對原始碼進行任何更改),請輸入 https://github.com/misskey-dev/misskey。"
-repositoryUrlOrTarballRequired: "如果儲存庫不是公開的,則必須提供 tarball。 詳細資訊請參閱 .config/example.yml。"
-feedback: "意見回饋"
-feedbackUrl: "意見回饋 URL"
impressum: "營運者資訊"
-impressumUrl: "營運者資訊 URL"
+impressumUrl: "營運者資訊網址"
impressumDescription: "在德國與部份地區必須要明確顯示營運者資訊。"
privacyPolicy: "隱私政策"
-privacyPolicyUrl: "隱私政策 URL"
+privacyPolicyUrl: "隱私政策網址"
tosAndPrivacyPolicy: "服務條款和隱私政策"
avatarDecorations: "頭像裝飾"
attach: "裝上"
detach: "取下"
-detachAll: "全部移除"
+detachAll: "移除所有裝飾"
angle: "角度"
flip: "翻轉"
showAvatarDecorations: "顯示頭像裝飾"
@@ -1239,7 +1195,7 @@ remainingN: "剩餘:{n}"
overwriteContentConfirm: "確定要覆蓋目前的內容嗎?"
seasonalScreenEffect: "隨季節變換畫面的呈現"
decorate: "設置頭像裝飾"
-addMfmFunction: "插入 MFM 功能語法"
+addMfmFunction: "插入MFM功能語法"
enableQuickAddMfmFunction: "顯示高級 MFM 選擇器"
bubbleGame: "氣泡遊戲"
sfx: "音效"
@@ -1247,8 +1203,6 @@ soundWillBePlayed: "將播放音效"
showReplay: "觀看重播"
replay: "重播"
replaying: "重播中"
-endReplay: "退出重播"
-copyReplayData: "複製重播資料"
ranking: "排行榜"
lastNDays: "過去 {n} 天"
backToTitle: "回到遊戲標題頁"
@@ -1256,70 +1210,8 @@ hemisphere: "您居住的地區"
withSensitive: "顯示包含敏感檔案的貼文"
userSaysSomethingSensitive: "包含 {name} 敏感檔案的貼文"
enableHorizontalSwipe: "滑動切換時間軸"
-loading: "載入中"
-surrender: "退出"
-gameRetry: "再試一次"
-notUsePleaseLeaveBlank: "如果不使用的話請留白"
-useTotp: "使用一次性密碼"
-useBackupCode: "使用備用驗證碼"
-launchApp: "啟動 APP"
-useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊"
-keepOriginalFilename: "保留原始檔名"
-keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。"
-noDescription: "沒有說明文字"
-alwaysConfirmFollow: "跟隨時總是確認"
-inquiry: "聯絡我們"
-tryAgain: "請再試一次。"
-confirmWhenRevealingSensitiveMedia: "要顯示敏感媒體時需確認"
-sensitiveMediaRevealConfirm: "這是敏感媒體。確定要顯示嗎?"
-createdLists: "已建立的清單"
-createdAntennas: "已建立的天線"
-fromX: "自 {x}"
-genEmbedCode: "產生嵌入程式碼"
-noteOfThisUser: "這個使用者的貼文列表"
-clipNoteLimitExceeded: "沒辦法在這個摘錄中增加更多貼文了。"
-performance: "性能"
-modified: "已變更"
-discard: "取消"
-thereAreNChanges: "有 {n} 處的變更"
-signinWithPasskey: "使用密碼金鑰登入"
-unknownWebAuthnKey: "未註冊的金鑰。"
-passkeyVerificationFailed: "驗證金鑰失敗。"
-passkeyVerificationSucceededButPasswordlessLoginDisabled: "雖然驗證金鑰成功,但是無密碼登入的方式是停用的。"
-messageToFollower: "給追隨者的訊息"
-target: "目標 "
-testCaptchaWarning: "此功能用於 CAPTCHA 的測試。請勿在正式環境中使用。 "
-prohibitedWordsForNameOfUser: "禁止使用的字詞(使用者名稱)"
-prohibitedWordsForNameOfUserDescription: "如果使用者名稱包含此清單中的任何字串,則拒絕重新命名使用者。 具有審查員權限的使用者不受此限制的影響。"
-yourNameContainsProhibitedWords: "您嘗試更改的名稱包含禁止的字串"
-yourNameContainsProhibitedWordsDescription: "名稱中包含禁止使用的字串。 如果您想使用此名稱,請聯絡您的伺服器管理員。"
-_abuseUserReport:
- forward: "轉發"
- forwardDescription: "以匿名系統帳戶將檢舉轉發至遠端伺服器。"
- resolve: "解決"
- accept: "接受"
- reject: "拒絕"
- resolveTutorial: "如果您已回覆正當的檢舉,請選擇「接受」以將案件標記為已解決。\n 如果檢舉的內容不正當,請選擇「拒絕」將案件標記為已解決。"
-_delivery:
- status: "傳送狀態"
- stop: "停止發送"
- resume: "恢復發送"
- _type:
- none: "發送中"
- manuallySuspended: "手動暫停中"
- goneSuspended: "因為伺服器刪除所以暫停中"
- autoSuspendedForNotResponding: "因為伺服器沒有回應所以暫停中"
_bubbleGame:
howToPlay: "玩法說明"
- hold: "保留"
- _score:
- score: "分數"
- scoreYen: "賺取的金額"
- highScore: "最高分"
- maxChain: "最大結合數"
- yen: "{yen}円"
- estimatedQty: "{qty}個"
- scoreSweets: "飯糰 {onigiriQtyWithUnit}"
_howToPlay:
section1: "調整位置並將物體放入盒子中。"
section2: "當相同類型的物體黏在一起時,它們會變成不同的物體,您就會得到分數。"
@@ -1345,7 +1237,7 @@ _initialAccountSetting:
privacySetting: "隱私設定"
theseSettingsCanEditLater: "這裡的設定可以在之後變更。"
youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。"
- followUsers: "為了構築時間軸,試著追隨您感興趣的使用者吧。"
+ followUsers: "為了構築時間軸,試著追蹤您感興趣的使用者吧。"
pushNotificationDescription: "啟用推送通知,就可以在設備上接收{name}的通知。"
initialAccountSettingCompleted: "初始設定完成了!"
haveFun: "盡情享受{name}吧!"
@@ -1400,7 +1292,7 @@ _initialTutorial:
title: "隱藏內容(CW)"
description: "將顯示「註釋」中寫入的內容而不是本文。按一下「顯示內容」以顯示本文。"
_exampleNote:
- cw: "注意消夜文"
+ cw: "美食恐怖主義注意"
note: "我吃了一個巧克力甜甜圈🍩😋"
useCases: "伺服器的服務條款可能會規範特定的貼文需要使用隱藏內容,除此之外也會用在隱藏劇情洩漏與敏感內容的貼文。"
_howToMakeAttachmentsSensitive:
@@ -1425,7 +1317,7 @@ _serverRules:
_serverSettings:
iconUrl: "圖示的 URL"
appIconDescription: "指定顯示 {host} 為應用程式時的圖示。"
- appIconUsageExample: "例如:PWA 或是在手機桌面作為書籤等"
+ appIconUsageExample: "例如:漸進式網路應用程式(PWA)、於手機桌面新增書籤"
appIconStyleRecommendation: "因為可能會裁剪成圓形或圓角,所以建議用單色填滿邊框及背景。"
appIconResolutionMustBe: "解析度必須為 {resolution}。"
manifestJsonOverride: "覆寫 manifest.json"
@@ -1434,14 +1326,10 @@ _serverSettings:
fanoutTimelineDescription: "如果啟用的話,檢索各個時間軸的性能會顯著提昇,資料庫的負荷也會減少。不過,Redis 的記憶體使用量會增加。如果伺服器的記憶體容量比較少或者運行不穩定,可以停用。"
fanoutTimelineDbFallback: "資料庫的回退"
fanoutTimelineDbFallbackDescription: "若啟用,在時間軸沒有快取的情況下將執行回退處理以額外查詢資料庫。若停用,可以透過不執行回退處理來進一步減少伺服器的負荷,但會限制可取得的時間軸範圍。"
- reactionsBufferingDescription: "啟用時,可以顯著提高建立反應時的效能並減少資料庫的負載。 但是,Redis 記憶體使用量會增加。"
- inquiryUrl: "聯絡表單網址"
- inquiryUrlDescription: "指定伺服器運營者的聯絡表單網址,或包含運營者聯絡資訊網頁的網址。"
- thisSettingWillAutomaticallyOffWhenModeratorsInactive: "為了防止 spam,如果一段期間內沒有偵測到審查員的活動,此設定將自動關閉。"
_accountMigration:
moveFrom: "從其他帳戶遷移到這個帳戶"
moveFromSub: "為另一個帳戶建立別名"
- moveFromLabel: "要遷移過來的帳戶 #{n}"
+ moveFromLabel: "要遷移過來的帳戶:"
moveFromDescription: "如果你想把追隨者從別的帳戶遷移過來,必須先在這裡建立別名。請務必在執行遷移之前建立別名!請像這樣輸入要遷移的帳戶:@person@instance.com"
moveTo: "將這個帳戶遷移至新的帳戶"
moveToLabel: "要遷移到的帳戶:"
@@ -1451,7 +1339,7 @@ _accountMigration:
startMigration: "遷移"
migrationConfirm: "確定要將這個帳戶遷移至 {account} 嗎?一旦遷移就無法撤銷,也就無法以原來的狀態使用這個帳戶。\n另外,請確認在要遷移到的帳戶已經建立了一個別名。"
movedAndCannotBeUndone: "帳戶已遷移。\n遷移無法撤消。"
- postMigrationNote: "取消追蹤此帳戶將在遷移操作後 24 小時執行。\n 此帳戶有 0 個關注者/關注者。 您的關注者仍然可以看到此帳戶的關注者帖子,因為您不會被取消關注。"
+ postMigrationNote: "在完成遷移的 24 小時後解除此帳戶的追隨。此帳戶的追隨中、追隨者數量變為 0。由於不會解除追隨者,你的追隨者仍然可以繼續檢視這個帳戶發布給追隨者的貼文。"
movedTo: "要遷移到的帳戶:"
_achievements:
earnedAt: "獲得日期"
@@ -1571,7 +1459,7 @@ _achievements:
_markedAsCat:
title: "我是貓"
description: "已將帳戶設定為貓"
- flavor: "沒有名字。"
+ flavor: "還沒有名字。"
_following1:
title: "首次追隨"
description: "首次追隨了"
@@ -1585,7 +1473,7 @@ _achievements:
title: "一百位朋友"
description: "追隨超過100人了"
_following300:
- title: "朋友太多"
+ title: "朋友過多"
description: "追隨超過300人了"
_followers1:
title: "第一個追隨者"
@@ -1637,7 +1525,7 @@ _achievements:
_postedAt0min0sec:
title: "報時"
description: "在零分零秒發佈貼文"
- flavor: "啵.啵.啵.嗶ー"
+ flavor: "啵、啵、啵、嗶ーー"
_selfQuote:
title: "自我引用"
description: "引用了自己的貼文"
@@ -1727,7 +1615,7 @@ _role:
baseRole: "基本角色"
useBaseValue: "使用基本角色的值"
chooseRoleToAssign: "選擇要指派的角色"
- iconUrl: "圖示的 URL"
+ iconUrl: "圖示的URL"
asBadge: "顯示為徽章"
descriptionOfAsBadge: "開啟的話,角色圖示會顯示在使用者名稱旁邊。"
isExplorable: "讓使用者更容易找到您"
@@ -1745,7 +1633,6 @@ _role:
gtlAvailable: "瀏覽全域時間軸"
ltlAvailable: "瀏覽本地時間軸"
canPublicNote: "允許公開貼文"
- mentionMax: "貼文內的最大提及數"
canInvite: "發行伺服器邀請碼"
inviteLimit: "可建立邀請碼的數量"
inviteLimitCycle: "邀請碼的發放間隔"
@@ -1754,7 +1641,6 @@ _role:
canManageAvatarDecorations: "管理頭像裝飾"
driveCapacity: "雲端硬碟容量"
alwaysMarkNsfw: "總是將檔案標記為NSFW"
- canUpdateBioMedia: "允許更新大頭貼和橫幅"
pinMax: "置頂貼文的最大數量"
antennaMax: "可建立的天線數量"
wordMuteMax: "靜音文字的最大字數"
@@ -1769,20 +1655,9 @@ _role:
canSearchNotes: "可否搜尋貼文"
canUseTranslator: "使用翻譯功能"
avatarDecorationLimit: "頭像裝飾的最大設置量"
- canImportAntennas: "允許匯入天線"
- canImportBlocking: "允許匯入封鎖名單"
- canImportFollowing: "允許匯入跟隨名單"
- canImportMuting: "允許匯入靜音名單"
- canImportUserLists: "允許匯入清單"
_condition:
- roleAssignedTo: "手動指派角色完成"
isLocal: "本地使用者"
isRemote: "遠端使用者"
- isCat: "貓使用者"
- isBot: "機器人使用者"
- isSuspended: "被停權的使用者"
- isLocked: "上鎖的使用者"
- isExplorable: "開啟了「使您的帳戶更容易被找到」功能的使用者"
createdLessThan: "帳戶加入時間不超過"
createdMoreThan: "帳戶加入時間已超過"
followersLessThanOrEq: "追隨者人數在~以下"
@@ -1852,7 +1727,6 @@ _plugin:
installWarn: "請不要安裝來源不明的外掛。"
manage: "管理外掛"
viewSource: "檢視原始碼"
- viewLog: "顯示記錄 "
_preferencesBackups:
list: "已備份的設定檔"
saveNew: "另存新檔"
@@ -1882,8 +1756,6 @@ _aboutMisskey:
contributors: "主要貢獻者"
allContributors: "全體貢獻人員"
source: "原始碼"
- original: "原始"
- thisIsModifiedVersion: "{name} 使用原始 Misskey 的修改版本。"
translation: "翻譯 Misskey"
donate: "贊助 Misskey"
morePatrons: "還有許許多多幫助我們的其他人,非常感謝你們。 🥰"
@@ -1911,7 +1783,7 @@ _channel:
following: "追隨中"
usersCount: "有 {n} 人參與"
notesCount: "有 {n} 篇貼文"
- nameAndDescription: "名稱"
+ nameAndDescription: "名稱與說明"
nameOnly: "僅名稱"
allowRenoteToExternal: "允許在頻道外轉發和引用"
_menuDisplay:
@@ -1941,7 +1813,7 @@ _theme:
invalid: "佈景主題格式錯誤"
make: "製作佈景主題"
base: "基於"
- addConstant: "新增常數"
+ addConstant: "添加常數"
constant: "常數"
defaultValue: "預設值"
color: "顏色"
@@ -1991,6 +1863,7 @@ _theme:
buttonBg: "按鈕背景"
buttonHoverBg: "按鈕背景 (漂浮)"
inputBorder: "輸入框邊框"
+ listItemHoverBg: "列表物品背景 (漂浮)"
driveFolderBg: "雲端硬碟文件夾背景"
wallpaperOverlay: "壁紙覆蓋層"
badge: "徽章"
@@ -2002,6 +1875,8 @@ _sfx:
note: "貼文"
noteMy: "我的貼文"
notification: "通知"
+ antenna: "天線接收"
+ channel: "頻道通知"
reaction: "選擇反應時"
_soundSettings:
driveFile: "使用雲端硬碟的音效檔案"
@@ -2010,26 +1885,25 @@ _soundSettings:
driveFileTypeWarnDescription: "請選擇音效檔案"
driveFileDurationWarn: "音效太長了"
driveFileDurationWarnDescription: "使用長音效檔可能會影響 Misskey 的使用體驗。仍要使用此檔案嗎?"
- driveFileError: "無法載入語音。請變更設定"
_ago:
future: "未來"
justNow: "剛剛"
- secondsAgo: "{n}秒前"
- minutesAgo: "{n}分鐘前"
- hoursAgo: "{n}小時前"
- daysAgo: "{n}天前"
- weeksAgo: "{n}周前"
- monthsAgo: "{n}個月前"
- yearsAgo: "{n}年前"
+ secondsAgo: "{n} 秒前"
+ minutesAgo: "{n} 分鐘前 "
+ hoursAgo: "{n} 小時前"
+ daysAgo: "{n} 天前"
+ weeksAgo: "{n} 週前"
+ monthsAgo: "{n} 個月前"
+ yearsAgo: "{n} 年前"
invalid: "無"
_timeIn:
- seconds: "{n}秒後"
- minutes: "{n}分鐘後"
- hours: "{n}小時後"
- days: "{n}天後"
- weeks: "{n}周後"
- months: "{n}個月後"
- years: "{n}年後"
+ seconds: "{n} 秒後"
+ minutes: "{n} 分後"
+ hours: "{n} 小時後"
+ days: "{n} 日後"
+ weeks: "{n} 週後"
+ months: "{n} 個月後"
+ years: "{n} 年後"
_time:
second: "秒"
minute: "分鐘"
@@ -2040,6 +1914,7 @@ _2fa:
registerTOTP: "開始設定驗證應用程式"
step1: "首先,在您的裝置上安裝驗證程式,例如 {a} 或 {b}。"
step2: "然後,掃描螢幕上的 QR 碼。"
+ step2Click: "您可以點擊 QR 碼,以使用裝置上的驗證應用程式或金鑰環註冊。"
step2Uri: "使用桌面版應用程式時,請輸入以下的 URI"
step3Title: "輸入驗證碼"
step3: "輸入應用程式所提供的權杖以完成設定。"
@@ -2063,7 +1938,6 @@ _2fa:
backupCodesDescription: "如果驗證應用程式不能用了,可以使用以下的備用驗證碼存取您的帳戶。請務必妥善保管這個驗證碼。每個驗證碼只能使用一次。"
backupCodeUsedWarning: "已使用備用驗證碼。如果無法使用驗證應用程式,請盡快重新設定。"
backupCodesExhaustedWarning: "已使用所有備用驗證碼。如果無法使用驗證應用程式,則將無法再存取您的帳戶。請重新設定您的驗證應用程式。"
- moreDetailedGuideHere: "請點擊此處查看詳細說明。"
_permissions:
"read:account": "查看我的帳戶資訊"
"write:account": "更改我的帳戶資訊"
@@ -2107,18 +1981,19 @@ _permissions:
"read:admin:index-stats": "查看資料庫索引的相關資訊"
"read:admin:table-stats": "查看資料庫表格的相關資訊"
"read:admin:user-ips": "查看使用者的 IP 位址"
- "read:admin:meta": "查看實例的詮釋資料"
+ "read:admin:meta": "查看實例的元資料"
"write:admin:reset-password": "重設使用者的密碼"
"write:admin:resolve-abuse-user-report": "解決來自使用者的檢舉"
"write:admin:send-email": "發送郵件"
"read:admin:server-info": "查看伺服器的資訊"
"read:admin:show-moderation-log": "查看審查紀錄"
"read:admin:show-user": "查看使用者的私密資訊"
+ "read:admin:show-users": "查看使用者的私密資訊"
"write:admin:suspend-user": "凍結使用者"
"write:admin:unset-user-avatar": "刪除使用者的頭像"
"write:admin:unset-user-banner": "刪除使用者的橫幅"
"write:admin:unsuspend-user": "解除凍結使用者"
- "write:admin:meta": "編輯實例的詮釋資料"
+ "write:admin:meta": "編輯實例的元資料"
"write:admin:user-note": "編輯審查筆記"
"write:admin:roles": "編輯角色"
"read:admin:roles": "查看角色"
@@ -2166,13 +2041,13 @@ _antennaSources:
userList: "來自特定清單中的貼文"
userBlacklist: "除指定使用者外的所有貼文"
_weekday:
- sunday: "星期天"
- monday: "星期一"
- tuesday: "星期二"
- wednesday: "星期三"
- thursday: "星期四"
- friday: "星期五"
- saturday: "星期六"
+ sunday: "週日"
+ monday: "週一"
+ tuesday: "週二"
+ wednesday: "週三"
+ thursday: "週四"
+ friday: "週五"
+ saturday: "週六"
_widgets:
profile: "個人檔案"
instanceInfo: "伺服器資訊"
@@ -2221,7 +2096,7 @@ _poll:
deadlineDate: "截止日期"
deadlineTime: "小時"
duration: "時長"
- votesCount: "{n}票"
+ votesCount: "{n} 票"
totalVotes: "合計 {n} 票"
vote: "投票"
showResult: "顯示結果"
@@ -2254,7 +2129,7 @@ _postForm:
e: "寫些什麼吧……"
f: "靜待發文……"
_profile:
- name: "名字"
+ name: "名稱"
username: "使用者名稱"
description: "關於我"
youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag"
@@ -2267,9 +2142,6 @@ _profile:
changeBanner: "變更橫幅圖像"
verifiedLinkDescription: "如果輸入包含您個人資料的網站 URL,欄位旁邊將出現驗證圖示。"
avatarDecorationMax: "最多可以設置 {max} 個裝飾。"
- followedMessage: "被追隨時的訊息"
- followedMessageDescription: "可以設定被追隨時顯示給對方的訊息。"
- followedMessageDescriptionForLockedAccount: "如果追隨是需要審核的話,在允許追隨請求之後顯示。"
_exportOrImport:
allNotes: "所有貼文"
favoritedNotes: "「我的最愛」貼文"
@@ -2285,12 +2157,12 @@ _charts:
federation: "聯邦宇宙"
apRequest: "請求"
usersIncDec: "使用者增減"
- usersTotal: "使用者合計"
+ usersTotal: "使用者總數"
activeUsers: "活躍使用者"
notesIncDec: "貼文増減"
localNotesIncDec: "本地貼文増減"
remoteNotesIncDec: "遠端貼文數目增减"
- notesTotal: "貼文總數"
+ notesTotal: "貼文合共"
filesIncDec: "檔案增減"
filesTotal: "檔案總數"
storageUsageIncDec: "儲存空間增減"
@@ -2315,10 +2187,10 @@ _timelines:
_play:
new: "新增 Play"
edit: "編輯 Play"
- created: "已新增 Play "
- updated: "已更新 Play "
+ created: "已新增Play "
+ updated: "已更新Play "
deleted: "已刪除 Play"
- pageSetting: "Play 設定"
+ pageSetting: "Play設定"
editThisPage: "編輯此 Play"
viewSource: "檢視原始碼"
my: "自己的 Play"
@@ -2327,11 +2199,10 @@ _play:
title: "標題"
script: "腳本"
summary: "描述"
- visibilityDescription: "如果您將其設為私密,它將不再顯示在您的個人資料中,但知道該 URL 的人仍然可以存取它。"
_pages:
newPage: "建立頁面"
editPage: "編輯頁面"
- readPage: "正在檢視原始碼"
+ readPage: "正檢視原始碼"
created: "頁面已建立"
updated: "頁面已更新"
deleted: "頁面已被刪除"
@@ -2358,11 +2229,10 @@ _pages:
hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
font: "字型"
fontSerif: "襯線體"
- fontSansSerif: "黑體"
+ fontSansSerif: "無襯線體"
eyeCatchingImageSet: "設定封面影像"
eyeCatchingImageRemove: "刪除封面影像"
chooseBlock: "新增方塊"
- enterSectionTitle: "輸入區段的標題"
selectType: "選擇類型"
contentBlocks: "內容"
inputBlocks: "輸入"
@@ -2373,8 +2243,6 @@ _pages:
section: "區段"
image: "圖片"
button: "按鈕"
- dynamic: "動態方塊"
- dynamicDescription: "這個方塊已經廢止,現在開始請使用 {play}。"
note: "嵌式貼文"
_note:
id: "貼文ID"
@@ -2404,12 +2272,8 @@ _notification:
sendTestNotification: "發送測試通知"
notificationWillBeDisplayedLikeThis: "通知會以這樣的方式顯示"
reactedBySomeUsers: "{n}人做出了反應"
- likedBySomeUsers: "{n} 人按了讚"
renotedBySomeUsers: "{n}人做了轉發"
followedBySomeUsers: "被{n}人追隨了"
- flushNotification: "重置通知歷史紀錄"
- exportOfXCompleted: "{x} 的匯出已完成。"
- login: "已登入"
_types:
all: "全部 "
note: "使用者的最新貼文"
@@ -2424,9 +2288,6 @@ _notification:
followRequestAccepted: "追隨請求已接受"
roleAssigned: "已授予角色"
achievementEarned: "獲得成就"
- exportCompleted: "已完成匯出。"
- login: "登入"
- test: "通知測試"
app: "應用程式通知"
_actions:
followBack: "追隨回去"
@@ -2436,7 +2297,6 @@ _deck:
alwaysShowMainColumn: "總是顯示主欄"
columnAlign: "對齊欄位"
addColumn: "新增欄位"
- newNoteNotificationSettings: "新貼文通知的設定"
configureColumn: "欄位的設定"
swapLeft: "向左移動"
swapRight: "向右移動"
@@ -2475,10 +2335,9 @@ _drivecleaner:
orderByCreatedAtAsc: "按新增日期降序排列"
_webhookSettings:
createWebhook: "建立 Webhook"
- modifyWebhook: "編輯 Webhook"
- name: "名字"
+ name: "名稱"
secret: "密鑰"
- trigger: "觸發器"
+ events: "何時運行 Webhook"
active: "已啟用"
_events:
follow: "當你追隨時"
@@ -2488,29 +2347,6 @@ _webhookSettings:
renote: "當被轉發時"
reaction: "當獲得反應時"
mention: "當被提到時"
- _systemEvents:
- abuseReport: "當使用者檢舉時"
- abuseReportResolved: "當處理了使用者的檢舉時"
- userCreated: "使用者被新增時"
- inactiveModeratorsWarning: "當審查員在一段時間內沒有活動時"
- inactiveModeratorsInvitationOnlyChanged: "當審查員在一段時間內不活動時,系統會將模式變更為邀請制"
- deleteConfirm: "請問是否要刪除 Webhook?"
- testRemarks: "按下切換開關右側的按鈕,就會將假資料發送至 Webhook。"
-_abuseReport:
- _notificationRecipient:
- createRecipient: "新增接收檢舉的通知對象"
- modifyRecipient: "編輯接收檢舉的通知對象"
- recipientType: "通知對象的種類"
- _recipientType:
- mail: "電子郵件"
- webhook: "Webhook"
- _captions:
- mail: "寄送到擁有監察員權限的使用者電子郵件地址(僅在收到檢舉時)"
- webhook: "向指定的 SystemWebhook 發送通知(在收到檢舉和解決檢舉時發送)"
- keywords: "關鍵字"
- notifiedUser: "通知的使用者"
- notifiedWebhook: "使用的 Webhook"
- deleteConfirm: "確定要刪除通知對象嗎?"
_moderationLogTypes:
createRole: "新增角色"
deleteRole: "刪除角色 "
@@ -2523,7 +2359,7 @@ _moderationLogTypes:
updateCustomEmoji: "更新自訂表情符號"
deleteCustomEmoji: "刪除自訂表情符號"
updateServerSettings: "更新伺服器設定"
- updateUserNote: "更新了使用者的管理筆記"
+ updateUserNote: "更新管理筆記"
deleteDriveFile: "刪除檔案"
deleteNote: "刪除貼文"
createGlobalAnnouncement: "建立全網通知"
@@ -2535,12 +2371,9 @@ _moderationLogTypes:
resetPassword: "重設密碼"
suspendRemoteInstance: "封鎖遠端伺服器"
unsuspendRemoteInstance: "解除封鎖遠端伺服器"
- updateRemoteInstanceNote: "更新了遠端伺服器的管理筆記"
markSensitiveDriveFile: "標記為敏感檔案"
unmarkSensitiveDriveFile: "撤銷標記為敏感檔案"
resolveAbuseReport: "解決檢舉"
- forwardAbuseReport: "轉發檢舉"
- updateAbuseReportNote: "更新檢舉的審查備註"
createInvitation: "建立邀請碼"
createAd: "建立廣告"
deleteAd: "刪除廣告"
@@ -2550,16 +2383,6 @@ _moderationLogTypes:
deleteAvatarDecoration: "刪除頭像裝飾"
unsetUserAvatar: "移除使用者的大頭貼"
unsetUserBanner: "移除使用者的橫幅圖像"
- createSystemWebhook: "建立 SystemWebhook"
- updateSystemWebhook: "更新 SystemWebhook"
- deleteSystemWebhook: "刪除 SystemWebhook"
- createAbuseReportNotificationRecipient: "建立接收檢舉的通知對象"
- updateAbuseReportNotificationRecipient: "更新接收檢舉的通知對象"
- deleteAbuseReportNotificationRecipient: "刪除接收檢舉的通知對象"
- deleteAccount: "刪除帳戶"
- deletePage: "刪除頁面"
- deleteFlash: "刪除 Play"
- deleteGalleryPost: "刪除相簿的貼文"
_fileViewer:
title: "檔案詳細資訊"
type: "檔案類型 "
@@ -2668,45 +2491,7 @@ _reversi:
opponentHasSettingsChanged: "對手更改了設定"
allowIrregularRules: "允許異常規則(完全自由)"
disallowIrregularRules: "不允許異常規則"
- showBoardLabels: "在棋盤上顯示行、列號"
- useAvatarAsStone: "用大頭貼當作棋子"
_offlineScreen:
title: "離線-無法連接伺服器"
header: "無法連接伺服器"
-_urlPreviewSetting:
- title: "URL 預覽設定"
- enable: "啟用 URL 預覽"
- timeout: "取得預覽的逾時時間 (ms)"
- timeoutDescription: "若取得預覽所需的時間超過這個值,則不會產生預覽。"
- maximumContentLength: "Content-Length 的最大値 (byte)"
- maximumContentLengthDescription: "若 Content-Length 超過這個值,則不會產生預覽。"
- requireContentLength: "僅在能夠取得 Content-Length 時,才產生預覽。"
- requireContentLengthDescription: "若對方的伺服器未回傳 Content -Length,則不會產生預覽。"
- userAgent: "User-Agent"
- userAgentDescription: "設定獲取預覽時使用的 User-Agent 。如果留空,將使用預設的 User-Agent 。"
- summaryProxy: "產生預覽的代理端點"
- summaryProxyDescription: "使用摘要代理程式而不是 Misskey 本身產生預覽。"
- summaryProxyDescription2: "以下參數會作為查詢字串連結到代理。如果代理端不支援,這些設定將被忽略。"
-_mediaControls:
- pip: "畫中畫"
- playbackRate: "播放速度"
- loop: "循環播放"
-_contextMenu:
- title: "內容功能表"
- app: "應用程式"
- appWithShift: "Shift 鍵應用程式"
- native: "瀏覽器的使用者介面"
-_embedCodeGen:
- title: "自訂嵌入程式碼"
- header: "檢視標頭 "
- autoload: "自動繼續載入(不建議)"
- maxHeight: "最大高度"
- maxHeightDescription: "設定為 0 時代表沒有最大值。請指定某個值以避免小工具持續在縱向延伸。"
- maxHeightWarn: "最大高度限制已停用(0)。如果這個變更不是您想要的,請將最大高度設定為某個值。"
- previewIsNotActual: "由於超出了預覽畫面可顯示的範圍,因此顯示內容會與實際嵌入時有所不同。"
- rounded: "圓角"
- border: "給外框加上邊框"
- applyToPreview: "反映在預覽中"
- generateCode: "建立嵌入程式碼"
- codeGenerated: "已產生程式碼"
- codeGeneratedDescription: "請將產生的程式碼貼到您的網站上。"
+
diff --git a/misskey-assets b/misskey-assets
new file mode 160000
index 0000000000..0179793ec8
--- /dev/null
+++ b/misskey-assets
@@ -0,0 +1 @@
+Subproject commit 0179793ec891856d6f37a3be16ba4c22f67a81b5
diff --git a/package.json b/package.json
index 02782e5388..970eddd0e1 100644
--- a/package.json
+++ b/package.json
@@ -1,16 +1,14 @@
{
"name": "sharkey",
- "version": "2024.10.0-dev",
+ "version": "2024.2.0-beta.12",
"codename": "shonk",
"repository": {
"type": "git",
"url": "https://activitypub.software/TransFem-org/Sharkey.git"
},
- "packageManager": "pnpm@9.6.0",
+ "packageManager": "pnpm@8.15.1",
"workspaces": [
- "packages/frontend-shared",
"packages/frontend",
- "packages/frontend-embed",
"packages/backend",
"packages/sw",
"packages/misskey-js",
@@ -23,8 +21,8 @@
"build-assets": "node ./scripts/build-assets.mjs",
"build": "pnpm build-pre && pnpm -r build && pnpm build-assets",
"build-storybook": "pnpm --filter frontend build-storybook",
- "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
- "start": "pnpm check:connect && cd packages/backend && MK_WARNED_ABOUT_CONFIG=true node ./built/boot/entry.js",
+ "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api",
+ "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js",
"start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js",
"init": "pnpm migrate",
"migrate": "cd packages/backend && pnpm migrate",
@@ -34,13 +32,9 @@
"watch": "pnpm dev",
"dev": "node scripts/dev.mjs",
"lint": "pnpm -r lint",
- "lint-all": "pnpm -r --no-bail lint",
- "eslint": "pnpm -r eslint",
- "eslint-all": "pnpm -r --no-bail eslint",
"cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts",
"cy:run": "pnpm cypress run",
"e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run",
- "e2e-dev-container": "cp ./.config/cypress-devcontainer.yml ./.config/test.yml && pnpm start-server-and-test start:test http://localhost:61812 cy:run",
"jest": "cd packages/backend && pnpm jest",
"jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage",
"test": "pnpm -r test",
@@ -54,30 +48,23 @@
"lodash": "4.17.21"
},
"dependencies": {
- "cssnano": "6.1.2",
+ "cssnano": "6.0.3",
"execa": "8.0.1",
"fast-glob": "3.3.2",
- "ignore-walk": "6.0.5",
+ "ignore-walk": "6.0.4",
"js-yaml": "4.1.0",
- "postcss": "8.4.47",
- "tar": "6.2.1",
- "terser": "5.33.0",
- "typescript": "5.6.2",
- "esbuild": "0.23.1",
- "glob": "11.0.0"
- },
- "optionalDependencies": {
- "cypress": "13.14.2"
+ "postcss": "8.4.33",
+ "tar": "6.2.0",
+ "terser": "5.27.0",
+ "typescript": "5.3.3"
},
"devDependencies": {
- "@misskey-dev/eslint-plugin": "2.0.3",
- "@types/node": "20.14.12",
- "@typescript-eslint/eslint-plugin": "7.17.0",
- "@typescript-eslint/parser": "7.17.0",
+ "@typescript-eslint/eslint-plugin": "6.18.1",
+ "@typescript-eslint/parser": "6.18.1",
"cross-env": "7.0.3",
- "eslint": "9.8.0",
- "globals": "15.9.0",
- "ncp": "2.0.0",
- "start-server-and-test": "2.0.8"
+ "cypress": "13.6.3",
+ "eslint": "8.56.0",
+ "start-server-and-test": "2.0.3",
+ "ncp": "2.0.0"
}
}
diff --git a/packages/backend/.eslintignore b/packages/backend/.eslintignore
new file mode 100644
index 0000000000..790eb90145
--- /dev/null
+++ b/packages/backend/.eslintignore
@@ -0,0 +1,4 @@
+node_modules
+/built
+/.eslintrc.js
+/@types/**/*
diff --git a/packages/backend/.eslintrc.cjs b/packages/backend/.eslintrc.cjs
new file mode 100644
index 0000000000..f9fe4814e6
--- /dev/null
+++ b/packages/backend/.eslintrc.cjs
@@ -0,0 +1,32 @@
+module.exports = {
+ parserOptions: {
+ tsconfigRootDir: __dirname,
+ project: ['./tsconfig.json', './test/tsconfig.json'],
+ },
+ extends: [
+ '../shared/.eslintrc.js',
+ ],
+ rules: {
+ 'import/order': ['warn', {
+ 'groups': ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
+ 'pathGroups': [
+ {
+ 'pattern': '@/**',
+ 'group': 'external',
+ 'position': 'after'
+ }
+ ],
+ }],
+ 'no-restricted-globals': [
+ 'error',
+ {
+ 'name': '__dirname',
+ 'message': 'Not in ESModule. Use `import.meta.url` instead.'
+ },
+ {
+ 'name': '__filename',
+ 'message': 'Not in ESModule. Use `import.meta.url` instead.'
+ }
+ ]
+ },
+};
diff --git a/packages/backend/.swcrc b/packages/backend/.swcrc
index 845190b5f4..0504a2d389 100644
--- a/packages/backend/.swcrc
+++ b/packages/backend/.swcrc
@@ -19,6 +19,5 @@
},
"target": "es2022"
},
- "minify": false,
- "sourceMaps": "inline"
+ "minify": false
}
diff --git a/packages/backend/assets/api-doc.html b/packages/backend/assets/api-doc.html
deleted file mode 100644
index 19e0349d47..0000000000
--- a/packages/backend/assets/api-doc.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
- Misskey API
-
-
-
-
-
-
-
-
-
diff --git a/packages/backend/assets/embed.js b/packages/backend/assets/embed.js
deleted file mode 100644
index 24fccc1b6c..0000000000
--- a/packages/backend/assets/embed.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: MIT
- */
-//@ts-check
-(() => {
- /** @type {NodeListOf} */
- const els = document.querySelectorAll('iframe[data-misskey-embed-id]');
-
- window.addEventListener('message', function (event) {
- els.forEach((el) => {
- if (event.source !== el.contentWindow) {
- return;
- }
-
- const id = el.dataset.misskeyEmbedId;
-
- if (event.data.type === 'misskey:embed:ready') {
- el.contentWindow?.postMessage({
- type: 'misskey:embedParent:registerIframeId',
- payload: {
- iframeId: id,
- }
- }, '*');
- }
- if (event.data.type === 'misskey:embed:changeHeight' && event.data.iframeId === id) {
- el.style.height = event.data.payload.height + 'px';
- }
- });
- });
-})();
diff --git a/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.svg b/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.svg
new file mode 100644
index 0000000000..9d21137072
--- /dev/null
+++ b/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.ttf b/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.ttf
new file mode 100644
index 0000000000..a2601e0f1b
Binary files /dev/null and b/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.ttf differ
diff --git a/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.woff b/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.woff
new file mode 100644
index 0000000000..d9f471fa35
Binary files /dev/null and b/packages/backend/assets/fonts/sharkey-icons/custom-sharkey-icons.woff differ
diff --git a/packages/backend/assets/fonts/sharkey-icons/shark-font.svg b/packages/backend/assets/fonts/sharkey-icons/shark-font.svg
deleted file mode 100644
index b67bd7f7d8..0000000000
--- a/packages/backend/assets/fonts/sharkey-icons/shark-font.svg
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/backend/assets/fonts/sharkey-icons/shark-font.ttf b/packages/backend/assets/fonts/sharkey-icons/shark-font.ttf
deleted file mode 100644
index 0fdf04df08..0000000000
Binary files a/packages/backend/assets/fonts/sharkey-icons/shark-font.ttf and /dev/null differ
diff --git a/packages/backend/assets/fonts/sharkey-icons/shark-font.woff b/packages/backend/assets/fonts/sharkey-icons/shark-font.woff
deleted file mode 100644
index 993666bc3a..0000000000
Binary files a/packages/backend/assets/fonts/sharkey-icons/shark-font.woff and /dev/null differ
diff --git a/packages/backend/assets/fonts/sharkey-icons/style.css b/packages/backend/assets/fonts/sharkey-icons/style.css
index 7168702e5a..7fb0f94504 100644
--- a/packages/backend/assets/fonts/sharkey-icons/style.css
+++ b/packages/backend/assets/fonts/sharkey-icons/style.css
@@ -1,114 +1,31 @@
+@charset "UTF-8";
+
@font-face {
- font-display: auto;
- font-family: "shark-font";
- font-style: normal;
+ font-family: "custom-sharkey-icons";
+ src: url("./custom-sharkey-icons.woff") format("woff"),
+ url("./custom-sharkey-icons.ttf") format("truetype"),
+ url("./custom-sharkey-icons.svg#custom-sharkey-icons") format("svg");
font-weight: normal;
-
- src: url("./shark-font.woff?1722899913909") format("woff"), url("./shark-font.ttf?1722899913909") format("truetype"), url("./shark-font.svg?1722899913909#shark-font") format("svg");
+ font-style: normal;
+ font-display: block;
}
.sk-icons {
- display: inline-block;
- font-family: "shark-font";
- font-weight: normal;
+ font-family: "custom-sharkey-icons" !important;
font-style: normal;
+ font-weight: normal;
font-variant: normal;
- text-rendering: auto;
+ text-transform: none;
line-height: 1;
- -moz-osx-font-smoothing: grayscale;
+ speak: none;
-webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
-.sk-icons-lg {
- font-size: 1.33333em;
- line-height: 0.75em;
- vertical-align: -0.0667em;
+.sk-icons.sk-shark:before {
+ content: "\61";
}
-.sk-icons-xs {
- font-size: 0.75em;
+.sk-icons.sk-misskey:before {
+ content: "\62";
}
-
-.sk-icons-sm {
- font-size: 0.875em;
-}
-
-.sk-icons-1x {
- font-size: 1em;
-}
-
-.sk-icons-2x {
- font-size: 2em;
-}
-
-.sk-icons-3x {
- font-size: 3em;
-}
-
-.sk-icons-4x {
- font-size: 4em;
-}
-
-.sk-icons-5x {
- font-size: 5em;
-}
-
-.sk-icons-6x {
- font-size: 6em;
-}
-
-.sk-icons-7x {
- font-size: 7em;
-}
-
-.sk-icons-8x {
- font-size: 8em;
-}
-
-.sk-icons-9x {
- font-size: 9em;
-}
-
-.sk-icons-10x {
- font-size: 10em;
-}
-
-.sk-icons-fw {
- text-align: center;
- width: 1.25em;
-}
-
-.sk-icons-border {
- border: solid 0.08em #eee;
- border-radius: 0.1em;
- padding: 0.2em 0.25em 0.15em;
-}
-
-.sk-icons-pull-left {
- float: left;
-}
-
-.sk-icons-pull-right {
- float: right;
-}
-
-.sk-icons.sk-icons-pull-left {
- margin-right: 0.3em;
-}
-
-.sk-icons.sk-icons-pull-right {
- margin-left: 0.3em;
-}
-
-
-.sk-icons.sk-foldermove::before {
- content: "\ea01";
-}
-
-.sk-icons.sk-misskey::before {
- content: "\ea02";
-}
-
-.sk-icons.sk-shark::before {
- content: "\ea03";
-}
\ No newline at end of file
diff --git a/packages/backend/assets/redoc.html b/packages/backend/assets/redoc.html
new file mode 100644
index 0000000000..061608bf53
--- /dev/null
+++ b/packages/backend/assets/redoc.html
@@ -0,0 +1,24 @@
+
+
+
+ Sharkey API
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/backend/check_connect.js b/packages/backend/check_connect.js
new file mode 100644
index 0000000000..d88e649c09
--- /dev/null
+++ b/packages/backend/check_connect.js
@@ -0,0 +1,15 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import Redis from 'ioredis';
+import { loadConfig } from './built/config.js';
+
+const config = loadConfig();
+const redis = new Redis(config.redis);
+
+redis.on('connect', () => redis.disconnect());
+redis.on('error', (e) => {
+ throw e;
+});
diff --git a/packages/backend/eslint.config.js b/packages/backend/eslint.config.js
deleted file mode 100644
index 452045bc3e..0000000000
--- a/packages/backend/eslint.config.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import tsParser from '@typescript-eslint/parser';
-import sharedConfig from '../shared/eslint.config.js';
-import globals from 'globals';
-
-export default [
- ...sharedConfig,
- {
- ignores: ['**/node_modules', 'built', '@types/**/*', 'migration'],
- },
- {
- files: ['**/*.ts', '**/*.tsx'],
- languageOptions: {
- parserOptions: {
- parser: tsParser,
- project: ['./tsconfig.json', './test/tsconfig.json'],
- sourceType: 'module',
- tsconfigRootDir: import.meta.dirname,
- },
- },
- rules: {
- 'import/order': ['warn', {
- groups: [
- 'builtin',
- 'external',
- 'internal',
- 'parent',
- 'sibling',
- 'index',
- 'object',
- 'type',
- ],
- pathGroups: [{
- pattern: '@/**',
- group: 'external',
- position: 'after',
- }],
- }],
- 'no-restricted-globals': ['error', {
- name: '__dirname',
- message: 'Not in ESModule. Use `import.meta.url` instead.',
- }, {
- name: '__filename',
- message: 'Not in ESModule. Use `import.meta.url` instead.',
- }],
- },
- },
- {
- files: ['src/server/web/**/*.js', 'src/server/web/**/*.ts'],
- languageOptions: {
- globals: {
- ...globals.browser,
- LANGS: true,
- CLIENT_ENTRY: true,
- LANGS_VERSION: true,
- },
- },
- },
- {
- ignores: [
- "**/lib/",
- "**/temp/",
- "**/built/",
- "**/coverage/",
- "**/node_modules/",
- "**/migration/",
- ]
- },
-];
diff --git a/packages/backend/generate_api_json.js b/packages/backend/generate_api_json.js
new file mode 100644
index 0000000000..4079b3bb0a
--- /dev/null
+++ b/packages/backend/generate_api_json.js
@@ -0,0 +1,8 @@
+import { loadConfig } from './built/config.js'
+import { genOpenapiSpec } from './built/server/api/openapi/gen-spec.js'
+import { writeFileSync } from "node:fs";
+
+const config = loadConfig();
+const spec = genOpenapiSpec(config, true);
+
+writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
\ No newline at end of file
diff --git a/packages/backend/migration/1680969937000-larger-image-comment.js b/packages/backend/migration/1680969937000-larger-image-comment.js
index 2645b12630..b6b4f90913 100644
--- a/packages/backend/migration/1680969937000-larger-image-comment.js
+++ b/packages/backend/migration/1680969937000-larger-image-comment.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: dakkar and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class largerImageComment1680969937000 {
name = 'largerImageComment1680969937000';
diff --git a/packages/backend/migration/1682753227899-NoteEdit.js b/packages/backend/migration/1682753227899-NoteEdit.js
index e67b1c566d..55a0de0206 100644
--- a/packages/backend/migration/1682753227899-NoteEdit.js
+++ b/packages/backend/migration/1682753227899-NoteEdit.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class NoteEdit1682753227899 {
name = "NoteEdit1682753227899";
diff --git a/packages/backend/migration/1689325027964-UserBlacklistAnntena.js b/packages/backend/migration/1689325027964-UserBlacklistAnntena.js
index 2dc7774493..ce246b20f8 100644
--- a/packages/backend/migration/1689325027964-UserBlacklistAnntena.js
+++ b/packages/backend/migration/1689325027964-UserBlacklistAnntena.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class UserBlacklistAnntena1689325027964 {
name = 'UserBlacklistAnntena1689325027964'
diff --git a/packages/backend/migration/1690417561185-fix-renote-muting.js b/packages/backend/migration/1690417561185-fix-renote-muting.js
index d9604ca26c..14150b0362 100644
--- a/packages/backend/migration/1690417561185-fix-renote-muting.js
+++ b/packages/backend/migration/1690417561185-fix-renote-muting.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class FixRenoteMuting1690417561185 {
name = 'FixRenoteMuting1690417561185'
diff --git a/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js b/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js
index 9bccdb3bb5..7eda5debe5 100644
--- a/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js
+++ b/packages/backend/migration/1690417561186-ChangeCacheRemoteFilesDefault.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class ChangeCacheRemoteFilesDefault1690417561186 {
name = 'ChangeCacheRemoteFilesDefault1690417561186'
diff --git a/packages/backend/migration/1690417561187-Fix.js b/packages/backend/migration/1690417561187-Fix.js
index 7f1d62d68c..e780e66d7b 100644
--- a/packages/backend/migration/1690417561187-Fix.js
+++ b/packages/backend/migration/1690417561187-Fix.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class Fix1690417561187 {
name = 'Fix1690417561187'
diff --git a/packages/backend/migration/1690569881926-user-2fa-backup-codes.js b/packages/backend/migration/1690569881926-user-2fa-backup-codes.js
index a3ef8dcf08..2049df8ea2 100644
--- a/packages/backend/migration/1690569881926-user-2fa-backup-codes.js
+++ b/packages/backend/migration/1690569881926-user-2fa-backup-codes.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class User2faBackupCodes1690569881926 {
name = 'User2faBackupCodes1690569881926'
diff --git a/packages/backend/migration/1691264431000-add-lb-to-user.js b/packages/backend/migration/1691264431000-add-lb-to-user.js
index f06017468a..fe6265e3f5 100644
--- a/packages/backend/migration/1691264431000-add-lb-to-user.js
+++ b/packages/backend/migration/1691264431000-add-lb-to-user.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: amelia and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class AddLbToUser1691264431000 {
name = "AddLbToUser1691264431000";
@@ -22,4 +17,4 @@ export class AddLbToUser1691264431000 {
ALTER TABLE "user_profile" DROP COLUMN "listenbrainz"
`);
}
-}
+}
\ No newline at end of file
diff --git a/packages/backend/migration/1691649257651-refine-announcement.js b/packages/backend/migration/1691649257651-refine-announcement.js
index ac621155d5..d8d63f3103 100644
--- a/packages/backend/migration/1691649257651-refine-announcement.js
+++ b/packages/backend/migration/1691649257651-refine-announcement.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class RefineAnnouncement1691649257651 {
name = 'RefineAnnouncement1691649257651'
diff --git a/packages/backend/migration/1691657412740-refine-announcement-2.js b/packages/backend/migration/1691657412740-refine-announcement-2.js
index 67edf19659..8791f99f44 100644
--- a/packages/backend/migration/1691657412740-refine-announcement-2.js
+++ b/packages/backend/migration/1691657412740-refine-announcement-2.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class RefineAnnouncement21691657412740 {
name = 'RefineAnnouncement21691657412740'
diff --git a/packages/backend/migration/1695260774117-verified-links.js b/packages/backend/migration/1695260774117-verified-links.js
index 64c8a9ad8f..18e0571d81 100644
--- a/packages/backend/migration/1695260774117-verified-links.js
+++ b/packages/backend/migration/1695260774117-verified-links.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class VerifiedLinks1695260774117 {
name = 'VerifiedLinks1695260774117'
diff --git a/packages/backend/migration/1695288787870-following-notify.js b/packages/backend/migration/1695288787870-following-notify.js
index b3f78d5f2a..e7e2194b15 100644
--- a/packages/backend/migration/1695288787870-following-notify.js
+++ b/packages/backend/migration/1695288787870-following-notify.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class FollowingNotify1695288787870 {
name = 'FollowingNotify1695288787870'
diff --git a/packages/backend/migration/1695440131671-short-name.js b/packages/backend/migration/1695440131671-short-name.js
index fdc256caf8..2c37297fc1 100644
--- a/packages/backend/migration/1695440131671-short-name.js
+++ b/packages/backend/migration/1695440131671-short-name.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class ShortName1695440131671 {
name = 'ShortName1695440131671'
diff --git a/packages/backend/migration/1695605508898-mutingNotificationTypes.js b/packages/backend/migration/1695605508898-mutingNotificationTypes.js
index 67d4243142..8c0e52a2f0 100644
--- a/packages/backend/migration/1695605508898-mutingNotificationTypes.js
+++ b/packages/backend/migration/1695605508898-mutingNotificationTypes.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class MutingNotificationTypes1695605508898 {
name = 'MutingNotificationTypes1695605508898'
diff --git a/packages/backend/migration/1695937489995-enableAchievements.js b/packages/backend/migration/1695937489995-enableAchievements.js
index 1ee08de146..2c20971ff5 100644
--- a/packages/backend/migration/1695937489995-enableAchievements.js
+++ b/packages/backend/migration/1695937489995-enableAchievements.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class EnableAchievements1695937489995 {
name = 'EnableAchievements1695937489995'
@@ -13,4 +8,4 @@ export class EnableAchievements1695937489995 {
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableAchievements"`);
}
-}
+}
\ No newline at end of file
diff --git a/packages/backend/migration/1696323464251-user-list-membership.js b/packages/backend/migration/1696323464251-user-list-membership.js
index dc1d438dd7..7534040c4c 100644
--- a/packages/backend/migration/1696323464251-user-list-membership.js
+++ b/packages/backend/migration/1696323464251-user-list-membership.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class UserListMembership1696323464251 {
name = 'UserListMembership1696323464251'
diff --git a/packages/backend/migration/1696331570827-hibernation.js b/packages/backend/migration/1696331570827-hibernation.js
index 1487ece77c..119d35913f 100644
--- a/packages/backend/migration/1696331570827-hibernation.js
+++ b/packages/backend/migration/1696331570827-hibernation.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class Hibernation1696331570827 {
name = 'Hibernation1696331570827'
diff --git a/packages/backend/migration/1696332072038-clean.js b/packages/backend/migration/1696332072038-clean.js
index 3900b96328..2eecf70cff 100644
--- a/packages/backend/migration/1696332072038-clean.js
+++ b/packages/backend/migration/1696332072038-clean.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class Clean1696332072038 {
name = 'Clean1696332072038'
diff --git a/packages/backend/migration/1696386694000-speakAsCat.js b/packages/backend/migration/1696386694000-speakAsCat.js
index b9ba95e2fa..d68b9401bf 100644
--- a/packages/backend/migration/1696386694000-speakAsCat.js
+++ b/packages/backend/migration/1696386694000-speakAsCat.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class SpeakAsCat1696386694000 {
name = "SpeakAsCat1696386694000";
diff --git a/packages/backend/migration/1696548899000-background.js b/packages/backend/migration/1696548899000-background.js
index f1c0b5a4a5..59309b98c2 100644
--- a/packages/backend/migration/1696548899000-background.js
+++ b/packages/backend/migration/1696548899000-background.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class Background1696548899000 {
name = 'Background1696548899000'
@@ -21,4 +16,4 @@ export class Background1696548899000 {
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "backgroundUrl"`);
await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "backgroundBlurhash"`);
}
-}
+}
\ No newline at end of file
diff --git a/packages/backend/migration/1697580470000-approvalSignup.js b/packages/backend/migration/1697580470000-approvalSignup.js
index cc53a6bb5c..c5f8255d49 100644
--- a/packages/backend/migration/1697580470000-approvalSignup.js
+++ b/packages/backend/migration/1697580470000-approvalSignup.js
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
diff --git a/packages/backend/migration/1697603945000-BotTrending.js b/packages/backend/migration/1697603945000-BotTrending.js
index d59f1b0552..73f1f598ed 100644
--- a/packages/backend/migration/1697603945000-BotTrending.js
+++ b/packages/backend/migration/1697603945000-BotTrending.js
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
diff --git a/packages/backend/migration/1697624010000-isSilenced.js b/packages/backend/migration/1697624010000-isSilenced.js
index 16749b54cf..98b5e8c55c 100644
--- a/packages/backend/migration/1697624010000-isSilenced.js
+++ b/packages/backend/migration/1697624010000-isSilenced.js
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
diff --git a/packages/backend/migration/1697970083000-alterNoteEdit.js b/packages/backend/migration/1697970083000-alterNoteEdit.js
index 0aa4f8fa9c..11accb3c54 100644
--- a/packages/backend/migration/1697970083000-alterNoteEdit.js
+++ b/packages/backend/migration/1697970083000-alterNoteEdit.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class AlterNoteEdit1697970083000 {
name = "AlterNoteEdit1697970083000";
diff --git a/packages/backend/migration/1697970083001-oldDateNoteEdit.js b/packages/backend/migration/1697970083001-oldDateNoteEdit.js
index c21f62c486..17565a0914 100644
--- a/packages/backend/migration/1697970083001-oldDateNoteEdit.js
+++ b/packages/backend/migration/1697970083001-oldDateNoteEdit.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class OldDateNoteEdit1697970083001 {
name = "OldDateNoteEdit1697970083001";
diff --git a/packages/backend/migration/1699376974000-isIndexable.js b/packages/backend/migration/1699376974000-isIndexable.js
index 7919b36c5d..ae826924a8 100644
--- a/packages/backend/migration/1699376974000-isIndexable.js
+++ b/packages/backend/migration/1699376974000-isIndexable.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class IsIndexable1699376974000 {
name = 'IsIndexable1699376974000'
diff --git a/packages/backend/migration/1699819257000-defaultLike.js b/packages/backend/migration/1699819257000-defaultLike.js
index a91926698a..45492fa6c6 100644
--- a/packages/backend/migration/1699819257000-defaultLike.js
+++ b/packages/backend/migration/1699819257000-defaultLike.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class instanceDefaultLike1699819257000 {
name = 'instanceDefaultLike1699819257000'
diff --git a/packages/backend/migration/1700228972000-update-indexable.js b/packages/backend/migration/1700228972000-update-indexable.js
index 1d46fd08fd..e724e2ec7e 100644
--- a/packages/backend/migration/1700228972000-update-indexable.js
+++ b/packages/backend/migration/1700228972000-update-indexable.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class UpdateIndexable1700228972000 {
name = 'UpdateIndexable1700228972000'
diff --git a/packages/backend/migration/1700383825690-hard-mute.js b/packages/backend/migration/1700383825690-hard-mute.js
index 92c3ada4a1..afd3247f5c 100644
--- a/packages/backend/migration/1700383825690-hard-mute.js
+++ b/packages/backend/migration/1700383825690-hard-mute.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class HardMute1700383825690 {
name = 'HardMute1700383825690'
diff --git a/packages/backend/migration/1701647674000-BubbleInstances.js b/packages/backend/migration/1701647674000-BubbleInstances.js
index f048f521b0..9928b4c36e 100644
--- a/packages/backend/migration/1701647674000-BubbleInstances.js
+++ b/packages/backend/migration/1701647674000-BubbleInstances.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class BubbleInstances1701647674000 {
name = 'BubbleInstances1701647674000'
diff --git a/packages/backend/migration/1701809447000-NSFW-Instance.js b/packages/backend/migration/1701809447000-NSFW-Instance.js
index 51075517b0..882aa9865d 100644
--- a/packages/backend/migration/1701809447000-NSFW-Instance.js
+++ b/packages/backend/migration/1701809447000-NSFW-Instance.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class NSFWInstance1701809447000 {
name = 'NSFWInstance1701809447000'
diff --git a/packages/backend/migration/1704744370000-add-donation-url.js b/packages/backend/migration/1704744370000-add-donation-url.js
index ead22c6a95..c953b13cc9 100644
--- a/packages/backend/migration/1704744370000-add-donation-url.js
+++ b/packages/backend/migration/1704744370000-add-donation-url.js
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: nila and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
export class AddDonationUrl1704744370000 {
name = 'AddDonationUrl1704744370000'
diff --git a/packages/backend/migration/1706232992000-deeplx.js b/packages/backend/migration/1706232992000-deeplx.js
index 17ddbef26a..5c763dbf8b 100644
--- a/packages/backend/migration/1706232992000-deeplx.js
+++ b/packages/backend/migration/1706232992000-deeplx.js
@@ -1,5 +1,5 @@
/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
diff --git a/packages/backend/migration/1708399372194-per-instance-mod-note.js b/packages/backend/migration/1708399372194-per-instance-mod-note.js
deleted file mode 100644
index 339a4d7af9..0000000000
--- a/packages/backend/migration/1708399372194-per-instance-mod-note.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class PerInstanceModNote1708399372194 {
- name = 'PerInstanceModNote1708399372194'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "instance" ADD "moderationNote" character varying(16384) NOT NULL DEFAULT ''`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "moderationNote"`);
- }
-}
diff --git a/packages/backend/migration/1709462550083-MoreRepoUrl.js b/packages/backend/migration/1709462550083-MoreRepoUrl.js
deleted file mode 100644
index 90bab0e676..0000000000
--- a/packages/backend/migration/1709462550083-MoreRepoUrl.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: dakkar and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class MoreRepoUrl1709462550083 {
- name = 'MoreRepoUrl1709462550083'
-
- async up(queryRunner) {
- await queryRunner.query(`UPDATE "meta" SET "repositoryUrl"=DEFAULT WHERE "repositoryUrl" IN ('https://git.joinfirefish.org/firefish/firefish','https://codeberg/firefish/firefish','https://codeberg.org/calckey/calckey','https://iceshrimp.dev/iceshrimp/iceshrimp')`);
- await queryRunner.query(`UPDATE "meta" SET "feedbackUrl"=DEFAULT WHERE "feedbackUrl" IN ('https://git.joinfirefish.org/firefish/firefish/issues','https://codeberg/firefish/firefish/issues','https://codeberg.org/calckey/calckey/firefish/firefish/issues','https://iceshrimp.dev/iceshrimp/iceshrimp/issues/new','https://iceshrimp.dev/iceshrimp/iceshrimp/issues')`);
- }
-
- async down(queryRunner) {
- }
-}
diff --git a/packages/backend/migration/1710512074000-url-preview-meta.js b/packages/backend/migration/1710512074000-url-preview-meta.js
deleted file mode 100644
index 8af521bbf4..0000000000
--- a/packages/backend/migration/1710512074000-url-preview-meta.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class UrlPreviewMeta1710512074000 {
- name = 'UrlPreviewMeta1710512074000'
-
- async up(queryRunner) {
- await queryRunner.query(`
- alter table meta
- rename column "summalyProxy" to "urlPreviewSummaryProxyUrl";
- alter table meta
- add "urlPreviewEnabled" boolean default true not null;
- alter table meta
- add "urlPreviewTimeout" integer default 10000 not null;
- alter table meta
- add "urlPreviewMaximumContentLength" bigint default 10485760 not null;
- alter table meta
- add "urlPreviewRequireContentLength" boolean default false not null;
- alter table meta
- add "urlPreviewUserAgent" varchar(1024) default null;
- `);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`
- alter table meta
- rename column "urlPreviewSummaryProxyUrl" to "summalyProxy";
- alter table meta
- drop column "urlPreviewEnabled";
- alter table meta
- drop column "urlPreviewTimeout";
- alter table meta
- drop column "urlPreviewMaximumContentLength";
- alter table meta
- drop column "urlPreviewRequireContentLength";
- alter table meta
- drop column "urlPreviewUserAgent";
- `);
- }
-}
diff --git a/packages/backend/migration/1710919614510-antenna-exclude-bots.js b/packages/backend/migration/1710919614510-antenna-exclude-bots.js
deleted file mode 100644
index fac84317cc..0000000000
--- a/packages/backend/migration/1710919614510-antenna-exclude-bots.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class AntennaExcludeBots1710919614510 {
- name = 'AntennaExcludeBots1710919614510'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "antenna" ADD "excludeBots" boolean NOT NULL DEFAULT false`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "excludeBots"`);
- }
-}
diff --git a/packages/backend/migration/1711008460816-external-website-warn.js b/packages/backend/migration/1711008460816-external-website-warn.js
deleted file mode 100644
index d36639459b..0000000000
--- a/packages/backend/migration/1711008460816-external-website-warn.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class ExternalWebsiteWarn1711008460816 {
- name = 'ExternalWebsiteWarn1711008460816'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "trustedLinkUrlPatterns" character varying(3072) array NOT NULL DEFAULT '{}'`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "trustedLinkUrlPatterns"`);
- }
-}
\ No newline at end of file
diff --git a/packages/backend/migration/1713656541000-abuse-report-notification.js b/packages/backend/migration/1713656541000-abuse-report-notification.js
deleted file mode 100644
index 4a754f81e2..0000000000
--- a/packages/backend/migration/1713656541000-abuse-report-notification.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class AbuseReportNotification1713656541000 {
- name = 'AbuseReportNotification1713656541000'
-
- async up(queryRunner) {
- await queryRunner.query(`
- CREATE TABLE "system_webhook" (
- "id" varchar(32) NOT NULL,
- "isActive" boolean NOT NULL DEFAULT true,
- "updatedAt" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "latestSentAt" timestamp with time zone NULL DEFAULT NULL,
- "latestStatus" integer NULL DEFAULT NULL,
- "name" varchar(255) NOT NULL,
- "on" varchar(128) [] NOT NULL DEFAULT '{}'::character varying[],
- "url" varchar(1024) NOT NULL,
- "secret" varchar(1024) NOT NULL,
- CONSTRAINT "PK_system_webhook_id" PRIMARY KEY ("id")
- );
- CREATE INDEX "IDX_system_webhook_isActive" ON "system_webhook" ("isActive");
- CREATE INDEX "IDX_system_webhook_on" ON "system_webhook" USING gin ("on");
-
- CREATE TABLE "abuse_report_notification_recipient" (
- "id" varchar(32) NOT NULL,
- "isActive" boolean NOT NULL DEFAULT true,
- "updatedAt" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
- "name" varchar(255) NOT NULL,
- "method" varchar(64) NOT NULL,
- "userId" varchar(32) NULL DEFAULT NULL,
- "systemWebhookId" varchar(32) NULL DEFAULT NULL,
- CONSTRAINT "PK_abuse_report_notification_recipient_id" PRIMARY KEY ("id"),
- CONSTRAINT "FK_abuse_report_notification_recipient_userId1" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION,
- CONSTRAINT "FK_abuse_report_notification_recipient_userId2" FOREIGN KEY ("userId") REFERENCES "user_profile"("userId") ON DELETE CASCADE ON UPDATE NO ACTION,
- CONSTRAINT "FK_abuse_report_notification_recipient_systemWebhookId" FOREIGN KEY ("systemWebhookId") REFERENCES "system_webhook"("id") ON DELETE CASCADE ON UPDATE NO ACTION
- );
- CREATE INDEX "IDX_abuse_report_notification_recipient_isActive" ON "abuse_report_notification_recipient" ("isActive");
- CREATE INDEX "IDX_abuse_report_notification_recipient_method" ON "abuse_report_notification_recipient" ("method");
- CREATE INDEX "IDX_abuse_report_notification_recipient_userId" ON "abuse_report_notification_recipient" ("userId");
- CREATE INDEX "IDX_abuse_report_notification_recipient_systemWebhookId" ON "abuse_report_notification_recipient" ("systemWebhookId");
- `);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`
- ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_userId1";
- ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_userId2";
- ALTER TABLE "abuse_report_notification_recipient" DROP CONSTRAINT "FK_abuse_report_notification_recipient_systemWebhookId";
- DROP INDEX "IDX_abuse_report_notification_recipient_isActive";
- DROP INDEX "IDX_abuse_report_notification_recipient_method";
- DROP INDEX "IDX_abuse_report_notification_recipient_userId";
- DROP INDEX "IDX_abuse_report_notification_recipient_systemWebhookId";
- DROP TABLE "abuse_report_notification_recipient";
-
- DROP INDEX "IDX_system_webhook_isActive";
- DROP INDEX "IDX_system_webhook_on";
- DROP TABLE "system_webhook";
- `);
- }
-}
diff --git a/packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js b/packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js
deleted file mode 100644
index f736378c04..0000000000
--- a/packages/backend/migration/1716129964060-ChannelIdDenormalizedForMiPoll.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class ChannelIdDenormalizedForMiPoll1716129964060 {
- name = 'ChannelIdDenormalizedForMiPoll1716129964060'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "poll" ADD "channelId" character varying(32)`);
- await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
- await queryRunner.query(`CREATE INDEX "IDX_c1240fcc9675946ea5d6c2860e" ON "poll" ("channelId") `);
- await queryRunner.query(`UPDATE "poll" SET "channelId" = "note"."channelId" FROM "note" WHERE "poll"."noteId" = "note"."id"`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`DROP INDEX "public"."IDX_c1240fcc9675946ea5d6c2860e"`);
- await queryRunner.query(`COMMENT ON COLUMN "poll"."channelId" IS '[Denormalized]'`);
- await queryRunner.query(`ALTER TABLE "poll" DROP COLUMN "channelId"`);
- }
-}
diff --git a/packages/backend/migration/1716197366117-MediaSilenceForHosts.js b/packages/backend/migration/1716197366117-MediaSilenceForHosts.js
deleted file mode 100644
index 10bb7f0255..0000000000
--- a/packages/backend/migration/1716197366117-MediaSilenceForHosts.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class MediaSilenceForHosts1716197366117 {
- name = 'MediaSilenceForHosts1716197366117'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "mediaSilencedHosts" character varying(1024) array NOT NULL DEFAULT '{}'`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "mediaSilencedHosts"`);
- }
-}
diff --git a/packages/backend/migration/1716345015347-NotRespondingSince.js b/packages/backend/migration/1716345015347-NotRespondingSince.js
deleted file mode 100644
index fc4ee6639a..0000000000
--- a/packages/backend/migration/1716345015347-NotRespondingSince.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class NotRespondingSince1716345015347 {
- name = 'NotRespondingSince1716345015347'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "instance" ADD "notRespondingSince" TIMESTAMP WITH TIME ZONE`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "notRespondingSince"`);
- }
-}
diff --git a/packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js b/packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js
deleted file mode 100644
index 4808a9a3db..0000000000
--- a/packages/backend/migration/1716447138870-SuspensionStateInsteadOfIsSspended.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class SuspensionStateInsteadOfIsSspended1716345771510 {
- name = 'SuspensionStateInsteadOfIsSspended1716345771510'
-
- async up(queryRunner) {
- await queryRunner.query(`CREATE TYPE "public"."instance_suspensionstate_enum" AS ENUM('none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding')`);
-
- await queryRunner.query(`DROP INDEX "public"."IDX_34500da2e38ac393f7bb6b299c"`);
-
- await queryRunner.query(`ALTER TABLE "instance" RENAME COLUMN "isSuspended" TO "suspensionState"`);
-
- await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" DROP DEFAULT`);
-
- await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" TYPE "public"."instance_suspensionstate_enum" USING (
- CASE "suspensionState"
- WHEN TRUE THEN 'manuallySuspended'::instance_suspensionstate_enum
- ELSE 'none'::instance_suspensionstate_enum
- END
- )`);
-
- await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" SET DEFAULT 'none'`);
-
- await queryRunner.query(`CREATE INDEX "IDX_3ede46f507c87ad698051d56a8" ON "instance" ("suspensionState") `);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`DROP INDEX "public"."IDX_3ede46f507c87ad698051d56a8"`);
-
- await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" DROP DEFAULT`);
-
- await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" TYPE boolean USING (
- CASE "suspensionState"
- WHEN 'none'::instance_suspensionstate_enum THEN FALSE
- ELSE TRUE
- END
- )`);
-
- await queryRunner.query(`ALTER TABLE "instance" ALTER COLUMN "suspensionState" SET DEFAULT false`);
-
- await queryRunner.query(`ALTER TABLE "instance" RENAME COLUMN "suspensionState" TO "isSuspended"`);
-
- await queryRunner.query(`CREATE INDEX "IDX_34500da2e38ac393f7bb6b299c" ON "instance" ("isSuspended") `);
-
- await queryRunner.query(`DROP TYPE "public"."instance_suspensionstate_enum"`);
- }
-}
diff --git a/packages/backend/migration/1716450883149-RemoveAntennaNotify.js b/packages/backend/migration/1716450883149-RemoveAntennaNotify.js
deleted file mode 100644
index b5a2441855..0000000000
--- a/packages/backend/migration/1716450883149-RemoveAntennaNotify.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class RemoveAntennaNotify1716450883149 {
- name = 'RemoveAntennaNotify1716450883149'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "notify"`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "antenna" ADD "notify" boolean NOT NULL`);
- }
-}
diff --git a/packages/backend/migration/1717117195275-inquiryUrl.js b/packages/backend/migration/1717117195275-inquiryUrl.js
deleted file mode 100644
index 29ca31af14..0000000000
--- a/packages/backend/migration/1717117195275-inquiryUrl.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class InquiryUrl1717117195275 {
- name = 'InquiryUrl1717117195275'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "inquiryUrl" character varying(1024)`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "inquiryUrl"`);
- }
-}
diff --git a/packages/backend/migration/1721666053703-fixDriveUrl.js b/packages/backend/migration/1721666053703-fixDriveUrl.js
deleted file mode 100644
index d8512fb835..0000000000
--- a/packages/backend/migration/1721666053703-fixDriveUrl.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class FixDriveUrl1721666053703 {
- name = 'FixDriveUrl1721666053703'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "url" TYPE character varying(1024), ALTER COLUMN "url" SET NOT NULL`);
- await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "uri" TYPE character varying(1024)`);
- await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "src" TYPE character varying(1024)`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "src" TYPE character varying(512)`);
- await queryRunner.query(`COMMENT ON COLUMN "drive_file"."uri" IS 'The URI of the DriveFile. it will be null when the DriveFile is local.'`);
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "uri" TYPE character varying(512)`);
- await queryRunner.query(`COMMENT ON COLUMN "drive_file"."url" IS 'The URL of the DriveFile.'`);
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "url" TYPE character varying(512), ALTER COLUMN "url" SET NOT NULL`);
- }
-}
diff --git a/packages/backend/migration/1723944246767-followedMessage.js b/packages/backend/migration/1723944246767-followedMessage.js
deleted file mode 100644
index fc9ad1cb85..0000000000
--- a/packages/backend/migration/1723944246767-followedMessage.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class FollowedMessage1723944246767 {
- name = 'FollowedMessage1723944246767';
-
- async up(queryRunner) {
- await queryRunner.query('ALTER TABLE "user_profile" ADD "followedMessage" character varying(256)');
- }
-
- async down(queryRunner) {
- await queryRunner.query('ALTER TABLE "user_profile" DROP COLUMN "followedMessage"');
- }
-}
diff --git a/packages/backend/migration/1726804538569-reactions-buffering.js b/packages/backend/migration/1726804538569-reactions-buffering.js
deleted file mode 100644
index bc19e9cc8a..0000000000
--- a/packages/backend/migration/1726804538569-reactions-buffering.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class ReactionsBuffering1726804538569 {
- name = 'ReactionsBuffering1726804538569'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "enableReactionsBuffering" boolean NOT NULL DEFAULT false`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableReactionsBuffering"`);
- }
-}
diff --git a/packages/backend/migration/1727027985575-SidebarLogo.js b/packages/backend/migration/1727027985575-SidebarLogo.js
deleted file mode 100644
index 03344a367f..0000000000
--- a/packages/backend/migration/1727027985575-SidebarLogo.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: piuvas and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class SidebarLogo1727027985575 {
- name = 'SidebarLogo1727027985575';
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "sidebarLogoUrl" character varying(1024)`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "sidebarLogoUrl"`);
- }
-}
diff --git a/packages/backend/migration/1727491883993-user-score.js b/packages/backend/migration/1727491883993-user-score.js
deleted file mode 100644
index 7292d5363c..0000000000
--- a/packages/backend/migration/1727491883993-user-score.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class UserScore1727491883993 {
- name = 'UserScore1727491883993'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "user" ADD "score" integer NOT NULL DEFAULT '0'`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "score"`);
- }
-}
diff --git a/packages/backend/migration/1727512908322-meta-federation.js b/packages/backend/migration/1727512908322-meta-federation.js
deleted file mode 100644
index 52c24df4f7..0000000000
--- a/packages/backend/migration/1727512908322-meta-federation.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class MetaFederation1727512908322 {
- name = 'MetaFederation1727512908322'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "federation" character varying(128) NOT NULL DEFAULT 'all'`);
- await queryRunner.query(`ALTER TABLE "meta" ADD "federationHosts" character varying(1024) array NOT NULL DEFAULT '{}'`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "federationHosts"`);
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "federation"`);
- }
-}
diff --git a/packages/backend/migration/1727659258948-add_latest_note.js b/packages/backend/migration/1727659258948-add_latest_note.js
deleted file mode 100644
index 0ab2b3f0d1..0000000000
--- a/packages/backend/migration/1727659258948-add_latest_note.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class AddLatestNote1727659258948 {
- name = 'AddLatestNote1727659258948';
-
- async up(queryRunner) {
- await queryRunner.query('CREATE TABLE "latest_note" ("user_id" character varying(32) NOT NULL, "note_id" character varying(32) NOT NULL, CONSTRAINT "PK_f619b62bfaafabe68f52fb50c9a" PRIMARY KEY ("user_id"))');
- await queryRunner.query('ALTER TABLE "latest_note" ADD CONSTRAINT "FK_20e346fffe4a2174585005d6d80" FOREIGN KEY ("user_id") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION');
- await queryRunner.query('ALTER TABLE "latest_note" ADD CONSTRAINT "FK_47a38b1c13de6ce4e5090fb1acd" FOREIGN KEY ("note_id") REFERENCES "note"("id") ON DELETE CASCADE ON UPDATE NO ACTION');
- }
-
- async down(queryRunner) {
- await queryRunner.query('ALTER TABLE "latest_note" DROP CONSTRAINT "FK_47a38b1c13de6ce4e5090fb1acd"');
- await queryRunner.query('ALTER TABLE "latest_note" DROP CONSTRAINT "FK_20e346fffe4a2174585005d6d80"');
- await queryRunner.query('DROP TABLE "latest_note"');
- }
-}
diff --git a/packages/backend/migration/1727998351561-increase_character_limits.js b/packages/backend/migration/1727998351561-increase_character_limits.js
deleted file mode 100644
index 8754163846..0000000000
--- a/packages/backend/migration/1727998351561-increase_character_limits.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class IncreaseCharacterLimits1727998351561 {
- name = 'IncreaseCharacterLimits1727998351561'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "comment" TYPE varchar(100000)`);
- await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "cw" TYPE text`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "cw" TYPE varchar(512)`);
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "comment" TYPE varchar(8192)`);
- }
-}
diff --git a/packages/backend/migration/1728177700920-add-reject-reports.js b/packages/backend/migration/1728177700920-add-reject-reports.js
deleted file mode 100644
index ed5f6bc559..0000000000
--- a/packages/backend/migration/1728177700920-add-reject-reports.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class AddRejectReports1728177700920 {
- name = 'AddRejectReports1728177700920'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "instance" ADD "rejectReports" boolean NOT NULL DEFAULT false`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "rejectReports"`);
- }
-}
diff --git a/packages/backend/migration/1728348353115-soft-limit-drive-comment.js b/packages/backend/migration/1728348353115-soft-limit-drive-comment.js
deleted file mode 100644
index 4eb04432c2..0000000000
--- a/packages/backend/migration/1728348353115-soft-limit-drive-comment.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class SoftLimitDriveComment1728348353115 {
- name = 'SoftLimitDriveComment1728348353115'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "comment" TYPE text`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "comment" TYPE varchar(100000)`);
- }
-}
diff --git a/packages/backend/migration/1728420772835-track-latest-note-type.js b/packages/backend/migration/1728420772835-track-latest-note-type.js
deleted file mode 100644
index 4c9b4ca594..0000000000
--- a/packages/backend/migration/1728420772835-track-latest-note-type.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class TrackLatestNoteType1728420772835 {
- name = 'TrackLatestNoteType1728420772835'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "latest_note" DROP CONSTRAINT "PK_f619b62bfaafabe68f52fb50c9a"`);
- await queryRunner.query(`ALTER TABLE "latest_note" ADD "is_public" boolean NOT NULL DEFAULT false`);
- await queryRunner.query(`ALTER TABLE "latest_note" ADD "is_reply" boolean NOT NULL DEFAULT false`);
- await queryRunner.query(`ALTER TABLE "latest_note" ADD "is_quote" boolean NOT NULL DEFAULT false`);
- await queryRunner.query(`ALTER TABLE "latest_note" ADD CONSTRAINT "PK_a44ac8ca9cb916faeefc0912abd" PRIMARY KEY ("user_id", is_public, is_reply, is_quote)`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "latest_note" DROP CONSTRAINT "PK_a44ac8ca9cb916faeefc0912abd"`);
- await queryRunner.query(`ALTER TABLE "latest_note" DROP COLUMN is_quote`);
- await queryRunner.query(`ALTER TABLE "latest_note" DROP COLUMN is_reply`);
- await queryRunner.query(`ALTER TABLE "latest_note" DROP COLUMN is_public`);
- await queryRunner.query(`ALTER TABLE "latest_note" ADD CONSTRAINT "PK_f619b62bfaafabe68f52fb50c9a" PRIMARY KEY ("user_id")`);
- }
-}
diff --git a/packages/backend/migration/1729414690009-defaultSensitive.js b/packages/backend/migration/1729414690009-defaultSensitive.js
deleted file mode 100644
index 47debf05a7..0000000000
--- a/packages/backend/migration/1729414690009-defaultSensitive.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * SPDX-FileCopyrightText: marie and sharkey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class DefaultSensitive1729414690009 {
- name = 'DefaultSensitive1729414690009'
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "user_profile" ADD "defaultSensitive" boolean NOT NULL DEFAULT false`);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "defaultSensitive"`);
- }
-}
diff --git a/packages/backend/migration/1730505338000-friendlyCaptcha.js b/packages/backend/migration/1730505338000-friendlyCaptcha.js
deleted file mode 100644
index 94a4f22dfa..0000000000
--- a/packages/backend/migration/1730505338000-friendlyCaptcha.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-export class friendlyCaptcha1730505338000 {
- name = 'friendlyCaptcha1730505338000';
-
- async up(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" ADD "enableFC" boolean NOT NULL DEFAULT false`, undefined);
- await queryRunner.query(`ALTER TABLE "meta" ADD "fcSiteKey" character varying(1024)`, undefined);
- await queryRunner.query(`ALTER TABLE "meta" ADD "fcSecretKey" character varying(1024)`, undefined);
- }
-
- async down(queryRunner) {
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "fcSecretKey"`, undefined);
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "fcSiteKey"`, undefined);
- await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableFC"`, undefined);
- }
-}
diff --git a/packages/backend/ormconfig.js b/packages/backend/ormconfig.js
index c88b3b3d65..229e5bf1fe 100644
--- a/packages/backend/ormconfig.js
+++ b/packages/backend/ormconfig.js
@@ -11,11 +11,7 @@ export default new DataSource({
username: config.db.user,
password: config.db.pass,
database: config.db.db,
- extra: {
- ...config.db.extra,
- // migrations may be very slow, give them longer to run (that 10*1000 comes from postgres.ts)
- statement_timeout: (config.db.extra?.statement_timeout ?? 1000 * 10) * 10,
- },
+ extra: config.db.extra,
entities: entities,
migrations: ['migration/*.js'],
});
diff --git a/packages/backend/package.json b/packages/backend/package.json
index 00baef56d8..b096d63b85 100644
--- a/packages/backend/package.json
+++ b/packages/backend/package.json
@@ -4,23 +4,23 @@
"private": true,
"type": "module",
"engines": {
- "node": "^20.10.0 || ^22.0.0"
+ "node": ">=20.10.0"
},
"scripts": {
"start": "node ./built/boot/entry.js",
"start:test": "cross-env NODE_ENV=test node ./built/boot/entry.js",
"migrate": "pnpm typeorm migration:run -d ormconfig.js",
"revert": "pnpm typeorm migration:revert -d ormconfig.js",
- "check:connect": "node ./scripts/check_connect.js",
- "build": "swc src -d built -D --strip-leading-paths",
- "build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc --strip-leading-paths",
- "watch:swc": "swc src -d built -D -w --strip-leading-paths",
+ "check:connect": "node ./check_connect.js",
+ "build": "swc src -d built -D",
+ "build:test": "swc test-server -d built-test -D --config-file test-server/.swcrc",
+ "watch:swc": "swc src -d built -D -w",
"build:tsc": "tsc -p tsconfig.json && tsc-alias -p tsconfig.json",
- "watch": "node ./scripts/watch.mjs",
+ "watch": "node watch.mjs",
"restart": "pnpm build && pnpm start",
- "dev": "node ./scripts/dev.mjs",
- "typecheck": "pnpm --filter megalodon build && tsc --noEmit && tsc -p test --noEmit",
- "eslint": "eslint --quiet \"{src,test,js,@types}/**/*.{js,jsx,ts,tsx,vue}\" --cache",
+ "dev": "nodemon -w src -e ts,js,mjs,cjs,json --exec \"cross-env NODE_ENV=development pnpm run restart\"",
+ "typecheck": "pnpm --filter megalodon build && tsc --noEmit",
+ "eslint": "eslint --quiet \"src/**/*.ts\"",
"lint": "pnpm typecheck && pnpm eslint",
"jest": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.unit.cjs",
"jest:e2e": "cross-env NODE_ENV=test node --experimental-vm-modules --experimental-import-meta-resolve node_modules/jest/bin/jest.js --forceExit --config jest.config.e2e.cjs",
@@ -31,7 +31,7 @@
"test:e2e": "pnpm build && pnpm build:test && pnpm jest:e2e",
"test-and-coverage": "pnpm jest-and-coverage",
"test-and-coverage:e2e": "pnpm build && pnpm build:test && pnpm jest-and-coverage:e2e",
- "generate-api-json": "node ./scripts/generate_api_json.js"
+ "generate-api-json": "pnpm build && node ./generate_api_json.js"
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
@@ -63,46 +63,42 @@
"utf-8-validate": "6.0.3"
},
"dependencies": {
- "@aws-sdk/client-s3": "3.620.0",
- "@aws-sdk/lib-storage": "3.620.0",
- "@bull-board/api": "6.0.0",
- "@bull-board/fastify": "6.0.0",
- "@bull-board/ui": "6.0.0",
- "@discordapp/twemoji": "15.1.0",
- "@fastify/accepts": "5.0.0",
- "@fastify/cookie": "10.0.0",
- "@fastify/cors": "10.0.0",
- "@fastify/express": "4.0.0",
- "@fastify/http-proxy": "10.0.0",
- "@fastify/multipart": "9.0.0",
- "@fastify/static": "8.0.0",
- "@fastify/view": "10.0.0",
- "@misskey-dev/sharp-read-bmp": "1.2.0",
- "@misskey-dev/summaly": "5.1.0",
- "@napi-rs/canvas": "0.1.56",
- "@nestjs/common": "10.4.3",
- "@nestjs/core": "10.4.3",
- "@nestjs/testing": "10.4.3",
+ "@aws-sdk/client-s3": "3.412.0",
+ "@aws-sdk/lib-storage": "3.412.0",
+ "@bull-board/api": "5.14.0",
+ "@bull-board/fastify": "5.14.0",
+ "@bull-board/ui": "5.14.0",
+ "@discordapp/twemoji": "15.0.2",
+ "@fastify/accepts": "4.3.0",
+ "@fastify/cookie": "9.3.1",
+ "@fastify/cors": "8.5.0",
+ "@fastify/express": "2.3.0",
+ "@fastify/http-proxy": "9.3.0",
+ "@fastify/multipart": "8.1.0",
+ "@fastify/static": "6.12.0",
+ "@fastify/view": "8.2.0",
+ "@misskey-dev/sharp-read-bmp": "^1.1.1",
+ "@misskey-dev/summaly": "^5.0.3",
+ "@nestjs/common": "10.2.10",
+ "@nestjs/core": "10.2.10",
+ "@nestjs/testing": "10.2.10",
"@peertube/http-signature": "1.7.0",
- "@sentry/node": "8.20.0",
- "@sentry/profiling-node": "8.20.0",
- "@simplewebauthn/server": "10.0.1",
+ "@transfem-org/sfm-js": "0.24.4",
+ "@simplewebauthn/server": "9.0.2",
"@sinonjs/fake-timers": "11.2.2",
- "@smithy/node-http-handler": "2.5.0",
- "@swc/cli": "0.3.12",
- "@swc/core": "1.6.6",
- "@transfem-org/sfm-js": "0.24.5",
- "@twemoji/parser": "15.1.1",
- "@types/psl": "^1.1.3",
+ "@smithy/node-http-handler": "2.1.10",
+ "@swc/cli": "0.1.63",
+ "@swc/core": "1.3.107",
+ "@twemoji/parser": "15.0.0",
"accepts": "1.3.8",
- "ajv": "8.17.1",
- "archiver": "7.0.1",
- "argon2": "^0.40.1",
- "async-mutex": "0.5.0",
+ "ajv": "8.12.0",
+ "archiver": "6.0.1",
+ "argon2": "^0.31.1",
+ "async-mutex": "0.4.1",
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
- "body-parser": "1.20.3",
- "bullmq": "5.13.2",
+ "body-parser": "1.20.2",
+ "bullmq": "5.1.9",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.3.0",
@@ -113,120 +109,116 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
- "fast-xml-parser": "4.4.1",
- "fastify": "5.0.0",
"fastify-multer": "^2.0.3",
- "fastify-raw-body": "5.0.0",
+ "fastify": "4.25.2",
+ "fastify-raw-body": "4.3.0",
"feed": "4.2.2",
- "file-type": "19.5.0",
- "fluent-ffmpeg": "2.1.3",
+ "file-type": "19.0.0",
+ "fluent-ffmpeg": "2.1.2",
"form-data": "4.0.0",
- "glob": "11.0.0",
- "got": "14.4.2",
- "happy-dom": "15.7.4",
+ "glob": "10.3.10",
+ "got": "14.1.0",
+ "happy-dom": "10.0.3",
"hpagent": "1.2.0",
- "htmlescape": "1.1.1",
- "http-link-header": "1.1.3",
- "ioredis": "5.4.1",
- "ip-cidr": "4.0.2",
- "ipaddr.js": "2.2.0",
- "is-svg": "5.1.0",
+ "http-link-header": "1.1.1",
+ "ioredis": "5.3.2",
+ "ip-cidr": "3.1.0",
+ "ipaddr.js": "2.1.0",
+ "is-svg": "5.0.0",
"js-yaml": "4.1.0",
- "jsdom": "24.1.1",
+ "jsdom": "23.2.0",
"json5": "2.2.3",
"jsonld": "8.3.2",
- "jsrsasign": "11.1.0",
- "juice": "11.0.0",
"megalodon": "workspace:*",
- "meilisearch": "0.42.0",
+ "jsrsasign": "11.0.0",
+ "meilisearch": "0.37.0",
"microformats-parser": "2.0.2",
"mime-types": "2.1.35",
"misskey-js": "workspace:*",
"misskey-reversi": "workspace:*",
"ms": "3.0.0-canary.1",
- "nanoid": "5.0.7",
+ "nanoid": "5.0.4",
"nested-property": "4.0.0",
"node-fetch": "3.3.2",
- "nodemailer": "6.9.15",
+ "nodemailer": "6.9.8",
"oauth": "0.10.0",
"oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14",
- "otpauth": "9.3.2",
+ "otpauth": "9.2.2",
"parse5": "7.1.2",
- "pg": "8.13.0",
+ "pg": "8.11.3",
"pkce-challenge": "4.1.0",
"probe-image-size": "7.2.3",
"promise-limit": "2.7.0",
- "proxy-addr": "^2.0.7",
- "psl": "^1.13.0",
- "pug": "3.0.3",
+ "pug": "3.0.2",
"punycode": "2.3.1",
- "qrcode": "1.5.4",
+ "pureimage": "0.3.17",
+ "qrcode": "1.5.3",
"random-seed": "0.3.0",
"ratelimiter": "3.4.1",
- "re2": "1.21.4",
+ "re2": "1.20.9",
"redis-lock": "0.1.4",
- "reflect-metadata": "0.2.2",
+ "reflect-metadata": "0.1.14",
"rename": "1.0.4",
"rss-parser": "3.13.0",
"rxjs": "7.8.1",
- "sanitize-html": "2.13.0",
+ "sanitize-html": "2.11.0",
"secure-json-parse": "2.7.0",
- "sharp": "0.33.5",
+ "sharp": "0.32.6",
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
- "systeminformation": "5.23.5",
+ "systeminformation": "5.21.24",
"tinycolor2": "1.6.0",
- "tmp": "0.2.3",
- "tsc-alias": "1.8.10",
+ "tmp": "0.2.1",
+ "tsc-alias": "1.8.8",
"tsconfig-paths": "4.2.0",
"typeorm": "0.3.20",
- "typescript": "5.6.2",
+ "typescript": "5.3.3",
"ulid": "2.3.0",
"uuid": "^9.0.1",
"vary": "1.1.2",
"web-push": "3.6.7",
- "ws": "8.18.0",
+ "ws": "8.16.0",
"xev": "3.0.2"
},
"devDependencies": {
"@jest/globals": "29.7.0",
- "@nestjs/platform-express": "10.4.3",
- "@simplewebauthn/types": "10.0.0",
- "@swc/jest": "0.2.36",
+ "@misskey-dev/eslint-plugin": "1.0.0",
+ "@nestjs/platform-express": "10.3.1",
+ "@simplewebauthn/types": "9.0.1",
+ "@swc/jest": "0.2.31",
"@types/accepts": "1.3.7",
"@types/archiver": "6.0.2",
"@types/bcryptjs": "2.4.6",
"@types/body-parser": "1.19.5",
"@types/color-convert": "2.0.3",
"@types/content-disposition": "0.5.8",
- "@types/fluent-ffmpeg": "2.1.26",
- "@types/htmlescape": "1.1.3",
- "@types/http-link-header": "1.0.7",
- "@types/jest": "29.5.13",
+ "@types/fluent-ffmpeg": "2.1.24",
+ "@types/http-link-header": "1.0.5",
+ "@types/jest": "29.5.11",
"@types/js-yaml": "4.0.9",
- "@types/jsdom": "21.1.7",
- "@types/jsonld": "1.5.15",
- "@types/jsrsasign": "10.5.14",
+ "@types/jsdom": "21.1.6",
+ "@types/jsonld": "1.5.13",
+ "@types/jsrsasign": "10.5.12",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
- "@types/node": "20.14.12",
- "@types/nodemailer": "6.4.16",
- "@types/oauth": "0.9.5",
- "@types/oauth2orize": "1.11.5",
+ "@types/node": "20.11.17",
+ "@types/node-fetch": "3.0.3",
+ "@types/nodemailer": "6.4.14",
+ "@types/oauth": "0.9.4",
+ "@types/oauth2orize": "1.11.3",
"@types/oauth2orize-pkce": "0.1.2",
- "@types/pg": "8.11.10",
- "@types/proxy-addr": "^2.0.3",
+ "@types/pg": "8.11.0",
"@types/pug": "2.0.10",
- "@types/punycode": "2.1.4",
+ "@types/punycode": "2.1.3",
"@types/qrcode": "1.5.5",
"@types/random-seed": "0.3.5",
"@types/ratelimiter": "3.4.6",
"@types/rename": "1.0.7",
- "@types/sanitize-html": "2.13.0",
- "@types/semver": "7.5.8",
+ "@types/sanitize-html": "2.9.5",
+ "@types/semver": "7.5.6",
"@types/simple-oauth2": "5.0.7",
"@types/sinonjs__fake-timers": "8.1.5",
"@types/tinycolor2": "1.4.6",
@@ -234,18 +226,19 @@
"@types/uuid": "^9.0.4",
"@types/vary": "1.1.3",
"@types/web-push": "3.6.3",
- "@types/ws": "8.5.12",
- "@typescript-eslint/eslint-plugin": "7.17.0",
- "@typescript-eslint/parser": "7.17.0",
- "aws-sdk-client-mock": "4.0.1",
+ "@types/ws": "8.5.10",
+ "@typescript-eslint/eslint-plugin": "6.18.1",
+ "@typescript-eslint/parser": "6.18.1",
+ "aws-sdk-client-mock": "3.0.1",
"cross-env": "7.0.3",
- "eslint-plugin-import": "2.30.0",
- "execa": "9.4.0",
- "fkill": "9.0.0",
+ "eslint": "8.56.0",
+ "eslint-plugin-import": "2.29.1",
+ "execa": "8.0.1",
+ "fkill": "^9.0.0",
"jest": "29.7.0",
"jest-mock": "29.7.0",
- "nodemon": "3.1.7",
+ "nodemon": "3.0.3",
"pid-port": "1.0.0",
- "simple-oauth2": "5.1.0"
+ "simple-oauth2": "5.0.0"
}
}
diff --git a/packages/backend/scripts/check_connect.js b/packages/backend/scripts/check_connect.js
deleted file mode 100644
index 17b198ef62..0000000000
--- a/packages/backend/scripts/check_connect.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import Redis from 'ioredis';
-import { loadConfig } from '../built/config.js';
-import { createPostgresDataSource } from '../built/postgres.js';
-
-const config = loadConfig();
-
-// createPostgresDataSource handels primaries and replicas automatically.
-// usually, it only opens connections first use, so we force it using
-// .initialize()
-async function connectToPostgres(){
- const source = createPostgresDataSource(config);
- await source.initialize();
- await source.destroy();
-}
-
-// Connect to all redis servers
-async function connectToRedis(redisOptions) {
- return await new Promise(async (resolve, reject) => {
- const redis = new Redis({
- ...redisOptions,
- lazyConnect: true,
- reconnectOnError: false,
- showFriendlyErrorStack: true,
- });
- redis.on('error', e => reject(e));
-
- try {
- await redis.connect();
- resolve();
-
- } catch (e) {
- reject(e);
-
- } finally {
- redis.disconnect(false);
- }
- });
-}
-
-// If not all of these are defined, the default one gets reused.
-// so we use a Set to only try connecting once to each **uniq** redis.
-const promises = Array
- .from(new Set([
- config.redis,
- config.redisForPubsub,
- config.redisForJobQueue,
- config.redisForTimelines,
- config.redisForReactions,
- ]))
- .map(connectToRedis)
- .concat([
- connectToPostgres()
- ]);
-
-await Promise.all(promises);
diff --git a/packages/backend/scripts/dev.mjs b/packages/backend/scripts/dev.mjs
deleted file mode 100644
index a3e0558abd..0000000000
--- a/packages/backend/scripts/dev.mjs
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { execa, execaNode } from 'execa';
-
-/** @type {import('execa').ExecaChildProcess | undefined} */
-let backendProcess;
-
-async function execBuildAssets() {
- await execa('pnpm', ['run', 'build-assets'], {
- cwd: '../../',
- stdout: process.stdout,
- stderr: process.stderr,
- })
-}
-
-function execStart() {
- // pnpm run start を呼び出したいが、windowsだとプロセスグループ単位でのkillが出来ずゾンビプロセス化するので
- // 上記と同等の動きをするコマンドで子・孫プロセスを作らないようにしたい
- backendProcess = execaNode('./built/boot/entry.js', [], {
- stdout: process.stdout,
- stderr: process.stderr,
- env: {
- 'NODE_ENV': 'development',
- },
- });
-}
-
-async function killProc() {
- if (backendProcess) {
- backendProcess.catch(() => {}); // backendProcess.kill()によって発生する例外を無視するためにcatch()を呼び出す
- backendProcess.kill();
- await new Promise(resolve => backendProcess.on('exit', resolve));
- backendProcess = undefined;
- }
-}
-
-(async () => {
- execaNode(
- './node_modules/nodemon/bin/nodemon.js',
- [
- '-w', 'src',
- '-e', 'ts,js,mjs,cjs,json',
- '--exec', 'pnpm', 'run', 'build',
- ],
- {
- stdio: [process.stdin, process.stdout, process.stderr, 'ipc'],
- serialization: "json",
- })
- .on('message', async (message) => {
- if (message.type === 'exit') {
- // かならずbuild->build-assetsの順番で呼び出したいので、
- // 少々トリッキーだがnodemonからのexitイベントを利用してbuild-assets->startを行う。
- // pnpm restartをbuildが終わる前にbuild-assetsが動いてしまうので、バラバラに呼び出す必要がある
-
- await killProc();
- await execBuildAssets();
- execStart();
- }
- })
-})();
diff --git a/packages/backend/scripts/generate_api_json.js b/packages/backend/scripts/generate_api_json.js
deleted file mode 100644
index 798e243004..0000000000
--- a/packages/backend/scripts/generate_api_json.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { execa } from 'execa';
-import { writeFileSync, existsSync } from "node:fs";
-
-async function main() {
- if (!process.argv.includes('--no-build')) {
- await execa('pnpm', ['run', 'build'], {
- stdout: process.stdout,
- stderr: process.stderr,
- });
- }
-
- if (!existsSync('./built')) {
- throw new Error('`built` directory does not exist.');
- }
-
- /** @type {import('../src/config.js')} */
- const { loadConfig } = await import('../built/config.js');
-
- /** @type {import('../src/server/api/openapi/gen-spec.js')} */
- const { genOpenapiSpec } = await import('../built/server/api/openapi/gen-spec.js');
-
- const config = loadConfig();
- const spec = genOpenapiSpec(config, true);
-
- writeFileSync('./built/api.json', JSON.stringify(spec), 'utf-8');
-}
-
-main().catch(e => {
- console.error(e);
- process.exit(1);
-});
diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts
index 6ae8ccfbb3..09971e8ca0 100644
--- a/packages/backend/src/GlobalModule.ts
+++ b/packages/backend/src/GlobalModule.ts
@@ -13,8 +13,6 @@ import { createPostgresDataSource } from './postgres.js';
import { RepositoryModule } from './models/RepositoryModule.js';
import { allSettled } from './misc/promise-tracker.js';
import type { Provider, OnApplicationShutdown } from '@nestjs/common';
-import { MiMeta } from '@/models/Meta.js';
-import { GlobalEvents } from './core/GlobalEventService.js';
const $config: Provider = {
provide: DI.config,
@@ -80,76 +78,11 @@ const $redisForTimelines: Provider = {
inject: [DI.config],
};
-const $redisForReactions: Provider = {
- provide: DI.redisForReactions,
- useFactory: (config: Config) => {
- return new Redis.Redis(config.redisForReactions);
- },
- inject: [DI.config],
-};
-
-const $meta: Provider = {
- provide: DI.meta,
- useFactory: async (db: DataSource, redisForSub: Redis.Redis) => {
- const meta = await db.transaction(async transactionalEntityManager => {
- // 過去のバグでレコードが複数出来てしまっている可能性があるので新しいIDを優先する
- const metas = await transactionalEntityManager.find(MiMeta, {
- order: {
- id: 'DESC',
- },
- });
-
- const meta = metas[0];
-
- if (meta) {
- return meta;
- } else {
- // metaが空のときfetchMetaが同時に呼ばれるとここが同時に呼ばれてしまうことがあるのでフェイルセーフなupsertを使う
- const saved = await transactionalEntityManager
- .upsert(
- MiMeta,
- {
- id: 'x',
- },
- ['id'],
- )
- .then((x) => transactionalEntityManager.findOneByOrFail(MiMeta, x.identifiers[0]));
-
- return saved;
- }
- });
-
- async function onMessage(_: string, data: string): Promise {
- const obj = JSON.parse(data);
-
- if (obj.channel === 'internal') {
- const { type, body } = obj.message as GlobalEvents['internal']['payload'];
- switch (type) {
- case 'metaUpdated': {
- for (const key in body.after) {
- (meta as any)[key] = (body.after as any)[key];
- }
- meta.proxyAccount = null; // joinなカラムは通常取ってこないので
- break;
- }
- default:
- break;
- }
- }
- }
-
- redisForSub.on('message', onMessage);
-
- return meta;
- },
- inject: [DI.db, DI.redisForSub],
-};
-
@Global()
@Module({
imports: [RepositoryModule],
- providers: [$config, $db, $meta, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions],
- exports: [$config, $db, $meta, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, $redisForReactions, RepositoryModule],
+ providers: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines],
+ exports: [$config, $db, $meilisearch, $redis, $redisForPub, $redisForSub, $redisForTimelines, RepositoryModule],
})
export class GlobalModule implements OnApplicationShutdown {
constructor(
@@ -158,7 +91,6 @@ export class GlobalModule implements OnApplicationShutdown {
@Inject(DI.redisForPub) private redisForPub: Redis.Redis,
@Inject(DI.redisForSub) private redisForSub: Redis.Redis,
@Inject(DI.redisForTimelines) private redisForTimelines: Redis.Redis,
- @Inject(DI.redisForReactions) private redisForReactions: Redis.Redis,
) { }
public async dispose(): Promise {
@@ -171,7 +103,6 @@ export class GlobalModule implements OnApplicationShutdown {
this.redisForPub.disconnect(),
this.redisForSub.disconnect(),
this.redisForTimelines.disconnect(),
- this.redisForReactions.disconnect(),
]);
}
diff --git a/packages/backend/src/NestLogger.ts b/packages/backend/src/NestLogger.ts
index d0be19664f..80f1f7a024 100644
--- a/packages/backend/src/NestLogger.ts
+++ b/packages/backend/src/NestLogger.ts
@@ -7,7 +7,7 @@ import { LoggerService } from '@nestjs/common';
import Logger from '@/logger.js';
const logger = new Logger('core', 'cyan');
-const nestLogger = logger.createSubLogger('nest', 'green');
+const nestLogger = logger.createSubLogger('nest', 'green', false);
export class NestLogger implements LoggerService {
/**
diff --git a/packages/backend/src/boot/entry.ts b/packages/backend/src/boot/entry.ts
index 56128a7ab9..ae74a43c84 100644
--- a/packages/backend/src/boot/entry.ts
+++ b/packages/backend/src/boot/entry.ts
@@ -15,7 +15,6 @@ import Logger from '@/logger.js';
import { envOption } from '../env.js';
import { masterMain } from './master.js';
import { workerMain } from './worker.js';
-import { readyRef } from './ready.js';
import 'reflect-metadata';
@@ -25,7 +24,7 @@ Error.stackTraceLimit = Infinity;
EventEmitter.defaultMaxListeners = 128;
const logger = new Logger('core', 'cyan');
-const clusterLogger = logger.createSubLogger('cluster', 'orange');
+const clusterLogger = logger.createSubLogger('cluster', 'orange', false);
const ev = new Xev();
// We wrap this in a main function, that gets called,
@@ -76,12 +75,10 @@ async function main() {
ev.mount();
}
}
- if (cluster.isWorker) {
+ if (cluster.isWorker || envOption.disableClustering) {
await workerMain();
}
- readyRef.value = true;
-
// ユニットテスト時にMisskeyが子プロセスで起動された時のため
// それ以外のときは process.send は使えないので弾く
if (process.send) {
diff --git a/packages/backend/src/boot/master.ts b/packages/backend/src/boot/master.ts
index 3559816e96..aafd43beea 100644
--- a/packages/backend/src/boot/master.ts
+++ b/packages/backend/src/boot/master.ts
@@ -10,8 +10,6 @@ import * as os from 'node:os';
import cluster from 'node:cluster';
import chalk from 'chalk';
import chalkTemplate from 'chalk-template';
-import * as Sentry from '@sentry/node';
-import { nodeProfilingIntegration } from '@sentry/profiling-node';
import Logger from '@/logger.js';
import { loadConfig } from '@/config.js';
import type { Config } from '@/config.js';
@@ -25,7 +23,7 @@ const _dirname = dirname(_filename);
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8'));
const logger = new Logger('core', 'cyan');
-const bootLogger = logger.createSubLogger('boot', 'magenta');
+const bootLogger = logger.createSubLogger('boot', 'magenta', false);
const themeColor = chalk.hex('#86b300');
@@ -44,7 +42,7 @@ function greet() {
//#endregion
console.log(' Sharkey is an open-source decentralized microblogging platform.');
- console.log(chalk.rgb(255, 136, 0)(' If you like Sharkey, please donate to support development. https://opencollective.com/sharkey'));
+ console.log(chalk.rgb(255, 136, 0)(' If you like Sharkey, please donate to support development. https://ko-fi.com/transfem'));
console.log('');
console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`);
@@ -76,24 +74,6 @@ export async function masterMain() {
bootLogger.succ('Sharkey initialized');
- if (config.sentryForBackend) {
- Sentry.init({
- integrations: [
- ...(config.sentryForBackend.enableNodeProfiling ? [nodeProfilingIntegration()] : []),
- ],
-
- // Performance Monitoring
- tracesSampleRate: 1.0, // Capture 100% of the transactions
-
- // Set sampling rate for profiling - this is relative to tracesSampleRate
- profilesSampleRate: 1.0,
-
- maxBreadcrumbs: 0,
-
- ...config.sentryForBackend.options,
- });
- }
-
if (envOption.disableClustering) {
if (envOption.onlyServer) {
await server();
@@ -112,11 +92,6 @@ export async function masterMain() {
await server();
}
- if (config.clusterLimit === 0) {
- bootLogger.error("Configuration error: we can't create workers, `config.clusterLimit` is 0 (if you don't want to use clustering, set the environment variable `MK_DISABLE_CLUSTERING` to a non-empty value instead)", null, true);
- process.exit(1);
- }
-
await spawnWorkers(config.clusterLimit);
}
@@ -185,10 +160,7 @@ async function connectDb(): Promise {
*/
async function spawnWorkers(limit = 1) {
- const cpuCount = os.cpus().length;
- // in some weird environments, node can't count the CPUs; we trust the config in those cases
- const workers = cpuCount === 0 ? limit : Math.min(limit, cpuCount);
-
+ const workers = Math.min(limit, os.cpus().length);
bootLogger.info(`Starting ${workers} worker${workers === 1 ? '' : 's'}...`);
await Promise.all([...Array(workers)].map(spawnWorker));
bootLogger.succ('All workers started');
diff --git a/packages/backend/src/boot/worker.ts b/packages/backend/src/boot/worker.ts
index 5d4a15b29f..d4a7cd56e5 100644
--- a/packages/backend/src/boot/worker.ts
+++ b/packages/backend/src/boot/worker.ts
@@ -4,36 +4,13 @@
*/
import cluster from 'node:cluster';
-import * as Sentry from '@sentry/node';
-import { nodeProfilingIntegration } from '@sentry/profiling-node';
import { envOption } from '@/env.js';
-import { loadConfig } from '@/config.js';
import { jobQueue, server } from './common.js';
/**
* Init worker process
*/
export async function workerMain() {
- const config = loadConfig();
-
- if (config.sentryForBackend) {
- Sentry.init({
- integrations: [
- ...(config.sentryForBackend.enableNodeProfiling ? [nodeProfilingIntegration()] : []),
- ],
-
- // Performance Monitoring
- tracesSampleRate: 1.0, // Capture 100% of the transactions
-
- // Set sampling rate for profiling - this is relative to tracesSampleRate
- profilesSampleRate: 1.0,
-
- maxBreadcrumbs: 0,
-
- ...config.sentryForBackend.options,
- });
- }
-
if (envOption.onlyServer) {
await server();
} else if (envOption.onlyQueue) {
diff --git a/packages/backend/src/config.ts b/packages/backend/src/config.ts
index 9cac058d96..c99bc7ae03 100644
--- a/packages/backend/src/config.ts
+++ b/packages/backend/src/config.ts
@@ -8,14 +8,12 @@ import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
import * as yaml from 'js-yaml';
import { globSync } from 'glob';
-import * as Sentry from '@sentry/node';
import type { RedisOptions } from 'ioredis';
type RedisOptionsSource = Partial & {
- host?: string;
- port?: number;
+ host: string;
+ port: number;
family?: number;
- path?: string,
pass: string;
db?: number;
prefix?: string;
@@ -25,7 +23,7 @@ type RedisOptionsSource = Partial & {
* 設定ファイルの型
*/
type Source = {
- url?: string;
+ url: string;
port?: number;
socket?: string;
chmodSocket?: string;
@@ -33,9 +31,9 @@ type Source = {
db: {
host: string;
port: number;
- db?: string;
- user?: string;
- pass?: string;
+ db: string;
+ user: string;
+ pass: string;
disableCache?: boolean;
extra?: { [x: string]: string };
};
@@ -51,7 +49,6 @@ type Source = {
redisForPubsub?: RedisOptionsSource;
redisForJobQueue?: RedisOptionsSource;
redisForTimelines?: RedisOptionsSource;
- redisForReactions?: RedisOptionsSource;
meilisearch?: {
host: string;
port: string;
@@ -60,8 +57,6 @@ type Source = {
index: string;
scope?: 'local' | 'global' | string[];
};
- sentryForBackend?: { options: Partial; enableNodeProfiling: boolean; };
- sentryForFrontend?: { options: Partial };
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
@@ -73,11 +68,6 @@ type Source = {
maxFileSize?: number;
maxNoteLength?: number;
- maxCwLength?: number;
- maxRemoteCwLength?: number;
- maxRemoteNoteLength?: number;
- maxAltTextLength?: number;
- maxRemoteAltTextLength?: number;
clusterLimit?: number;
@@ -102,20 +92,12 @@ type Source = {
customMOTD?: string[];
signToActivityPubGet?: boolean;
- attachLdSignatureForRelays?: boolean;
checkActivityPubGetSignature?: boolean;
perChannelMaxNoteCacheCount?: number;
perUserNotificationsMaxCount?: number;
deactivateAntennaThreshold?: number;
-
- import?: {
- downloadTimeout: number;
- maxFileSize: number;
- };
-
pidFile: string;
- filePermissionBits?: string;
};
export type Config = {
@@ -153,13 +135,8 @@ export type Config = {
proxySmtp: string | undefined;
proxyBypassHosts: string[] | undefined;
allowedPrivateNetworks: string[] | undefined;
- maxFileSize: number;
+ maxFileSize: number | undefined;
maxNoteLength: number;
- maxRemoteNoteLength: number;
- maxCwLength: number;
- maxRemoteCwLength: number;
- maxAltTextLength: number;
- maxRemoteAltTextLength: number;
clusterLimit: number | undefined;
id: string;
outgoingAddress: string | undefined;
@@ -175,7 +152,6 @@ export type Config = {
proxyRemoteFiles: boolean | undefined;
customMOTD: string[] | undefined;
signToActivityPubGet: boolean;
- attachLdSignatureForRelays: boolean;
checkActivityPubGetSignature: boolean | undefined;
version: string;
@@ -189,10 +165,8 @@ export type Config = {
authUrl: string;
driveUrl: string;
userAgent: string;
- frontendEntry: string;
- frontendManifestExists: boolean;
- frontendEmbedEntry: string;
- frontendEmbedManifestExists: boolean;
+ clientEntry: string;
+ clientManifestExists: boolean;
mediaProxy: string;
externalMediaProxyEnabled: boolean;
videoThumbnailGenerator: string | null;
@@ -200,20 +174,10 @@ export type Config = {
redisForPubsub: RedisOptions & RedisOptionsSource;
redisForJobQueue: RedisOptions & RedisOptionsSource;
redisForTimelines: RedisOptions & RedisOptionsSource;
- redisForReactions: RedisOptions & RedisOptionsSource;
- sentryForBackend: { options: Partial; enableNodeProfiling: boolean; } | undefined;
- sentryForFrontend: { options: Partial } | undefined;
perChannelMaxNoteCacheCount: number;
perUserNotificationsMaxCount: number;
deactivateAntennaThreshold: number;
-
- import: {
- downloadTimeout: number;
- maxFileSize: number;
- } | undefined;
-
pidFile: string;
- filePermissionBits?: string;
};
const _filename = fileURLToPath(import.meta.url);
@@ -235,44 +199,26 @@ const path = process.env.MISSKEY_CONFIG_YML
export function loadConfig(): Config {
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../built/meta.json`, 'utf-8'));
-
- const frontendManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_vite_/manifest.json');
- const frontendEmbedManifestExists = fs.existsSync(_dirname + '/../../../built/_frontend_embed_vite_/manifest.json');
- const frontendManifest = frontendManifestExists ?
- JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_vite_/manifest.json`, 'utf-8'))
+ const clientManifestExists = fs.existsSync(`${_dirname}/../../../built/_vite_/manifest.json`);
+ const clientManifest = clientManifestExists ?
+ JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_vite_/manifest.json`, 'utf-8'))
: { 'src/_boot_.ts': { file: 'src/_boot_.ts' } };
- const frontendEmbedManifest = frontendEmbedManifestExists ?
- JSON.parse(fs.readFileSync(`${_dirname}/../../../built/_frontend_embed_vite_/manifest.json`, 'utf-8'))
- : { 'src/boot.ts': { file: 'src/boot.ts' } };
- const configFiles = globSync(path).sort();
-
- if (configFiles.length === 0
- && !process.env['MK_WARNED_ABOUT_CONFIG']) {
- console.log('No config files loaded, check if this is intentional');
- process.env['MK_WARNED_ABOUT_CONFIG'] = '1';
- }
-
- const config = configFiles.map(path => fs.readFileSync(path, 'utf-8'))
+ const config = globSync(path).sort()
+ .map(path => fs.readFileSync(path, 'utf-8'))
.map(contents => yaml.load(contents) as Source)
.reduce(
(acc: Source, cur: Source) => Object.assign(acc, cur),
{} as Source,
) as Source;
- applyEnvOverrides(config);
-
- const url = tryCreateUrl(config.url ?? process.env.MISSKEY_URL ?? '');
+ const url = tryCreateUrl(config.url);
const version = meta.version;
const host = url.host;
const hostname = url.hostname;
const scheme = url.protocol.replace(/:$/, '');
const wsScheme = scheme.replace('http', 'ws');
- const dbDb = config.db.db ?? process.env.DATABASE_DB ?? '';
- const dbUser = config.db.user ?? process.env.DATABASE_USER ?? '';
- const dbPass = config.db.pass ?? process.env.DATABASE_PASSWORD ?? '';
-
const externalMediaProxy = config.mediaProxy ?
config.mediaProxy.endsWith('/') ? config.mediaProxy.substring(0, config.mediaProxy.length - 1) : config.mediaProxy
: null;
@@ -283,7 +229,7 @@ export function loadConfig(): Config {
version,
publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl,
url: url.origin,
- port: config.port ?? parseInt(process.env.PORT ?? '3000', 10),
+ port: config.port ?? parseInt(process.env.PORT ?? '', 10),
socket: config.socket,
chmodSocket: config.chmodSocket,
disableHsts: config.disableHsts,
@@ -295,7 +241,7 @@ export function loadConfig(): Config {
apiUrl: `${scheme}://${host}/api`,
authUrl: `${scheme}://${host}/auth`,
driveUrl: `${scheme}://${host}/files`,
- db: { ...config.db, db: dbDb, user: dbUser, pass: dbPass },
+ db: config.db,
dbReplications: config.dbReplications,
dbSlaves: config.dbSlaves,
meilisearch: config.meilisearch,
@@ -303,21 +249,13 @@ export function loadConfig(): Config {
redisForPubsub: config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, host) : redis,
redisForJobQueue: config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, host) : redis,
redisForTimelines: config.redisForTimelines ? convertRedisOptions(config.redisForTimelines, host) : redis,
- redisForReactions: config.redisForReactions ? convertRedisOptions(config.redisForReactions, host) : redis,
- sentryForBackend: config.sentryForBackend,
- sentryForFrontend: config.sentryForFrontend,
id: config.id,
proxy: config.proxy,
proxySmtp: config.proxySmtp,
proxyBypassHosts: config.proxyBypassHosts,
allowedPrivateNetworks: config.allowedPrivateNetworks,
- maxFileSize: config.maxFileSize ?? 262144000,
+ maxFileSize: config.maxFileSize,
maxNoteLength: config.maxNoteLength ?? 3000,
- maxRemoteNoteLength: config.maxRemoteNoteLength ?? 100000,
- maxCwLength: config.maxCwLength ?? 500,
- maxRemoteCwLength: config.maxRemoteCwLength ?? 5000,
- maxAltTextLength: config.maxAltTextLength ?? 20000,
- maxRemoteAltTextLength: config.maxRemoteAltTextLength ?? 100000,
clusterLimit: config.clusterLimit,
outgoingAddress: config.outgoingAddress,
outgoingAddressFamily: config.outgoingAddressFamily,
@@ -332,7 +270,6 @@ export function loadConfig(): Config {
proxyRemoteFiles: config.proxyRemoteFiles,
customMOTD: config.customMOTD,
signToActivityPubGet: config.signToActivityPubGet ?? true,
- attachLdSignatureForRelays: config.attachLdSignatureForRelays ?? true,
checkActivityPubGetSignature: config.checkActivityPubGetSignature,
mediaProxy: externalMediaProxy ?? internalMediaProxy,
externalMediaProxyEnabled: externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy,
@@ -340,16 +277,12 @@ export function loadConfig(): Config {
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
: null,
userAgent: `Misskey/${version} (${config.url})`,
- frontendEntry: frontendManifest['src/_boot_.ts'],
- frontendManifestExists: frontendManifestExists,
- frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'],
- frontendEmbedManifestExists: frontendEmbedManifestExists,
+ clientEntry: clientManifest['src/_boot_.ts'],
+ clientManifestExists: clientManifestExists,
perChannelMaxNoteCacheCount: config.perChannelMaxNoteCacheCount ?? 1000,
perUserNotificationsMaxCount: config.perUserNotificationsMaxCount ?? 500,
deactivateAntennaThreshold: config.deactivateAntennaThreshold ?? (1000 * 60 * 60 * 24 * 7),
- import: config.import,
pidFile: config.pidFile,
- filePermissionBits: config.filePermissionBits,
};
}
@@ -371,132 +304,3 @@ function convertRedisOptions(options: RedisOptionsSource, host: string): RedisOp
db: options.db ?? 0,
};
}
-
-/*
- this function allows overriding any string-valued config option with
- a sensible-named environment variable
-
- e.g. `MK_CONFIG_MEILISEARCH_APIKEY` sets `config.meilisearch.apikey`
-
- you can also override a single `dbSlave` value,
- e.g. `MK_CONFIG_DBSLAVES_1_PASS` sets the password for the 2nd
- database replica (the first one would be
- `MK_CONFIG_DBSLAVES_0_PASS`); in this case, `config.dbSlaves` must
- be set to an array of the right size already in the file
-
- values can be read from files, too: setting `MK_DB_PASS_FILE` to
- `/some/file` would set the main database password to the contents of
- `/some/file` (trimmed of whitespaces)
- */
-function applyEnvOverrides(config: Source) {
- // these inner functions recurse through the config structure, using
- // the given steps, building the env variable name
-
- function _apply_top(steps: (string | string[] | number | number[])[]) {
- _walk('', [], steps);
- }
-
- function _walk(name: string, path: (string | number)[], steps: (string | string[] | number | number[])[]) {
- // are there more steps after this one? recurse
- if (steps.length > 1) {
- const thisStep = steps.shift();
- if (thisStep === null || thisStep === undefined) return;
-
- // if a step is not a simple value, iterate through it
- if (typeof thisStep === 'object') {
- for (const thisOneStep of thisStep) {
- _descend(name, path, thisOneStep, steps);
- }
- } else {
- _descend(name, path, thisStep, steps);
- }
-
- // the actual override has happened at the bottom of the
- // recursion, we're done
- return;
- }
-
- // this is the last step, same thing as above
- const lastStep = steps[0];
-
- if (typeof lastStep === 'object') {
- for (const lastOneStep of lastStep) {
- _lastBit(name, path, lastOneStep);
- }
- } else {
- _lastBit(name, path, lastStep);
- }
- }
-
- function _step2name(step: string|number): string {
- return step.toString().replaceAll(/[^a-z0-9]+/gi, '').toUpperCase();
- }
-
- // this recurses down, bailing out if there's no config to override
- function _descend(name: string, path: (string | number)[], thisStep: string | number, steps: (string | string[] | number | number[])[]) {
- name = `${name}${_step2name(thisStep)}_`;
- path = [...path, thisStep];
- _walk(name, path, steps);
- }
-
- // this is the bottom of the recursion: look at the environment and
- // set the value
- function _lastBit(name: string, path: (string | number)[], lastStep: string | number) {
- name = `MK_CONFIG_${name}${_step2name(lastStep)}`;
-
- const val = process.env[name];
- if (val !== null && val !== undefined) {
- _assign(path, lastStep, val);
- }
-
- const file = process.env[`${name}_FILE`];
- if (file) {
- _assign(path, lastStep, fs.readFileSync(file, 'utf-8').trim());
- }
- }
-
- const alwaysStrings: { [key in string]?: boolean } = {
- 'chmodSocket': true,
- 'filePermissionBits': true,
- };
-
- function _assign(path: (string | number)[], lastStep: string | number, value: string) {
- let thisConfig = config as any;
- for (const step of path) {
- if (!thisConfig[step]) {
- thisConfig[step] = {};
- }
- thisConfig = thisConfig[step];
- }
-
- if (!alwaysStrings[lastStep]) {
- if (value.match(/^[0-9]+$/)) {
- thisConfig[lastStep] = parseInt(value);
- return;
- } else if (value.match(/^(true|false)$/i)) {
- thisConfig[lastStep] = !!value.match(/^true$/i);
- return;
- }
- }
-
- thisConfig[lastStep] = value;
- }
-
- // these are all the settings that can be overridden
-
- _apply_top([['url', 'port', 'socket', 'chmodSocket', 'disableHsts', 'id', 'dbReplications']]);
- _apply_top(['db', ['host', 'port', 'db', 'user', 'pass', 'disableCache']]);
- _apply_top(['dbSlaves', Array.from((config.dbSlaves ?? []).keys()), ['host', 'port', 'db', 'user', 'pass']]);
- _apply_top([
- ['redis', 'redisForPubsub', 'redisForJobQueue', 'redisForTimelines', 'redisForReactions'],
- ['host', 'port', 'username', 'pass', 'db', 'prefix'],
- ]);
- _apply_top(['meilisearch', ['host', 'port', 'apikey', 'ssl', 'index', 'scope']]);
- _apply_top([['sentryForFrontend', 'sentryForBackend'], 'options', ['dsn', 'profileSampleRate', 'serverName', 'includeLocalVariables', 'proxy', 'keepAlive', 'caCerts']]);
- _apply_top(['sentryForBackend', 'enableNodeProfiling']);
- _apply_top([['clusterLimit', 'deliverJobConcurrency', 'inboxJobConcurrency', 'relashionshipJobConcurrency', 'deliverJobPerSec', 'inboxJobPerSec', 'relashionshipJobPerSec', 'deliverJobMaxAttempts', 'inboxJobMaxAttempts']]);
- _apply_top([['outgoingAddress', 'outgoingAddressFamily', 'proxy', 'proxySmtp', 'mediaProxy', 'proxyRemoteFiles', 'videoThumbnailGenerator']]);
- _apply_top([['maxFileSize', 'maxNoteLength', 'maxRemoteNoteLength', 'maxAltTextLength', 'maxRemoteAltTextLength', 'pidFile', 'filePermissionBits']]);
- _apply_top(['import', ['downloadTimeout', 'maxFileSize']]);
- _apply_top([['signToActivityPubGet', 'checkActivityPubGetSignature']]);
-}
diff --git a/packages/backend/src/const.ts b/packages/backend/src/const.ts
index adb0a63ad7..02c27779ca 100644
--- a/packages/backend/src/const.ts
+++ b/packages/backend/src/const.ts
@@ -3,10 +3,26 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+export const MAX_NOTE_TEXT_LENGTH = 3000;
+
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
-export const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16;
+//#region hard limits
+// If you change DB_* values, you must also change the DB schema.
+
+/**
+ * Maximum note text length that can be stored in DB.
+ * Surrogate pairs count as one
+ */
+export const DB_MAX_NOTE_TEXT_LENGTH = 8192;
+
+/**
+ * Maximum image description length that can be stored in DB.
+ * Surrogate pairs count as one
+ */
+export const DB_MAX_IMAGE_COMMENT_LENGTH = 8192;
+//#endregion
// ブラウザで直接表示することを許可するファイルの種類のリスト
// ここに含まれないものは application/octet-stream としてレスポンスされる
diff --git a/packages/backend/src/core/AbuseReportNotificationService.ts b/packages/backend/src/core/AbuseReportNotificationService.ts
deleted file mode 100644
index fe2c63e7d6..0000000000
--- a/packages/backend/src/core/AbuseReportNotificationService.ts
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable, type OnApplicationShutdown } from '@nestjs/common';
-import { Brackets, In, IsNull, Not } from 'typeorm';
-import * as Redis from 'ioredis';
-import sanitizeHtml from 'sanitize-html';
-import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
-import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js';
-import type {
- AbuseReportNotificationRecipientRepository,
- MiAbuseReportNotificationRecipient,
- MiAbuseUserReport,
- MiMeta,
- MiUser,
-} from '@/models/_.js';
-import { EmailService } from '@/core/EmailService.js';
-import { RoleService } from '@/core/RoleService.js';
-import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { SystemWebhookService } from '@/core/SystemWebhookService.js';
-import { IdService } from './IdService.js';
-
-@Injectable()
-export class AbuseReportNotificationService implements OnApplicationShutdown {
- constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
- @Inject(DI.abuseReportNotificationRecipientRepository)
- private abuseReportNotificationRecipientRepository: AbuseReportNotificationRecipientRepository,
-
- @Inject(DI.redisForSub)
- private redisForSub: Redis.Redis,
-
- private idService: IdService,
- private roleService: RoleService,
- private systemWebhookService: SystemWebhookService,
- private emailService: EmailService,
- private moderationLogService: ModerationLogService,
- private globalEventService: GlobalEventService,
- ) {
- this.redisForSub.on('message', this.onMessage);
- }
-
- /**
- * 管理者用Redisイベントを用いて{@link abuseReports}の内容を管理者各位に通知する.
- * 通知先ユーザは{@link getModeratorIds}の取得結果に依る.
- *
- * @see RoleService.getModeratorIds
- * @see GlobalEventService.publishAdminStream
- */
- @bindThis
- public async notifyAdminStream(abuseReports: MiAbuseUserReport[]) {
- if (abuseReports.length <= 0) {
- return;
- }
-
- const moderatorIds = await this.roleService.getModeratorIds(true, true);
-
- for (const moderatorId of moderatorIds) {
- for (const abuseReport of abuseReports) {
- this.globalEventService.publishAdminStream(
- moderatorId,
- 'newAbuseUserReport',
- {
- id: abuseReport.id,
- targetUserId: abuseReport.targetUserId,
- reporterId: abuseReport.reporterId,
- comment: abuseReport.comment,
- },
- );
- }
- }
- }
-
- /**
- * Mailを用いて{@link abuseReports}の内容を管理者各位に通知する.
- * メールアドレスの送信先は以下の通り.
- * - モデレータ権限所有者ユーザ(設定画面からメールアドレスの設定を行っているユーザに限る)
- * - metaテーブルに設定されているメールアドレス
- *
- * @see EmailService.sendEmail
- */
- @bindThis
- public async notifyMail(abuseReports: MiAbuseUserReport[]) {
- if (abuseReports.length <= 0) {
- return;
- }
-
- const recipientEMailAddresses = await this.fetchEMailRecipients().then(it => it
- .filter(it => it.isActive && it.userProfile?.emailVerified)
- .map(it => it.userProfile?.email)
- .filter(x => x != null),
- );
-
- recipientEMailAddresses.push(
- ...(this.meta.email ? [this.meta.email] : []),
- );
-
- if (recipientEMailAddresses.length <= 0) {
- return;
- }
-
- for (const mailAddress of recipientEMailAddresses) {
- await Promise.all(
- abuseReports.map(it => {
- // TODO: 送信処理はJobQueue化したい
- return this.emailService.sendEmail(
- mailAddress,
- 'New Abuse Report',
- sanitizeHtml(it.comment),
- sanitizeHtml(it.comment),
- );
- }),
- );
- }
- }
-
- /**
- * SystemWebhookを用いて{@link abuseReports}の内容を管理者各位に通知する.
- * ここではJobQueueへのエンキューのみを行うため、即時実行されない.
- *
- * @see SystemWebhookService.enqueueSystemWebhook
- */
- @bindThis
- public async notifySystemWebhook(
- abuseReports: MiAbuseUserReport[],
- type: 'abuseReport' | 'abuseReportResolved',
- ) {
- if (abuseReports.length <= 0) {
- return;
- }
-
- const recipientWebhookIds = await this.fetchWebhookRecipients()
- .then(it => it
- .filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook')
- .map(it => it.systemWebhookId)
- .filter(x => x != null));
- for (const webhookId of recipientWebhookIds) {
- await Promise.all(
- abuseReports.map(it => {
- return this.systemWebhookService.enqueueSystemWebhook(
- webhookId,
- type,
- it,
- );
- }),
- );
- }
- }
-
- /**
- * 通報の通知先一覧を取得する.
- *
- * @param {Object} [params] クエリの取得条件
- * @param {Object} [params.method] 取得する通知先の通知方法
- * @param {Object} [opts] 動作時の詳細なオプション
- * @param {boolean} [opts.removeUnauthorized] 副作用としてモデレータ権限を持たない送信先ユーザをDBから削除するかどうか(default: true)
- * @param {boolean} [opts.joinUser] 通知先のユーザ情報をJOINするかどうか(default: false)
- * @param {boolean} [opts.joinSystemWebhook] 通知先のSystemWebhook情報をJOINするかどうか(default: false)
- * @see removeUnauthorizedRecipientUsers
- */
- @bindThis
- public async fetchRecipients(
- params?: {
- ids?: MiAbuseReportNotificationRecipient['id'][],
- method?: RecipientMethod[],
- },
- opts?: {
- removeUnauthorized?: boolean,
- joinUser?: boolean,
- joinSystemWebhook?: boolean,
- },
- ): Promise {
- const query = this.abuseReportNotificationRecipientRepository.createQueryBuilder('recipient');
-
- if (opts?.joinUser) {
- query.innerJoinAndSelect('user', 'user', 'recipient.userId = user.id');
- query.innerJoinAndSelect('recipient.userProfile', 'userProfile');
- }
-
- if (opts?.joinSystemWebhook) {
- query.innerJoinAndSelect('recipient.systemWebhook', 'systemWebhook');
- }
-
- if (params?.ids) {
- query.andWhere({ id: In(params.ids) });
- }
-
- if (params?.method) {
- query.andWhere(new Brackets(qb => {
- if (params.method?.includes('email')) {
- qb.orWhere({ method: 'email', userId: Not(IsNull()) });
- }
- if (params.method?.includes('webhook')) {
- qb.orWhere({ method: 'webhook', userId: IsNull() });
- }
- }));
- }
-
- const recipients = await query.getMany();
- if (recipients.length <= 0) {
- return [];
- }
-
- // アサイン有効期限切れはイベントで拾えないので、このタイミングでチェック及び削除(オプション)
- return (opts?.removeUnauthorized ?? true)
- ? await this.removeUnauthorizedRecipientUsers(recipients)
- : recipients;
- }
-
- /**
- * EMailの通知先一覧を取得する.
- * リレーション先の{@link MiUser}および{@link MiUserProfile}も同時に取得する.
- *
- * @param {Object} [opts]
- * @param {boolean} [opts.removeUnauthorized] 副作用としてモデレータ権限を持たない送信先ユーザをDBから削除するかどうか(default: true)
- * @see removeUnauthorizedRecipientUsers
- */
- @bindThis
- public async fetchEMailRecipients(opts?: {
- removeUnauthorized?: boolean
- }): Promise {
- return this.fetchRecipients({ method: ['email'] }, { joinUser: true, ...opts });
- }
-
- /**
- * Webhookの通知先一覧を取得する.
- * リレーション先の{@link MiSystemWebhook}も同時に取得する.
- */
- @bindThis
- public fetchWebhookRecipients(): Promise {
- return this.fetchRecipients({ method: ['webhook'] }, { joinSystemWebhook: true });
- }
-
- /**
- * 通知先を作成する.
- */
- @bindThis
- public async createRecipient(
- params: {
- isActive: MiAbuseReportNotificationRecipient['isActive'];
- name: MiAbuseReportNotificationRecipient['name'];
- method: MiAbuseReportNotificationRecipient['method'];
- userId: MiAbuseReportNotificationRecipient['userId'];
- systemWebhookId: MiAbuseReportNotificationRecipient['systemWebhookId'];
- },
- updater: MiUser,
- ): Promise {
- const id = this.idService.gen();
- await this.abuseReportNotificationRecipientRepository.insert({
- ...params,
- id,
- });
-
- const created = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: id });
-
- this.moderationLogService
- .log(updater, 'createAbuseReportNotificationRecipient', {
- recipientId: id,
- recipient: created,
- })
- .then();
-
- return created;
- }
-
- /**
- * 通知先を更新する.
- */
- @bindThis
- public async updateRecipient(
- params: {
- id: MiAbuseReportNotificationRecipient['id'];
- isActive: MiAbuseReportNotificationRecipient['isActive'];
- name: MiAbuseReportNotificationRecipient['name'];
- method: MiAbuseReportNotificationRecipient['method'];
- userId: MiAbuseReportNotificationRecipient['userId'];
- systemWebhookId: MiAbuseReportNotificationRecipient['systemWebhookId'];
- },
- updater: MiUser,
- ): Promise {
- const beforeEntity = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: params.id });
-
- await this.abuseReportNotificationRecipientRepository.update(params.id, {
- isActive: params.isActive,
- updatedAt: new Date(),
- name: params.name,
- method: params.method,
- userId: params.userId,
- systemWebhookId: params.systemWebhookId,
- });
-
- const afterEntity = await this.abuseReportNotificationRecipientRepository.findOneByOrFail({ id: params.id });
-
- this.moderationLogService
- .log(updater, 'updateAbuseReportNotificationRecipient', {
- recipientId: params.id,
- before: beforeEntity,
- after: afterEntity,
- })
- .then();
-
- return afterEntity;
- }
-
- /**
- * 通知先を削除する.
- */
- @bindThis
- public async deleteRecipient(
- id: MiAbuseReportNotificationRecipient['id'],
- updater: MiUser,
- ) {
- const entity = await this.abuseReportNotificationRecipientRepository.findBy({ id });
-
- await this.abuseReportNotificationRecipientRepository.delete(id);
-
- this.moderationLogService
- .log(updater, 'deleteAbuseReportNotificationRecipient', {
- recipientId: id,
- recipient: entity,
- })
- .then();
- }
-
- /**
- * モデレータ権限を持たない(*1)通知先ユーザを削除する.
- *
- * *1: 以下の両方を満たすものの事を言う
- * - 通知先にユーザIDが設定されている
- * - 付与ロールにモデレータ権限がない or アサインの有効期限が切れている
- *
- * @param recipients 通知先一覧の配列
- * @returns {@lisk recipients}からモデレータ権限を持たない通知先を削除した配列
- */
- @bindThis
- private async removeUnauthorizedRecipientUsers(recipients: MiAbuseReportNotificationRecipient[]): Promise {
- const userRecipients = recipients.filter(it => it.userId !== null);
- const recipientUserIds = new Set(userRecipients.map(it => it.userId).filter(x => x != null));
- if (recipientUserIds.size <= 0) {
- // ユーザが通知先として設定されていない場合、この関数での処理を行うべきレコードが無い
- return recipients;
- }
-
- // モデレータ権限の有無で通知先設定を振り分ける
- const authorizedUserIds = await this.roleService.getModeratorIds(true, true);
- const authorizedUserRecipients = Array.of();
- const unauthorizedUserRecipients = Array.of();
- for (const recipient of userRecipients) {
- // eslint-disable-next-line
- if (authorizedUserIds.includes(recipient.userId!)) {
- authorizedUserRecipients.push(recipient);
- } else {
- unauthorizedUserRecipients.push(recipient);
- }
- }
-
- // モデレータ権限を持たない通知先をDBから削除する
- if (unauthorizedUserRecipients.length > 0) {
- await this.abuseReportNotificationRecipientRepository.delete(unauthorizedUserRecipients.map(it => it.id));
- }
- const nonUserRecipients = recipients.filter(it => it.userId === null);
- return [...nonUserRecipients, ...authorizedUserRecipients].sort((a, b) => a.id.localeCompare(b.id));
- }
-
- @bindThis
- private async onMessage(_: string, data: string): Promise {
- const obj = JSON.parse(data);
- if (obj.channel !== 'internal') {
- return;
- }
-
- const { type } = obj.message as GlobalEvents['internal']['payload'];
- switch (type) {
- case 'roleUpdated':
- case 'roleDeleted':
- case 'userRoleUnassigned': {
- // 場合によってはキャッシュ更新よりも先にここが呼ばれてしまう可能性があるのでnextTickで遅延実行
- process.nextTick(async () => {
- const recipients = await this.abuseReportNotificationRecipientRepository.findBy({
- userId: Not(IsNull()),
- });
- await this.removeUnauthorizedRecipientUsers(recipients);
- });
- break;
- }
- default: {
- break;
- }
- }
- }
-
- @bindThis
- public dispose(): void {
- this.redisForSub.off('message', this.onMessage);
- }
-
- @bindThis
- public onApplicationShutdown(signal?: string | undefined): void {
- this.dispose();
- }
-}
diff --git a/packages/backend/src/core/AbuseReportService.ts b/packages/backend/src/core/AbuseReportService.ts
deleted file mode 100644
index 007c3f1bf9..0000000000
--- a/packages/backend/src/core/AbuseReportService.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import { In } from 'typeorm';
-import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
-import type { AbuseUserReportsRepository, MiAbuseUserReport, MiUser, UsersRepository } from '@/models/_.js';
-import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
-import { QueueService } from '@/core/QueueService.js';
-import { InstanceActorService } from '@/core/InstanceActorService.js';
-import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { IdService } from './IdService.js';
-
-@Injectable()
-export class AbuseReportService {
- constructor(
- @Inject(DI.abuseUserReportsRepository)
- private abuseUserReportsRepository: AbuseUserReportsRepository,
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
- private idService: IdService,
- private abuseReportNotificationService: AbuseReportNotificationService,
- private queueService: QueueService,
- private instanceActorService: InstanceActorService,
- private apRendererService: ApRendererService,
- private moderationLogService: ModerationLogService,
- ) {
- }
-
- /**
- * ユーザからの通報をDBに記録し、その内容を下記の手段で管理者各位に通知する.
- * - 管理者用Redisイベント
- * - EMail(モデレータ権限所有者ユーザ+metaテーブルに設定されているメールアドレス)
- * - SystemWebhook
- *
- * @param params 通報内容. もし複数件の通報に対応した時のために、あらかじめ複数件を処理できる前提で考える
- * @see AbuseReportNotificationService.notify
- */
- @bindThis
- public async report(params: {
- targetUserId: MiAbuseUserReport['targetUserId'],
- targetUserHost: MiAbuseUserReport['targetUserHost'],
- reporterId: MiAbuseUserReport['reporterId'],
- reporterHost: MiAbuseUserReport['reporterHost'],
- comment: string,
- }[]) {
- const entities = params.map(param => {
- return {
- id: this.idService.gen(),
- targetUserId: param.targetUserId,
- targetUserHost: param.targetUserHost,
- reporterId: param.reporterId,
- reporterHost: param.reporterHost,
- comment: param.comment,
- };
- });
-
- const reports = Array.of();
- for (const entity of entities) {
- const report = await this.abuseUserReportsRepository.insertOne(entity);
- reports.push(report);
- }
-
- return Promise.all([
- this.abuseReportNotificationService.notifyAdminStream(reports),
- this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReport'),
- this.abuseReportNotificationService.notifyMail(reports),
- ]);
- }
-
- /**
- * 通報を解決し、その内容を下記の手段で管理者各位に通知する.
- * - SystemWebhook
- *
- * @param params 通報内容. もし複数件の通報に対応した時のために、あらかじめ複数件を処理できる前提で考える
- * @param operator 通報を処理したユーザ
- * @see AbuseReportNotificationService.notify
- */
- @bindThis
- public async resolve(
- params: {
- reportId: string;
- forward: boolean;
- }[],
- operator: MiUser,
- ) {
- const paramsMap = new Map(params.map(it => [it.reportId, it]));
- const reports = await this.abuseUserReportsRepository.findBy({
- id: In(params.map(it => it.reportId)),
- });
-
- const targetUserMap = new Map();
- for (const report of reports) {
- const shouldForward = paramsMap.get(report.id)!.forward;
-
- if (shouldForward && report.targetUserHost != null) {
- targetUserMap.set(report.id, await this.usersRepository.findOneByOrFail({ id: report.targetUserId }));
- } else {
- targetUserMap.set(report.id, null);
- }
- }
-
- for (const report of reports) {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- const ps = paramsMap.get(report.id)!;
-
- await this.abuseUserReportsRepository.update(report.id, {
- resolved: true,
- assigneeId: operator.id,
- forwarded: ps.forward && report.targetUserHost !== null,
- });
-
- const targetUser = targetUserMap.get(report.id)!;
- if (targetUser != null) {
- const actor = await this.instanceActorService.getInstanceActor();
-
- // eslint-disable-next-line
- const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment);
- const contextAssignedFlag = this.apRendererService.addContext(flag);
- this.queueService.deliver(actor, contextAssignedFlag, targetUser.inbox, false);
- }
-
- this.moderationLogService
- .log(operator, 'resolveAbuseReport', {
- reportId: report.id,
- report: report,
- forwarded: ps.forward && report.targetUserHost !== null,
- });
- }
-
- return this.abuseUserReportsRepository.findBy({ id: In(reports.map(it => it.id)) })
- .then(reports => this.abuseReportNotificationService.notifySystemWebhook(reports, 'abuseReportResolved'));
- }
-}
diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts
index 6e3125044c..b7796a5183 100644
--- a/packages/backend/src/core/AccountMoveService.ts
+++ b/packages/backend/src/core/AccountMoveService.ts
@@ -9,7 +9,7 @@ import { IsNull, In, MoreThan, Not } from 'typeorm';
import { bindThis } from '@/decorators.js';
import { DI } from '@/di-symbols.js';
import type { MiLocalUser, MiRemoteUser, MiUser } from '@/models/User.js';
-import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MiMeta, MutingsRepository, UserListMembershipsRepository, UsersRepository } from '@/models/_.js';
+import type { BlockingsRepository, FollowingsRepository, InstancesRepository, MutingsRepository, UserListMembershipsRepository, UsersRepository } from '@/models/_.js';
import type { RelationshipJobData, ThinUser } from '@/queue/types.js';
import { IdService } from '@/core/IdService.js';
@@ -20,17 +20,16 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { CacheService } from '@/core/CacheService.js';
import { ProxyAccountService } from '@/core/ProxyAccountService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
+import { MetaService } from '@/core/MetaService.js';
import InstanceChart from '@/core/chart/charts/instance.js';
import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
@Injectable()
export class AccountMoveService {
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -59,7 +58,9 @@ export class AccountMoveService {
private perUserFollowingChart: PerUserFollowingChart,
private federatedInstanceService: FederatedInstanceService,
private instanceChart: InstanceChart,
+ private metaService: MetaService,
private relayService: RelayService,
+ private cacheService: CacheService,
private queueService: QueueService,
) {
}
@@ -83,7 +84,7 @@ export class AccountMoveService {
Object.assign(src, update);
// Update cache
- this.globalEventService.publishInternalEvent('localUserUpdated', src);
+ this.cacheService.uriPersonCache.set(srcUri, src);
const srcPerson = await this.apRendererService.renderPerson(src);
const updateAct = this.apRendererService.addContext(this.apRendererService.renderUpdate(srcPerson, src));
@@ -277,7 +278,7 @@ export class AccountMoveService {
if (this.userEntityService.isRemoteUser(oldAccount)) {
this.federatedInstanceService.fetch(oldAccount.host).then(async i => {
this.instancesRepository.decrement({ id: i.id }, 'followersCount', localFollowerIds.length);
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateFollowers(i.host, false);
}
});
@@ -306,7 +307,7 @@ export class AccountMoveService {
let resultUser: MiLocalUser | MiRemoteUser | null = null;
if (this.userEntityService.isRemoteUser(dst)) {
- if (Date.now() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
+ if ((new Date()).getTime() - (dst.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
await this.apPersonService.updatePerson(dst.uri);
}
dst = await this.apPersonService.fetchPerson(dst.uri) ?? dst;
@@ -322,7 +323,7 @@ export class AccountMoveService {
if (!src) continue; // oldAccountを探してもこのサーバーに存在しない場合はフォロー関係もないということなのでスルー
if (this.userEntityService.isRemoteUser(dst)) {
- if (Date.now() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
+ if ((new Date()).getTime() - (src.lastFetchedAt?.getTime() ?? 0) > 10 * 1000) {
await this.apPersonService.updatePerson(srcUri);
}
diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts
index 40a9db01c0..b298a70929 100644
--- a/packages/backend/src/core/AnnouncementService.ts
+++ b/packages/backend/src/core/AnnouncementService.ts
@@ -4,14 +4,13 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import { Brackets, EntityNotFoundError } from 'typeorm';
+import { Brackets } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { MiUser } from '@/models/User.js';
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead, UsersRepository } from '@/models/_.js';
import { bindThis } from '@/decorators.js';
import { Packed } from '@/misc/json-schema.js';
import { IdService } from '@/core/IdService.js';
-import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
@@ -30,7 +29,6 @@ export class AnnouncementService {
private idService: IdService,
private globalEventService: GlobalEventService,
private moderationLogService: ModerationLogService,
- private announcementEntityService: AnnouncementEntityService,
) {
}
@@ -67,7 +65,7 @@ export class AnnouncementService {
@bindThis
public async create(values: Partial, moderator?: MiUser): Promise<{ raw: MiAnnouncement; packed: Packed<'Announcement'> }> {
- const announcement = await this.announcementsRepository.insertOne({
+ const announcement = await this.announcementsRepository.insert({
id: this.idService.gen(),
updatedAt: null,
title: values.title,
@@ -79,9 +77,9 @@ export class AnnouncementService {
silence: values.silence,
needConfirmationToRead: values.needConfirmationToRead,
userId: values.userId,
- });
+ }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
- const packed = await this.announcementEntityService.pack(announcement);
+ const packed = (await this.packMany([announcement]))[0];
if (values.userId) {
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
@@ -179,24 +177,6 @@ export class AnnouncementService {
}
}
- @bindThis
- public async getAnnouncement(announcementId: MiAnnouncement['id'], me: MiUser | null): Promise> {
- const announcement = await this.announcementsRepository.findOneByOrFail({ id: announcementId });
- if (me) {
- if (announcement.userId && announcement.userId !== me.id) {
- throw new EntityNotFoundError(this.announcementsRepository.metadata.target, { id: announcementId });
- }
-
- const read = await this.announcementReadsRepository.findOneBy({
- announcementId: announcement.id,
- userId: me.id,
- });
- return this.announcementEntityService.pack({ ...announcement, isRead: read !== null }, me);
- } else {
- return this.announcementEntityService.pack(announcement, null);
- }
- }
-
@bindThis
public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise {
try {
@@ -213,4 +193,29 @@ export class AnnouncementService {
this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
}
}
+
+ @bindThis
+ public async packMany(
+ announcements: MiAnnouncement[],
+ me?: { id: MiUser['id'] } | null | undefined,
+ options?: {
+ reads?: MiAnnouncementRead[];
+ },
+ ): Promise[]> {
+ const reads = me ? (options?.reads ?? await this.getReads(me.id)) : [];
+ return announcements.map(announcement => ({
+ id: announcement.id,
+ createdAt: this.idService.parse(announcement.id).date.toISOString(),
+ updatedAt: announcement.updatedAt?.toISOString() ?? null,
+ text: announcement.text,
+ title: announcement.title,
+ imageUrl: announcement.imageUrl,
+ icon: announcement.icon,
+ display: announcement.display,
+ needConfirmationToRead: announcement.needConfirmationToRead,
+ silence: announcement.silence,
+ forYou: announcement.userId === me?.id,
+ isRead: reads.some(read => read.announcementId === announcement.id),
+ }));
+ }
}
diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts
index ec9ace417e..4f956a43ed 100644
--- a/packages/backend/src/core/AntennaService.ts
+++ b/packages/backend/src/core/AntennaService.ts
@@ -92,7 +92,7 @@ export class AntennaService implements OnApplicationShutdown {
}
@bindThis
- public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise {
+ public async addNoteToAntennas(note: MiNote, noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise {
const antennas = await this.getAntennas();
const antennasWithMatchResult = await Promise.all(antennas.map(antenna => this.checkHitAntenna(antenna, note, noteUser).then(hit => [antenna, hit] as const)));
const matchedAntennas = antennasWithMatchResult.filter(([, hit]) => hit).map(([antenna]) => antenna);
@@ -110,12 +110,10 @@ export class AntennaService implements OnApplicationShutdown {
// NOTE: フォローしているユーザーのノート、リストのユーザーのノート、グループのユーザーのノート指定はパフォーマンス上の理由で無効になっている
@bindThis
- public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; isBot: boolean; }): Promise {
+ public async checkHitAntenna(antenna: MiAntenna, note: (MiNote | Packed<'Note'>), noteUser: { id: MiUser['id']; username: string; host: string | null; }): Promise {
if (note.visibility === 'specified') return false;
if (note.visibility === 'followers') return false;
- if (antenna.excludeBots && noteUser.isBot) return false;
-
if (antenna.localOnly && noteUser.host != null) return false;
if (!antenna.withReplies && note.replyId != null) return false;
@@ -123,30 +121,23 @@ export class AntennaService implements OnApplicationShutdown {
if (antenna.src === 'home') {
// TODO
} else if (antenna.src === 'list') {
- if (antenna.userListId == null) return false;
- const exists = await this.userListMembershipsRepository.exists({
- where: {
- userListId: antenna.userListId,
- userId: note.userId,
- },
- });
- if (!exists) return false;
+ const listUsers = (await this.userListMembershipsRepository.findBy({
+ userListId: antenna.userListId!,
+ })).map(x => x.userId);
+
+ if (!listUsers.includes(note.userId)) return false;
} else if (antenna.src === 'users') {
const accts = antenna.users.map(x => {
const { username, host } = Acct.parse(x);
return this.utilityService.getFullApAccount(username, host).toLowerCase();
});
- const matchUser = this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase();
- const matchWildcard = this.utilityService.getFullApAccount('*', noteUser.host).toLowerCase();
- if (!accts.includes(matchUser) && !accts.includes(matchWildcard)) return false;
+ if (!accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
} else if (antenna.src === 'users_blacklist') {
const accts = antenna.users.map(x => {
const { username, host } = Acct.parse(x);
return this.utilityService.getFullApAccount(username, host).toLowerCase();
});
- const matchUser = this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase();
- const matchWildcard = this.utilityService.getFullApAccount('*', noteUser.host).toLowerCase();
- if (accts.includes(matchUser) || accts.includes(matchWildcard)) return false;
+ if (accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
}
const keywords = antenna.keywords
diff --git a/packages/backend/src/core/AvatarDecorationService.ts b/packages/backend/src/core/AvatarDecorationService.ts
index 4efd6122b1..21e31d79a4 100644
--- a/packages/backend/src/core/AvatarDecorationService.ts
+++ b/packages/backend/src/core/AvatarDecorationService.ts
@@ -29,7 +29,7 @@ export class AvatarDecorationService implements OnApplicationShutdown {
private moderationLogService: ModerationLogService,
private globalEventService: GlobalEventService,
) {
- this.cache = new MemorySingleCache(1000 * 60 * 30); // 30s
+ this.cache = new MemorySingleCache(1000 * 60 * 30);
this.redisForSub.on('message', this.onMessage);
}
@@ -55,10 +55,10 @@ export class AvatarDecorationService implements OnApplicationShutdown {
@bindThis
public async create(options: Partial, moderator?: MiUser): Promise {
- const created = await this.avatarDecorationsRepository.insertOne({
+ const created = await this.avatarDecorationsRepository.insert({
id: this.idService.gen(),
...options,
- });
+ }).then(x => this.avatarDecorationsRepository.findOneByOrFail(x.identifiers[0]));
this.globalEventService.publishInternalEvent('avatarDecorationCreated', created);
diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts
index 6725ebe75b..263df56476 100644
--- a/packages/backend/src/core/CacheService.ts
+++ b/packages/backend/src/core/CacheService.ts
@@ -56,10 +56,10 @@ export class CacheService implements OnApplicationShutdown {
) {
//this.onMessage = this.onMessage.bind(this);
- this.userByIdCache = new MemoryKVCache(1000 * 60 * 5); // 5m
- this.localUserByNativeTokenCache = new MemoryKVCache(1000 * 60 * 5); // 5m
- this.localUserByIdCache = new MemoryKVCache(1000 * 60 * 5); // 5m
- this.uriPersonCache = new MemoryKVCache(1000 * 60 * 5); // 5m
+ this.userByIdCache = new MemoryKVCache(Infinity);
+ this.localUserByNativeTokenCache = new MemoryKVCache(Infinity);
+ this.localUserByIdCache = new MemoryKVCache(Infinity);
+ this.uriPersonCache = new MemoryKVCache(Infinity);
this.userProfileCache = new RedisKVCache(this.redisClient, 'userProfile', {
lifetime: 1000 * 60 * 30, // 30m
@@ -128,21 +128,18 @@ export class CacheService implements OnApplicationShutdown {
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
switch (type) {
case 'userChangeSuspendedState':
- case 'userChangeDeletedState':
- case 'remoteUserUpdated':
- case 'localUserUpdated': {
+ case 'remoteUserUpdated': {
const user = await this.usersRepository.findOneBy({ id: body.id });
if (user == null) {
this.userByIdCache.delete(body.id);
- this.localUserByIdCache.delete(body.id);
- for (const [k, v] of this.uriPersonCache.entries) {
+ for (const [k, v] of this.uriPersonCache.cache.entries()) {
if (v.value?.id === body.id) {
this.uriPersonCache.delete(k);
}
}
} else {
this.userByIdCache.set(user.id, user);
- for (const [k, v] of this.uriPersonCache.entries) {
+ for (const [k, v] of this.uriPersonCache.cache.entries()) {
if (v.value?.id === user.id) {
this.uriPersonCache.set(k, user);
}
diff --git a/packages/backend/src/core/CaptchaService.ts b/packages/backend/src/core/CaptchaService.ts
index 4be45dabb8..f6b7955cd2 100644
--- a/packages/backend/src/core/CaptchaService.ts
+++ b/packages/backend/src/core/CaptchaService.ts
@@ -10,7 +10,6 @@ import { bindThis } from '@/decorators.js';
type CaptchaResponse = {
success: boolean;
'error-codes'?: string[];
- 'errors'?: string[];
};
@Injectable()
@@ -74,35 +73,6 @@ export class CaptchaService {
}
}
- @bindThis
- public async verifyFriendlyCaptcha(secret: string, response: string | null | undefined): Promise {
- if (response == null) {
- throw new Error('frc-failed: no response provided');
- }
-
- const result = await this.httpRequestService.send('https://api.friendlycaptcha.com/api/v1/siteverify', {
- method: 'POST',
- body: JSON.stringify({
- secret: secret,
- solution: response,
- }),
- headers: {
- 'Content-Type': 'application/json',
- },
- });
-
- if (result.status !== 200) {
- throw new Error('frc-failed: frc didn\'t return 200 OK');
- }
-
- const resp = await result.json() as CaptchaResponse;
-
- if (resp.success !== true) {
- const errorCodes = resp['errors'] ? resp['errors'].join(', ') : '';
- throw new Error(`frc-failed: ${errorCodes}`);
- }
- }
-
// https://codeberg.org/Gusted/mCaptcha/src/branch/main/mcaptcha.go
@bindThis
public async verifyMcaptcha(secret: string, siteKey: string, instanceHost: string, response: string | null | undefined): Promise {
diff --git a/packages/backend/src/core/ChannelFollowingService.ts b/packages/backend/src/core/ChannelFollowingService.ts
index 12251595e2..75843b9773 100644
--- a/packages/backend/src/core/ChannelFollowingService.ts
+++ b/packages/backend/src/core/ChannelFollowingService.ts
@@ -1,8 +1,3 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import Redis from 'ioredis';
import { DI } from '@/di-symbols.js';
diff --git a/packages/backend/src/core/ClipService.ts b/packages/backend/src/core/ClipService.ts
index 929a9db064..bb8be26ce6 100644
--- a/packages/backend/src/core/ClipService.ts
+++ b/packages/backend/src/core/ClipService.ts
@@ -41,17 +41,17 @@ export class ClipService {
const currentCount = await this.clipsRepository.countBy({
userId: me.id,
});
- if (currentCount >= (await this.roleService.getUserPolicies(me.id)).clipLimit) {
+ if (currentCount > (await this.roleService.getUserPolicies(me.id)).clipLimit) {
throw new ClipService.TooManyClipsError();
}
- const clip = await this.clipsRepository.insertOne({
+ const clip = await this.clipsRepository.insert({
id: this.idService.gen(),
userId: me.id,
name: name,
isPublic: isPublic,
description: description,
- });
+ }).then(x => this.clipsRepository.findOneByOrFail(x.identifiers[0]));
return clip;
}
@@ -102,7 +102,7 @@ export class ClipService {
const currentCount = await this.clipNotesRepository.countBy({
clipId: clip.id,
});
- if (currentCount >= (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
+ if (currentCount > (await this.roleService.getUserPolicies(me.id)).noteEachClipsLimit) {
throw new ClipService.TooManyClipNotesError();
}
diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts
index c083068392..dbfa81c458 100644
--- a/packages/backend/src/core/CoreModule.ts
+++ b/packages/backend/src/core/CoreModule.ts
@@ -5,15 +5,6 @@
import { Module } from '@nestjs/common';
import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js';
-import { AbuseReportService } from '@/core/AbuseReportService.js';
-import { SystemWebhookEntityService } from '@/core/entities/SystemWebhookEntityService.js';
-import {
- AbuseReportNotificationRecipientEntityService,
-} from '@/core/entities/AbuseReportNotificationRecipientEntityService.js';
-import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
-import { SystemWebhookService } from '@/core/SystemWebhookService.js';
-import { UserSearchService } from '@/core/UserSearchService.js';
-import { WebhookTestService } from '@/core/WebhookTestService.js';
import { AccountMoveService } from './AccountMoveService.js';
import { AccountUpdateService } from './AccountUpdateService.js';
import { AnnouncementService } from './AnnouncementService.js';
@@ -43,7 +34,6 @@ import { ModerationLogService } from './ModerationLogService.js';
import { NoteCreateService } from './NoteCreateService.js';
import { NoteEditService } from './NoteEditService.js';
import { NoteDeleteService } from './NoteDeleteService.js';
-import { LatestNoteService } from './LatestNoteService.js';
import { NotePiningService } from './NotePiningService.js';
import { NoteReadService } from './NoteReadService.js';
import { NotificationService } from './NotificationService.js';
@@ -51,7 +41,6 @@ import { PollService } from './PollService.js';
import { PushNotificationService } from './PushNotificationService.js';
import { QueryService } from './QueryService.js';
import { ReactionService } from './ReactionService.js';
-import { ReactionsBufferingService } from './ReactionsBufferingService.js';
import { RelayService } from './RelayService.js';
import { RoleService } from './RoleService.js';
import { S3Service } from './S3Service.js';
@@ -64,11 +53,10 @@ import { UserFollowingService } from './UserFollowingService.js';
import { UserKeypairService } from './UserKeypairService.js';
import { UserListService } from './UserListService.js';
import { UserMutingService } from './UserMutingService.js';
-import { UserRenoteMutingService } from './UserRenoteMutingService.js';
import { UserSuspendService } from './UserSuspendService.js';
import { UserAuthService } from './UserAuthService.js';
import { VideoProcessingService } from './VideoProcessingService.js';
-import { UserWebhookService } from './UserWebhookService.js';
+import { WebhookService } from './WebhookService.js';
import { ProxyAccountService } from './ProxyAccountService.js';
import { UtilityService } from './UtilityService.js';
import { FileInfoService } from './FileInfoService.js';
@@ -96,7 +84,6 @@ import ApRequestChart from './chart/charts/ap-request.js';
import { ChartManagementService } from './chart/ChartManagementService.js';
import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js';
-import { AnnouncementEntityService } from './entities/AnnouncementEntityService.js';
import { AntennaEntityService } from './entities/AntennaEntityService.js';
import { AppEntityService } from './entities/AppEntityService.js';
import { AuthSessionEntityService } from './entities/AuthSessionEntityService.js';
@@ -129,7 +116,6 @@ import { FlashEntityService } from './entities/FlashEntityService.js';
import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
import { RoleEntityService } from './entities/RoleEntityService.js';
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
-import { MetaEntityService } from './entities/MetaEntityService.js';
import { ApAudienceService } from './activitypub/ApAudienceService.js';
import { ApDbResolverService } from './activitypub/ApDbResolverService.js';
@@ -140,7 +126,7 @@ import { ApMfmService } from './activitypub/ApMfmService.js';
import { ApRendererService } from './activitypub/ApRendererService.js';
import { ApRequestService } from './activitypub/ApRequestService.js';
import { ApResolverService } from './activitypub/ApResolverService.js';
-import { JsonLdService } from './activitypub/JsonLdService.js';
+import { LdSignatureService } from './activitypub/LdSignatureService.js';
import { RemoteLoggerService } from './RemoteLoggerService.js';
import { RemoteUserResolveService } from './RemoteUserResolveService.js';
import { WebfingerService } from './WebfingerService.js';
@@ -152,13 +138,10 @@ import { ApQuestionService } from './activitypub/models/ApQuestionService.js';
import { QueueModule } from './QueueModule.js';
import { QueueService } from './QueueService.js';
import { LoggerService } from './LoggerService.js';
-import { SponsorsService } from './SponsorsService.js';
import type { Provider } from '@nestjs/common';
//#region 文字列ベースでのinjection用(循環参照対応のため)
const $LoggerService: Provider = { provide: 'LoggerService', useExisting: LoggerService };
-const $AbuseReportService: Provider = { provide: 'AbuseReportService', useExisting: AbuseReportService };
-const $AbuseReportNotificationService: Provider = { provide: 'AbuseReportNotificationService', useExisting: AbuseReportNotificationService };
const $AccountMoveService: Provider = { provide: 'AccountMoveService', useExisting: AccountMoveService };
const $AccountUpdateService: Provider = { provide: 'AccountUpdateService', useExisting: AccountUpdateService };
const $AnnouncementService: Provider = { provide: 'AnnouncementService', useExisting: AnnouncementService };
@@ -188,7 +171,6 @@ const $ModerationLogService: Provider = { provide: 'ModerationLogService', useEx
const $NoteCreateService: Provider = { provide: 'NoteCreateService', useExisting: NoteCreateService };
const $NoteEditService: Provider = { provide: 'NoteEditService', useExisting: NoteEditService };
const $NoteDeleteService: Provider = { provide: 'NoteDeleteService', useExisting: NoteDeleteService };
-const $LatestNoteService: Provider = { provide: 'LatestNoteService', useExisting: LatestNoteService };
const $NotePiningService: Provider = { provide: 'NotePiningService', useExisting: NotePiningService };
const $NoteReadService: Provider = { provide: 'NoteReadService', useExisting: NoteReadService };
const $NotificationService: Provider = { provide: 'NotificationService', useExisting: NotificationService };
@@ -197,7 +179,6 @@ const $ProxyAccountService: Provider = { provide: 'ProxyAccountService', useExis
const $PushNotificationService: Provider = { provide: 'PushNotificationService', useExisting: PushNotificationService };
const $QueryService: Provider = { provide: 'QueryService', useExisting: QueryService };
const $ReactionService: Provider = { provide: 'ReactionService', useExisting: ReactionService };
-const $ReactionsBufferingService: Provider = { provide: 'ReactionsBufferingService', useExisting: ReactionsBufferingService };
const $RelayService: Provider = { provide: 'RelayService', useExisting: RelayService };
const $RoleService: Provider = { provide: 'RoleService', useExisting: RoleService };
const $S3Service: Provider = { provide: 'S3Service', useExisting: S3Service };
@@ -210,14 +191,10 @@ const $UserFollowingService: Provider = { provide: 'UserFollowingService', useEx
const $UserKeypairService: Provider = { provide: 'UserKeypairService', useExisting: UserKeypairService };
const $UserListService: Provider = { provide: 'UserListService', useExisting: UserListService };
const $UserMutingService: Provider = { provide: 'UserMutingService', useExisting: UserMutingService };
-const $UserRenoteMutingService: Provider = { provide: 'UserRenoteMutingService', useExisting: UserRenoteMutingService };
-const $UserSearchService: Provider = { provide: 'UserSearchService', useExisting: UserSearchService };
const $UserSuspendService: Provider = { provide: 'UserSuspendService', useExisting: UserSuspendService };
const $UserAuthService: Provider = { provide: 'UserAuthService', useExisting: UserAuthService };
const $VideoProcessingService: Provider = { provide: 'VideoProcessingService', useExisting: VideoProcessingService };
-const $UserWebhookService: Provider = { provide: 'UserWebhookService', useExisting: UserWebhookService };
-const $SystemWebhookService: Provider = { provide: 'SystemWebhookService', useExisting: SystemWebhookService };
-const $WebhookTestService: Provider = { provide: 'WebhookTestService', useExisting: WebhookTestService };
+const $WebhookService: Provider = { provide: 'WebhookService', useExisting: WebhookService };
const $UtilityService: Provider = { provide: 'UtilityService', useExisting: UtilityService };
const $FileInfoService: Provider = { provide: 'FileInfoService', useExisting: FileInfoService };
const $SearchService: Provider = { provide: 'SearchService', useExisting: SearchService };
@@ -245,8 +222,6 @@ const $ApRequestChart: Provider = { provide: 'ApRequestChart', useExisting: ApRe
const $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService };
const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
-const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService };
-const $AbuseReportNotificationRecipientEntityService: Provider = { provide: 'AbuseReportNotificationRecipientEntityService', useExisting: AbuseReportNotificationRecipientEntityService };
const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
@@ -279,8 +254,6 @@ const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisti
const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService };
const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService };
-const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService };
-const $SystemWebhookEntityService: Provider = { provide: 'SystemWebhookEntityService', useExisting: SystemWebhookEntityService };
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
@@ -291,7 +264,7 @@ const $ApMfmService: Provider = { provide: 'ApMfmService', useExisting: ApMfmSer
const $ApRendererService: Provider = { provide: 'ApRendererService', useExisting: ApRendererService };
const $ApRequestService: Provider = { provide: 'ApRequestService', useExisting: ApRequestService };
const $ApResolverService: Provider = { provide: 'ApResolverService', useExisting: ApResolverService };
-const $JsonLdService: Provider = { provide: 'JsonLdService', useExisting: JsonLdService };
+const $LdSignatureService: Provider = { provide: 'LdSignatureService', useExisting: LdSignatureService };
const $RemoteLoggerService: Provider = { provide: 'RemoteLoggerService', useExisting: RemoteLoggerService };
const $RemoteUserResolveService: Provider = { provide: 'RemoteUserResolveService', useExisting: RemoteUserResolveService };
const $WebfingerService: Provider = { provide: 'WebfingerService', useExisting: WebfingerService };
@@ -302,16 +275,12 @@ const $ApPersonService: Provider = { provide: 'ApPersonService', useExisting: Ap
const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting: ApQuestionService };
//#endregion
-const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: SponsorsService };
-
@Module({
imports: [
QueueModule,
],
providers: [
LoggerService,
- AbuseReportService,
- AbuseReportNotificationService,
AccountMoveService,
AccountUpdateService,
AnnouncementService,
@@ -341,7 +310,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
NoteCreateService,
NoteEditService,
NoteDeleteService,
- LatestNoteService,
NotePiningService,
NoteReadService,
NotificationService,
@@ -350,7 +318,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
PushNotificationService,
QueryService,
ReactionService,
- ReactionsBufferingService,
RelayService,
RoleService,
S3Service,
@@ -363,14 +330,10 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
UserKeypairService,
UserListService,
UserMutingService,
- UserRenoteMutingService,
- UserSearchService,
UserSuspendService,
UserAuthService,
VideoProcessingService,
- UserWebhookService,
- SystemWebhookService,
- WebhookTestService,
+ WebhookService,
UtilityService,
FileInfoService,
SearchService,
@@ -398,8 +361,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
ChartManagementService,
AbuseUserReportEntityService,
- AnnouncementEntityService,
- AbuseReportNotificationRecipientEntityService,
AntennaEntityService,
AppEntityService,
AuthSessionEntityService,
@@ -432,8 +393,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
FlashLikeEntityService,
RoleEntityService,
ReversiGameEntityService,
- MetaEntityService,
- SystemWebhookEntityService,
ApAudienceService,
ApDbResolverService,
@@ -444,7 +403,7 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
ApRendererService,
ApRequestService,
ApResolverService,
- JsonLdService,
+ LdSignatureService,
RemoteLoggerService,
RemoteUserResolveService,
WebfingerService,
@@ -455,12 +414,8 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
ApQuestionService,
QueueService,
- SponsorsService,
-
//#region 文字列ベースでのinjection用(循環参照対応のため)
$LoggerService,
- $AbuseReportService,
- $AbuseReportNotificationService,
$AccountMoveService,
$AccountUpdateService,
$AnnouncementService,
@@ -490,7 +445,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$NoteCreateService,
$NoteEditService,
$NoteDeleteService,
- $LatestNoteService,
$NotePiningService,
$NoteReadService,
$NotificationService,
@@ -499,7 +453,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$PushNotificationService,
$QueryService,
$ReactionService,
- $ReactionsBufferingService,
$RelayService,
$RoleService,
$S3Service,
@@ -512,14 +465,10 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$UserKeypairService,
$UserListService,
$UserMutingService,
- $UserRenoteMutingService,
- $UserSearchService,
$UserSuspendService,
$UserAuthService,
$VideoProcessingService,
- $UserWebhookService,
- $SystemWebhookService,
- $WebhookTestService,
+ $WebhookService,
$UtilityService,
$FileInfoService,
$SearchService,
@@ -547,8 +496,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$ChartManagementService,
$AbuseUserReportEntityService,
- $AnnouncementEntityService,
- $AbuseReportNotificationRecipientEntityService,
$AntennaEntityService,
$AppEntityService,
$AuthSessionEntityService,
@@ -581,8 +528,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$FlashLikeEntityService,
$RoleEntityService,
$ReversiGameEntityService,
- $MetaEntityService,
- $SystemWebhookEntityService,
$ApAudienceService,
$ApDbResolverService,
@@ -593,7 +538,7 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$ApRendererService,
$ApRequestService,
$ApResolverService,
- $JsonLdService,
+ $LdSignatureService,
$RemoteLoggerService,
$RemoteUserResolveService,
$WebfingerService,
@@ -603,14 +548,10 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$ApPersonService,
$ApQuestionService,
//#endregion
-
- $SponsorsService,
],
exports: [
QueueModule,
LoggerService,
- AbuseReportService,
- AbuseReportNotificationService,
AccountMoveService,
AccountUpdateService,
AnnouncementService,
@@ -640,7 +581,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
NoteCreateService,
NoteEditService,
NoteDeleteService,
- LatestNoteService,
NotePiningService,
NoteReadService,
NotificationService,
@@ -649,7 +589,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
PushNotificationService,
QueryService,
ReactionService,
- ReactionsBufferingService,
RelayService,
RoleService,
S3Service,
@@ -662,14 +601,10 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
UserKeypairService,
UserListService,
UserMutingService,
- UserRenoteMutingService,
- UserSearchService,
UserSuspendService,
UserAuthService,
VideoProcessingService,
- UserWebhookService,
- SystemWebhookService,
- WebhookTestService,
+ WebhookService,
UtilityService,
FileInfoService,
SearchService,
@@ -696,8 +631,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
ChartManagementService,
AbuseUserReportEntityService,
- AnnouncementEntityService,
- AbuseReportNotificationRecipientEntityService,
AntennaEntityService,
AppEntityService,
AuthSessionEntityService,
@@ -730,8 +663,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
FlashLikeEntityService,
RoleEntityService,
ReversiGameEntityService,
- MetaEntityService,
- SystemWebhookEntityService,
ApAudienceService,
ApDbResolverService,
@@ -742,7 +673,7 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
ApRendererService,
ApRequestService,
ApResolverService,
- JsonLdService,
+ LdSignatureService,
RemoteLoggerService,
RemoteUserResolveService,
WebfingerService,
@@ -753,12 +684,8 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
ApQuestionService,
QueueService,
- SponsorsService,
-
//#region 文字列ベースでのinjection用(循環参照対応のため)
$LoggerService,
- $AbuseReportService,
- $AbuseReportNotificationService,
$AccountMoveService,
$AccountUpdateService,
$AnnouncementService,
@@ -788,7 +715,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$NoteCreateService,
$NoteEditService,
$NoteDeleteService,
- $LatestNoteService,
$NotePiningService,
$NoteReadService,
$NotificationService,
@@ -797,7 +723,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$PushNotificationService,
$QueryService,
$ReactionService,
- $ReactionsBufferingService,
$RelayService,
$RoleService,
$S3Service,
@@ -810,14 +735,10 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$UserKeypairService,
$UserListService,
$UserMutingService,
- $UserRenoteMutingService,
- $UserSearchService,
$UserSuspendService,
$UserAuthService,
$VideoProcessingService,
- $UserWebhookService,
- $SystemWebhookService,
- $WebhookTestService,
+ $WebhookService,
$UtilityService,
$FileInfoService,
$SearchService,
@@ -844,8 +765,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$ChartManagementService,
$AbuseUserReportEntityService,
- $AnnouncementEntityService,
- $AbuseReportNotificationRecipientEntityService,
$AntennaEntityService,
$AppEntityService,
$AuthSessionEntityService,
@@ -878,8 +797,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$FlashLikeEntityService,
$RoleEntityService,
$ReversiGameEntityService,
- $MetaEntityService,
- $SystemWebhookEntityService,
$ApAudienceService,
$ApDbResolverService,
@@ -890,7 +807,7 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$ApRendererService,
$ApRequestService,
$ApResolverService,
- $JsonLdService,
+ $LdSignatureService,
$RemoteLoggerService,
$RemoteUserResolveService,
$WebfingerService,
@@ -900,8 +817,6 @@ const $SponsorsService: Provider = { provide: 'SponsorsService', useExisting: Sp
$ApPersonService,
$ApQuestionService,
//#endregion
-
- $SponsorsService,
],
})
export class CoreModule { }
diff --git a/packages/backend/src/core/CustomEmojiService.ts b/packages/backend/src/core/CustomEmojiService.ts
index cd906a72af..7bb3007d32 100644
--- a/packages/backend/src/core/CustomEmojiService.ts
+++ b/packages/backend/src/core/CustomEmojiService.ts
@@ -22,11 +22,11 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
import type { Config } from '@/config.js';
import { DriveService } from './DriveService.js';
-const parseEmojiStrRegexp = /^([-\w]+)(?:@([\w.-]+))?$/;
+const parseEmojiStrRegexp = /^(\w+)(?:@([\w.-]+))?$/;
@Injectable()
export class CustomEmojiService implements OnApplicationShutdown {
- private emojisCache: MemoryKVCache;
+ private cache: MemoryKVCache;
public localEmojisCache: RedisSingleCache>;
constructor(
@@ -49,7 +49,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
private globalEventService: GlobalEventService,
private driveService: DriveService,
) {
- this.emojisCache = new MemoryKVCache(1000 * 60 * 60 * 12); // 12h
+ this.cache = new MemoryKVCache(1000 * 60 * 60 * 12);
this.localEmojisCache = new RedisSingleCache>(this.redisClient, 'localEmojis', {
lifetime: 1000 * 60 * 30, // 30m
@@ -77,7 +77,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
localOnly: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction: MiRole['id'][];
}, moderator?: MiUser): Promise {
- const emoji = await this.emojisRepository.insertOne({
+ const emoji = await this.emojisRepository.insert({
id: this.idService.gen(),
updatedAt: new Date(),
name: data.name,
@@ -91,7 +91,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
isSensitive: data.isSensitive,
localOnly: data.localOnly,
roleIdsThatCanBeUsedThisEmojiAsReaction: data.roleIdsThatCanBeUsedThisEmojiAsReaction,
- });
+ }).then(x => this.emojisRepository.findOneByOrFail(x.identifiers[0]));
if (data.host == null) {
this.localEmojisCache.refresh();
@@ -142,13 +142,6 @@ export class CustomEmojiService implements OnApplicationShutdown {
this.localEmojisCache.refresh();
- if (data.driveFile != null) {
- const file = await this.driveFilesRepository.findOneBy({ url: emoji.originalUrl, userHost: emoji.host ? emoji.host : IsNull() });
- if (file && file.id !== data.driveFile.id) {
- await this.driveService.deleteFile(file, false, moderator ? moderator : undefined);
- }
- }
-
const packed = await this.emojiEntityService.packDetailed(emoji.id);
if (emoji.name === data.name) {
@@ -357,14 +350,14 @@ export class CustomEmojiService implements OnApplicationShutdown {
if (name == null) return null;
if (host == null) return null;
- const newHost = host === this.config.host ? null : host;
+ const newHost = host === this.config.host ? null : host;
const queryOrNull = async () => (await this.emojisRepository.findOneBy({
name,
host: newHost ?? IsNull(),
})) ?? null;
- const emoji = await this.emojisCache.fetch(`${name} ${host}`, queryOrNull);
+ const emoji = await this.cache.fetch(`${name} ${host}`, queryOrNull);
if (emoji == null) return null;
return emoji.publicUrl || emoji.originalUrl; // || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
@@ -376,11 +369,10 @@ export class CustomEmojiService implements OnApplicationShutdown {
@bindThis
public async populateEmojis(emojiNames: string[], noteUserHost: string | null): Promise> {
const emojis = await Promise.all(emojiNames.map(x => this.populateEmoji(x, noteUserHost)));
- const res = {} as Record;
+ const res = {} as any;
for (let i = 0; i < emojiNames.length; i++) {
- const resolvedEmoji = emojis[i];
- if (resolvedEmoji != null) {
- res[emojiNames[i]] = resolvedEmoji;
+ if (emojis[i] != null) {
+ res[emojiNames[i]] = emojis[i];
}
}
return res;
@@ -391,7 +383,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
*/
@bindThis
public async prefetchEmojis(emojis: { name: string; host: string | null; }[]): Promise {
- const notCachedEmojis = emojis.filter(emoji => this.emojisCache.get(`${emoji.name} ${emoji.host}`) == null);
+ const notCachedEmojis = emojis.filter(emoji => this.cache.get(`${emoji.name} ${emoji.host}`) == null);
const emojisQuery: any[] = [];
const hosts = new Set(notCachedEmojis.map(e => e.host));
for (const host of hosts) {
@@ -406,7 +398,7 @@ export class CustomEmojiService implements OnApplicationShutdown {
select: ['name', 'host', 'originalUrl', 'publicUrl'],
}) : [];
for (const emoji of _emojis) {
- this.emojisCache.set(`${emoji.name} ${emoji.host}`, emoji);
+ this.cache.set(`${emoji.name} ${emoji.host}`, emoji);
}
}
@@ -424,14 +416,9 @@ export class CustomEmojiService implements OnApplicationShutdown {
return this.emojisRepository.findOneBy({ id });
}
- @bindThis
- public getEmojiByName(name: string): Promise {
- return this.emojisRepository.findOneBy({ name, host: IsNull() });
- }
-
@bindThis
public dispose(): void {
- this.emojisCache.dispose();
+ this.cache.dispose();
}
@bindThis
diff --git a/packages/backend/src/core/DeleteAccountService.ts b/packages/backend/src/core/DeleteAccountService.ts
index 8408e95863..fc5d217ae0 100644
--- a/packages/backend/src/core/DeleteAccountService.ts
+++ b/packages/backend/src/core/DeleteAccountService.ts
@@ -4,16 +4,11 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import { Not, IsNull } from 'typeorm';
-import type { FollowingsRepository, MiUser, UsersRepository } from '@/models/_.js';
+import type { UsersRepository } from '@/models/_.js';
import { QueueService } from '@/core/QueueService.js';
+import { UserSuspendService } from '@/core/UserSuspendService.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
-import { GlobalEventService } from '@/core/GlobalEventService.js';
-import { UserEntityService } from '@/core/entities/UserEntityService.js';
-import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { isSystemAccount } from '@/misc/is-system-account.js';
@Injectable()
export class DeleteAccountService {
@@ -21,14 +16,8 @@ export class DeleteAccountService {
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
- @Inject(DI.followingsRepository)
- private followingsRepository: FollowingsRepository,
-
- private userEntityService: UserEntityService,
- private apRendererService: ApRendererService,
+ private userSuspendService: UserSuspendService,
private queueService: QueueService,
- private globalEventService: GlobalEventService,
- private moderationLogService: ModerationLogService,
) {
}
@@ -36,58 +25,19 @@ export class DeleteAccountService {
public async deleteAccount(user: {
id: string;
host: string | null;
- }, moderator?: MiUser): Promise {
+ }): Promise {
const _user = await this.usersRepository.findOneByOrFail({ id: user.id });
if (_user.isRoot) throw new Error('cannot delete a root account');
- if (isSystemAccount(_user)) throw new Error('cannot delete a system account');
-
- if (moderator != null) {
- this.moderationLogService.log(moderator, 'deleteAccount', {
- userId: user.id,
- userUsername: _user.username,
- userHost: user.host,
- });
- }
// 物理削除する前にDelete activityを送信する
- if (this.userEntityService.isLocalUser(user)) {
- // 知り得る全SharedInboxにDelete配信
- const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.userEntityService.genLocalUserUri(user.id), user));
+ await this.userSuspendService.doPostSuspend(user).catch(e => {});
- const queue: string[] = [];
-
- const followings = await this.followingsRepository.find({
- where: [
- { followerSharedInbox: Not(IsNull()) },
- { followeeSharedInbox: Not(IsNull()) },
- ],
- select: ['followerSharedInbox', 'followeeSharedInbox'],
- });
-
- const inboxes = followings.map(x => x.followerSharedInbox ?? x.followeeSharedInbox);
-
- for (const inbox of inboxes) {
- if (inbox != null && !queue.includes(inbox)) queue.push(inbox);
- }
-
- for (const inbox of queue) {
- this.queueService.deliver(user, content, inbox, true);
- }
-
- this.queueService.createDeleteAccountJob(user, {
- soft: false,
- });
- } else {
- // リモートユーザーの削除は、完全にDBから物理削除してしまうと再度連合してきてアカウントが復活する可能性があるため、soft指定する
- this.queueService.createDeleteAccountJob(user, {
- soft: true,
- });
- }
+ this.queueService.createDeleteAccountJob(user, {
+ soft: false,
+ });
await this.usersRepository.update(user.id, {
isDeleted: true,
});
-
- this.globalEventService.publishInternalEvent('userChangeDeletedState', { id: user.id, isDeleted: true });
}
}
diff --git a/packages/backend/src/core/DownloadService.ts b/packages/backend/src/core/DownloadService.ts
index 05b9e64a37..21ae798f9f 100644
--- a/packages/backend/src/core/DownloadService.ts
+++ b/packages/backend/src/core/DownloadService.ts
@@ -6,6 +6,7 @@
import * as fs from 'node:fs';
import * as stream from 'node:stream/promises';
import { Inject, Injectable } from '@nestjs/common';
+import ipaddr from 'ipaddr.js';
import chalk from 'chalk';
import got, * as Got from 'got';
import { parse } from 'content-disposition';
@@ -34,14 +35,14 @@ export class DownloadService {
}
@bindThis
- public async downloadUrl(url: string, path: string, options: { timeout?: number, operationTimeout?: number, maxSize?: number} = {} ): Promise<{
+ public async downloadUrl(url: string, path: string): Promise<{
filename: string;
}> {
this.logger.info(`Downloading ${chalk.cyan(url)} to ${chalk.cyanBright(path)} ...`);
- const timeout = options.timeout ?? 30 * 1000;
- const operationTimeout = options.operationTimeout ?? 60 * 1000;
- const maxSize = options.maxSize ?? this.config.maxFileSize;
+ const timeout = 30 * 1000;
+ const operationTimeout = 60 * 1000;
+ const maxSize = this.config.maxFileSize ?? 262144000;
const urlObj = new URL(url);
let filename = urlObj.pathname.split('/').pop() ?? 'untitled';
@@ -69,6 +70,13 @@ export class DownloadService {
},
enableUnixSockets: false,
}).on('response', (res: Got.Response) => {
+ if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) {
+ if (this.isPrivateIp(res.ip)) {
+ this.logger.warn(`Blocked address: ${res.ip}`);
+ req.destroy();
+ }
+ }
+
const contentLength = res.headers['content-length'];
if (contentLength != null) {
const size = Number(contentLength);
@@ -131,4 +139,18 @@ export class DownloadService {
cleanup();
}
}
+
+ @bindThis
+ private isPrivateIp(ip: string): boolean {
+ const parsedIp = ipaddr.parse(ip);
+
+ for (const net of this.config.allowedPrivateNetworks ?? []) {
+ const cidr = ipaddr.parseCIDR(net);
+ if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
+ return false;
+ }
+ }
+
+ return parsedIp.range() !== 'unicast';
+ }
}
diff --git a/packages/backend/src/core/DriveService.ts b/packages/backend/src/core/DriveService.ts
index 086f2f94d5..f64568ee9a 100644
--- a/packages/backend/src/core/DriveService.ts
+++ b/packages/backend/src/core/DriveService.ts
@@ -11,10 +11,11 @@ import { sharpBmp } from '@misskey-dev/sharp-read-bmp';
import { IsNull } from 'typeorm';
import { DeleteObjectCommandInput, PutObjectCommandInput, NoSuchKey } from '@aws-sdk/client-s3';
import { DI } from '@/di-symbols.js';
-import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js';
+import type { DriveFilesRepository, UsersRepository, DriveFoldersRepository, UserProfilesRepository } from '@/models/_.js';
import type { Config } from '@/config.js';
import Logger from '@/logger.js';
import type { MiRemoteUser, MiUser } from '@/models/User.js';
+import { MetaService } from '@/core/MetaService.js';
import { MiDriveFile } from '@/models/DriveFile.js';
import { IdService } from '@/core/IdService.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
@@ -42,7 +43,6 @@ import { RoleService } from '@/core/RoleService.js';
import { correctFilename } from '@/misc/correct-filename.js';
import { isMimeImage } from '@/misc/is-mime-image.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { UtilityService } from '@/core/UtilityService.js';
type AddFileArgs = {
/** User who wish to add file */
@@ -98,9 +98,6 @@ export class DriveService {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -117,6 +114,7 @@ export class DriveService {
private userEntityService: UserEntityService,
private driveFileEntityService: DriveFileEntityService,
private idService: IdService,
+ private metaService: MetaService,
private downloadService: DownloadService,
private internalStorageService: InternalStorageService,
private s3Service: S3Service,
@@ -129,7 +127,6 @@ export class DriveService {
private driveChart: DriveChart,
private perUserDriveChart: PerUserDriveChart,
private instanceChart: InstanceChart,
- private utilityService: UtilityService,
) {
const logger = new Logger('drive', 'blue');
this.registerLogger = logger.createSubLogger('register', 'yellow');
@@ -150,7 +147,9 @@ export class DriveService {
// thunbnail, webpublic を必要なら生成
const alts = await this.generateAlts(path, type, !file.uri);
- if (this.meta.useObjectStorage) {
+ const meta = await this.metaService.fetch();
+
+ if (meta.useObjectStorage) {
//#region ObjectStorage params
let [ext] = (name.match(/\.([a-zA-Z0-9_-]+)$/) ?? ['']);
@@ -169,11 +168,11 @@ export class DriveService {
ext = '';
}
- const baseUrl = this.meta.objectStorageBaseUrl
- ?? `${ this.meta.objectStorageUseSSL ? 'https' : 'http' }://${ this.meta.objectStorageEndpoint }${ this.meta.objectStoragePort ? `:${this.meta.objectStoragePort}` : '' }/${ this.meta.objectStorageBucket }`;
+ const baseUrl = meta.objectStorageBaseUrl
+ ?? `${ meta.objectStorageUseSSL ? 'https' : 'http' }://${ meta.objectStorageEndpoint }${ meta.objectStoragePort ? `:${meta.objectStoragePort}` : '' }/${ meta.objectStorageBucket }`;
// for original
- const key = `${this.meta.objectStoragePrefix}/${randomUUID()}${ext}`;
+ const key = `${meta.objectStoragePrefix}/${randomUUID()}${ext}`;
const url = `${ baseUrl }/${ key }`;
// for alts
@@ -190,7 +189,7 @@ export class DriveService {
];
if (alts.webpublic) {
- webpublicKey = `${this.meta.objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
+ webpublicKey = `${meta.objectStoragePrefix}/webpublic-${randomUUID()}.${alts.webpublic.ext}`;
webpublicUrl = `${ baseUrl }/${ webpublicKey }`;
this.registerLogger.info(`uploading webpublic: ${webpublicKey}`);
@@ -198,7 +197,7 @@ export class DriveService {
}
if (alts.thumbnail) {
- thumbnailKey = `${this.meta.objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
+ thumbnailKey = `${meta.objectStoragePrefix}/thumbnail-${randomUUID()}.${alts.thumbnail.ext}`;
thumbnailUrl = `${ baseUrl }/${ thumbnailKey }`;
this.registerLogger.info(`uploading thumbnail: ${thumbnailKey}`);
@@ -221,39 +220,31 @@ export class DriveService {
file.size = size;
file.storedInternal = false;
- return await this.driveFilesRepository.insertOne(file);
+ return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
} else { // use internal storage
const accessKey = randomUUID();
const thumbnailAccessKey = 'thumbnail-' + randomUUID();
const webpublicAccessKey = 'webpublic-' + randomUUID();
- // Ugly type is just to help TS figure out that 2nd / 3rd promises are optional.
- const promises: [Promise, ...(Promise | undefined)[]] = [
- this.internalStorageService.saveFromPath(accessKey, path),
- ];
+ const url = this.internalStorageService.saveFromPath(accessKey, path);
+
+ let thumbnailUrl: string | null = null;
+ let webpublicUrl: string | null = null;
if (alts.thumbnail) {
- promises.push(this.internalStorageService.saveFromBuffer(thumbnailAccessKey, alts.thumbnail.data));
- }
-
- if (alts.webpublic) {
- promises.push(this.internalStorageService.saveFromBuffer(webpublicAccessKey, alts.webpublic.data));
- }
-
- const [url, thumbnailUrl, webpublicUrl] = await Promise.all(promises);
-
- if (thumbnailUrl) {
+ thumbnailUrl = this.internalStorageService.saveFromBuffer(thumbnailAccessKey, alts.thumbnail.data);
this.registerLogger.info(`thumbnail stored: ${thumbnailAccessKey}`);
}
- if (webpublicUrl) {
+ if (alts.webpublic) {
+ webpublicUrl = this.internalStorageService.saveFromBuffer(webpublicAccessKey, alts.webpublic.data);
this.registerLogger.info(`web stored: ${webpublicAccessKey}`);
}
file.storedInternal = true;
file.url = url;
- file.thumbnailUrl = thumbnailUrl ?? null;
- file.webpublicUrl = webpublicUrl ?? null;
+ file.thumbnailUrl = thumbnailUrl;
+ file.webpublicUrl = webpublicUrl;
file.accessKey = accessKey;
file.thumbnailAccessKey = thumbnailAccessKey;
file.webpublicAccessKey = webpublicAccessKey;
@@ -263,7 +254,7 @@ export class DriveService {
file.md5 = hash;
file.size = size;
- return await this.driveFilesRepository.insertOne(file);
+ return await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
}
}
@@ -383,8 +374,10 @@ export class DriveService {
if (type === 'image/apng') type = 'image/png';
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
+ const meta = await this.metaService.fetch();
+
const params = {
- Bucket: this.meta.objectStorageBucket,
+ Bucket: meta.objectStorageBucket,
Key: key,
Body: stream,
ContentType: type,
@@ -397,9 +390,9 @@ export class DriveService {
// 許可されているファイル形式でしか拡張子をつけない
ext ? correctFilename(filename, ext) : filename,
);
- if (this.meta.objectStorageSetPublicRead) params.ACL = 'public-read';
+ if (meta.objectStorageSetPublicRead) params.ACL = 'public-read';
- await this.s3Service.upload(this.meta, params)
+ await this.s3Service.upload(meta, params)
.then(
result => {
if ('Bucket' in result) { // CompleteMultipartUploadCommandOutput
@@ -468,7 +461,9 @@ export class DriveService {
requestHeaders = null,
ext = null,
}: AddFileArgs): Promise {
+ const instance = await this.metaService.fetch();
const userRoleNSFW = user && (await this.roleService.getUserPolicies(user.id)).alwaysMarkNsfw;
+
const info = await this.fileInfoService.getFileInfo(path);
this.registerLogger.info(`${JSON.stringify(info)}`);
@@ -482,20 +477,14 @@ export class DriveService {
if (user && !force) {
// Check if there is a file with the same hash
- const matched = await this.driveFilesRepository.findOneBy({
+ const much = await this.driveFilesRepository.findOneBy({
md5: info.md5,
userId: user.id,
});
- if (matched) {
- this.registerLogger.info(`file with same hash is found: ${matched.id}`);
- if (sensitive && !matched.isSensitive) {
- // The file is federated as sensitive for this time, but was federated as non-sensitive before.
- // Therefore, update the file to sensitive.
- await this.driveFilesRepository.update({ id: matched.id }, { isSensitive: true });
- matched.isSensitive = true;
- }
- return matched;
+ if (much) {
+ this.registerLogger.info(`file with same hash is found: ${much.id}`);
+ return much;
}
}
@@ -568,11 +557,10 @@ export class DriveService {
file.maybeSensitive = info.sensitive;
file.maybePorn = info.porn;
file.isSensitive = user
- ? this.userEntityService.isLocalUser(user) && (profile!.alwaysMarkNsfw || profile!.defaultSensitive) ? true :
+ ? this.userEntityService.isLocalUser(user) && profile!.alwaysMarkNsfw ? true :
sensitive ?? false
: false;
- if (user && this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, user.host)) file.isSensitive = true;
if (info.sensitive && profile!.autoSensitive) file.isSensitive = true;
if (userRoleNSFW) file.isSensitive = true;
@@ -600,7 +588,7 @@ export class DriveService {
file.type = info.type.mime;
file.storedInternal = false;
- file = await this.driveFilesRepository.insertOne(file);
+ file = await this.driveFilesRepository.insert(file).then(x => this.driveFilesRepository.findOneByOrFail(x.identifiers[0]));
} catch (err) {
// duplicate key error (when already registered)
if (isDuplicateKeyValueError(err)) {
@@ -634,7 +622,7 @@ export class DriveService {
// ローカルユーザーのみ
this.perUserDriveChart.update(file, true);
} else {
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateDrive(file, true);
}
}
@@ -644,8 +632,7 @@ export class DriveService {
@bindThis
public async updateFile(file: MiDriveFile, values: Partial, updater: MiUser) {
- const profile = file.userId ? await this.userProfilesRepository.findOneBy({ userId: file.userId }) : null;
- const alwaysMarkNsfw = file.userId ? (await this.roleService.getUserPolicies(file.userId)).alwaysMarkNsfw || (profile !== null && profile!.alwaysMarkNsfw) : false;
+ const alwaysMarkNsfw = (await this.roleService.getUserPolicies(file.userId)).alwaysMarkNsfw;
if (values.name != null && !this.driveFileEntityService.validateFileName(values.name)) {
throw new DriveService.InvalidFileNameError();
@@ -728,19 +715,19 @@ export class DriveService {
@bindThis
public async deleteFileSync(file: MiDriveFile, isExpired = false, deleter?: MiUser) {
- const promises = [];
-
if (file.storedInternal) {
- promises.push(this.internalStorageService.del(file.accessKey!));
+ this.internalStorageService.del(file.accessKey!);
if (file.thumbnailUrl) {
- promises.push(this.internalStorageService.del(file.thumbnailAccessKey!));
+ this.internalStorageService.del(file.thumbnailAccessKey!);
}
if (file.webpublicUrl) {
- promises.push(this.internalStorageService.del(file.webpublicAccessKey!));
+ this.internalStorageService.del(file.webpublicAccessKey!);
}
} else if (!file.isLink) {
+ const promises = [];
+
promises.push(this.deleteObjectStorageFile(file.accessKey!));
if (file.thumbnailUrl) {
@@ -750,9 +737,9 @@ export class DriveService {
if (file.webpublicUrl) {
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!));
}
- }
- await Promise.all(promises);
+ await Promise.all(promises);
+ }
this.deletePostProcess(file, isExpired, deleter);
}
@@ -781,7 +768,7 @@ export class DriveService {
// ローカルユーザーのみ
this.perUserDriveChart.update(file, false);
} else {
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateDrive(file, false);
}
}
@@ -803,13 +790,14 @@ export class DriveService {
@bindThis
public async deleteObjectStorageFile(key: string) {
+ const meta = await this.metaService.fetch();
try {
const param = {
- Bucket: this.meta.objectStorageBucket,
+ Bucket: meta.objectStorageBucket,
Key: key,
} as DeleteObjectCommandInput;
- await this.s3Service.delete(this.meta, param);
+ await this.s3Service.delete(meta, param);
} catch (err: any) {
if (err.name === 'NoSuchKey') {
this.deleteLogger.warn(`The object storage had no such key to delete: ${key}. Skipping this.`, err as Error);
diff --git a/packages/backend/src/core/EmailService.ts b/packages/backend/src/core/EmailService.ts
index da198d0e42..08f8f80a6e 100644
--- a/packages/backend/src/core/EmailService.ts
+++ b/packages/backend/src/core/EmailService.ts
@@ -5,14 +5,14 @@
import { URLSearchParams } from 'node:url';
import * as nodemailer from 'nodemailer';
-import juice from 'juice';
import { Inject, Injectable } from '@nestjs/common';
import { validate as validateEmail } from 'deep-email-validator';
+import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type Logger from '@/logger.js';
-import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
+import type { UserProfilesRepository } from '@/models/_.js';
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
@@ -25,12 +25,10 @@ export class EmailService {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
+ private metaService: MetaService,
private loggerService: LoggerService,
private utilityService: UtilityService,
private httpRequestService: HttpRequestService,
@@ -40,26 +38,35 @@ export class EmailService {
@bindThis
public async sendEmail(to: string, subject: string, html: string, text: string) {
- if (!this.meta.enableEmail) return;
+ const meta = await this.metaService.fetch(true);
+
+ if (!meta.enableEmail) return;
const iconUrl = `${this.config.url}/static-assets/mi-white.png`;
const emailSettingUrl = `${this.config.url}/settings/email`;
- const enableAuth = this.meta.smtpUser != null && this.meta.smtpUser !== '';
+ const enableAuth = meta.smtpUser != null && meta.smtpUser !== '';
const transporter = nodemailer.createTransport({
- host: this.meta.smtpHost,
- port: this.meta.smtpPort,
- secure: this.meta.smtpSecure,
+ host: meta.smtpHost,
+ port: meta.smtpPort,
+ secure: meta.smtpSecure,
ignoreTLS: !enableAuth,
proxy: this.config.proxySmtp,
auth: enableAuth ? {
- user: this.meta.smtpUser,
- pass: this.meta.smtpPass,
+ user: meta.smtpUser,
+ pass: meta.smtpPass,
} : undefined,
} as any);
- const htmlContent = `
+ try {
+ // TODO: htmlサニタイズ
+ const info = await transporter.sendMail({
+ from: meta.email!,
+ to: to,
+ subject: subject,
+ text: text,
+ html: `
@@ -124,7 +131,7 @@ export class EmailService {
-
+
${ subject }
@@ -138,18 +145,7 @@ export class EmailService {
${ this.config.host }
-`;
-
- const inlinedHtml = juice(htmlContent);
-
- try {
- // TODO: htmlサニタイズ
- const info = await transporter.sendMail({
- from: this.meta.email!,
- to: to,
- subject: subject,
- text: text,
- html: inlinedHtml,
+`,
});
this.logger.info(`Message sent: ${info.messageId}`);
@@ -164,6 +160,8 @@ export class EmailService {
available: boolean;
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist';
}> {
+ const meta = await this.metaService.fetch();
+
const exist = await this.userProfilesRepository.countBy({
emailVerified: true,
email: emailAddress,
@@ -181,11 +179,11 @@ export class EmailService {
reason?: string | null,
} = { valid: true, reason: null };
- if (this.meta.enableActiveEmailValidation) {
- if (this.meta.enableVerifymailApi && this.meta.verifymailAuthKey != null) {
- validated = await this.verifyMail(emailAddress, this.meta.verifymailAuthKey);
- } else if (this.meta.enableTruemailApi && this.meta.truemailInstance && this.meta.truemailAuthKey != null) {
- validated = await this.trueMail(this.meta.truemailInstance, emailAddress, this.meta.truemailAuthKey);
+ if (meta.enableActiveEmailValidation) {
+ if (meta.enableVerifymailApi && meta.verifymailAuthKey != null) {
+ validated = await this.verifyMail(emailAddress, meta.verifymailAuthKey);
+ } else if (meta.enableTruemailApi && meta.truemailInstance && meta.truemailAuthKey != null) {
+ validated = await this.trueMail(meta.truemailInstance, emailAddress, meta.truemailAuthKey);
} else {
validated = await validateEmail({
email: emailAddress,
@@ -215,7 +213,7 @@ export class EmailService {
}
const emailDomain: string = emailAddress.split('@')[1];
- const isBanned = this.utilityService.isBlockedHost(this.meta.bannedEmailDomains, emailDomain);
+ const isBanned = this.utilityService.isBlockedHost(meta.bannedEmailDomains, emailDomain);
if (isBanned) {
return {
@@ -312,7 +310,6 @@ export class EmailService {
Accept: 'application/json',
Authorization: truemailAuthKey,
},
- isLocalAddressAllowed: true,
});
const json = (await res.json()) as {
diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts
index bd86a80cbd..6aa63d7d55 100644
--- a/packages/backend/src/core/FanoutTimelineEndpointService.ts
+++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts
@@ -13,7 +13,7 @@ import type { NotesRepository } from '@/models/_.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { FanoutTimelineName, FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { isUserRelated } from '@/misc/is-user-related.js';
-import { isQuote, isRenote } from '@/misc/is-renote.js';
+import { isPureRenote } from '@/misc/is-pure-renote.js';
import { CacheService } from '@/core/CacheService.js';
import { isReply } from '@/misc/is-reply.js';
import { isInstanceMuted } from '@/misc/is-instance-muted.js';
@@ -56,20 +56,24 @@ export class FanoutTimelineEndpointService {
@bindThis
private async getMiNotes(ps: TimelineOptions): Promise {
+ let noteIds: string[];
+ let shouldFallbackToDb = false;
+
// 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える
if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]);
- const ascending = ps.sinceId && !ps.untilId;
- const idCompare: (a: string, b: string) => number = ascending ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1;
+ const shouldPrepend = ps.sinceId && !ps.untilId;
+ const idCompare: (a: string, b: string) => number = shouldPrepend ? (a, b) => a < b ? -1 : 1 : (a, b) => a > b ? -1 : 1;
const redisResult = await this.fanoutTimelineService.getMulti(ps.redisTimelines, ps.untilId, ps.sinceId);
// TODO: いい感じにgetMulti内でソート済だからuniqするときにredisResultが全てソート済なのを利用して再ソートを避けたい
- const redisResultIds = Array.from(new Set(redisResult.flat(1))).sort(idCompare);
+ const redisResultIds = Array.from(new Set(redisResult.flat(1)));
- let noteIds = redisResultIds.slice(0, ps.limit);
- const oldestNoteId = ascending ? redisResultIds[0] : redisResultIds[redisResultIds.length - 1];
- const shouldFallbackToDb = noteIds.length === 0 || ps.sinceId != null && ps.sinceId < oldestNoteId;
+ redisResultIds.sort(idCompare);
+ noteIds = redisResultIds.slice(0, ps.limit);
+
+ shouldFallbackToDb = shouldFallbackToDb || (noteIds.length === 0);
if (!shouldFallbackToDb) {
let filter = ps.noteFilter ?? (_note => true);
@@ -97,7 +101,7 @@ export class FanoutTimelineEndpointService {
if (ps.excludePureRenotes) {
const parentFilter = filter;
- filter = (note) => (!isRenote(note) || isQuote(note)) && parentFilter(note);
+ filter = (note) => !isPureRenote(note) && parentFilter(note);
}
if (ps.me) {
@@ -118,7 +122,9 @@ export class FanoutTimelineEndpointService {
filter = (note) => {
if (isUserRelated(note, userIdsWhoBlockingMe, ps.ignoreAuthorFromBlock)) return false;
if (isUserRelated(note, userIdsWhoMeMuting, ps.ignoreAuthorFromMute)) return false;
- if (!ps.ignoreAuthorFromMute && isRenote(note) && !isQuote(note) && userIdsWhoMeMutingRenotes.has(note.userId)) return false;
+ if (note.mentions.some(mention => userIdsWhoMeMuting.has(mention))) return false;
+ if (isPureRenote(note) && note.renote && note.renote.mentions.some(mention => userIdsWhoMeMuting.has(mention))) return false;
+ if (isPureRenote(note) && isUserRelated(note, userIdsWhoMeMutingRenotes, ps.ignoreAuthorFromMute)) return false;
if (isInstanceMuted(note, userMutedInstances)) return false;
return parentFilter(note);
@@ -144,7 +150,9 @@ export class FanoutTimelineEndpointService {
if (ps.allowPartial ? redisTimeline.length !== 0 : redisTimeline.length >= ps.limit) {
// 十分Redisからとれた
- return redisTimeline.slice(0, ps.limit);
+ const result = redisTimeline.slice(0, ps.limit);
+ if (shouldPrepend) result.reverse();
+ return result;
}
}
@@ -152,7 +160,8 @@ export class FanoutTimelineEndpointService {
const remainingToRead = ps.limit - redisTimeline.length;
let dbUntil: string | null;
let dbSince: string | null;
- if (ascending) {
+ if (shouldPrepend) {
+ redisTimeline.reverse();
dbUntil = ps.untilId;
dbSince = noteIds[noteIds.length - 1];
} else {
@@ -160,7 +169,7 @@ export class FanoutTimelineEndpointService {
dbSince = ps.sinceId;
}
const gotFromDb = await ps.dbFallback(dbUntil, dbSince, remainingToRead);
- return [...redisTimeline, ...gotFromDb];
+ return shouldPrepend ? [...gotFromDb, ...redisTimeline] : [...redisTimeline, ...gotFromDb];
}
return await ps.dbFallback(ps.untilId, ps.sinceId, ps.limit);
diff --git a/packages/backend/src/core/FederatedInstanceService.ts b/packages/backend/src/core/FederatedInstanceService.ts
index 7ec565557c..66db2067d9 100644
--- a/packages/backend/src/core/FederatedInstanceService.ts
+++ b/packages/backend/src/core/FederatedInstanceService.ts
@@ -12,8 +12,6 @@ import { IdService } from '@/core/IdService.js';
import { DI } from '@/di-symbols.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
-import { QueryFailedError } from 'typeorm';
-import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
@Injectable()
export class FederatedInstanceService implements OnApplicationShutdown {
@@ -42,7 +40,6 @@ export class FederatedInstanceService implements OnApplicationShutdown {
firstRetrievedAt: new Date(parsed.firstRetrievedAt),
latestRequestReceivedAt: parsed.latestRequestReceivedAt ? new Date(parsed.latestRequestReceivedAt) : null,
infoUpdatedAt: parsed.infoUpdatedAt ? new Date(parsed.infoUpdatedAt) : null,
- notRespondingSince: parsed.notRespondingSince ? new Date(parsed.notRespondingSince) : null,
};
},
});
@@ -58,24 +55,11 @@ export class FederatedInstanceService implements OnApplicationShutdown {
const index = await this.instancesRepository.findOneBy({ host });
if (index == null) {
- let i;
- try {
- i = await this.instancesRepository.insertOne({
- id: this.idService.gen(),
- host,
- firstRetrievedAt: new Date(),
- });
- } catch (e: unknown) {
- if (e instanceof QueryFailedError) {
- if (isDuplicateKeyValueError(e)) {
- i = await this.instancesRepository.findOneBy({ host });
- }
- }
-
- if (i == null) {
- throw e;
- }
- }
+ const i = await this.instancesRepository.insert({
+ id: this.idService.gen(),
+ host,
+ firstRetrievedAt: new Date(),
+ }).then(x => this.instancesRepository.findOneByOrFail(x.identifiers[0]));
this.federatedInstanceCache.set(host, i);
return i;
diff --git a/packages/backend/src/core/FetchInstanceMetadataService.ts b/packages/backend/src/core/FetchInstanceMetadataService.ts
index aa16468ecb..bc270bd28f 100644
--- a/packages/backend/src/core/FetchInstanceMetadataService.ts
+++ b/packages/backend/src/core/FetchInstanceMetadataService.ts
@@ -51,35 +51,21 @@ export class FetchInstanceMetadataService {
}
@bindThis
- // public for test
- public async tryLock(host: string): Promise {
- // TODO: マイグレーションなのであとで消す (2024.3.1)
- this.redisClient.del(`fetchInstanceMetadata:mutex:${host}`);
-
- return await this.redisClient.set(
- `fetchInstanceMetadata:mutex:v2:${host}`, '1',
- 'EX', 30, // 30秒したら自動でロック解除 https://github.com/misskey-dev/misskey/issues/13506#issuecomment-1975375395
- 'GET' // 古い値を返す(なかったらnull)
- );
+ public async tryLock(host: string): Promise {
+ const mutex = await this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '1', 'GET');
+ return mutex !== '1';
}
@bindThis
- // public for test
- public unlock(host: string): Promise {
- return this.redisClient.del(`fetchInstanceMetadata:mutex:v2:${host}`);
+ public unlock(host: string): Promise<'OK'> {
+ return this.redisClient.set(`fetchInstanceMetadata:mutex:${host}`, '0');
}
@bindThis
public async fetchInstanceMetadata(instance: MiInstance, force = false): Promise {
const host = instance.host;
-
- // finallyでunlockされてしまうのでtry内でロックチェックをしない
- // (returnであってもfinallyは実行される)
- if (!force && await this.tryLock(host) === '1') {
- // 1が返ってきていたらロックされているという意味なので、何もしない
- return;
- }
-
+ // Acquire mutex to ensure no parallel runs
+ if (!await this.tryLock(host)) return;
try {
if (!force) {
const _instance = await this.federatedInstanceService.fetch(host);
@@ -154,7 +140,7 @@ export class FetchInstanceMetadataService {
throw new Error('No wellknown links');
}
- const links = wellknown.links as ({ rel: string, href: string; })[];
+ const links = wellknown.links as any[];
const link1_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/1.0');
const link2_0 = links.find(link => link.rel === 'http://nodeinfo.diaspora.software/ns/schema/2.0');
diff --git a/packages/backend/src/core/FileInfoService.ts b/packages/backend/src/core/FileInfoService.ts
index cc66e9fe3a..1698b2987e 100644
--- a/packages/backend/src/core/FileInfoService.ts
+++ b/packages/backend/src/core/FileInfoService.ts
@@ -8,13 +8,10 @@ import * as crypto from 'node:crypto';
import * as stream from 'node:stream/promises';
import { Injectable } from '@nestjs/common';
import * as fileType from 'file-type';
-import FFmpeg from 'fluent-ffmpeg';
import isSvg from 'is-svg';
import probeImageSize from 'probe-image-size';
-import { sharpBmp } from '@misskey-dev/sharp-read-bmp';
-import * as blurhash from 'blurhash';
-import { LoggerService } from '@/core/LoggerService.js';
-import type Logger from '@/logger.js';
+import sharp from 'sharp';
+import { encode } from 'blurhash';
import { bindThis } from '@/decorators.js';
export type FileInfo = {
@@ -45,12 +42,8 @@ const TYPE_SVG = {
@Injectable()
export class FileInfoService {
- private logger: Logger;
-
constructor(
- private loggerService: LoggerService,
) {
- this.logger = this.loggerService.getLogger('file-info');
}
/**
@@ -117,7 +110,7 @@ export class FileInfoService {
'image/avif',
'image/svg+xml',
].includes(type.mime)) {
- blurhash = await this.getBlurhash(path, type.mime).catch(e => {
+ blurhash = await this.getBlurhash(path).catch(e => {
warnings.push(`getBlurhash failed: ${e}`);
return undefined;
});
@@ -153,34 +146,6 @@ export class FileInfoService {
return mime;
}
- /**
- * ビデオファイルにビデオトラックがあるかどうかチェック
- * (ない場合:m4a, webmなど)
- *
- * @param path ファイルパス
- * @returns ビデオトラックがあるかどうか(エラー発生時は常に`true`を返す)
- */
- @bindThis
- private hasVideoTrackOnVideoFile(path: string): Promise {
- const sublogger = this.logger.createSubLogger('ffprobe');
- sublogger.info(`Checking the video file. File path: ${path}`);
- return new Promise((resolve) => {
- try {
- FFmpeg.ffprobe(path, (err, metadata) => {
- if (err) {
- sublogger.warn(`Could not check the video file. Returns true. File path: ${path}`, err);
- resolve(true);
- return;
- }
- resolve(metadata.streams.some((stream) => stream.codec_type === 'video'));
- });
- } catch (err) {
- sublogger.warn(`Could not check the video file. Returns true. File path: ${path}`, err as Error);
- resolve(true);
- }
- });
- }
-
/**
* Detect MIME Type and extension
*/
@@ -203,20 +168,6 @@ export class FileInfoService {
return TYPE_SVG;
}
- if ((type.mime.startsWith('video') || type.mime === 'application/ogg') && !(await this.hasVideoTrackOnVideoFile(path))) {
- const newMime = `audio/${type.mime.split('/')[1]}`;
- if (newMime === 'audio/mp4') {
- return {
- mime: 'audio/mp4',
- ext: 'm4a',
- };
- }
- return {
- mime: newMime,
- ext: type.ext,
- };
- }
-
return {
mime: this.fixMime(type.mime),
ext: type.ext,
@@ -283,12 +234,12 @@ export class FileInfoService {
}
/**
- * Calculate blurhash string of image
+ * Calculate average color of image
*/
@bindThis
- private getBlurhash(path: string, type: string): Promise {
- return new Promise(async (resolve, reject) => {
- (await sharpBmp(path, type))
+ private getBlurhash(path: string): Promise {
+ return new Promise((resolve, reject) => {
+ sharp(path)
.raw()
.ensureAlpha()
.resize(64, 64, { fit: 'inside' })
@@ -298,7 +249,7 @@ export class FileInfoService {
let hash;
try {
- hash = blurhash.encode(new Uint8ClampedArray(buffer), info.width, info.height, 5, 5);
+ hash = encode(new Uint8ClampedArray(buffer), info.width, info.height, 5, 5);
} catch (e) {
return reject(e);
}
diff --git a/packages/backend/src/core/GlobalEventService.ts b/packages/backend/src/core/GlobalEventService.ts
index 211c22bfaf..e568cbf646 100644
--- a/packages/backend/src/core/GlobalEventService.ts
+++ b/packages/backend/src/core/GlobalEventService.ts
@@ -18,7 +18,6 @@ import type { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
import type { MiSignin } from '@/models/Signin.js';
import type { MiPage } from '@/models/Page.js';
import type { MiWebhook } from '@/models/Webhook.js';
-import type { MiSystemWebhook } from '@/models/SystemWebhook.js';
import type { MiMeta } from '@/models/Meta.js';
import { MiAvatarDecoration, MiReversiGame, MiRole, MiRoleAssignment } from '@/models/_.js';
import type { Packed } from '@/misc/json-schema.js';
@@ -70,7 +69,6 @@ export interface MainEventTypes {
file: Packed<'DriveFile'>;
};
readAllNotifications: undefined;
- notificationFlushed: undefined;
unreadNotification: Packed<'Notification'>;
unreadMention: MiNote['id'];
readAllUnreadMentions: undefined;
@@ -136,7 +134,6 @@ export interface NoteEventTypes {
};
replied: {
id: MiNote['id'];
- userId: MiUser['id'];
};
}
type NoteStreamEventTypes = {
@@ -214,16 +211,10 @@ type SerializedAll = {
[K in keyof T]: Serialized;
};
-type UndefinedAsNullAll = {
- [K in keyof T]: T[K] extends undefined ? null : T[K];
-}
-
export interface InternalEventTypes {
userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
- userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; };
userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; };
remoteUserUpdated: { id: MiUser['id']; };
- localUserUpdated: { id: MiUser['id']; };
follow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
unfollow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
blockingCreated: { blockerId: MiUser['id']; blockeeId: MiUser['id']; };
@@ -237,16 +228,13 @@ export interface InternalEventTypes {
webhookCreated: MiWebhook;
webhookDeleted: MiWebhook;
webhookUpdated: MiWebhook;
- systemWebhookCreated: MiSystemWebhook;
- systemWebhookDeleted: MiSystemWebhook;
- systemWebhookUpdated: MiSystemWebhook;
antennaCreated: MiAntenna;
antennaDeleted: MiAntenna;
antennaUpdated: MiAntenna;
avatarDecorationCreated: MiAvatarDecoration;
avatarDecorationDeleted: MiAvatarDecoration;
avatarDecorationUpdated: MiAvatarDecoration;
- metaUpdated: { before?: MiMeta; after: MiMeta; };
+ metaUpdated: MiMeta;
followChannel: { userId: MiUser['id']; channelId: MiChannel['id']; };
unfollowChannel: { userId: MiUser['id']; channelId: MiChannel['id']; };
updateUserProfile: MiUserProfile;
@@ -256,45 +244,43 @@ export interface InternalEventTypes {
userListMemberRemoved: { userListId: MiUserList['id']; memberId: MiUser['id']; };
}
-type EventTypesToEventPayload = EventUnionFromDictionary>>;
-
// name/messages(spec) pairs dictionary
export type GlobalEvents = {
internal: {
name: 'internal';
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
broadcast: {
name: 'broadcast';
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
main: {
name: `mainStream:${MiUser['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
drive: {
name: `driveStream:${MiUser['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
note: {
name: `noteStream:${MiNote['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
userList: {
name: `userListStream:${MiUserList['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
roleTimeline: {
name: `roleTimelineStream:${MiRole['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
antenna: {
name: `antennaStream:${MiAntenna['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
admin: {
name: `adminStream:${MiUser['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
notes: {
name: 'notesStream';
@@ -302,11 +288,11 @@ export type GlobalEvents = {
};
reversi: {
name: `reversiStream:${MiUser['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
reversiGame: {
name: `reversiGameStream:${MiReversiGame['id']}`;
- payload: EventTypesToEventPayload;
+ payload: EventUnionFromDictionary>;
};
};
diff --git a/packages/backend/src/core/HashtagService.ts b/packages/backend/src/core/HashtagService.ts
index 793bbeecb1..eb192ee6da 100644
--- a/packages/backend/src/core/HashtagService.ts
+++ b/packages/backend/src/core/HashtagService.ts
@@ -10,18 +10,16 @@ import type { MiUser } from '@/models/User.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import { IdService } from '@/core/IdService.js';
import type { MiHashtag } from '@/models/Hashtag.js';
-import type { HashtagsRepository, MiMeta } from '@/models/_.js';
+import type { HashtagsRepository } from '@/models/_.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
import { FeaturedService } from '@/core/FeaturedService.js';
+import { MetaService } from '@/core/MetaService.js';
import { UtilityService } from '@/core/UtilityService.js';
@Injectable()
export class HashtagService {
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.redis)
private redisClient: Redis.Redis, // TODO: 専用のRedisサーバーを設定できるようにする
@@ -31,6 +29,7 @@ export class HashtagService {
private userEntityService: UserEntityService,
private featuredService: FeaturedService,
private idService: IdService,
+ private metaService: MetaService,
private utilityService: UtilityService,
) {
}
@@ -161,9 +160,10 @@ export class HashtagService {
@bindThis
public async updateHashtagsRanking(hashtag: string, userId: MiUser['id']): Promise {
- const hiddenTags = this.meta.hiddenTags.map(t => normalizeForSearch(t));
+ const instance = await this.metaService.fetch();
+ const hiddenTags = instance.hiddenTags.map(t => normalizeForSearch(t));
if (hiddenTags.includes(hashtag)) return;
- if (this.utilityService.isKeyWordIncluded(hashtag, this.meta.sensitiveWords)) return;
+ if (this.utilityService.isKeyWordIncluded(hashtag, instance.sensitiveWords)) return;
// YYYYMMDDHHmm (10分間隔)
const now = new Date();
diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts
index 083153940a..7f3cac7c58 100644
--- a/packages/backend/src/core/HttpRequestService.ts
+++ b/packages/backend/src/core/HttpRequestService.ts
@@ -6,7 +6,6 @@
import * as http from 'node:http';
import * as https from 'node:https';
import * as net from 'node:net';
-import ipaddr from 'ipaddr.js';
import CacheableLookup from 'cacheable-lookup';
import fetch from 'node-fetch';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
@@ -16,7 +15,6 @@ import type { Config } from '@/config.js';
import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
import { validateContentTypeSetAsActivityPub } from '@/core/activitypub/misc/validator.js';
-import { assertActivityMatchesUrls } from '@/core/activitypub/misc/check-against-url.js';
import type { IObject } from '@/core/activitypub/type.js';
import type { Response } from 'node-fetch';
import type { URL } from 'node:url';
@@ -26,102 +24,8 @@ export type HttpRequestSendOptions = {
validators?: ((res: Response) => void)[];
};
-declare module 'node:http' {
- interface Agent {
- createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket;
- }
-}
-
-class HttpRequestServiceAgent extends http.Agent {
- constructor(
- private config: Config,
- options?: http.AgentOptions,
- ) {
- super(options);
- }
-
- @bindThis
- public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
- const socket = super.createConnection(options, callback)
- .on('connect', () => {
- const address = socket.remoteAddress;
- if (process.env.NODE_ENV === 'production') {
- if (address && ipaddr.isValid(address)) {
- if (this.isPrivateIp(address)) {
- socket.destroy(new Error(`Blocked address: ${address}`));
- }
- }
- }
- });
- return socket;
- }
-
- @bindThis
- private isPrivateIp(ip: string): boolean {
- const parsedIp = ipaddr.parse(ip);
-
- for (const net of this.config.allowedPrivateNetworks ?? []) {
- const cidr = ipaddr.parseCIDR(net);
- if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
- return false;
- }
- }
-
- return parsedIp.range() !== 'unicast';
- }
-}
-
-class HttpsRequestServiceAgent extends https.Agent {
- constructor(
- private config: Config,
- options?: https.AgentOptions,
- ) {
- super(options);
- }
-
- @bindThis
- public createConnection(options: net.NetConnectOpts, callback?: (err: unknown, stream: net.Socket) => void): net.Socket {
- const socket = super.createConnection(options, callback)
- .on('connect', () => {
- const address = socket.remoteAddress;
- if (process.env.NODE_ENV === 'production') {
- if (address && ipaddr.isValid(address)) {
- if (this.isPrivateIp(address)) {
- socket.destroy(new Error(`Blocked address: ${address}`));
- }
- }
- }
- });
- return socket;
- }
-
- @bindThis
- private isPrivateIp(ip: string): boolean {
- const parsedIp = ipaddr.parse(ip);
-
- for (const net of this.config.allowedPrivateNetworks ?? []) {
- const cidr = ipaddr.parseCIDR(net);
- if (cidr[0].kind() === parsedIp.kind() && parsedIp.match(ipaddr.parseCIDR(net))) {
- return false;
- }
- }
-
- return parsedIp.range() !== 'unicast';
- }
-}
-
@Injectable()
export class HttpRequestService {
- /**
- * Get http non-proxy agent (without local address filtering)
- */
- private httpNative: http.Agent;
-
- /**
- * Get https non-proxy agent (without local address filtering)
- */
- private httpsNative: https.Agent;
-
/**
* Get http non-proxy agent
*/
@@ -152,20 +56,19 @@ export class HttpRequestService {
lookup: false, // nativeのdns.lookupにfallbackしない
});
- const agentOption = {
+ this.http = new http.Agent({
keepAlive: true,
keepAliveMsecs: 30 * 1000,
lookup: cache.lookup as unknown as net.LookupFunction,
localAddress: config.outgoingAddress,
- };
+ });
- this.httpNative = new http.Agent(agentOption);
-
- this.httpsNative = new https.Agent(agentOption);
-
- this.http = new HttpRequestServiceAgent(config, agentOption);
-
- this.https = new HttpsRequestServiceAgent(config, agentOption);
+ this.https = new https.Agent({
+ keepAlive: true,
+ keepAliveMsecs: 30 * 1000,
+ lookup: cache.lookup as unknown as net.LookupFunction,
+ localAddress: config.outgoingAddress,
+ });
const maxSockets = Math.max(256, config.deliverJobConcurrency ?? 128);
@@ -200,22 +103,16 @@ export class HttpRequestService {
* @param bypassProxy Allways bypass proxy
*/
@bindThis
- public getAgentByUrl(url: URL, bypassProxy = false, isLocalAddressAllowed = false): http.Agent | https.Agent {
+ public getAgentByUrl(url: URL, bypassProxy = false): http.Agent | https.Agent {
if (bypassProxy || (this.config.proxyBypassHosts ?? []).includes(url.hostname)) {
- if (isLocalAddressAllowed) {
- return url.protocol === 'http:' ? this.httpNative : this.httpsNative;
- }
return url.protocol === 'http:' ? this.http : this.https;
} else {
- if (isLocalAddressAllowed && (!this.config.proxy)) {
- return url.protocol === 'http:' ? this.httpNative : this.httpsNative;
- }
return url.protocol === 'http:' ? this.httpAgent : this.httpsAgent;
}
}
@bindThis
- public async getActivityJson(url: string, isLocalAddressAllowed = false): Promise {
+ public async getActivityJson(url: string): Promise {
const res = await this.send(url, {
method: 'GET',
headers: {
@@ -223,22 +120,16 @@ export class HttpRequestService {
},
timeout: 5000,
size: 1024 * 256,
- isLocalAddressAllowed: isLocalAddressAllowed,
}, {
throwErrorWhenResponseNotOk: true,
validators: [validateContentTypeSetAsActivityPub],
});
- const finalUrl = res.url; // redirects may have been involved
- const activity = await res.json() as IObject;
-
- assertActivityMatchesUrls(activity, [finalUrl]);
-
- return activity;
+ return await res.json() as IObject;
}
@bindThis
- public async getJson(url: string, accept = 'application/json, */*', headers?: Record, isLocalAddressAllowed = false): Promise {
+ public async getJson(url: string, accept = 'application/json, */*', headers?: Record): Promise {
const res = await this.send(url, {
method: 'GET',
headers: Object.assign({
@@ -246,21 +137,19 @@ export class HttpRequestService {
}, headers ?? {}),
timeout: 5000,
size: 1024 * 256,
- isLocalAddressAllowed: isLocalAddressAllowed,
});
return await res.json() as T;
}
@bindThis
- public async getHtml(url: string, accept = 'text/html, */*', headers?: Record, isLocalAddressAllowed = false): Promise {
+ public async getHtml(url: string, accept = 'text/html, */*', headers?: Record): Promise {
const res = await this.send(url, {
method: 'GET',
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
timeout: 5000,
- isLocalAddressAllowed: isLocalAddressAllowed,
});
return await res.text();
@@ -275,7 +164,6 @@ export class HttpRequestService {
headers?: Record,
timeout?: number,
size?: number,
- isLocalAddressAllowed?: boolean,
} = {},
extra: HttpRequestSendOptions = {
throwErrorWhenResponseNotOk: true,
@@ -289,8 +177,6 @@ export class HttpRequestService {
controller.abort();
}, timeout);
- const isLocalAddressAllowed = args.isLocalAddressAllowed ?? false;
-
const res = await fetch(url, {
method: args.method ?? 'GET',
headers: {
@@ -299,7 +185,7 @@ export class HttpRequestService {
},
body: args.body,
size: args.size ?? 10 * 1024 * 1024,
- agent: (url) => this.getAgentByUrl(url, false, isLocalAddressAllowed),
+ agent: (url) => this.getAgentByUrl(url),
signal: controller.signal,
});
diff --git a/packages/backend/src/core/InternalStorageService.ts b/packages/backend/src/core/InternalStorageService.ts
index b00c5796d2..4fb8a93e49 100644
--- a/packages/backend/src/core/InternalStorageService.ts
+++ b/packages/backend/src/core/InternalStorageService.ts
@@ -4,7 +4,6 @@
*/
import * as fs from 'node:fs';
-import { copyFile, unlink, writeFile, chmod } from 'node:fs/promises';
import * as Path from 'node:path';
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
@@ -24,8 +23,6 @@ export class InternalStorageService {
@Inject(DI.config)
private config: Config,
) {
- // No one should erase the working directory *while the server is running*.
- fs.mkdirSync(path, { recursive: true });
}
@bindThis
@@ -39,27 +36,21 @@ export class InternalStorageService {
}
@bindThis
- public async saveFromPath(key: string, srcPath: string): Promise {
- await copyFile(srcPath, this.resolvePath(key));
- return await this.finalizeSavedFile(key);
- }
-
- @bindThis
- public async saveFromBuffer(key: string, data: Buffer): Promise {
- await writeFile(this.resolvePath(key), data);
- return await this.finalizeSavedFile(key);
- }
-
- private async finalizeSavedFile(key: string): Promise {
- if (this.config.filePermissionBits) {
- const path = this.resolvePath(key);
- await chmod(path, this.config.filePermissionBits);
- }
+ public saveFromPath(key: string, srcPath: string) {
+ fs.mkdirSync(path, { recursive: true });
+ fs.copyFileSync(srcPath, this.resolvePath(key));
return `${this.config.url}/files/${key}`;
}
@bindThis
- public async del(key: string): Promise {
- await unlink(this.resolvePath(key));
+ public saveFromBuffer(key: string, data: Buffer) {
+ fs.mkdirSync(path, { recursive: true });
+ fs.writeFileSync(this.resolvePath(key), data);
+ return `${this.config.url}/files/${key}`;
+ }
+
+ @bindThis
+ public del(key: string) {
+ fs.unlink(this.resolvePath(key), () => {});
}
}
diff --git a/packages/backend/src/core/LatestNoteService.ts b/packages/backend/src/core/LatestNoteService.ts
deleted file mode 100644
index c379805506..0000000000
--- a/packages/backend/src/core/LatestNoteService.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import { Inject, Injectable } from '@nestjs/common';
-import { Not } from 'typeorm';
-import { MiNote } from '@/models/Note.js';
-import { isPureRenote } from '@/misc/is-renote.js';
-import { SkLatestNote } from '@/models/LatestNote.js';
-import { DI } from '@/di-symbols.js';
-import type { LatestNotesRepository, NotesRepository } from '@/models/_.js';
-import { LoggerService } from '@/core/LoggerService.js';
-import Logger from '@/logger.js';
-
-@Injectable()
-export class LatestNoteService {
- private readonly logger: Logger;
-
- constructor(
- @Inject(DI.notesRepository)
- private notesRepository: NotesRepository,
-
- @Inject(DI.latestNotesRepository)
- private latestNotesRepository: LatestNotesRepository,
-
- loggerService: LoggerService,
- ) {
- this.logger = loggerService.getLogger('LatestNoteService');
- }
-
- handleUpdatedNoteBG(before: MiNote, after: MiNote): void {
- this
- .handleUpdatedNote(before, after)
- .catch(err => this.logger.error('Unhandled exception while updating latest_note (after update):', err));
- }
-
- async handleUpdatedNote(before: MiNote, after: MiNote): Promise {
- // If the key didn't change, then there's nothing to update
- if (SkLatestNote.areEquivalent(before, after)) return;
-
- // Simulate update as delete + create
- await this.handleDeletedNote(before);
- await this.handleCreatedNote(after);
- }
-
- handleCreatedNoteBG(note: MiNote): void {
- this
- .handleCreatedNote(note)
- .catch(err => this.logger.error('Unhandled exception while updating latest_note (after create):', err));
- }
-
- async handleCreatedNote(note: MiNote): Promise {
- // Ignore DMs.
- // Followers-only posts are *included*, as this table is used to back the "following" feed.
- if (note.visibility === 'specified') return;
-
- // Ignore pure renotes
- if (isPureRenote(note)) return;
-
- // Compute the compound key of the entry to check
- const key = SkLatestNote.keyFor(note);
-
- // Make sure that this isn't an *older* post.
- // We can get older posts through replies, lookups, updates, etc.
- const currentLatest = await this.latestNotesRepository.findOneBy(key);
- if (currentLatest != null && currentLatest.noteId >= note.id) return;
-
- // Record this as the latest note for the given user
- const latestNote = new SkLatestNote({
- ...key,
- noteId: note.id,
- });
- await this.latestNotesRepository.upsert(latestNote, ['userId', 'isPublic', 'isReply', 'isQuote']);
- }
-
- handleDeletedNoteBG(note: MiNote): void {
- this
- .handleDeletedNote(note)
- .catch(err => this.logger.error('Unhandled exception while updating latest_note (after delete):', err));
- }
-
- async handleDeletedNote(note: MiNote): Promise {
- // If it's a DM, then it can't possibly be the latest note so we can safely skip this.
- if (note.visibility === 'specified') return;
-
- // If it's a pure renote, then it can't possibly be the latest note so we can safely skip this.
- if (isPureRenote(note)) return;
-
- // Compute the compound key of the entry to check
- const key = SkLatestNote.keyFor(note);
-
- // Check if the deleted note was possibly the latest for the user
- const existingLatest = await this.latestNotesRepository.findOneBy(key);
- if (existingLatest == null || existingLatest.noteId !== note.id) return;
-
- // Find the newest remaining note for the user.
- // We exclude DMs and pure renotes.
- const nextLatest = await this.notesRepository
- .createQueryBuilder('note')
- .select()
- .where({
- userId: key.userId,
- visibility: key.isPublic
- ? 'public'
- : Not('specified'),
- replyId: key.isReply
- ? Not(null)
- : null,
- renoteId: key.isQuote
- ? Not(null)
- : null,
- })
- .andWhere(`
- (
- note."renoteId" IS NULL
- OR note.text IS NOT NULL
- OR note.cw IS NOT NULL
- OR note."replyId" IS NOT NULL
- OR note."hasPoll"
- OR note."fileIds" != '{}'
- )
- `)
- .orderBy({ id: 'DESC' })
- .getOne();
- if (!nextLatest) return;
-
- // Record it as the latest
- const latestNote = new SkLatestNote({
- ...key,
- noteId: nextLatest.id,
- });
-
- // When inserting the latest note, it's possible that another worker has "raced" the insert and already added a newer note.
- // We must use orIgnore() to ensure that the query ignores conflicts, otherwise an exception may be thrown.
- await this.latestNotesRepository
- .createQueryBuilder('latest')
- .insert()
- .into(SkLatestNote)
- .values(latestNote)
- .orIgnore()
- .execute();
- }
-}
diff --git a/packages/backend/src/core/LoggerService.ts b/packages/backend/src/core/LoggerService.ts
index f102461a50..96d9b09992 100644
--- a/packages/backend/src/core/LoggerService.ts
+++ b/packages/backend/src/core/LoggerService.ts
@@ -15,7 +15,7 @@ export class LoggerService {
}
@bindThis
- public getLogger(domain: string, color?: KEYWORD | undefined) {
- return new Logger(domain, color);
+ public getLogger(domain: string, color?: KEYWORD | undefined, store?: boolean) {
+ return new Logger(domain, color, store);
}
}
diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts
index 3d88d0aefe..ec630f804e 100644
--- a/packages/backend/src/core/MetaService.ts
+++ b/packages/backend/src/core/MetaService.ts
@@ -52,7 +52,7 @@ export class MetaService implements OnApplicationShutdown {
switch (type) {
case 'metaUpdated': {
this.cache = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
- ...(body.after),
+ ...body,
proxyAccount: null, // joinなカラムは通常取ってこないので
};
break;
@@ -141,7 +141,7 @@ export class MetaService implements OnApplicationShutdown {
});
}
- this.globalEventService.publishInternalEvent('metaUpdated', { before, after: updated });
+ this.globalEventService.publishInternalEvent('metaUpdated', updated);
return updated;
}
diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts
index 42676d6f98..651b752544 100644
--- a/packages/backend/src/core/MfmService.ts
+++ b/packages/backend/src/core/MfmService.ts
@@ -6,19 +6,16 @@
import { URL } from 'node:url';
import { Inject, Injectable } from '@nestjs/common';
import * as parse5 from 'parse5';
-import { Window, XMLSerializer } from 'happy-dom';
+import { Window } from 'happy-dom';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { intersperse } from '@/misc/prelude/array.js';
-import { normalizeForSearch } from '@/misc/normalize-for-search.js';
import type { IMentionedRemoteUsers } from '@/models/Note.js';
import { bindThis } from '@/decorators.js';
-import type { DefaultTreeAdapterMap } from 'parse5';
+import * as TreeAdapter from '../../node_modules/parse5/dist/tree-adapters/default.js';
import type * as mfm from '@transfem-org/sfm-js';
-const treeAdapter = parse5.defaultTreeAdapter;
-type Node = DefaultTreeAdapterMap['node'];
-type ChildNode = DefaultTreeAdapterMap['childNode'];
+const treeAdapter = TreeAdapter.defaultTreeAdapter;
const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/;
const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/;
@@ -36,8 +33,6 @@ export class MfmService {
// some AP servers like Pixelfed use br tags as well as newlines
html = html.replace(/ \r?\n/gi, '\n');
- const normalizedHashtagNames = hashtagNames == null ? undefined : new Set(hashtagNames.map(x => normalizeForSearch(x)));
-
const dom = parse5.parseFragment(html);
let text = '';
@@ -48,7 +43,7 @@ export class MfmService {
return text.trim();
- function getText(node: Node): string {
+ function getText(node: TreeAdapter.Node): string {
if (treeAdapter.isTextNode(node)) return node.value;
if (!treeAdapter.isElementNode(node)) return '';
if (node.nodeName === 'br') return '\n';
@@ -60,7 +55,7 @@ export class MfmService {
return '';
}
- function appendChildren(childNodes: ChildNode[]): void {
+ function appendChildren(childNodes: TreeAdapter.ChildNode[]): void {
if (childNodes) {
for (const n of childNodes) {
analyze(n);
@@ -68,16 +63,14 @@ export class MfmService {
}
}
- function analyze(node: Node) {
+ function analyze(node: TreeAdapter.Node) {
if (treeAdapter.isTextNode(node)) {
text += node.value;
return;
}
// Skip comment or document type node
- if (!treeAdapter.isElementNode(node)) {
- return;
- }
+ if (!treeAdapter.isElementNode(node)) return;
switch (node.nodeName) {
case 'br': {
@@ -85,15 +78,16 @@ export class MfmService {
break;
}
- case 'a': {
+ case 'a':
+ {
const txt = getText(node);
const rel = node.attrs.find(x => x.name === 'rel');
const href = node.attrs.find(x => x.name === 'href');
// ハッシュタグ
- if (normalizedHashtagNames && href && normalizedHashtagNames.has(normalizeForSearch(txt))) {
+ if (hashtagNames && href && hashtagNames.map(x => x.toLowerCase()).includes(txt.toLowerCase())) {
text += txt;
- // メンション
+ // メンション
} else if (txt.startsWith('@') && !(rel && rel.value.startsWith('me '))) {
const part = txt.split('@');
@@ -105,7 +99,7 @@ export class MfmService {
} else if (part.length === 3) {
text += txt;
}
- // その他
+ // その他
} else {
const generateLink = () => {
if (!href && !txt) {
@@ -133,30 +127,25 @@ export class MfmService {
break;
}
- case 'h1': {
- text += '**【';
+ case 'h1':
+ {
+ text += '【';
appendChildren(node.childNodes);
- text += '】**\n';
- break;
- }
-
- case 'h2':
- case 'h3': {
- text += '**';
- appendChildren(node.childNodes);
- text += '**\n';
+ text += '】\n';
break;
}
case 'b':
- case 'strong': {
+ case 'strong':
+ {
text += '**';
appendChildren(node.childNodes);
text += '**';
break;
}
- case 'small': {
+ case 'small':
+ {
text += '';
appendChildren(node.childNodes);
text += ' ';
@@ -164,7 +153,8 @@ export class MfmService {
}
case 's':
- case 'del': {
+ case 'del':
+ {
text += '~~';
appendChildren(node.childNodes);
text += '~~';
@@ -172,7 +162,8 @@ export class MfmService {
}
case 'i':
- case 'em': {
+ case 'em':
+ {
text += '';
appendChildren(node.childNodes);
text += ' ';
@@ -209,9 +200,12 @@ export class MfmService {
}
case 'p':
+ case 'h2':
+ case 'h3':
case 'h4':
case 'h5':
- case 'h6': {
+ case 'h6':
+ {
text += '\n\n';
appendChildren(node.childNodes);
break;
@@ -224,7 +218,8 @@ export class MfmService {
case 'article':
case 'li':
case 'dt':
- case 'dd': {
+ case 'dd':
+ {
text += '\n';
appendChildren(node.childNodes);
break;
@@ -245,12 +240,10 @@ export class MfmService {
return null;
}
- const { happyDOM, window } = new Window();
+ const { window } = new Window();
const doc = window.document;
- const body = doc.createElement('p');
-
function appendChildren(children: mfm.MfmNode[], targetElement: any): void {
if (children) {
for (const child of children.map(x => (handlers as any)[x.type](x))) targetElement.appendChild(child);
@@ -412,10 +405,8 @@ export class MfmService {
mention: (node) => {
const a = doc.createElement('a');
const { username, host, acct } = node.props;
- const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username.toLowerCase() === username.toLowerCase() && remoteUser.host?.toLowerCase() === host?.toLowerCase());
- a.setAttribute('href', remoteUserInfo
- ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri)
- : `${this.config.url}/${acct.endsWith(`@${this.config.url}`) ? acct.substring(0, acct.length - this.config.url.length - 1) : acct}`);
+ const remoteUserInfo = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
+ a.setAttribute('href', remoteUserInfo ? (remoteUserInfo.url ? remoteUserInfo.url : remoteUserInfo.uri) : `${this.config.url}/${acct}`);
a.className = 'u-url mention';
a.textContent = acct;
return a;
@@ -463,29 +454,23 @@ export class MfmService {
},
};
- appendChildren(nodes, body);
+ appendChildren(nodes, doc.body);
- const serialized = new XMLSerializer().serializeToString(body);
-
- happyDOM.close().catch(err => {});
-
- return serialized;
+ return `${doc.body.innerHTML}
`;
}
- // the toMastoApiHtml function was taken from Iceshrimp and written by zotan and modified by marie to work with the current MK version
+ // the toMastoHtml function was taken from Iceshrimp and written by zotan and modified by marie to work with the current MK version
@bindThis
- public async toMastoApiHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], inline = false, quoteUri: string | null = null) {
+ public async toMastoHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], inline = false, quoteUri: string | null = null) {
if (nodes == null) {
return null;
}
- const { happyDOM, window } = new Window();
+ const { window } = new Window();
const doc = window.document;
- const body = doc.createElement('p');
-
async function appendChildren(children: mfm.MfmNode[], targetElement: any): Promise {
if (children) {
for (const child of await Promise.all(children.map(async (x) => await (handlers as any)[x.type](x)))) targetElement.appendChild(child);
@@ -493,178 +478,178 @@ export class MfmService {
}
const handlers: {
- [K in mfm.MfmNode['type']]: (node: mfm.NodeType) => any;
- } = {
- async bold(node) {
- const el = doc.createElement('span');
- el.textContent = '**';
- await appendChildren(node.children, el);
- el.textContent += '**';
- return el;
- },
+ [K in mfm.MfmNode['type']]: (node: mfm.NodeType) => any;
+ } = {
+ async bold(node) {
+ const el = doc.createElement('span');
+ el.textContent = '**';
+ await appendChildren(node.children, el);
+ el.textContent += '**';
+ return el;
+ },
- async small(node) {
- const el = doc.createElement('small');
- await appendChildren(node.children, el);
- return el;
- },
+ async small(node) {
+ const el = doc.createElement('small');
+ await appendChildren(node.children, el);
+ return el;
+ },
- async strike(node) {
- const el = doc.createElement('span');
- el.textContent = '~~';
- await appendChildren(node.children, el);
- el.textContent += '~~';
- return el;
- },
+ async strike(node) {
+ const el = doc.createElement('span');
+ el.textContent = '~~';
+ await appendChildren(node.children, el);
+ el.textContent += '~~';
+ return el;
+ },
- async italic(node) {
- const el = doc.createElement('span');
- el.textContent = '*';
- await appendChildren(node.children, el);
- el.textContent += '*';
- return el;
- },
+ async italic(node) {
+ const el = doc.createElement('span');
+ el.textContent = '*';
+ await appendChildren(node.children, el);
+ el.textContent += '*';
+ return el;
+ },
- async fn(node) {
- const el = doc.createElement('span');
- el.textContent = '*';
- await appendChildren(node.children, el);
- el.textContent += '*';
- return el;
- },
+ async fn(node) {
+ const el = doc.createElement('span');
+ el.textContent = '*';
+ await appendChildren(node.children, el);
+ el.textContent += '*';
+ return el;
+ },
- blockCode(node) {
- const pre = doc.createElement('pre');
- const inner = doc.createElement('code');
+ blockCode(node) {
+ const pre = doc.createElement('pre');
+ const inner = doc.createElement('code');
- const nodes = node.props.code
- .split(/\r\n|\r|\n/)
- .map((x) => doc.createTextNode(x));
+ const nodes = node.props.code
+ .split(/\r\n|\r|\n/)
+ .map((x) => doc.createTextNode(x));
- for (const x of intersperse('br', nodes)) {
- inner.appendChild(x === 'br' ? doc.createElement('br') : x);
- }
+ for (const x of intersperse('br', nodes)) {
+ inner.appendChild(x === 'br' ? doc.createElement('br') : x);
+ }
- pre.appendChild(inner);
- return pre;
- },
+ pre.appendChild(inner);
+ return pre;
+ },
- async center(node) {
- const el = doc.createElement('div');
- await appendChildren(node.children, el);
- return el;
- },
+ async center(node) {
+ const el = doc.createElement('div');
+ await appendChildren(node.children, el);
+ return el;
+ },
- emojiCode(node) {
- return doc.createTextNode(`\u200B:${node.props.name}:\u200B`);
- },
+ emojiCode(node) {
+ return doc.createTextNode(`\u200B:${node.props.name}:\u200B`);
+ },
- unicodeEmoji(node) {
- return doc.createTextNode(node.props.emoji);
- },
+ unicodeEmoji(node) {
+ return doc.createTextNode(node.props.emoji);
+ },
- hashtag: (node) => {
- const a = doc.createElement('a');
- a.setAttribute('href', `${this.config.url}/tags/${node.props.hashtag}`);
- a.textContent = `#${node.props.hashtag}`;
- a.setAttribute('rel', 'tag');
- a.setAttribute('class', 'hashtag');
- return a;
- },
+ hashtag: (node) => {
+ const a = doc.createElement('a');
+ a.setAttribute('href', `${this.config.url}/tags/${node.props.hashtag}`);
+ a.textContent = `#${node.props.hashtag}`;
+ a.setAttribute('rel', 'tag');
+ a.setAttribute('class', 'hashtag');
+ return a;
+ },
- inlineCode(node) {
- const el = doc.createElement('code');
- el.textContent = node.props.code;
- return el;
- },
+ inlineCode(node) {
+ const el = doc.createElement('code');
+ el.textContent = node.props.code;
+ return el;
+ },
- mathInline(node) {
- const el = doc.createElement('code');
- el.textContent = node.props.formula;
- return el;
- },
+ mathInline(node) {
+ const el = doc.createElement('code');
+ el.textContent = node.props.formula;
+ return el;
+ },
- mathBlock(node) {
- const el = doc.createElement('code');
- el.textContent = node.props.formula;
- return el;
- },
+ mathBlock(node) {
+ const el = doc.createElement('code');
+ el.textContent = node.props.formula;
+ return el;
+ },
- async link(node) {
- const a = doc.createElement('a');
- a.setAttribute('rel', 'nofollow noopener noreferrer');
- a.setAttribute('target', '_blank');
- a.setAttribute('href', node.props.url);
- await appendChildren(node.children, a);
- return a;
- },
+ async link(node) {
+ const a = doc.createElement('a');
+ a.setAttribute('rel', 'nofollow noopener noreferrer');
+ a.setAttribute('target', '_blank');
+ a.setAttribute('href', node.props.url);
+ await appendChildren(node.children, a);
+ return a;
+ },
- async mention(node) {
- const { username, host, acct } = node.props;
- const resolved = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
+ async mention(node) {
+ const { username, host, acct } = node.props;
+ const resolved = mentionedRemoteUsers.find(remoteUser => remoteUser.username === username && remoteUser.host === host);
- const el = doc.createElement('span');
- if (!resolved) {
- el.textContent = acct;
- } else {
- el.setAttribute('class', 'h-card');
- el.setAttribute('translate', 'no');
- const a = doc.createElement('a');
- a.setAttribute('href', resolved.url ? resolved.url : resolved.uri);
- a.className = 'u-url mention';
- const span = doc.createElement('span');
- span.textContent = resolved.username || username;
- a.textContent = '@';
- a.appendChild(span);
- el.appendChild(a);
- }
+ const el = doc.createElement('span');
+ if (!resolved) {
+ el.textContent = acct;
+ } else {
+ el.setAttribute('class', 'h-card');
+ el.setAttribute('translate', 'no');
+ const a = doc.createElement('a');
+ a.setAttribute('href', resolved.url ? resolved.url : resolved.uri);
+ a.className = 'u-url mention';
+ const span = doc.createElement('span');
+ span.textContent = resolved.username || username;
+ a.textContent = '@';
+ a.appendChild(span);
+ el.appendChild(a);
+ }
- return el;
- },
+ return el;
+ },
- async quote(node) {
- const el = doc.createElement('blockquote');
- await appendChildren(node.children, el);
- return el;
- },
+ async quote(node) {
+ const el = doc.createElement('blockquote');
+ await appendChildren(node.children, el);
+ return el;
+ },
- text(node) {
- const el = doc.createElement('span');
- const nodes = node.props.text
- .split(/\r\n|\r|\n/)
- .map((x) => doc.createTextNode(x));
+ text(node) {
+ const el = doc.createElement('span');
+ const nodes = node.props.text
+ .split(/\r\n|\r|\n/)
+ .map((x) => doc.createTextNode(x));
- for (const x of intersperse('br', nodes)) {
- el.appendChild(x === 'br' ? doc.createElement('br') : x);
- }
+ for (const x of intersperse('br', nodes)) {
+ el.appendChild(x === 'br' ? doc.createElement('br') : x);
+ }
- return el;
- },
+ return el;
+ },
- url(node) {
- const a = doc.createElement('a');
- a.setAttribute('rel', 'nofollow noopener noreferrer');
- a.setAttribute('target', '_blank');
- a.setAttribute('href', node.props.url);
- a.textContent = node.props.url.replace(/^https?:\/\//, '');
- return a;
- },
+ url(node) {
+ const a = doc.createElement('a');
+ a.setAttribute('rel', 'nofollow noopener noreferrer');
+ a.setAttribute('target', '_blank');
+ a.setAttribute('href', node.props.url);
+ a.textContent = node.props.url.replace(/^https?:\/\//, '');
+ return a;
+ },
- search: (node) => {
- const a = doc.createElement('a');
- a.setAttribute('href', `https://www.google.com/search?q=${node.props.query}`);
- a.textContent = node.props.content;
- return a;
- },
+ search: (node) => {
+ const a = doc.createElement('a');
+ a.setAttribute('href', `https"google.com/${node.props.query}`);
+ a.textContent = node.props.content;
+ return a;
+ },
- async plain(node) {
- const el = doc.createElement('span');
- await appendChildren(node.children, el);
- return el;
- },
- };
-
- await appendChildren(nodes, body);
+ async plain(node) {
+ const el = doc.createElement('span');
+ await appendChildren(node.children, el);
+ return el;
+ },
+ };
+
+ await appendChildren(nodes, doc.body);
if (quoteUri !== null) {
const a = doc.createElement('a');
@@ -678,17 +663,9 @@ export class MfmService {
quote.innerHTML += 'RE: ';
quote.appendChild(a);
- body.appendChild(quote);
+ doc.body.appendChild(quote);
}
- let result = new XMLSerializer().serializeToString(body);
-
- if (inline) {
- result = result.replace(/^/, '').replace(/<\/p>$/, '');
- }
-
- happyDOM.close().catch(e => {});
-
- return result;
+ return inline ? doc.body.innerHTML : `
${doc.body.innerHTML}
`;
}
}
diff --git a/packages/backend/src/core/ModerationLogService.ts b/packages/backend/src/core/ModerationLogService.ts
index 2c02af217d..6c155c9a62 100644
--- a/packages/backend/src/core/ModerationLogService.ts
+++ b/packages/backend/src/core/ModerationLogService.ts
@@ -9,8 +9,7 @@ import type { ModerationLogsRepository } from '@/models/_.js';
import type { MiUser } from '@/models/User.js';
import { IdService } from '@/core/IdService.js';
import { bindThis } from '@/decorators.js';
-import type { ModerationLogPayloads } from '@/types.js';
-import { moderationLogTypes } from '@/types.js';
+import { ModerationLogPayloads, moderationLogTypes } from '@/types.js';
@Injectable()
export class ModerationLogService {
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 35a2d8e290..5a5930a8f6 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -8,12 +8,13 @@ import * as mfm from '@transfem-org/sfm-js';
import { In, DataSource, IsNull, LessThan } from 'typeorm';
import * as Redis from 'ioredis';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
+import RE2 from 're2';
import { extractMentions } from '@/misc/extract-mentions.js';
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
import { extractHashtags } from '@/misc/extract-hashtags.js';
import type { IMentionedRemoteUsers } from '@/models/Note.js';
import { MiNote } from '@/models/Note.js';
-import type { ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MiMeta, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
+import type { ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiApp } from '@/models/App.js';
import { concat } from '@/misc/prelude/array.js';
@@ -22,8 +23,11 @@ import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
import type { IPoll } from '@/models/Poll.js';
import { MiPoll } from '@/models/Poll.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
+import { checkWordMute } from '@/misc/check-word-mute.js';
import type { MiChannel } from '@/models/Channel.js';
import { normalizeForSearch } from '@/misc/normalize-for-search.js';
+import { MemorySingleCache } from '@/misc/cache.js';
+import type { MiUserProfile } from '@/models/UserProfile.js';
import { RelayService } from '@/core/RelayService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { DI } from '@/di-symbols.js';
@@ -34,7 +38,7 @@ import InstanceChart from '@/core/chart/charts/instance.js';
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { NotificationService } from '@/core/NotificationService.js';
-import { UserWebhookService } from '@/core/UserWebhookService.js';
+import { WebhookService } from '@/core/WebhookService.js';
import { HashtagService } from '@/core/HashtagService.js';
import { AntennaService } from '@/core/AntennaService.js';
import { QueueService } from '@/core/QueueService.js';
@@ -45,7 +49,9 @@ import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerServ
import { NoteReadService } from '@/core/NoteReadService.js';
import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js';
import { bindThis } from '@/decorators.js';
+import { DB_MAX_NOTE_TEXT_LENGTH } from '@/const.js';
import { RoleService } from '@/core/RoleService.js';
+import { MetaService } from '@/core/MetaService.js';
import { SearchService } from '@/core/SearchService.js';
import { FeaturedService } from '@/core/FeaturedService.js';
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
@@ -55,9 +61,6 @@ import { CacheService } from '@/core/CacheService.js';
import { isReply } from '@/misc/is-reply.js';
import { trackPromise } from '@/misc/promise-tracker.js';
import { isUserRelated } from '@/misc/is-user-related.js';
-import { IdentifiableError } from '@/misc/identifiable-error.js';
-import { LatestNoteService } from '@/core/LatestNoteService.js';
-import { CollapsedQueue } from '@/misc/collapsed-queue.js';
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
@@ -146,20 +149,16 @@ type Option = {
app?: MiApp | null;
};
-export type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
-
@Injectable()
export class NoteCreateService implements OnApplicationShutdown {
#shutdownController = new AbortController();
- private updateNotesCountQueue: CollapsedQueue;
+
+ public static ContainsProhibitedWordsError = class extends Error {};
constructor(
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.db)
private db: DataSource,
@@ -208,12 +207,13 @@ export class NoteCreateService implements OnApplicationShutdown {
private federatedInstanceService: FederatedInstanceService,
private hashtagService: HashtagService,
private antennaService: AntennaService,
- private webhookService: UserWebhookService,
+ private webhookService: WebhookService,
private featuredService: FeaturedService,
private remoteUserResolveService: RemoteUserResolveService,
private apDeliverManagerService: ApDeliverManagerService,
private apRendererService: ApRendererService,
private roleService: RoleService,
+ private metaService: MetaService,
private searchService: SearchService,
private notesChart: NotesChart,
private perUserNotesChart: PerUserNotesChart,
@@ -222,10 +222,7 @@ export class NoteCreateService implements OnApplicationShutdown {
private utilityService: UtilityService,
private userBlockingService: UserBlockingService,
private cacheService: CacheService,
- private latestNoteService: LatestNoteService,
- ) {
- this.updateNotesCountQueue = new CollapsedQueue(60 * 1000 * 5, this.collapseNotesCount, this.performUpdateNotesCount);
- }
+ ) { }
@bindThis
public async create(user: {
@@ -258,8 +255,10 @@ export class NoteCreateService implements OnApplicationShutdown {
if (data.channel != null) data.visibleUsers = [];
if (data.channel != null) data.localOnly = true;
+ const meta = await this.metaService.fetch();
+
if (data.visibility === 'public' && data.channel == null) {
- const sensitiveWords = this.meta.sensitiveWords;
+ const sensitiveWords = meta.sensitiveWords;
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) {
data.visibility = 'home';
} else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) {
@@ -267,17 +266,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}
- const hasProhibitedWords = this.checkProhibitedWordsContain({
- cw: data.cw,
- text: data.text,
- pollChoices: data.poll?.choices,
- }, this.meta.prohibitedWords);
-
- if (hasProhibitedWords) {
- throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
- }
-
- const inSilencedInstance = this.utilityService.isSilencedHost(this.meta.silencedHosts, user.host);
+ const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
if (data.visibility === 'public' && inSilencedInstance && user.host !== null) {
data.visibility = 'home';
@@ -310,7 +299,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
// Check blocking
- if (this.isRenote(data) && !this.isQuote(data)) {
+ if (data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)) {
if (data.renote.userHost === null) {
if (data.renote.userId !== user.id) {
const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id);
@@ -336,13 +325,9 @@ export class NoteCreateService implements OnApplicationShutdown {
data.localOnly = true;
}
- const maxTextLength = user.host == null
- ? this.config.maxNoteLength
- : this.config.maxRemoteNoteLength;
-
if (data.text) {
- if (data.text.length > maxTextLength) {
- data.text = data.text.slice(0, maxTextLength);
+ if (data.text.length > DB_MAX_NOTE_TEXT_LENGTH) {
+ data.text = data.text.slice(0, DB_MAX_NOTE_TEXT_LENGTH);
}
data.text = data.text.trim();
if (data.text === '') {
@@ -352,22 +337,6 @@ export class NoteCreateService implements OnApplicationShutdown {
data.text = null;
}
- const maxCwLength = user.host == null
- ? this.config.maxCwLength
- : this.config.maxRemoteCwLength;
-
- if (data.cw) {
- if (data.cw.length > maxCwLength) {
- data.cw = data.cw.slice(0, maxCwLength);
- }
- data.cw = data.cw.trim();
- if (data.cw === '') {
- data.cw = null;
- }
- } else {
- data.cw = null;
- }
-
let tags = data.apHashtags;
let emojis = data.apEmojis;
let mentionedUsers = data.apMentions;
@@ -389,9 +358,6 @@ export class NoteCreateService implements OnApplicationShutdown {
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
}
- // if the host is media-silenced, custom emojis are not allowed
- if (this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, user.host)) emojis = [];
-
tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
@@ -414,16 +380,12 @@ export class NoteCreateService implements OnApplicationShutdown {
if (user.host && !data.cw) {
await this.federatedInstanceService.fetch(user.host).then(async i => {
- if (i.isNSFW && !this.isPureRenote(data)) {
+ if (i.isNSFW) {
data.cw = 'Instance is marked as NSFW';
}
});
}
- if (mentionedUsers.length > 0 && mentionedUsers.length > (await this.roleService.getUserPolicies(user.id)).mentionLimit) {
- throw new IdentifiableError('9f466dab-c856-48cd-9e65-ff90ff750580', 'Note contains too many mentions');
- }
-
const note = await this.insertNote(user, data, tags, emojis, mentionedUsers);
setImmediate('post created', { signal: this.#shutdownController.signal }).then(
@@ -441,8 +403,165 @@ export class NoteCreateService implements OnApplicationShutdown {
host: MiUser['host'];
isBot: MiUser['isBot'];
noindex: MiUser['noindex'];
- }, data: Option): Promise {
- return this.create(user, data, true);
+ }, data: Option, silent = false): Promise {
+ // チャンネル外にリプライしたら対象のスコープに合わせる
+ // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
+ if (data.reply && data.channel && data.reply.channelId !== data.channel.id) {
+ if (data.reply.channelId) {
+ data.channel = await this.channelsRepository.findOneBy({ id: data.reply.channelId });
+ } else {
+ data.channel = null;
+ }
+ }
+
+ // チャンネル内にリプライしたら対象のスコープに合わせる
+ // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
+ if (data.reply && (data.channel == null) && data.reply.channelId) {
+ data.channel = await this.channelsRepository.findOneBy({ id: data.reply.channelId });
+ }
+
+ if (data.createdAt == null) data.createdAt = new Date();
+ if (data.visibility == null) data.visibility = 'public';
+ if (data.localOnly == null) data.localOnly = false;
+ if (data.channel != null) data.visibility = 'public';
+ if (data.channel != null) data.visibleUsers = [];
+ if (data.channel != null) data.localOnly = true;
+
+ const meta = await this.metaService.fetch();
+
+ if (data.visibility === 'public' && data.channel == null) {
+ const sensitiveWords = meta.sensitiveWords;
+ if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) {
+ data.visibility = 'home';
+ } else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) {
+ data.visibility = 'home';
+ }
+ }
+
+ if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
+ throw new NoteCreateService.ContainsProhibitedWordsError();
+ }
+
+ const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
+
+ if (data.visibility === 'public' && inSilencedInstance && user.host !== null) {
+ data.visibility = 'home';
+ }
+
+ if (data.renote) {
+ switch (data.renote.visibility) {
+ case 'public':
+ // public noteは無条件にrenote可能
+ break;
+ case 'home':
+ // home noteはhome以下にrenote可能
+ if (data.visibility === 'public') {
+ data.visibility = 'home';
+ }
+ break;
+ case 'followers':
+ // 他人のfollowers noteはreject
+ if (data.renote.userId !== user.id) {
+ throw new Error('Renote target is not public or home');
+ }
+
+ // Renote対象がfollowersならfollowersにする
+ data.visibility = 'followers';
+ break;
+ case 'specified':
+ // specified / direct noteはreject
+ throw new Error('Renote target is not public or home');
+ }
+ }
+
+ // Check blocking
+ if (data.renote && !this.isQuote(data)) {
+ if (data.renote.userHost === null) {
+ if (data.renote.userId !== user.id) {
+ const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id);
+ if (blocked) {
+ throw new Error('blocked');
+ }
+ }
+ }
+ }
+
+ // 返信対象がpublicではないならhomeにする
+ if (data.reply && data.reply.visibility !== 'public' && data.visibility === 'public') {
+ data.visibility = 'home';
+ }
+
+ // ローカルのみをRenoteしたらローカルのみにする
+ if (data.renote && data.renote.localOnly && data.channel == null) {
+ data.localOnly = true;
+ }
+
+ // ローカルのみにリプライしたらローカルのみにする
+ if (data.reply && data.reply.localOnly && data.channel == null) {
+ data.localOnly = true;
+ }
+
+ if (data.text) {
+ if (data.text.length > DB_MAX_NOTE_TEXT_LENGTH) {
+ data.text = data.text.slice(0, DB_MAX_NOTE_TEXT_LENGTH);
+ }
+ data.text = data.text.trim();
+ if (data.text === '') {
+ data.text = null;
+ }
+ } else {
+ data.text = null;
+ }
+
+ let tags = data.apHashtags;
+ let emojis = data.apEmojis;
+ let mentionedUsers = data.apMentions;
+
+ // Parse MFM if needed
+ if (!tags || !emojis || !mentionedUsers) {
+ const tokens = (data.text ? mfm.parse(data.text)! : []);
+ const cwTokens = data.cw ? mfm.parse(data.cw)! : [];
+ const choiceTokens = data.poll && data.poll.choices
+ ? concat(data.poll.choices.map(choice => mfm.parse(choice)!))
+ : [];
+
+ const combinedTokens = tokens.concat(cwTokens).concat(choiceTokens);
+
+ tags = data.apHashtags ?? extractHashtags(combinedTokens);
+
+ emojis = data.apEmojis ?? extractCustomEmojisFromMfm(combinedTokens);
+
+ mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
+ }
+
+ tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);
+
+ if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
+ mentionedUsers.push(await this.usersRepository.findOneByOrFail({ id: data.reply!.userId }));
+ }
+
+ if (data.visibility === 'specified') {
+ if (data.visibleUsers == null) throw new Error('invalid param');
+
+ for (const u of data.visibleUsers) {
+ if (!mentionedUsers.some(x => x.id === u.id)) {
+ mentionedUsers.push(u);
+ }
+ }
+
+ if (data.reply && !data.visibleUsers.some(x => x.id === data.reply!.userId)) {
+ data.visibleUsers.push(await this.usersRepository.findOneByOrFail({ id: data.reply!.userId }));
+ }
+ }
+
+ const note = await this.insertNote(user, data, tags, emojis, mentionedUsers);
+
+ setImmediate('post created', { signal: this.#shutdownController.signal }).then(
+ () => this.postNoteImported(note, user, data, silent, tags!, mentionedUsers!),
+ () => { /* aborted, ignore this */ },
+ );
+
+ return note;
}
@bindThis
@@ -484,14 +603,6 @@ export class NoteCreateService implements OnApplicationShutdown {
userHost: user.host,
});
- // should really not happen, but better safe than sorry
- if (data.reply?.id === insert.id) {
- throw new Error("A note can't reply to itself");
- }
- if (data.renote?.id === insert.id) {
- throw new Error("A note can't renote itself");
- }
-
if (data.uri != null) insert.uri = data.uri;
if (data.url != null) insert.url = data.url;
@@ -527,7 +638,6 @@ export class NoteCreateService implements OnApplicationShutdown {
noteVisibility: insert.visibility,
userId: user.id,
userHost: user.host,
- channelId: insert.channelId,
});
await transactionalEntityManager.insert(MiPoll, poll);
@@ -559,8 +669,10 @@ export class NoteCreateService implements OnApplicationShutdown {
isBot: MiUser['isBot'];
noindex: MiUser['noindex'];
}, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) {
+ const meta = await this.metaService.fetch();
+
this.notesChart.update(note, true);
- if (note.visibility !== 'specified' && (this.meta.enableChartsForRemoteUser || (user.host == null))) {
+ if (meta.enableChartsForRemoteUser || (user.host == null)) {
this.perUserNotesChart.update(user, note, true);
}
@@ -568,11 +680,11 @@ export class NoteCreateService implements OnApplicationShutdown {
if (this.userEntityService.isRemoteUser(user)) {
this.federatedInstanceService.fetch(user.host).then(async i => {
if (note.renote && note.text) {
- this.updateNotesCountQueue.enqueue(i.id, 1);
+ this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
} else if (!note.renote) {
- this.updateNotesCountQueue.enqueue(i.id, 1);
+ this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
}
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateNote(i.host, note, true);
}
});
@@ -580,7 +692,7 @@ export class NoteCreateService implements OnApplicationShutdown {
// ハッシュタグ更新
if (data.visibility === 'public' || data.visibility === 'home') {
- if (user.isBot && this.meta.enableBotTrending) {
+ if (user.isBot && meta.enableBotTrending) {
this.hashtagService.updateHashtags(user, tags);
} else if (!user.isBot) {
this.hashtagService.updateHashtags(user, tags);
@@ -629,7 +741,6 @@ export class NoteCreateService implements OnApplicationShutdown {
this.queueService.endedPollNotificationQueue.add(note.id, {
noteId: note.id,
}, {
- jobId: `pollEnd:${note.id}`,
delay,
removeOnComplete: true,
});
@@ -673,7 +784,7 @@ export class NoteCreateService implements OnApplicationShutdown {
this.webhookService.getActiveWebhooks().then(webhooks => {
webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'note', {
+ this.queueService.webhookDeliver(webhook, 'note', {
note: noteObj,
});
}
@@ -687,7 +798,6 @@ export class NoteCreateService implements OnApplicationShutdown {
if (data.reply) {
this.globalEventService.publishNoteStream(data.reply.id, 'replied', {
id: note.id,
- userId: user.id,
});
// 通知
if (data.reply.userHost === null) {
@@ -712,7 +822,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'reply', {
+ this.queueService.webhookDeliver(webhook, 'reply', {
note: noteObj,
});
}
@@ -721,7 +831,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
// If it is renote
- if (this.isRenote(data)) {
+ if (data.renote) {
const type = this.isQuote(data) ? 'quote' : 'renote';
// Notify
@@ -752,7 +862,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'renote', {
+ this.queueService.webhookDeliver(webhook, 'renote', {
note: noteObj,
});
}
@@ -817,33 +927,113 @@ export class NoteCreateService implements OnApplicationShutdown {
});
}
- // Update the Latest Note index / following feed
- this.latestNoteService.handleCreatedNoteBG(note);
+ // Register to search database
+ if (!user.noindex) this.index(note);
+ }
+
+ @bindThis
+ private async postNoteImported(note: MiNote, user: {
+ id: MiUser['id'];
+ username: MiUser['username'];
+ host: MiUser['host'];
+ isBot: MiUser['isBot'];
+ noindex: MiUser['noindex'];
+ }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) {
+ const meta = await this.metaService.fetch();
+
+ this.notesChart.update(note, true);
+ if (meta.enableChartsForRemoteUser || (user.host == null)) {
+ this.perUserNotesChart.update(user, note, true);
+ }
+
+ // Register host
+ if (this.userEntityService.isRemoteUser(user)) {
+ this.federatedInstanceService.fetch(user.host).then(async i => {
+ if (note.renote && note.text) {
+ this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
+ } else if (!note.renote) {
+ this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
+ }
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
+ this.instanceChart.updateNote(i.host, note, true);
+ }
+ });
+ }
+
+ if (data.renote && data.text) {
+ // Increment notes count (user)
+ this.incNotesCountOfUser(user);
+ } else if (!data.renote) {
+ // Increment notes count (user)
+ this.incNotesCountOfUser(user);
+ }
+
+ this.pushToTl(note, user);
+
+ this.antennaService.addNoteToAntennas(note, user);
+
+ if (data.reply) {
+ this.saveReply(data.reply, note);
+ }
+
+ if (data.reply == null) {
+ // TODO: キャッシュ
+ this.followingsRepository.findBy({
+ followeeId: user.id,
+ notify: 'normal',
+ }).then(followings => {
+ for (const following of followings) {
+ // TODO: ワードミュート考慮
+ this.notificationService.createNotification(following.followerId, 'note', {
+ noteId: note.id,
+ }, user.id);
+ }
+ });
+ }
+
+ if (data.renote && data.text == null && data.renote.userId !== user.id && !user.isBot) {
+ this.incRenoteCount(data.renote);
+ }
+
+ if (data.poll && data.poll.expiresAt) {
+ const delay = data.poll.expiresAt.getTime() - Date.now();
+ this.queueService.endedPollNotificationQueue.add(note.id, {
+ noteId: note.id,
+ }, {
+ delay,
+ removeOnComplete: true,
+ });
+ }
+
+ // Pack the note
+ const noteObj = await this.noteEntityService.pack(note, null, { skipHide: true, withReactionAndUserPairCache: true });
+
+ if (data.channel) {
+ this.channelsRepository.increment({ id: data.channel.id }, 'notesCount', 1);
+ this.channelsRepository.update(data.channel.id, {
+ lastNotedAt: new Date(),
+ });
+
+ this.notesRepository.countBy({
+ userId: user.id,
+ channelId: data.channel.id,
+ }).then(count => {
+ // この処理が行われるのはノート作成後なので、ノートが一つしかなかったら最初の投稿だと判断できる
+ // TODO: とはいえノートを削除して何回も投稿すればその分だけインクリメントされる雑さもあるのでどうにかしたい
+ if (count === 1) {
+ this.channelsRepository.increment({ id: data.channel!.id }, 'usersCount', 1);
+ }
+ });
+ }
// Register to search database
if (!user.noindex) this.index(note);
}
@bindThis
- public isPureRenote(note: Option): note is PureRenoteOption {
- return this.isRenote(note) && !this.isQuote(note);
- }
-
- @bindThis
- private isRenote(note: Option): note is Option & { renote: MiNote } {
- return note.renote != null;
- }
-
- @bindThis
- private isQuote(note: Option & { renote: MiNote }): note is Option & { renote: MiNote } & (
- { text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] }
- ) {
- // NOTE: SYNC WITH misc/is-quote.ts
- return note.text != null ||
- note.reply != null ||
- note.cw != null ||
- note.poll != null ||
- (note.files != null && note.files.length > 0);
+ private isQuote(note: Option): note is Option & { renote: MiNote } {
+ // sync with misc/is-quote.ts
+ return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll);
}
@bindThis
@@ -900,7 +1090,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'mention', {
+ this.queueService.webhookDeliver(webhook, 'mention', {
note: detailPackedNote,
});
}
@@ -919,7 +1109,7 @@ export class NoteCreateService implements OnApplicationShutdown {
private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
if (data.localOnly) return null;
- const content = this.isRenote(data) && !this.isQuote(data)
+ const content = data.renote && !this.isQuote(data)
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
: this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
@@ -951,7 +1141,7 @@ export class NoteCreateService implements OnApplicationShutdown {
const mentions = extractMentions(tokens);
let mentionedUsers = (await Promise.all(mentions.map(m =>
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
- ))).filter(x => x != null);
+ ))).filter(x => x != null) as MiUser[];
// Drop duplicate users
mentionedUsers = mentionedUsers.filter((u, i, self) =>
@@ -963,14 +1153,15 @@ export class NoteCreateService implements OnApplicationShutdown {
@bindThis
private async pushToTl(note: MiNote, user: { id: MiUser['id']; host: MiUser['host']; }) {
- if (!this.meta.enableFanoutTimeline) return;
+ const meta = await this.metaService.fetch();
+ if (!meta.enableFanoutTimeline) return;
const r = this.redisForTimelines.pipeline();
if (note.channelId) {
this.fanoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r);
- this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
const channelFollowings = await this.channelFollowingsRepository.find({
where: {
@@ -980,9 +1171,9 @@ export class NoteCreateService implements OnApplicationShutdown {
});
for (const channelFollowing of channelFollowings) {
- this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
}
}
} else {
@@ -1020,9 +1211,9 @@ export class NoteCreateService implements OnApplicationShutdown {
if (!following.withReplies) continue;
}
- this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
}
}
@@ -1039,25 +1230,22 @@ export class NoteCreateService implements OnApplicationShutdown {
if (!userListMembership.withReplies) continue;
}
- this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, this.meta.perUserListTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, this.meta.perUserListTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r);
}
}
- // 自分自身のHTL
- if (note.userHost == null) {
- if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) {
- this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
- if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
- }
+ if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL
+ this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
+ if (note.fileIds.length > 0) {
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
}
}
// 自分自身以外への返信
if (isReply(note)) {
- this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
if (note.visibility === 'public' && note.userHost == null) {
this.fanoutTimelineService.push('localTimelineWithReplies', note.id, 300, r);
@@ -1066,9 +1254,9 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}
} else {
- this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax / 2 : this.meta.perRemoteUserUserTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r);
}
if (note.visibility === 'public' && note.userHost == null) {
@@ -1127,41 +1315,13 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}
- public checkProhibitedWordsContain(content: Parameters[0], prohibitedWords?: string[]) {
- if (prohibitedWords == null) {
- prohibitedWords = this.meta.prohibitedWords;
- }
-
- if (
- this.utilityService.isKeyWordIncluded(
- this.utilityService.concatNoteContentsForKeyWordCheck(content),
- prohibitedWords,
- )
- ) {
- return true;
- }
-
- return false;
- }
-
@bindThis
- private collapseNotesCount(oldValue: number, newValue: number) {
- return oldValue + newValue;
- }
-
- @bindThis
- private async performUpdateNotesCount(id: MiNote['id'], incrBy: number) {
- await this.instancesRepository.increment({ id: id }, 'notesCount', incrBy);
- }
-
- @bindThis
- public async dispose(): Promise {
+ public dispose(): void {
this.#shutdownController.abort();
- await this.updateNotesCountQueue.performAllNow();
}
@bindThis
- public async onApplicationShutdown(signal?: string | undefined): Promise {
- await this.dispose();
+ public onApplicationShutdown(signal?: string | undefined): void {
+ this.dispose();
}
}
diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts
index 285db9f152..471ade92c7 100644
--- a/packages/backend/src/core/NoteDeleteService.ts
+++ b/packages/backend/src/core/NoteDeleteService.ts
@@ -6,8 +6,8 @@
import { Brackets, In } from 'typeorm';
import { Injectable, Inject } from '@nestjs/common';
import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js';
-import { MiNote, IMentionedRemoteUsers } from '@/models/Note.js';
-import type { InstancesRepository, MiMeta, NotesRepository, UsersRepository } from '@/models/_.js';
+import type { MiNote, IMentionedRemoteUsers } from '@/models/Note.js';
+import type { InstancesRepository, NotesRepository, UsersRepository } from '@/models/_.js';
import { RelayService } from '@/core/RelayService.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
import { DI } from '@/di-symbols.js';
@@ -19,11 +19,12 @@ import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
+import { MetaService } from '@/core/MetaService.js';
import { SearchService } from '@/core/SearchService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { isQuote, isRenote } from '@/misc/is-renote.js';
-import { LatestNoteService } from '@/core/LatestNoteService.js';
+import { isPureRenote } from '@/misc/is-pure-renote.js';
@Injectable()
export class NoteDeleteService {
@@ -31,9 +32,6 @@ export class NoteDeleteService {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -44,17 +42,18 @@ export class NoteDeleteService {
private instancesRepository: InstancesRepository,
private userEntityService: UserEntityService,
+ private noteEntityService: NoteEntityService,
private globalEventService: GlobalEventService,
private relayService: RelayService,
private federatedInstanceService: FederatedInstanceService,
private apRendererService: ApRendererService,
private apDeliverManagerService: ApDeliverManagerService,
+ private metaService: MetaService,
private searchService: SearchService,
private moderationLogService: ModerationLogService,
private notesChart: NotesChart,
private perUserNotesChart: PerUserNotesChart,
private instanceChart: InstanceChart,
- private latestNoteService: LatestNoteService,
) {}
/**
@@ -87,7 +86,7 @@ export class NoteDeleteService {
let renote: MiNote | null = null;
// if deleted note is renote
- if (isRenote(note) && !isQuote(note)) {
+ if (isPureRenote(note)) {
renote = await this.notesRepository.findOneBy({
id: note.renoteId,
});
@@ -100,7 +99,7 @@ export class NoteDeleteService {
this.deliverToConcerned(user, note, content);
}
- // also deliver delete activity to cascaded notes
+ // also deliever delete activity to cascaded notes
const federatedLocalCascadingNotes = (cascadingNotes).filter(note => !note.localOnly && note.userHost == null); // filter out local-only notes
for (const cascadingNote of federatedLocalCascadingNotes) {
if (!cascadingNote.user) continue;
@@ -110,8 +109,10 @@ export class NoteDeleteService {
}
//#endregion
+ const meta = await this.metaService.fetch();
+
this.notesChart.update(note, false);
- if (this.meta.enableChartsForRemoteUser || (user.host == null)) {
+ if (meta.enableChartsForRemoteUser || (user.host == null)) {
this.perUserNotesChart.update(user, note, false);
}
@@ -130,7 +131,7 @@ export class NoteDeleteService {
} else if (!note.renoteId) {
this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1);
}
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateNote(i.host, note, false);
}
});
@@ -147,8 +148,6 @@ export class NoteDeleteService {
userId: user.id,
});
- this.latestNoteService.handleDeletedNoteBG(note);
-
if (deleter && (note.userId !== deleter.id)) {
const user = await this.usersRepository.findOneByOrFail({ id: note.userId });
this.moderationLogService.log(deleter, 'deleteNote', {
diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts
index 406d134420..6a469c9634 100644
--- a/packages/backend/src/core/NoteEditService.ts
+++ b/packages/backend/src/core/NoteEditService.ts
@@ -8,12 +8,13 @@ import * as mfm from '@transfem-org/sfm-js';
import { DataSource, In, IsNull, LessThan } from 'typeorm';
import * as Redis from 'ioredis';
import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
+import RE2 from 're2';
import { extractMentions } from '@/misc/extract-mentions.js';
import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mfm.js';
import { extractHashtags } from '@/misc/extract-hashtags.js';
import type { IMentionedRemoteUsers } from '@/models/Note.js';
import { MiNote } from '@/models/Note.js';
-import type { NoteEditRepository, ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MiMeta, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository, PollsRepository } from '@/models/_.js';
+import type { NoteEditRepository, ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository, PollsRepository } from '@/models/_.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiApp } from '@/models/App.js';
import { concat } from '@/misc/prelude/array.js';
@@ -30,7 +31,7 @@ import InstanceChart from '@/core/chart/charts/instance.js';
import ActiveUsersChart from '@/core/chart/charts/active-users.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { NotificationService } from '@/core/NotificationService.js';
-import { UserWebhookService } from '@/core/UserWebhookService.js';
+import { WebhookService } from '@/core/WebhookService.js';
import { QueueService } from '@/core/QueueService.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
@@ -39,7 +40,9 @@ import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerServ
import { NoteReadService } from '@/core/NoteReadService.js';
import { RemoteUserResolveService } from '@/core/RemoteUserResolveService.js';
import { bindThis } from '@/decorators.js';
+import { DB_MAX_NOTE_TEXT_LENGTH } from '@/const.js';
import { RoleService } from '@/core/RoleService.js';
+import { MetaService } from '@/core/MetaService.js';
import { SearchService } from '@/core/SearchService.js';
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { UtilityService } from '@/core/UtilityService.js';
@@ -48,10 +51,6 @@ import { CacheService } from '@/core/CacheService.js';
import { isReply } from '@/misc/is-reply.js';
import { trackPromise } from '@/misc/promise-tracker.js';
import { isUserRelated } from '@/misc/is-user-related.js';
-import { IdentifiableError } from '@/misc/identifiable-error.js';
-import { LatestNoteService } from '@/core/LatestNoteService.js';
-import { CollapsedQueue } from '@/misc/collapsed-queue.js';
-import { NoteCreateService } from '@/core/NoteCreateService.js';
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention' | 'edited';
@@ -145,15 +144,13 @@ type Option = {
@Injectable()
export class NoteEditService implements OnApplicationShutdown {
#shutdownController = new AbortController();
- private updateNotesCountQueue: CollapsedQueue;
+
+ public static ContainsProhibitedWordsError = class extends Error {};
constructor(
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.db)
private db: DataSource,
@@ -206,22 +203,19 @@ export class NoteEditService implements OnApplicationShutdown {
private notificationService: NotificationService,
private relayService: RelayService,
private federatedInstanceService: FederatedInstanceService,
- private webhookService: UserWebhookService,
+ private webhookService: WebhookService,
private remoteUserResolveService: RemoteUserResolveService,
private apDeliverManagerService: ApDeliverManagerService,
private apRendererService: ApRendererService,
private roleService: RoleService,
+ private metaService: MetaService,
private searchService: SearchService,
private activeUsersChart: ActiveUsersChart,
private instanceChart: InstanceChart,
private utilityService: UtilityService,
private userBlockingService: UserBlockingService,
private cacheService: CacheService,
- private latestNoteService: LatestNoteService,
- private noteCreateService: NoteCreateService,
- ) {
- this.updateNotesCountQueue = new CollapsedQueue(60 * 1000 * 5, this.collapseNotesCount, this.performUpdateNotesCount);
- }
+ ) { }
@bindThis
public async edit(user: {
@@ -247,18 +241,6 @@ export class NoteEditService implements OnApplicationShutdown {
throw new Error('not the author');
}
- // we never want to change the replyId, so fetch the original "parent"
- if (oldnote.replyId) {
- data.reply = await this.notesRepository.findOneBy({ id: oldnote.replyId });
- } else {
- data.reply = undefined;
- }
-
- // changing visibility on an edit is ill-defined, let's try to
- // keep the same visibility as the original note
- data.visibility = oldnote.visibility;
- data.localOnly = oldnote.localOnly;
-
// チャンネル外にリプライしたら対象のスコープに合わせる
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
if (data.reply && data.channel && data.reply.channelId !== data.channel.id) {
@@ -282,8 +264,10 @@ export class NoteEditService implements OnApplicationShutdown {
if (data.channel != null) data.localOnly = true;
if (data.updatedAt == null) data.updatedAt = new Date();
+ const meta = await this.metaService.fetch();
+
if (data.visibility === 'public' && data.channel == null) {
- const sensitiveWords = this.meta.sensitiveWords;
+ const sensitiveWords = meta.sensitiveWords;
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', sensitiveWords)) {
data.visibility = 'home';
} else if ((await this.roleService.getUserPolicies(user.id)).canPublicNote === false) {
@@ -291,27 +275,17 @@ export class NoteEditService implements OnApplicationShutdown {
}
}
- const hasProhibitedWords = this.noteCreateService.checkProhibitedWordsContain({
- cw: data.cw,
- text: data.text,
- pollChoices: data.poll?.choices,
- }, this.meta.prohibitedWords);
-
- if (hasProhibitedWords) {
- throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
+ if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
+ throw new NoteEditService.ContainsProhibitedWordsError();
}
- const inSilencedInstance = this.utilityService.isSilencedHost(this.meta.silencedHosts, user.host);
+ const inSilencedInstance = this.utilityService.isSilencedHost((meta).silencedHosts, user.host);
if (data.visibility === 'public' && inSilencedInstance && user.host !== null) {
data.visibility = 'home';
}
- if (this.isRenote(data)) {
- if (data.renote.id === oldnote.id) {
- throw new Error("A note can't renote itself");
- }
-
+ if (data.renote) {
switch (data.renote.visibility) {
case 'public':
// public noteは無条件にrenote可能
@@ -338,7 +312,7 @@ export class NoteEditService implements OnApplicationShutdown {
}
// Check blocking
- if (this.isRenote(data) && !this.isQuote(data)) {
+ if (data.renote && !this.isQuote(data)) {
if (data.renote.userHost === null) {
if (data.renote.userId !== user.id) {
const blocked = await this.userBlockingService.checkBlocked(data.renote.userId, user.id);
@@ -355,7 +329,7 @@ export class NoteEditService implements OnApplicationShutdown {
}
// ローカルのみをRenoteしたらローカルのみにする
- if (this.isRenote(data) && data.renote.localOnly && data.channel == null) {
+ if (data.renote && data.renote.localOnly && data.channel == null) {
data.localOnly = true;
}
@@ -364,13 +338,9 @@ export class NoteEditService implements OnApplicationShutdown {
data.localOnly = true;
}
- const maxTextLength = user.host == null
- ? this.config.maxNoteLength
- : this.config.maxRemoteNoteLength;
-
if (data.text) {
- if (data.text.length > maxTextLength) {
- data.text = data.text.slice(0, maxTextLength);
+ if (data.text.length > DB_MAX_NOTE_TEXT_LENGTH) {
+ data.text = data.text.slice(0, DB_MAX_NOTE_TEXT_LENGTH);
}
data.text = data.text.trim();
if (data.text === '') {
@@ -380,22 +350,6 @@ export class NoteEditService implements OnApplicationShutdown {
data.text = null;
}
- const maxCwLength = user.host == null
- ? this.config.maxCwLength
- : this.config.maxRemoteCwLength;
-
- if (data.cw) {
- if (data.cw.length > maxCwLength) {
- data.cw = data.cw.slice(0, maxCwLength);
- }
- data.cw = data.cw.trim();
- if (data.cw === '') {
- data.cw = null;
- }
- } else {
- data.cw = null;
- }
-
let tags = data.apHashtags;
let emojis = data.apEmojis;
let mentionedUsers = data.apMentions;
@@ -417,9 +371,6 @@ export class NoteEditService implements OnApplicationShutdown {
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
}
- // if the host is media-silenced, custom emojis are not allowed
- if (this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, user.host)) emojis = [];
-
tags = tags.filter(tag => Array.from(tag ?? '').length <= 128).splice(0, 32);
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
@@ -442,16 +393,12 @@ export class NoteEditService implements OnApplicationShutdown {
if (user.host && !data.cw) {
await this.federatedInstanceService.fetch(user.host).then(async i => {
- if (i.isNSFW && !this.noteCreateService.isPureRenote(data)) {
+ if (i.isNSFW) {
data.cw = 'Instance is marked as NSFW';
}
});
}
- if (mentionedUsers.length > 0 && mentionedUsers.length > (await this.roleService.getUserPolicies(user.id)).mentionLimit) {
- throw new IdentifiableError('9f466dab-c856-48cd-9e65-ff90ff750580', 'Note contains too many mentions');
- }
-
const update: Partial = {};
if (data.text !== oldnote.text) {
update.text = data.text;
@@ -459,21 +406,18 @@ export class NoteEditService implements OnApplicationShutdown {
if (data.cw !== oldnote.cw) {
update.cw = data.cw;
}
+ if (data.localOnly !== oldnote.localOnly) {
+ update.localOnly = data.localOnly;
+ }
if (oldnote.hasPoll !== !!data.poll) {
update.hasPoll = !!data.poll;
}
- // technically we should check if the two sets of files are
- // different, or if their descriptions have changed. In practice
- // this is good enough.
- const filesChanged = oldnote.fileIds?.length || data.files?.length;
-
const poll = await this.pollsRepository.findOneBy({ noteId: oldnote.id });
const oldPoll = poll ? { choices: poll.choices, multiple: poll.multiple, expiresAt: poll.expiresAt } : null;
- const pollChanged = data.poll != null && JSON.stringify(data.poll) !== JSON.stringify(oldPoll);
- if (Object.keys(update).length > 0 || filesChanged || pollChanged) {
+ if (Object.keys(update).length > 0) {
const exists = await this.noteEditRepository.findOneBy({ noteId: oldnote.id });
await this.noteEditRepository.insert({
@@ -491,7 +435,7 @@ export class NoteEditService implements OnApplicationShutdown {
id: oldnote.id,
updatedAt: data.updatedAt ? data.updatedAt : new Date(),
fileIds: data.files ? data.files.map(file => file.id) : [],
- replyId: oldnote.replyId,
+ replyId: data.reply ? data.reply.id : null,
renoteId: data.renote ? data.renote.id : null,
channelId: data.channel ? data.channel.id : null,
threadId: data.reply
@@ -524,7 +468,6 @@ export class NoteEditService implements OnApplicationShutdown {
renoteUserId: data.renote ? data.renote.userId : null,
renoteUserHost: data.renote ? data.renote.userHost : null,
userHost: user.host,
- reactionAndUserPairCache: oldnote.reactionAndUserPairCache,
});
if (data.uri != null) note.uri = data.uri;
@@ -545,7 +488,7 @@ export class NoteEditService implements OnApplicationShutdown {
}));
}
- if (pollChanged) {
+ if (data.poll != null && JSON.stringify(data.poll) !== JSON.stringify(oldPoll)) {
// Start transaction
await this.db.transaction(async transactionalEntityManager => {
await transactionalEntityManager.update(MiNote, oldnote.id, note);
@@ -559,7 +502,6 @@ export class NoteEditService implements OnApplicationShutdown {
noteVisibility: note.visibility,
userId: user.id,
userHost: user.host,
- channelId: data.channel ? data.channel.id : null,
});
if (!oldnote.hasPoll) {
@@ -573,7 +515,7 @@ export class NoteEditService implements OnApplicationShutdown {
}
setImmediate('post edited', { signal: this.#shutdownController.signal }).then(
- () => this.postNoteEdited(note, oldnote, user, data, silent, tags!, mentionedUsers!),
+ () => this.postNoteEdited(note, user, data, silent, tags!, mentionedUsers!),
() => { /* aborted, ignore this */ },
);
@@ -584,7 +526,7 @@ export class NoteEditService implements OnApplicationShutdown {
}
@bindThis
- private async postNoteEdited(note: MiNote, oldNote: MiNote, user: {
+ private async postNoteEdited(note: MiNote, user: {
id: MiUser['id'];
username: MiUser['username'];
host: MiUser['host'];
@@ -594,8 +536,8 @@ export class NoteEditService implements OnApplicationShutdown {
// Register host
if (this.userEntityService.isRemoteUser(user)) {
this.federatedInstanceService.fetch(user.host).then(async i => {
- this.updateNotesCountQueue.enqueue(i.id, 1);
- if (this.meta.enableChartsForFederatedInstances) {
+ this.instancesRepository.increment({ id: i.id }, 'notesCount', 1);
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateNote(i.host, note, true);
}
});
@@ -606,11 +548,10 @@ export class NoteEditService implements OnApplicationShutdown {
if (data.poll && data.poll.expiresAt) {
const delay = data.poll.expiresAt.getTime() - Date.now();
- this.queueService.endedPollNotificationQueue.remove(`pollEnd:${note.id}`);
+ this.queueService.endedPollNotificationQueue.remove(note.id);
this.queueService.endedPollNotificationQueue.add(note.id, {
noteId: note.id,
}, {
- jobId: `pollEnd:${note.id}`,
delay,
removeOnComplete: true,
});
@@ -663,7 +604,7 @@ export class NoteEditService implements OnApplicationShutdown {
this.webhookService.getActiveWebhooks().then(webhooks => {
webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'note', {
+ this.queueService.webhookDeliver(webhook, 'note', {
note: noteObj,
});
}
@@ -698,7 +639,7 @@ export class NoteEditService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('edited'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'edited', {
+ this.queueService.webhookDeliver(webhook, 'edited', {
note: noteObj,
});
}
@@ -726,7 +667,7 @@ export class NoteEditService implements OnApplicationShutdown {
}
// 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送
- if (this.isRenote(data) && data.renote.userHost !== null) {
+ if (data.renote && data.renote.userHost !== null) {
const u = await this.usersRepository.findOneBy({ id: data.renote.userId });
if (u && this.userEntityService.isRemoteUser(u)) dm.addDirectRecipe(u);
}
@@ -736,24 +677,6 @@ export class NoteEditService implements OnApplicationShutdown {
dm.addFollowersRecipe();
}
- if (['public', 'home'].includes(note.visibility)) {
- // Send edit event to all users who replied to,
- // renoted a post or reacted to a note.
- const noteId = note.id;
- const users = await this.usersRepository.createQueryBuilder()
- .where(
- 'id IN (SELECT "userId" FROM note WHERE "replyId" = :noteId OR "renoteId" = :noteId UNION SELECT "userId" FROM note_reaction WHERE "noteId" = :noteId)',
- { noteId },
- )
- .andWhere('host IS NOT NULL')
- .getMany();
- for (const u of users) {
- // User was verified to be remote by checking
- // whether host IS NOT NULL in SQL query.
- dm.addDirectRecipe(u as MiRemoteUser);
- }
- }
-
if (['public'].includes(note.visibility)) {
this.relayService.deliverToRelays(user, noteActivity);
}
@@ -782,28 +705,14 @@ export class NoteEditService implements OnApplicationShutdown {
});
}
- // Update the Latest Note index / following feed
- this.latestNoteService.handleUpdatedNoteBG(oldNote, note);
-
// Register to search database
if (!user.noindex) this.index(note);
}
@bindThis
- private isRenote(note: Option): note is Option & { renote: MiNote } {
- return note.renote != null;
- }
-
- @bindThis
- private isQuote(note: Option & { renote: MiNote }): note is Option & { renote: MiNote } & (
- { text: string } | { cw: string } | { reply: MiNote } | { poll: IPoll } | { files: MiDriveFile[] }
- ) {
- // NOTE: SYNC WITH misc/is-quote.ts
- return note.text != null ||
- note.reply != null ||
- note.cw != null ||
- note.poll != null ||
- (note.files != null && note.files.length > 0);
+ private isQuote(note: Option): note is Option & { renote: MiNote } {
+ // sync with misc/is-quote.ts
+ return !!note.renote && (!!note.text || !!note.cw || (!!note.files && !!note.files.length) || !!note.poll);
}
@bindThis
@@ -836,7 +745,7 @@ export class NoteEditService implements OnApplicationShutdown {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('edited'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'edited', {
+ this.queueService.webhookDeliver(webhook, 'edited', {
note: detailPackedNote,
});
}
@@ -852,7 +761,7 @@ export class NoteEditService implements OnApplicationShutdown {
const user = await this.usersRepository.findOneBy({ id: note.userId });
if (user == null) throw new Error('user not found');
- const content = this.isRenote(data) && !this.isQuote(data)
+ const content = data.renote && !this.isQuote(data)
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
: this.apRendererService.renderUpdate(await this.apRendererService.renderUpNote(note, false), user);
@@ -873,7 +782,7 @@ export class NoteEditService implements OnApplicationShutdown {
const mentions = extractMentions(tokens);
let mentionedUsers = (await Promise.all(mentions.map(m =>
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
- ))).filter(x => x !== null) as MiUser[];
+ ))).filter(x => x != null) as MiUser[];
// Drop duplicate users
mentionedUsers = mentionedUsers.filter((u, i, self) =>
@@ -885,14 +794,15 @@ export class NoteEditService implements OnApplicationShutdown {
@bindThis
private async pushToTl(note: MiNote, user: { id: MiUser['id']; host: MiUser['host']; }) {
- if (!this.meta.enableFanoutTimeline) return;
+ const meta = await this.metaService.fetch();
+ if (!meta.enableFanoutTimeline) return;
const r = this.redisForTimelines.pipeline();
if (note.channelId) {
this.fanoutTimelineService.push(`channelTimeline:${note.channelId}`, note.id, this.config.perChannelMaxNoteCacheCount, r);
- this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userTimelineWithChannel:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
const channelFollowings = await this.channelFollowingsRepository.find({
where: {
@@ -902,9 +812,9 @@ export class NoteEditService implements OnApplicationShutdown {
});
for (const channelFollowing of channelFollowings) {
- this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`homeTimeline:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${channelFollowing.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
}
}
} else {
@@ -942,9 +852,9 @@ export class NoteEditService implements OnApplicationShutdown {
if (!following.withReplies) continue;
}
- this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`homeTimeline:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${following.followerId}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
}
}
@@ -961,25 +871,22 @@ export class NoteEditService implements OnApplicationShutdown {
if (!userListMembership.withReplies) continue;
}
- this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, this.meta.perUserListTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userListTimeline:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, this.meta.perUserListTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`userListTimelineWithFiles:${userListMembership.userListId}`, note.id, meta.perUserListTimelineCacheMax / 2, r);
}
}
- // 自分自身のHTL
- if (note.userHost == null) {
- if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) {
- this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, this.meta.perUserHomeTimelineCacheMax, r);
- if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, this.meta.perUserHomeTimelineCacheMax / 2, r);
- }
+ if (note.visibility !== 'specified' || !note.visibleUserIds.some(v => v === user.id)) { // 自分自身のHTL
+ this.fanoutTimelineService.push(`homeTimeline:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax, r);
+ if (note.fileIds.length > 0) {
+ this.fanoutTimelineService.push(`homeTimelineWithFiles:${user.id}`, note.id, meta.perUserHomeTimelineCacheMax / 2, r);
}
}
// 自分自身以外への返信
if (isReply(note)) {
- this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userTimelineWithReplies:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
if (note.visibility === 'public' && note.userHost == null) {
this.fanoutTimelineService.push('localTimelineWithReplies', note.id, 300, r);
@@ -988,9 +895,9 @@ export class NoteEditService implements OnApplicationShutdown {
}
}
} else {
- this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax : this.meta.perRemoteUserUserTimelineCacheMax, r);
+ this.fanoutTimelineService.push(`userTimeline:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax : meta.perRemoteUserUserTimelineCacheMax, r);
if (note.fileIds.length > 0) {
- this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? this.meta.perLocalUserUserTimelineCacheMax / 2 : this.meta.perRemoteUserUserTimelineCacheMax / 2, r);
+ this.fanoutTimelineService.push(`userTimelineWithFiles:${user.id}`, note.id, note.userHost == null ? meta.perLocalUserUserTimelineCacheMax / 2 : meta.perRemoteUserUserTimelineCacheMax / 2, r);
}
if (note.visibility === 'public' && note.userHost == null) {
@@ -1050,23 +957,12 @@ export class NoteEditService implements OnApplicationShutdown {
}
@bindThis
- private collapseNotesCount(oldValue: number, newValue: number) {
- return oldValue + newValue;
- }
-
- @bindThis
- private async performUpdateNotesCount(id: MiNote['id'], incrBy: number) {
- await this.instancesRepository.increment({ id: id }, 'notesCount', incrBy);
- }
-
- @bindThis
- public async dispose(): Promise {
+ public dispose(): void {
this.#shutdownController.abort();
- await this.updateNotesCountQueue.performAllNow();
}
@bindThis
- public async onApplicationShutdown(signal?: string | undefined): Promise {
- await this.dispose();
+ public onApplicationShutdown(signal?: string | undefined): void {
+ this.dispose();
}
}
diff --git a/packages/backend/src/core/NoteReadService.ts b/packages/backend/src/core/NoteReadService.ts
index 320b23cc1a..feef024602 100644
--- a/packages/backend/src/core/NoteReadService.ts
+++ b/packages/backend/src/core/NoteReadService.ts
@@ -66,11 +66,7 @@ export class NoteReadService implements OnApplicationShutdown {
noteUserId: note.userId,
};
- /* we may be called from NoteEditService, for a note that's
- already present in the `note_unread` table: `upsert` makes sure
- we don't throw a "duplicate key" error, while still updating
- the other columns if they've changed */
- await this.noteUnreadsRepository.upsert(unread, ['userId', 'noteId']);
+ await this.noteUnreadsRepository.insert(unread);
// 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する
setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => {
@@ -92,47 +88,46 @@ export class NoteReadService implements OnApplicationShutdown {
userId: MiUser['id'],
notes: (MiNote | Packed<'Note'>)[],
): Promise {
- if (notes.length === 0) return;
-
- const noteIds = new Set();
+ const readMentions: (MiNote | Packed<'Note'>)[] = [];
+ const readSpecifiedNotes: (MiNote | Packed<'Note'>)[] = [];
for (const note of notes) {
if (note.mentions && note.mentions.includes(userId)) {
- noteIds.add(note.id);
+ readMentions.push(note);
} else if (note.visibleUserIds && note.visibleUserIds.includes(userId)) {
- noteIds.add(note.id);
+ readSpecifiedNotes.push(note);
}
}
- if (noteIds.size === 0) return;
+ if ((readMentions.length > 0) || (readSpecifiedNotes.length > 0)) {
+ // Remove the record
+ await this.noteUnreadsRepository.delete({
+ userId: userId,
+ noteId: In([...readMentions.map(n => n.id), ...readSpecifiedNotes.map(n => n.id)]),
+ });
- // Remove the record
- await this.noteUnreadsRepository.delete({
- userId: userId,
- noteId: In(Array.from(noteIds)),
- });
+ // TODO: ↓まとめてクエリしたい
- // TODO: ↓まとめてクエリしたい
+ trackPromise(this.noteUnreadsRepository.countBy({
+ userId: userId,
+ isMentioned: true,
+ }).then(mentionsCount => {
+ if (mentionsCount === 0) {
+ // 全て既読になったイベントを発行
+ this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions');
+ }
+ }));
- trackPromise(this.noteUnreadsRepository.countBy({
- userId: userId,
- isMentioned: true,
- }).then(mentionsCount => {
- if (mentionsCount === 0) {
- // 全て既読になったイベントを発行
- this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions');
- }
- }));
-
- trackPromise(this.noteUnreadsRepository.countBy({
- userId: userId,
- isSpecified: true,
- }).then(specifiedCount => {
- if (specifiedCount === 0) {
- // 全て既読になったイベントを発行
- this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
- }
- }));
+ trackPromise(this.noteUnreadsRepository.countBy({
+ userId: userId,
+ isSpecified: true,
+ }).then(specifiedCount => {
+ if (specifiedCount === 0) {
+ // 全て既読になったイベントを発行
+ this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
+ }
+ }));
+ }
}
@bindThis
diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts
index 68ad92f396..ee16193579 100644
--- a/packages/backend/src/core/NotificationService.ts
+++ b/packages/backend/src/core/NotificationService.ts
@@ -122,14 +122,6 @@ export class NotificationService implements OnApplicationShutdown {
return null;
}
} else if (recieveConfig?.type === 'mutualFollow') {
- const [isFollowing, isFollower] = await Promise.all([
- this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)),
- this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)),
- ]);
- if (!(isFollowing && isFollower)) {
- return null;
- }
- } else if (recieveConfig?.type === 'followingOrFollower') {
const [isFollowing, isFollower] = await Promise.all([
this.cacheService.userFollowingsCache.fetch(notifieeId).then(followings => Object.hasOwn(followings, notifierId)),
this.cacheService.userFollowingsCache.fetch(notifierId).then(followings => Object.hasOwn(followings, notifieeId)),
@@ -163,8 +155,6 @@ export class NotificationService implements OnApplicationShutdown {
const packed = await this.notificationEntityService.pack(notification, notifieeId, {});
- if (packed == null) return null;
-
// Publish notification event
this.globalEventService.publishMainStream(notifieeId, 'notification', packed);
@@ -214,15 +204,6 @@ export class NotificationService implements OnApplicationShutdown {
*/
}
- @bindThis
- public async flushAllNotifications(userId: MiUser['id']) {
- await Promise.all([
- this.redisClient.del(`notificationTimeline:${userId}`),
- this.redisClient.del(`latestReadNotification:${userId}`),
- ]);
- this.globalEventService.publishMainStream(userId, 'notificationFlushed');
- }
-
@bindThis
public dispose(): void {
this.#shutdownController.abort();
diff --git a/packages/backend/src/core/ProxyAccountService.ts b/packages/backend/src/core/ProxyAccountService.ts
index c3ff2a68d3..71d663bf90 100644
--- a/packages/backend/src/core/ProxyAccountService.ts
+++ b/packages/backend/src/core/ProxyAccountService.ts
@@ -4,25 +4,26 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import type { MiMeta, UsersRepository } from '@/models/_.js';
+import type { UsersRepository } from '@/models/_.js';
import type { MiLocalUser } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
+import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js';
@Injectable()
export class ProxyAccountService {
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
+
+ private metaService: MetaService,
) {
}
@bindThis
public async fetch(): Promise {
- if (this.meta.proxyAccountId == null) return null;
- return await this.usersRepository.findOneByOrFail({ id: this.meta.proxyAccountId }) as MiLocalUser;
+ const meta = await this.metaService.fetch();
+ if (meta.proxyAccountId == null) return null;
+ return await this.usersRepository.findOneByOrFail({ id: meta.proxyAccountId }) as MiLocalUser;
}
}
diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts
index 1479bb00d9..e630539fbc 100644
--- a/packages/backend/src/core/PushNotificationService.ts
+++ b/packages/backend/src/core/PushNotificationService.ts
@@ -10,7 +10,8 @@ import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { Packed } from '@/misc/json-schema.js';
import { getNoteSummary } from '@/misc/get-note-summary.js';
-import type { MiMeta, MiSwSubscription, SwSubscriptionsRepository } from '@/models/_.js';
+import type { MiSwSubscription, SwSubscriptionsRepository } from '@/models/_.js';
+import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js';
import { RedisKVCache } from '@/misc/cache.js';
@@ -53,14 +54,13 @@ export class PushNotificationService implements OnApplicationShutdown {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.redis)
private redisClient: Redis.Redis,
@Inject(DI.swSubscriptionsRepository)
private swSubscriptionsRepository: SwSubscriptionsRepository,
+
+ private metaService: MetaService,
) {
this.subscriptionsCache = new RedisKVCache(this.redisClient, 'userSwSubscriptions', {
lifetime: 1000 * 60 * 60 * 1, // 1h
@@ -73,12 +73,14 @@ export class PushNotificationService implements OnApplicationShutdown {
@bindThis
public async pushNotification(userId: string, type: T, body: PushNotificationsTypes[T]) {
- if (!this.meta.enableServiceWorker || this.meta.swPublicKey == null || this.meta.swPrivateKey == null) return;
+ const meta = await this.metaService.fetch();
+
+ if (!meta.enableServiceWorker || meta.swPublicKey == null || meta.swPrivateKey == null) return;
// アプリケーションの連絡先と、サーバーサイドの鍵ペアの情報を登録
push.setVapidDetails(this.config.url,
- this.meta.swPublicKey,
- this.meta.swPrivateKey);
+ meta.swPublicKey,
+ meta.swPrivateKey);
const subscriptions = await this.subscriptionsCache.fetch(userId);
@@ -99,7 +101,7 @@ export class PushNotificationService implements OnApplicationShutdown {
type,
body: (type === 'notification' || type === 'unreadAntennaNote') ? truncateBody(type, body) : body,
userId,
- dateTime: Date.now(),
+ dateTime: (new Date()).getTime(),
}), {
proxy: this.config.proxy,
}).catch((err: any) => {
@@ -113,19 +115,12 @@ export class PushNotificationService implements OnApplicationShutdown {
endpoint: subscription.endpoint,
auth: subscription.auth,
publickey: subscription.publickey,
- }).then(() => {
- this.refreshCache(userId);
});
}
});
}
}
- @bindThis
- public refreshCache(userId: string): void {
- this.subscriptionsCache.refresh(userId);
- }
-
@bindThis
public dispose(): void {
this.subscriptionsCache.dispose();
diff --git a/packages/backend/src/core/QueueModule.ts b/packages/backend/src/core/QueueModule.ts
index b10b8e5899..216734e9e5 100644
--- a/packages/backend/src/core/QueueModule.ts
+++ b/packages/backend/src/core/QueueModule.ts
@@ -7,17 +7,10 @@ import { Inject, Module, OnApplicationShutdown } from '@nestjs/common';
import * as Bull from 'bullmq';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
-import { baseQueueOptions, QUEUE } from '@/queue/const.js';
+import { QUEUE, baseQueueOptions } from '@/queue/const.js';
import { allSettled } from '@/misc/promise-tracker.js';
-import {
- DeliverJobData,
- EndedPollNotificationJobData,
- InboxJobData,
- RelationshipJobData,
- UserWebhookDeliverJobData,
- SystemWebhookDeliverJobData,
-} from '../queue/types.js';
import type { Provider } from '@nestjs/common';
+import type { DeliverJobData, InboxJobData, EndedPollNotificationJobData, WebhookDeliverJobData, RelationshipJobData } from '../queue/types.js';
export type SystemQueue = Bull.Queue>;
export type EndedPollNotificationQueue = Bull.Queue;
@@ -26,8 +19,7 @@ export type InboxQueue = Bull.Queue;
export type DbQueue = Bull.Queue;
export type RelationshipQueue = Bull.Queue;
export type ObjectStorageQueue = Bull.Queue;
-export type UserWebhookDeliverQueue = Bull.Queue;
-export type SystemWebhookDeliverQueue = Bull.Queue;
+export type WebhookDeliverQueue = Bull.Queue;
const $system: Provider = {
provide: 'queue:system',
@@ -71,15 +63,9 @@ const $objectStorage: Provider = {
inject: [DI.config],
};
-const $userWebhookDeliver: Provider = {
- provide: 'queue:userWebhookDeliver',
- useFactory: (config: Config) => new Bull.Queue(QUEUE.USER_WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.USER_WEBHOOK_DELIVER)),
- inject: [DI.config],
-};
-
-const $systemWebhookDeliver: Provider = {
- provide: 'queue:systemWebhookDeliver',
- useFactory: (config: Config) => new Bull.Queue(QUEUE.SYSTEM_WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.SYSTEM_WEBHOOK_DELIVER)),
+const $webhookDeliver: Provider = {
+ provide: 'queue:webhookDeliver',
+ useFactory: (config: Config) => new Bull.Queue(QUEUE.WEBHOOK_DELIVER, baseQueueOptions(config, QUEUE.WEBHOOK_DELIVER)),
inject: [DI.config],
};
@@ -94,8 +80,7 @@ const $systemWebhookDeliver: Provider = {
$db,
$relationship,
$objectStorage,
- $userWebhookDeliver,
- $systemWebhookDeliver,
+ $webhookDeliver,
],
exports: [
$system,
@@ -105,8 +90,7 @@ const $systemWebhookDeliver: Provider = {
$db,
$relationship,
$objectStorage,
- $userWebhookDeliver,
- $systemWebhookDeliver,
+ $webhookDeliver,
],
})
export class QueueModule implements OnApplicationShutdown {
@@ -118,8 +102,7 @@ export class QueueModule implements OnApplicationShutdown {
@Inject('queue:db') public dbQueue: DbQueue,
@Inject('queue:relationship') public relationshipQueue: RelationshipQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
- @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
- @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
+ @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
) {}
public async dispose(): Promise {
@@ -134,8 +117,7 @@ export class QueueModule implements OnApplicationShutdown {
this.dbQueue.close(),
this.relationshipQueue.close(),
this.objectStorageQueue.close(),
- this.userWebhookDeliverQueue.close(),
- this.systemWebhookDeliverQueue.close(),
+ this.webhookDeliverQueue.close(),
]);
}
diff --git a/packages/backend/src/core/QueueService.ts b/packages/backend/src/core/QueueService.ts
index dc13aa21bf..103813acf2 100644
--- a/packages/backend/src/core/QueueService.ts
+++ b/packages/backend/src/core/QueueService.ts
@@ -8,34 +8,16 @@ import { Inject, Injectable } from '@nestjs/common';
import type { IActivity } from '@/core/activitypub/type.js';
import type { MiDriveFile } from '@/models/DriveFile.js';
import type { MiWebhook, webhookEventTypes } from '@/models/Webhook.js';
-import type { MiSystemWebhook, SystemWebhookEventType } from '@/models/SystemWebhook.js';
import type { Config } from '@/config.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import type { Antenna } from '@/server/api/endpoints/i/import-antennas.js';
-import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
-import type {
- DbJobData,
- DeliverJobData,
- RelationshipJobData,
- SystemWebhookDeliverJobData,
- ThinUser,
- UserWebhookDeliverJobData,
-} from '../queue/types.js';
-import type {
- DbQueue,
- DeliverQueue,
- EndedPollNotificationQueue,
- InboxQueue,
- ObjectStorageQueue,
- RelationshipQueue,
- SystemQueue,
- UserWebhookDeliverQueue,
- SystemWebhookDeliverQueue,
-} from './QueueModule.js';
+import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, RelationshipQueue, SystemQueue, WebhookDeliverQueue } from './QueueModule.js';
+import type { DbJobData, DeliverJobData, RelationshipJobData, ThinUser } from '../queue/types.js';
import type httpSignature from '@peertube/http-signature';
import type * as Bull from 'bullmq';
import { MiNote } from '@/models/Note.js';
+import { ApRequestCreator } from '@/core/activitypub/ApRequestService.js';
@Injectable()
export class QueueService {
@@ -50,8 +32,7 @@ export class QueueService {
@Inject('queue:db') public dbQueue: DbQueue,
@Inject('queue:relationship') public relationshipQueue: RelationshipQueue,
@Inject('queue:objectStorage') public objectStorageQueue: ObjectStorageQueue,
- @Inject('queue:userWebhookDeliver') public userWebhookDeliverQueue: UserWebhookDeliverQueue,
- @Inject('queue:systemWebhookDeliver') public systemWebhookDeliverQueue: SystemWebhookDeliverQueue,
+ @Inject('queue:webhookDeliver') public webhookDeliverQueue: WebhookDeliverQueue,
) {
this.systemQueue.add('tickCharts', {
}, {
@@ -88,12 +69,6 @@ export class QueueService {
repeat: { pattern: '*/5 * * * *' },
removeOnComplete: true,
});
-
- this.systemQueue.add('bakeBufferedReactions', {
- }, {
- repeat: { pattern: '0 0 * * *' },
- removeOnComplete: true,
- });
}
@bindThis
@@ -515,18 +490,9 @@ export class QueueService {
});
}
- /**
- * @see UserWebhookDeliverJobData
- * @see UserWebhookDeliverProcessorService
- */
@bindThis
- public userWebhookDeliver(
- webhook: MiWebhook,
- type: typeof webhookEventTypes[number],
- content: unknown,
- opts?: { attempts?: number },
- ) {
- const data: UserWebhookDeliverJobData = {
+ public webhookDeliver(webhook: MiWebhook, type: typeof webhookEventTypes[number], content: unknown) {
+ const data = {
type,
content,
webhookId: webhook.id,
@@ -537,39 +503,8 @@ export class QueueService {
eventId: randomUUID(),
};
- return this.userWebhookDeliverQueue.add(webhook.id, data, {
- attempts: opts?.attempts ?? 4,
- backoff: {
- type: 'custom',
- },
- removeOnComplete: true,
- removeOnFail: true,
- });
- }
-
- /**
- * @see SystemWebhookDeliverJobData
- * @see SystemWebhookDeliverProcessorService
- */
- @bindThis
- public systemWebhookDeliver(
- webhook: MiSystemWebhook,
- type: SystemWebhookEventType,
- content: unknown,
- opts?: { attempts?: number },
- ) {
- const data: SystemWebhookDeliverJobData = {
- type,
- content,
- webhookId: webhook.id,
- to: webhook.url,
- secret: webhook.secret,
- createdAt: Date.now(),
- eventId: randomUUID(),
- };
-
- return this.systemWebhookDeliverQueue.add(webhook.id, data, {
- attempts: opts?.attempts ?? 4,
+ return this.webhookDeliverQueue.add(webhook.id, data, {
+ attempts: 4,
backoff: {
type: 'custom',
},
diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts
index 0179b0680f..ace6fc69b6 100644
--- a/packages/backend/src/core/ReactionService.ts
+++ b/packages/backend/src/core/ReactionService.ts
@@ -4,8 +4,9 @@
*/
import { Inject, Injectable } from '@nestjs/common';
+import * as Redis from 'ioredis';
import { DI } from '@/di-symbols.js';
-import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, NoteThreadMutingsRepository, MiMeta } from '@/models/_.js';
+import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, NoteThreadMutingsRepository } from '@/models/_.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import type { MiRemoteUser, MiUser } from '@/models/User.js';
import type { MiNote } from '@/models/Note.js';
@@ -20,6 +21,7 @@ import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerServ
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
+import { MetaService } from '@/core/MetaService.js';
import { bindThis } from '@/decorators.js';
import { UtilityService } from '@/core/UtilityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
@@ -27,11 +29,9 @@ import { CustomEmojiService } from '@/core/CustomEmojiService.js';
import { RoleService } from '@/core/RoleService.js';
import { FeaturedService } from '@/core/FeaturedService.js';
import { trackPromise } from '@/misc/promise-tracker.js';
-import { isQuote, isRenote } from '@/misc/is-renote.js';
-import { ReactionsBufferingService } from '@/core/ReactionsBufferingService.js';
-import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js';
const FALLBACK = '\u2764';
+const PER_NOTE_REACTION_USER_PAIR_CACHE_MAX = 16;
const legacies: Record = {
'like': '👍',
@@ -64,14 +64,14 @@ type DecodedReaction = {
host?: string | null;
};
-const isCustomEmojiRegexp = /^:([\p{Letter}\p{Number}\p{Mark}_+-]+)(?:@\.)?:$/u;
-const decodeCustomEmojiRegexp = /^:([\p{Letter}\p{Number}\p{Mark}_+-]+)(?:@([\w.-]+))?:$/u;
+const isCustomEmojiRegexp = /^:([\w+-]+)(?:@\.)?:$/;
+const decodeCustomEmojiRegexp = /^:([\w+-]+)(?:@([\w.-]+))?:$/;
@Injectable()
export class ReactionService {
constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
+ @Inject(DI.redis)
+ private redisClient: Redis.Redis,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -89,12 +89,12 @@ export class ReactionService {
private emojisRepository: EmojisRepository,
private utilityService: UtilityService,
+ private metaService: MetaService,
private customEmojiService: CustomEmojiService,
private roleService: RoleService,
private userEntityService: UserEntityService,
private noteEntityService: NoteEntityService,
private userBlockingService: UserBlockingService,
- private reactionsBufferingService: ReactionsBufferingService,
private idService: IdService,
private featuredService: FeaturedService,
private globalEventService: GlobalEventService,
@@ -120,16 +120,11 @@ export class ReactionService {
throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.');
}
- // Check if note is Renote
- if (isRenote(note) && !isQuote(note)) {
- throw new IdentifiableError('12c35529-3c79-4327-b1cc-e2cf63a71925', 'You cannot react to Renote.');
- }
-
let reaction = _reaction ?? FALLBACK;
if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && (user.host != null))) {
reaction = '\u2764';
- } else if (_reaction != null) {
+ } else if (_reaction) {
const custom = reaction.match(isCustomEmojiRegexp);
if (custom) {
const reacterHost = this.utilityService.toPunyNullable(user.host);
@@ -150,11 +145,6 @@ export class ReactionService {
if ((note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote') && emoji.isSensitive) {
reaction = FALLBACK;
}
-
- // for media silenced host, custom emoji reactions are not allowed
- if (reacterHost != null && this.utilityService.isMediaSilencedHost(this.meta.mediaSilencedHosts, reacterHost)) {
- reaction = FALLBACK;
- }
} else {
// リアクションとして使う権限がない
reaction = FALLBACK;
@@ -174,6 +164,7 @@ export class ReactionService {
reaction,
};
+ // Create reaction
try {
await this.noteReactionsRepository.insert(record);
} catch (e) {
@@ -197,20 +188,16 @@ export class ReactionService {
}
// Increment reactions count
- if (this.meta.enableReactionsBuffering) {
- await this.reactionsBufferingService.create(note.id, user.id, reaction, note.reactionAndUserPairCache);
- } else {
- const sql = `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + 1)::text::jsonb)`;
- await this.notesRepository.createQueryBuilder().update()
- .set({
- reactions: () => sql,
- ...(note.reactionAndUserPairCache.length < PER_NOTE_REACTION_USER_PAIR_CACHE_MAX ? {
- reactionAndUserPairCache: () => `array_append("reactionAndUserPairCache", '${user.id}/${reaction}')`,
- } : {}),
- })
- .where('id = :id', { id: note.id })
- .execute();
- }
+ const sql = `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + 1)::text::jsonb)`;
+ await this.notesRepository.createQueryBuilder().update()
+ .set({
+ reactions: () => sql,
+ ...(note.reactionAndUserPairCache.length < PER_NOTE_REACTION_USER_PAIR_CACHE_MAX ? {
+ reactionAndUserPairCache: () => `array_append("reactionAndUserPairCache", '${user.id}/${reaction}')`,
+ } : {}),
+ })
+ .where('id = :id', { id: note.id })
+ .execute();
// 30%の確率、セルフではない、3日以内に投稿されたノートの場合ハイライト用ランキング更新
if (
@@ -230,7 +217,9 @@ export class ReactionService {
}
}
- if (this.meta.enableChartsForRemoteUser || (user.host == null)) {
+ const meta = await this.metaService.fetch();
+
+ if (meta.enableChartsForRemoteUser || (user.host == null)) {
this.perUserReactionsChart.update(user, note);
}
@@ -317,18 +306,14 @@ export class ReactionService {
}
// Decrement reactions count
- if (this.meta.enableReactionsBuffering) {
- await this.reactionsBufferingService.delete(note.id, user.id, exist.reaction);
- } else {
- const sql = `jsonb_set("reactions", '{${exist.reaction}}', (COALESCE("reactions"->>'${exist.reaction}', '0')::int - 1)::text::jsonb)`;
- await this.notesRepository.createQueryBuilder().update()
- .set({
- reactions: () => sql,
- reactionAndUserPairCache: () => `array_remove("reactionAndUserPairCache", '${user.id}/${exist.reaction}')`,
- })
- .where('id = :id', { id: note.id })
- .execute();
- }
+ const sql = `jsonb_set("reactions", '{${exist.reaction}}', (COALESCE("reactions"->>'${exist.reaction}', '0')::int - 1)::text::jsonb)`;
+ await this.notesRepository.createQueryBuilder().update()
+ .set({
+ reactions: () => sql,
+ reactionAndUserPairCache: () => `array_remove("reactionAndUserPairCache", '${user.id}/${exist.reaction}')`,
+ })
+ .where('id = :id', { id: note.id })
+ .execute();
this.globalEventService.publishNoteStream(note.id, 'unreacted', {
reaction: this.decodeReaction(exist.reaction).reaction,
@@ -349,46 +334,35 @@ export class ReactionService {
//#endregion
}
- /**
- * - 文字列タイプのレガシーな形式のリアクションを現在の形式に変換する
- * - ローカルのリアクションのホストを `@.` にする(`decodeReaction()`の効果)
- */
@bindThis
- public convertLegacyReaction(reaction: string): string {
- reaction = this.decodeReaction(reaction).reaction;
- if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
- return reaction;
- }
+ public convertLegacyReactions(reactions: Record) {
+ const _reactions = {} as Record;
- // TODO: 廃止
- /**
- * - 文字列タイプのレガシーな形式のリアクションを現在の形式に変換する
- * - ローカルのリアクションのホストを `@.` にする(`decodeReaction()`の効果)
- * - データベース上には存在する「0個のリアクションがついている」という情報を削除する
- */
- @bindThis
- public convertLegacyReactions(reactions: MiNote['reactions']): MiNote['reactions'] {
- return Object.entries(reactions)
- .filter(([, count]) => {
- // `ReactionService.prototype.delete`ではリアクション削除時に、
- // `MiNote['reactions']`のエントリの値をデクリメントしているが、
- // デクリメントしているだけなのでエントリ自体は0を値として持つ形で残り続ける。
- // そのため、この処理がなければ、「0個のリアクションがついている」ということになってしまう。
- return count > 0;
- })
- .map(([reaction, count]) => {
- const key = this.convertLegacyReaction(reaction);
+ for (const reaction of Object.keys(reactions)) {
+ if (reactions[reaction] <= 0) continue;
- return [key, count] as const;
- })
- .reduce((acc, [key, count]) => {
- // unchecked indexed access
- const prevCount = acc[key] as number | undefined;
+ if (Object.keys(legacies).includes(reaction)) {
+ if (_reactions[legacies[reaction]]) {
+ _reactions[legacies[reaction]] += reactions[reaction];
+ } else {
+ _reactions[legacies[reaction]] = reactions[reaction];
+ }
+ } else {
+ if (_reactions[reaction]) {
+ _reactions[reaction] += reactions[reaction];
+ } else {
+ _reactions[reaction] = reactions[reaction];
+ }
+ }
+ }
- acc[key] = (prevCount ?? 0) + count;
+ const _reactions2 = {} as Record;
- return acc;
- }, {});
+ for (const reaction of Object.keys(_reactions)) {
+ _reactions2[this.decodeReaction(reaction).reaction] = _reactions[reaction];
+ }
+
+ return _reactions2;
}
@bindThis
@@ -432,4 +406,11 @@ export class ReactionService {
host: undefined,
};
}
+
+ @bindThis
+ public convertLegacyReaction(reaction: string): string {
+ reaction = this.decodeReaction(reaction).reaction;
+ if (Object.keys(legacies).includes(reaction)) return legacies[reaction];
+ return reaction;
+ }
}
diff --git a/packages/backend/src/core/ReactionsBufferingService.ts b/packages/backend/src/core/ReactionsBufferingService.ts
deleted file mode 100644
index b4207c5106..0000000000
--- a/packages/backend/src/core/ReactionsBufferingService.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import * as Redis from 'ioredis';
-import { DI } from '@/di-symbols.js';
-import type { MiNote } from '@/models/Note.js';
-import { bindThis } from '@/decorators.js';
-import type { MiUser, NotesRepository } from '@/models/_.js';
-import type { Config } from '@/config.js';
-import { PER_NOTE_REACTION_USER_PAIR_CACHE_MAX } from '@/const.js';
-import type { GlobalEvents } from '@/core/GlobalEventService.js';
-import type { OnApplicationShutdown } from '@nestjs/common';
-
-const REDIS_DELTA_PREFIX = 'reactionsBufferDeltas';
-const REDIS_PAIR_PREFIX = 'reactionsBufferPairs';
-
-@Injectable()
-export class ReactionsBufferingService implements OnApplicationShutdown {
- constructor(
- @Inject(DI.config)
- private config: Config,
-
- @Inject(DI.redisForSub)
- private redisForSub: Redis.Redis,
-
- @Inject(DI.redisForReactions)
- private redisForReactions: Redis.Redis, // TODO: 専用のRedisインスタンスにする
-
- @Inject(DI.notesRepository)
- private notesRepository: NotesRepository,
- ) {
- this.redisForSub.on('message', this.onMessage);
- }
-
- @bindThis
- private async onMessage(_: string, data: string) {
- const obj = JSON.parse(data);
-
- if (obj.channel === 'internal') {
- const { type, body } = obj.message as GlobalEvents['internal']['payload'];
- switch (type) {
- case 'metaUpdated': {
- // リアクションバッファリングが有効→無効になったら即bake
- if (body.before != null && body.before.enableReactionsBuffering && !body.after.enableReactionsBuffering) {
- this.bake();
- }
- break;
- }
- default:
- break;
- }
- }
- }
-
- @bindThis
- public async create(noteId: MiNote['id'], userId: MiUser['id'], reaction: string, currentPairs: string[]): Promise {
- const pipeline = this.redisForReactions.pipeline();
- pipeline.hincrby(`${REDIS_DELTA_PREFIX}:${noteId}`, reaction, 1);
- for (let i = 0; i < currentPairs.length; i++) {
- pipeline.zadd(`${REDIS_PAIR_PREFIX}:${noteId}`, i, currentPairs[i]);
- }
- pipeline.zadd(`${REDIS_PAIR_PREFIX}:${noteId}`, Date.now(), `${userId}/${reaction}`);
- pipeline.zremrangebyrank(`${REDIS_PAIR_PREFIX}:${noteId}`, 0, -(PER_NOTE_REACTION_USER_PAIR_CACHE_MAX + 1));
- await pipeline.exec();
- }
-
- @bindThis
- public async delete(noteId: MiNote['id'], userId: MiUser['id'], reaction: string): Promise {
- const pipeline = this.redisForReactions.pipeline();
- pipeline.hincrby(`${REDIS_DELTA_PREFIX}:${noteId}`, reaction, -1);
- pipeline.zrem(`${REDIS_PAIR_PREFIX}:${noteId}`, `${userId}/${reaction}`);
- // TODO: 「消した要素一覧」も持っておかないとcreateされた時に上書きされて復活する
- await pipeline.exec();
- }
-
- @bindThis
- public async get(noteId: MiNote['id']): Promise<{
- deltas: Record;
- pairs: ([MiUser['id'], string])[];
- }> {
- const pipeline = this.redisForReactions.pipeline();
- pipeline.hgetall(`${REDIS_DELTA_PREFIX}:${noteId}`);
- pipeline.zrange(`${REDIS_PAIR_PREFIX}:${noteId}`, 0, -1);
- const results = await pipeline.exec();
-
- const resultDeltas = results![0][1] as Record;
- const resultPairs = results![1][1] as string[];
-
- const deltas = {} as Record;
- for (const [name, count] of Object.entries(resultDeltas)) {
- deltas[name] = parseInt(count);
- }
-
- const pairs = resultPairs.map(x => x.split('/') as [MiUser['id'], string]);
-
- return {
- deltas,
- pairs,
- };
- }
-
- @bindThis
- public async getMany(noteIds: MiNote['id'][]): Promise;
- pairs: ([MiUser['id'], string])[];
- }>> {
- const map = new Map;
- pairs: ([MiUser['id'], string])[];
- }>();
-
- const pipeline = this.redisForReactions.pipeline();
- for (const noteId of noteIds) {
- pipeline.hgetall(`${REDIS_DELTA_PREFIX}:${noteId}`);
- pipeline.zrange(`${REDIS_PAIR_PREFIX}:${noteId}`, 0, -1);
- }
- const results = await pipeline.exec();
-
- const opsForEachNotes = 2;
- for (let i = 0; i < noteIds.length; i++) {
- const noteId = noteIds[i];
- const resultDeltas = results![i * opsForEachNotes][1] as Record;
- const resultPairs = results![i * opsForEachNotes + 1][1] as string[];
-
- const deltas = {} as Record;
- for (const [name, count] of Object.entries(resultDeltas)) {
- deltas[name] = parseInt(count);
- }
-
- const pairs = resultPairs.map(x => x.split('/') as [MiUser['id'], string]);
-
- map.set(noteId, {
- deltas,
- pairs,
- });
- }
-
- return map;
- }
-
- // TODO: scanは重い可能性があるので、別途 bufferedNoteIds を直接Redis上に持っておいてもいいかもしれない
- @bindThis
- public async bake(): Promise {
- const bufferedNoteIds = [];
- let cursor = '0';
- do {
- // https://github.com/redis/ioredis#transparent-key-prefixing
- const result = await this.redisForReactions.scan(
- cursor,
- 'MATCH',
- `${this.config.redis.prefix}:${REDIS_DELTA_PREFIX}:*`,
- 'COUNT',
- '1000');
-
- cursor = result[0];
- bufferedNoteIds.push(...result[1].map(x => x.replace(`${this.config.redis.prefix}:${REDIS_DELTA_PREFIX}:`, '')));
- } while (cursor !== '0');
-
- const bufferedMap = await this.getMany(bufferedNoteIds);
-
- // clear
- const pipeline = this.redisForReactions.pipeline();
- for (const noteId of bufferedNoteIds) {
- pipeline.del(`${REDIS_DELTA_PREFIX}:${noteId}`);
- pipeline.del(`${REDIS_PAIR_PREFIX}:${noteId}`);
- }
- await pipeline.exec();
-
- // TODO: SQL一個にまとめたい
- for (const [noteId, buffered] of bufferedMap) {
- const sql = Object.entries(buffered.deltas)
- .map(([reaction, count]) =>
- `jsonb_set("reactions", '{${reaction}}', (COALESCE("reactions"->>'${reaction}', '0')::int + ${count})::text::jsonb)`)
- .join(' || ');
-
- this.notesRepository.createQueryBuilder().update()
- .set({
- reactions: () => sql,
- reactionAndUserPairCache: buffered.pairs.map(x => x.join('/')),
- })
- .where('id = :id', { id: noteId })
- .execute();
- }
- }
-
- @bindThis
- public mergeReactions(src: MiNote['reactions'], delta: Record): MiNote['reactions'] {
- const reactions = { ...src };
- for (const [name, count] of Object.entries(delta)) {
- if (reactions[name] != null) {
- reactions[name] += count;
- } else {
- reactions[name] = count;
- }
- }
- return reactions;
- }
-
- @bindThis
- public dispose(): void {
- this.redisForSub.off('message', this.onMessage);
- }
-
- @bindThis
- public onApplicationShutdown(signal?: string | undefined): void {
- this.dispose();
- }
-}
diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts
index db32114346..e9dc9b57af 100644
--- a/packages/backend/src/core/RelayService.ts
+++ b/packages/backend/src/core/RelayService.ts
@@ -35,7 +35,7 @@ export class RelayService {
private createSystemUserService: CreateSystemUserService,
private apRendererService: ApRendererService,
) {
- this.relaysCache = new MemorySingleCache(1000 * 60 * 10); // 10m
+ this.relaysCache = new MemorySingleCache(1000 * 60 * 10);
}
@bindThis
@@ -53,11 +53,11 @@ export class RelayService {
@bindThis
public async addRelay(inbox: string): Promise {
- const relay = await this.relaysRepository.insertOne({
+ const relay = await this.relaysRepository.insert({
id: this.idService.gen(),
inbox,
status: 'requesting',
- });
+ }).then(x => this.relaysRepository.findOneByOrFail(x.identifiers[0]));
const relayActor = await this.getRelayActor();
const follow = await this.apRendererService.renderFollowRelay(relay, relayActor);
diff --git a/packages/backend/src/core/RemoteUserResolveService.ts b/packages/backend/src/core/RemoteUserResolveService.ts
index 098b5e1706..f5a55eb8bc 100644
--- a/packages/backend/src/core/RemoteUserResolveService.ts
+++ b/packages/backend/src/core/RemoteUserResolveService.ts
@@ -56,7 +56,7 @@ export class RemoteUserResolveService {
host = this.utilityService.toPuny(host);
- if (host === this.utilityService.toPuny(this.config.host)) {
+ if (this.config.host === host) {
this.logger.info(`return local user: ${usernameLower}`);
return await this.usersRepository.findOneBy({ usernameLower, host: IsNull() }).then(u => {
if (u == null) {
diff --git a/packages/backend/src/core/ReversiService.ts b/packages/backend/src/core/ReversiService.ts
index 8c0a8f6cc7..53a7234823 100644
--- a/packages/backend/src/core/ReversiService.ts
+++ b/packages/backend/src/core/ReversiService.ts
@@ -6,7 +6,6 @@
import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis';
import { ModuleRef } from '@nestjs/core';
-import { reversiUpdateKeys } from 'misskey-js';
import * as Reversi from 'misskey-reversi';
import { IsNull, LessThan, MoreThan } from 'typeorm';
import type {
@@ -282,7 +281,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
@bindThis
private async matched(parentId: MiUser['id'], childId: MiUser['id'], options: { noIrregularRules: boolean; }): Promise {
- const game = await this.reversiGamesRepository.insertOne({
+ const game = await this.reversiGamesRepository.insert({
id: this.idService.gen(),
user1Id: parentId,
user2Id: childId,
@@ -295,7 +294,10 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
bw: 'random',
isLlotheo: false,
noIrregularRules: options.noIrregularRules,
- }, { relations: ['user1', 'user2'] });
+ }).then(x => this.reversiGamesRepository.findOneOrFail({
+ where: { id: x.identifiers[0].id },
+ relations: ['user1', 'user2'],
+ }));
this.cacheGame(game);
const packed = await this.reversiGameEntityService.packDetail(game);
@@ -400,33 +402,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
- public isValidReversiUpdateKey(key: unknown): key is typeof reversiUpdateKeys[number] {
- if (typeof key !== 'string') return false;
- return (reversiUpdateKeys as string[]).includes(key);
- }
-
- @bindThis
- public isValidReversiUpdateValue(key: K, value: unknown): value is MiReversiGame[K] {
- switch (key) {
- case 'map':
- return Array.isArray(value) && value.every(row => typeof row === 'string');
- case 'bw':
- return typeof value === 'string' && ['random', '1', '2'].includes(value);
- case 'isLlotheo':
- return typeof value === 'boolean';
- case 'canPutEverywhere':
- return typeof value === 'boolean';
- case 'loopedBoard':
- return typeof value === 'boolean';
- case 'timeLimitForEachTurn':
- return typeof value === 'number' && value >= 0;
- default:
- return false;
- }
- }
-
- @bindThis
- public async updateSettings(gameId: MiReversiGame['id'], user: MiUser, key: K, value: MiReversiGame[K]) {
+ public async updateSettings(gameId: MiReversiGame['id'], user: MiUser, key: string, value: any) {
const game = await this.get(gameId);
if (game == null) throw new Error('game not found');
if (game.isStarted) return;
@@ -434,6 +410,10 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
if ((game.user1Id === user.id) && game.user1Ready) return;
if ((game.user2Id === user.id) && game.user2Ready) return;
+ if (!['map', 'bw', 'isLlotheo', 'canPutEverywhere', 'loopedBoard', 'timeLimitForEachTurn'].includes(key)) return;
+
+ // TODO: より厳格なバリデーション
+
const updatedGame = {
...game,
[key]: value,
diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts
index 64f7539031..32c8514502 100644
--- a/packages/backend/src/core/RoleService.ts
+++ b/packages/backend/src/core/RoleService.ts
@@ -8,7 +8,6 @@ import * as Redis from 'ioredis';
import { In } from 'typeorm';
import { ModuleRef } from '@nestjs/core';
import type {
- MiMeta,
MiRole,
MiRoleAssignment,
RoleAssignmentsRepository,
@@ -19,6 +18,7 @@ import { MemoryKVCache, MemorySingleCache } from '@/misc/cache.js';
import type { MiUser } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
+import { MetaService } from '@/core/MetaService.js';
import { CacheService } from '@/core/CacheService.js';
import type { RoleCondFormulaValue } from '@/models/Role.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
@@ -36,7 +36,6 @@ export type RolePolicies = {
ltlAvailable: boolean;
btlAvailable: boolean;
canPublicNote: boolean;
- mentionLimit: number;
canInvite: boolean;
inviteLimit: number;
inviteLimitCycle: number;
@@ -48,7 +47,6 @@ export type RolePolicies = {
canHideAds: boolean;
driveCapacityMb: number;
alwaysMarkNsfw: boolean;
- canUpdateBioMedia: boolean;
pinLimit: number;
antennaLimit: number;
wordMuteLimit: number;
@@ -60,11 +58,6 @@ export type RolePolicies = {
rateLimitFactor: number;
canImportNotes: boolean;
avatarDecorationLimit: number;
- canImportAntennas: boolean;
- canImportBlocking: boolean;
- canImportFollowing: boolean;
- canImportMuting: boolean;
- canImportUserLists: boolean;
};
export const DEFAULT_POLICIES: RolePolicies = {
@@ -72,7 +65,6 @@ export const DEFAULT_POLICIES: RolePolicies = {
ltlAvailable: true,
btlAvailable: false,
canPublicNote: true,
- mentionLimit: 20,
canInvite: false,
inviteLimit: 0,
inviteLimitCycle: 60 * 24 * 7,
@@ -84,7 +76,6 @@ export const DEFAULT_POLICIES: RolePolicies = {
canHideAds: false,
driveCapacityMb: 100,
alwaysMarkNsfw: false,
- canUpdateBioMedia: true,
pinLimit: 5,
antennaLimit: 5,
wordMuteLimit: 200,
@@ -96,11 +87,6 @@ export const DEFAULT_POLICIES: RolePolicies = {
rateLimitFactor: 1,
canImportNotes: true,
avatarDecorationLimit: 1,
- canImportAntennas: true,
- canImportBlocking: true,
- canImportFollowing: true,
- canImportMuting: true,
- canImportUserLists: true,
};
@Injectable()
@@ -115,8 +101,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
constructor(
private moduleRef: ModuleRef,
- @Inject(DI.meta)
- private meta: MiMeta,
+ @Inject(DI.redis)
+ private redisClient: Redis.Redis,
@Inject(DI.redisForTimelines)
private redisForTimelines: Redis.Redis,
@@ -133,6 +119,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
@Inject(DI.roleAssignmentsRepository)
private roleAssignmentsRepository: RoleAssignmentsRepository,
+ private metaService: MetaService,
private cacheService: CacheService,
private userEntityService: UserEntityService,
private globalEventService: GlobalEventService,
@@ -140,8 +127,10 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
private moderationLogService: ModerationLogService,
private fanoutTimelineService: FanoutTimelineService,
) {
- this.rolesCache = new MemorySingleCache(1000 * 60 * 60); // 1h
- this.roleAssignmentByUserIdCache = new MemoryKVCache(1000 * 60 * 5); // 5m
+ //this.onMessage = this.onMessage.bind(this);
+
+ this.rolesCache = new MemorySingleCache(1000 * 60 * 60 * 1);
+ this.roleAssignmentByUserIdCache = new MemoryKVCache(1000 * 60 * 60 * 1);
this.redisForSub.on('message', this.onMessage);
}
@@ -215,82 +204,45 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
- private evalCond(user: MiUser, roles: MiRole[], value: RoleCondFormulaValue): boolean {
+ private evalCond(user: MiUser, value: RoleCondFormulaValue): boolean {
try {
switch (value.type) {
- // ~かつ~
case 'and': {
- return value.values.every(v => this.evalCond(user, roles, v));
+ return value.values.every(v => this.evalCond(user, v));
}
- // ~または~
case 'or': {
- return value.values.some(v => this.evalCond(user, roles, v));
+ return value.values.some(v => this.evalCond(user, v));
}
- // ~ではない
case 'not': {
- return !this.evalCond(user, roles, value.value);
+ return !this.evalCond(user, value.value);
}
- // マニュアルロールがアサインされている
- case 'roleAssignedTo': {
- return roles.some(r => r.id === value.roleId);
- }
- // ローカルユーザのみ
case 'isLocal': {
return this.userEntityService.isLocalUser(user);
}
- // リモートユーザのみ
case 'isRemote': {
return this.userEntityService.isRemoteUser(user);
}
- // サスペンド済みユーザである
- case 'isSuspended': {
- return user.isSuspended;
- }
- // 鍵アカウントユーザである
- case 'isLocked': {
- return user.isLocked;
- }
- // botユーザである
- case 'isBot': {
- return user.isBot;
- }
- // 猫である
- case 'isCat': {
- return user.isCat;
- }
- // 「ユーザを見つけやすくする」が有効なアカウント
- case 'isExplorable': {
- return user.isExplorable;
- }
- // ユーザが作成されてから指定期間経過した
case 'createdLessThan': {
return this.idService.parse(user.id).date.getTime() > (Date.now() - (value.sec * 1000));
}
- // ユーザが作成されてから指定期間経っていない
case 'createdMoreThan': {
return this.idService.parse(user.id).date.getTime() < (Date.now() - (value.sec * 1000));
}
- // フォロワー数が指定値以下
case 'followersLessThanOrEq': {
return user.followersCount <= value.value;
}
- // フォロワー数が指定値以上
case 'followersMoreThanOrEq': {
return user.followersCount >= value.value;
}
- // フォロー数が指定値以下
case 'followingLessThanOrEq': {
return user.followingCount <= value.value;
}
- // フォロー数が指定値以上
case 'followingMoreThanOrEq': {
return user.followingCount >= value.value;
}
- // ノート数が指定値以下
case 'notesLessThanOrEq': {
return user.notesCount <= value.value;
}
- // ノート数が指定値以上
case 'notesMoreThanOrEq': {
return user.notesCount >= value.value;
}
@@ -324,7 +276,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
const assigns = await this.getUserAssigns(userId);
const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
- const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, assignedRoles, r.condFormula));
+ const matchedCondRoles = roles.filter(r => r.target === 'conditional' && this.evalCond(user!, r.condFormula));
return [...assignedRoles, ...matchedCondRoles];
}
@@ -337,13 +289,13 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
let assigns = await this.roleAssignmentByUserIdCache.fetch(userId, () => this.roleAssignmentsRepository.findBy({ userId }));
// 期限切れのロールを除外
assigns = assigns.filter(a => a.expiresAt == null || (a.expiresAt.getTime() > now));
+ const assignedRoleIds = assigns.map(x => x.roleId);
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
- const assignedRoles = roles.filter(r => assigns.map(x => x.roleId).includes(r.id));
- const assignedBadgeRoles = assignedRoles.filter(r => r.asBadge);
+ const assignedBadgeRoles = roles.filter(r => r.asBadge && assignedRoleIds.includes(r.id));
const badgeCondRoles = roles.filter(r => r.asBadge && (r.target === 'conditional'));
if (badgeCondRoles.length > 0) {
const user = roles.some(r => r.target === 'conditional') ? await this.cacheService.findUserById(userId) : null;
- const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, assignedRoles, r.condFormula));
+ const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, r.condFormula));
return [...assignedBadgeRoles, ...matchedBadgeCondRoles];
} else {
return assignedBadgeRoles;
@@ -352,7 +304,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
@bindThis
public async getUserPolicies(userId: MiUser['id'] | null): Promise {
- const basePolicies = { ...DEFAULT_POLICIES, ...this.meta.policies };
+ const meta = await this.metaService.fetch();
+ const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies };
if (userId == null) return basePolicies;
@@ -377,7 +330,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
btlAvailable: calc('btlAvailable', vs => vs.some(v => v === true)),
ltlAvailable: calc('ltlAvailable', vs => vs.some(v => v === true)),
canPublicNote: calc('canPublicNote', vs => vs.some(v => v === true)),
- mentionLimit: calc('mentionLimit', vs => Math.max(...vs)),
canInvite: calc('canInvite', vs => vs.some(v => v === true)),
inviteLimit: calc('inviteLimit', vs => Math.max(...vs)),
inviteLimitCycle: calc('inviteLimitCycle', vs => Math.max(...vs)),
@@ -389,7 +341,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canHideAds: calc('canHideAds', vs => vs.some(v => v === true)),
driveCapacityMb: calc('driveCapacityMb', vs => Math.max(...vs)),
alwaysMarkNsfw: calc('alwaysMarkNsfw', vs => vs.some(v => v === true)),
- canUpdateBioMedia: calc('canUpdateBioMedia', vs => vs.some(v => v === true)),
pinLimit: calc('pinLimit', vs => Math.max(...vs)),
antennaLimit: calc('antennaLimit', vs => Math.max(...vs)),
wordMuteLimit: calc('wordMuteLimit', vs => Math.max(...vs)),
@@ -401,11 +352,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
rateLimitFactor: calc('rateLimitFactor', vs => Math.max(...vs)),
canImportNotes: calc('canImportNotes', vs => vs.some(v => v === true)),
avatarDecorationLimit: calc('avatarDecorationLimit', vs => Math.max(...vs)),
- canImportAntennas: calc('canImportAntennas', vs => vs.some(v => v === true)),
- canImportBlocking: calc('canImportBlocking', vs => vs.some(v => v === true)),
- canImportFollowing: calc('canImportFollowing', vs => vs.some(v => v === true)),
- canImportMuting: calc('canImportMuting', vs => vs.some(v => v === true)),
- canImportUserLists: calc('canImportUserLists', vs => vs.some(v => v === true)),
};
}
@@ -430,32 +376,14 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
@bindThis
- public async getModeratorIds(includeAdmins = true, excludeExpire = false): Promise {
+ public async getModeratorIds(includeAdmins = true): Promise {
const roles = await this.rolesCache.fetch(() => this.rolesRepository.findBy({}));
- const moderatorRoles = includeAdmins
- ? roles.filter(r => r.isModerator || r.isAdministrator)
- : roles.filter(r => r.isModerator);
-
+ const moderatorRoles = includeAdmins ? roles.filter(r => r.isModerator || r.isAdministrator) : roles.filter(r => r.isModerator);
+ const assigns = moderatorRoles.length > 0 ? await this.roleAssignmentsRepository.findBy({
+ roleId: In(moderatorRoles.map(r => r.id)),
+ }) : [];
// TODO: isRootなアカウントも含める
- const assigns = moderatorRoles.length > 0
- ? await this.roleAssignmentsRepository.findBy({ roleId: In(moderatorRoles.map(r => r.id)) })
- : [];
-
- const now = Date.now();
- const result = [
- // Setを経由して重複を除去(ユーザIDは重複する可能性があるので)
- ...new Set(
- assigns
- .filter(it =>
- (excludeExpire)
- ? (it.expiresAt == null || it.expiresAt.getTime() > now)
- : true,
- )
- .map(a => a.userId),
- ),
- ];
-
- return result.sort((x, y) => x.localeCompare(y));
+ return assigns.map(a => a.userId);
}
@bindThis
@@ -509,12 +437,12 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
}
}
- const created = await this.roleAssignmentsRepository.insertOne({
+ const created = await this.roleAssignmentsRepository.insert({
id: this.idService.gen(now),
expiresAt: expiresAt,
roleId: roleId,
userId: userId,
- });
+ }).then(x => this.roleAssignmentsRepository.findOneByOrFail(x.identifiers[0]));
this.rolesRepository.update(roleId, {
lastUsedAt: new Date(),
@@ -522,15 +450,14 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
this.globalEventService.publishInternalEvent('userRoleAssigned', created);
- const user = await this.usersRepository.findOneByOrFail({ id: userId });
-
- if (role.isPublic && user.host === null) {
+ if (role.isPublic) {
this.notificationService.createNotification(userId, 'roleAssigned', {
roleId: roleId,
});
}
if (moderator) {
+ const user = await this.usersRepository.findOneByOrFail({ id: userId });
this.moderationLogService.log(moderator, 'assignRole', {
roleId: roleId,
roleName: role.name,
@@ -597,7 +524,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
@bindThis
public async create(values: Partial, moderator?: MiUser): Promise {
const date = new Date();
- const created = await this.rolesRepository.insertOne({
+ const created = await this.rolesRepository.insert({
id: this.idService.gen(date.getTime()),
updatedAt: date,
lastUsedAt: date,
@@ -615,7 +542,7 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
canEditMembersByModerator: values.canEditMembersByModerator,
displayOrder: values.displayOrder,
policies: values.policies,
- });
+ }).then(x => this.rolesRepository.findOneByOrFail(x.identifiers[0]));
this.globalEventService.publishInternalEvent('roleCreated', created);
diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts
index 1b0b1e5bbd..e3d69e5e94 100644
--- a/packages/backend/src/core/SignupService.ts
+++ b/packages/backend/src/core/SignupService.ts
@@ -9,7 +9,7 @@ import { Inject, Injectable } from '@nestjs/common';
import * as argon2 from 'argon2';
import { DataSource, IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js';
-import type { MiMeta, UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
+import type { UsedUsernamesRepository, UsersRepository } from '@/models/_.js';
import { MiUser } from '@/models/User.js';
import { MiUserProfile } from '@/models/UserProfile.js';
import { IdService } from '@/core/IdService.js';
@@ -21,7 +21,7 @@ import { InstanceActorService } from '@/core/InstanceActorService.js';
import { bindThis } from '@/decorators.js';
import UsersChart from '@/core/chart/charts/users.js';
import { UtilityService } from '@/core/UtilityService.js';
-import { UserService } from '@/core/UserService.js';
+import { MetaService } from '@/core/MetaService.js';
@Injectable()
export class SignupService {
@@ -29,9 +29,6 @@ export class SignupService {
@Inject(DI.db)
private db: DataSource,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -39,9 +36,9 @@ export class SignupService {
private usedUsernamesRepository: UsedUsernamesRepository,
private utilityService: UtilityService,
- private userService: UserService,
private userEntityService: UserEntityService,
private idService: IdService,
+ private metaService: MetaService,
private instanceActorService: InstanceActorService,
private usersChart: UsersChart,
) {
@@ -55,10 +52,10 @@ export class SignupService {
host?: string | null;
reason?: string | null;
ignorePreservedUsernames?: boolean;
- approved?: boolean;
}) {
const { username, password, passwordHash, host, reason } = opts;
let hash = passwordHash;
+ const instance = await this.metaService.fetch(true);
// Validate username
if (!this.userEntityService.validateLocalUsername(username)) {
@@ -92,7 +89,7 @@ export class SignupService {
const isTheFirstUser = !await this.instanceActorService.realLocalUsersPresent();
if (!opts.ignorePreservedUsernames && !isTheFirstUser) {
- const isPreserved = this.meta.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
+ const isPreserved = instance.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
if (isPreserved) {
throw new Error('USED_USERNAME');
}
@@ -116,6 +113,9 @@ export class SignupService {
));
let account!: MiUser;
+ let defaultApproval = false;
+
+ if (!instance.approvalRequiredForSignup) defaultApproval = true;
// Start transaction
await this.db.transaction(async transactionalEntityManager => {
@@ -133,7 +133,7 @@ export class SignupService {
host: this.utilityService.toPunyNullable(host),
token: secret,
isRoot: isTheFirstUser,
- approved: isTheFirstUser || (opts.approved ?? !this.meta.approvalRequiredForSignup),
+ approved: defaultApproval,
signupReason: reason,
}));
@@ -155,9 +155,9 @@ export class SignupService {
}));
});
- this.usersChart.update(account, true).then();
- this.userService.notifySystemWebhook(account, 'userCreated').then();
+ this.usersChart.update(account, true);
return { account, secret };
}
}
+
diff --git a/packages/backend/src/core/SponsorsService.ts b/packages/backend/src/core/SponsorsService.ts
deleted file mode 100644
index 77dd6f81a4..0000000000
--- a/packages/backend/src/core/SponsorsService.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * SPDX-FileCopyrightText: marie and other Sharkey contributors
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable, OnApplicationShutdown } from '@nestjs/common';
-import type { MiMeta } from '@/models/_.js';
-import * as Redis from 'ioredis';
-import { DI } from '@/di-symbols.js';
-import { RedisKVCache } from '@/misc/cache.js';
-import { bindThis } from '@/decorators.js';
-
-@Injectable()
-export class SponsorsService implements OnApplicationShutdown {
- private cache: RedisKVCache;
-
- constructor(
- @Inject(DI.meta)
- private meta: MiMeta,
-
- @Inject(DI.redis)
- private redisClient: Redis.Redis,
- ) {
- this.cache = new RedisKVCache(this.redisClient, 'sponsors', {
- lifetime: 1000 * 60 * 60,
- memoryCacheLifetime: 1000 * 60,
- fetcher: (key) => {
- if (key === 'instance') return this.fetchInstanceSponsors();
- return this.fetchSharkeySponsors();
- },
- toRedisConverter: (value) => JSON.stringify(value),
- fromRedisConverter: (value) => JSON.parse(value),
- });
- }
-
- @bindThis
- private async fetchInstanceSponsors() {
- if (!(this.meta.donationUrl && this.meta.donationUrl.includes('opencollective.com'))) {
- return [];
- }
-
- try {
- const backers = await fetch(`${this.meta.donationUrl}/members/users.json`).then((response) => response.json());
-
- // Merge both together into one array and make sure it only has Active subscriptions
- const allSponsors = [...backers].filter(sponsor => sponsor.isActive === true && sponsor.role === 'BACKER' && sponsor.tier);
-
- // Remove possible duplicates
- return [...new Map(allSponsors.map(v => [v.profile, v])).values()];
- } catch (error) {
- return [];
- }
- }
-
- @bindThis
- private async fetchSharkeySponsors() {
- try {
- const backers = await fetch('https://opencollective.com/sharkey/tiers/backer/all.json').then((response) => response.json());
- const sponsorsOC = await fetch('https://opencollective.com/sharkey/tiers/sponsor/all.json').then((response) => response.json());
-
- // Merge both together into one array and make sure it only has Active subscriptions
- const allSponsors = [...sponsorsOC, ...backers].filter(sponsor => sponsor.isActive === true);
-
- // Remove possible duplicates
- return [...new Map(allSponsors.map(v => [v.profile, v])).values()];
- } catch (error) {
- return [];
- }
- }
-
- @bindThis
- public async instanceSponsors(forceUpdate: boolean) {
- if (forceUpdate) this.cache.refresh('instance');
- return this.cache.fetch('instance');
- }
-
- @bindThis
- public async sharkeySponsors(forceUpdate: boolean) {
- if (forceUpdate) this.cache.refresh('sharkey');
- return this.cache.fetch('sharkey');
- }
-
- @bindThis
- public onApplicationShutdown(signal?: string | undefined): void {
- this.cache.dispose();
- }
-}
diff --git a/packages/backend/src/core/SystemWebhookService.ts b/packages/backend/src/core/SystemWebhookService.ts
deleted file mode 100644
index bb7c6b8c0e..0000000000
--- a/packages/backend/src/core/SystemWebhookService.ts
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import * as Redis from 'ioredis';
-import type { MiUser, SystemWebhooksRepository } from '@/models/_.js';
-import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
-import { GlobalEvents, GlobalEventService } from '@/core/GlobalEventService.js';
-import { MiSystemWebhook, type SystemWebhookEventType } from '@/models/SystemWebhook.js';
-import { IdService } from '@/core/IdService.js';
-import { QueueService } from '@/core/QueueService.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { LoggerService } from '@/core/LoggerService.js';
-import Logger from '@/logger.js';
-import type { OnApplicationShutdown } from '@nestjs/common';
-
-@Injectable()
-export class SystemWebhookService implements OnApplicationShutdown {
- private logger: Logger;
- private activeSystemWebhooksFetched = false;
- private activeSystemWebhooks: MiSystemWebhook[] = [];
-
- constructor(
- @Inject(DI.redisForSub)
- private redisForSub: Redis.Redis,
- @Inject(DI.systemWebhooksRepository)
- private systemWebhooksRepository: SystemWebhooksRepository,
- private idService: IdService,
- private queueService: QueueService,
- private moderationLogService: ModerationLogService,
- private loggerService: LoggerService,
- private globalEventService: GlobalEventService,
- ) {
- this.redisForSub.on('message', this.onMessage);
- this.logger = this.loggerService.getLogger('webhook');
- }
-
- @bindThis
- public async fetchActiveSystemWebhooks() {
- if (!this.activeSystemWebhooksFetched) {
- this.activeSystemWebhooks = await this.systemWebhooksRepository.findBy({
- isActive: true,
- });
- this.activeSystemWebhooksFetched = true;
- }
-
- return this.activeSystemWebhooks;
- }
-
- /**
- * SystemWebhook の一覧を取得する.
- */
- @bindThis
- public fetchSystemWebhooks(params?: {
- ids?: MiSystemWebhook['id'][];
- isActive?: MiSystemWebhook['isActive'];
- on?: MiSystemWebhook['on'];
- }): Promise {
- const query = this.systemWebhooksRepository.createQueryBuilder('systemWebhook');
- if (params) {
- if (params.ids && params.ids.length > 0) {
- query.andWhere('systemWebhook.id IN (:...ids)', { ids: params.ids });
- }
- if (params.isActive !== undefined) {
- query.andWhere('systemWebhook.isActive = :isActive', { isActive: params.isActive });
- }
- if (params.on && params.on.length > 0) {
- query.andWhere(':on <@ systemWebhook.on', { on: params.on });
- }
- }
-
- return query.getMany();
- }
-
- /**
- * SystemWebhook を作成する.
- */
- @bindThis
- public async createSystemWebhook(
- params: {
- isActive: MiSystemWebhook['isActive'];
- name: MiSystemWebhook['name'];
- on: MiSystemWebhook['on'];
- url: MiSystemWebhook['url'];
- secret: MiSystemWebhook['secret'];
- },
- updater: MiUser,
- ): Promise {
- const id = this.idService.gen();
- await this.systemWebhooksRepository.insert({
- ...params,
- id,
- });
-
- const webhook = await this.systemWebhooksRepository.findOneByOrFail({ id });
- this.globalEventService.publishInternalEvent('systemWebhookCreated', webhook);
- this.moderationLogService
- .log(updater, 'createSystemWebhook', {
- systemWebhookId: webhook.id,
- webhook: webhook,
- })
- .then();
-
- return webhook;
- }
-
- /**
- * SystemWebhook を更新する.
- */
- @bindThis
- public async updateSystemWebhook(
- params: {
- id: MiSystemWebhook['id'];
- isActive: MiSystemWebhook['isActive'];
- name: MiSystemWebhook['name'];
- on: MiSystemWebhook['on'];
- url: MiSystemWebhook['url'];
- secret: MiSystemWebhook['secret'];
- },
- updater: MiUser,
- ): Promise {
- const beforeEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: params.id });
- await this.systemWebhooksRepository.update(beforeEntity.id, {
- updatedAt: new Date(),
- isActive: params.isActive,
- name: params.name,
- on: params.on,
- url: params.url,
- secret: params.secret,
- });
-
- const afterEntity = await this.systemWebhooksRepository.findOneByOrFail({ id: beforeEntity.id });
- this.globalEventService.publishInternalEvent('systemWebhookUpdated', afterEntity);
- this.moderationLogService
- .log(updater, 'updateSystemWebhook', {
- systemWebhookId: beforeEntity.id,
- before: beforeEntity,
- after: afterEntity,
- })
- .then();
-
- return afterEntity;
- }
-
- /**
- * SystemWebhook を削除する.
- */
- @bindThis
- public async deleteSystemWebhook(id: MiSystemWebhook['id'], updater: MiUser) {
- const webhook = await this.systemWebhooksRepository.findOneByOrFail({ id });
- await this.systemWebhooksRepository.delete(id);
-
- this.globalEventService.publishInternalEvent('systemWebhookDeleted', webhook);
- this.moderationLogService
- .log(updater, 'deleteSystemWebhook', {
- systemWebhookId: webhook.id,
- webhook,
- })
- .then();
- }
-
- /**
- * SystemWebhook をWebhook配送キューに追加する
- * @see QueueService.systemWebhookDeliver
- * // TODO: contentの型を厳格化する
- */
- @bindThis
- public async enqueueSystemWebhook(
- webhook: MiSystemWebhook | MiSystemWebhook['id'],
- type: T,
- content: unknown,
- ) {
- const webhookEntity = typeof webhook === 'string'
- ? (await this.fetchActiveSystemWebhooks()).find(a => a.id === webhook)
- : webhook;
- if (!webhookEntity || !webhookEntity.isActive) {
- this.logger.info(`SystemWebhook is not active or not found : ${webhook}`);
- return;
- }
-
- if (!webhookEntity.on.includes(type)) {
- this.logger.info(`SystemWebhook ${webhookEntity.id} is not listening to ${type}`);
- return;
- }
-
- return this.queueService.systemWebhookDeliver(webhookEntity, type, content);
- }
-
- @bindThis
- private async onMessage(_: string, data: string): Promise {
- const obj = JSON.parse(data);
- if (obj.channel !== 'internal') {
- return;
- }
-
- const { type, body } = obj.message as GlobalEvents['internal']['payload'];
- switch (type) {
- case 'systemWebhookCreated': {
- if (body.isActive) {
- this.activeSystemWebhooks.push(MiSystemWebhook.deserialize(body));
- }
- break;
- }
- case 'systemWebhookUpdated': {
- if (body.isActive) {
- const i = this.activeSystemWebhooks.findIndex(a => a.id === body.id);
- if (i > -1) {
- this.activeSystemWebhooks[i] = MiSystemWebhook.deserialize(body);
- } else {
- this.activeSystemWebhooks.push(MiSystemWebhook.deserialize(body));
- }
- } else {
- this.activeSystemWebhooks = this.activeSystemWebhooks.filter(a => a.id !== body.id);
- }
- break;
- }
- case 'systemWebhookDeleted': {
- this.activeSystemWebhooks = this.activeSystemWebhooks.filter(a => a.id !== body.id);
- break;
- }
- default:
- break;
- }
- }
-
- @bindThis
- public dispose(): void {
- this.redisForSub.off('message', this.onMessage);
- }
-
- @bindThis
- public onApplicationShutdown(signal?: string | undefined): void {
- this.dispose();
- }
-}
diff --git a/packages/backend/src/core/UserBlockingService.ts b/packages/backend/src/core/UserBlockingService.ts
index 2f1310b8ef..96f389b54c 100644
--- a/packages/backend/src/core/UserBlockingService.ts
+++ b/packages/backend/src/core/UserBlockingService.ts
@@ -16,7 +16,7 @@ import Logger from '@/logger.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { LoggerService } from '@/core/LoggerService.js';
-import { UserWebhookService } from '@/core/UserWebhookService.js';
+import { WebhookService } from '@/core/WebhookService.js';
import { bindThis } from '@/decorators.js';
import { CacheService } from '@/core/CacheService.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
@@ -46,7 +46,7 @@ export class UserBlockingService implements OnModuleInit {
private idService: IdService,
private queueService: QueueService,
private globalEventService: GlobalEventService,
- private webhookService: UserWebhookService,
+ private webhookService: WebhookService,
private apRendererService: ApRendererService,
private loggerService: LoggerService,
) {
@@ -121,7 +121,7 @@ export class UserBlockingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'unfollow', {
+ this.queueService.webhookDeliver(webhook, 'unfollow', {
user: packed,
});
}
diff --git a/packages/backend/src/core/UserFollowingService.ts b/packages/backend/src/core/UserFollowingService.ts
index 77e7b60bea..8ad85391c6 100644
--- a/packages/backend/src/core/UserFollowingService.ts
+++ b/packages/backend/src/core/UserFollowingService.ts
@@ -13,21 +13,23 @@ import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { IdService } from '@/core/IdService.js';
import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js';
+import type { Packed } from '@/misc/json-schema.js';
import InstanceChart from '@/core/chart/charts/instance.js';
import { FederatedInstanceService } from '@/core/FederatedInstanceService.js';
-import { UserWebhookService } from '@/core/UserWebhookService.js';
+import { WebhookService } from '@/core/WebhookService.js';
import { NotificationService } from '@/core/NotificationService.js';
import { DI } from '@/di-symbols.js';
-import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, MiMeta, UserProfilesRepository, UsersRepository } from '@/models/_.js';
+import type { FollowingsRepository, FollowRequestsRepository, InstancesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { bindThis } from '@/decorators.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
+import { MetaService } from '@/core/MetaService.js';
import { CacheService } from '@/core/CacheService.js';
import type { Config } from '@/config.js';
import { AccountMoveService } from '@/core/AccountMoveService.js';
import { UtilityService } from '@/core/UtilityService.js';
-import type { ThinUser } from '@/queue/types.js';
+import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import Logger from '../logger.js';
const logger = new Logger('following/create');
@@ -55,9 +57,6 @@ export class UserFollowingService implements OnModuleInit {
@Inject(DI.config)
private config: Config,
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
@@ -79,11 +78,13 @@ export class UserFollowingService implements OnModuleInit {
private idService: IdService,
private queueService: QueueService,
private globalEventService: GlobalEventService,
+ private metaService: MetaService,
private notificationService: NotificationService,
private federatedInstanceService: FederatedInstanceService,
- private webhookService: UserWebhookService,
+ private webhookService: WebhookService,
private apRendererService: ApRendererService,
private accountMoveService: AccountMoveService,
+ private fanoutTimelineService: FanoutTimelineService,
private perUserFollowingChart: PerUserFollowingChart,
private instanceChart: InstanceChart,
) {
@@ -93,35 +94,21 @@ export class UserFollowingService implements OnModuleInit {
this.userBlockingService = this.moduleRef.get('UserBlockingService');
}
- @bindThis
- public async deliverAccept(follower: MiRemoteUser, followee: MiPartialLocalUser, requestId?: string) {
- const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
- this.queueService.deliver(followee, content, follower.inbox, false);
- }
-
@bindThis
public async follow(
- _follower: ThinUser,
- _followee: ThinUser,
+ _follower: { id: MiUser['id'] },
+ _followee: { id: MiUser['id'] },
{ requestId, silent = false, withReplies }: {
requestId?: string,
silent?: boolean,
withReplies?: boolean,
} = {},
): Promise {
- /**
- * 必ず最新のユーザー情報を取得する
- */
const [follower, followee] = await Promise.all([
this.usersRepository.findOneByOrFail({ id: _follower.id }),
this.usersRepository.findOneByOrFail({ id: _followee.id }),
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
- if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) {
- // What?
- throw new Error('Remote user cannot follow remote user.');
- }
-
// check blocking
const [blocking, blocked] = await Promise.all([
this.userBlockingService.checkBlocked(follower.id, followee.id),
@@ -142,24 +129,6 @@ export class UserFollowingService implements OnModuleInit {
if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked');
}
- if (await this.followingsRepository.exists({
- where: {
- followerId: follower.id,
- followeeId: followee.id,
- },
- })) {
- // すでにフォロー関係が存在している場合
- if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
- // リモート → ローカル: acceptを送り返しておしまい
- this.deliverAccept(follower, followee, requestId);
- return;
- }
- if (this.userEntityService.isLocalUser(follower)) {
- // ローカル → リモート/ローカル: 例外
- throw new IdentifiableError('ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced', 'already following');
- }
- }
-
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
// フォロー対象が鍵アカウントである or
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
@@ -170,7 +139,7 @@ export class UserFollowingService implements OnModuleInit {
followee.isLocked ||
(followeeProfile.carefulBot && follower.isBot) ||
(this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee) && process.env.FORCE_FOLLOW_REMOTE_USER_FOR_TESTING !== 'true') ||
- (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isSilencedHost(this.meta.silencedHosts, follower.host))
+ (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower) && this.utilityService.isSilencedHost((await this.metaService.fetch()).silencedHosts, follower.host))
) {
let autoAccept = false;
@@ -220,7 +189,8 @@ export class UserFollowingService implements OnModuleInit {
await this.insertFollowingDoc(followee, follower, silent, withReplies);
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
- this.deliverAccept(follower, followee, requestId);
+ const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
+ this.queueService.deliver(followee, content, follower.inbox, false);
}
}
@@ -275,19 +245,14 @@ export class UserFollowingService implements OnModuleInit {
followeeId: followee.id,
followerId: follower.id,
});
+
+ // 通知を作成
+ this.notificationService.createNotification(follower.id, 'followRequestAccepted', {
+ }, followee.id);
}
if (alreadyFollowed) return;
- // 通知を作成
- if (follower.host === null) {
- const profile = await this.cacheService.userProfileCache.fetch(followee.id);
-
- this.notificationService.createNotification(follower.id, 'followRequestAccepted', {
- message: profile.followedMessage,
- }, followee.id);
- }
-
this.globalEventService.publishInternalEvent('follow', { followerId: follower.id, followeeId: followee.id });
const [followeeUser, followerUser] = await Promise.all([
@@ -308,14 +273,14 @@ export class UserFollowingService implements OnModuleInit {
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
this.federatedInstanceService.fetch(follower.host).then(async i => {
this.instancesRepository.increment({ id: i.id }, 'followingCount', 1);
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateFollowing(i.host, true);
}
});
} else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
this.federatedInstanceService.fetch(followee.host).then(async i => {
this.instancesRepository.increment({ id: i.id }, 'followersCount', 1);
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateFollowers(i.host, true);
}
});
@@ -334,7 +299,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('follow'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'follow', {
+ this.queueService.webhookDeliver(webhook, 'follow', {
user: packed,
});
}
@@ -348,7 +313,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === followee.id && x.on.includes('followed'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'followed', {
+ this.queueService.webhookDeliver(webhook, 'followed', {
user: packed,
});
}
@@ -401,7 +366,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'unfollow', {
+ this.queueService.webhookDeliver(webhook, 'unfollow', {
user: packed,
});
}
@@ -440,14 +405,14 @@ export class UserFollowingService implements OnModuleInit {
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
this.federatedInstanceService.fetch(follower.host).then(async i => {
this.instancesRepository.decrement({ id: i.id }, 'followingCount', 1);
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateFollowing(i.host, false);
}
});
} else if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
this.federatedInstanceService.fetch(followee.host).then(async i => {
this.instancesRepository.decrement({ id: i.id }, 'followersCount', 1);
- if (this.meta.enableChartsForFederatedInstances) {
+ if ((await this.metaService.fetch()).enableChartsForFederatedInstances) {
this.instanceChart.updateFollowers(i.host, false);
}
});
@@ -514,13 +479,7 @@ export class UserFollowingService implements OnModuleInit {
if (blocking) throw new Error('blocking');
if (blocked) throw new Error('blocked');
- // Remove old follow requests before creating a new one.
- await this.followRequestsRepository.delete({
- followeeId: followee.id,
- followerId: follower.id,
- });
-
- const followRequest = await this.followRequestsRepository.insertOne({
+ const followRequest = await this.followRequestsRepository.insert({
id: this.idService.gen(),
followerId: follower.id,
followeeId: followee.id,
@@ -534,7 +493,7 @@ export class UserFollowingService implements OnModuleInit {
followeeHost: followee.host,
followeeInbox: this.userEntityService.isRemoteUser(followee) ? followee.inbox : undefined,
followeeSharedInbox: this.userEntityService.isRemoteUser(followee) ? followee.sharedInbox : undefined,
- });
+ }).then(x => this.followRequestsRepository.findOneByOrFail(x.identifiers[0]));
// Publish receiveRequest event
if (this.userEntityService.isLocalUser(followee)) {
@@ -612,7 +571,8 @@ export class UserFollowingService implements OnModuleInit {
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
- this.deliverAccept(follower, followee as MiPartialLocalUser, request.requestId ?? undefined);
+ const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee));
+ this.queueService.deliver(followee, content, follower.inbox, false);
}
this.userEntityService.pack(followee.id, followee, {
@@ -743,7 +703,7 @@ export class UserFollowingService implements OnModuleInit {
const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === follower.id && x.on.includes('unfollow'));
for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'unfollow', {
+ this.queueService.webhookDeliver(webhook, 'unfollow', {
user: packedFollowee,
});
}
diff --git a/packages/backend/src/core/UserKeypairService.ts b/packages/backend/src/core/UserKeypairService.ts
index 92d61cd103..51ac99179a 100644
--- a/packages/backend/src/core/UserKeypairService.ts
+++ b/packages/backend/src/core/UserKeypairService.ts
@@ -25,7 +25,7 @@ export class UserKeypairService implements OnApplicationShutdown {
) {
this.cache = new RedisKVCache(this.redisClient, 'userKeypair', {
lifetime: 1000 * 60 * 60 * 24, // 24h
- memoryCacheLifetime: 1000 * 60 * 60, // 1h
+ memoryCacheLifetime: Infinity,
fetcher: (key) => this.userKeypairsRepository.findOneByOrFail({ userId: key }),
toRedisConverter: (value) => JSON.stringify(value),
fromRedisConverter: (value) => JSON.parse(value),
diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts
index 6333356fe9..bbdcfed738 100644
--- a/packages/backend/src/core/UserListService.ts
+++ b/packages/backend/src/core/UserListService.ts
@@ -95,7 +95,7 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit {
const currentCount = await this.userListMembershipsRepository.countBy({
userListId: list.id,
});
- if (currentCount >= (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
+ if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
throw new UserListService.TooManyUsersError();
}
diff --git a/packages/backend/src/core/UserRenoteMutingService.ts b/packages/backend/src/core/UserRenoteMutingService.ts
deleted file mode 100644
index bdc5e23f4b..0000000000
--- a/packages/backend/src/core/UserRenoteMutingService.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project , Type4ny-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import { In } from 'typeorm';
-import type { RenoteMutingsRepository } from '@/models/_.js';
-import type { MiRenoteMuting } from '@/models/RenoteMuting.js';
-
-import { IdService } from '@/core/IdService.js';
-import type { MiUser } from '@/models/User.js';
-import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
-import { CacheService } from '@/core/CacheService.js';
-
-@Injectable()
-export class UserRenoteMutingService {
- constructor(
- @Inject(DI.renoteMutingsRepository)
- private renoteMutingsRepository: RenoteMutingsRepository,
-
- private idService: IdService,
- private cacheService: CacheService,
- ) {
- }
-
- @bindThis
- public async mute(user: MiUser, target: MiUser, expiresAt: Date | null = null): Promise {
- await this.renoteMutingsRepository.insert({
- id: this.idService.gen(),
- muterId: user.id,
- muteeId: target.id,
- });
-
- await this.cacheService.renoteMutingsCache.refresh(user.id);
- }
-
- @bindThis
- public async unmute(mutings: MiRenoteMuting[]): Promise {
- if (mutings.length === 0) return;
-
- await this.renoteMutingsRepository.delete({
- id: In(mutings.map(m => m.id)),
- });
-
- const muterIds = [...new Set(mutings.map(m => m.muterId))];
- for (const muterId of muterIds) {
- await this.cacheService.renoteMutingsCache.refresh(muterId);
- }
- }
-}
diff --git a/packages/backend/src/core/UserSearchService.ts b/packages/backend/src/core/UserSearchService.ts
deleted file mode 100644
index 0d03cf6ee0..0000000000
--- a/packages/backend/src/core/UserSearchService.ts
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import { Brackets, SelectQueryBuilder } from 'typeorm';
-import { DI } from '@/di-symbols.js';
-import { type FollowingsRepository, MiUser, type UsersRepository } from '@/models/_.js';
-import { bindThis } from '@/decorators.js';
-import { sqlLikeEscape } from '@/misc/sql-like-escape.js';
-import type { Config } from '@/config.js';
-import { UserEntityService } from '@/core/entities/UserEntityService.js';
-import { Packed } from '@/misc/json-schema.js';
-
-function defaultActiveThreshold() {
- return new Date(Date.now() - 1000 * 60 * 60 * 24 * 30);
-}
-
-@Injectable()
-export class UserSearchService {
- constructor(
- @Inject(DI.config)
- private config: Config,
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
- @Inject(DI.followingsRepository)
- private followingsRepository: FollowingsRepository,
- private userEntityService: UserEntityService,
- ) {
- }
-
- /**
- * ユーザ名とホスト名によるユーザ検索を行う.
- *
- * - 検索結果には優先順位がつけられており、以下の順序で検索が行われる.
- * 1. フォローしているユーザのうち、一定期間以内(※)に更新されたユーザ
- * 2. フォローしているユーザのうち、一定期間以内に更新されていないユーザ
- * 3. フォローしていないユーザのうち、一定期間以内に更新されたユーザ
- * 4. フォローしていないユーザのうち、一定期間以内に更新されていないユーザ
- * - ログインしていない場合は、以下の順序で検索が行われる.
- * 1. 一定期間以内に更新されたユーザ
- * 2. 一定期間以内に更新されていないユーザ
- * - それぞれの検索結果はユーザ名の昇順でソートされる.
- * - 動作的には先に登場した検索結果の登場位置が優先される(条件的にユーザIDが重複することはないが).
- * (1で既にヒットしていた場合、2, 3, 4でヒットしても無視される)
- * - ユーザ名とホスト名の検索条件はそれぞれ前方一致で検索される.
- * - ユーザ名の検索は大文字小文字を区別しない.
- * - ホスト名の検索は大文字小文字を区別しない.
- * - 検索結果は最大で {@link opts.limit} 件までとなる.
- *
- * ※一定期間とは {@link params.activeThreshold} で指定された日時から現在までの期間を指す.
- *
- * @param params 検索条件.
- * @param opts 関数の動作を制御するオプション.
- * @param me 検索を実行するユーザの情報. 未ログインの場合は指定しない.
- * @see {@link UserSearchService#buildSearchUserQueries}
- * @see {@link UserSearchService#buildSearchUserNoLoginQueries}
- */
- @bindThis
- public async search(
- params: {
- username?: string | null,
- host?: string | null,
- activeThreshold?: Date,
- },
- opts?: {
- limit?: number,
- detail?: boolean,
- },
- me?: MiUser | null,
- ): Promise[]> {
- const queries = me ? this.buildSearchUserQueries(me, params) : this.buildSearchUserNoLoginQueries(params);
-
- let resultSet = new Set();
- const limit = opts?.limit ?? 10;
- for (const query of queries) {
- const ids = await query
- .select('user.id')
- .limit(limit - resultSet.size)
- .orderBy('user.usernameLower', 'ASC')
- .getRawMany<{ user_id: MiUser['id'] }>()
- .then(res => res.map(x => x.user_id));
-
- resultSet = new Set([...resultSet, ...ids]);
- if (resultSet.size >= limit) {
- break;
- }
- }
-
- return this.userEntityService.packMany<'UserLite' | 'UserDetailed'>(
- [...resultSet].slice(0, limit),
- me,
- { schema: opts?.detail ? 'UserDetailed' : 'UserLite' },
- );
- }
-
- /**
- * ログイン済みユーザによる検索実行時のクエリ一覧を構築する.
- * @param me
- * @param params
- * @private
- */
- @bindThis
- private buildSearchUserQueries(
- me: MiUser,
- params: {
- username?: string | null,
- host?: string | null,
- activeThreshold?: Date,
- },
- ) {
- // デフォルト30日以内に更新されたユーザーをアクティブユーザーとする
- const activeThreshold = params.activeThreshold ?? defaultActiveThreshold();
-
- const followingUserQuery = this.followingsRepository.createQueryBuilder('following')
- .select('following.followeeId')
- .where('following.followerId = :followerId', { followerId: me.id });
-
- const activeFollowingUsersQuery = this.generateUserQueryBuilder(params)
- .andWhere(`user.id IN (${followingUserQuery.getQuery()})`)
- .andWhere('user.updatedAt > :activeThreshold', { activeThreshold });
- activeFollowingUsersQuery.setParameters(followingUserQuery.getParameters());
-
- const inactiveFollowingUsersQuery = this.generateUserQueryBuilder(params)
- .andWhere(`user.id IN (${followingUserQuery.getQuery()})`)
- .andWhere(new Brackets(qb => {
- qb
- .where('user.updatedAt IS NULL')
- .orWhere('user.updatedAt <= :activeThreshold', { activeThreshold });
- }));
- inactiveFollowingUsersQuery.setParameters(followingUserQuery.getParameters());
-
- // 自分自身がヒットするとしたらここ
- const activeUserQuery = this.generateUserQueryBuilder(params)
- .andWhere(`user.id NOT IN (${followingUserQuery.getQuery()})`)
- .andWhere('user.updatedAt > :activeThreshold', { activeThreshold });
- activeUserQuery.setParameters(followingUserQuery.getParameters());
-
- const inactiveUserQuery = this.generateUserQueryBuilder(params)
- .andWhere(`user.id NOT IN (${followingUserQuery.getQuery()})`)
- .andWhere('user.updatedAt <= :activeThreshold', { activeThreshold });
- inactiveUserQuery.setParameters(followingUserQuery.getParameters());
-
- return [activeFollowingUsersQuery, inactiveFollowingUsersQuery, activeUserQuery, inactiveUserQuery];
- }
-
- /**
- * ログインしていないユーザによる検索実行時のクエリ一覧を構築する.
- * @param params
- * @private
- */
- @bindThis
- private buildSearchUserNoLoginQueries(params: {
- username?: string | null,
- host?: string | null,
- activeThreshold?: Date,
- }) {
- // デフォルト30日以内に更新されたユーザーをアクティブユーザーとする
- const activeThreshold = params.activeThreshold ?? defaultActiveThreshold();
-
- const activeUserQuery = this.generateUserQueryBuilder(params)
- .andWhere(new Brackets(qb => {
- qb
- .where('user.updatedAt IS NULL')
- .orWhere('user.updatedAt > :activeThreshold', { activeThreshold });
- }));
-
- const inactiveUserQuery = this.generateUserQueryBuilder(params)
- .andWhere('user.updatedAt <= :activeThreshold', { activeThreshold });
-
- return [activeUserQuery, inactiveUserQuery];
- }
-
- /**
- * ユーザ検索クエリで共通する抽出条件をあらかじめ設定したクエリビルダを生成する.
- * @param params
- * @private
- */
- @bindThis
- private generateUserQueryBuilder(params: {
- username?: string | null,
- host?: string | null,
- }): SelectQueryBuilder {
- const userQuery = this.usersRepository.createQueryBuilder('user');
-
- if (params.username) {
- userQuery.andWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(params.username.toLowerCase()) + '%' });
- }
-
- if (params.host) {
- if (params.host === this.config.hostname || params.host === '.') {
- userQuery.andWhere('user.host IS NULL');
- } else {
- userQuery.andWhere('user.host LIKE :host', {
- host: sqlLikeEscape(params.host.toLowerCase()) + '%',
- });
- }
- }
-
- userQuery.andWhere('user.isSuspended = FALSE');
-
- return userQuery;
- }
-}
diff --git a/packages/backend/src/core/UserService.ts b/packages/backend/src/core/UserService.ts
index 9b1961c631..72fa4d928d 100644
--- a/packages/backend/src/core/UserService.ts
+++ b/packages/backend/src/core/UserService.ts
@@ -8,18 +8,15 @@ import type { FollowingsRepository, UsersRepository } from '@/models/_.js';
import type { MiUser } from '@/models/User.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
-import { SystemWebhookService } from '@/core/SystemWebhookService.js';
-import { UserEntityService } from '@/core/entities/UserEntityService.js';
@Injectable()
export class UserService {
constructor(
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
+
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
- private systemWebhookService: SystemWebhookService,
- private userEntityService: UserEntityService,
) {
}
@@ -53,23 +50,4 @@ export class UserService {
});
}
}
-
- /**
- * SystemWebhookを用いてユーザに関する操作内容を管理者各位に通知する.
- * ここではJobQueueへのエンキューのみを行うため、即時実行されない.
- *
- * @see SystemWebhookService.enqueueSystemWebhook
- */
- @bindThis
- public async notifySystemWebhook(user: MiUser, type: 'userCreated') {
- const packedUser = await this.userEntityService.pack(user, null, { schema: 'UserLite' });
- const recipientWebhookIds = await this.systemWebhookService.fetchSystemWebhooks({ isActive: true, on: [type] });
- for (const webhookId of recipientWebhookIds) {
- await this.systemWebhookService.enqueueSystemWebhook(
- webhookId,
- type,
- packedUser,
- );
- }
- }
}
diff --git a/packages/backend/src/core/UserSuspendService.ts b/packages/backend/src/core/UserSuspendService.ts
index 30dcaa6f7d..d594a223f4 100644
--- a/packages/backend/src/core/UserSuspendService.ts
+++ b/packages/backend/src/core/UserSuspendService.ts
@@ -5,7 +5,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Not, IsNull } from 'typeorm';
-import type { FollowingsRepository, FollowRequestsRepository, UsersRepository } from '@/models/_.js';
+import type { FollowingsRepository } from '@/models/_.js';
import type { MiUser } from '@/models/User.js';
import { QueueService } from '@/core/QueueService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
@@ -13,78 +13,24 @@ import { DI } from '@/di-symbols.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
-import { RelationshipJobData } from '@/queue/types.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
-import { isSystemAccount } from '@/misc/is-system-account.js';
@Injectable()
export class UserSuspendService {
constructor(
- @Inject(DI.usersRepository)
- private usersRepository: UsersRepository,
-
@Inject(DI.followingsRepository)
private followingsRepository: FollowingsRepository,
- @Inject(DI.followRequestsRepository)
- private followRequestsRepository: FollowRequestsRepository,
-
private userEntityService: UserEntityService,
private queueService: QueueService,
private globalEventService: GlobalEventService,
private apRendererService: ApRendererService,
- private moderationLogService: ModerationLogService,
) {
}
@bindThis
- public async suspend(user: MiUser, moderator: MiUser): Promise {
- if (isSystemAccount(user)) throw new Error('cannot suspend a system account');
-
- await this.usersRepository.update(user.id, {
- isSuspended: true,
- });
-
- this.moderationLogService.log(moderator, 'suspend', {
- userId: user.id,
- userUsername: user.username,
- userHost: user.host,
- });
-
- (async () => {
- await this.postSuspend(user).catch(e => {});
- await this.unFollowAll(user).catch(e => {});
- })();
- }
-
- @bindThis
- public async unsuspend(user: MiUser, moderator: MiUser): Promise {
- await this.usersRepository.update(user.id, {
- isSuspended: false,
- });
-
- this.moderationLogService.log(moderator, 'unsuspend', {
- userId: user.id,
- userUsername: user.username,
- userHost: user.host,
- });
-
- (async () => {
- await this.postUnsuspend(user).catch(e => {});
- })();
- }
-
- @bindThis
- private async postSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise {
+ public async doPostSuspend(user: { id: MiUser['id']; host: MiUser['host'] }): Promise {
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: true });
- this.followRequestsRepository.delete({
- followeeId: user.id,
- });
- this.followRequestsRepository.delete({
- followerId: user.id,
- });
-
if (this.userEntityService.isLocalUser(user)) {
// 知り得る全SharedInboxにDelete配信
const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.userEntityService.genLocalUserUri(user.id), user));
@@ -112,7 +58,7 @@ export class UserSuspendService {
}
@bindThis
- private async postUnsuspend(user: MiUser): Promise {
+ public async doPostUnsuspend(user: MiUser): Promise {
this.globalEventService.publishInternalEvent('userChangeSuspendedState', { id: user.id, isSuspended: false });
if (this.userEntityService.isLocalUser(user)) {
@@ -140,26 +86,4 @@ export class UserSuspendService {
}
}
}
-
- @bindThis
- private async unFollowAll(follower: MiUser) {
- const followings = await this.followingsRepository.find({
- where: {
- followerId: follower.id,
- followeeId: Not(IsNull()),
- },
- });
-
- const jobs: RelationshipJobData[] = [];
- for (const following of followings) {
- if (following.followeeId && following.followerId) {
- jobs.push({
- from: { id: following.followerId },
- to: { id: following.followeeId },
- silent: true,
- });
- }
- }
- this.queueService.createUnfollowJob(jobs);
- }
}
diff --git a/packages/backend/src/core/UserWebhookService.ts b/packages/backend/src/core/UserWebhookService.ts
deleted file mode 100644
index 8a40a53688..0000000000
--- a/packages/backend/src/core/UserWebhookService.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SPDX-FileCopyrightText: syuilo and misskey-project
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-import { Inject, Injectable } from '@nestjs/common';
-import * as Redis from 'ioredis';
-import { type WebhooksRepository } from '@/models/_.js';
-import { MiWebhook } from '@/models/Webhook.js';
-import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
-import { GlobalEvents } from '@/core/GlobalEventService.js';
-import type { OnApplicationShutdown } from '@nestjs/common';
-
-@Injectable()
-export class UserWebhookService implements OnApplicationShutdown {
- private activeWebhooksFetched = false;
- private activeWebhooks: MiWebhook[] = [];
-
- constructor(
- @Inject(DI.redisForSub)
- private redisForSub: Redis.Redis,
- @Inject(DI.webhooksRepository)
- private webhooksRepository: WebhooksRepository,
- ) {
- this.redisForSub.on('message', this.onMessage);
- }
-
- @bindThis
- public async getActiveWebhooks() {
- if (!this.activeWebhooksFetched) {
- this.activeWebhooks = await this.webhooksRepository.findBy({
- active: true,
- });
- this.activeWebhooksFetched = true;
- }
-
- return this.activeWebhooks;
- }
-
- /**
- * UserWebhook の一覧を取得する.
- */
- @bindThis
- public fetchWebhooks(params?: {
- ids?: MiWebhook['id'][];
- isActive?: MiWebhook['active'];
- on?: MiWebhook['on'];
- }): Promise {
- const query = this.webhooksRepository.createQueryBuilder('webhook');
- if (params) {
- if (params.ids && params.ids.length > 0) {
- query.andWhere('webhook.id IN (:...ids)', { ids: params.ids });
- }
- if (params.isActive !== undefined) {
- query.andWhere('webhook.active = :isActive', { isActive: params.isActive });
- }
- if (params.on && params.on.length > 0) {
- query.andWhere(':on <@ webhook.on', { on: params.on });
- }
- }
-
- return query.getMany();
- }
-
- @bindThis
- private async onMessage(_: string, data: string): Promise {
- const obj = JSON.parse(data);
- if (obj.channel !== 'internal') {
- return;
- }
-
- const { type, body } = obj.message as GlobalEvents['internal']['payload'];
- switch (type) {
- case 'webhookCreated': {
- if (body.active) {
- this.activeWebhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
- ...body,
- latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
- user: null, // joinなカラムは通常取ってこないので
- });
- }
- break;
- }
- case 'webhookUpdated': {
- if (body.active) {
- const i = this.activeWebhooks.findIndex(a => a.id === body.id);
- if (i > -1) {
- this.activeWebhooks[i] = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
- ...body,
- latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
- user: null, // joinなカラムは通常取ってこないので
- };
- } else {
- this.activeWebhooks.push({ // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい
- ...body,
- latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
- user: null, // joinなカラムは通常取ってこないので
- });
- }
- } else {
- this.activeWebhooks = this.activeWebhooks.filter(a => a.id !== body.id);
- }
- break;
- }
- case 'webhookDeleted': {
- this.activeWebhooks = this.activeWebhooks.filter(a => a.id !== body.id);
- break;
- }
- default:
- break;
- }
- }
-
- @bindThis
- public dispose(): void {
- this.redisForSub.off('message', this.onMessage);
- }
-
- @bindThis
- public onApplicationShutdown(signal?: string | undefined): void {
- this.dispose();
- }
-}
diff --git a/packages/backend/src/core/UtilityService.ts b/packages/backend/src/core/UtilityService.ts
index dda4bd5fbd..638a0c019e 100644
--- a/packages/backend/src/core/UtilityService.ts
+++ b/packages/backend/src/core/UtilityService.ts
@@ -4,23 +4,18 @@
*/
import { URL } from 'node:url';
-import punycode from 'punycode/punycode.js';
+import { toASCII } from 'punycode';
import { Inject, Injectable } from '@nestjs/common';
import RE2 from 're2';
-import psl from 'psl';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js';
-import { MiMeta } from '@/models/Meta.js';
@Injectable()
export class UtilityService {
constructor(
@Inject(DI.config)
private config: Config,
-
- @Inject(DI.meta)
- private meta: MiMeta,
) {
}
@@ -35,11 +30,6 @@ export class UtilityService {
return this.toPuny(this.config.host) === this.toPuny(host);
}
- @bindThis
- public isUriLocal(uri: string): boolean {
- return this.punyHost(uri) === this.toPuny(this.config.host);
- }
-
@bindThis
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
if (host == null) return false;
@@ -52,26 +42,6 @@ export class UtilityService {
return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
}
- @bindThis
- public isMediaSilencedHost(silencedHosts: string[] | undefined, host: string | null): boolean {
- if (!silencedHosts || host == null) return false;
- return silencedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
- }
-
- @bindThis
- public concatNoteContentsForKeyWordCheck(content: {
- cw?: string | null;
- text?: string | null;
- pollChoices?: string[] | null;
- others?: string[] | null;
- }): string {
- /**
- * ノートの内容を結合してキーワードチェック用の文字列を生成する
- * cwとtextは内容が繋がっているかもしれないので間に何も入れずにチェックする
- */
- return `${content.cw ?? ''}${content.text ?? ''}\n${(content.pollChoices ?? []).join('\n')}\n${(content.others ?? []).join('\n')}`;
- }
-
@bindThis
public isKeyWordIncluded(text: string, keyWords: string[]): boolean {
if (keyWords.length === 0) return false;
@@ -102,58 +72,17 @@ export class UtilityService {
@bindThis
public extractDbHost(uri: string): string {
const url = new URL(uri);
- return this.toPuny(url.host);
+ return this.toPuny(url.hostname);
}
@bindThis
public toPuny(host: string): string {
- return punycode.toASCII(host.toLowerCase());
+ return toASCII(host.toLowerCase());
}
@bindThis
public toPunyNullable(host: string | null | undefined): string | null {
if (host == null) return null;
- return punycode.toASCII(host.toLowerCase());
- }
-
- @bindThis
- public punyHost(url: string): string {
- const urlObj = new URL(url);
- const host = `${this.toPuny(urlObj.hostname)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`;
- return host;
- }
-
- private specialSuffix(hostname: string): string | null {
- // masto.host provides domain names for its clients, we have to
- // treat it as if it were a public suffix
- const mastoHost = hostname.match(/\.?([a-zA-Z0-9-]+\.masto\.host)$/i);
- if (mastoHost) {
- return mastoHost[1];
- }
-
- return null;
- }
-
- @bindThis
- public punyHostPSLDomain(url: string): string {
- const urlObj = new URL(url);
- const hostname = urlObj.hostname;
- const domain = this.specialSuffix(hostname) ?? psl.get(hostname) ?? hostname;
- const host = `${this.toPuny(domain)}${urlObj.port.length > 0 ? ':' + urlObj.port : ''}`;
- return host;
- }
-
- public isFederationAllowedHost(host: string): boolean {
- if (this.meta.federation === 'none') return false;
- if (this.meta.federation === 'specified' && !this.meta.federationHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`))) return false;
- if (this.isBlockedHost(this.meta.blockedHosts, host)) return false;
-
- return true;
- }
-
- @bindThis
- public isFederationAllowedUri(uri: string): boolean {
- const host = this.extractDbHost(uri);
- return this.isFederationAllowedHost(host);
+ return toASCII(host.toLowerCase());
}
}
diff --git a/packages/backend/src/core/WebAuthnService.ts b/packages/backend/src/core/WebAuthnService.ts
index 75ab0a207c..4d11865906 100644
--- a/packages/backend/src/core/WebAuthnService.ts
+++ b/packages/backend/src/core/WebAuthnService.ts
@@ -10,11 +10,12 @@ import {
generateRegistrationOptions, verifyAuthenticationResponse,
verifyRegistrationResponse,
} from '@simplewebauthn/server';
-import { AttestationFormat, isoCBOR, isoUint8Array } from '@simplewebauthn/server/helpers';
+import { AttestationFormat, isoCBOR } from '@simplewebauthn/server/helpers';
import { DI } from '@/di-symbols.js';
-import type { MiMeta, UserSecurityKeysRepository } from '@/models/_.js';
+import type { UserSecurityKeysRepository } from '@/models/_.js';
import type { Config } from '@/config.js';
import { bindThis } from '@/decorators.js';
+import { MetaService } from '@/core/MetaService.js';
import { MiUser } from '@/models/_.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import type {
@@ -22,6 +23,7 @@ import type {
AuthenticatorTransportFuture,
CredentialDeviceType,
PublicKeyCredentialCreationOptionsJSON,
+ PublicKeyCredentialDescriptorFuture,
PublicKeyCredentialRequestOptionsJSON,
RegistrationResponseJSON,
} from '@simplewebauthn/types';
@@ -29,33 +31,33 @@ import type {
@Injectable()
export class WebAuthnService {
constructor(
- @Inject(DI.config)
- private config: Config,
-
- @Inject(DI.meta)
- private meta: MiMeta,
-
@Inject(DI.redis)
private redisClient: Redis.Redis,
+ @Inject(DI.config)
+ private config: Config,
+
@Inject(DI.userSecurityKeysRepository)
private userSecurityKeysRepository: UserSecurityKeysRepository,
+
+ private metaService: MetaService,
) {
}
@bindThis
- public getRelyingParty(): { origin: string; rpId: string; rpName: string; rpIcon?: string; } {
+ public async getRelyingParty(): Promise<{ origin: string; rpId: string; rpName: string; rpIcon?: string; }> {
+ const instance = await this.metaService.fetch();
return {
origin: this.config.url,
- rpId: this.config.hostname,
- rpName: this.meta.name ?? this.config.host,
- rpIcon: this.meta.iconUrl ?? undefined,
+ rpId: this.config.host,
+ rpName: instance.name ?? this.config.host,
+ rpIcon: instance.iconUrl ?? undefined,
};
}
@bindThis
public async initiateRegistration(userId: MiUser['id'], userName: string, userDisplayName?: string): Promise {
- const relyingParty = this.getRelyingParty();
+ const relyingParty = await this.getRelyingParty();
const keys = await this.userSecurityKeysRepository.findBy({
userId: userId,
});
@@ -63,12 +65,13 @@ export class WebAuthnService {
const registrationOptions = await generateRegistrationOptions({
rpName: relyingParty.rpName,
rpID: relyingParty.rpId,
- userID: isoUint8Array.fromUTF8String(userId),
+ userID: userId,
userName: userName,
userDisplayName: userDisplayName,
attestationType: 'indirect',
- excludeCredentials: keys.map(key => (<{ id: string; transports?: AuthenticatorTransportFuture[]; }>{
- id: key.id,
+ excludeCredentials: keys.map(key => ({
+ id: Buffer.from(key.id, 'base64url'),
+ type: 'public-key',
transports: key.transports ?? undefined,
})),
authenticatorSelection: {
@@ -84,7 +87,7 @@ export class WebAuthnService {
@bindThis
public async verifyRegistration(userId: MiUser['id'], response: RegistrationResponseJSON): Promise<{
- credentialID: string;
+ credentialID: Uint8Array;
credentialPublicKey: Uint8Array;
attestationObject: Uint8Array;
fmt: AttestationFormat;
@@ -102,7 +105,7 @@ export class WebAuthnService {
await this.redisClient.del(`webauthn:challenge:${userId}`);
- const relyingParty = this.getRelyingParty();
+ const relyingParty = await this.getRelyingParty();
let verification;
try {
@@ -141,7 +144,6 @@ export class WebAuthnService {
@bindThis
public async initiateAuthentication(userId: MiUser['id']): Promise {
- const relyingParty = this.getRelyingParty();
const keys = await this.userSecurityKeysRepository.findBy({
userId: userId,
});
@@ -151,9 +153,9 @@ export class WebAuthnService {
}
const authenticationOptions = await generateAuthenticationOptions({
- rpID: relyingParty.rpId,
- allowCredentials: keys.map(key => (<{ id: string; transports?: AuthenticatorTransportFuture[]; }>{
- id: key.id,
+ allowCredentials: keys.map(key => ({
+ id: Buffer.from(key.id, 'base64url'),
+ type: 'public-key',
transports: key.transports ?? undefined,
})),
userVerification: 'preferred',
@@ -164,86 +166,6 @@ export class WebAuthnService {
return authenticationOptions;
}
- /**
- * Initiate Passkey Auth (Without specifying user)
- * @returns authenticationOptions
- */
- @bindThis
- public async initiateSignInWithPasskeyAuthentication(context: string): Promise {
- const relyingParty = await this.getRelyingParty();
-
- const authenticationOptions = await generateAuthenticationOptions({
- rpID: relyingParty.rpId,
- userVerification: 'preferred',
- });
-
- await this.redisClient.setex(`webauthn:challenge:${context}`, 90, authenticationOptions.challenge);
-
- return authenticationOptions;
- }
-
- /**
- * Verify Webauthn AuthenticationCredential
- * @throws IdentifiableError
- * @returns If the challenge is successful, return the user ID. Otherwise, return null.
- */
- @bindThis
- public async verifySignInWithPasskeyAuthentication(context: string, response: AuthenticationResponseJSON): Promise {
- const challenge = await this.redisClient.get(`webauthn:challenge:${context}`);
-
- if (!challenge) {
- throw new IdentifiableError('2d16e51c-007b-4edd-afd2-f7dd02c947f6', `challenge '${context}' not found`);
- }
-
- await this.redisClient.del(`webauthn:challenge:${context}`);
-
- const key = await this.userSecurityKeysRepository.findOneBy({
- id: response.id,
- });
-
- if (!key) {
- throw new IdentifiableError('36b96a7d-b547-412d-aeed-2d611cdc8cdc', 'Unknown Webauthn key');
- }
-
- const relyingParty = await this.getRelyingParty();
-
- let verification;
- try {
- verification = await verifyAuthenticationResponse({
- response: response,
- expectedChallenge: challenge,
- expectedOrigin: relyingParty.origin,
- expectedRPID: relyingParty.rpId,
- authenticator: {
- credentialID: key.id,
- credentialPublicKey: Buffer.from(key.publicKey, 'base64url'),
- counter: key.counter,
- transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
- },
- requireUserVerification: true,
- });
- } catch (error) {
- throw new IdentifiableError('b18c89a7-5b5e-4cec-bb5b-0419f332d430', `verification failed: ${error}`);
- }
-
- const { verified, authenticationInfo } = verification;
-
- if (!verified) {
- return null;
- }
-
- await this.userSecurityKeysRepository.update({
- id: response.id,
- }, {
- lastUsed: new Date(),
- counter: authenticationInfo.newCounter,
- credentialDeviceType: authenticationInfo.credentialDeviceType,
- credentialBackedUp: authenticationInfo.credentialBackedUp,
- });
-
- return key.userId;
- }
-
@bindThis
public async verifyAuthentication(userId: MiUser['id'], response: AuthenticationResponseJSON): Promise {
const challenge = await this.redisClient.get(`webauthn:challenge:${userId}`);
@@ -269,7 +191,7 @@ export class WebAuthnService {
if (cert[0] === 0x04) { // 前の実装ではいつも 0x04 で始まっていた
const halfLength = (cert.length - 1) / 2;
- const cborMap = new Map();
+ const cborMap = new Map();
cborMap.set(1, 2); // kty, EC2
cborMap.set(3, -7); // alg, ES256
cborMap.set(-1, 1); // crv, P256
@@ -287,7 +209,7 @@ export class WebAuthnService {
}
}
- const relyingParty = this.getRelyingParty();
+ const relyingParty = await this.getRelyingParty();
let verification;
try {
@@ -297,7 +219,7 @@ export class WebAuthnService {
expectedOrigin: relyingParty.origin,
expectedRPID: relyingParty.rpId,
authenticator: {
- credentialID: key.id,
+ credentialID: Buffer.from(key.id, 'base64url'),
credentialPublicKey: Buffer.from(key.publicKey, 'base64url'),
counter: key.counter,
transports: key.transports ? key.transports as AuthenticatorTransportFuture[] : undefined,
diff --git a/packages/backend/src/core/WebfingerService.ts b/packages/backend/src/core/WebfingerService.ts
index f57e7a2c1f..374536a741 100644
--- a/packages/backend/src/core/WebfingerService.ts
+++ b/packages/backend/src/core/WebfingerService.ts
@@ -5,11 +5,9 @@
import { URL } from 'node:url';
import { Injectable } from '@nestjs/common';
-import { XMLParser } from 'fast-xml-parser';
+import { query as urlQuery } from '@/misc/prelude/url.js';
import { HttpRequestService } from '@/core/HttpRequestService.js';
import { bindThis } from '@/decorators.js';
-import type Logger from '@/logger.js';
-import { RemoteLoggerService } from './RemoteLoggerService.js';
export type ILink = {
href: string;
@@ -24,93 +22,34 @@ export type IWebFinger = {
const urlRegex = /^https?:\/\//;
const mRegex = /^([^@]+)@(.*)/;
-// we have the colons here, because URL.protocol does as well, so it's
-// more uniform in the places we use both
-const defaultProtocol = process.env.MISSKEY_WEBFINGER_USE_HTTP?.toLowerCase() === 'true' ? 'http:' : 'https:';
-
@Injectable()
export class WebfingerService {
- private logger: Logger;
-
constructor(
private httpRequestService: HttpRequestService,
- private remoteLoggerService: RemoteLoggerService,
) {
- this.logger = this.remoteLoggerService.logger.createSubLogger('webfinger');
}
@bindThis
public async webfinger(query: string): Promise {
- const hostMetaUrl = this.queryToHostMetaUrl(query);
- const template = await this.fetchWebFingerTemplateFromHostMeta(hostMetaUrl) ?? this.queryToWebFingerTemplate(query);
- const url = this.genUrl(query, template);
+ const url = this.genUrl(query);
return await this.httpRequestService.getJson