mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
Compare commits
153
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52b2f660e8 | ||
|
|
04a7ae55e7 | ||
|
|
5a33d462f6 | ||
|
|
cefa7b90ed | ||
|
|
0875a8a0bc | ||
|
|
5624e86c2b | ||
|
|
c622a9281f | ||
|
|
937d385241 | ||
|
|
3ec9bcf7e7 | ||
|
|
3dd5314062 | ||
|
|
d77823c5f4 | ||
|
|
41b48bd353 | ||
|
|
6225ece6be | ||
|
|
3f8805b953 | ||
|
|
6d68c0983f | ||
|
|
3ac0eb896c | ||
|
|
9c309e6da2 | ||
|
|
deaa57fa15 | ||
|
|
8053fec29f | ||
|
|
78aca7e5c0 | ||
|
|
728f8db7b9 | ||
|
|
4c14339b4b | ||
|
|
16ac2aae6b | ||
|
|
6d68d50699 | ||
|
|
400c571fe6 | ||
|
|
e57c15b3ce | ||
|
|
7cb7e881fa | ||
|
|
2cf82349a5 | ||
|
|
638bb55649 | ||
|
|
6d1b0eef15 | ||
|
|
03658b6a62 | ||
|
|
f998a8dca5 | ||
|
|
0d6bee3a5b | ||
|
|
7ce334aeb2 | ||
|
|
fe3a1b2058 | ||
|
|
662b73211a | ||
|
|
c453a03a02 | ||
|
|
05f8113bd0 | ||
|
|
63dfc3f636 | ||
|
|
c96a303d8a | ||
|
|
2d7e87a4cb | ||
|
|
fa421b4b83 | ||
|
|
79217e78b4 | ||
|
|
bdd808c279 | ||
|
|
986a7e6216 | ||
|
|
b54fcaa0b1 | ||
|
|
1cf782c298 | ||
|
|
fb1050e409 | ||
|
|
5c29a8c7dd | ||
|
|
09dead50d2 | ||
|
|
772e0ee220 | ||
|
|
86b0de3cee | ||
|
|
d174d96b74 | ||
|
|
1d193ed01b | ||
|
|
adf365d99d | ||
|
|
f3f48c3c6f | ||
|
|
e072f2237b | ||
|
|
306eee3a21 | ||
|
|
ca1d66d070 | ||
|
|
7e1400d111 | ||
|
|
7595e77170 | ||
|
|
08fcc61d35 | ||
|
|
b36801c5ed | ||
|
|
4ed1a1ae7f | ||
|
|
04db01cb55 | ||
|
|
8f5185de1c | ||
|
|
9f6db31785 | ||
|
|
a869086ce9 | ||
|
|
2af6a1b36f | ||
|
|
d4381f513f | ||
|
|
a281f13f15 | ||
|
|
a9641dadff | ||
|
|
c94dde9b47 | ||
|
|
976644d1e6 | ||
|
|
11fe90a69b | ||
|
|
1108086854 | ||
|
|
5aea892a39 | ||
|
|
3f3e6f5199 | ||
|
|
2efcd383bb | ||
|
|
faec9c2965 | ||
|
|
a0e8c7f924 | ||
|
|
6efdfdf17e | ||
|
|
aec268c6e9 | ||
|
|
2c096a85d6 | ||
|
|
240e5455cc | ||
|
|
c538a9ec6d | ||
|
|
72458f5c41 | ||
|
|
82e4eb7b40 | ||
|
|
c9bfc4e9b6 | ||
|
|
1ea96df00e | ||
|
|
75c5316dc3 | ||
|
|
4ee7623837 | ||
|
|
f65479ee15 | ||
|
|
a903e46be9 | ||
|
|
4497131206 | ||
|
|
4871abfb3a | ||
|
|
b0ed808745 | ||
|
|
169224560b | ||
|
|
106edc3a51 | ||
|
|
ede405c650 | ||
|
|
1dd1629884 | ||
|
|
0070c9877b | ||
|
|
eb208eed8b | ||
|
|
c37bf75853 | ||
|
|
7838008396 | ||
|
|
454c708fd6 | ||
|
|
3ffa78aa07 | ||
|
|
7dba9cbe54 | ||
|
|
716c4e9a21 | ||
|
|
f85a2d3ec1 | ||
|
|
d055dc68dc | ||
|
|
50a87ba933 | ||
|
|
6030cb560c | ||
|
|
c498230ebf | ||
|
|
4bbc5905e4 | ||
|
|
40f5db64d8 | ||
|
|
8d72a42be5 | ||
|
|
61c8cd75cd | ||
|
|
b46f6d0141 | ||
|
|
915d8c68bf | ||
|
|
21045142cd | ||
|
|
f171752109 | ||
|
|
82f00f961e | ||
|
|
b55b7fdc1c | ||
|
|
0b60060f65 | ||
|
|
b0f1266a8b | ||
|
|
863ff2e228 | ||
|
|
579aa5967f | ||
|
|
3bf5a6ebec | ||
|
|
ff222aa168 | ||
|
|
ea17534f77 | ||
|
|
b91d581928 | ||
|
|
4f6cb7f26c | ||
|
|
c1da3e7e95 | ||
|
|
040c568fdb | ||
|
|
7a78565c97 | ||
|
|
62e56eb27e | ||
|
|
8175120c4c | ||
|
|
6221fe5e08 | ||
|
|
4a8f882063 | ||
|
|
17db55a0bc | ||
|
|
a1d9268d00 | ||
|
|
14d227a1a3 | ||
|
|
3fd6ce1b6d | ||
|
|
7eb1b38cc7 | ||
|
|
2e9730ea1f | ||
|
|
a6cd4dfc0f | ||
|
|
0cf28c6392 | ||
|
|
7c2327ce16 | ||
|
|
099011a177 | ||
|
|
61d4a34f0f | ||
|
|
5b890dcd8a | ||
|
|
c2bd88377b |
@@ -1,6 +1,6 @@
|
||||
name: 👥 Bug with Modrinth Servers
|
||||
description: For issues with a Modrinth Servers product.
|
||||
labels: [servers]
|
||||
name: 👥 Bug with Modrinth Hosting
|
||||
description: For issues with a Modrinth Hosting product.
|
||||
labels: [hosting]
|
||||
type: 'bug'
|
||||
body:
|
||||
- type: checkboxes
|
||||
@@ -19,7 +19,7 @@ body:
|
||||
options:
|
||||
- Modrinth App
|
||||
- Modrinth.com website
|
||||
- Modrinth Servers
|
||||
- Modrinth Hosting
|
||||
- Modrinth API for developers
|
||||
- type: textarea
|
||||
attributes:
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
name: Deploy frontend
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- prod
|
||||
paths:
|
||||
- 'apps/frontend/**/*'
|
||||
- 'packages/ui/**/*'
|
||||
- 'packages/utils/**/*'
|
||||
- 'packages/assets/**/*'
|
||||
- '**/wrangler.jsonc'
|
||||
- '**/pnpm-*.yaml'
|
||||
- '.github/workflows/frontend-deploy.yml'
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
inputs:
|
||||
environment:
|
||||
required: true
|
||||
type: string
|
||||
description: 'The environment to deploy to (staging-preview or production-preview)'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure environment
|
||||
id: meta
|
||||
run: |
|
||||
echo "cmd=deploy" >> $GITHUB_OUTPUT
|
||||
|
||||
ENV_INPUT="${{ inputs.environment }}"
|
||||
REF="${{ github.ref }}"
|
||||
SHA_SHORT="${GITHUB_SHA::8}"
|
||||
|
||||
if [ "$ENV_INPUT" = "staging-preview" ]; then
|
||||
echo "env=staging" >> $GITHUB_OUTPUT
|
||||
echo "url=https://git-$SHA_SHORT-frontend-staging.modrinth.workers.dev" >> $GITHUB_OUTPUT
|
||||
echo "cmd=versions upload --preview-alias git-$SHA_SHORT --var PREVIEW:true" >> $GITHUB_OUTPUT
|
||||
|
||||
elif [ "$ENV_INPUT" = "production-preview" ]; then
|
||||
echo "env=production" >> $GITHUB_OUTPUT
|
||||
echo "url=https://git-$SHA_SHORT-frontend.modrinth.workers.dev" >> $GITHUB_OUTPUT
|
||||
echo "cmd=versions upload --preview-alias git-$SHA_SHORT --var PREVIEW:true" >> $GITHUB_OUTPUT
|
||||
|
||||
elif [ "$REF" = "refs/heads/main" ]; then
|
||||
echo "env=staging" >> $GITHUB_OUTPUT
|
||||
echo "url=https://staging.modrinth.com" >> $GITHUB_OUTPUT
|
||||
|
||||
else
|
||||
# Production env (no preview)
|
||||
echo "env=production" >> $GITHUB_OUTPUT
|
||||
echo "url=https://modrinth.com" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: .nvmrc
|
||||
cache: pnpm
|
||||
|
||||
- name: Inject build variables
|
||||
working-directory: ./apps/frontend
|
||||
run: |
|
||||
if [ "${{ steps.meta.outputs.env }}" == "staging" ]; then
|
||||
echo "Injecting staging variables from wrangler.jsonc..."
|
||||
jq -r '.env.staging.vars | to_entries[] | "\(.key)=\(.value)"' wrangler.jsonc >> $GITHUB_ENV
|
||||
else
|
||||
echo "Injecting production variables from wrangler.jsonc..."
|
||||
jq -r '.vars | to_entries[] | "\(.key)=\(.value)"' wrangler.jsonc >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Install dependencies
|
||||
working-directory: ./apps/frontend
|
||||
run: pnpm install
|
||||
|
||||
- name: Build frontend
|
||||
working-directory: ./apps/frontend
|
||||
run: pnpm build
|
||||
env:
|
||||
CF_PAGES_BRANCH: ${{ github.ref_name }}
|
||||
CF_PAGES_COMMIT_SHA: ${{ github.sha }}
|
||||
CF_PAGES_URL: ${{ steps.meta.outputs.url }}
|
||||
BUILD_ENV: ${{ steps.meta.outputs.env }}
|
||||
PREVIEW: ${{ inputs.environment != '' && 'true' || 'false' }}
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
|
||||
- name: Create Sentry release and upload sourcemaps
|
||||
uses: getsentry/action-release@v3
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: modrinth
|
||||
SENTRY_PROJECT: knossos-server
|
||||
with:
|
||||
environment: ${{ steps.meta.outputs.env }}
|
||||
sourcemaps: ./apps/frontend/.output/server
|
||||
url_prefix: '~/'
|
||||
|
||||
- name: Deploy Cloudflare Worker
|
||||
id: wrangler
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
environment: ${{ steps.meta.outputs.env != 'production' && steps.meta.outputs.env || '' }}
|
||||
workingDirectory: ./apps/frontend
|
||||
packageManager: pnpm
|
||||
wranglerVersion: '4.54.0'
|
||||
command: ${{ steps.meta.outputs.cmd }}
|
||||
|
||||
- name: Purge cache
|
||||
if: github.ref == 'refs/heads/prod'
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"hosts": ["modrinth.com", "www.modrinth.com", "staging.modrinth.com"]}' \
|
||||
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
||||
|
||||
- name: Write deployment URL to file
|
||||
if: ${{ inputs.environment != '' }}
|
||||
run: |
|
||||
echo "${{ steps.meta.outputs.url }}" > deployment-url-${{ inputs.environment }}.txt
|
||||
|
||||
- name: Upload deployment URL
|
||||
if: ${{ inputs.environment != '' }}
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: deployment-url-${{ inputs.environment }}
|
||||
path: deployment-url-${{ inputs.environment }}.txt
|
||||
@@ -1,30 +0,0 @@
|
||||
name: Clear pages cache
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- prod
|
||||
|
||||
jobs:
|
||||
wait:
|
||||
if: github.repository_owner == 'modrinth'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
deployments: write
|
||||
steps:
|
||||
- name: Cloudflare Pages deployment
|
||||
uses: WalshyDev/cf-pages-await@v1
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: '9ddae624c98677d68d93df6e524a6061'
|
||||
project: 'frontend'
|
||||
commitHash: ${{ steps.push-changes.outputs.commit-hash }}
|
||||
- name: Purge cache
|
||||
if: github.ref == 'refs/heads/prod'
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H "Authorization: Bearer ${{ secrets.CF_API_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
--data '{"hosts": ["modrinth.com", "www.modrinth.com"]}' \
|
||||
https://api.cloudflare.com/client/v4/zones/e39df17b9c4ef44cbce2646346ee6d33/purge_cache
|
||||
@@ -0,0 +1,72 @@
|
||||
name: Deploy frontend preview
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'apps/frontend/**/*'
|
||||
- 'packages/ui/**/*'
|
||||
- 'packages/utils/**/*'
|
||||
- 'packages/assets/**/*'
|
||||
- '**/wrangler.jsonc'
|
||||
- '**/pnpm-*.yaml'
|
||||
- '.github/workflows/frontend-preview.yml'
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: ./.github/workflows/frontend-deploy.yml
|
||||
secrets: inherit
|
||||
strategy:
|
||||
matrix:
|
||||
environment: [staging-preview, production-preview]
|
||||
with:
|
||||
environment: ${{ matrix.environment }}
|
||||
|
||||
comment:
|
||||
if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
steps:
|
||||
- name: Download deployment URLs
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
pattern: deployment-url-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Read deployment URLs
|
||||
id: urls
|
||||
run: |
|
||||
STAGING_PREVIEW_URL=$(cat deployment-url-staging-preview.txt)
|
||||
PRODUCTION_PREVIEW_URL=$(cat deployment-url-production-preview.txt)
|
||||
|
||||
echo "Production preview URL: $PRODUCTION_PREVIEW_URL"
|
||||
echo "Staging preview URL: $STAGING_PREVIEW_URL"
|
||||
|
||||
echo "staging-preview-url=$STAGING_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
echo "production-preview-url=$PRODUCTION_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Find comment
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: peter-evans/find-comment@v3
|
||||
id: fc
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Frontend previews
|
||||
|
||||
- name: Comment deploy URL on PR
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: peter-evans/create-or-update-comment@v5
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
body: |
|
||||
## Frontend previews
|
||||
|
||||
Last deployed commit is [${{ github.sha }}](${{ github.event.pull_request.head.repo.html_url }}/commit/${{ github.sha }})
|
||||
|
||||
| Environment | URL |
|
||||
|-------------|-----|
|
||||
| staging | ${{ steps.urls.outputs.staging-preview-url }} |
|
||||
| production | ${{ steps.urls.outputs.production-preview-url }} |
|
||||
edit-mode: replace
|
||||
@@ -70,19 +70,33 @@ jobs:
|
||||
- name: 🧰 Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: ⚙️ Set app environment
|
||||
working-directory: packages/app-lib
|
||||
run: cp .env.staging .env
|
||||
|
||||
# check if labrinth tests will actually run (cache miss)
|
||||
- name: 🔍 Check if labrinth tests need to run
|
||||
id: check-labrinth
|
||||
run: |
|
||||
LABRINTH_TEST_STATUS=$(pnpm turbo run test --filter=@modrinth/labrinth --dry-run=json | jq -r '.tasks[] | select(.task == "test") | .cache.status')
|
||||
echo "Labrinth test cache status: $LABRINTH_TEST_STATUS"
|
||||
if [ "$LABRINTH_TEST_STATUS" = "HIT" ]; then
|
||||
echo "needs_services=false" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "needs_services=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: ⚙️ Start services
|
||||
if: steps.check-labrinth.outputs.needs_services == 'true'
|
||||
run: docker compose up --wait
|
||||
|
||||
- name: ⚙️ Setup labrinth environment and database
|
||||
if: steps.check-labrinth.outputs.needs_services == 'true'
|
||||
working-directory: apps/labrinth
|
||||
run: |
|
||||
cp .env.local .env
|
||||
sqlx database setup
|
||||
|
||||
- name: ⚙️ Set app environment
|
||||
working-directory: packages/app-lib
|
||||
run: cp .env.staging .env
|
||||
|
||||
- name: 🔍 Lint and test
|
||||
run: pnpm run ci
|
||||
|
||||
|
||||
@@ -65,9 +65,15 @@ app-playground-data/*
|
||||
|
||||
.astro
|
||||
.claude
|
||||
.letta
|
||||
|
||||
# labrinth demo fixtures
|
||||
apps/labrinth/fixtures/demo
|
||||
|
||||
*storybook.log
|
||||
storybook-static
|
||||
|
||||
.wrangler/
|
||||
|
||||
# frontend robots.txt
|
||||
apps/frontend/src/public/robots.txt
|
||||
|
||||
Generated
+5
@@ -12,6 +12,11 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/app-lib/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/ariadne/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/path-util/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-log/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-maxmind/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-maxmind/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/modrinth-util/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/packages/muralpay/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
Vendored
+6
-6
@@ -11,21 +11,21 @@
|
||||
"source.fixAll.eslint": "explicit",
|
||||
"source.organizeImports": "always"
|
||||
},
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[scss]": {
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[css]": {
|
||||
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[rust]": {
|
||||
"editor.defaultFormatter": "rust-lang.rust-analyzer"
|
||||
|
||||
Generated
+593
-17
@@ -521,6 +521,22 @@ dependencies = [
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "astral-tokio-tar"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec179a06c1769b1e42e1e2cbe74c7dcdb3d6383c838454d063eaac5bbb7ebbe5"
|
||||
dependencies = [
|
||||
"filetime",
|
||||
"futures-core",
|
||||
"libc",
|
||||
"portable-atomic",
|
||||
"rustc-hash",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.2"
|
||||
@@ -671,6 +687,28 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stripe"
|
||||
version = "0.41.0"
|
||||
@@ -892,6 +930,49 @@ dependencies = [
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8"
|
||||
dependencies = [
|
||||
"axum-core",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"itoa",
|
||||
"matchit",
|
||||
"memchr",
|
||||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"serde_core",
|
||||
"sync_wrapper",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "axum-core"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"mime",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.76"
|
||||
@@ -1066,6 +1147,83 @@ dependencies = [
|
||||
"piper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bollard"
|
||||
version = "0.19.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87a52479c9237eb04047ddb94788c41ca0d26eaff8b697ecfbb4c32f7fdc3b1b"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"base64 0.22.1",
|
||||
"bitflags 2.9.4",
|
||||
"bollard-buildkit-proto",
|
||||
"bollard-stubs",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"home",
|
||||
"http 1.3.1",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper-named-pipe",
|
||||
"hyper-rustls 0.27.7",
|
||||
"hyper-util",
|
||||
"hyperlocal",
|
||||
"log",
|
||||
"num",
|
||||
"pin-project-lite",
|
||||
"rand 0.9.2",
|
||||
"rustls 0.23.32",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"serde_urlencoded",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"tonic 0.14.2",
|
||||
"tower-service",
|
||||
"url",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bollard-buildkit-proto"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85a885520bf6249ab931a764ffdb87b0ceef48e6e7d807cfdb21b751e086e1ad"
|
||||
dependencies = [
|
||||
"prost 0.14.3",
|
||||
"prost-types",
|
||||
"tonic 0.14.2",
|
||||
"tonic-prost",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bollard-stubs"
|
||||
version = "1.49.1-rc.28.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5731fe885755e92beff1950774068e0cae67ea6ec7587381536fca84f1779623"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"bollard-buildkit-proto",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"prost 0.14.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"serde_with",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "borsh"
|
||||
version = "1.5.7"
|
||||
@@ -2378,6 +2536,17 @@ dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "docker_credential"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d89dfcba45b4afad7450a99b39e751590463e45c04728cf555d36bb66940de8"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.11"
|
||||
@@ -2679,6 +2848,17 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "etcetera"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"home",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
@@ -3801,6 +3981,21 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-named-pipe"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"hyper 1.7.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-rustls"
|
||||
version = "0.24.2"
|
||||
@@ -3835,6 +4030,19 @@ dependencies = [
|
||||
"webpki-roots 1.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0"
|
||||
dependencies = [
|
||||
"hyper 1.7.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.6.0"
|
||||
@@ -3877,6 +4085,21 @@ dependencies = [
|
||||
"windows-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyperlocal"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.64"
|
||||
@@ -4523,6 +4746,7 @@ dependencies = [
|
||||
"const_format",
|
||||
"dashmap",
|
||||
"deadpool-redis",
|
||||
"derive_more 2.0.1",
|
||||
"dotenv-build",
|
||||
"dotenvy",
|
||||
"either",
|
||||
@@ -4558,7 +4782,6 @@ dependencies = [
|
||||
"rustls 0.23.32",
|
||||
"rusty-money",
|
||||
"sentry",
|
||||
"sentry-actix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
@@ -4566,6 +4789,7 @@ dependencies = [
|
||||
"sha2",
|
||||
"spdx",
|
||||
"sqlx",
|
||||
"sqlx-tracing",
|
||||
"strum",
|
||||
"thiserror 2.0.17",
|
||||
"tikv-jemalloc-ctl",
|
||||
@@ -4888,6 +5112,12 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
||||
|
||||
[[package]]
|
||||
name = "matchit"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||
|
||||
[[package]]
|
||||
name = "maxminddb"
|
||||
version = "0.26.0"
|
||||
@@ -5061,6 +5291,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"eyre",
|
||||
"sentry",
|
||||
"tracing",
|
||||
"tracing-ecs",
|
||||
"tracing-subscriber",
|
||||
@@ -5872,6 +6103,124 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf416e4cb72756655126f7dd7bb0af49c674f4c1b9903e80c009e0c37e552e6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"js-sys",
|
||||
"pin-project-lite",
|
||||
"thiserror 2.0.17",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-appender-tracing"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e68f63eca5fad47e570e00e893094fc17be959c80c79a7d6ec1abdd5ae6ffc16"
|
||||
dependencies = [
|
||||
"opentelemetry",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-http"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f6639e842a97dbea8886e3439710ae463120091e2e064518ba8e716e6ac36d"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bytes",
|
||||
"http 1.3.1",
|
||||
"opentelemetry",
|
||||
"reqwest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-otlp"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbee664a43e07615731afc539ca60c6d9f1a9425e25ca09c57bc36c87c55852b"
|
||||
dependencies = [
|
||||
"http 1.3.1",
|
||||
"opentelemetry",
|
||||
"opentelemetry-http",
|
||||
"opentelemetry-proto",
|
||||
"opentelemetry_sdk",
|
||||
"prost 0.13.5",
|
||||
"reqwest",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tonic 0.13.1",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e046fd7660710fe5a05e8748e70d9058dc15c94ba914e7c4faa7c728f0e8ddc"
|
||||
dependencies = [
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"prost 0.13.5",
|
||||
"tonic 0.13.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-semantic-conventions"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83d059a296a47436748557a353c5e6c5705b9470ef6c95cfc52c21a8814ddac2"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-testing"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562407eb254fea88076c8a410a733a8ee2075fd9c7fbde3da2a03d29e2cef104"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"opentelemetry",
|
||||
"opentelemetry-appender-tracing",
|
||||
"opentelemetry-otlp",
|
||||
"opentelemetry-semantic-conventions",
|
||||
"opentelemetry_sdk",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
"tempfile",
|
||||
"testcontainers",
|
||||
"tokio",
|
||||
"tracing-opentelemetry",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry_sdk"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11f644aa9e5e31d11896e024305d7e3c98a88884d9f8919dbf37a9991bc47a4b"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-executor",
|
||||
"futures-util",
|
||||
"opentelemetry",
|
||||
"percent-encoding",
|
||||
"rand 0.9.2",
|
||||
"serde_json",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
@@ -5996,6 +6345,31 @@ dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a"
|
||||
dependencies = [
|
||||
"parse-display-derive",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display-derive"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"structmeta",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-size"
|
||||
version = "1.1.0"
|
||||
@@ -6383,7 +6757,7 @@ dependencies = [
|
||||
"inferno",
|
||||
"num",
|
||||
"paste",
|
||||
"prost",
|
||||
"prost 0.13.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6589,7 +6963,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
"prost-derive 0.13.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6605,6 +6989,28 @@ dependencies = [
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7"
|
||||
dependencies = [
|
||||
"prost 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "protobuf"
|
||||
version = "3.7.2"
|
||||
@@ -7632,6 +8038,15 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scc"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc"
|
||||
dependencies = [
|
||||
"sdd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.28"
|
||||
@@ -7723,6 +8138,12 @@ dependencies = [
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdd"
|
||||
version = "3.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca"
|
||||
|
||||
[[package]]
|
||||
name = "seahash"
|
||||
version = "4.1.0"
|
||||
@@ -7846,19 +8267,6 @@ dependencies = [
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-actix"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc694e6ffc8d5d7fdb2a33923b0358f6ad41c0b428ced034b349b9e2b08260bc"
|
||||
dependencies = [
|
||||
"actix-http",
|
||||
"actix-web",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"sentry-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-backtrace"
|
||||
version = "0.45.0"
|
||||
@@ -8182,6 +8590,32 @@ dependencies = [
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d0b343e184fc3b7bb44dff0705fffcf4b3756ba6aff420dddd8b24ca145e555"
|
||||
dependencies = [
|
||||
"futures-executor",
|
||||
"futures-util",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"scc",
|
||||
"serial_test_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serial_test_derive"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f50427f258fb77356e4cd4aa0e87e2bd2c66dbcee41dc405282cae2bfc26c83"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serialize-to-javascript"
|
||||
version = "0.1.2"
|
||||
@@ -8588,7 +9022,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"crc",
|
||||
"dotenvy",
|
||||
"etcetera",
|
||||
"etcetera 0.8.0",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
@@ -8641,6 +9075,20 @@ dependencies = [
|
||||
"uuid 1.18.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-tracing"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"derive_more 2.0.1",
|
||||
"futures",
|
||||
"opentelemetry",
|
||||
"opentelemetry-testing",
|
||||
"sqlx",
|
||||
"testcontainers",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
@@ -9417,6 +9865,35 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "testcontainers"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f3ac71069f20ecfa60c396316c283fbf35e6833a53dff551a31b5458da05edc"
|
||||
dependencies = [
|
||||
"astral-tokio-tar",
|
||||
"async-trait",
|
||||
"bollard",
|
||||
"bytes",
|
||||
"docker_credential",
|
||||
"either",
|
||||
"etcetera 0.10.0",
|
||||
"futures",
|
||||
"log",
|
||||
"memchr",
|
||||
"parse-display",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"thiserror 2.0.17",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tokio-util",
|
||||
"ulid",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "theseus"
|
||||
version = "1.0.0-local"
|
||||
@@ -9454,6 +9931,7 @@ dependencies = [
|
||||
"notify",
|
||||
"notify-debouncer-mini",
|
||||
"p256",
|
||||
"parking_lot",
|
||||
"paste",
|
||||
"path-util",
|
||||
"phf 0.13.1",
|
||||
@@ -9882,6 +10360,72 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e581ba15a835f4d9ea06c55ab1bd4dce26fc53752c69a04aac00703bfb49ba9"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper-timeout",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost 0.13.5",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"h2 0.4.12",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper 1.7.0",
|
||||
"hyper-timeout",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"socket2 0.6.1",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic-prost"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost 0.14.3",
|
||||
"tonic 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "totp-rs"
|
||||
version = "5.7.0"
|
||||
@@ -9904,11 +10448,15 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap 2.11.4",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10024,6 +10572,24 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-opentelemetry"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddcf5959f39507d0d04d6413119c04f33b623f4f951ebcbdddddfad2d0623a9c"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"once_cell",
|
||||
"opentelemetry",
|
||||
"opentelemetry_sdk",
|
||||
"smallvec",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
"tracing-subscriber",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.20"
|
||||
@@ -10119,6 +10685,16 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ulid"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe"
|
||||
dependencies = [
|
||||
"rand 0.9.2",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uname"
|
||||
version = "0.1.1"
|
||||
|
||||
+4
-2
@@ -116,6 +116,7 @@ native-dialog = "0.9.2"
|
||||
notify = { version = "8.2.0", default-features = false }
|
||||
notify-debouncer-mini = { version = "0.7.0", default-features = false }
|
||||
p256 = "0.13.2"
|
||||
parking_lot = "0.12.5"
|
||||
paste = "1.0.15"
|
||||
path-util = { path = "packages/path-util" }
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
@@ -150,7 +151,6 @@ sentry = { version = "0.45.0", default-features = false, features = [
|
||||
"reqwest",
|
||||
"rustls",
|
||||
] }
|
||||
sentry-actix = "0.45.0"
|
||||
serde = "1.0.228"
|
||||
serde_bytes = "0.11.19"
|
||||
serde_cbor = "0.11.2"
|
||||
@@ -164,6 +164,7 @@ sha2 = "0.10.9"
|
||||
shlex = "1.3.0"
|
||||
spdx = "0.12.0"
|
||||
sqlx = { version = "0.8.6", default-features = false }
|
||||
sqlx-tracing = { path = "packages/sqlx-tracing" }
|
||||
strum = "0.27.2"
|
||||
sysinfo = { version = "0.37.2", default-features = false }
|
||||
tar = "0.4.44"
|
||||
@@ -239,7 +240,7 @@ manual_assert = "warn"
|
||||
manual_instant_elapsed = "warn"
|
||||
manual_is_variant_and = "warn"
|
||||
manual_let_else = "warn"
|
||||
map_unwrap_or = "warn"
|
||||
map_unwrap_or = "allow"
|
||||
match_bool = "warn"
|
||||
needless_collect = "warn"
|
||||
negative_feature_names = "warn"
|
||||
@@ -269,4 +270,5 @@ codegen-units = 1 # Compile crates one after another so the compiler can optimi
|
||||
# Specific profile for labrinth production builds
|
||||
[profile.release-labrinth]
|
||||
inherits = "release"
|
||||
strip = false # Keep debug symbols for Sentry
|
||||
panic = "unwind" # Don't exit the whole app on panic in production
|
||||
|
||||
@@ -71,6 +71,7 @@ import PromotionWrapper from '@/components/ui/PromotionWrapper.vue'
|
||||
import QuickInstanceSwitcher from '@/components/ui/QuickInstanceSwitcher.vue'
|
||||
import RunningAppBar from '@/components/ui/RunningAppBar.vue'
|
||||
import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
import UpdateAvailableToast from '@/components/ui/UpdateAvailableToast.vue'
|
||||
import UpdateToast from '@/components/ui/UpdateToast.vue'
|
||||
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
|
||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||
@@ -143,6 +144,7 @@ const showOnboarding = ref(false)
|
||||
const nativeDecorations = ref(false)
|
||||
|
||||
const os = ref('')
|
||||
const isDevEnvironment = ref(false)
|
||||
|
||||
const stateInitialized = ref(false)
|
||||
|
||||
@@ -221,7 +223,6 @@ const messages = defineMessages({
|
||||
})
|
||||
|
||||
async function setupApp() {
|
||||
stateInitialized.value = true
|
||||
const {
|
||||
native_decorations,
|
||||
theme,
|
||||
@@ -248,6 +249,7 @@ async function setupApp() {
|
||||
|
||||
os.value = await getOS()
|
||||
const dev = await isDev()
|
||||
isDevEnvironment.value = dev
|
||||
const version = await getVersion()
|
||||
showOnboarding.value = !onboarded
|
||||
|
||||
@@ -260,6 +262,7 @@ async function setupApp() {
|
||||
themeStore.toggleSidebar = toggle_sidebar
|
||||
themeStore.devMode = developer_mode
|
||||
themeStore.featureFlags = feature_flags
|
||||
stateInitialized.value = true
|
||||
|
||||
isMaximized.value = await getCurrentWindow().isMaximized()
|
||||
|
||||
@@ -505,21 +508,23 @@ const restarting = ref(false)
|
||||
const updateToastDismissed = ref(false)
|
||||
const availableUpdate = ref(null)
|
||||
const updateSize = ref(null)
|
||||
const updatesEnabled = ref(true)
|
||||
async function checkUpdates() {
|
||||
if (!(await areUpdatesEnabled())) {
|
||||
console.log('Skipping update check as updates are disabled in this build or environment')
|
||||
updatesEnabled.value = false
|
||||
return
|
||||
}
|
||||
|
||||
async function performCheck() {
|
||||
const update = await invoke('plugin:updater|check')
|
||||
const isExistingUpdate = update.version === availableUpdate.value?.version
|
||||
|
||||
if (!update) {
|
||||
console.log('No update available')
|
||||
return
|
||||
}
|
||||
|
||||
const isExistingUpdate = update.version === availableUpdate.value?.version
|
||||
|
||||
if (isExistingUpdate) {
|
||||
console.log('Update is already known')
|
||||
return
|
||||
@@ -769,6 +774,7 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
@restart="installUpdate"
|
||||
@download="downloadAvailableUpdate"
|
||||
/>
|
||||
<UpdateAvailableToast v-else-if="!updatesEnabled && os === 'Linux' && !isDevEnvironment" />
|
||||
</Transition>
|
||||
</Suspense>
|
||||
<Transition name="fade">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { GameIcon, LeftArrowIcon } from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled } from '@modrinth/ui'
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
import { Avatar, ButtonStyled, FormattedTag } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
|
||||
type Instance = {
|
||||
@@ -37,7 +36,8 @@ defineProps<{
|
||||
</span>
|
||||
<span class="text-secondary flex items-center gap-2 font-semibold">
|
||||
<GameIcon class="h-5 w-5 text-secondary" />
|
||||
{{ formatCategory(instance.loader) }} {{ instance.game_version }}
|
||||
<FormattedTag :tag="instance.loader" enforce-type="loader" />
|
||||
{{ instance.game_version }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import { DownloadIcon, HeartIcon, TagIcon } from '@modrinth/assets'
|
||||
import { Avatar, TagItem } from '@modrinth/ui'
|
||||
import { formatCategory, formatNumber } from '@modrinth/utils'
|
||||
import { Avatar, FormattedTag, TagItem } from '@modrinth/ui'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { computed } from 'vue'
|
||||
@@ -107,7 +107,7 @@ const toTransparent = computed(() => {
|
||||
<div class="flex items-center gap-1 pr-2">
|
||||
<TagIcon />
|
||||
<TagItem>
|
||||
{{ formatCategory(featuredCategory) }}
|
||||
<FormattedTag :tag="featuredCategory" />
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
:key="tag"
|
||||
class="text-sm font-semibold text-secondary flex gap-1 px-[0.375rem] py-0.5 bg-button-bg rounded-full"
|
||||
>
|
||||
{{ formatCategory(tag.name) }}
|
||||
<FormattedTag :tag="tag.name" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -118,8 +118,8 @@
|
||||
|
||||
<script setup>
|
||||
import { CheckIcon, DownloadIcon, HeartIcon, PlusIcon, TagsIcon } from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import { formatCategory, formatNumber } from '@modrinth/utils'
|
||||
import { Avatar, ButtonStyled, FormattedTag, injectNotificationManager } from '@modrinth/ui'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const dismissed = ref(false)
|
||||
const availableUpdate = ref<{ version: string } | null>(null)
|
||||
|
||||
let checkInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
async function checkForUpdate() {
|
||||
try {
|
||||
const [response, currentVersion] = await Promise.all([
|
||||
fetch('https://launcher-files.modrinth.com/updates.json'),
|
||||
getVersion(),
|
||||
])
|
||||
const updates = await response.json()
|
||||
const latestVersion = updates?.version
|
||||
|
||||
if (latestVersion && latestVersion !== currentVersion) {
|
||||
if (latestVersion !== availableUpdate.value?.version) {
|
||||
availableUpdate.value = { version: latestVersion }
|
||||
dismissed.value = false
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to check for updates:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
dismissed.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkForUpdate()
|
||||
checkInterval = setInterval(checkForUpdate, 5 * 60 * 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (checkInterval) {
|
||||
clearInterval(checkInterval)
|
||||
}
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.update-toast.title',
|
||||
defaultMessage: 'Update available',
|
||||
},
|
||||
body: {
|
||||
id: 'app.update-toast.body.linux',
|
||||
defaultMessage:
|
||||
'Modrinth App v{version} is available. Use your package manager to update for the latest features and fixes!',
|
||||
},
|
||||
download: {
|
||||
id: 'app.update-toast.download-page',
|
||||
defaultMessage: 'Download',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
v-if="availableUpdate && !dismissed"
|
||||
class="grid grid-cols-[min-content] fixed card-shadow rounded-2xl top-[--top-bar-height] mt-6 right-6 p-4 z-10 bg-bg-raised border-divider border-solid border-[2px]"
|
||||
>
|
||||
<div class="flex min-w-[25rem] gap-4">
|
||||
<h2 class="whitespace-nowrap text-base text-contrast font-semibold m-0 grow">
|
||||
{{ formatMessage(messages.title) }}
|
||||
</h2>
|
||||
<ButtonStyled size="small" circular>
|
||||
<button v-tooltip="formatMessage(commonMessages.closeButton)" @click="dismiss">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<p class="text-sm mt-2 mb-0">
|
||||
{{ formatMessage(messages.body, { version: availableUpdate.version }) }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -159,20 +159,21 @@ const reset_icon = () => {
|
||||
const createInstance = async () => {
|
||||
creatingInstance.value = true
|
||||
|
||||
const loader =
|
||||
versions.value[0].loaders[0] !== 'forge' &&
|
||||
versions.value[0].loaders[0] !== 'fabric' &&
|
||||
versions.value[0].loaders[0] !== 'quilt'
|
||||
? 'vanilla'
|
||||
: versions.value[0].loaders[0]
|
||||
const gameVersions = versions.value[0].game_versions
|
||||
const gameVersion = gameVersions[0]
|
||||
|
||||
const id = await create(
|
||||
name.value,
|
||||
versions.value[0].game_versions[0],
|
||||
loader,
|
||||
'latest',
|
||||
icon.value,
|
||||
).catch(handleError)
|
||||
const loaders = versions.value[0].loaders
|
||||
const loader = loaders.contains('fabric')
|
||||
? 'fabric'
|
||||
: loaders.contains('neoforge')
|
||||
? 'neoforge'
|
||||
: loaders.contains('forge')
|
||||
? 'forge'
|
||||
: loaders.contains('quilt')
|
||||
? 'quilt'
|
||||
: 'vanilla'
|
||||
|
||||
const id = await create(name.value, gameVersion, loader, 'latest', icon.value).catch(handleError)
|
||||
|
||||
await installMod(id, versions.value[0].id).catch(handleError)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
DownloadIcon,
|
||||
getLoaderIcon,
|
||||
HammerIcon,
|
||||
IssuesIcon,
|
||||
SpinnerIcon,
|
||||
@@ -17,16 +18,11 @@ import {
|
||||
Chips,
|
||||
Combobox,
|
||||
defineMessages,
|
||||
getTagMessageOrDefault,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import {
|
||||
formatCategory,
|
||||
type GameVersionTag,
|
||||
type PlatformTag,
|
||||
type Project,
|
||||
type Version,
|
||||
} from '@modrinth/utils'
|
||||
import type { GameVersionTag, PlatformTag, Project, Version } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, type ComputedRef, type Ref, ref, shallowRef, watch } from 'vue'
|
||||
|
||||
@@ -129,9 +125,7 @@ if (props.instance.linked_data && props.instance.linked_data.project_id && !prop
|
||||
fetching.value = false
|
||||
}
|
||||
|
||||
const currentLoaderIcon = computed(
|
||||
() => loaders?.value.find((x) => x.name === props.instance.loader)?.icon,
|
||||
)
|
||||
const currentLoaderIcon = computed(() => getLoaderIcon(props.instance.loader))
|
||||
|
||||
const gameVersionsForLoader = computed(() => {
|
||||
return all_game_versions?.value.filter((item) => {
|
||||
@@ -550,7 +544,7 @@ const messages = defineMessages({
|
||||
v-else
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full bg-button-bg border-solid border-[1px] border-button-border p-2 [&_svg]:h-full [&_svg]:w-full"
|
||||
>
|
||||
<div v-if="!!currentLoaderIcon" class="contents" v-html="currentLoaderIcon" />
|
||||
<component :is="currentLoaderIcon" v-if="currentLoaderIcon" />
|
||||
<WrenchIcon v-else />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 justify-center">
|
||||
@@ -569,7 +563,10 @@ const messages = defineMessages({
|
||||
? modpackVersion
|
||||
? modpackVersion?.version_number
|
||||
: 'Unknown version'
|
||||
: formatCategory(instance.loader)
|
||||
: (() => {
|
||||
const message = getTagMessageOrDefault(instance.loader, 'loader')
|
||||
return typeof message === 'string' ? message : formatMessage(message)
|
||||
})()
|
||||
}}
|
||||
<template v-if="instance.loader !== 'vanilla' && !modpackProject">
|
||||
{{ instance.loader_version || formatMessage(messages.unknownVersion) }}
|
||||
@@ -677,7 +674,14 @@ const messages = defineMessages({
|
||||
</div>
|
||||
<template v-if="loader !== 'vanilla'">
|
||||
<h2 class="m-0 mt-4 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.loaderVersion, { loader: formatCategory(loader) }) }}
|
||||
{{
|
||||
formatMessage(messages.loaderVersion, {
|
||||
loader: (() => {
|
||||
const message = getTagMessageOrDefault(loader, 'loader')
|
||||
return typeof message === 'string' ? message : formatMessage(message)
|
||||
})(),
|
||||
})
|
||||
}}
|
||||
</h2>
|
||||
<Combobox
|
||||
v-if="selectableLoaderVersions"
|
||||
@@ -709,7 +713,10 @@ const messages = defineMessages({
|
||||
? messages.alreadyInstalledVanilla
|
||||
: messages.alreadyInstalledModded,
|
||||
{
|
||||
platform: formatCategory(loader),
|
||||
platform: (() => {
|
||||
const message = getTagMessageOrDefault(loader, 'loader')
|
||||
return typeof message === 'string' ? message : formatMessage(message)
|
||||
})(),
|
||||
version: instance.loader_version,
|
||||
game_version: gameVersion,
|
||||
},
|
||||
|
||||
@@ -7,7 +7,14 @@ import {
|
||||
MonitorIcon,
|
||||
WrenchIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, defineMessage, TabbedModal, type TabbedModalTab, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
commonMessages,
|
||||
defineMessage,
|
||||
TabbedModal,
|
||||
type TabbedModalTab,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -74,11 +81,6 @@ function show() {
|
||||
}
|
||||
|
||||
defineExpose({ show })
|
||||
|
||||
const titleMessage = defineMessage({
|
||||
id: 'instance.settings.title',
|
||||
defaultMessage: 'Settings',
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
@@ -90,7 +92,9 @@ const titleMessage = defineMessage({
|
||||
:tint-by="props.instance.path"
|
||||
/>
|
||||
{{ instance.name }} <ChevronRightIcon />
|
||||
<span class="font-extrabold text-contrast">{{ formatMessage(titleMessage) }}</span>
|
||||
<span class="font-extrabold text-contrast">{{
|
||||
formatMessage(commonMessages.settingsLabel)
|
||||
}}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "قد تكون خوادم مصادقة ماينكرافت معطلة حاليًا. تحقق من اتصالك بالإنترنت وحاول مرة أخرى لاحقًا."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "تعذر الوصول إلى خوادم المصادقة"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "تم تفعيل وضع المطوّر."
|
||||
},
|
||||
@@ -17,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "تثبيتات جافا"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "اللغة"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "الخصوصية"
|
||||
},
|
||||
@@ -78,7 +87,7 @@
|
||||
"message": "جار إضافة صديق"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "قد يختلف عن اسم المستخدم الخاص بهم في Minecraft!"
|
||||
"message": "قد يختلف عن اسم المستخدم الخاص بهم في ماينكرافت!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "أدخل اسم مستخدم Modrinth..."
|
||||
@@ -132,7 +141,7 @@
|
||||
"message": "إضافة واللعب"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "إضافة الخادم"
|
||||
"message": "إضافة خادم"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "معطَّل"
|
||||
@@ -177,7 +186,7 @@
|
||||
"message": "الاسم"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "خادم ماين كرافت"
|
||||
"message": "خادم ماينكرافت"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "حزمة الموارد"
|
||||
@@ -270,7 +279,7 @@
|
||||
"message": "مُغلِّف"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "أمر غلاف لتشغيل ماين كرافت."
|
||||
"message": "أمر غلاف لتشغيل ماينكرافت."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "أدخل أمر الغلاف..."
|
||||
@@ -279,7 +288,7 @@
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} لماين كرافت {game_version} مثبت بالفعل"
|
||||
"message": "{platform} {version} لماينكرافت {game_version} مثبت بالفعل"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "فانيلا {game_version} مُثبّتة بالفعل"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalace Javy"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Jazyk"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Soukromí"
|
||||
},
|
||||
@@ -72,7 +75,10 @@
|
||||
"message": "Restartovat aplikaci pro nainstalování aktualizace"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Přidat kamaráda"
|
||||
"message": "Přidat přítele"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {žádost} few {žádosti} other {žádostí}} o přátelství"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Poslat žádost o přátelství"
|
||||
@@ -80,9 +86,27 @@
|
||||
"friends.add-friend.title": {
|
||||
"message": "Přidávání kamaráda"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Může být jiné než jejich Minecraft jméno!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Zadejte uživatelské jméno Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Jak se váš kamarád jmenuje na Modrinthu?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Přidejte si přátelé</link> a podívejte se, co hrají!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Zrušit žádost"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Odebrat přítele"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Žádost o přátelství odeslána"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Zobrazit profil"
|
||||
},
|
||||
@@ -98,9 +122,21 @@
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Čeká na vyřízení"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Žádní přátelé neodpovídají '{query}''"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Hledat přátele..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Přihlašte se ke svému Modrinth účtu</link>, abyste jsi přidali přátele a uviděli co hrají!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Přidat a hrát"
|
||||
},
|
||||
@@ -114,7 +150,7 @@
|
||||
"message": "Zapnuto"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Dotázat se"
|
||||
"message": "Ptát se"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Přidat server"
|
||||
@@ -207,7 +243,7 @@
|
||||
"message": "Zadejte název skupiny"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Jméno"
|
||||
"message": "Název"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Spouštěcí hooky"
|
||||
@@ -264,7 +300,7 @@
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Probíhá nstalace"
|
||||
"message": "Instalování"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Načítání verzí modpacku"
|
||||
@@ -348,7 +384,7 @@
|
||||
"message": "Ukázat všechny verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Změnit verzi"
|
||||
"message": "změnit verzi"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Instalovat"
|
||||
@@ -468,7 +504,7 @@
|
||||
"message": "Můžeš rovnou skočit na server pouze v Minecraftu Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Můžeš rovnou skočit do světa jednoho hráče pouze v Minecraftu 1.20+"
|
||||
"message": "Můžeš se rovnou připojit do světa jednoho hráče pouze v Minecraftu 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Hrát instanci"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft autentificeringsservere kan måske være nede lige nu. Tjek din internet forbindelse og prøv igen senere."
|
||||
"message": "Minecraft authentication servere kan måske være nede lige nu. Tjek din internet forbindelse og prøv igen senere."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Kan ikke nå autentificeringsservere"
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Javainstallationer"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Sprog"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privatliv"
|
||||
},
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java Installationen"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Sprache"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Datenschutz"
|
||||
},
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java-Installationen"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Sprache"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Datenschutz"
|
||||
},
|
||||
@@ -69,7 +72,7 @@
|
||||
"message": "Update wird heruntergeladen ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Neu laden um Update zu installieren"
|
||||
"message": "Neu laden, um das Update zu installieren"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Freund hinzufügen"
|
||||
@@ -78,7 +81,7 @@
|
||||
"message": "{count} {count, plural, one {Freundesanfrage} other {Freundesanfragen}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Freundesanfrage senden"
|
||||
"message": "Freundschaftsanfrage senden"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Einen Freund hinzufügen"
|
||||
@@ -102,7 +105,7 @@
|
||||
"message": "Freund entfernen"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Freundesanfrage gesendet"
|
||||
"message": "Freundschaftsanfrage gesendet"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Profil anzeigen"
|
||||
@@ -156,7 +159,7 @@
|
||||
"message": "Server bearbeiten"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Von Startseite verbergen"
|
||||
"message": "Von der Startseite verbergen"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Name"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Löscht eine Instanz dauerhaft von deinem Gerät, einschließlich deiner Welten, Einstellungen und aller installierten Inhalte. Sei vorsichtig, da eine gelöschte Instanz nicht wiederhergestellt werden kann."
|
||||
"message": "Löscht eine Instanz dauerhaft von deinem Gerät, einschließlich deiner Welten, Einstellungen und aller installierten Inhalte. Sei vorsichtig, eine gelöschte Instanz ist nicht wiederherstellbar."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Wird gelöscht..."
|
||||
@@ -207,13 +210,13 @@
|
||||
"message": "Kopieren"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Kann während der Installation nicht kopiert werden."
|
||||
"message": "Kann während der Installation nicht dupliziert werden."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Instanz duplizieren"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Erstellt eine Kopie dieser Instanz, inklusive aller Welten, Einstellungen, Modifikationen, usw."
|
||||
"message": "Erstellt eine Kopie dieser Instanz, inklusive aller Welten, Einstellungen, Mods, usw."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Icon bearbeiten"
|
||||
@@ -243,10 +246,10 @@
|
||||
"message": "Name"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Start Hooks"
|
||||
"message": "Startargumente"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Benutzerdefinierte Start Hooks"
|
||||
"message": "Benutzerdefinierte Startargumente"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Hooks ermöglichen es fortgeschrittenen Benutzern, bestimmte Systembefehle vor und nach dem Spielstart auszuführen."
|
||||
@@ -267,7 +270,7 @@
|
||||
"message": "Wird vor dem Starten der Instanz ausgeführt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Vor Spielstart auszuführender Befehl eingeben..."
|
||||
"message": "Vor Spielstart auszuführenden Befehl eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Start-Hooks"
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} has finished downloading. Reload to update now, or automatically when you close Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} is available. Use your package manager to update for the latest features and fixes!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} is available now! Since you're on a metered network, we didn't automatically download it."
|
||||
},
|
||||
@@ -47,6 +50,9 @@
|
||||
"app.update-toast.download": {
|
||||
"message": "Download ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Download"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Downloading..."
|
||||
},
|
||||
@@ -470,9 +476,6 @@
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Enter width..."
|
||||
},
|
||||
"instance.settings.title": {
|
||||
"message": "Settings"
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "A Minecraft Server"
|
||||
},
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalaciones de Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Idioma"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacidad"
|
||||
},
|
||||
@@ -30,13 +33,13 @@
|
||||
"message": "Gestión de recursos"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "¡La aplicación Modrinth v{version} está lista para instalarse! Actualiza ahora o automáticamente al cerrar la aplicación Modrinth."
|
||||
"message": "¡Modrinth App v{version} lista para instalar! Actualiza ahora o automáticamente al cerrar la aplicación."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "La descarga de la aplicación Modrinth v{version} ha finalizado. Actualice ahora o automáticamente al cerrar la aplicación Modrinth."
|
||||
"message": "La descarga de la Modrinth App v{version} ha finalizado. Actualiza ahora o automáticamente al cerrar la aplicación Modrinth."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "¡La aplicación Modrinth v{version} ya está disponible! Como estás conectado a una red con límite de datos, no la hemos descargado automáticamente."
|
||||
"message": "¡Modrinth App v{version} ya está disponible! Como estás en una red con límite de datos, no se descargó automáticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Registro de cambios"
|
||||
@@ -57,7 +60,7 @@
|
||||
"message": "Descarga completada"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Haga clic aquí para ver el registro de cambios."
|
||||
"message": "Haz clic aquí para ver el registro de cambios."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "¡La versión {version} se ha instalado correctamente!"
|
||||
@@ -84,10 +87,10 @@
|
||||
"message": "Añadiendo un amigo"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "¡Podría ser distinto a su nombre de Minecraft!"
|
||||
"message": "¡Podría ser distinto a su nombre de usuario de Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Escribe el nombre de usuario de Modrinth..."
|
||||
"message": "Ingresa tu nombre de usuario de Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "¿Cuál es el nombre de usuario de Modrinth de tu amigo?"
|
||||
@@ -165,7 +168,7 @@
|
||||
"message": "Mundo de Minecraft"
|
||||
},
|
||||
"instance.edit-world.reset-icon": {
|
||||
"message": "Resetear ícono"
|
||||
"message": "Restablecer ícono"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Editar mundo"
|
||||
@@ -186,7 +189,7 @@
|
||||
"message": "Servidor de Minecraft"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Resource pack"
|
||||
"message": "Paquete de recursos"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "General"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Elimina permanentemente una instancia de tu dispositivo, incluyendo tus mundos, configuraciones y todo el contenido instalado. Ten cuidado, ya que una vez que elimines una instancia no hay forma de recuperarla."
|
||||
"message": "Elimina permanentemente una instancia de tu dispositivo, incluidos tus mundos, configuraciones y todo el contenido instalado. Ten cuidado, una vez eliminada, no hay forma de recuperarla."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Eliminando..."
|
||||
@@ -219,7 +222,7 @@
|
||||
"message": "Editar ícono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Remover ícono"
|
||||
"message": "Eliminar ícono"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Reemplazar ícono"
|
||||
@@ -237,16 +240,16 @@
|
||||
"message": "Los grupos de la librería te ayudan a organizar tus instancias en diferentes secciones en tu librería."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Escribe el nombre del grupo"
|
||||
"message": "Ingresa el nombre del grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Nombre"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Lanzar hooks"
|
||||
"message": "Hooks de inicio"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Perfiles personalizados"
|
||||
"message": "Hooks de inicio personalizados"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Los hooks permiten que usuarios avanzados ejecuten comandos del sistema antes y despues de lanzar el juego."
|
||||
@@ -255,7 +258,7 @@
|
||||
"message": "Post-cierre"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Ejecutados luego de que el juego se cierra."
|
||||
"message": "Ejecutados después de que el juego se cierre."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Introduce el comando post-cierre..."
|
||||
@@ -267,19 +270,19 @@
|
||||
"message": "Ejecutados antes de que la instancia inicie."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Introducir comando pre-inicio..."
|
||||
"message": "Introduce el comando pre-inicio..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Hooks de inicio de juego"
|
||||
"message": "Hooks de inicio del juego"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Comando de capa para lanzar Minecraft."
|
||||
"message": "Comando Wrapper para iniciar Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Introduce el comando capa..."
|
||||
"message": "Introduce el comando Wrapper..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instalación"
|
||||
@@ -288,7 +291,7 @@
|
||||
"message": "{platform} {version} ya está instalado para Minecraft {game_version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "{game_version} vanilla ya está instalado"
|
||||
"message": "Vanilla {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Cambiar versión"
|
||||
@@ -333,7 +336,7 @@
|
||||
"message": "No se pueden obtener los detalles del modpack vinculado. Por favor, verifica tu conexión a internet."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} no esta disponible para Minecraft {version}. Prueba con otro mod loader."
|
||||
"message": "{loader} no está disponible para Minecraft {version}. Prueba con otro mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Esta instancia está vinculada a un modpack, pero no se pudo encontrar el modpack en Modrinth."
|
||||
@@ -348,13 +351,13 @@
|
||||
"message": "Reinstalando modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Reinstalar restablecerá todo el contenido instalado o modificado a lo que proporciona el modpack, eliminando cualquier mod o contenido que hayas agregado encima de la instalación original. Esto puede solucionar comportamientos inesperados si se han hecho cambios en la instancia, pero si tus mundos dependen de contenido adicional instalado, podría afectar los mundos existentes."
|
||||
"message": "La reinstalación restablecerá todo el contenido instalado o modificado a lo que proporciona el modpack, eliminando cualquier mod o contenido que hayas agregado sobre la instalación original. Esto puede solucionar comportamientos inesperados si se han hecho cambios en la instancia, pero si tus mundos dependen de contenido adicional instalado, podría romper los mundos existentes."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres reinstalar esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Restablece el contenido de la instancia a su estado original, eliminando cualquier mod o contenido que hayas agregado encima del modpack original."
|
||||
"message": "Restablece el contenido de la instancia a su estado original, eliminando cualquier mod o contenido que hayas agregado sobre el modpack original."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstalar modpack"
|
||||
@@ -366,7 +369,7 @@
|
||||
"message": "Reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparar reinstala las dependencias de Minecraft y verifica si hay archivos dañados. Esto puede solucionar problemas si tu juego no se inicia por errores relacionados con el launcher, pero no resolverá problemas causados por mods instalados."
|
||||
"message": "Reparar reinstala las dependencias de Minecraft y verifica la integridad de los archivos. Esto puede solucionar problemas si tu juego no se inicia por errores relacionados con el launcher, pero no resolverá problemas debidos a mods instalados."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "¿Reparar instancia?"
|
||||
@@ -408,13 +411,13 @@
|
||||
"message": "Desvincular instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Si continúas, no podrás volver a vincularla sin crear una instancia completamente nueva. Ya no recibirás actualizaciones del modpack y se convertirá en una instancia normal."
|
||||
"message": "Si continúas, no podrás volver a vincularla sin crear una nueva instancia. Ya no recibirás actualizaciones del modpack y pasará a ser una instancia normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres desvincular esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Esta instancia está vinculada a un modpack, lo que significa que los mods no se pueden actualizar y no puedes cambiar el mod loader ni la versión de Minecraft. Desvincularla desconectará permanentemente esta instancia del modpack."
|
||||
"message": "Esta instancia está vinculada a un modpack, lo que significa que los mods no pueden actualizarse y no puedes cambiar el mod loader ni la versión de Minecraft. Desvincularla la desconectará permanentemente del modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Desvincular del modpack"
|
||||
@@ -441,13 +444,13 @@
|
||||
"message": "Ventana"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Opciones personalizadas de ventana"
|
||||
"message": "Configuración de ventana personalizada"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Pantalla completa"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Inicia el juego en pantalla completa al ejecutarlo (usando options.txt)."
|
||||
"message": "Inicia el juego en pantalla completa al iniciarlo (usando options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Altura"
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Los servidores de autenticación de Minecraft podrían estar inactivos. Comprueba tu conexión a internet e inténtalo más tarde."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": ""
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
},
|
||||
@@ -17,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalaciones de Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Idioma"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacidad"
|
||||
},
|
||||
@@ -30,7 +39,7 @@
|
||||
"message": "La descarga de la versión v{version} de Modrinth ha finalizado. Actualice ahora o automáticamente al cerrar la aplicación."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "¡La versión v{version} de Modrinth ya está disponible! Como estás conectado a una red con límite de datos, no la hemos descargado automáticamente."
|
||||
"message": "¡La versión v{version} de Modrinth App ya está disponible! Como estás conectado a una red con límite de datos, no la hemos descargado automáticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Registro de cambios"
|
||||
@@ -87,7 +96,7 @@
|
||||
"message": "¿Cuál es el apodo de tu amigo en Modrinth?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Añade amigos</link> para ver a qué están jugando."
|
||||
"message": "<link>Añade amigos</link> para ver a qué están jugando!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Cancelar petición"
|
||||
@@ -126,7 +135,7 @@
|
||||
"message": "{title}: {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Inicia sesión en una cuenta Modrinth</link> para añadir amigos y ver a qué están jugando."
|
||||
"message": "<link>Inicia sesión en una cuenta Modrinth</link> para añadir amigos y ver a qué están jugando!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Añadir y jugar"
|
||||
@@ -270,7 +279,7 @@
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": ".."
|
||||
"message": "comando Wrapper para lanzar Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Introducir comando para el wrapper..."
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java asennukset"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Kieli"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Yksityisyys"
|
||||
},
|
||||
@@ -48,7 +51,7 @@
|
||||
"message": "Ladataan..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Lataa uudelleen"
|
||||
"message": "Uudelleen lataa"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Päivitys saatavilla"
|
||||
@@ -78,13 +81,13 @@
|
||||
"message": "{count} ystävä{count, plural, one {pyyntö} other {pyyntöä}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Lähetä ystäväpyyntö"
|
||||
"message": "Lähetä kaveripyyntö"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Lisätään ystävää"
|
||||
"message": "Lisätään kaveria"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Se voi olla eri kuin heidän Minecraft-käyttäjänimensä!"
|
||||
"message": "Se ei voi olla eri kuin heidän Minecraft-käyttäjänimi!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Syötä Modrinth-käyttäjätunnus..."
|
||||
|
||||
@@ -18,16 +18,19 @@
|
||||
"message": "Mga pagpipilian sa default na instansiya"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Mga feature flag"
|
||||
"message": "Mga hudyat ng tampok"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Mga instalasyon ng Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Wika"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Pribasiya"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Pamamahala ng resource"
|
||||
"message": "Pamamahala ng paglalaan"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Ang Modrinth App v{version} ay handa nang ma-install. Mag-reload upang ma-update ngayon, o awtomatiko sa pagsara ng Modrinth App."
|
||||
@@ -57,7 +60,7 @@
|
||||
"message": "Nakumpleto ang pagdownload"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Magpindot rito upang matingnan ang changelog."
|
||||
"message": "Dito pumindot upang matingnan ang changelog."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Tagumpay na na-install ang bersiyong {version}!"
|
||||
@@ -192,13 +195,13 @@
|
||||
"message": "General"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "I-delete ang instansiya"
|
||||
"message": "Tanggalin ang instansiya"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "I-delete ang instansiya"
|
||||
"message": "Tanggalin ang instansiya"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Permanenteng matatanggal ang instansiya sa iyong device, kasali na ang iyong mga mundo, konpigurasyon, at lahat ng nakainstall na kontento. Mag-ingat, kapag magtanggal ka ng instansiya ay hindi na ito mababawi."
|
||||
"message": "Habambuhay na matatanggal ang instansiya sa iyong device, kasama ang iyong mga mundo, kompigurasyon, at lahat ng naka-install na kontento. Mag-ingat, kapag nagtanggal ka ng instansiya ay hindi na ito mababawi."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Nagde-delete..."
|
||||
@@ -213,7 +216,7 @@
|
||||
"message": "I-duplicate ang instansiya"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Gagawan ng kopya ng instansiyang ito, kasali na ang mga mundo, konpigurasyon, mods, at iba pa."
|
||||
"message": "Lilikhaan ng kopya ang instansiyang ito, kasama ang mga mundo, kumpigurasyon, mod, at iba pa."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Baguhin ang ikono"
|
||||
@@ -231,7 +234,7 @@
|
||||
"message": "Mga grupo ng librerya"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Gumawa ng bagong grupo"
|
||||
"message": "Lumikha ng bagong grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Binibigyan ng mga grupo ng librerya na iyong maayos ang iyong mga instansiya sa iba't-ibang pangkat in iyong librerya."
|
||||
@@ -249,7 +252,7 @@
|
||||
"message": "Mga custom na launch hook"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Binibigyan-daan ng mga hook ang mga ekspertong user na makapagtakbo ng mga system command bago at pagkatapos ma-launch ang laro."
|
||||
"message": "Binibigyan-daan ng mga hook ang mga ekspertong tagagamit na makapagtakbo ng mga system command bago at pagkatapos ma-launch ang laro."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Post-exist"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Installations de Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Langue"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Confidentialité"
|
||||
},
|
||||
@@ -30,16 +33,16 @@
|
||||
"message": "Gestion des ressources"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "L'application Modrinth v{version} est prêtes à être installé ! Relancez l'application pour faire la mise à jour maintenant ou la mise à jour se fera automatiquement lorsque vous fermerez l'application Modrinth."
|
||||
"message": "Modrinth App v{version} est prête à être installée ! Relancez l'application pour faire la mise à jour maintenant, ou automatiquement à la fermeture de Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "L'application Modrinth v{version} a finis d'être téléchargé ! Relancez l'application pour faire la mise à jour maintenant ou la mise à jour se fera automatiquement lorsque vous fermerez l'application Modrinth."
|
||||
"message": "Le téléchargement de Modrinth App v{version} est terminé ! Relancez l'application pour mettre à jour maintenant, ou automatiquement à la fermeture de Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "L'application Modrinth v{version} est disponible dès maintenant ! Lorsque vous êtes sur un réseau limité ou en donnée mobile, nous ne téléchargerons pas les mises à jour automatiquement."
|
||||
"message": "Modrinth App v{version} est disponible dès maintenant ! Lorsque vous êtes sur un réseau limité ou en données mobiles, nous ne téléchargerons pas les mises à jour automatiquement."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Notes de changement"
|
||||
"message": "Journal des modifications"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Télécharger ({size})"
|
||||
@@ -48,7 +51,7 @@
|
||||
"message": "Téléchargement..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Rechargement"
|
||||
"message": "Recharger"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Mise à jour disponible"
|
||||
@@ -75,7 +78,7 @@
|
||||
"message": "Ajouter un ami"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural,one {demande}other {demandes}} d'ami"
|
||||
"message": "{count} {count, plural, one {demande} other {demandes}} d'ami"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Envoyer une demande d'ami"
|
||||
@@ -123,7 +126,7 @@
|
||||
"message": "En attente"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Aucuns amis ne correspondent à \"{query}\""
|
||||
"message": "Aucuns amis ne correspondent à « {query} »"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Chercher des amis..."
|
||||
@@ -246,7 +249,7 @@
|
||||
"message": "Crochets de lancement"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Crochets de lancement custom"
|
||||
"message": "Crochets de lancement personnalisés"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Les crochets permettent aux usagers avancés d'exécuter certaines commandes systèmes avant et après le lancement du jeu."
|
||||
@@ -255,7 +258,7 @@
|
||||
"message": "Post-fermeture"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Exécuté après fermeture."
|
||||
"message": "Exécuté après la fermeture du jeu."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Entrer commande de post-fermeture..."
|
||||
@@ -366,7 +369,7 @@
|
||||
"message": "Réparation"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "La réparation réinstalle les dépendances de Minecraft et vérifie la corruption. Cela peut résoudre les problèmes de lancement du jeu en raison d'erreurs liées au lanceur, mais ne résoudra pas les problèmes ou plantages liés aux mods installés."
|
||||
"message": "La réparation réinstalle les dépendances de Minecraft et vérifie la corruption. Cela peut résoudre les problèmes de lancement du jeu en raison d'erreurs liées au launcher, mais ne résoudra pas les problèmes ou plantages liés aux mods installés."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Réparer l'instance ?"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "התקנות ג'אווה"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "שפה"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "פרטיות"
|
||||
},
|
||||
@@ -80,6 +83,9 @@
|
||||
"friends.add-friend.title": {
|
||||
"message": "מוסיף חבר"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "זה יכול להיות שונה מהמשתמש מיינקראפט שלהם!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "הכנס שם משתמש של Modrinth..."
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "A Minecraft hitelesítési szerverei jelenleg nem elérhetők. Ellenőrizd az internetkapcsolatodat, és próbálkozz később újra."
|
||||
"message": "A Minecraft hitelesítő szerverek lehet, hogy nem üzemelnek. Bizonyosodj meg róla, hogy van internetkapcsolatod és próbáld meg újra."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Nem lehet elérni a hitelesítési kiszolgálókat"
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Telepített Java példányok"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Nyelv"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Adatvédelem"
|
||||
},
|
||||
@@ -135,7 +138,7 @@
|
||||
"message": "<link>Lépj be Modrinth fiókodba</link>, hogy felvehess barátokat és lásd mivel játszanak!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Hozzáadás és játék"
|
||||
"message": "Hozzáadás és csatlakozás"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Szerver hozzáadása"
|
||||
@@ -147,7 +150,7 @@
|
||||
"message": "Engedélyezve"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Kérdezzen"
|
||||
"message": "Mindig kérdezzen rá"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Adjon hozzá egy szervert"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "Profil törlése"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Örökké eltávolít egy profilt az eszközről, beleértve a világait, beállításait és minden telepített tartalmat. Legyél óvatos, mert ha egyszer kitörölsz egy profilt, azt többé nem lehet visszaállítani."
|
||||
"message": "Örökké eltávolít egy profilt az eszközről, beleértve a világait, beállításait és minden telepített tartalmat. Legyen óvatos, mert ha egyszer kitöröl egy profilt, azt többé nem lehet visszaállítani."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Törlés..."
|
||||
@@ -231,7 +234,7 @@
|
||||
"message": "Könyvtár gyűjtemények"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Új gyűjtemény létrehozása"
|
||||
"message": "Új csoport létrehozása"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "A könyvtárgyűjtemények segítenek külön kategóriákba rendszerezni a profiljaidat."
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Peladen autentikasi Minecraft mungkin sedang tidak tersedia saat ini. Periksa koneksi internet Anda dan coba lagi nanti."
|
||||
"message": "Server autentikasi Minecraft mungkin sedang tidak tersedia saat ini. Periksa koneksi internet Anda dan coba lagi nanti."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Tidak dapat terhubung ke peladen autentikasi"
|
||||
"message": "Tidak dapat terhubung ke server autentikasi"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Mode pengembang dihidupkan."
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Pemasangan Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Bahasa"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privasi"
|
||||
},
|
||||
@@ -90,7 +93,7 @@
|
||||
"message": "Masukkan nama pengguna Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Apakah nama pengguna Modrinth teman Anda?"
|
||||
"message": "Apa nama pengguna Modrinth teman Anda?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Tambah teman</link> untuk melihat apa yang mereka mainkan!"
|
||||
@@ -138,7 +141,7 @@
|
||||
"message": "Tambah dan mainkan"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Tambah peladen"
|
||||
"message": "Tambah server"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Dimatikan"
|
||||
@@ -150,10 +153,10 @@
|
||||
"message": "Konfirmasi"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Tambah peladen"
|
||||
"message": "Tambah server"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Sunting peladen"
|
||||
"message": "Sunting server"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Sembunyikan dari Beranda"
|
||||
@@ -183,7 +186,7 @@
|
||||
"message": "Nama"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "Peladen Minecraft"
|
||||
"message": "Server Minecraft"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Paket sumber"
|
||||
@@ -471,10 +474,10 @@
|
||||
"message": "Pengaturan"
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Peladen Minecraft"
|
||||
"message": "Server Minecraft"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Tidak dapat menghubungkan ke peladen"
|
||||
"message": "Tidak dapat menghubungkan ke server"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Salin alamat"
|
||||
@@ -492,13 +495,13 @@
|
||||
"message": "Mode Menantang"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Peladen tidak cocok"
|
||||
"message": "Server tidak cocok"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Peladen tidak dapat dihubungi"
|
||||
"message": "Server tidak dapat dihubungi"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Anda hanya dapat memasuki peladen secara langsung pada Minecraft versi Alpha 1.0.5 ke atas"
|
||||
"message": "Anda hanya dapat memasuki server secara langsung pada Minecraft versi Alpha 1.0.5 ke atas"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Anda hanya dapat memasuki dunia bermain sendiri secara langsung pada Minecraft versi Alpha 1.20 ke atas"
|
||||
@@ -507,7 +510,7 @@
|
||||
"message": "Mainkan wujud"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Peladen"
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Bermain sendiri"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Installazioni Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Lingua"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacy"
|
||||
},
|
||||
@@ -36,10 +39,10 @@
|
||||
"message": "Modrinth App v{version} è stata scaricata. Ricarica per aggiornare ora, o avverrà in automatico alla chiusura di Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} è ora disponibile! Poiché sei su una rete a consumo, non l'abbiamo scaricata automaticamente."
|
||||
"message": "Modrinth App v{version} è ora disponibile! Poiché sei su una rete a consumo, non l''abbiamo scaricata automaticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Changelog"
|
||||
"message": "Novità"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Scarica ({size})"
|
||||
@@ -57,7 +60,7 @@
|
||||
"message": "Download completato"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Clicca qui per leggere il changelog."
|
||||
"message": "Clicca qui per leggere le ultime novità in inglese."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "La versione {version} è stata installata con successo!"
|
||||
@@ -69,19 +72,19 @@
|
||||
"message": "Scaricando aggiornamento ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Ricarica per installare l'aggiornamento"
|
||||
"message": "Ricarica per installare l''aggiornamento"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Stringi un'amicizia"
|
||||
"message": "Stringi un''amicizia"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {richiesta} other {richieste}} d'amicizia"
|
||||
"message": "{count} {count, plural, one {richiesta} other {richieste}} d''amicizia"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Invia richiesta d'amicizia"
|
||||
"message": "Invia richiesta d''amicizia"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Stringendo l'amicizia"
|
||||
"message": "Stringendo l''amicizia"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Potrebbe essere diverso dal nome utente di Minecraft!"
|
||||
@@ -90,10 +93,10 @@
|
||||
"message": "Inserisci il nome utente Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Con quale utente Modrinth vuoi stringere l'amicizia?"
|
||||
"message": "Con quale utente Modrinth vuoi stringere l''amicizia?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Stringi un'amicizia</link> per sapere a cosa stanno giocando!"
|
||||
"message": "<link>Stringi un''amicizia</link> per sapere a cosa stanno giocando!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Annulla richiesta"
|
||||
@@ -102,7 +105,7 @@
|
||||
"message": "Annulla amicizia"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Richiesta d'amicizia inviata"
|
||||
"message": "Richiesta d''amicizia inviata"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Visita profilo"
|
||||
@@ -132,7 +135,7 @@
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Accedi all'account Modrinth</link> per stringere amicizie e sapere a cosa stanno giocando!"
|
||||
"message": "<link>Accedi all''account Modrinth</link> per stringere amicizie e sapere a cosa stanno giocando!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Aggiungi e gioca"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "Elimina istanza"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Elimina permanentemente un'istanza dal tuo dispositivo, compresi i tuoi mondi, file di configurazione, e tutto il contenuto installato. Fai attenzione: eliminata un'istanza non c'è modo di recuperarla."
|
||||
"message": "Elimina permanentemente un''istanza dal tuo dispositivo, compresi i tuoi mondi, file di configurazione e tutto il contenuto installato. Fai attenzione: eliminata un''istanza non c'è modo di recuperarla."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Eliminando..."
|
||||
@@ -207,7 +210,7 @@
|
||||
"message": "Duplica"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Impossibile duplicare durante l'installazione."
|
||||
"message": "Impossibile duplicare durante l''installazione."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Duplica istanza"
|
||||
@@ -249,7 +252,7 @@
|
||||
"message": "Hook di avvio personalizzati"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "I hook permettono a utenti avanzati di eseguire comandi di sistema prima e dopo l'avvio del gioco."
|
||||
"message": "I hook permettono a utenti avanzati di eseguire comandi di sistema prima e dopo l''avvio del gioco."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Post-uscita"
|
||||
@@ -264,13 +267,13 @@
|
||||
"message": "Pre-lancio"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Eseguito prima dell'avvio dell'istanza."
|
||||
"message": "Eseguito prima dell''avvio dell''istanza."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Inserisci comando pre-avvio..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Hook all'avvio del gioco"
|
||||
"message": "Hook all''avvio del gioco"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
@@ -336,7 +339,7 @@
|
||||
"message": "{loader} non è disponibile per Minecraft {version}. Prova un altro loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "L'istanza è collegata a un pacchetto di mod, ma non è stato possibile trovarlo su Modrinth."
|
||||
"message": "L''istanza è collegata a un pacchetto di mod, ma non è stato possibile trovarlo su Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Piattaforma"
|
||||
@@ -348,13 +351,13 @@
|
||||
"message": "Reinstallando pacchetto di mod"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "La reinstallazione resetterà tutto il contenuto installato o modificato a ciò che è fornito dal pacchetto di mod, rimuovendo ogni mod o contenuto che tu abbia aggiunto all'installazione originale. Questo potrebbe risolvere comportamenti inaspettati se ci sono state modifiche all'istanza, ma se ora i tuoi mondi dipendessero da contenuto aggiuntivo installato, essi verrebbero corrotti."
|
||||
"message": "La reinstallazione resetterà tutto il contenuto installato o modificato a ciò che è fornito dal pacchetto di mod, rimuovendo ogni mod o contenuto che tu abbia aggiunto all''installazione originale. Questo potrebbe risolvere comportamenti inaspettati se ci sono state modifiche all''istanza, ma se ora i tuoi mondi dipendessero da contenuto aggiuntivo installato, essi verrebbero corrotti."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Vuoi davvero reinstallare questa istanza?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Resetta il contenuto dell'istanza al suo stato originale, rimuovendo ogni mod o contenuto che tu abbia aggiunto al pacchetto di mod originale."
|
||||
"message": "Resetta il contenuto dell''istanza al suo stato originale, rimuovendo ogni mod o contenuto che tu abbia aggiunto al pacchetto di mod originale."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstalla pacchetto di mod"
|
||||
@@ -369,7 +372,7 @@
|
||||
"message": "La riparazione reinstalla le dipendenze di Minecraft e verifica eventuali corruzioni. Questo potrebbe risolvere problemi di avvio del gioco se dovuti a errori legati al launcher, ma non risolverà problemi o crash legati alle mod installate."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Riparare l'istanza?"
|
||||
"message": "Riparare l''istanza?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Riparazione in corso"
|
||||
@@ -393,7 +396,7 @@
|
||||
"message": "ripara"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Impossibile {action} durante l'installazione"
|
||||
"message": "Impossibile {action} durante l''installazione"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Impossibile {action} senza connessione"
|
||||
@@ -423,7 +426,7 @@
|
||||
"message": "Java e memoria"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Variabili d'ambiente"
|
||||
"message": "Variabili d''ambiente"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hook"
|
||||
@@ -453,7 +456,7 @@
|
||||
"message": "Altezza"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "L'altezza della finestra del gioco all'avvio."
|
||||
"message": "L''altezza della finestra del gioco all''avvio."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Inserisci altezza..."
|
||||
@@ -462,7 +465,7 @@
|
||||
"message": "Larghezza"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "La larghezza della finestra del gioco all'avvio."
|
||||
"message": "La larghezza della finestra del gioco all''avvio."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Inserisci larghezza..."
|
||||
@@ -519,15 +522,15 @@
|
||||
"message": "Mondo già in uso"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Fornito dall'istanza"
|
||||
"message": "Fornito dall''istanza"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "La versione del gioco è fornita dall'istanza"
|
||||
"message": "La versione del gioco è fornita dall''istanza"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Il loader è fornito dall'istanza"
|
||||
"message": "Il loader è fornito dall''istanza"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizza con l'istanza"
|
||||
"message": "Sincronizza con l''istanza"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"message": "v{version}をダウンロード中"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "外観"
|
||||
"message": "表示設定"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "インスタンスの基本設定"
|
||||
@@ -21,22 +21,25 @@
|
||||
"message": "機能設定"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Javaのインストール"
|
||||
"message": "Javaのインストール設定"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "言語"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "プライバシー"
|
||||
"message": "プライバシー設定"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "リソース管理"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version}は今すぐインストールできます!再起動して今すぐ更新するか、アプリを閉じた際に自動で更新されます。"
|
||||
"message": "Modrinth App v{version}のインストールの準備ができました。再起動して今すぐ更新するか、アプリを閉じた際に自動で更新されます。"
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version}のダウンロードが完了しました。再起動して今すぐ更新するか、アプリを閉じた際に自動で更新されます。"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version}は今すぐダウンロードできます!従量課金制ネットワークを使用しているため自動でダウンロードはされていません。"
|
||||
"message": "Modrinth App v{version}は今すぐダウンロードできます。従量課金制ネットワークを使用しているため自動ダウンロードはされていません。"
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "更新履歴"
|
||||
@@ -51,7 +54,7 @@
|
||||
"message": "再起動"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "アップデートが可能"
|
||||
"message": "アップデートが利用可能です"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "ダウンロード完了"
|
||||
@@ -60,7 +63,7 @@
|
||||
"message": "クリックすると更新履歴を表示できます。"
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "バージョン {version} のインストールが正常に完了しました!"
|
||||
"message": "バージョン {version} が正常にインストールされました!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "アップデートをダウンロード"
|
||||
@@ -90,7 +93,7 @@
|
||||
"message": "Modrinthユーザーネームを入力..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "あなたのフレンドのModrinthユーザーネームは何ですか?"
|
||||
"message": "あなたのフレンドのModrinthユーザー名は何ですか?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>友達を追加</link>して、彼らが何をしているか見てみよう!"
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": ""
|
||||
"message": "Minecraft 인증 서버가 일시적으로 중단되었을 수 있습니다. 인터넷 연결을 확인한 후 나중에 다시 시도하세요."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "인증 서버에 연결할 수 없습니다"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "개발자 모드가 활성화되어 있습니다."
|
||||
"message": "개발자 모드가 활성화되었습니다."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "v{version} 다운로드 중"
|
||||
@@ -20,26 +23,122 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java 설치"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "언어"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "개인정보 보호"
|
||||
"message": "개인정보"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "리소스 관리"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version}을 설치할 준비가 완료되었습니다! 새로고침하거나 Modrinth App을 종료하면 자동으로 업데이트합니다."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} 다운로드가 완료되었습니다. 새로고침하거나 Modrinth App을 종료하면 자동으로 업데이트합니다."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version}이 지금 이용 가능합니다! 종량제 네트워크에 있기 때문에, 자동으로 다운로드하지 않았습니다."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "변경사항"
|
||||
"message": "변경 내역"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "다운로드 ({size})"
|
||||
"message": "({size}) 다운로드"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "다운로드 중..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "리로드"
|
||||
"message": "새로고침"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "업데이트 가능"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "다운로드 완료"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "변경 내역을 보려면 클릭하세요."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "{version} 버전이 성공적으로 설치되었습니다!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "업데이트 다운로드"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "업데이트 다운로드 중 ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "새로고침하여 업데이트 설치"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "친구 추가"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} 친구 요청 {count, plural, one {요청} other {요청}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "친구 요청 보내기"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "친구 추가 중"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Minecraft 사용자명과 다를 수 있습니다!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Modrinth 사용자명 입력..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "친구의 Modrinth 사용자명이 무엇인가요?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "친구들이 무엇을 하는지 보려면 <link>친구 추가</link>를 하세요!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "요청 취소"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "친구 삭제"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "이미 친구 요청을 보냈습니다"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "프로필 보기"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "친구"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "활동 중"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "오프라인"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "온라인"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "대기 중"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "\"{query}\"와 일치하는 친구가 없습니다"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "친구 찾는 중..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "친구를 추가하고 무엇을 하는지 보려면 <link>Modrinth 계정에 로그인</link>하세요!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "추가하고 플레이"
|
||||
"message": "추가 후 플레이"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "서버 추가"
|
||||
@@ -102,22 +201,22 @@
|
||||
"message": "인스턴스 삭제"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "기기에서 인스턴스를 완전히 삭제합니다. 월드, 설정, 설치된 모든 콘텐츠가 함께 제거됩니다. 주의하세요, 한 번 삭제하면 인스턴스를 복구할 방법은 없습니다."
|
||||
"message": "기기에서 인스턴스를 완전히 삭제합니다. 세계, 설정, 설치된 모든 콘텐츠가 함께 삭제됩니다. 주의하세요, 한 번 삭제하면 인스턴스를 복구할 수 없습니다."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "삭제중..."
|
||||
"message": "삭제 중..."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button": {
|
||||
"message": "복제"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "설치중에는 복제할 수 없습니다."
|
||||
"message": "설치 중에는 복제할 수 없습니다."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "인스턴스 복제"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "인스턴스의 복사본을 생성합니다. 월드, 설정, 모드, 기타 등등도 함께 복사됩니다."
|
||||
"message": "인스턴스의 복사본을 생성합니다. 세계, 설정, 모드, 기타 등등도 함께 복사됩니다."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "아이콘 수정"
|
||||
@@ -180,7 +279,7 @@
|
||||
"message": "래퍼"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Minecraft를 실행을 위한 래퍼 명령어 입니다."
|
||||
"message": "Minecraft 실행을 위한 래퍼 명령어 입니다."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "래퍼 명령어 입력..."
|
||||
@@ -252,7 +351,7 @@
|
||||
"message": "모드팩 재설치 중"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "재설치하면 설치 또는 수정된 모든 콘텐츠가 모드팩에서 제공하는 콘텐츠로 초기화되며, 기존 팩에 추가한 모드나 콘텐츠는 모두 제거됩니다. 인스턴스에 변경 사항이 있는 경우 예상치 못한 동작은 해결할 수 있지만, 현재 월드가 추가로 설치된 콘텐츠에 의존하고 있다면 기존 월드가 손상될 수 있습니다."
|
||||
"message": "재설치하면 설치 또는 수정된 모든 콘텐츠가 모드팩에서 제공하는 콘텐츠로 초기화되며, 기존 팩에 추가한 모드나 콘텐츠는 모두 제거됩니다. 인스턴스에 변경 사항이 있는 경우 예상치 못한 동작은 해결할 수 있지만, 현재 세계가 추가로 설치된 콘텐츠에 의존하고 있다면 기존 세계가 손상될 수 있습니다."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "정말로 이 인스턴스를 다시 설치하시겠습니까?"
|
||||
@@ -402,10 +501,10 @@
|
||||
"message": "서버가 응답하지 않음"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Minecraft 알파 1.0.5 이후 버전에서만 서버에 바로 진입할 수 있습니다."
|
||||
"message": "Minecraft 알파 1.0.5 이후 버전에서만 서버에 바로 진입할 수 있습니다"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Minecraft 1.20 이후 버전에서만 싱글플레이 세계로 바로 진입할 수 있습니다."
|
||||
"message": "Minecraft 1.20 이후 버전에서만 싱글플레이 세계로 바로 진입할 수 있습니다"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "인스턴스 플레이"
|
||||
@@ -420,7 +519,7 @@
|
||||
"message": "인스턴스 보기"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "사용중인 월드"
|
||||
"message": "사용 중인 세계"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "인스턴스에서 관리"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Pemasangan Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Bahasa"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privasi"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft verificatie servers zijn misschien offline. Check je internetverbinding en probeer opnieuw later."
|
||||
"message": "Minecraft verificatie servers zijn mogelijk offline. Check je internetverbinding en probeer opnieuw later."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Authenticatieservers kunnen niet worden bereikt"
|
||||
@@ -18,11 +18,14 @@
|
||||
"message": "Standaardopties voor instantie"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Functie vlaggen"
|
||||
"message": "Feature flags"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java installaties"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Taal"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacy"
|
||||
},
|
||||
@@ -39,7 +42,7 @@
|
||||
"message": "Modrinth App v{version} is nu beschikbaar! Omdat je nu op een netwerk met datalimiet zit, is de download niet automatisch gestart."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Changelog"
|
||||
"message": "Wijzigingenlogboek"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Download ({size})"
|
||||
@@ -57,7 +60,7 @@
|
||||
"message": "Downloaden voltooid"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klik hier om de changelog te bekijken."
|
||||
"message": "Klik hier om het wijzigingenlogboek te bekijken."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Versie {version} is succesvol geïnstalleerd!"
|
||||
@@ -90,10 +93,10 @@
|
||||
"message": "Voer Modrinth gebruikersnaam in..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Wat is de Modrinth gebruikersnaam van uw vriend?"
|
||||
"message": "Wat is de Modrinth gebruikersnaam van jouw vriend?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Voeg vrienden</link> om te zien wat hun spelen!"
|
||||
"message": "<link>Voeg vrienden toe</link> om te zien wat zij spelen!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Annuleer verzoek"
|
||||
@@ -132,7 +135,7 @@
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Log in op een Modrinth account</link> om vrienden toe te voegen en te kijken wat zij spelen!"
|
||||
"message": "<link>Log in op een Modrinth account</link> om vrienden toe te voegen en zien wat zij spelen!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Toevoegen en spelen"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "Verwijder instantie"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Verwijdert permanent een instantie van je apparaat, inclusief je werelden, instellingen en alle geïnstalleerde inhoud. Wees voorzichtig, want zodra je een instantie verwijdert, is het niet meer mogelijk om deze te herstellen."
|
||||
"message": "Verwijdert permanent een instantie van je apparaat, inclusief je werelden, instellingen en alle geïnstalleerde inhoud. Wees voorzichtig, zodra je een instantie verwijdert, is het niet meer mogelijk om deze te herstellen."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Verwijderen..."
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft-autentiseringsservere kan være nede for øyeblikket. Kontroller internettforbindelsen din og prøv igjen senere."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Kan ikke nå autentiseringsservere"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Utviklermodus aktivert."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Nedlaster v{version}"
|
||||
"message": "Laster ned v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Utseende"
|
||||
@@ -17,17 +23,32 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java installasjoner"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Språk"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Personvern"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressursforvaltning"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} er klar for installering! Last inn på nytt for å oppdatere nå, eller automatisk når du lukker Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} er ferdig lastet ned. Last in på nytt for å oppdatere nå, eller automatisk når du lukker Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} er tilgjengelig nå! Siden du er på en forbruksmålt tilkobling, lastet vi den ikke ned automatisk."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Endringslogg"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Nedlast ({size})"
|
||||
"message": "Last ned ({size})"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Laster ned..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Last inn på nytt"
|
||||
@@ -35,15 +56,87 @@
|
||||
"app.update-toast.title": {
|
||||
"message": "Oppdatering tilgjengelig"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Ferdig lastet ned"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klikk her for å se endringsloggen."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Versjon {version} ble installert!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Last ned oppdatering"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Laster ned oppdatering ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Last inn på nytt for å installere oppdateringen"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Legg til en venn"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} venne{count, plural,one {forespørsel} other {forespørsler}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Send venneforespørsel"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Legger til en venn"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Det kan være annerledes enn Minecraft-brukernavnet deres!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Fyll ut Modrinth-brukernavn..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Hva er Modrinth-brukernavnet til vennen din?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Legg til venner</link> for å se hva de spiller!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Avbryt forespørsel"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Fjern venn"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Venneforespørsel sent"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Vis profil"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Venner"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Aktiv"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Ventende"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Ingen venner som samsvarer \"{query}\""
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Søk venner..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Logg inn til en Modrinth-bruker</link> for å legge til venner og se hva de spiller!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Legg til og spill"
|
||||
},
|
||||
@@ -167,21 +260,39 @@
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Kørt etter spillet lukkes."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Skriv inn kommando etter avslutning..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Før oppstart"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Kørt før instansen startes."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Skriv inn kommando før start..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Spillstartkroker"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Wrapper-kommando for å starte Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Skriv inn wrapper-kommando..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installasjon"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} for Minecraft {game_version} er allerede installert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} er allerede installert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Endre versjon"
|
||||
},
|
||||
@@ -191,6 +302,9 @@
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Installerer"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Henter modpakkeversjoner"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Installerer ny versjon"
|
||||
},
|
||||
@@ -200,6 +314,9 @@
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Feilsøkingsinformasjon:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Henter modpakkedetaljer"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spillversjon"
|
||||
},
|
||||
@@ -215,9 +332,15 @@
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Kan ikke hente detaljer for tilknyttet modpakke."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} er ikke tilgjengelig for Minecraft {version}. Prøv en annen mod laster."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Denne instansen er tilknyttet til en modpakke, men modpakken er ikke funnet på Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
@@ -233,42 +356,81 @@
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Er du sikker på at du vil reinstallere denne instansen?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Resetter innholdet til instansen til sin opprinnelige tilstand, som fjerner alle mods eller innhold som du har lagd til på toppen av originalpakken."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstaller modpakke"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparerer"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparasjon reinstallerer Minecraft-avhengigheter og sjekker for korrupsjon. Dette kan fikse problemer hvis spillet ikke starter grunnet launcher-relaterte feil, men vil ikke løse problemer eller krasj relatert til installerte mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Reparer instanse?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparasjon pågår"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Reset til nåværende"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Vis alle versjoner"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "endre versjon"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "reinstaller"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "reparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Kan ikke {action} mens en installasjon pågår"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Kan ikke {action} når man er offline"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Kan ikke {action} mens en reparasjon pågår"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(ukjent versjon)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Koble fra instanse"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Hvis du fortsetter, vil du ikke kunne koble det på nytt uten å lage en helt ny instans. Du vil ikke kunne få oppdateringer for modpakker lenger og det vil bli til en normal instans."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Er du sikker på at du vil koble fra denne instansen?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Denne instansen er koblet til en modpakke, som betyr at mods ikke kan bli oppdatert og at du ikke kan endre modloaderen eller Minecraft-versjonen. Å avlenke vil permanent koble fra instansen fra modpakken."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Koble fra modpakke"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java og minne"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Miljøvariabler"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Hooker"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Java argumenter"
|
||||
},
|
||||
@@ -281,9 +443,15 @@
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Vindu"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Tilpasset vindusinstillinger"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Fullskjerm"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Få spillet til å starte i fullskjerm når det starter opp (ved å bruke options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Høyde"
|
||||
},
|
||||
@@ -314,6 +482,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopier addresse"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Ikke vis på Hjem"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Tilgjengelig"
|
||||
},
|
||||
@@ -329,6 +500,12 @@
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server kunne ikke kontaktes"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Du kan bare hoppe rett inn i servere på Minecraft Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Du kan bare hoppe rett inn i enkeltspiller-verdener på Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Spill instans"
|
||||
},
|
||||
@@ -343,5 +520,17 @@
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Verdenen er i bruk"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Levert av instansen"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Spillversjon er levert av instansen"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Oppstarter er levert av instansen"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkroniser med instans"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalacje Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Język"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Prywatność"
|
||||
},
|
||||
@@ -30,7 +33,7 @@
|
||||
"message": "Zarządzanie zasobami"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Wersja Modrinth App v{version} jest gotowa do pobrania! Odśwież, żeby zaktualizować teraz, albo automatycznie, gdy zamkniesz Modrinth App."
|
||||
"message": "Wersja Modrinth App v{version} jest gotowa do zainstalowania! Odśwież, żeby zaktualizować teraz, albo automatycznie, gdy zamkniesz Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Wersja Modrinth App v{version} została pobrana. Odśwież, żeby zaktualizować teraz, albo automatycznie, gdy zamkniesz Modrinth App."
|
||||
@@ -87,7 +90,7 @@
|
||||
"message": "Może różnić się od nazwy użytkownika Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Wpisz nazwę użytkownika Modrinth..."
|
||||
"message": "Wprowadź nazwę użytkownika Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Jaka jest nazwa użytkownika Twojego znajomego?"
|
||||
@@ -99,7 +102,7 @@
|
||||
"message": "Anuluj zaproszenie"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Usuń z znajomych"
|
||||
"message": "Usuń znajomego"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Wysłano zaproszenie"
|
||||
@@ -213,7 +216,7 @@
|
||||
"message": "Duplikuj instancję"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Tworzy kopie tej instancji, w tym światy, konfiguracje, mody, itp."
|
||||
"message": "Tworzy kopię tej instancji, w tym światy, konfiguracje, mody, itp."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Edytuj ikonę"
|
||||
@@ -234,7 +237,7 @@
|
||||
"message": "Utwórz nową grupę"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Grupowanie bibliotek pozwala ci na rozdzielenie instalacji na kilka różnych sekcji w twojej bibliotece."
|
||||
"message": "Grupy bibliotek pozwalają ci organizować twoje instancje w różne sekcje w twojej bibliotece."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Wpisz nazwę grupy"
|
||||
@@ -258,7 +261,7 @@
|
||||
"message": "Aktywowane po zamknięciu gry."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Wpisz komendę po zamknięciu..."
|
||||
"message": "Wprowadź komendę po zamknięciu..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Przed uruchomieniem"
|
||||
@@ -333,7 +336,7 @@
|
||||
"message": "Nie można pobrać powiązanych szczegółów paczki modów. Sprawdź swoje połączenie internetowe."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} nie jest dostępny dla wersji Minecraft {version}. Spróbuj inny."
|
||||
"message": "{loader} nie jest dostępny dla Minecraft {version}. Spróbuj inny."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Ta instancja jest połączona z paczką modów, ale nie udało się znaleźć tej paczki modów na Modrinth."
|
||||
@@ -354,7 +357,7 @@
|
||||
"message": "Czy jesteś pewien, że chcesz ponownie zainstalować tę instancję?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Resetuje zawartość instancji do jej oryginalnego stanu, usuwając jakiekolwiek modyfikacje lub zawartość, którą dodano do paczki modów."
|
||||
"message": "Resetuje zawartość instancji do jej oryginalnego stanu, usuwając jakiekolwiek modyfikacje lub zawartość którą dodano do paczki modów."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Ponownie zainstaluj paczkę modów"
|
||||
@@ -366,7 +369,7 @@
|
||||
"message": "Naprawianie"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Naprawa ponownej instalacji zależności Minecraft i kontroli korupcji. Może to rozwiązać problemy, jeśli gra nie uruchomi się z powodu błędów związanych z uruchamianiem, ale nie rozwiąże problemów ani awarii związanych z zainstalowanymi modami."
|
||||
"message": "Naprawa ponownie instaluje zależności Minecraft i sprawdza, czy nie są one uszkodzone. Może to rozwiązać problemy, jeśli gra nie uruchomi się z powodu błędów związanych z launcherem, ale nie rozwiąże problemów związanych z zainstalowanymi modami."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Naprawić instancję?"
|
||||
@@ -426,7 +429,7 @@
|
||||
"message": "Zmienne środowiskowe"
|
||||
},
|
||||
"instance.settings.tabs.java.hooks": {
|
||||
"message": "Haczyki"
|
||||
"message": "Hooki"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Argumenty Javy"
|
||||
@@ -522,7 +525,7 @@
|
||||
"message": "Podane przez instancję"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Wersja gry jest dostarczana przez instancję"
|
||||
"message": "Wersja gry jest dostarczona przez instancję"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Loader jest dostarczony przez instancję"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalações do Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Idioma"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacidade"
|
||||
},
|
||||
@@ -75,7 +78,7 @@
|
||||
"message": "Adicionar um amigo"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count, plural, =0 {Nenhuma solicitação de amizade} one {{count} solicitação de amizade} other {{count} solicitações de amizade}}"
|
||||
"message": "{count, plural, =0 {{count} solicitações de amizade} one {{count} solicitação de amizade} other {{count} solicitações de amizade}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Enviar amizade"
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalações Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Linguagem"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Privacidade"
|
||||
},
|
||||
@@ -249,7 +252,7 @@
|
||||
"message": "Ganchos de inicio personalizados"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Ganchos permitem a utilizadores avançados executarem certos comandos de sistema antes e depois de abrir o jogo."
|
||||
"message": "Ganchos permitem a utilizadores avançados executarem certos comandos de sistema antes e após abrir o jogo."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Pós-saída"
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Serverele de autentificare Minecraft pot fi indisponibile în acest moment. Verificați conexiunea la internet și încercați din nou mai târziu."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Nu se pot accesa serverele de autentificare"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modul dezvoltator activat."
|
||||
},
|
||||
@@ -17,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalări Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Limbă"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Confidențialitate"
|
||||
},
|
||||
@@ -65,6 +74,63 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Reîncarcă pentru a instala actualizarea"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Adaugă un prieten"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Trimite cerere de prietenie"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Adăugarea unui prieten"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Poate fi diferit de numele lor de utilizator Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Introduceți numele de utilizator Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Care este numele de utilizator Modrinth al prietenului tău?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Adaugă prieteni</link> pentru a vedea ce joacă!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Anulează cererea"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Eliminare prieten"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Cerere de prietenie trimisă"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Vizualizați profilul"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Prieteni"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Activ"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Inactiv"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "În așteptare"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Nu există prieteni care să corespundă cu \"{query}”"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Caută prieteni..."
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Conectează-te la un cont Modrinth</link> pentru a adăuga prieteni și a vedea ce joacă!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Adaugă și joacă"
|
||||
},
|
||||
@@ -432,10 +498,10 @@
|
||||
"message": "Poți să intri direct pe servere doar pe Minecraft Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Poți să intri direct în lumile singleplayer numai pe Minecraft 1.20+"
|
||||
"message": "Poți să intri direct în lumile de jucător simplu numai pe Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Joacă instanța"
|
||||
"message": "Joacă pe instanța"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"message": "Режим разработчика включён."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Скачивание v{version}"
|
||||
"message": "Скачивание версии {version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Внешний вид"
|
||||
@@ -23,20 +23,23 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Установки Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Язык"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Конфиденциальность"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Управление данными"
|
||||
"message": "Управление ресурсами"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} готово к установке! Перезапустите приложение, чтобы обновить его, или оно обновится автоматически при закрытии."
|
||||
"message": "Версия Modrinth App {version} готова к установке! Перезапустите приложение, чтобы обновить его, или оно обновится автоматически после закрытия."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Скачивание Modrinth App v{version} завершено. Перезапустите приложение, чтобы обновить его, или оно обновится автоматически при закрытии."
|
||||
"message": "Скачивание версии Modrinth App {version} завершено. Перезапустите приложение, чтобы обновить его, или оно обновится автоматически после закрытия."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} доступно для скачивания! Используется лимитное подключение, поэтому скачивание не началось автоматически."
|
||||
"message": "Версия Modrinth App {version} доступна для скачивания! Используется сеть с лимитным тарифным планом, поэтому скачивание не началось автоматически."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Список изменений"
|
||||
@@ -72,34 +75,34 @@
|
||||
"message": "Перезапустить и обновить"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Добавить в друзья"
|
||||
"message": "Добавить в друзья"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {запрос} few {запроса} many {запросов} other {запроса}} дружбы"
|
||||
"message": "{count} {count, plural, one {запрос} few {запроса} many {запросов} other {запроса}} дружбы"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Отправить запрос дружбы"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Добавление в друзья"
|
||||
"message": "Добавление в друзья"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Оно может быть не таким, как в Minecraft!"
|
||||
"message": "Оно может быть не таким, как в Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Введите имя на Modrinth..."
|
||||
"message": "Введите имя с Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Какое имя у друга на Modrinth?"
|
||||
"message": "Какое имя у друга на Modrinth?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Добавьте друзей</link>, чтобы знать, во что они играют!"
|
||||
"message": "<link>Добавьте друзей</link>, чтобы видеть их статус игры!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Отменить запрос"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Удалить из друзей"
|
||||
"message": "Удалить из друзей"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Отправлен запрос дружбы"
|
||||
@@ -120,13 +123,13 @@
|
||||
"message": "В сети"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "В ожидании"
|
||||
"message": "В ожидании"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Нет друзей по запросу «{query}»"
|
||||
"message": "Нет друзей по запросу «{query}»"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Поиск по друзьям..."
|
||||
"message": "Поиск по друзьям..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} — {count}"
|
||||
@@ -135,7 +138,7 @@
|
||||
"message": "<link>Войдите в Modrinth</link>, чтобы добавлять друзей и знать, во что они играют!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Добавить и играть"
|
||||
"message": "Добавить и играть"
|
||||
},
|
||||
"instance.add-server.add-server": {
|
||||
"message": "Добавить сервер"
|
||||
@@ -168,10 +171,10 @@
|
||||
"message": "Сбросить иконку"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "Изменение мира"
|
||||
"message": "Настройка мира"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Отключённые"
|
||||
"message": "Отключённые проекты"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Доступны обновления"
|
||||
@@ -186,7 +189,7 @@
|
||||
"message": "Сервер Minecraft"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "Наборы ресурсов"
|
||||
"message": "Набор ресурсов"
|
||||
},
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "Основные"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "Удалить сборку"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Навсегда удаляет сборку с устройства, включая миры, настройки и весь установленный контент. Учтите, что после удаления сборки восстановить её невозможно."
|
||||
"message": "Навсегда удаляет сборку с вашего устройства, включая миры, настройки и весь установленный контент. Учтите, что после удаления сборки восстановить её будет невозможно."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Удаление..."
|
||||
@@ -207,34 +210,34 @@
|
||||
"message": "Создать копию"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Копирование невозможно в процессе установки."
|
||||
"message": "Создание копии невозможно во время установки."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Создание копии сборки"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Создаёт копию сборки, включая миры, настройки, моды и т. д."
|
||||
"message": "Создаёт копию сборки, включая миры, настройки, моды и т. д."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Изменить значок"
|
||||
"message": "Изменить иконку"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.remove": {
|
||||
"message": "Удалить значок"
|
||||
"message": "Удалить иконку"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.replace": {
|
||||
"message": "Заменить значок"
|
||||
"message": "Заменить иконку"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Выбрать значок"
|
||||
"message": "Выбрать иконку"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Группировка"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "Создать группу"
|
||||
"message": "Создать новую группу"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "Разделение по группам позволяет организовать сборки по разным разделам в библиотеке."
|
||||
"message": "Разделение по группам позволяет организовать сборки по разным разделам в библиотеке."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Введите название группы"
|
||||
@@ -246,7 +249,7 @@
|
||||
"message": "Команды запуска"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Изменение команд запуска"
|
||||
"message": "Переопределение команд запуска"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Позволяет опытным пользователям задать системные команды, выполняемые до и после запуска игры."
|
||||
@@ -264,7 +267,7 @@
|
||||
"message": "Перед запуском"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Выполняется перед запуском игры."
|
||||
"message": "Выполняется перед запуском сборки."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Введите команду перед запуском..."
|
||||
@@ -276,16 +279,16 @@
|
||||
"message": "Обёртка"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Команда-обёртка для запуска Minecraft."
|
||||
"message": "Команда-обёртка для запуска Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Команда обёртки..."
|
||||
"message": "Введите команду-обёртку..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Установка"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} для Minecraft {game_version} уже установлен"
|
||||
"message": "{platform} {version} для Minecraft {game_version} уже установлен"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Ванильный Minecraft {game_version} уже установлен"
|
||||
@@ -312,7 +315,7 @@
|
||||
"message": "Отладочная информация:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Получение данных о сборке"
|
||||
"message": "Получение сведений о сборке"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Версия игры"
|
||||
@@ -330,13 +333,13 @@
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Не удалось получить данные о сборке. Проверьте соединение с интернетом."
|
||||
"message": "Не удалось получить сведения о сборке. Проверьте подключение к интернету."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} недоступен для Minecraft {version}. Выберите другой загрузчик."
|
||||
"message": "{loader} недоступен для Minecraft {version}. Выберите другой загрузчик."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Не удалось найти сборку на Modrinth, с которой связано установленное содержимое."
|
||||
"message": "Не удалось найти сборку на Modrinth, с которой связано установленное содержимое."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Платформа"
|
||||
@@ -348,7 +351,7 @@
|
||||
"message": "Переустановка сборки"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "При переустановке всё установленное содержимое будет сброшено к исходному состоянию сборки, а внесённые в её состав изменения удалены. Это может исправить проблемы с игрой, вызванные изменениями, однако есть риск повреждения миров, зависящих от них."
|
||||
"message": "Установленное содержимое будет сброшено к исходному состоянию сборки, а внесённые в её состав изменения будут удалены. Это может исправить возникшие после изменений проблемы с игрой, но зависящие от добавленного содержимого миры могут перестать корректно работать."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Вы действительно хотите переустановить сборку?"
|
||||
@@ -366,10 +369,10 @@
|
||||
"message": "Исправление"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Будут переустановлены зависимости Minecraft, а также определены и восстановлены повреждённые файлы. Это может помочь с проблемами запуска игры на стороне лаунчера, но не исправит проблемы и вылеты из-за ошибок в имеющихся модах."
|
||||
"message": "Будут переустановлены зависимости Minecraft, а также определены и восстановлены повреждённые файлы. Это может помочь с проблемами запуска игры на стороне лаунчера, но не исправит проблемы и вылеты из-за ошибок в имеющихся модах."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Восстановить сборку?"
|
||||
"message": "Исправить сборку?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Выполняется исправление"
|
||||
@@ -378,10 +381,10 @@
|
||||
"message": "Сбросить выбор"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Показать все версии"
|
||||
"message": "Показывать все версии"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "изменить версию"
|
||||
"message": "сменить версию"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "установить"
|
||||
@@ -390,16 +393,16 @@
|
||||
"message": "переустановить"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "восстановить"
|
||||
"message": "исправить"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Невозможно {action} во время установки"
|
||||
"message": "Невозможно {action} во время установки"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Невозможно {action} без подключения к сети"
|
||||
"message": "Невозможно {action} без подключения к сети"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Невозможно {action} во время восстановления"
|
||||
"message": "Невозможно {action} во время исправления"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(неизвестная версия)"
|
||||
@@ -411,7 +414,7 @@
|
||||
"message": "Если продолжить, восстановить связь будет невозможно без создания новой сборки. Сборка утратит возможность получать обновления и станет локальной."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Вы уверены, что хотите отвязать сборку?"
|
||||
"message": "Вы действительно хотите отвязать сборку?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Установленное содержимое связано со сборкой на Modrinth, что блокирует возможность менять версии игры, модов или загрузчик. Нажатие на кнопку ниже необратимо разрушит эту связь."
|
||||
@@ -435,25 +438,25 @@
|
||||
"message": "Расположение Java"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Выделение памяти"
|
||||
"message": "Выделенная память"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Окно"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Изменение настроек окна"
|
||||
"message": "Переопределение настроек окна"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Полноэкранный режим"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Запускать игру в полноэкранном режиме (используя options.txt)."
|
||||
"message": "Запускать игру в полноэкранном режиме (через options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Высота"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Высота окна игры при запуске."
|
||||
"message": "Высота окна игры при запуске."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Введите высоту..."
|
||||
@@ -462,7 +465,7 @@
|
||||
"message": "Ширина"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Ширина окна игры при запуске."
|
||||
"message": "Ширина окна игры при запуске."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Введите ширину..."
|
||||
@@ -474,7 +477,7 @@
|
||||
"message": "Сервер Minecraft"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Невозможно подключиться к серверу"
|
||||
"message": "Невозможно подключиться к серверу"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Копировать адрес"
|
||||
@@ -483,7 +486,7 @@
|
||||
"message": "Не показывать на главной"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Доступны"
|
||||
"message": "Доступно"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Сборка уже запущена"
|
||||
@@ -495,13 +498,13 @@
|
||||
"message": "Сервер несовместим"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Не удалось связаться с сервером"
|
||||
"message": "Не удалось связаться с сервером"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Подключиться напрямую можно только к серверам Minecraft Alpha 1.0.5 и выше"
|
||||
"message": "Подключаться к серверам напрямую можно только в Minecraft Alpha 1.0.5 и выше"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Открывать миры напрямую можно только в Minecraft 1.20 и выше"
|
||||
"message": "Открывать миры напрямую можно только в Minecraft 1.20 и выше"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Запустить сборку"
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecrafts autentiseringsservrar kan vara nere just nu. Kontrollera din internetanslutning och försök igen senare."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Kan ej nå autentiseringsservrarna"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Utvecklarläge aktiverat."
|
||||
},
|
||||
@@ -17,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java installationer"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Språk"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Integritet"
|
||||
},
|
||||
@@ -264,7 +273,7 @@
|
||||
"message": "Ange kommando före start..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Startkrokar för spelet"
|
||||
"message": "Hooks för spelstart"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Omslag"
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "การจัดการ Java ที่ติดตั้ง"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "ภาษา"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "ความเป็นส่วนตัว"
|
||||
},
|
||||
@@ -65,9 +68,48 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "รีโหลดเพื่อติดตั้งอัพเดต"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "เพิ่มเพื่อน"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "ส่งคำขอเป็นเพื่อน"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "อาจจะแตกต่างกับชื่อใน Minecraft"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "ใส่ชื่อบน Modrinth"
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "เพื่อนของคุณมีชื่อบน Modrinth ว่าอะไร"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "ยกเลิกคำขอ"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "ลบเพื่อน"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "ส่งคำขอเป็นเพื่อนแล้ว"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "ดูโปรไฟล์"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "เพื่อน"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "ออฟไลน์"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "ไม่มีเพื่อนชื่อว่า \"{query}\""
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "ค้นหาเพื่อน"
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "เพิ่มและเล่นทันที"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft doğrulama sunucuları çökmüş olabilir. İnternet bağlantını kontrol et ve daha sonra tekrar dene."
|
||||
"message": "Minecraft doğrulama sunucuları kapalı olabilir. İnternet bağlantını kontrol et ve daha sonra tekrar dene."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Doğrulama sunucularına erişilemedi"
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java kurulumları"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Dil"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Gizlilik"
|
||||
},
|
||||
@@ -30,10 +33,10 @@
|
||||
"message": "Kaynak yönetimi"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} yüklemeye hazır! Şimdi güncellemek için uygulamayı yeniden başlat ya da sen Modrinth App'ı kapatınca otomatik olarak güncellensin."
|
||||
"message": "Modrinth App v{version} kuruluma hazır! Şimdi güncellemek için uygulamayı yeniden yükle ya da sen Modrinth App'i kapatınca otomatik olarak güncellensin."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} indirmeyi bitirdi. Şimdi güncellemek için uygulamayı yeniden başlat ya da sen Modrinth App'ı kapatınca otomatik olarak güncellensin."
|
||||
"message": "Modrinth App v{version} indirildi. Şimdi güncellemek için uygulamayı yeniden yükle ya da Modrinth App'i kapatınca otomatik olarak güncellensin."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} artık mevcut! Ölçülü ağda olduğunuzdan otomatik olarak indirmedik."
|
||||
@@ -57,31 +60,31 @@
|
||||
"message": "Yükleme tamamlandı"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Değişiklikleri görüntülemek için buraya tıklayın."
|
||||
"message": "Değişiklik günlüğünü görüntülemek için buraya tıklayın."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Sürüm {version} başarıyla indirildi!"
|
||||
"message": "{version} sürümü başarıyla kuruldu!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Güncellemeyi indir"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Güncelleme indiriliyor ({percent}%)"
|
||||
"message": "Güncelleme indiriliyor (%{percent})"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Güncellemeyi yüklemek için yeniden yükleyin"
|
||||
"message": "Güncellemeyi kurmak için yeniden yükleyin"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Bir arkadaş ekle"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} Arkadaşlık {count, plural,one {isteği} other {istekleri}}"
|
||||
"message": "{count} arkadaşlık isteği"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Arkadaşlık isteği gönder"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Bir arkadaş ekleme"
|
||||
"message": "Arkadaş ekleme"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Minecraft kullanıcı adlarından farklı olabilir!"
|
||||
@@ -93,7 +96,7 @@
|
||||
"message": "Arkadaşının Modrinth kullanıcı adı nedir?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "Arkadaşlarının ne oynadığını görmek için <link>onları ekle</link>!"
|
||||
"message": "<link>Arkadaş ekleyerek</link> ne oynadıklarını gör!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "İsteği iptal et"
|
||||
@@ -114,10 +117,10 @@
|
||||
"message": "Aktif"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Çevrimdışı"
|
||||
"message": "Çevrim dışı"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Çevrimiçi"
|
||||
"message": "Çevrim içi"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Bekleniyor"
|
||||
@@ -141,10 +144,10 @@
|
||||
"message": "Sunucu ekle"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Kapalı"
|
||||
"message": "Devre dışı"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Açık"
|
||||
"message": "Etkin"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Sor"
|
||||
@@ -156,7 +159,7 @@
|
||||
"message": "Sunucuyu düzenle"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Ana Sayfadan gizle"
|
||||
"message": "Ana sayfada gizle"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Dünya Adı"
|
||||
@@ -243,13 +246,13 @@
|
||||
"message": "Ad"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Başlatma bağları"
|
||||
"message": "Başlatma kancaları"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Özel başlantı bağları"
|
||||
"message": "Özel başlatma kancası"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Bağlar kullanıcılara oyunu başlatmadan önce veya başlattıktan sonra sistem komutları çalıştırmalarını sağlar."
|
||||
"message": "Kancalar gelişmiş kullanıcıların oyunu başlattıktan önce ve sonra belirli sistem komutları çalıştırmasını sağlar."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Çıkış-sonrası"
|
||||
@@ -300,7 +303,7 @@
|
||||
"message": "Kuruluyor"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Mod paket sürümleri çekiliyor"
|
||||
"message": "Mod paketi sürümleri çekiliyor"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Yeni sürüm kuruluyor"
|
||||
@@ -312,7 +315,7 @@
|
||||
"message": "Ayıklama bilgisi:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Mod paketi detayları alınıyor"
|
||||
"message": "Mod paketi detayları çekiliyor"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Oyun sürümü"
|
||||
@@ -330,7 +333,7 @@
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Bağlı modpaketi detayları alınamıyor. Lütfen internet bağlantınızı kontrol edin."
|
||||
"message": "Bağlı mod paketi detayları çekilemiyor. Lütfen internet bağlantınızı kontrol edin."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader}, Minecraft {version} için mevcut değil. Başka bir mod yükleyici deneyin."
|
||||
@@ -342,22 +345,22 @@
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Mod paketini tekrar indir"
|
||||
"message": "Mod paketini yeniden kur"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Mod paketi tekrar kuruluyor"
|
||||
"message": "Mod paketi yeniden kuruluyor"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Tekrar indirmek modpack'teki indirilmiş veya değişmiş her şeyi sıfırlar ve senin modpack'in üstüne eklediğin herhangi bir modu veya içeriği siler. Eğer kurulumu değiştirdi isen bu bazı şeyleri düzeltebilir, fakat ekstra indirdiğin modları kullanan dünyalar varsa bozulabilirler."
|
||||
"message": "Yeniden kurmak mod paketindeki indirilmiş veya değiştirilmiş her şeyi mod paketinin sağladıklarına sıfırlar, senin mod paketinin üstüne eklediğin modları ve içerikleri siler. Bu değişiklik kaynaklı beklenmedik durumları düzeltebilir, ama dünyaların ek kurulmuş içeriğe bağımlıysa o dünyaları bozabilir."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Bu kurulumu tekrar indirmek istediğine emin misin?"
|
||||
"message": "Bu kurulumu tekrar kurmak istediğine emin misin?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Orijinal modpack'in üstüne eklediğin herşeyi silip kurulumun içeriğini eski haline döndürür."
|
||||
"message": "Kurulumun içeriğini ilk hâline geri döndürür, orijinal mod paketinin üstüne eklediğin modları ve içerikleri siler."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Mod Paketini Tekrar İndir"
|
||||
"message": "Mod paketini yeniden kur"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Tamir Et"
|
||||
@@ -381,13 +384,13 @@
|
||||
"message": "Bütün sürümleri göster"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Sürümü Değiştir"
|
||||
"message": "sürümü değiştir"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "indirilemez"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "tekrar indirilemez"
|
||||
"message": "yeniden kur"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "tamir edilemez"
|
||||
@@ -405,19 +408,19 @@
|
||||
"message": "(bilinmeyen sürüm)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Kurulum bağını koparr"
|
||||
"message": "Kurulum bağlantısını kes"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Eğer devam edersen, yeni bir kurulum oluşturmadan geri bağlayamayacaksın. Modpack güncellemeleri almayacaksın ve bu kurulum normal kuruluma dönüşecek."
|
||||
"message": "Devam edersen bu kurulumu geri bağlayamazsın. Mod paketi güncellemeleri almazsın ve bu kurulum normal kuruluma dönüşür."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Bu kurulumun bağını koparmak istediğine eminmisin?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Bu kurulum bir modpack'e bağlı, bu nedenle modlar güncellenemez ve mod yükleyicisini veya Minecraft sürümünü değiştiremezsin."
|
||||
"message": "Bu kurulum bir mod paketine bağlı, bu nedenle modlar güncellenemez ve mod yükleyicisini veya Minecraft sürümünü değiştiremezsin. Kurulumdan mod paketini koparmak kalıcıdır."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Modpack bağını kopar"
|
||||
"message": "Mod paketi bağını kopar"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java ve bellek"
|
||||
@@ -471,7 +474,7 @@
|
||||
"message": "Ayarlar"
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Bir Minecraft Sunucusu"
|
||||
"message": "Minecraft Sunucusu"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Sunucuya bağlanılamıyor"
|
||||
@@ -480,7 +483,7 @@
|
||||
"message": "Adresi kopyala"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Ana Sayfada gösterme"
|
||||
"message": "Ana sayfada gösterme"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Kullanılabilir"
|
||||
@@ -528,6 +531,6 @@
|
||||
"message": "Yükleyici veren kurulumlar"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Kurulum ile senkronize et"
|
||||
"message": "Kurulumla senkronize et"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Сервери автентифікації Minecraft можуть зараз не працювати. Перевірте підключення до Інтернету та спробуйте пізніше."
|
||||
"message": "Сервери автентифікації Minecraft можуть зараз не працювати. Перевірте з’єднання з інтернетом та спробуйте пізніше."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Не вдається зв'язатися зі серверами автентифікації"
|
||||
"message": "Не вдається зв’язатися зі серверами автентифікації"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Увімкнено режим розробника."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Завантаження v{version}"
|
||||
"message": "Завантаження версії {version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Вигляд"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Налаштування усталеного профілю"
|
||||
"message": "Усталені налашт. профілю"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Спеціальні функції"
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Інсталяції Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Мова"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Конфіденційність"
|
||||
},
|
||||
@@ -30,13 +33,13 @@
|
||||
"message": "Керування ресурсами"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} готова до встановлення! Перезапустіть, щоб оновити зараз. Або, оновлення буде здійснено автоматично, коли закриєте Modrinth App."
|
||||
"message": "Modrinth App v{version} готовий до встановлення! Перезапустіть, щоб оновити зараз. Або, оновлення буде здійснено автоматично, коли закриєте Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} уже завантажилась. Перезапустіть, щоб оновити зараз. Або, оновлення буде здійснено автоматично, коли закриєте Modrinth App."
|
||||
"message": "Версія {version} Modrinth App уже завантажилася. Перезапустіть, щоб оновити зараз, або дозвольте оновитися автоматично, коли закриватимете Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} доступна зараз! Оскільки ви на лімітному з’єднанні, ми не завантажили її автоматично."
|
||||
"message": "Версія {version} Modrinth App доступна для завантаження! Оскільки ви на лімітному з’єднанні, ми не завантажили її автоматично."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Журнал змін"
|
||||
@@ -51,13 +54,13 @@
|
||||
"message": "Перезапустити"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Оновлення доступне"
|
||||
"message": "Доступне оновлення"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Завантаження завершено"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Натисніть тут, щоб побачити список змін."
|
||||
"message": "Натисніть тут, щоб побачити журнал змін."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Версію {version} успішно встановлено!"
|
||||
@@ -69,7 +72,7 @@
|
||||
"message": "Завантаження оновлення ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Перезавантажте, щоб установити оновлення"
|
||||
"message": "Перезавантажте, аби встановити оновлення"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Додати друга"
|
||||
@@ -87,13 +90,13 @@
|
||||
"message": "Може відрізнятися від його або її імені користувача Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Уведіть ім’я користувача Modrinth…"
|
||||
"message": "Уведіть ім’я користувача…"
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Яке ім’я користувача Modrinth у вашого друга?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Додайте друзів</link>, щоб бачити, у що вони грають!"
|
||||
"message": "<link>Додайте друзів</link>, аби бачити, у що вони грають!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Скасувати запит"
|
||||
@@ -123,7 +126,7 @@
|
||||
"message": "Очікується"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Немає друзів, котрі збігаються з «{query}»"
|
||||
"message": "Немає друзів, які збігаються з «{query}»"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Шукати друзів…"
|
||||
@@ -153,7 +156,7 @@
|
||||
"message": "Додати сервер"
|
||||
},
|
||||
"instance.edit-server.title": {
|
||||
"message": "Змінити сервер"
|
||||
"message": "Редагувати сервер"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Не показувати на головній сторінці"
|
||||
@@ -174,7 +177,7 @@
|
||||
"message": "Вимкнені проєкти"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Наявні оновлення"
|
||||
"message": "Оновлення доступні"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Адреса"
|
||||
@@ -192,13 +195,13 @@
|
||||
"message": "Загальні"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Видалити примірник"
|
||||
"message": "Видалити профіль"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Видалити профіль"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Назавжди видаляє профіль з вашого пристрою, включно з вашими світами, налаштуваннями та всім встановленим контентом.\nБудьте обережні, після видалення, відновити профіль буде неможливо."
|
||||
"message": "Назавжди видаляє профіль з вашого пристрою, включно з вашими світами, налаштуваннями та всім установленим умістом. Будьте обережні, після видалення, відновити профіль буде неможливо."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Видалення…"
|
||||
@@ -207,13 +210,13 @@
|
||||
"message": "Клонувати"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Неможливо клонувати під час встановлення."
|
||||
"message": "Неможливо клонувати під час установлення."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Клонувати профіль"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Створює копію інсталяції, включно зі світами, налаштуваннями, модами тощо."
|
||||
"message": "Створює копію профілю, включно зі світами, налаштуваннями, модами тощо."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Редагувати значок"
|
||||
@@ -225,7 +228,7 @@
|
||||
"message": "Замінити значок"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon.select": {
|
||||
"message": "Обрати значок"
|
||||
"message": "Вибрати значок"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "Групи бібліотеки"
|
||||
@@ -267,13 +270,13 @@
|
||||
"message": "Запускається перед відкриттям профілю."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Уведіть команду, що виконується перед запуском..."
|
||||
"message": "Уведіть команду, що виконуватиметься перед запуском…"
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Гуки запуску гри"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Обгортач"
|
||||
"message": "Під час гри"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Обгортальна команда для запуску Minecraft."
|
||||
@@ -282,10 +285,10 @@
|
||||
"message": "Уведіть обгортальну команду…"
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Інсталяція"
|
||||
"message": "Установлення"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} для Minecraft {game_version} вже встановлена"
|
||||
"message": "{platform} {version} для Minecraft {game_version} вже встановлено"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Ванільна {game_version} вже встановлена"
|
||||
@@ -318,10 +321,10 @@
|
||||
"message": "Версія гри"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Встановити"
|
||||
"message": "Установити"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Відбувається встановлення"
|
||||
"message": "Установлення триває"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "Версія {loader}"
|
||||
@@ -330,13 +333,13 @@
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Неможливо отримати деталі пов'язаної збірки. Будь ласка, перевірте ваше з'єднання з інтернетом."
|
||||
"message": "Не вдається отримати деталі пов’язаної збірки. Будь ласка, перевірте ваше з’єднання з інтернетом."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} недоступний для Minecraft {version}. Спробуйте інший завантажувач модів."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Ця інсталяція пов'язана зі збіркою, проте саму збірку не вдалося знайти на Modrinth."
|
||||
"message": "Цей профіль пов’язаний зі збіркою, проте саму збірку не вдалося знайти на Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Платформа"
|
||||
@@ -348,13 +351,13 @@
|
||||
"message": "Перевстановлення збірки"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Перевстановлення скине увесь доданий або модифікований вміст до наданого збіркою, прибираючи будь-які, додатково встановлені вами модифікації чи вміст.\nЯкщо ви змінювали інсталяцію, це може виправити непередбачувану поведінку, однак, якщо ваші світи залежать від додаткового вмісту, це може зламати ці світи."
|
||||
"message": "Перевстановлення скине ввесь доданий або модифікований уміст до наданого збіркою, прибираючи будь-які додатково встановлені вами моди чи вміст. Якщо ви змінювали профіль, це може виправити непередбачувану поведінку, однак, якщо ваші світи залежать від додаткового вмісту, світи можуть пошкодитися."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Ви впевнені, що хочете перевстановити цей профіль?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Скидає вміст інсталяції до початкового стану, прибираючи будь-які модифікації чи вміст, що було додано поверх оригінальної збірки."
|
||||
"message": "Скидає вміст профілю до початкового стану, прибираючи будь-які моди чи вміст, що було додано поверх оригінальної збірки."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Перевстановити збірку"
|
||||
@@ -366,13 +369,13 @@
|
||||
"message": "Лагодження"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Відновлення перевстановлює залежності Minecraft та перевіряє їх на наявність пошкоджень. Це може розв'язати проблеми, якщо ваша гра не запускається через помилки завантажувача, але не розв'яже проблеми або збої, пов'язані зі встановленими модифікаціями."
|
||||
"message": "Відновлення перевстановлює залежності Minecraft та перевіряє їх на наявність пошкоджень. Це може розв’язати проблеми, якщо ваша гра не запускається через помилки запускача, але не розв’яже проблеми або збої, пов’язані зі встановленими модами."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Відновити профіль?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Лагодження в процесі"
|
||||
"message": "Лагодження триває"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Скинути до поточного"
|
||||
@@ -393,34 +396,34 @@
|
||||
"message": "полагодити"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Неможливо {action} під час встановлення"
|
||||
"message": "Неможливо {action} під час установлення"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Неможливо {action} без підключення до інтернету"
|
||||
"message": "Неможливо {action} без з’єднання з інтернетом"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Неможливо {action} під час виправлення"
|
||||
"message": "Неможливо {action} під час лагодження"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(невідома версія)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Відв'язати профіль"
|
||||
"message": "Відв’язати профіль"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Якщо ви продовжите, ви не зможете повторно підв'язати його без створення повністю нової інсталяції. Ви більше не будете отримувати оновлення збірки та вона стане звичайною."
|
||||
"message": "Якщо ви продовжите, ви не зможете повторно підв’язати його без створення повністю нового профілю. Ви більше не будете отримувати оновлення збірки та цей профіль стане звичайним."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Ви впевнені, що хочете відв'язати цю інсталяцію?"
|
||||
"message": "Ви впевнені, що хочете відв’язати цей профіль?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Цей профіль пов'язаний зі збіркою, тобто, не можна оновлювати модифікації та не можна змінювати завантажувач чи версію Minecraft. Відв'язання призведе до остаточного відключення цієї інсталяції від збірки."
|
||||
"message": "Цей профіль пов’язаний зі збіркою, тобто, не можна оновлювати моди та не можна змінювати завантажувач чи версію Minecraft. Відв’язання призведе до остаточного від’єднання цього профілю від збірки."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Відв'язати від збірки"
|
||||
"message": "Відв’язати від збірки"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java та пам'ять"
|
||||
"message": "Java та пам’ять"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Змінні середовища"
|
||||
@@ -435,7 +438,7 @@
|
||||
"message": "Інсталяції Java"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "Виділена пам'ять"
|
||||
"message": "Виділена пам’ять"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Вікно"
|
||||
@@ -447,7 +450,7 @@
|
||||
"message": "Повний екран"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Змусити гру запускатися на повний екран (використовуючи options.txt)."
|
||||
"message": "Запускати гру в повноекранному режимі (за допомогою options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Висота"
|
||||
@@ -474,13 +477,13 @@
|
||||
"message": "Сервер Minecraft"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Неможливо під'єднатися до сервера"
|
||||
"message": "Неможливо під’єднатися до сервера"
|
||||
},
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Скопіювати адресу"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Не показувати на Головній"
|
||||
"message": "Не показувати на головній"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Доступно"
|
||||
@@ -492,10 +495,10 @@
|
||||
"message": "Режим гардкору"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Несумісний сервер"
|
||||
"message": "Сервер несумісний"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Не вдалося зв'язатися з сервером"
|
||||
"message": "Не вдалося зв’язатися зі сервером"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Запускатися у сервери напряму можливо лише починаючи з версії Minecraft Alpha 1.0.5"
|
||||
@@ -516,7 +519,7 @@
|
||||
"message": "Переглянути профіль"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Світ зараз використовується"
|
||||
"message": "Світ наразі використовується"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Надано профілем"
|
||||
@@ -525,7 +528,7 @@
|
||||
"message": "Версія гри надана профілем"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Запускач наданий профілем"
|
||||
"message": "Завантажувач наданий профілем"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Синхронізувати з профілем"
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Máy chủ xác thực của Minecraft có thể đang bị sập. Hãy kiểm tra kết nối Internet của bạn và thử lại sau."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Không thể kết nối đến máy chủ xác thực"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Chế độ nhà phát triển đã được bật."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Đang tải về v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Diện mạo"
|
||||
"message": "Giao diện"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Tuỳ chọn bản hiện thể mặc định"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Các cờ tính năng"
|
||||
@@ -11,12 +23,120 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Các bản cài Java"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "Ngôn ngữ"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "Quyền riêng tư"
|
||||
},
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Quản lý tài nguyên"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth phiên bản v{version} đã sẵn sằng! Chạy lại để cập nhật ngay bây giờ, hoặc cập nhật tự động khi bạn đóng Modrinth."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth phiên bản v{version} đã tải xuống hoàn tất. Chạy lại để cập nhật ngay bây giờ, hoặc tự động cập nhật khi bạn thoát Modrinth."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth phiên bản v{version} đang có sẵn! Do mạng của bạn đang tính phí theo dung lượng và có định mức, chúng tôi không tải phiên bản này tự động."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Nhật ký thay đổi"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Tải xuống ({size})"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Đang tải xuống..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Tải lại"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Có bản cập nhật mới"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Đã tải xuống xong"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Nháy vào đây để xem nhật kí thay đổi."
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "Phiên bản {version} đã được cài đặt thành công!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "Tải về bản cập nhật"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "Đang tải xuống bản cập nhật ({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Hãy tải lại để cài đặt bản cập nhật"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Thêm một người bạn"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} yêu cầu kết bạn {count, plural, one {request} other {requests}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Gửi yêu cầu kết bạn"
|
||||
},
|
||||
"friends.add-friend.title": {
|
||||
"message": "Thêm một người bạn"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "Nó có thể khác với tên người dùng Minecraft của họ!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Nhập tên người dùng Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Tên người dùng Modrinth của bạn của bạn là gì?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "Hãy <link>Thêm bạn bè</link> để biết họ đang chơi gì!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Huỷ yêu cầu"
|
||||
},
|
||||
"friends.friend.remove-friend": {
|
||||
"message": "Loại bỏ bạn bè"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "Đã gửi yêu cầu kết bạn"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "Xem hồ sơ"
|
||||
},
|
||||
"friends.heading": {
|
||||
"message": "Bạn bè"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "Đang hoạt động"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Ngoại tuyến"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Trực tuyến"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Đang chờ"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "Không có người bạn nào phù hợp với ''{query}''"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "Tìm kiếm bạn bè..."
|
||||
},
|
||||
"friends.section.heading": {
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Đăng nhập bằng tài khoản Modrinth</link> để kết bạn và xem họ đang chơi gì!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Thêm và chơi"
|
||||
},
|
||||
@@ -30,7 +150,7 @@
|
||||
"message": "Bật"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Hỏi trước"
|
||||
"message": "Nhắc nhở"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "Thêm máy chủ"
|
||||
@@ -74,6 +194,15 @@
|
||||
"instance.settings.tabs.general": {
|
||||
"message": "Tổng quát"
|
||||
},
|
||||
"instance.settings.tabs.general.delete": {
|
||||
"message": "Xoá hiện thể"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.button": {
|
||||
"message": "Xoá hiện thể"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "Xoá vĩnh viễn bản này khỏi thiết bị, bao gồm thế giới, cài đặt, và các nội dung được cài đặt khác. Hãy cân nhắc vì bạn không thể khôi phục sau khi xoá."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Đang xoá..."
|
||||
},
|
||||
@@ -83,6 +212,12 @@
|
||||
"instance.settings.tabs.general.duplicate-button.tooltip.installing": {
|
||||
"message": "Không thể nhân đôi trong khi đang cài đặt."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Sao đôi hiện thể"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Tạo ra một bản sao của hiện thể này, bao gồm các thế giới, cấu hình, mod, v.v.."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "Sửa biểu tượng"
|
||||
},
|
||||
@@ -110,6 +245,15 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Tên"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Khởi chạy Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Hooks khởi chạy tuỳ biến"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Hooks cho phép người dùng nâng cao chạy câu lệnh hệ thống trước và sau khi chạy game."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Sau khi thoát"
|
||||
},
|
||||
@@ -122,6 +266,24 @@
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Trước khi chạy"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Chạy trước khi hiện thể được khởi chạy."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Nhập câu lệnh trước khi chạy..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Hooks để chạy game"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "Lệnh bao bọc (Wrapper)"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Lệnh bao bọc (Wrapper) để khởi chạy Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Nhập lệnh bao bọc..."
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Cài đặt"
|
||||
},
|
||||
@@ -140,6 +302,21 @@
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Đang cài đặt"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Đang tìm phiên bản modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Cài đặt phiên bản mới"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Đã cài đặt"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Thông tin gỡ lỗi:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Đang tìm chi tiết của modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Phiên bản trò chơi"
|
||||
},
|
||||
@@ -179,6 +356,9 @@
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Bạn có chắc là bạn muốn tải lại phiên bản này không?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Đặt lại bản cài đặt này về phiên bản ban đầu, xoá các mod và nội dung bạn đã cài đặt đè lên modpack gốc."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Cài lại gói mod"
|
||||
},
|
||||
@@ -188,6 +368,9 @@
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Đang sửa chữa"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Trình Sửa lỗi sẽ cài đặt lại các tệp phụ thuộc của Minecraft và kiểm tra các lỗi hư hại dữ liệu. Hành động này có thể khắc phục sự cố nếu trò chơi không khởi chạy được do lỗi trình khởi động, nhưng sẽ không giải quyết được các vấn đề hoặc sự cố sập game liên quan đến các bản mod đã cài đặt."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Sửa chữa phiên bản?"
|
||||
},
|
||||
@@ -227,6 +410,9 @@
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Xóa liên kết phiên bản"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Nếu tiếp tục, bạn sẽ không thể liên kết nó lại mà phải tạo một bản mới. Bạn sẽ không nhận được các bản cập nhật của modpack và nó sẽ trở lại bình thường."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Bạn có chắc là bạn muốn xóa liên kết phiên bản này không?"
|
||||
},
|
||||
@@ -296,9 +482,15 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Sao chép địa chỉ"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Không hiện ở Trang chủ"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Có sẵn"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Bản này đã mở sẵn"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Chế độ siêu khó"
|
||||
},
|
||||
@@ -326,6 +518,9 @@
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Xem phiên bản"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Thế giới đang mở"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Được cung cấp bởi phiên bản"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft 认证服务器可能现在无法使用。检查你的网络连接,稍后再试。"
|
||||
"message": "Minecraft 认证服务器现在可能无法使用。请检查你的网络连接,并稍后再试。"
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "无法连接到认证服务器"
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java 管理"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "语言"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "隐私"
|
||||
},
|
||||
@@ -30,13 +33,13 @@
|
||||
"message": "资源管理"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} 准备好更新。现在重新启动以更新,或在您关闭 Modrinth App 时自动更新。"
|
||||
"message": "Modrinth App v{version} 更新已就绪!立即重启更新,或退出时自动安装。"
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} 已经完成下载好。现在重新启动以更新,或在您关闭Modrinth App时自动更新。"
|
||||
"message": "Modrinth App v{version} 已经完成下载。现在重新启动以更新,或在关闭 Modrinth App 时自动更新。"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} 现在可用。自从您处在按流量计费的网络环境,我们没有自动下载更新。"
|
||||
"message": "Modrinth App v{version} 现已发布!由于你正在使用按流量计费的网络,该更新未自动下载。"
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "更新日志"
|
||||
@@ -45,34 +48,34 @@
|
||||
"message": "下载({size})"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "下载中……"
|
||||
"message": "下载中…"
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "重新启动"
|
||||
"message": "重启应用"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "更新可用"
|
||||
"message": "有可用更新"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "下载完成"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "点击此处查看变更日志。"
|
||||
"message": "点击此处查看更新日志。"
|
||||
},
|
||||
"app.update.complete-toast.title": {
|
||||
"message": "版本{version}已成功安装!"
|
||||
"message": "版本 {version} 已成功安装!"
|
||||
},
|
||||
"app.update.download-update": {
|
||||
"message": "下载完成"
|
||||
"message": "下载更新"
|
||||
},
|
||||
"app.update.downloading-update": {
|
||||
"message": "更新下载中({percent}%)"
|
||||
"message": "下载更新中({percent}%)"
|
||||
},
|
||||
"app.update.reload-to-update": {
|
||||
"message": "重新启动以安装更新"
|
||||
"message": "立即重启以安装更新"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "加一好友"
|
||||
"message": "添加好友"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} 个好友请求"
|
||||
@@ -84,16 +87,16 @@
|
||||
"message": "添加好友"
|
||||
},
|
||||
"friends.add-friend.username.description": {
|
||||
"message": "可能和他们的 Minecraft 用户名不一样!"
|
||||
"message": "这可能与对方的 Minecraft 用户名不同!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "输入Modrinth用户名……"
|
||||
"message": "输入 Modrinth 用户名……"
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "你朋友的 Modrinth 用户名是什么?"
|
||||
"message": "好友的 Modrinth 用户名是什么?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>添加好友</link>来看看他们在玩什么!"
|
||||
"message": "<link>添加好友</link> 来看看他们都在玩什么!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "取消请求"
|
||||
@@ -111,7 +114,7 @@
|
||||
"message": "好友"
|
||||
},
|
||||
"friends.heading.active": {
|
||||
"message": "活跃的"
|
||||
"message": "活跃"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "离线"
|
||||
@@ -123,7 +126,7 @@
|
||||
"message": "待确认"
|
||||
},
|
||||
"friends.no-friends-match": {
|
||||
"message": "没有匹配“{query}”的朋友"
|
||||
"message": "没有对应名字“{query}”的好友"
|
||||
},
|
||||
"friends.search-friends-placeholder": {
|
||||
"message": "搜索好友……"
|
||||
@@ -132,7 +135,7 @@
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "登录你的 <link> Modrinth 账号</link> ,添加好友并看看他们在玩什么!"
|
||||
"message": "登录你的 <link>Modrinth 账号</link>,添加好友,看看他们在玩什么!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "添加并游玩"
|
||||
@@ -147,7 +150,7 @@
|
||||
"message": "启用"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "提示"
|
||||
"message": "询问"
|
||||
},
|
||||
"instance.add-server.title": {
|
||||
"message": "添加服务器"
|
||||
@@ -168,13 +171,13 @@
|
||||
"message": "重置图标"
|
||||
},
|
||||
"instance.edit-world.title": {
|
||||
"message": "编辑世界"
|
||||
"message": "编辑存档"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "已禁用的项目"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "有更新可用"
|
||||
"message": "有可用更新"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "地址"
|
||||
@@ -198,7 +201,7 @@
|
||||
"message": "删除实例"
|
||||
},
|
||||
"instance.settings.tabs.general.delete.description": {
|
||||
"message": "从你的设备永久删除实例,包括你的世界,配置和所有已安装的内容。注意:你无法恢复被删除的实例。"
|
||||
"message": "将从设备中永久删除该实例,包括所有存档、配置文件及已安装内容。此操作不可撤销,请谨慎操作。"
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "删除中……"
|
||||
@@ -213,7 +216,7 @@
|
||||
"message": "复制实例"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "创建此实例的备份,包含世界、配置、模组等所有内容。"
|
||||
"message": "创建此实例的副本,包含世界、配置、模组等所有内容。"
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "编辑图标"
|
||||
@@ -228,13 +231,13 @@
|
||||
"message": "选择图标"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "库分组"
|
||||
"message": "实例分组"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "创建新的分组"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "库分组功能可以让你将实例整理到库中的不同部分。"
|
||||
"message": "实例分组可将你的实例整理到实例库的不同版块中。"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "输入分组名称"
|
||||
@@ -243,22 +246,22 @@
|
||||
"message": "名称"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "启动钩子"
|
||||
"message": "启动Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "自定义启动钩子"
|
||||
"message": "自定义启动Hooks"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "启动钩子允许高级用户在游戏启动前后运行特定的系统命令。"
|
||||
"message": "Hooks允许高级用户在启动游戏前后运行特定的系统命令。"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "退出后运行"
|
||||
"message": "退出后"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "在游戏关闭后运行。"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "输入退出后运行的命令……"
|
||||
"message": "输入退出后运行的命令…"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "启动前"
|
||||
@@ -267,25 +270,25 @@
|
||||
"message": "在实例启动前运行。"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "输入启动前命令……"
|
||||
"message": "输入启动前命令..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "游戏启动钩子"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper": {
|
||||
"message": "封装器"
|
||||
"message": "包装器命令"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "用于启动 Minecraft 的封装器命令。"
|
||||
"message": "用于启动 Minecraft 的包装器命令。"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "输入封装器命令……"
|
||||
"message": "输入包装器命令……"
|
||||
},
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "安装"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "适用于 Minecraft {game_version} 的{platform} {version}已安装"
|
||||
"message": "适用于 Minecraft {game_version} 的 {platform} {version} 已安装"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "原版 {game_version} 已安装"
|
||||
@@ -306,7 +309,7 @@
|
||||
"message": "正在安装新版本"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "当前安装"
|
||||
"message": "当前已安装"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "调试信息:"
|
||||
@@ -321,19 +324,19 @@
|
||||
"message": "安装"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "安装中"
|
||||
"message": "正在安装"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader}版本"
|
||||
"message": "{loader} 版本"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "获取整合包详细信息失败。请检查你的网络连接。"
|
||||
"message": "无法获取整合包详细信息。请检查网络连接。"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader}不适用于Minecraft {version}。试试换一个模组加载器。"
|
||||
"message": "{loader} 不支持 Minecraft {version}。请尝试其他模组加载器。"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "此实例与一个整合包相关联,但在 Modrinth 上无法找到该整合包。"
|
||||
@@ -342,19 +345,19 @@
|
||||
"message": "平台"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "正在重新安装整合包"
|
||||
"message": "重新安装整合包"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "正在重新安装整合包"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "重新安装将会把所有已安装或修改过的内容重置为整合包提供的状态,并移除你在原始安装基础上添加的任何模组或内容。这可能会修复因实例更改而导致的异常行为,但如果你的世界依赖于额外安装的内容,则可能会破坏现有的世界。"
|
||||
"message": "重新安装实例将重置所有已安装或修改的内容,并恢复到整合包的初始状态,移除在原来的安装内容上另外添加的的所有模组或内容。该操作有可能修复因实例更改导致的异常,但如果你的世界依赖已安装的额外内容,此举可能会损坏现有世界。"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "你确定要重新安装该实例吗?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "将实例的内容重置为原始状态,并移除你在原始整合包基础上添加的任何模组或内容。"
|
||||
"message": "重置实例至原始状态,移除你在原始整合包上添加的所有模组及内容。"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "重新安装整合包"
|
||||
@@ -366,19 +369,19 @@
|
||||
"message": "修复中"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "修复会重新安装 Minecraft 依赖并检查是否损坏。这可能会解决因启动器相关错误导致游戏无法启动的问题,但不会解决由已安装模组引起的问题或崩溃。"
|
||||
"message": "修复实例将重新安装 Minecraft 依赖,并检查文件完整性。该操作有可能解决因启动器错误导致的启动失败问题,但不能解决由模组引发的问题或崩溃。"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "确定修复该实例吗?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "修复进行中"
|
||||
"message": "正在修复"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "重置为当前"
|
||||
"message": "重置为当前版本"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "列出所有版本"
|
||||
"message": "显示所有版本"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "切换版本"
|
||||
@@ -408,19 +411,19 @@
|
||||
"message": "解除关联实例"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "如果继续操作,你将无法在不创建全新实例的情况下重新关联它。你也将不再接收整合包更新,该实例会变为普通实例。"
|
||||
"message": "若继续操作,该实例将无法重新关联至原整合包,除非创建全新的实例。此后,不再接收整合包的任何更新,该实例变为普通实例。"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "你确定要解除关联实例吗?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "该实例已与一整合包相关联,这意味着你无法更新模组,且不能更改模组加载器或Minecraft版本。解除关联将永久断开此实例与整合包的连接。"
|
||||
"message": "该实例已关联至整合包,因此无法单独更新模组,也无法更改模组加载器和 Minecraft 版本。解除关联后,该实例将无法重新关联至整合包。"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "断开与整合包的关联"
|
||||
"message": "解除整合包关联"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java及内存"
|
||||
"message": "Java 及内存"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "环境变量"
|
||||
@@ -429,16 +432,16 @@
|
||||
"message": "钩子"
|
||||
},
|
||||
"instance.settings.tabs.java.java-arguments": {
|
||||
"message": "Java参数"
|
||||
"message": "Java 参数"
|
||||
},
|
||||
"instance.settings.tabs.java.java-installation": {
|
||||
"message": "Java安装路径"
|
||||
"message": "Java 安装路径"
|
||||
},
|
||||
"instance.settings.tabs.java.java-memory": {
|
||||
"message": "分配内存"
|
||||
"message": "内存分配"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "窗口"
|
||||
"message": "游戏窗口"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "自定义窗口设置"
|
||||
@@ -456,7 +459,7 @@
|
||||
"message": "游戏启动时的窗口高度。"
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "输入高度……"
|
||||
"message": "输入高度…"
|
||||
},
|
||||
"instance.settings.tabs.window.width": {
|
||||
"message": "宽度"
|
||||
@@ -465,13 +468,13 @@
|
||||
"message": "游戏启动时的窗口宽度。"
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "输入宽度……"
|
||||
"message": "输入宽度…"
|
||||
},
|
||||
"instance.settings.title": {
|
||||
"message": "设置"
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "一个Minecraft服务器"
|
||||
"message": "Minecraft 服务器"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "无法连接至服务器"
|
||||
@@ -486,7 +489,7 @@
|
||||
"message": "可用"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "实例已打开"
|
||||
"message": "实例已启动"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "极限模式"
|
||||
@@ -495,13 +498,13 @@
|
||||
"message": "服务器不兼容"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "无法联系服务器"
|
||||
"message": "无法连接服务器"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "你只能在 Minecraft Alpha 1.0.5 及以上版本中直接进入服务器"
|
||||
"message": "只能在 Minecraft Alpha 1.0.5 及以后的版本中快速进入服务器"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "你只能在 Minecraft 1.20 及以上版本中直接进入单人世界"
|
||||
"message": "只能在 Minecraft 1.20 及以后的版本中快速进入单人游戏世界"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "游玩实例"
|
||||
@@ -513,10 +516,10 @@
|
||||
"message": "单人游戏"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "预览实例"
|
||||
"message": "查看实例"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "世界正在使用中"
|
||||
"message": "世界占用中"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "由该实例提供"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "Minecraft 驗證伺服器目前可能無法連線。請檢查你的網路連線,並稍後再試。"
|
||||
"message": "Minecraft 驗證伺服器現在可能無法使用。請檢查你的網路連線,並稍後再試。"
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "無法連線到驗證伺服器"
|
||||
@@ -9,7 +9,7 @@
|
||||
"message": "開發人員模式已啟用。"
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "下載 v{version}"
|
||||
"message": "正在下載 v{version}"
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "外觀"
|
||||
@@ -23,6 +23,9 @@
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java 安裝"
|
||||
},
|
||||
"app.settings.tabs.language": {
|
||||
"message": "語言"
|
||||
},
|
||||
"app.settings.tabs.privacy": {
|
||||
"message": "隱私"
|
||||
},
|
||||
@@ -102,7 +105,7 @@
|
||||
"message": "移除好友"
|
||||
},
|
||||
"friends.friend.request-sent": {
|
||||
"message": "好友請求已送出"
|
||||
"message": "已送出好友請求"
|
||||
},
|
||||
"friends.friend.view-profile": {
|
||||
"message": "查看個人檔案"
|
||||
@@ -132,7 +135,7 @@
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>登入 Modrinth 帳號</link>即可新增好友並查看對方正在玩什麼!"
|
||||
"message": "<link>登入 Modrinth 帳號</link>即可新增好友並查看他們正在玩什麼!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "新增並遊玩"
|
||||
@@ -228,13 +231,13 @@
|
||||
"message": "選擇圖示"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups": {
|
||||
"message": "遊戲庫群組"
|
||||
"message": "實例庫群組"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.create": {
|
||||
"message": "建立新的群組"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.description": {
|
||||
"message": "遊戲庫群組讓你可以將實例整理到遊戲庫中的不同分類。"
|
||||
"message": "實例庫群組讓你可以將實例整理到實例庫中的不同分類。"
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "輸入群組名稱"
|
||||
@@ -375,7 +378,7 @@
|
||||
"message": "修復進行中"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "重設為目前"
|
||||
"message": "重設為目前版本"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "顯示所有版本"
|
||||
@@ -501,7 +504,7 @@
|
||||
"message": "你只能在 Minecraft Alpha 1.0.5 以上版本直接加入伺服器"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "你只能在 Minecraft 1.20 以上版本直接加入伺服器"
|
||||
"message": "你只能在 Minecraft 1.20 以上版本直接進入單人遊戲世界"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "遊戲實例"
|
||||
|
||||
@@ -8,7 +8,7 @@ import { createPinia } from 'pinia'
|
||||
import { createApp } from 'vue'
|
||||
|
||||
import App from '@/App.vue'
|
||||
import i18n from '@/i18n.config'
|
||||
import i18nPlugin from '@/plugins/i18n'
|
||||
import router from '@/routes'
|
||||
|
||||
const vueScan = new VueScanPlugin({
|
||||
@@ -43,6 +43,6 @@ app.use(FloatingVue, {
|
||||
},
|
||||
},
|
||||
})
|
||||
app.use(i18n)
|
||||
app.use(i18nPlugin)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { I18N_INJECTION_KEY, type I18nContext } from '@modrinth/ui'
|
||||
import type { App } from 'vue'
|
||||
|
||||
import i18n from '@/i18n.config'
|
||||
|
||||
export default {
|
||||
install(app: App) {
|
||||
// Install vue-i18n as before
|
||||
app.use(i18n)
|
||||
|
||||
// Wrap it in our I18nContext interface
|
||||
const context: I18nContext = {
|
||||
locale: i18n.global.locale,
|
||||
t: (key, values) => i18n.global.t(key, values ?? {}) as string,
|
||||
setLocale: (newLocale) => {
|
||||
i18n.global.locale.value = newLocale
|
||||
},
|
||||
}
|
||||
|
||||
// Provide the context at app-level
|
||||
app.provide(I18N_INJECTION_KEY, context)
|
||||
},
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 21 KiB |
@@ -93,19 +93,24 @@ pub fn highlight_in_folder<R: Runtime>(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_path<R: Runtime>(app: tauri::AppHandle<R>, path: PathBuf) {
|
||||
if let Err(e) = app.opener().open_path(path.to_string_lossy(), None::<&str>)
|
||||
{
|
||||
tracing::error!("Failed to open path: {}", e);
|
||||
}
|
||||
pub async fn open_path<R: Runtime>(app: tauri::AppHandle<R>, path: PathBuf) {
|
||||
tauri::async_runtime::spawn_blocking(move || {
|
||||
if let Err(e) =
|
||||
app.opener().open_path(path.to_string_lossy(), None::<&str>)
|
||||
{
|
||||
tracing::error!("Failed to open path: {}", e);
|
||||
}
|
||||
})
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn show_launcher_logs_folder<R: Runtime>(app: tauri::AppHandle<R>) {
|
||||
pub async fn show_launcher_logs_folder<R: Runtime>(app: tauri::AppHandle<R>) {
|
||||
let path = DirectoryInfo::launcher_logs_dir().unwrap_or_default();
|
||||
// failure to get folder just opens filesystem
|
||||
// (ie: if in debug mode only and launcher_logs never created)
|
||||
open_path(app, path);
|
||||
open_path(app, path).await;
|
||||
}
|
||||
|
||||
// Get opening command
|
||||
|
||||
@@ -119,12 +119,12 @@ fn main() {
|
||||
#[cfg(feature = "updater")]
|
||||
{
|
||||
use tauri_plugin_http::reqwest::header::{HeaderValue, USER_AGENT};
|
||||
use theseus::LAUNCHER_USER_AGENT;
|
||||
use theseus::launcher_user_agent;
|
||||
builder = builder.plugin(
|
||||
tauri_plugin_updater::Builder::new()
|
||||
.header(
|
||||
USER_AGENT,
|
||||
HeaderValue::from_str(LAUNCHER_USER_AGENT).unwrap(),
|
||||
HeaderValue::from_str(&launcher_user_agent()).unwrap(),
|
||||
)
|
||||
.unwrap()
|
||||
.build(),
|
||||
|
||||
@@ -8,7 +8,7 @@ use tauri_plugin_http::reqwest::ClientBuilder;
|
||||
use tauri_plugin_updater::Error;
|
||||
use tauri_plugin_updater::Update;
|
||||
use theseus::{
|
||||
LAUNCHER_USER_AGENT, LoadingBarType, emit_loading, init_loading,
|
||||
LoadingBarType, emit_loading, init_loading, launcher_user_agent,
|
||||
};
|
||||
use tokio::time::Instant;
|
||||
|
||||
@@ -31,7 +31,7 @@ pub async fn get_update_size<R: Runtime>(
|
||||
);
|
||||
}
|
||||
|
||||
let mut request = ClientBuilder::new().user_agent(LAUNCHER_USER_AGENT);
|
||||
let mut request = ClientBuilder::new().user_agent(launcher_user_agent());
|
||||
if let Some(timeout) = update.timeout {
|
||||
request = request.timeout(timeout);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"capabilities": ["ads", "core", "plugins"],
|
||||
"csp": {
|
||||
"default-src": "'self' customprotocol: asset:",
|
||||
"connect-src": "ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://api.mclo.gs 'self' data: blob:",
|
||||
"connect-src": "ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://api.mclo.gs http://textures.minecraft.net https://textures.minecraft.net 'self' data: blob:",
|
||||
"font-src": ["https://cdn-raw.modrinth.com/fonts/"],
|
||||
"img-src": "https: 'unsafe-inline' 'self' asset: http://asset.localhost http://textures.minecraft.net blob: data:",
|
||||
"style-src": "'unsafe-inline' 'self'",
|
||||
|
||||
@@ -2516,6 +2516,13 @@ paths:
|
||||
description: 'Allows to filter for featured or non-featured versions only'
|
||||
schema:
|
||||
type: boolean
|
||||
- in: query
|
||||
name: include_changelog
|
||||
required: false
|
||||
description: 'Allows you to toggle the inclusion of the changelog field in the response. It is highly recommended to use include_changelog=false in most cases unless you specifically need the changelog for all versions.'
|
||||
schema:
|
||||
type: boolean
|
||||
default: true
|
||||
responses:
|
||||
'200':
|
||||
description: Expected response to a valid request
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
**/dist
|
||||
**/.output
|
||||
**/.data
|
||||
**/.wrangler
|
||||
src/generated/**
|
||||
src/locales/**
|
||||
src/public/news/feed
|
||||
src/assets/**/*.svg
|
||||
**/.wrangler
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { createMessageCompiler } from '@modrinth/ui'
|
||||
|
||||
export default defineI18nConfig(() => ({
|
||||
legacy: false,
|
||||
locale: 'en-US',
|
||||
fallbackLocale: 'en-US',
|
||||
messageCompiler: createMessageCompiler(),
|
||||
missingWarn: false,
|
||||
fallbackWarn: false,
|
||||
}))
|
||||
@@ -1,17 +0,0 @@
|
||||
import { type CrowdinMessages, transformCrowdinMessages } from '@modrinth/ui'
|
||||
|
||||
// eager:false - only loads the locale requested
|
||||
const localeModules = import.meta.glob<{ default: CrowdinMessages }>(
|
||||
'../src/locales/*/index.json',
|
||||
{ eager: false },
|
||||
)
|
||||
|
||||
export default defineI18nLocale(async (locale) => {
|
||||
const loader = localeModules[`../src/locales/${locale}/index.json`]
|
||||
if (!loader) {
|
||||
console.warn(`Locale ${locale} not found`)
|
||||
return {}
|
||||
}
|
||||
const messages = await loader()
|
||||
return transformCrowdinMessages(messages.default)
|
||||
})
|
||||
@@ -1,8 +1,6 @@
|
||||
import { GenericModrinthClient, type Labrinth } from '@modrinth/api-client'
|
||||
// Import directly from utils to avoid loading .vue files at config time
|
||||
import { LOCALES } from '@modrinth/ui/src/composables/i18n.ts'
|
||||
import serverSidedVue from '@vitejs/plugin-vue'
|
||||
import { promises as fs } from 'fs'
|
||||
import fs from 'fs/promises'
|
||||
import { defineNuxtConfig } from 'nuxt/config'
|
||||
import svgLoader from 'vite-svg-loader'
|
||||
|
||||
@@ -21,6 +19,9 @@ const favicons = {
|
||||
'(prefers-color-scheme:dark)': '/favicon.ico',
|
||||
}
|
||||
|
||||
const PROD_MODRINTH_URL = 'https://modrinth.com'
|
||||
const STAGING_MODRINTH_URL = 'https://staging.modrinth.com'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
srcDir: 'src/',
|
||||
app: {
|
||||
@@ -96,6 +97,11 @@ export default defineNuxtConfig({
|
||||
},
|
||||
}),
|
||||
],
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['cloudflare:workers'],
|
||||
},
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
async 'nitro:config'(nitroConfig) {
|
||||
@@ -160,7 +166,25 @@ export default defineNuxtConfig({
|
||||
|
||||
await fs.writeFile('./src/generated/state.json', JSON.stringify(state))
|
||||
|
||||
// throw if errors and building for prod (preview & staging allowed to have errors)
|
||||
if (
|
||||
process.env.BUILD_ENV === 'production' &&
|
||||
process.env.PREVIEW !== 'true' &&
|
||||
generatedState.errors.length > 0
|
||||
) {
|
||||
throw new Error(
|
||||
`Production build failed: State generation encountered errors. Error codes: ${JSON.stringify(generatedState.errors)}; API URL: ${API_URL}`,
|
||||
)
|
||||
}
|
||||
|
||||
console.log('Tags generated!')
|
||||
|
||||
const robotsContent =
|
||||
getDomain() === PROD_MODRINTH_URL
|
||||
? 'User-agent: *\nDisallow: /_internal/'
|
||||
: 'User-agent: *\nDisallow: /'
|
||||
|
||||
await fs.writeFile('./src/public/robots.txt', robotsContent)
|
||||
},
|
||||
},
|
||||
runtimeConfig: {
|
||||
@@ -174,6 +198,8 @@ export default defineNuxtConfig({
|
||||
pyroBaseUrl: process.env.PYRO_BASE_URL,
|
||||
siteUrl: getDomain(),
|
||||
production: isProduction(),
|
||||
buildEnv: process.env.BUILD_ENV,
|
||||
preview: process.env.PREVIEW === 'true',
|
||||
featureFlagOverrides: getFeatureFlagOverrides(),
|
||||
|
||||
owner: process.env.VERCEL_GIT_REPO_OWNER || 'modrinth',
|
||||
@@ -183,7 +209,7 @@ export default defineNuxtConfig({
|
||||
process.env.CF_PAGES_BRANCH ||
|
||||
// @ts-ignore
|
||||
globalThis.CF_PAGES_BRANCH ||
|
||||
'master',
|
||||
'main',
|
||||
hash:
|
||||
process.env.VERCEL_GIT_COMMIT_SHA ||
|
||||
process.env.CF_PAGES_COMMIT_SHA ||
|
||||
@@ -208,7 +234,12 @@ export default defineNuxtConfig({
|
||||
},
|
||||
},
|
||||
},
|
||||
modules: ['@nuxtjs/i18n', '@pinia/nuxt', 'floating-vue/nuxt'],
|
||||
modules: [
|
||||
'@pinia/nuxt',
|
||||
'floating-vue/nuxt',
|
||||
// Sentry causes rollup-plugin-inject errors in dev, only enable in production
|
||||
...(isProduction() ? ['@sentry/nuxt/module'] : []),
|
||||
],
|
||||
floatingVue: {
|
||||
themes: {
|
||||
'ribbit-popout': {
|
||||
@@ -223,29 +254,19 @@ export default defineNuxtConfig({
|
||||
},
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
defaultLocale: 'en-US',
|
||||
lazy: true,
|
||||
langDir: '.',
|
||||
locales: LOCALES.map((locale) => ({
|
||||
...locale,
|
||||
file: 'locale-loader.ts',
|
||||
})),
|
||||
strategy: 'no_prefix',
|
||||
detectBrowserLanguage: {
|
||||
useCookie: true,
|
||||
cookieKey: 'locale',
|
||||
fallbackLocale: 'en-US',
|
||||
},
|
||||
vueI18n: './i18n.config.ts',
|
||||
bundle: {
|
||||
optimizeTranslationDirective: false,
|
||||
},
|
||||
},
|
||||
nitro: {
|
||||
rollupConfig: {
|
||||
// @ts-expect-error because of rolldown-vite - completely fine though
|
||||
plugins: [serverSidedVue()],
|
||||
external: ['cloudflare:workers'],
|
||||
},
|
||||
preset: 'cloudflare_module',
|
||||
cloudflare: {
|
||||
nodeCompat: true,
|
||||
},
|
||||
replace: {
|
||||
__SENTRY_RELEASE__: JSON.stringify(process.env.CF_PAGES_COMMIT_SHA || 'unknown'),
|
||||
__SENTRY_ENVIRONMENT__: JSON.stringify(process.env.BUILD_ENV || 'development'),
|
||||
},
|
||||
},
|
||||
devtools: {
|
||||
@@ -291,6 +312,15 @@ export default defineNuxtConfig({
|
||||
},
|
||||
compatibilityDate: '2025-01-01',
|
||||
telemetry: false,
|
||||
experimental: {
|
||||
asyncContext: true,
|
||||
},
|
||||
sourcemap: { client: 'hidden' },
|
||||
sentry: {
|
||||
sourcemaps: {
|
||||
disable: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
function getApiUrl() {
|
||||
@@ -308,11 +338,8 @@ function getFeatureFlagOverrides() {
|
||||
|
||||
function getDomain() {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
if (process.env.SITE_URL) {
|
||||
return process.env.SITE_URL
|
||||
}
|
||||
// @ts-ignore
|
||||
else if (process.env.CF_PAGES_URL || globalThis.CF_PAGES_URL) {
|
||||
if (process.env.CF_PAGES_URL || globalThis.CF_PAGES_URL) {
|
||||
// @ts-ignore
|
||||
return process.env.CF_PAGES_URL ?? globalThis.CF_PAGES_URL
|
||||
} else if (process.env.HEROKU_APP_NAME) {
|
||||
@@ -320,9 +347,9 @@ function getDomain() {
|
||||
} else if (process.env.VERCEL_URL) {
|
||||
return `https://${process.env.VERCEL_URL}`
|
||||
} else if (getApiUrl() === STAGING_API_URL) {
|
||||
return 'https://staging.modrinth.com'
|
||||
return STAGING_MODRINTH_URL
|
||||
} else {
|
||||
return 'https://modrinth.com'
|
||||
return PROD_MODRINTH_URL
|
||||
}
|
||||
} else {
|
||||
const port = process.env.PORT || 3000
|
||||
|
||||
@@ -11,15 +11,18 @@
|
||||
"lint": "eslint . && prettier --check .",
|
||||
"fix": "eslint . --fix && prettier --write .",
|
||||
"intl:extract": "formatjs extract \"src/{components,composables,layouts,middleware,modules,pages,plugins,utils}/**/*.{vue,ts,tsx,js,jsx,mts,cts,mjs,cjs}\" \"src/error.vue\" --ignore \"**/*.d.ts\" --ignore node_modules --out-file src/locales/en-US/index.json --format crowdin --preserve-whitespace",
|
||||
"test": "pnpm build"
|
||||
"cf-deploy": "pnpm run build && wrangler deploy --env staging",
|
||||
"cf-dev": "pnpm run build && wrangler dev --env staging",
|
||||
"cf-typegen": "wrangler types"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^6.2.12",
|
||||
"@modrinth/tooling-config": "workspace:*",
|
||||
"@nuxtjs/i18n": "^9.0.0",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/iso-3166-2": "^1.0.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^20.1.0",
|
||||
"@types/semver": "^7.7.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"glob": "^10.2.7",
|
||||
"nuxt": "^3.20.2",
|
||||
@@ -30,7 +33,8 @@
|
||||
"typescript": "^5.4.5",
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vue-component-type-helpers": "^3.1.8",
|
||||
"vue-tsc": "^2.0.24"
|
||||
"vue-tsc": "^2.0.24",
|
||||
"wrangler": "^4.54.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formatjs/intl-localematcher": "^0.5.4",
|
||||
@@ -43,6 +47,7 @@
|
||||
"@modrinth/ui": "workspace:*",
|
||||
"@modrinth/utils": "workspace:*",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"@sentry/nuxt": "^10.33.0",
|
||||
"@tanstack/vue-query": "^5.90.7",
|
||||
"@types/three": "^0.172.0",
|
||||
"@vitejs/plugin-vue": "^6.0.3",
|
||||
@@ -60,6 +65,7 @@
|
||||
"iso-3166-2": "1.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"jszip": "^3.10.1",
|
||||
"lru-cache": "^11.2.4",
|
||||
"markdown-it": "14.1.0",
|
||||
"pathe": "^1.1.2",
|
||||
"pinia": "^3.0.0",
|
||||
|
||||
@@ -223,10 +223,7 @@
|
||||
:where(input) {
|
||||
box-sizing: border-box;
|
||||
max-height: 40px;
|
||||
|
||||
&:not(.stylized-toggle) {
|
||||
max-width: 100%;
|
||||
}
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
:where(.adjacent-input, &.adjacent-input) {
|
||||
@@ -271,10 +268,6 @@
|
||||
&:not(&.small) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
||||
.stylized-toggle {
|
||||
flex-basis: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -650,64 +643,6 @@ tr.button-transparent {
|
||||
}
|
||||
}
|
||||
|
||||
.switch {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
//outline: 0; Bad for accessibility
|
||||
}
|
||||
}
|
||||
|
||||
.stylized-toggle {
|
||||
@extend .button-base;
|
||||
|
||||
box-sizing: content-box;
|
||||
min-height: 32px;
|
||||
height: 32px;
|
||||
width: 52px;
|
||||
max-width: 52px;
|
||||
border-radius: var(--size-rounded-max);
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
transition: all 0.2s ease;
|
||||
background: var(--color-button-bg);
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 7px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-toggle-handle);
|
||||
transition: all 0.2s cubic-bezier(0.5, 0.1, 0.75, 1.35);
|
||||
outline: 2px solid transparent;
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
background-color: var(--color-brand);
|
||||
|
||||
&:after {
|
||||
transform: translatex(20px);
|
||||
background: var(--color-brand-inverted);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover &:focus {
|
||||
background: var(--color-button-bg);
|
||||
}
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -60,8 +60,6 @@ html {
|
||||
--color-button-bg-active: #c3c6cb;
|
||||
--color-button-text-active: var(--color-button-text-hover);
|
||||
|
||||
--color-toggle-handle: var(--color-icon);
|
||||
|
||||
--color-dropdown-bg: var(--color-button-bg);
|
||||
--color-dropdown-text: var(--color-button-text);
|
||||
|
||||
@@ -177,8 +175,6 @@ html {
|
||||
--color-button-bg-active: #616570;
|
||||
--color-button-text-active: var(--color-button-text-hover);
|
||||
|
||||
--color-toggle-handle: var(--color-button-text);
|
||||
|
||||
--color-dropdown-bg: var(--color-button-bg);
|
||||
--color-dropdown-text: var(--color-button-text);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { BlueskyIcon, DiscordIcon, GithubIcon, MastodonIcon, TwitterIcon } from '@modrinth/assets'
|
||||
import {
|
||||
AutoLink,
|
||||
ButtonStyled,
|
||||
defineMessage,
|
||||
defineMessages,
|
||||
@@ -15,6 +16,7 @@ import TextLogo from '~/components/brand/TextLogo.vue'
|
||||
const flags = useFeatureFlags()
|
||||
const { formatMessage } = useVIntl()
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
const messages = defineMessages({
|
||||
modrinthInformation: {
|
||||
@@ -302,6 +304,27 @@ function developerModeIncrement() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="flags.developerMode" class="m-0 text-sm text-secondary">
|
||||
Based on
|
||||
<a
|
||||
v-if="config.public.owner && config.public.branch"
|
||||
class="hover:underline"
|
||||
target="_blank"
|
||||
:href="`https://github.com/${config.public.owner}/code/tree/${config.public.branch}`"
|
||||
>
|
||||
{{ config.public.owner }}/{{ config.public.branch }}
|
||||
</a>
|
||||
@
|
||||
<span v-if="config.public.hash === 'unknown'">unknown</span>
|
||||
<AutoLink
|
||||
v-else
|
||||
class="text-link"
|
||||
target="_blank"
|
||||
:to="`https://github.com/${config.public.owner}/code/commit/${config.public.hash}`"
|
||||
>
|
||||
{{ config.public.hash }}
|
||||
</AutoLink>
|
||||
</p>
|
||||
<div class="flex justify-center text-center text-xs font-medium text-secondary opacity-50">
|
||||
{{ formatMessage(messages.legalDisclaimer) }}
|
||||
</div>
|
||||
|
||||
@@ -2,71 +2,54 @@
|
||||
<nav
|
||||
ref="scrollContainer"
|
||||
class="experimental-styles-within relative flex w-fit overflow-x-auto rounded-full bg-bg-raised p-1 text-sm font-bold"
|
||||
:class="[mode === 'navigation' ? 'card-shadow' : undefined]"
|
||||
:class="{ 'card-shadow': mode === 'navigation' }"
|
||||
>
|
||||
<template v-if="mode === 'navigation'">
|
||||
<NuxtLink
|
||||
v-for="(link, index) in filteredLinks"
|
||||
v-show="link.shown === undefined ? true : link.shown"
|
||||
v-show="link.shown ?? true"
|
||||
:key="link.href"
|
||||
ref="tabLinkElements"
|
||||
:to="query ? (link.href ? `?${query}=${link.href}` : '?') : link.href"
|
||||
class="button-animation z-[1] flex flex-row items-center gap-2 px-4 py-2 focus:rounded-full"
|
||||
:class="getSSRFallbackClasses(index)"
|
||||
@mouseenter="link.onHover?.()"
|
||||
@focus="link.onHover?.()"
|
||||
>
|
||||
<component
|
||||
:is="link.icon"
|
||||
v-if="link.icon"
|
||||
class="size-5"
|
||||
:class="{
|
||||
'text-brand': currentActiveIndex === index && !subpageSelected,
|
||||
'text-secondary': currentActiveIndex !== index || subpageSelected,
|
||||
}"
|
||||
/>
|
||||
<span class="text-nowrap text-contrast">{{ link.label }}</span>
|
||||
<component :is="link.icon" v-if="link.icon" class="size-5" :class="getIconClasses(index)" />
|
||||
<span class="text-nowrap" :class="getLabelClasses(index)">
|
||||
{{ link.label }}
|
||||
</span>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="(link, index) in filteredLinks"
|
||||
v-show="link.shown === undefined ? true : link.shown"
|
||||
v-show="link.shown ?? true"
|
||||
:key="link.href"
|
||||
ref="tabLinkElements"
|
||||
class="button-animation z-[1] flex flex-row items-center gap-2 px-4 py-2 hover:cursor-pointer focus:rounded-full"
|
||||
:class="getSSRFallbackClasses(index)"
|
||||
@click="emit('tabClick', index, link)"
|
||||
>
|
||||
<component
|
||||
:is="link.icon"
|
||||
v-if="link.icon"
|
||||
class="size-5"
|
||||
:class="{
|
||||
'text-brand': currentActiveIndex === index && !subpageSelected,
|
||||
'text-secondary': currentActiveIndex !== index || subpageSelected,
|
||||
}"
|
||||
/>
|
||||
<span
|
||||
class="text-nowrap"
|
||||
:class="{
|
||||
'text-brand': currentActiveIndex === index && !subpageSelected,
|
||||
'text-contrast': currentActiveIndex !== index || subpageSelected,
|
||||
}"
|
||||
>{{ link.label }}</span
|
||||
>
|
||||
<component :is="link.icon" v-if="link.icon" class="size-5" :class="getIconClasses(index)" />
|
||||
<span class="text-nowrap" :class="getLabelClasses(index)">
|
||||
{{ link.label }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Animated slider background -->
|
||||
<div
|
||||
:class="`navtabs-transition pointer-events-none absolute h-[calc(100%-0.5rem)] overflow-hidden rounded-full p-1 ${
|
||||
subpageSelected ? 'bg-button-bg' : 'bg-button-bgSelected'
|
||||
}`"
|
||||
:style="{
|
||||
left: sliderLeftPx,
|
||||
top: sliderTopPx,
|
||||
right: sliderRightPx,
|
||||
bottom: sliderBottomPx,
|
||||
opacity:
|
||||
sliderLeft === 4 && sliderLeft === sliderRight ? 0 : currentActiveIndex === -1 ? 0 : 1,
|
||||
}"
|
||||
class="pointer-events-none absolute h-[calc(100%-0.5rem)] overflow-hidden rounded-full p-1"
|
||||
:class="[
|
||||
subpageSelected ? 'bg-button-bg' : 'bg-button-bgSelected',
|
||||
{ 'navtabs-transition': transitionsEnabled },
|
||||
]"
|
||||
:style="sliderStyle"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
/>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
@@ -82,6 +65,7 @@ interface Tab {
|
||||
shown?: boolean
|
||||
icon?: Component
|
||||
subpages?: string[]
|
||||
onHover?: () => void
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -102,124 +86,194 @@ const emit = defineEmits<{
|
||||
tabClick: [index: number, tab: Tab]
|
||||
}>()
|
||||
|
||||
// DOM refs
|
||||
const scrollContainer = ref<HTMLElement | null>(null)
|
||||
const tabLinkElements = ref<HTMLElement[]>()
|
||||
|
||||
// Slider pos state
|
||||
const sliderLeft = ref(4)
|
||||
const sliderTop = ref(4)
|
||||
const sliderRight = ref(4)
|
||||
const sliderBottom = ref(4)
|
||||
|
||||
// active tab state
|
||||
const currentActiveIndex = ref(-1)
|
||||
const subpageSelected = ref(false)
|
||||
|
||||
const filteredLinks = computed(() =>
|
||||
props.links.filter((x) => (x.shown === undefined ? true : x.shown)),
|
||||
// SSR state
|
||||
const sliderReady = ref(false) // Slider is positioned and should be visible
|
||||
const transitionsEnabled = ref(false) // CSS transitions should apply (after first paint)
|
||||
|
||||
const filteredLinks = computed(() => props.links.filter((link) => link.shown ?? true))
|
||||
|
||||
const sliderStyle = computed(() => ({
|
||||
left: `${sliderLeft.value}px`,
|
||||
top: `${sliderTop.value}px`,
|
||||
right: `${sliderRight.value}px`,
|
||||
bottom: `${sliderBottom.value}px`,
|
||||
opacity: sliderReady.value && currentActiveIndex.value !== -1 ? 1 : 0,
|
||||
}))
|
||||
|
||||
const isActiveAndNotSubpage = computed(
|
||||
() => (index: number) => currentActiveIndex.value === index && !subpageSelected.value,
|
||||
)
|
||||
const sliderLeftPx = computed(() => `${sliderLeft.value}px`)
|
||||
const sliderTopPx = computed(() => `${sliderTop.value}px`)
|
||||
const sliderRightPx = computed(() => `${sliderRight.value}px`)
|
||||
const sliderBottomPx = computed(() => `${sliderBottom.value}px`)
|
||||
|
||||
const tabLinkElements = ref()
|
||||
function getSSRFallbackClasses(index: number) {
|
||||
if (sliderReady.value) return {}
|
||||
if (currentActiveIndex.value !== index) return {}
|
||||
|
||||
function pickLink() {
|
||||
let index = -1
|
||||
subpageSelected.value = false
|
||||
return {
|
||||
'rounded-full': true,
|
||||
'bg-button-bgSelected': !subpageSelected.value,
|
||||
'bg-button-bg': subpageSelected.value,
|
||||
}
|
||||
}
|
||||
|
||||
function getIconClasses(index: number) {
|
||||
return {
|
||||
'text-button-textSelected': isActiveAndNotSubpage.value(index),
|
||||
'text-secondary': !isActiveAndNotSubpage.value(index),
|
||||
}
|
||||
}
|
||||
|
||||
function getLabelClasses(index: number) {
|
||||
return {
|
||||
'text-button-textSelected': isActiveAndNotSubpage.value(index),
|
||||
'text-contrast': !isActiveAndNotSubpage.value(index),
|
||||
}
|
||||
}
|
||||
|
||||
function computeActiveIndex(): { index: number; isSubpage: boolean } {
|
||||
if (props.mode === 'local' && props.activeIndex !== undefined) {
|
||||
index = Math.min(props.activeIndex, filteredLinks.value.length - 1)
|
||||
} else {
|
||||
for (let i = filteredLinks.value.length - 1; i >= 0; i--) {
|
||||
const link = filteredLinks.value[i]
|
||||
if (props.query) {
|
||||
if (route.query[props.query] === link.href || (!route.query[props.query] && !link.href)) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
} else if (decodeURIComponent(route.path) === link.href) {
|
||||
index = i
|
||||
break
|
||||
} else if (
|
||||
decodeURIComponent(route.path).includes(link.href) ||
|
||||
(link.subpages &&
|
||||
link.subpages.some((subpage) => decodeURIComponent(route.path).includes(subpage)))
|
||||
) {
|
||||
index = i
|
||||
subpageSelected.value = true
|
||||
break
|
||||
}
|
||||
return {
|
||||
index: Math.min(props.activeIndex, filteredLinks.value.length - 1),
|
||||
isSubpage: false,
|
||||
}
|
||||
}
|
||||
|
||||
currentActiveIndex.value = index
|
||||
for (let i = filteredLinks.value.length - 1; i >= 0; i--) {
|
||||
const link = filteredLinks.value[i]
|
||||
const decodedPath = decodeURIComponent(route.path)
|
||||
|
||||
if (currentActiveIndex.value !== -1) {
|
||||
nextTick(() => startAnimation())
|
||||
// Query-based matching
|
||||
if (props.query) {
|
||||
const queryValue = route.query[props.query]
|
||||
if (queryValue === link.href || (!queryValue && !link.href)) {
|
||||
return { index: i, isSubpage: false }
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Exact path match
|
||||
if (decodedPath === link.href) {
|
||||
return { index: i, isSubpage: false }
|
||||
}
|
||||
|
||||
// Subpage match
|
||||
const isSubpageMatch =
|
||||
decodedPath.includes(link.href) ||
|
||||
link.subpages?.some((subpage) => decodedPath.includes(subpage))
|
||||
|
||||
if (isSubpageMatch) {
|
||||
return { index: i, isSubpage: true }
|
||||
}
|
||||
}
|
||||
|
||||
return { index: -1, isSubpage: false }
|
||||
}
|
||||
|
||||
function getTabElement(index: number): HTMLElement | null {
|
||||
if (!tabLinkElements.value?.[index]) return null
|
||||
|
||||
// In navigation mode, elements are NuxtLinks with $el property
|
||||
// In local mode, elements are plain divs
|
||||
const element = tabLinkElements.value[index]
|
||||
return props.mode === 'navigation' ? (element as any).$el : element
|
||||
}
|
||||
|
||||
function positionSlider() {
|
||||
const el = getTabElement(currentActiveIndex.value)
|
||||
if (!el?.offsetParent) return
|
||||
|
||||
const parent = el.offsetParent as HTMLElement
|
||||
const newPosition = {
|
||||
left: el.offsetLeft,
|
||||
top: el.offsetTop,
|
||||
right: parent.offsetWidth - el.offsetLeft - el.offsetWidth,
|
||||
bottom: parent.offsetHeight - el.offsetTop - el.offsetHeight,
|
||||
}
|
||||
|
||||
const isInitialPosition = sliderLeft.value === 4 && sliderRight.value === 4
|
||||
|
||||
if (isInitialPosition) {
|
||||
// Initial positioning: set position instantly, no animation
|
||||
sliderLeft.value = newPosition.left
|
||||
sliderRight.value = newPosition.right
|
||||
sliderTop.value = newPosition.top
|
||||
sliderBottom.value = newPosition.bottom
|
||||
|
||||
sliderReady.value = true
|
||||
|
||||
// enable transitions after slider is painted, so future changes animate
|
||||
requestAnimationFrame(() => {
|
||||
transitionsEnabled.value = true
|
||||
})
|
||||
} else {
|
||||
animateSliderTo(newPosition)
|
||||
}
|
||||
}
|
||||
|
||||
function animateSliderTo(newPosition: {
|
||||
left: number
|
||||
top: number
|
||||
right: number
|
||||
bottom: number
|
||||
}) {
|
||||
const STAGGER_DELAY = 200
|
||||
|
||||
// Horizontal animation - lead with the direction of movement
|
||||
if (newPosition.left < sliderLeft.value) {
|
||||
sliderLeft.value = newPosition.left
|
||||
setTimeout(() => (sliderRight.value = newPosition.right), STAGGER_DELAY)
|
||||
} else {
|
||||
sliderRight.value = newPosition.right
|
||||
setTimeout(() => (sliderLeft.value = newPosition.left), STAGGER_DELAY)
|
||||
}
|
||||
|
||||
// Vertical animation - lead with the direction of movement
|
||||
if (newPosition.top < sliderTop.value) {
|
||||
sliderTop.value = newPosition.top
|
||||
setTimeout(() => (sliderBottom.value = newPosition.bottom), STAGGER_DELAY)
|
||||
} else {
|
||||
sliderBottom.value = newPosition.bottom
|
||||
setTimeout(() => (sliderTop.value = newPosition.top), STAGGER_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
function updateActiveTab() {
|
||||
const { index, isSubpage } = computeActiveIndex()
|
||||
currentActiveIndex.value = index
|
||||
subpageSelected.value = isSubpage
|
||||
|
||||
if (index !== -1) {
|
||||
nextTick(positionSlider)
|
||||
} else {
|
||||
sliderLeft.value = 0
|
||||
sliderRight.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
function startAnimation() {
|
||||
// In navigation mode, elements are NuxtLinks with $el property
|
||||
// In local mode, elements are plain divs
|
||||
const el =
|
||||
props.mode === 'navigation'
|
||||
? tabLinkElements.value[currentActiveIndex.value]?.$el
|
||||
: tabLinkElements.value[currentActiveIndex.value]
|
||||
const initialActive = computeActiveIndex()
|
||||
currentActiveIndex.value = initialActive.index
|
||||
subpageSelected.value = initialActive.isSubpage
|
||||
|
||||
if (!el || !el.offsetParent) return
|
||||
|
||||
const newValues = {
|
||||
left: el.offsetLeft,
|
||||
top: el.offsetTop,
|
||||
right: el.offsetParent.offsetWidth - el.offsetLeft - el.offsetWidth,
|
||||
bottom: el.offsetParent.offsetHeight - el.offsetTop - el.offsetHeight,
|
||||
}
|
||||
|
||||
if (sliderLeft.value === 4 && sliderRight.value === 4) {
|
||||
sliderLeft.value = newValues.left
|
||||
sliderRight.value = newValues.right
|
||||
sliderTop.value = newValues.top
|
||||
sliderBottom.value = newValues.bottom
|
||||
} else {
|
||||
const delay = 200
|
||||
|
||||
if (newValues.left < sliderLeft.value) {
|
||||
sliderLeft.value = newValues.left
|
||||
setTimeout(() => {
|
||||
sliderRight.value = newValues.right
|
||||
}, delay)
|
||||
} else {
|
||||
sliderRight.value = newValues.right
|
||||
setTimeout(() => {
|
||||
sliderLeft.value = newValues.left
|
||||
}, delay)
|
||||
}
|
||||
|
||||
if (newValues.top < sliderTop.value) {
|
||||
sliderTop.value = newValues.top
|
||||
setTimeout(() => {
|
||||
sliderBottom.value = newValues.bottom
|
||||
}, delay)
|
||||
} else {
|
||||
sliderBottom.value = newValues.bottom
|
||||
setTimeout(() => {
|
||||
sliderTop.value = newValues.top
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
pickLink()
|
||||
})
|
||||
onMounted(updateActiveTab)
|
||||
|
||||
watch(
|
||||
() => [route.path, route.query],
|
||||
() => {
|
||||
if (props.mode === 'navigation') {
|
||||
pickLink()
|
||||
updateActiveTab()
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -228,19 +282,12 @@ watch(
|
||||
() => props.activeIndex,
|
||||
() => {
|
||||
if (props.mode === 'local') {
|
||||
pickLink()
|
||||
updateActiveTab()
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.links,
|
||||
() => {
|
||||
// Re-trigger animation when links change
|
||||
pickLink()
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
watch(() => props.links, updateActiveTab, { deep: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -458,9 +458,11 @@ function getMessages() {
|
||||
}
|
||||
|
||||
function getLoaderCategories(ver) {
|
||||
return tags.value.loaders.filter((loader) => {
|
||||
return ver?.loaders?.includes(loader.name)
|
||||
})
|
||||
return tags.value.loaders
|
||||
.filter((loader) => {
|
||||
return ver?.loaders?.includes(loader.name)
|
||||
})
|
||||
.map((loader) => loader.name)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -91,10 +91,9 @@
|
||||
|
||||
<script>
|
||||
import { CalendarIcon, DownloadIcon, HeartIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import { Avatar, ProjectStatusBadge, useRelativeTime } from '@modrinth/ui'
|
||||
import { Avatar, Categories, ProjectStatusBadge, useRelativeTime } from '@modrinth/ui'
|
||||
|
||||
import EnvironmentIndicator from '~/components/ui/EnvironmentIndicator.vue'
|
||||
import Categories from '~/components/ui/search/Categories.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<ButtonStyled color="brand">
|
||||
<button class="brand-button" @click="acceptInvite()">
|
||||
<CheckIcon />
|
||||
{{ getFormattedMessage(messages.accept) }}
|
||||
{{ getFormattedMessage(commonMessages.acceptButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="red">
|
||||
<button @click="declineInvite">
|
||||
<XIcon />
|
||||
{{ getFormattedMessage(messages.decline) }}
|
||||
{{ getFormattedMessage(commonMessages.declineButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
@@ -26,6 +26,7 @@
|
||||
import { CheckIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
type MessageDescriptor,
|
||||
@@ -81,14 +82,6 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
"You've been invited to join this project. Please accept or decline the invitation.",
|
||||
},
|
||||
accept: {
|
||||
id: 'project-member-header.accept',
|
||||
defaultMessage: 'Accept',
|
||||
},
|
||||
decline: {
|
||||
id: 'project-member-header.decline',
|
||||
defaultMessage: 'Decline',
|
||||
},
|
||||
successJoin: {
|
||||
id: 'project-member-header.success-join',
|
||||
defaultMessage: 'You have joined the project team',
|
||||
@@ -105,14 +98,6 @@ const messages = defineMessages({
|
||||
id: 'project-member-header.error-decline',
|
||||
defaultMessage: 'Failed to decline team invitation',
|
||||
},
|
||||
success: {
|
||||
id: 'project-member-header.success',
|
||||
defaultMessage: 'Success',
|
||||
},
|
||||
error: {
|
||||
id: 'project-member-header.error',
|
||||
defaultMessage: 'Error',
|
||||
},
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
@@ -171,13 +156,13 @@ async function acceptInvite(): Promise<void> {
|
||||
await acceptTeamInvite(props.project.team)
|
||||
await handleUpdateMembers()
|
||||
addNotification({
|
||||
title: formatMessage(messages.success),
|
||||
title: formatMessage(commonMessages.successLabel),
|
||||
text: formatMessage(messages.successJoin),
|
||||
type: 'success',
|
||||
})
|
||||
} catch {
|
||||
addNotification({
|
||||
title: formatMessage(messages.error),
|
||||
title: formatMessage(commonMessages.errorLabel),
|
||||
text: formatMessage(messages.errorJoin),
|
||||
type: 'error',
|
||||
})
|
||||
@@ -192,13 +177,13 @@ async function declineInvite(): Promise<void> {
|
||||
await removeTeamMember(props.project.team, props.auth.user.id)
|
||||
await handleUpdateMembers()
|
||||
addNotification({
|
||||
title: formatMessage(messages.success),
|
||||
title: formatMessage(commonMessages.successLabel),
|
||||
text: formatMessage(messages.successDecline),
|
||||
type: 'success',
|
||||
})
|
||||
} catch {
|
||||
addNotification({
|
||||
title: formatMessage(messages.error),
|
||||
title: formatMessage(commonMessages.errorLabel),
|
||||
text: formatMessage(messages.errorDecline),
|
||||
type: 'error',
|
||||
})
|
||||
|
||||
@@ -0,0 +1,416 @@
|
||||
<template>
|
||||
<NewModal ref="modal">
|
||||
<template #title>
|
||||
<span class="text-lg font-extrabold text-contrast">Schedule transfer</span>
|
||||
</template>
|
||||
<div class="flex w-[550px] max-w-[90vw] flex-col gap-6">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast"> Type </span>
|
||||
<span>Select transfer type.</span>
|
||||
</label>
|
||||
<Combobox
|
||||
v-model="mode"
|
||||
:options="modeOptions"
|
||||
placeholder="Select type"
|
||||
class="max-w-[10rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="mode === 'servers'" class="flex flex-col gap-2">
|
||||
<label for="server-ids" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">
|
||||
Server IDs
|
||||
<span class="text-brand-red">*</span>
|
||||
</span>
|
||||
<span>Server IDs (one per line or comma-separated.)</span>
|
||||
</label>
|
||||
<div class="textarea-wrapper">
|
||||
<textarea
|
||||
id="server-ids"
|
||||
v-model="serverIdsInput"
|
||||
rows="4"
|
||||
class="w-full bg-surface-3"
|
||||
placeholder="123e4569-e89b-12d3-a456-426614174005 123e9569-e89b-12d3-a456-413678919876"
|
||||
/>
|
||||
</div>
|
||||
<span v-if="parsedServerIds.length" class="text-sm text-secondary">
|
||||
{{ parsedServerIds.length }} server{{ parsedServerIds.length === 1 ? '' : 's' }} selected
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-else class="flex flex-col gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="node-input" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">
|
||||
Node hostnames
|
||||
<span class="text-brand-red">*</span>
|
||||
</span>
|
||||
<span>Add nodes to transfer (comma or space-separated).</span>
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
id="node-input"
|
||||
v-model="nodeInput"
|
||||
class="w-64"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
placeholder="us-vin200, us-vin201"
|
||||
@keydown.enter.prevent="addNodes"
|
||||
/>
|
||||
<ButtonStyled color="blue" color-fill="text">
|
||||
<button class="shrink-0" @click="addNodes">
|
||||
<PlusIcon />
|
||||
Add
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<div v-if="selectedNodes.length" class="mt-1 flex flex-wrap gap-2">
|
||||
<TagItem v-for="h in selectedNodes" :key="`node-${h}`" :action="() => removeNode(h)">
|
||||
<XIcon />
|
||||
{{ h }}
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3">
|
||||
<label for="cordon-nodes" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">Cordon nodes now</span>
|
||||
<span>
|
||||
Prevent new servers from being provisioned on the transferred nodes from now on.<br /><br />
|
||||
Note that if this option isn't chosen, new servers provisioned onto transferred nodes
|
||||
between now and the scheduled time will still be transferred.
|
||||
</span>
|
||||
</label>
|
||||
<Toggle id="cordon-nodes" v-model="cordonNodes" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="tag-nodes" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">Tag transferred nodes</span>
|
||||
<span>Optional tag to add to the transferred nodes.</span>
|
||||
</label>
|
||||
<input
|
||||
id="tag-nodes"
|
||||
v-model="tagNodes"
|
||||
class="max-w-[12rem]"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="region-select" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast"> Target region </span>
|
||||
<span>Select the destination region for transferred servers.</span>
|
||||
</label>
|
||||
<Combobox
|
||||
v-model="selectedRegion"
|
||||
:options="regions"
|
||||
placeholder="Select region"
|
||||
class="max-w-[24rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="tag-input" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast"> Node tags </span>
|
||||
<span>Optional preferred node tags for node selection.</span>
|
||||
</label>
|
||||
<div class="flex items-center gap-2">
|
||||
<input
|
||||
id="tag-input"
|
||||
v-model="tagInput"
|
||||
class="w-40"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
placeholder="ovh-gen4"
|
||||
@keydown.enter.prevent="addTag"
|
||||
/>
|
||||
<ButtonStyled color="blue" color-fill="text">
|
||||
<button class="shrink-0" @click="addTag">
|
||||
<PlusIcon />
|
||||
Add
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<div v-if="selectedTags.length" class="mt-1 flex flex-wrap gap-2">
|
||||
<TagItem v-for="t in selectedTags" :key="`tag-${t}`" :action="() => removeTag(t)">
|
||||
<XIcon />
|
||||
{{ t }}
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<label class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast"> Schedule </span>
|
||||
</label>
|
||||
<Chips
|
||||
v-model="scheduleOption"
|
||||
:items="scheduleOptions"
|
||||
:format-label="(item) => scheduleOptionLabels[item]"
|
||||
:capitalize="false"
|
||||
/>
|
||||
<input
|
||||
v-if="scheduleOption === 'later'"
|
||||
v-model="scheduledDate"
|
||||
type="datetime-local"
|
||||
class="mt-2 max-w-[16rem]"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="reason" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">
|
||||
Reason
|
||||
<span class="text-brand-red">*</span>
|
||||
</span>
|
||||
<span>Provide a reason for this transfer batch.</span>
|
||||
</label>
|
||||
<div class="textarea-wrapper">
|
||||
<textarea
|
||||
id="reason"
|
||||
v-model="reason"
|
||||
rows="2"
|
||||
class="w-full bg-surface-3"
|
||||
placeholder="Node maintenance scheduled"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="submitDisabled || submitting" @click="submit">
|
||||
<SendIcon aria-hidden="true" />
|
||||
{{ submitting ? 'Scheduling...' : 'Schedule transfer' }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="modal?.hide?.()">
|
||||
<XIcon aria-hidden="true" />
|
||||
Cancel
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PlusIcon, SendIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Chips,
|
||||
Combobox,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
TagItem,
|
||||
Toggle,
|
||||
} from '@modrinth/ui'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { useServersFetch } from '~/composables/servers/servers-fetch.ts'
|
||||
|
||||
const emit = defineEmits<{
|
||||
success: []
|
||||
}>()
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
|
||||
const modeOptions = [
|
||||
{ value: 'servers', label: 'Servers' },
|
||||
{ value: 'nodes', label: 'Nodes' },
|
||||
]
|
||||
const mode = ref<string>('servers')
|
||||
|
||||
const serverIdsInput = ref('')
|
||||
const parsedServerIds = computed(() => {
|
||||
const input = serverIdsInput.value.trim()
|
||||
if (!input) return []
|
||||
return input
|
||||
.split(/[\n,\s]+/)
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s.length > 0)
|
||||
})
|
||||
|
||||
const nodeInput = ref('')
|
||||
const selectedNodes = ref<string[]>([])
|
||||
const cordonNodes = ref(true)
|
||||
const tagNodes = ref('')
|
||||
|
||||
type RegionOpt = { value: string; label: string }
|
||||
const regions = ref<RegionOpt[]>([])
|
||||
const selectedRegion = ref<string | null>(null)
|
||||
const nodeHostnames = ref<string[]>([])
|
||||
|
||||
const tagInput = ref('')
|
||||
const selectedTags = ref<string[]>([])
|
||||
|
||||
const scheduleOptions: ('now' | 'later')[] = ['now', 'later']
|
||||
const scheduleOptionLabels: Record<string, string> = {
|
||||
now: 'Now',
|
||||
later: 'Schedule for later',
|
||||
}
|
||||
const scheduleOption = ref<'now' | 'later'>('now')
|
||||
const scheduledDate = ref<string>('')
|
||||
|
||||
const reason = ref('')
|
||||
|
||||
const submitting = ref(false)
|
||||
|
||||
function show(event?: MouseEvent) {
|
||||
void ensureOverview()
|
||||
mode.value = 'servers'
|
||||
serverIdsInput.value = ''
|
||||
selectedNodes.value = []
|
||||
cordonNodes.value = true
|
||||
tagNodes.value = `migration${dayjs().format('YYYYMMDD')}`
|
||||
selectedTags.value = []
|
||||
tagInput.value = ''
|
||||
nodeInput.value = ''
|
||||
scheduleOption.value = 'now'
|
||||
scheduledDate.value = ''
|
||||
reason.value = ''
|
||||
modal.value?.show(event)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
function addNodes() {
|
||||
const input = nodeInput.value.trim()
|
||||
if (!input) return
|
||||
|
||||
const nodes = input
|
||||
.split(/[,\s]+/)
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s.length > 0)
|
||||
|
||||
const unknownNodes: string[] = []
|
||||
const addedNodes: string[] = []
|
||||
|
||||
for (const v of nodes) {
|
||||
if (!nodeHostnames.value.includes(v)) {
|
||||
unknownNodes.push(v)
|
||||
continue
|
||||
}
|
||||
if (!selectedNodes.value.includes(v)) {
|
||||
selectedNodes.value.push(v)
|
||||
addedNodes.push(v)
|
||||
}
|
||||
}
|
||||
|
||||
if (unknownNodes.length > 0) {
|
||||
addNotification({
|
||||
title: `Unknown node${unknownNodes.length > 1 ? 's' : ''}`,
|
||||
text: unknownNodes.join(', '),
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
|
||||
nodeInput.value = ''
|
||||
}
|
||||
|
||||
function removeNode(v: string) {
|
||||
selectedNodes.value = selectedNodes.value.filter((x) => x !== v)
|
||||
}
|
||||
|
||||
function addTag() {
|
||||
const v = tagInput.value.trim()
|
||||
if (!v) return
|
||||
if (!selectedTags.value.includes(v)) selectedTags.value.push(v)
|
||||
tagInput.value = ''
|
||||
}
|
||||
|
||||
function removeTag(v: string) {
|
||||
selectedTags.value = selectedTags.value.filter((x) => x !== v)
|
||||
}
|
||||
|
||||
const submitDisabled = computed(() => {
|
||||
if (!reason.value.trim()) return true
|
||||
if (mode.value === 'servers') {
|
||||
if (parsedServerIds.value.length === 0) return true
|
||||
} else {
|
||||
if (selectedNodes.value.length === 0) return true
|
||||
}
|
||||
if (scheduleOption.value === 'later' && !scheduledDate.value) return true
|
||||
return false
|
||||
})
|
||||
|
||||
async function ensureOverview() {
|
||||
if (regions.value.length || nodeHostnames.value.length) return
|
||||
try {
|
||||
const data = await useServersFetch<any>('/nodes/overview', { version: 'internal' })
|
||||
regions.value = (data.regions || []).map((r: any) => ({
|
||||
value: r.key,
|
||||
label: `${r.display_name} (${r.key})`,
|
||||
}))
|
||||
nodeHostnames.value = data.node_hostnames || []
|
||||
if (!selectedRegion.value && regions.value.length) {
|
||||
selectedRegion.value = regions.value[0].value
|
||||
}
|
||||
} catch (err) {
|
||||
addNotification({ title: 'Failed to load nodes overview', text: String(err), type: 'error' })
|
||||
}
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (submitDisabled.value || submitting.value) return
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
const scheduledAt =
|
||||
scheduleOption.value === 'now' ? undefined : dayjs(scheduledDate.value).toISOString()
|
||||
|
||||
if (mode.value === 'servers') {
|
||||
await useServersFetch('/transfers/schedule/servers', {
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: {
|
||||
server_ids: parsedServerIds.value,
|
||||
scheduled_at: scheduledAt,
|
||||
target_region: selectedRegion.value || undefined,
|
||||
node_tags: selectedTags.value.length > 0 ? selectedTags.value : undefined,
|
||||
reason: reason.value.trim(),
|
||||
},
|
||||
})
|
||||
} else {
|
||||
await useServersFetch('/transfers/schedule/nodes', {
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: {
|
||||
node_hostnames: selectedNodes.value.slice(),
|
||||
scheduled_at: scheduledAt,
|
||||
target_region: selectedRegion.value || undefined,
|
||||
node_tags: selectedTags.value.length > 0 ? selectedTags.value : undefined,
|
||||
reason: reason.value.trim(),
|
||||
cordon_nodes: cordonNodes.value,
|
||||
tag_nodes: tagNodes.value.trim() || undefined,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
addNotification({ title: 'Transfer scheduled', type: 'success' })
|
||||
emit('success')
|
||||
modal.value?.hide()
|
||||
} catch (err: any) {
|
||||
addNotification({
|
||||
title: 'Error scheduling transfer',
|
||||
text: err?.data?.description ?? err?.message ?? String(err),
|
||||
type: 'error',
|
||||
})
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
hide,
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,86 @@
|
||||
<script setup lang="ts">
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
normalizeChildren,
|
||||
PagewideBanner,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const flags = useFeatureFlags()
|
||||
const config = useRuntimeConfig()
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'layout.banner.preview.title',
|
||||
defaultMessage: `This is a preview deploy of the Modrinth website.`,
|
||||
},
|
||||
description: {
|
||||
id: 'layout.banner.preview.description',
|
||||
defaultMessage: `If you meant to access the official Modrinth website, visit <link>https://modrinth.com</link>. This preview deploy is used by Modrinth staff for testing purposes. It was built using <branch-link>{owner}/{branch}</branch-link> @ {commit}.`,
|
||||
},
|
||||
})
|
||||
|
||||
function hidePreviewBanner() {
|
||||
flags.value.hidePreviewBanner = true
|
||||
saveFeatureFlags()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PagewideBanner v-if="!flags.hidePreviewBanner" variant="info">
|
||||
<template #title>
|
||||
<span>{{ formatMessage(messages.title) }}</span>
|
||||
</template>
|
||||
<template #description>
|
||||
<span>
|
||||
<IntlFormatted
|
||||
:message-id="messages.description"
|
||||
:values="{
|
||||
owner: config.public.owner,
|
||||
branch: config.public.branch,
|
||||
}"
|
||||
>
|
||||
<template #link="{ children }">
|
||||
<a href="https://modrinth.com" target="_blank" rel="noopener" class="text-link">
|
||||
<component :is="() => normalizeChildren(children)" />
|
||||
</a>
|
||||
</template>
|
||||
<template #branch-link="{ children }">
|
||||
<a
|
||||
:href="`https://github.com/${config.public.owner}/code/tree/${config.public.branch}`"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="hover:underline"
|
||||
>
|
||||
<component :is="() => normalizeChildren(children)" />
|
||||
</a>
|
||||
</template>
|
||||
<template #commit>
|
||||
<span v-if="config.public.hash === 'unknown'">unknown</span>
|
||||
<a
|
||||
v-else
|
||||
:href="`https://github.com/${config.public.owner}/code/commit/${config.public.hash}`"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
class="text-link"
|
||||
>
|
||||
{{ config.public.hash }}
|
||||
</a>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
</span>
|
||||
</template>
|
||||
<template #actions_right>
|
||||
<ButtonStyled type="transparent" circular>
|
||||
<button :aria-label="formatMessage(commonMessages.closeButton)" @click="hidePreviewBanner">
|
||||
<XIcon aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
</PagewideBanner>
|
||||
</template>
|
||||
@@ -286,7 +286,7 @@ const flipLegend = (legend, newVal) => {
|
||||
}
|
||||
|
||||
const resetChart = () => {
|
||||
if (!chart.value) return
|
||||
if (!chart.value?.chart) return
|
||||
chart.value.updateSeries([...props.data])
|
||||
chart.value.updateOptions({
|
||||
xaxis: {
|
||||
|
||||
@@ -309,14 +309,13 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import { DownloadIcon, PaletteIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import { Button, Card, DropdownSelect } from '@modrinth/ui'
|
||||
import { formatCategoryHeader, formatMoney, formatNumber } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { UiChartsChart as Chart, UiChartsCompactChart as CompactChart } from '#components'
|
||||
import PaletteIcon from '~/assets/icons/palette.svg?component'
|
||||
import {
|
||||
analyticsSetToCSVString,
|
||||
countryCodeToFlag,
|
||||
|
||||
@@ -125,13 +125,14 @@ const chartOptions = {
|
||||
const chart = ref(null)
|
||||
|
||||
const resetChart = () => {
|
||||
chart.value?.updateSeries([...props.data])
|
||||
chart.value?.updateOptions({
|
||||
if (!chart.value?.chart) return
|
||||
chart.value.updateSeries([...props.data])
|
||||
chart.value.updateOptions({
|
||||
xaxis: {
|
||||
categories: props.labels,
|
||||
},
|
||||
})
|
||||
chart.value?.resetSeries()
|
||||
chart.value.resetSeries()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
+31
-4
@@ -1,15 +1,28 @@
|
||||
<template>
|
||||
<MultiStageModal ref="modal" :stages="ctx.stageConfigs" :context="ctx" />
|
||||
<MultiStageModal
|
||||
ref="modal"
|
||||
:stages="ctx.stageConfigs"
|
||||
:context="ctx"
|
||||
:breadcrumbs="!editingVersion"
|
||||
@hide="() => (modalOpen = false)"
|
||||
/>
|
||||
<DropArea
|
||||
v-if="!modalOpen"
|
||||
:accept="acceptFileFromProjectType(projectV2.project_type)"
|
||||
@change="handleDropArea"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
DropArea,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
MultiStageModal,
|
||||
} from '@modrinth/ui'
|
||||
import { acceptFileFromProjectType } from '@modrinth/utils'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
|
||||
import {
|
||||
@@ -17,12 +30,17 @@ import {
|
||||
provideManageVersionContext,
|
||||
} from '~/providers/version/manage-version-modal'
|
||||
|
||||
const modal = useTemplateRef<ComponentExposed<typeof MultiStageModal>>('modal')
|
||||
const emit = defineEmits<{
|
||||
(e: 'save'): void
|
||||
}>()
|
||||
|
||||
const ctx = createManageVersionContext(modal)
|
||||
const modal = useTemplateRef<ComponentExposed<typeof MultiStageModal>>('modal')
|
||||
const modalOpen = ref(false)
|
||||
|
||||
const ctx = createManageVersionContext(modal, () => emit('save'))
|
||||
provideManageVersionContext(ctx)
|
||||
|
||||
const { newDraftVersion } = ctx
|
||||
const { newDraftVersion, editingVersion, handleNewFiles } = ctx
|
||||
|
||||
const { projectV2 } = injectProjectPageContext()
|
||||
const { addNotification } = injectNotificationManager()
|
||||
@@ -64,6 +82,15 @@ function openCreateVersionModal(
|
||||
newDraftVersion(projectV2.value.id, version)
|
||||
modal.value?.setStage(stageId ?? 0)
|
||||
modal.value?.show()
|
||||
modalOpen.value = true
|
||||
}
|
||||
|
||||
async function handleDropArea(files: FileList) {
|
||||
newDraftVersion(projectV2.value.id, null)
|
||||
modal.value?.setStage(0)
|
||||
await handleNewFiles(Array.from(files))
|
||||
modal.value?.show()
|
||||
modalOpen.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
||||
+8
-6
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-between gap-2 rounded-xl bg-button-bg px-4 py-1 text-button-text"
|
||||
class="flex h-11 items-center justify-between gap-2 rounded-xl bg-button-bg px-4 py-1 text-button-text"
|
||||
>
|
||||
<div class="grid max-w-[75%] grid-cols-[auto_1fr_auto] items-center gap-2">
|
||||
<Avatar v-if="icon" :src="icon" alt="dependency-icon" size="20px" :no-shadow="true" />
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ name || 'Unknown Project' }}
|
||||
</span>
|
||||
|
||||
<TagItem class="shrink-0 border !border-solid border-surface-5">
|
||||
<TagItem class="shrink-0 border !border-solid border-surface-5 capitalize">
|
||||
{{ dependencyType }}
|
||||
</TagItem>
|
||||
</div>
|
||||
@@ -17,14 +17,15 @@
|
||||
<span
|
||||
v-if="versionName"
|
||||
v-tooltip="versionName"
|
||||
class="max-w-[35%] truncate whitespace-nowrap font-medium"
|
||||
class="truncate whitespace-nowrap font-medium"
|
||||
:class="!hideRemove ? 'max-w-[35%]' : 'max-w-[50%]'"
|
||||
>
|
||||
{{ versionName }}
|
||||
</span>
|
||||
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<div v-if="!hideRemove" class="flex items-center justify-end gap-1">
|
||||
<ButtonStyled size="standard" :circular="true">
|
||||
<button aria-label="Remove file" class="!shadow-none" @click="emitRemove">
|
||||
<button aria-label="Remove file" class="-mr-2 !shadow-none" @click="emitRemove">
|
||||
<XIcon aria-hidden="true" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
@@ -42,12 +43,13 @@ const emit = defineEmits<{
|
||||
(e: 'remove'): void
|
||||
}>()
|
||||
|
||||
const { projectId, name, icon, dependencyType, versionName } = defineProps<{
|
||||
const { projectId, name, icon, dependencyType, versionName, hideRemove } = defineProps<{
|
||||
projectId: string
|
||||
name?: string
|
||||
icon?: string
|
||||
dependencyType: Labrinth.Versions.v2.DependencyType
|
||||
versionName?: string
|
||||
hideRemove?: boolean
|
||||
}>()
|
||||
|
||||
function emitRemove() {
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<div v-if="addedDependencies.length" class="5 flex flex-col gap-2">
|
||||
<template v-for="(dependency, index) in addedDependencies">
|
||||
<AddedDependencyRow
|
||||
v-if="dependency"
|
||||
:key="index"
|
||||
:project-id="dependency.projectId"
|
||||
:name="dependency.name"
|
||||
:icon="dependency.icon"
|
||||
:dependency-type="dependency.dependencyType"
|
||||
:version-name="dependency.versionName"
|
||||
:hide-remove="disableRemove"
|
||||
@remove="() => removeDependency(index)"
|
||||
/>
|
||||
</template>
|
||||
<span v-if="!addedDependencies.length"> No dependencies added. </span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
import AddedDependencyRow from './AddedDependencyRow.vue'
|
||||
|
||||
const { disableRemove } = defineProps<{
|
||||
disableRemove?: boolean
|
||||
}>()
|
||||
|
||||
const { draftVersion, dependencyProjects, dependencyVersions, projectsFetchLoading } =
|
||||
injectManageVersionContext()
|
||||
|
||||
const addedDependencies = computed(() =>
|
||||
(draftVersion.value.dependencies || [])
|
||||
.map((dep) => {
|
||||
if (!dep.project_id) return null
|
||||
|
||||
const dependencyProject = dependencyProjects.value[dep.project_id]
|
||||
const versionName = dependencyVersions.value[dep.version_id || '']?.name ?? ''
|
||||
|
||||
if (!dependencyProject && projectsFetchLoading.value) return null
|
||||
|
||||
return {
|
||||
projectId: dep.project_id,
|
||||
name: dependencyProject?.name,
|
||||
icon: dependencyProject?.icon_url,
|
||||
dependencyType: dep.dependency_type,
|
||||
versionName,
|
||||
}
|
||||
})
|
||||
.filter(Boolean),
|
||||
)
|
||||
|
||||
const removeDependency = (index: number) => {
|
||||
if (!draftVersion.value.dependencies) return
|
||||
draftVersion.value.dependencies.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
@@ -27,8 +27,8 @@
|
||||
"
|
||||
:style="`--_color: var(--color-platform-${loader.name})`"
|
||||
>
|
||||
<div v-html="loader.icon"></div>
|
||||
{{ formatCategory(loader.name) }}
|
||||
<component :is="getLoaderIcon(loader.name)" v-if="getLoaderIcon(loader.name)" />
|
||||
<FormattedTag :tag="loader.name" enforce-type="loader" />
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,8 +40,8 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { Chips, TagItem } from '@modrinth/ui'
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
import { getLoaderIcon } from '@modrinth/assets'
|
||||
import { Chips, FormattedTag, TagItem } from '@modrinth/ui'
|
||||
|
||||
const selectedLoaders = defineModel<string[]>({ default: [] })
|
||||
|
||||
@@ -118,4 +118,17 @@ function groupLoaders(loaders: Labrinth.Tags.v2.Loader[]) {
|
||||
}
|
||||
|
||||
const groupedLoaders = computed(() => groupLoaders(loaders))
|
||||
|
||||
onMounted(() => {
|
||||
if (selectedLoaders.value.length === 0) return
|
||||
|
||||
// Find the first group that contains any of the selected loaders
|
||||
const groups = groupedLoaders.value
|
||||
for (const [groupName, loadersInGroup] of Object.entries(groups)) {
|
||||
if (loadersInGroup.some((loader) => selectedLoaders.value.includes(loader.name))) {
|
||||
loaderGroup.value = groupName as GroupLabels
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+33
-2
@@ -66,7 +66,7 @@ import type { Labrinth } from '@modrinth/api-client'
|
||||
import { SearchIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, Chips } from '@modrinth/ui'
|
||||
import { useMagicKeys } from '@vueuse/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
||||
|
||||
type GameVersion = Labrinth.Tags.v2.GameVersion
|
||||
|
||||
@@ -147,9 +147,15 @@ function groupVersions(gameVersions: GameVersion[]) {
|
||||
)
|
||||
|
||||
const getGroupKey = (v: string) => v.split('.').slice(0, 2).join('.')
|
||||
|
||||
const getSnapshotGroupKey = (v: string) => {
|
||||
const cleanVersion = v.split('-')[0]
|
||||
return cleanVersion.split('.').slice(0, 2).join('.')
|
||||
}
|
||||
|
||||
const groups: Record<string, string[]> = {}
|
||||
|
||||
let currentGroupKey = getGroupKey(gameVersions.find((v) => v.major)?.version || '')
|
||||
let currentGroupKey
|
||||
|
||||
gameVersions.forEach((gameVersion) => {
|
||||
if (gameVersion.version_type === 'release') {
|
||||
@@ -157,6 +163,8 @@ function groupVersions(gameVersions: GameVersion[]) {
|
||||
if (!groups[currentGroupKey]) groups[currentGroupKey] = []
|
||||
groups[currentGroupKey].push(gameVersion.version)
|
||||
} else {
|
||||
if (!currentGroupKey) currentGroupKey = getSnapshotGroupKey(gameVersion.version)
|
||||
|
||||
const key = `${currentGroupKey} ${DEV_RELEASE_KEY}`
|
||||
if (!groups[key]) groups[key] = []
|
||||
groups[key].push(gameVersion.version)
|
||||
@@ -205,4 +213,27 @@ function compareGroupKeys(a: string, b: string) {
|
||||
function searchFilter(gameVersion: Labrinth.Tags.v2.GameVersion) {
|
||||
return gameVersion.version.toLowerCase().includes(searchQuery.value.toLowerCase())
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.modelValue.length === 0) return
|
||||
|
||||
// Open non-release tab if any non-release versions are selected
|
||||
const hasNonReleaseVersions = props.gameVersions.some(
|
||||
(v) => props.modelValue.includes(v.version) && v.version_type !== 'release',
|
||||
)
|
||||
|
||||
if (hasNonReleaseVersions) {
|
||||
versionType.value = 'all'
|
||||
}
|
||||
|
||||
await nextTick()
|
||||
const firstSelectedVersion = allVersionsFlat.value.find((v) => props.modelValue.includes(v))
|
||||
if (firstSelectedVersion) {
|
||||
const buttons = Array.from(document.querySelectorAll('button'))
|
||||
const element = buttons.find((btn) => btn.textContent?.trim() === firstSelectedVersion)
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+21
-45
@@ -1,27 +1,24 @@
|
||||
<template>
|
||||
<div v-if="visibleDependencies.length" class="flex flex-col gap-4">
|
||||
<span class="font-semibold text-contrast">Suggested dependencies</span>
|
||||
<div class="flex flex-col gap-2">
|
||||
<template v-for="(dependency, index) in visibleDependencies">
|
||||
<SuggestedDependency
|
||||
v-if="dependency"
|
||||
:key="index"
|
||||
:project-id="dependency.project_id"
|
||||
:name="dependency.name"
|
||||
:icon="dependency.icon"
|
||||
:dependency-type="dependency.dependency_type"
|
||||
:version-name="dependency.versionName"
|
||||
@on-add-suggestion="
|
||||
() =>
|
||||
handleAddSuggestion({
|
||||
dependency_type: dependency.dependency_type,
|
||||
project_id: dependency.project_id,
|
||||
version_id: dependency.version_id,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<div v-if="visibleSuggestedDependencies.length" class="flex flex-col gap-2">
|
||||
<template v-for="(dependency, index) in visibleSuggestedDependencies">
|
||||
<SuggestedDependency
|
||||
v-if="dependency"
|
||||
:key="index"
|
||||
:project-id="dependency.project_id"
|
||||
:name="dependency.name"
|
||||
:icon="dependency.icon"
|
||||
:dependency-type="dependency.dependency_type"
|
||||
:version-name="dependency.versionName"
|
||||
@on-add-suggestion="
|
||||
() =>
|
||||
handleAddSuggestion({
|
||||
dependency_type: dependency.dependency_type,
|
||||
project_id: dependency.project_id,
|
||||
version_id: dependency.version_id,
|
||||
})
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -32,28 +29,7 @@ import { injectManageVersionContext } from '~/providers/version/manage-version-m
|
||||
|
||||
import SuggestedDependency from './SuggestedDependency.vue'
|
||||
|
||||
export interface SuggestedDependency extends Labrinth.Versions.v3.Dependency {
|
||||
icon?: string
|
||||
name?: string
|
||||
versionName?: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
suggestedDependencies: SuggestedDependency[]
|
||||
}>()
|
||||
|
||||
const { draftVersion } = injectManageVersionContext()
|
||||
|
||||
const visibleDependencies = computed<SuggestedDependency[]>(() =>
|
||||
props.suggestedDependencies
|
||||
.filter(
|
||||
(dep) =>
|
||||
!draftVersion.value.dependencies?.some(
|
||||
(d) => d.project_id === dep.project_id && d.version_id === dep.version_id,
|
||||
),
|
||||
)
|
||||
.sort((a, b) => (a.name || '').localeCompare(b.name || '')),
|
||||
)
|
||||
const { visibleSuggestedDependencies } = injectManageVersionContext()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'onAddSuggestion', dependency: Labrinth.Versions.v3.Dependency): void
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-between gap-2 rounded-xl bg-button-bg px-4 py-1 text-button-text"
|
||||
class="flex items-center justify-between gap-2 rounded-xl border-2 border-dashed border-surface-5 px-4 py-1 text-button-text"
|
||||
>
|
||||
<div class="grid max-w-[75%] grid-cols-[auto_1fr_auto] items-center gap-2">
|
||||
<Avatar v-if="icon" :src="icon" alt="dependency-icon" size="20px" :no-shadow="true" />
|
||||
@@ -9,7 +9,7 @@
|
||||
{{ name || 'Unknown Project' }}
|
||||
</span>
|
||||
|
||||
<TagItem class="shrink-0 border !border-solid border-surface-5">
|
||||
<TagItem class="shrink-0 border !border-solid border-surface-5 capitalize">
|
||||
{{ dependencyType }}
|
||||
</TagItem>
|
||||
</div>
|
||||
@@ -23,7 +23,7 @@
|
||||
</span>
|
||||
|
||||
<div class="flex items-center justify-end gap-1">
|
||||
<ButtonStyled size="standard" :circular="true">
|
||||
<ButtonStyled size="standard" :circular="true" type="transparent">
|
||||
<button aria-label="Add dependency" class="!shadow-none" @click="emitAddSuggestion">
|
||||
<PlusIcon aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
+30
-11
@@ -68,10 +68,16 @@
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { ArrowLeftRightIcon, CheckIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, Combobox, injectProjectPageContext } from '@modrinth/ui'
|
||||
import type { DropdownOption } from '@modrinth/ui/src/components/base/Combobox.vue'
|
||||
import type { ComboboxOption } from '@modrinth/ui/src/components/base/Combobox.vue'
|
||||
import { acceptFileFromProjectType } from '@modrinth/utils'
|
||||
|
||||
import {
|
||||
fileTypeLabels,
|
||||
injectManageVersionContext,
|
||||
} from '~/providers/version/manage-version-modal'
|
||||
|
||||
const { projectV2 } = injectProjectPageContext()
|
||||
const { projectType } = injectManageVersionContext()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'setPrimaryFile', file?: File): void
|
||||
@@ -89,16 +95,29 @@ const { name, isPrimary, onRemove, initialFileType, editingVersion } = definePro
|
||||
const selectedType = ref<Labrinth.Versions.v3.FileType | 'primary'>(initialFileType || 'unknown')
|
||||
const primaryFileInput = ref<HTMLInputElement>()
|
||||
|
||||
const versionTypes = [
|
||||
!editingVersion && { class: 'text-sm', value: 'primary', label: 'Primary' },
|
||||
{ class: 'text-sm', value: 'unknown', label: 'Other' },
|
||||
{ class: 'text-sm', value: 'required-resource-pack', label: 'Required RP' },
|
||||
{ class: 'text-sm', value: 'optional-resource-pack', label: 'Optional RP' },
|
||||
{ class: 'text-sm', value: 'sources-jar', label: 'Sources JAR' },
|
||||
{ class: 'text-sm', value: 'dev-jar', label: 'Dev JAR' },
|
||||
{ class: 'text-sm', value: 'javadoc-jar', label: 'Javadoc JAR' },
|
||||
{ class: 'text-sm', value: 'signature', label: 'Signature' },
|
||||
].filter(Boolean) as DropdownOption<Labrinth.Versions.v3.FileType | 'primary'>[]
|
||||
const isDatapackProject = computed(() => projectType.value === 'datapack')
|
||||
|
||||
const versionTypes = computed(
|
||||
() =>
|
||||
[
|
||||
!editingVersion && { class: 'text-sm', value: 'primary', label: fileTypeLabels.primary },
|
||||
{ class: 'text-sm', value: 'unknown', label: fileTypeLabels.unknown },
|
||||
isDatapackProject.value && {
|
||||
class: 'text-sm',
|
||||
value: 'required-resource-pack',
|
||||
label: fileTypeLabels['required-resource-pack'],
|
||||
},
|
||||
isDatapackProject.value && {
|
||||
class: 'text-sm',
|
||||
value: 'optional-resource-pack',
|
||||
label: fileTypeLabels['optional-resource-pack'],
|
||||
},
|
||||
{ class: 'text-sm', value: 'sources-jar', label: fileTypeLabels['sources-jar'] },
|
||||
{ class: 'text-sm', value: 'dev-jar', label: fileTypeLabels['dev-jar'] },
|
||||
{ class: 'text-sm', value: 'javadoc-jar', label: fileTypeLabels['javadoc-jar'] },
|
||||
{ class: 'text-sm', value: 'signature', label: fileTypeLabels.signature },
|
||||
].filter(Boolean) as ComboboxOption<Labrinth.Versions.v3.FileType | 'primary'>[],
|
||||
)
|
||||
|
||||
function emitFileTypeChange() {
|
||||
if (selectedType.value === 'primary') emit('setPrimaryFile')
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-between gap-2 rounded-xl bg-button-bg px-4 py-2 text-button-text"
|
||||
>
|
||||
<div class="flex items-center gap-2 overflow-hidden">
|
||||
<FileIcon v-if="isPrimary" class="text-lg" />
|
||||
<FilePlusIcon v-else class="text-lg" />
|
||||
|
||||
<span v-tooltip="name" class="overflow-hidden text-ellipsis whitespace-nowrap font-medium">
|
||||
{{ name }}
|
||||
</span>
|
||||
|
||||
<TagItem class="shrink-0 border !border-solid border-surface-5">
|
||||
{{ isPrimary ? 'Primary' : fileTypeLabels[fileType ?? 'unknown'] }}
|
||||
</TagItem>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { FileIcon, FilePlusIcon } from '@modrinth/assets'
|
||||
import { TagItem } from '@modrinth/ui'
|
||||
|
||||
import { fileTypeLabels } from '~/providers/version/manage-version-modal'
|
||||
|
||||
const { name, isPrimary, fileType } = defineProps<{
|
||||
name: string
|
||||
isPrimary?: boolean
|
||||
fileType?: Labrinth.Versions.v3.FileType | 'primary'
|
||||
}>()
|
||||
</script>
|
||||
@@ -1,23 +0,0 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<MarkdownEditor
|
||||
v-model="draftVersion.changelog"
|
||||
:on-image-upload="onImageUpload"
|
||||
:max-height="500"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { MarkdownEditor } from '@modrinth/ui'
|
||||
|
||||
import { useImageUpload } from '~/composables/image-upload.ts'
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
const { draftVersion } = injectManageVersionContext()
|
||||
|
||||
async function onImageUpload(file: File) {
|
||||
const response = await useImageUpload(file, { context: 'version' })
|
||||
return response.url
|
||||
}
|
||||
</script>
|
||||
@@ -1,272 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6 sm:w-[512px]">
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">
|
||||
Version type <span class="text-red">*</span>
|
||||
</span>
|
||||
<Chips
|
||||
v-model="draftVersion.version_type"
|
||||
:items="['release', 'beta', 'alpha']"
|
||||
:never-empty="true"
|
||||
:capitalize="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">
|
||||
Version number <span class="text-red">*</span>
|
||||
</span>
|
||||
<input
|
||||
id="version-number"
|
||||
v-model="draftVersion.version_number"
|
||||
placeholder="Enter version number, e.g. 1.2.3-alpha.1"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
maxlength="32"
|
||||
/>
|
||||
<span> The version number differentiates this specific version from others. </span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast"> Version subtitle </span>
|
||||
<input
|
||||
id="version-number"
|
||||
v-model="draftVersion.name"
|
||||
placeholder="Enter subtitle..."
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
maxlength="256"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-if="!noLoadersProject && (inferredVersionData?.loaders?.length || editingVersion)">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ usingDetectedLoaders ? 'Detected loaders' : 'Loaders' }}
|
||||
</span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button
|
||||
v-tooltip="isModpack ? 'Modpack versions cannot be edited' : undefined"
|
||||
:disabled="isModpack"
|
||||
@click="editLoaders"
|
||||
>
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-1.5 gap-y-4 rounded-xl border border-solid border-surface-5 p-3 py-4"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<template
|
||||
v-for="loader in draftVersionLoaders.map((selectedLoader) =>
|
||||
loaders.find((loader) => selectedLoader === loader.name),
|
||||
)"
|
||||
>
|
||||
<TagItem
|
||||
v-if="loader"
|
||||
:key="`loader-${loader.name}`"
|
||||
class="border !border-solid border-surface-5 hover:no-underline"
|
||||
:style="`--_color: var(--color-platform-${loader.name})`"
|
||||
>
|
||||
<div v-html="loader.icon"></div>
|
||||
{{ formatCategory(loader.name) }}
|
||||
</TagItem>
|
||||
</template>
|
||||
|
||||
<span v-if="!draftVersion.loaders.length">No loaders selected.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="inferredVersionData?.game_versions?.length || editingVersion">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ usingDetectedVersions ? 'Detected versions' : 'Versions' }}
|
||||
</span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button
|
||||
v-tooltip="isModpack ? 'Modpack versions cannot be edited' : undefined"
|
||||
:disabled="isModpack"
|
||||
@click="editVersions"
|
||||
>
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex max-h-56 flex-col gap-1.5 gap-y-4 overflow-y-auto rounded-xl border border-solid border-surface-5 p-3 py-4"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<TagItem
|
||||
v-for="version in draftVersion.game_versions"
|
||||
:key="version"
|
||||
class="border !border-solid border-surface-5 hover:no-underline"
|
||||
>
|
||||
{{ version }}
|
||||
</TagItem>
|
||||
|
||||
<span v-if="!draftVersion.game_versions.length">No versions selected.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template
|
||||
v-if="
|
||||
!noEnvironmentProject &&
|
||||
((!editingVersion && inferredVersionData?.environment) ||
|
||||
(editingVersion && draftVersion.environment))
|
||||
"
|
||||
>
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast"> Environment </span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button @click="editEnvironment">
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5 gap-y-4 rounded-xl bg-surface-2 p-3 py-4">
|
||||
<div v-if="draftVersion.environment" class="flex flex-col gap-1">
|
||||
<div class="font-semibold text-contrast">
|
||||
{{ environmentCopy.title }}
|
||||
</div>
|
||||
<div class="text-sm font-medium">{{ environmentCopy.description }}</div>
|
||||
</div>
|
||||
|
||||
<span v-else class="text-sm font-medium">No environment has been set.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { EditIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Chips,
|
||||
defineMessages,
|
||||
ENVIRONMENTS_COPY,
|
||||
TagItem,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
|
||||
import { useGeneratedState } from '~/composables/generated'
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
const {
|
||||
draftVersion,
|
||||
inferredVersionData,
|
||||
projectType,
|
||||
editingVersion,
|
||||
noLoadersProject,
|
||||
noEnvironmentProject,
|
||||
modal,
|
||||
} = injectManageVersionContext()
|
||||
|
||||
const generatedState = useGeneratedState()
|
||||
const loaders = computed(() => generatedState.value.loaders)
|
||||
const isModpack = computed(() => projectType.value === 'modpack')
|
||||
|
||||
const draftVersionLoaders = computed(() =>
|
||||
[
|
||||
...new Set([...draftVersion.value.loaders, ...(draftVersion.value.mrpack_loaders ?? [])]),
|
||||
].filter((loader) => loader !== 'mrpack'),
|
||||
)
|
||||
|
||||
const editLoaders = () => {
|
||||
modal.value?.setStage('from-details-loaders')
|
||||
}
|
||||
const editVersions = () => {
|
||||
modal.value?.setStage('from-details-mc-versions')
|
||||
}
|
||||
const editEnvironment = () => {
|
||||
modal.value?.setStage('from-details-environment')
|
||||
}
|
||||
|
||||
const usingDetectedVersions = computed(() => {
|
||||
if (!inferredVersionData.value?.game_versions) return false
|
||||
|
||||
const versionsMatch =
|
||||
draftVersion.value.game_versions.length === inferredVersionData.value.game_versions.length &&
|
||||
draftVersion.value.game_versions.every((version) =>
|
||||
inferredVersionData.value?.game_versions?.includes(version),
|
||||
)
|
||||
|
||||
return versionsMatch
|
||||
})
|
||||
|
||||
const usingDetectedLoaders = computed(() => {
|
||||
if (!inferredVersionData.value?.loaders) return false
|
||||
|
||||
const loadersMatch =
|
||||
draftVersion.value.loaders.length === inferredVersionData.value.loaders.length &&
|
||||
draftVersion.value.loaders.every((loader) =>
|
||||
inferredVersionData.value?.loaders?.includes(loader),
|
||||
)
|
||||
|
||||
return loadersMatch
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const noEnvironmentMessage = defineMessages({
|
||||
title: {
|
||||
id: 'version.environment.none.title',
|
||||
defaultMessage: 'No environment set',
|
||||
},
|
||||
description: {
|
||||
id: 'version.environment.none.description',
|
||||
defaultMessage: 'The environment for this version has not been specified.',
|
||||
},
|
||||
})
|
||||
|
||||
const unknownEnvironmentMessage = defineMessages({
|
||||
title: {
|
||||
id: 'version.environment.unknown.title',
|
||||
defaultMessage: 'Unknown environment',
|
||||
},
|
||||
description: {
|
||||
id: 'version.environment.unknown.description',
|
||||
defaultMessage: 'The environment: "{environment}" is not recognized.',
|
||||
},
|
||||
})
|
||||
|
||||
const environmentCopy = computed(() => {
|
||||
if (!draftVersion.value.environment) {
|
||||
return {
|
||||
title: formatMessage(noEnvironmentMessage.title),
|
||||
description: formatMessage(noEnvironmentMessage.description),
|
||||
}
|
||||
}
|
||||
|
||||
const envCopy = ENVIRONMENTS_COPY[draftVersion.value.environment]
|
||||
if (envCopy) {
|
||||
return {
|
||||
title: formatMessage(envCopy.title),
|
||||
description: formatMessage(envCopy.description),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title: formatMessage(unknownEnvironmentMessage.title),
|
||||
description: formatMessage(unknownEnvironmentMessage.description, {
|
||||
environment: draftVersion.value.environment,
|
||||
}),
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,11 +1,15 @@
|
||||
<template>
|
||||
<div class="flex w-full flex-col gap-4 sm:w-[512px]">
|
||||
<template v-if="!(filesToAdd.length || draftVersion.existing_files?.length)">
|
||||
<div class="flex w-full flex-col gap-4">
|
||||
<template
|
||||
v-if="handlingNewFiles || !(filesToAdd.length || draftVersion.existing_files?.length)"
|
||||
>
|
||||
<DropzoneFileInput
|
||||
aria-label="Upload file"
|
||||
multiple
|
||||
:accept="acceptFileFromProjectType(projectV2.project_type)"
|
||||
:max-size="524288000"
|
||||
primary-prompt="Upload primary and supporting files"
|
||||
secondary-prompt="Drag and drop files or click to browse"
|
||||
@change="handleNewFiles"
|
||||
/>
|
||||
</template>
|
||||
@@ -21,11 +25,7 @@
|
||||
:is-primary="true"
|
||||
:editing-version="editingVersion"
|
||||
:on-remove="undefined"
|
||||
@set-primary-file="
|
||||
(file) => {
|
||||
if (file && !editingVersion) filesToAdd[0] = { file }
|
||||
}
|
||||
"
|
||||
@set-primary-file="(file) => file && replacePrimaryFile(file)"
|
||||
/>
|
||||
</div>
|
||||
<span>
|
||||
@@ -72,7 +72,7 @@
|
||||
:editing-version="editingVersion"
|
||||
:on-remove="() => handleRemoveFile(idx + (primaryFile?.existing ? 0 : 1))"
|
||||
@set-file-type="(type) => (versionFile.fileType = type)"
|
||||
@set-primary-file="handleSetPrimaryFile(idx + (primaryFile?.existing ? 0 : 1))"
|
||||
@set-primary-file="() => swapPrimaryFile(idx + (primaryFile?.existing ? 0 : 1))"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -86,7 +86,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
Admonition,
|
||||
defineMessages,
|
||||
@@ -107,68 +106,18 @@ const {
|
||||
draftVersion,
|
||||
filesToAdd,
|
||||
existingFilesToDelete,
|
||||
setPrimaryFile,
|
||||
setInferredVersionData,
|
||||
handlingNewFiles,
|
||||
swapPrimaryFile,
|
||||
replacePrimaryFile,
|
||||
editingVersion,
|
||||
primaryFile,
|
||||
handleNewFiles,
|
||||
} = injectManageVersionContext()
|
||||
|
||||
const addDetectedData = async () => {
|
||||
if (editingVersion.value) return
|
||||
|
||||
const primaryFile = filesToAdd.value[0]?.file
|
||||
if (!primaryFile) return
|
||||
|
||||
try {
|
||||
const inferredData = await setInferredVersionData(primaryFile, projectV2.value)
|
||||
const mappedInferredData: Partial<Labrinth.Versions.v3.DraftVersion> = {
|
||||
...inferredData,
|
||||
name: inferredData.name || '',
|
||||
}
|
||||
|
||||
draftVersion.value = {
|
||||
...draftVersion.value,
|
||||
...mappedInferredData,
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error parsing version file data', err)
|
||||
}
|
||||
}
|
||||
|
||||
// add detected data when the primary file changes
|
||||
watch(
|
||||
() => filesToAdd.value[0]?.file,
|
||||
() => addDetectedData(),
|
||||
)
|
||||
|
||||
function handleNewFiles(newFiles: File[]) {
|
||||
// detect primary file if no primary file is set
|
||||
const primaryFileIndex = primaryFile.value ? null : detectPrimaryFileIndex(newFiles)
|
||||
|
||||
newFiles.forEach((file) => filesToAdd.value.push({ file }))
|
||||
|
||||
if (primaryFileIndex !== null) {
|
||||
if (primaryFileIndex) setPrimaryFile(primaryFileIndex)
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemoveFile(index: number) {
|
||||
filesToAdd.value.splice(index, 1)
|
||||
}
|
||||
|
||||
function detectPrimaryFileIndex(files: File[]): number {
|
||||
const extensionPriority = ['.jar', '.zip', '.litemod', '.mrpack', '.mrpack-primary']
|
||||
|
||||
for (const ext of extensionPriority) {
|
||||
const matches = files.filter((file) => file.name.toLowerCase().endsWith(ext))
|
||||
if (matches.length > 0) {
|
||||
const shortest = matches.reduce((a, b) => (a.name.length < b.name.length ? a : b))
|
||||
return files.indexOf(shortest)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function handleRemoveExistingFile(sha1: string) {
|
||||
existingFilesToDelete.value.push(sha1)
|
||||
draftVersion.value.existing_files = draftVersion.value.existing_files?.filter(
|
||||
@@ -176,38 +125,6 @@ function handleRemoveExistingFile(sha1: string) {
|
||||
)
|
||||
}
|
||||
|
||||
function handleSetPrimaryFile(index: number) {
|
||||
setPrimaryFile(index)
|
||||
}
|
||||
|
||||
interface PrimaryFile {
|
||||
name: string
|
||||
fileType?: string
|
||||
existing?: boolean
|
||||
}
|
||||
|
||||
const primaryFile = computed<PrimaryFile | null>(() => {
|
||||
const existingPrimaryFile = draftVersion.value.existing_files?.[0]
|
||||
if (existingPrimaryFile) {
|
||||
return {
|
||||
name: existingPrimaryFile.filename,
|
||||
fileType: existingPrimaryFile.file_type,
|
||||
existing: true,
|
||||
}
|
||||
}
|
||||
|
||||
const addedPrimaryFile = filesToAdd.value[0]
|
||||
if (addedPrimaryFile) {
|
||||
return {
|
||||
name: addedPrimaryFile.file.name,
|
||||
fileType: addedPrimaryFile.fileType,
|
||||
existing: false,
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
const supplementaryNewFiles = computed(() => {
|
||||
if (primaryFile.value?.existing) {
|
||||
return filesToAdd.value
|
||||
|
||||
+26
-127
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="flex w-full max-w-full flex-col gap-6 sm:w-[512px]">
|
||||
<div class="flex w-full max-w-full flex-col gap-6">
|
||||
<div class="flex flex-col gap-4">
|
||||
<span class="font-semibold text-contrast">Add dependency</span>
|
||||
<div class="flex flex-col gap-3 rounded-2xl border border-solid border-surface-5 p-4">
|
||||
<div class="grid gap-2.5">
|
||||
<span class="font-semibold text-contrast">Project <span class="text-red">*</span></span>
|
||||
<span class="font-semibold text-contrast">Project</span>
|
||||
<DependencySelect v-model="newDependencyProjectId" />
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ButtonStyled>
|
||||
<ButtonStyled color="green">
|
||||
<button
|
||||
class="self-start"
|
||||
:disabled="!newDependencyProjectId"
|
||||
@@ -55,28 +55,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SuggestedDependencies
|
||||
:suggested-dependencies="suggestedDependencies"
|
||||
@on-add-suggestion="handleAddSuggestedDependency"
|
||||
/>
|
||||
<div v-if="visibleSuggestedDependencies.length" class="flex flex-col gap-4">
|
||||
<span class="font-semibold text-contrast">Suggested dependencies</span>
|
||||
<SuggestedDependencies @on-add-suggestion="handleAddSuggestedDependency" />
|
||||
</div>
|
||||
|
||||
<div v-if="addedDependencies.length" class="flex flex-col gap-4">
|
||||
<span class="font-semibold text-contrast">Added dependencies</span>
|
||||
<div class="5 flex flex-col gap-2">
|
||||
<template v-for="(dependency, index) in addedDependencies">
|
||||
<AddedDependencyRow
|
||||
v-if="dependency"
|
||||
:key="index"
|
||||
:project-id="dependency.projectId"
|
||||
:name="dependency.name"
|
||||
:icon="dependency.icon"
|
||||
:dependency-type="dependency.dependencyType"
|
||||
:version-name="dependency.versionName"
|
||||
@remove="() => removeDependency(index)"
|
||||
/>
|
||||
</template>
|
||||
<span v-if="!addedDependencies.length"> No dependencies added. </span>
|
||||
</div>
|
||||
<DependenciesList />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -88,19 +74,26 @@ import {
|
||||
Combobox,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
} from '@modrinth/ui'
|
||||
import type { DropdownOption } from '@modrinth/ui/src/components/base/Combobox.vue'
|
||||
import type { ComboboxOption } from '@modrinth/ui/src/components/base/Combobox.vue'
|
||||
|
||||
import DependencySelect from '~/components/ui/create-project-version/components/DependencySelect.vue'
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
import AddedDependencyRow from '../components/AddedDependencyRow.vue'
|
||||
import DependenciesList from '../components/DependenciesList.vue'
|
||||
import SuggestedDependencies from '../components/SuggestedDependencies/SuggestedDependencies.vue'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const { labrinth } = injectModrinthClient()
|
||||
|
||||
const {
|
||||
draftVersion,
|
||||
dependencyProjects,
|
||||
dependencyVersions,
|
||||
projectsFetchLoading,
|
||||
visibleSuggestedDependencies,
|
||||
} = injectManageVersionContext()
|
||||
|
||||
const errorNotification = (err: any) => {
|
||||
addNotification({
|
||||
title: 'An error occurred',
|
||||
@@ -113,12 +106,7 @@ const newDependencyProjectId = ref<string>()
|
||||
const newDependencyType = ref<Labrinth.Versions.v2.DependencyType>('required')
|
||||
const newDependencyVersionId = ref<string | null>(null)
|
||||
|
||||
const newDependencyVersions = ref<DropdownOption<string>[]>([])
|
||||
|
||||
const projectsFetchLoading = ref(false)
|
||||
const suggestedDependencies = ref<
|
||||
Array<Labrinth.Versions.v3.Dependency & { name?: string; icon?: string; versionName?: string }>
|
||||
>([])
|
||||
const newDependencyVersions = ref<ComboboxOption<string>[]>([])
|
||||
|
||||
// reset to defaults when select different project
|
||||
watch(newDependencyProjectId, async () => {
|
||||
@@ -140,91 +128,6 @@ watch(newDependencyProjectId, async () => {
|
||||
}
|
||||
})
|
||||
|
||||
const { draftVersion, dependencyProjects, dependencyVersions, getProject, getVersion } =
|
||||
injectManageVersionContext()
|
||||
const { projectV2: project } = injectProjectPageContext()
|
||||
|
||||
const getSuggestedDependencies = async () => {
|
||||
try {
|
||||
suggestedDependencies.value = []
|
||||
|
||||
if (!draftVersion.value.game_versions?.length || !draftVersion.value.loaders?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const versions = await labrinth.versions_v3.getProjectVersions(project.value.id, {
|
||||
loaders: draftVersion.value.loaders,
|
||||
})
|
||||
|
||||
// Get the most recent matching version and extract its dependencies
|
||||
if (versions.length > 0) {
|
||||
const mostRecentVersion = versions[0]
|
||||
for (const dep of mostRecentVersion.dependencies) {
|
||||
suggestedDependencies.value.push({
|
||||
project_id: dep.project_id,
|
||||
version_id: dep.version_id,
|
||||
dependency_type: dep.dependency_type,
|
||||
file_name: dep.file_name,
|
||||
})
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`Failed to get versions for project ${project.value.id}:`, error)
|
||||
}
|
||||
|
||||
for (const dep of suggestedDependencies.value) {
|
||||
try {
|
||||
if (dep.project_id) {
|
||||
const proj = await getProject(dep.project_id)
|
||||
dep.name = proj.name
|
||||
dep.icon = proj.icon_url
|
||||
}
|
||||
|
||||
if (dep.version_id) {
|
||||
const version = await getVersion(dep.version_id)
|
||||
dep.versionName = version.name
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`Failed to fetch project/version data for dependency:`, error)
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
errorNotification(error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getSuggestedDependencies()
|
||||
})
|
||||
|
||||
watch(
|
||||
draftVersion,
|
||||
async (draftVersion) => {
|
||||
const deps = draftVersion.dependencies || []
|
||||
|
||||
for (const dep of deps) {
|
||||
if (dep?.project_id) {
|
||||
try {
|
||||
await getProject(dep.project_id)
|
||||
} catch (error: any) {
|
||||
errorNotification(error)
|
||||
}
|
||||
}
|
||||
|
||||
if (dep?.version_id) {
|
||||
try {
|
||||
await getVersion(dep.version_id)
|
||||
} catch (error: any) {
|
||||
errorNotification(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
projectsFetchLoading.value = false
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
const addedDependencies = computed(() =>
|
||||
(draftVersion.value.dependencies || [])
|
||||
.map((dep) => {
|
||||
@@ -249,12 +152,13 @@ const addedDependencies = computed(() =>
|
||||
const addDependency = (dependency: Labrinth.Versions.v3.Dependency) => {
|
||||
if (!draftVersion.value.dependencies) draftVersion.value.dependencies = []
|
||||
|
||||
// already added
|
||||
if (
|
||||
draftVersion.value.dependencies.find(
|
||||
(d) => d.project_id === dependency.project_id && d.version_id === dependency.version_id,
|
||||
)
|
||||
) {
|
||||
const alreadyAdded = draftVersion.value.dependencies.some((existing) => {
|
||||
if (existing.project_id !== dependency.project_id) return false
|
||||
if (!existing.version_id && !dependency.version_id) return true
|
||||
return existing.version_id === dependency.version_id
|
||||
})
|
||||
|
||||
if (alreadyAdded) {
|
||||
addNotification({
|
||||
title: 'Dependency already added',
|
||||
text: 'You cannot add the same dependency twice.',
|
||||
@@ -268,11 +172,6 @@ const addDependency = (dependency: Labrinth.Versions.v3.Dependency) => {
|
||||
newDependencyProjectId.value = undefined
|
||||
}
|
||||
|
||||
const removeDependency = (index: number) => {
|
||||
if (!draftVersion.value.dependencies) return
|
||||
draftVersion.value.dependencies.splice(index, 1)
|
||||
}
|
||||
|
||||
const handleAddSuggestedDependency = (dependency: Labrinth.Versions.v3.Dependency) => {
|
||||
draftVersion.value.dependencies?.push({
|
||||
project_id: dependency.project_id,
|
||||
@@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<div class="flex w-full flex-col gap-6">
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">
|
||||
Version type <span class="text-red">*</span>
|
||||
</span>
|
||||
<Chips
|
||||
v-model="draftVersion.version_type"
|
||||
:items="['release', 'beta', 'alpha']"
|
||||
:never-empty="true"
|
||||
:capitalize="true"
|
||||
:disabled="isUploading"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">
|
||||
Version number <span class="text-red">*</span>
|
||||
</span>
|
||||
<input
|
||||
id="version-number"
|
||||
v-model="draftVersion.version_number"
|
||||
:disabled="isUploading"
|
||||
placeholder="Enter version number, e.g. 1.2.3-alpha.1"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
maxlength="32"
|
||||
/>
|
||||
<span> The version number differentiates this specific version from others. </span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast"> Version subtitle </span>
|
||||
<input
|
||||
id="version-number"
|
||||
v-model="draftVersion.name"
|
||||
placeholder="Enter subtitle..."
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
maxlength="256"
|
||||
:disabled="isUploading"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast"> Version changlog </span>
|
||||
|
||||
<div class="w-full">
|
||||
<MarkdownEditor
|
||||
v-model="draftVersion.changelog"
|
||||
:on-image-upload="onImageUpload"
|
||||
:min-height="150"
|
||||
:disabled="isUploading"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Chips, MarkdownEditor } from '@modrinth/ui'
|
||||
|
||||
import { useImageUpload } from '~/composables/image-upload.ts'
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
const { draftVersion, isUploading } = injectManageVersionContext()
|
||||
|
||||
async function onImageUpload(file: File) {
|
||||
const response = await useImageUpload(file, { context: 'version' })
|
||||
return response.url
|
||||
}
|
||||
</script>
|
||||
+5
-6
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="space-y-6 sm:w-[512px]">
|
||||
<div class="space-y-6">
|
||||
<LoaderPicker
|
||||
v-model="draftVersion.loaders"
|
||||
:loaders="generatedState.loaders"
|
||||
@@ -29,8 +29,8 @@
|
||||
class="border !border-solid border-surface-5 !transition-all hover:bg-button-bgHover hover:no-underline"
|
||||
:style="`--_color: var(--color-platform-${loader.name})`"
|
||||
>
|
||||
<div v-html="loader.icon"></div>
|
||||
{{ formatCategory(loader.name) }}
|
||||
<component :is="getLoaderIcon(loader.name)" v-if="getLoaderIcon(loader.name)" />
|
||||
<FormattedTag :tag="loader.name" enforce-type="loader" />
|
||||
<XIcon class="text-secondary" />
|
||||
</TagItem>
|
||||
</template>
|
||||
@@ -41,9 +41,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, TagItem } from '@modrinth/ui'
|
||||
import { formatCategory } from '@modrinth/utils'
|
||||
import { getLoaderIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, FormattedTag, TagItem } from '@modrinth/ui'
|
||||
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6 sm:w-[512px]">
|
||||
<div class="flex flex-col gap-6">
|
||||
<McVersionPicker v-model="draftVersion.game_versions" :game-versions="gameVersions" />
|
||||
<div v-if="draftVersion.game_versions.length" class="space-y-1">
|
||||
<div class="flex items-center justify-between">
|
||||
@@ -0,0 +1,380 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div v-if="!editingVersion" class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast"> Uploaded files </span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button @click="editFiles">
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<ViewOnlyFileRow
|
||||
v-if="primaryFile"
|
||||
:key="primaryFile.name"
|
||||
:name="primaryFile.name"
|
||||
:is-primary="true"
|
||||
/>
|
||||
<ViewOnlyFileRow
|
||||
v-for="file in supplementaryNewFiles"
|
||||
:key="file.file.name"
|
||||
:name="file.file.name"
|
||||
:file-type="file.fileType"
|
||||
/>
|
||||
<ViewOnlyFileRow
|
||||
v-for="file in supplementaryExistingFiles"
|
||||
:key="file.filename"
|
||||
:name="file.filename"
|
||||
:file-type="file.file_type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ usingDetectedLoaders ? 'Detected loaders' : 'Loaders' }}
|
||||
</span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button
|
||||
v-tooltip="
|
||||
isModpack
|
||||
? 'Modpack loaders cannot be edited'
|
||||
: isResourcePack
|
||||
? 'Resource pack loaders cannot be edited'
|
||||
: undefined
|
||||
"
|
||||
:disabled="isModpack || isResourcePack"
|
||||
@click="editLoaders"
|
||||
>
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-1.5 gap-y-4 rounded-xl border border-solid border-surface-5 p-3 py-4"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<template
|
||||
v-for="loader in draftVersionLoaders.map((selectedLoader) =>
|
||||
loaders.find((loader) => selectedLoader === loader.name),
|
||||
)"
|
||||
>
|
||||
<TagItem
|
||||
v-if="loader"
|
||||
:key="`loader-${loader.name}`"
|
||||
class="border !border-solid border-surface-5 hover:no-underline"
|
||||
:style="`--_color: var(--color-platform-${loader.name})`"
|
||||
>
|
||||
<component :is="getLoaderIcon(loader.name)" v-if="getLoaderIcon(loader.name)" />
|
||||
<FormattedTag :tag="loader.name" enforce-type="loader" />
|
||||
</TagItem>
|
||||
</template>
|
||||
|
||||
<span v-if="!draftVersion.loaders.length">No loaders selected.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ usingDetectedVersions ? 'Detected versions' : 'Versions' }}
|
||||
</span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button
|
||||
v-tooltip="isModpack ? 'Modpack versions cannot be edited' : undefined"
|
||||
:disabled="isModpack"
|
||||
@click="editVersions"
|
||||
>
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex max-h-56 flex-col gap-1.5 gap-y-4 overflow-y-auto rounded-xl border border-solid border-surface-5 p-3 py-4"
|
||||
>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<TagItem
|
||||
v-for="version in draftVersion.game_versions"
|
||||
:key="version"
|
||||
class="border !border-solid border-surface-5 hover:no-underline"
|
||||
>
|
||||
{{ version }}
|
||||
</TagItem>
|
||||
|
||||
<span v-if="!draftVersion.game_versions.length">No versions selected.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="!noEnvironmentProject">
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="font-semibold text-contrast"> Environment </span>
|
||||
<UnknownIcon v-tooltip="'Pre-filled from a previous similar version'" />
|
||||
</div>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button @click="editEnvironment">
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1.5 gap-y-4 rounded-xl bg-surface-2 p-3 py-4">
|
||||
<div v-if="draftVersion.environment" class="flex flex-col gap-1">
|
||||
<div class="font-semibold text-contrast">
|
||||
{{ environmentCopy.title }}
|
||||
</div>
|
||||
<div class="text-sm font-medium">{{ environmentCopy.description }}</div>
|
||||
</div>
|
||||
|
||||
<span v-else class="text-sm font-medium">No environment has been set.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="!noDependenciesProject">
|
||||
<div v-if="visibleSuggestedDependencies.length" class="flex flex-col gap-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast"> Suggested dependencies </span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button @click="editDependencies">
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<SuggestedDependencies @on-add-suggestion="handleAddSuggestedDependency" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!visibleSuggestedDependencies.length || draftVersion.dependencies?.length"
|
||||
class="flex flex-col gap-1"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast"> Dependencies </span>
|
||||
|
||||
<ButtonStyled type="transparent" size="standard">
|
||||
<button @click="editDependencies">
|
||||
<EditIcon />
|
||||
Edit
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div v-if="draftVersion.dependencies?.length" class="flex flex-col gap-4">
|
||||
<DependenciesList disable-remove />
|
||||
</div>
|
||||
<div v-else class="flex flex-col gap-1.5 gap-y-4 rounded-xl bg-surface-2 p-3 py-4">
|
||||
<span class="text-sm font-medium">No dependencies added.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { EditIcon, getLoaderIcon, UnknownIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
ENVIRONMENTS_COPY,
|
||||
FormattedTag,
|
||||
injectProjectPageContext,
|
||||
TagItem,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import { useGeneratedState } from '~/composables/generated'
|
||||
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
|
||||
|
||||
import DependenciesList from '../components/DependenciesList.vue'
|
||||
import SuggestedDependencies from '../components/SuggestedDependencies/SuggestedDependencies.vue'
|
||||
import ViewOnlyFileRow from '../components/ViewOnlyFileRow.vue'
|
||||
|
||||
const {
|
||||
draftVersion,
|
||||
inferredVersionData,
|
||||
projectType,
|
||||
noEnvironmentProject,
|
||||
noDependenciesProject,
|
||||
modal,
|
||||
filesToAdd,
|
||||
editingVersion,
|
||||
visibleSuggestedDependencies,
|
||||
} = injectManageVersionContext()
|
||||
|
||||
const { projectV2 } = injectProjectPageContext()
|
||||
|
||||
const generatedState = useGeneratedState()
|
||||
const loaders = computed(() => generatedState.value.loaders)
|
||||
const isModpack = computed(() => projectType.value === 'modpack')
|
||||
const isResourcePack = computed(
|
||||
() =>
|
||||
projectType.value === 'resourcepack' &&
|
||||
(projectV2.value?.project_type === 'resourcepack' ||
|
||||
projectV2.value?.project_type === 'project'),
|
||||
)
|
||||
|
||||
const draftVersionLoaders = computed(() =>
|
||||
[
|
||||
...new Set([...draftVersion.value.loaders, ...(draftVersion.value.mrpack_loaders ?? [])]),
|
||||
].filter((loader) => loader !== 'mrpack'),
|
||||
)
|
||||
|
||||
const editLoaders = () => {
|
||||
modal.value?.setStage('from-details-loaders')
|
||||
}
|
||||
const editVersions = () => {
|
||||
modal.value?.setStage('from-details-mc-versions')
|
||||
}
|
||||
const editEnvironment = () => {
|
||||
modal.value?.setStage('from-details-environment')
|
||||
}
|
||||
const editFiles = () => {
|
||||
modal.value?.setStage('from-details-files')
|
||||
}
|
||||
const editDependencies = () => {
|
||||
modal.value?.setStage('from-details-dependencies')
|
||||
}
|
||||
|
||||
const usingDetectedVersions = computed(() => {
|
||||
if (!inferredVersionData.value?.game_versions) return false
|
||||
|
||||
const versionsMatch =
|
||||
draftVersion.value.game_versions.length === inferredVersionData.value.game_versions.length &&
|
||||
draftVersion.value.game_versions.every((version) =>
|
||||
inferredVersionData.value?.game_versions?.includes(version),
|
||||
)
|
||||
|
||||
return versionsMatch
|
||||
})
|
||||
|
||||
const usingDetectedLoaders = computed(() => {
|
||||
if (!inferredVersionData.value?.loaders) return false
|
||||
|
||||
const loadersMatch =
|
||||
draftVersion.value.loaders.length === inferredVersionData.value.loaders.length &&
|
||||
draftVersion.value.loaders.every((loader) =>
|
||||
inferredVersionData.value?.loaders?.includes(loader),
|
||||
)
|
||||
|
||||
return loadersMatch
|
||||
})
|
||||
|
||||
interface PrimaryFile {
|
||||
name: string
|
||||
fileType?: string
|
||||
existing?: boolean
|
||||
}
|
||||
|
||||
const primaryFile = computed<PrimaryFile | null>(() => {
|
||||
const existingPrimaryFile = draftVersion.value.existing_files?.[0]
|
||||
if (existingPrimaryFile) {
|
||||
return {
|
||||
name: existingPrimaryFile.filename,
|
||||
fileType: existingPrimaryFile.file_type,
|
||||
existing: true,
|
||||
}
|
||||
}
|
||||
|
||||
const addedPrimaryFile = filesToAdd.value[0]
|
||||
if (addedPrimaryFile) {
|
||||
return {
|
||||
name: addedPrimaryFile.file.name,
|
||||
fileType: addedPrimaryFile.fileType,
|
||||
existing: false,
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
})
|
||||
|
||||
const supplementaryNewFiles = computed(() => {
|
||||
if (primaryFile.value?.existing) {
|
||||
return filesToAdd.value
|
||||
} else {
|
||||
return filesToAdd.value.slice(1)
|
||||
}
|
||||
})
|
||||
|
||||
const supplementaryExistingFiles = computed(() => {
|
||||
if (primaryFile.value?.existing) {
|
||||
return draftVersion.value.existing_files?.slice(1)
|
||||
} else {
|
||||
return draftVersion.value.existing_files
|
||||
}
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const noEnvironmentMessage = defineMessages({
|
||||
title: {
|
||||
id: 'version.environment.none.title',
|
||||
defaultMessage: 'No environment set',
|
||||
},
|
||||
description: {
|
||||
id: 'version.environment.none.description',
|
||||
defaultMessage: 'The environment for this version has not been specified.',
|
||||
},
|
||||
})
|
||||
|
||||
const unknownEnvironmentMessage = defineMessages({
|
||||
title: {
|
||||
id: 'version.environment.unknown.title',
|
||||
defaultMessage: 'Unknown environment',
|
||||
},
|
||||
description: {
|
||||
id: 'version.environment.unknown.description',
|
||||
defaultMessage: 'The environment: "{environment}" is not recognized.',
|
||||
},
|
||||
})
|
||||
|
||||
const environmentCopy = computed(() => {
|
||||
if (!draftVersion.value.environment) {
|
||||
return {
|
||||
title: formatMessage(noEnvironmentMessage.title),
|
||||
description: formatMessage(noEnvironmentMessage.description),
|
||||
}
|
||||
}
|
||||
|
||||
const envCopy = ENVIRONMENTS_COPY[draftVersion.value.environment]
|
||||
if (envCopy) {
|
||||
return {
|
||||
title: formatMessage(envCopy.title),
|
||||
description: formatMessage(envCopy.description),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title: formatMessage(unknownEnvironmentMessage.title),
|
||||
description: formatMessage(unknownEnvironmentMessage.description, {
|
||||
environment: draftVersion.value.environment,
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
const handleAddSuggestedDependency = (dependency: Labrinth.Versions.v3.Dependency) => {
|
||||
if (!draftVersion.value.dependencies) draftVersion.value.dependencies = []
|
||||
draftVersion.value.dependencies.push({
|
||||
project_id: dependency.project_id,
|
||||
version_id: dependency.version_id,
|
||||
dependency_type: dependency.dependency_type,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -43,7 +43,7 @@
|
||||
<ButtonStyled class="w-24">
|
||||
<button @click="modal.hide()">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancel) }}
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand" class="w-36">
|
||||
@@ -60,6 +60,7 @@
|
||||
import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
@@ -102,18 +103,10 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'Your new collection will be created as a public collection with {count, plural, =0 {no projects} one {# project} other {# projects}}.',
|
||||
},
|
||||
cancel: {
|
||||
id: 'create.collection.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
createCollection: {
|
||||
id: 'create.collection.create-collection',
|
||||
defaultMessage: 'Create collection',
|
||||
},
|
||||
errorTitle: {
|
||||
id: 'create.collection.error-title',
|
||||
defaultMessage: 'An error occurred',
|
||||
},
|
||||
})
|
||||
|
||||
const name = ref('')
|
||||
@@ -150,7 +143,7 @@ async function create() {
|
||||
await router.push(`/collection/${result.id}`)
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
title: formatMessage(messages.errorTitle),
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err?.data?.description || err?.message || err,
|
||||
type: 'error',
|
||||
})
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<ButtonStyled class="w-24">
|
||||
<button @click="hide">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancel) }}
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand" class="w-40">
|
||||
@@ -83,6 +83,7 @@
|
||||
import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
@@ -130,18 +131,10 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'You will be the owner of this organization, but you can invite other members and transfer ownership at any time.',
|
||||
},
|
||||
cancel: {
|
||||
id: 'create.organization.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
createOrganization: {
|
||||
id: 'create.organization.create-organization',
|
||||
defaultMessage: 'Create organization',
|
||||
},
|
||||
errorTitle: {
|
||||
id: 'create.organization.error-title',
|
||||
defaultMessage: 'An error occurred',
|
||||
},
|
||||
})
|
||||
|
||||
const name = ref<string>('')
|
||||
@@ -172,7 +165,7 @@ async function createOrganization(): Promise<void> {
|
||||
} catch (err: any) {
|
||||
console.error(err)
|
||||
addNotification({
|
||||
title: formatMessage(messages.errorTitle),
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: 'error',
|
||||
})
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<div class="flex flex-col gap-2">
|
||||
<label for="visibility" class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.visibilityLabel) }}
|
||||
{{ formatMessage(commonMessages.visibilityLabel) }}
|
||||
<span class="text-brand-red">*</span>
|
||||
</span>
|
||||
<span>{{ formatMessage(messages.visibilityDescription) }}</span>
|
||||
@@ -79,7 +79,7 @@
|
||||
<ButtonStyled class="w-24">
|
||||
<button @click="cancel">
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.cancel) }}
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand" class="w-32">
|
||||
@@ -98,6 +98,7 @@ import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
Chips,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
@@ -127,10 +128,6 @@ const messages = defineMessages({
|
||||
id: 'create.project.url-label',
|
||||
defaultMessage: 'URL',
|
||||
},
|
||||
visibilityLabel: {
|
||||
id: 'create.project.visibility-label',
|
||||
defaultMessage: 'Visibility',
|
||||
},
|
||||
visibilityDescription: {
|
||||
id: 'create.project.visibility-description',
|
||||
defaultMessage: 'The visibility of your project after it has been approved.',
|
||||
@@ -147,18 +144,10 @@ const messages = defineMessages({
|
||||
id: 'create.project.summary-placeholder',
|
||||
defaultMessage: 'This project adds...',
|
||||
},
|
||||
cancel: {
|
||||
id: 'create.project.cancel',
|
||||
defaultMessage: 'Cancel',
|
||||
},
|
||||
createProject: {
|
||||
id: 'create.project.create-project',
|
||||
defaultMessage: 'Create project',
|
||||
},
|
||||
errorTitle: {
|
||||
id: 'create.project.error-title',
|
||||
defaultMessage: 'An error occurred',
|
||||
},
|
||||
visibilityPublic: {
|
||||
id: 'create.project.visibility-public',
|
||||
defaultMessage: 'Public',
|
||||
@@ -256,7 +245,7 @@ async function createProject() {
|
||||
await router.push(`/project/${slug.value}/settings`)
|
||||
} catch (err) {
|
||||
addNotification({
|
||||
title: formatMessage(messages.errorTitle),
|
||||
title: formatMessage(commonMessages.errorNotificationTitle),
|
||||
text: err.data ? err.data.description : err,
|
||||
type: 'error',
|
||||
})
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
v-model="isUSCitizen"
|
||||
:items="['yes', 'no']"
|
||||
:format-label="
|
||||
(item) => (item === 'yes' ? formatMessage(messages.yes) : formatMessage(messages.no))
|
||||
(item) =>
|
||||
item === 'yes'
|
||||
? formatMessage(commonMessages.yesLabel)
|
||||
: formatMessage(commonMessages.noLabel)
|
||||
"
|
||||
:never-empty="false"
|
||||
:capitalize="true"
|
||||
@@ -162,6 +165,7 @@ import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
Chips,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
@@ -228,8 +232,6 @@ const messages = defineMessages({
|
||||
id: 'dashboard.creator-tax-form-modal.us-citizen.question',
|
||||
defaultMessage: 'Are you a US citizen?',
|
||||
},
|
||||
yes: { id: 'common.yes', defaultMessage: 'Yes' },
|
||||
no: { id: 'common.no', defaultMessage: 'No' },
|
||||
entityQuestion: {
|
||||
id: 'dashboard.creator-tax-form-modal.entity.question',
|
||||
defaultMessage: 'Are you a private individual or part of a foreign entity?',
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<div v-if="currentStage === 'completion'" class="mt-4 flex w-full gap-3">
|
||||
<ButtonStyled class="flex-1">
|
||||
<button class="w-full text-contrast" @click="handleClose">
|
||||
{{ formatMessage(messages.closeButton) }}
|
||||
{{ formatMessage(commonMessages.closeButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled class="flex-1">
|
||||
@@ -128,6 +128,7 @@ import { computed, nextTick, onMounted, ref, useTemplateRef, watch } from 'vue'
|
||||
|
||||
import {
|
||||
createWithdrawContext,
|
||||
type PaymentProvider,
|
||||
type PayoutMethod,
|
||||
provideWithdrawContext,
|
||||
TAX_THRESHOLD_ACTUAL,
|
||||
@@ -332,51 +333,76 @@ function continueWithLimit() {
|
||||
setStage(nextStep.value)
|
||||
}
|
||||
|
||||
// TODO: God we need better errors from the backend (e.g error ids), this shit is insane
|
||||
function getWithdrawalError(error: any): { title: string; text: string } {
|
||||
const description = error?.data?.description?.toLowerCase() || ''
|
||||
function buildSupportData(error: any): Record<string, unknown> {
|
||||
// Extract response headers, excluding sensitive ones
|
||||
const responseHeaders: Record<string, string> = {}
|
||||
if (error?.response?.headers) {
|
||||
const headers = error.response.headers
|
||||
const entries =
|
||||
typeof headers.entries === 'function' ? [...headers.entries()] : Object.entries(headers)
|
||||
for (const [key, value] of entries) {
|
||||
const lowerKey = key.toLowerCase()
|
||||
// Exclude sensitive headers
|
||||
if (!['authorization', 'cookie', 'set-cookie'].includes(lowerKey)) {
|
||||
responseHeaders[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
timestamp: new Date().toISOString(),
|
||||
provider: withdrawData.value.selection.provider,
|
||||
method: withdrawData.value.selection.method,
|
||||
methodId: withdrawData.value.selection.methodId,
|
||||
country: withdrawData.value.selection.country?.id,
|
||||
amount: withdrawData.value.calculation?.amount,
|
||||
fee: withdrawData.value.calculation?.fee,
|
||||
request: {
|
||||
url: 'POST /api/v3/payout',
|
||||
},
|
||||
response: {
|
||||
status: error?.response?.status ?? error?.statusCode,
|
||||
statusText: error?.response?.statusText,
|
||||
headers: responseHeaders,
|
||||
body: error?.data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function formatBilingualText(
|
||||
messageDescriptor: { id: string; defaultMessage: string },
|
||||
values?: Record<string, string>,
|
||||
): string {
|
||||
const localized = formatMessage(messageDescriptor, values)
|
||||
// Interpolate values into the English default message
|
||||
let english = messageDescriptor.defaultMessage
|
||||
if (values) {
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
english = english.replace(`{${key}}`, value)
|
||||
}
|
||||
}
|
||||
|
||||
if (localized === english) {
|
||||
return localized
|
||||
}
|
||||
|
||||
return `${localized}\n${english}`
|
||||
}
|
||||
|
||||
function getWithdrawalError(
|
||||
error: any,
|
||||
provider: PaymentProvider | null,
|
||||
): { title: string; text: string; supportData: Record<string, unknown> } {
|
||||
const description = error?.data?.description?.toLowerCase() || ''
|
||||
const supportData = buildSupportData(error)
|
||||
|
||||
// === Common patterns (all providers) ===
|
||||
// Tax form error
|
||||
if (description.includes('tax form')) {
|
||||
return {
|
||||
title: formatMessage(messages.errorTaxFormTitle),
|
||||
text: formatMessage(messages.errorTaxFormText),
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid crypto wallet address
|
||||
if (
|
||||
(description.includes('wallet') && description.includes('invalid')) ||
|
||||
description.includes('wallet_address') ||
|
||||
(description.includes('blockchain') && description.includes('invalid'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInvalidWalletTitle),
|
||||
text: formatMessage(messages.errorInvalidWalletText),
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid bank details
|
||||
if (
|
||||
(description.includes('bank') || description.includes('account')) &&
|
||||
(description.includes('invalid') || description.includes('failed'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInvalidBankTitle),
|
||||
text: formatMessage(messages.errorInvalidBankText),
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid/fraudulent address
|
||||
if (
|
||||
description.includes('address') &&
|
||||
(description.includes('invalid') ||
|
||||
description.includes('verification') ||
|
||||
description.includes('fraudulent'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInvalidAddressTitle),
|
||||
text: formatMessage(messages.errorInvalidAddressText),
|
||||
text: formatBilingualText(messages.errorTaxFormText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,14 +414,106 @@ function getWithdrawalError(error: any): { title: string; text: string } {
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorMinimumNotMetTitle),
|
||||
text: formatMessage(messages.errorMinimumNotMetText),
|
||||
text: formatBilingualText(messages.errorMinimumNotMetText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
// Insufficient balance
|
||||
if (description.includes('enough funds') || description.includes('insufficient')) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInsufficientBalanceTitle),
|
||||
text: formatBilingualText(messages.errorInsufficientBalanceText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
// Email verification required
|
||||
if (description.includes('verify your email') || description.includes('email_verified')) {
|
||||
return {
|
||||
title: formatMessage(messages.errorEmailVerificationTitle),
|
||||
text: formatBilingualText(messages.errorEmailVerificationText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
// === MuralPay-only patterns ===
|
||||
if (provider === 'muralpay') {
|
||||
// Invalid crypto wallet address
|
||||
if (
|
||||
(description.includes('wallet') && description.includes('invalid')) ||
|
||||
description.includes('wallet_address') ||
|
||||
(description.includes('blockchain') && description.includes('invalid'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInvalidWalletTitle),
|
||||
text: formatBilingualText(messages.errorInvalidWalletText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid bank details
|
||||
if (
|
||||
(description.includes('bank') || description.includes('account')) &&
|
||||
(description.includes('invalid') || description.includes('failed'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInvalidBankTitle),
|
||||
text: formatBilingualText(messages.errorInvalidBankText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
// Invalid/fraudulent address (physical address for KYC)
|
||||
if (
|
||||
description.includes('address') &&
|
||||
(description.includes('invalid') ||
|
||||
description.includes('verification') ||
|
||||
description.includes('fraudulent'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorInvalidAddressTitle),
|
||||
text: formatBilingualText(messages.errorInvalidAddressText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// === PayPal/Venmo-only patterns ===
|
||||
if (provider === 'paypal' || provider === 'venmo') {
|
||||
// Account not linked
|
||||
if (
|
||||
description.includes('not linked') ||
|
||||
description.includes('link') ||
|
||||
description.includes('paypal account') ||
|
||||
description.includes('venmo')
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorAccountNotLinkedTitle),
|
||||
text: formatBilingualText(messages.errorAccountNotLinkedText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
// Country mismatch for PayPal
|
||||
if (
|
||||
provider === 'paypal' &&
|
||||
(description.includes('us paypal') || description.includes('international paypal'))
|
||||
) {
|
||||
return {
|
||||
title: formatMessage(messages.errorPaypalCountryMismatchTitle),
|
||||
text: formatBilingualText(messages.errorPaypalCountryMismatchText),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generic fallback
|
||||
const errorDescription = error?.data?.description || ''
|
||||
return {
|
||||
title: formatMessage(messages.errorGenericTitle),
|
||||
text: formatMessage(messages.errorGenericText),
|
||||
text: formatBilingualText(messages.errorGenericText, { error: errorDescription }),
|
||||
supportData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,11 +527,15 @@ async function handleWithdraw() {
|
||||
} catch (error) {
|
||||
console.error('Withdrawal failed:', error)
|
||||
|
||||
const { title, text } = getWithdrawalError(error)
|
||||
const { title, text, supportData } = getWithdrawalError(
|
||||
error,
|
||||
withdrawData.value.selection.provider,
|
||||
)
|
||||
addNotification({
|
||||
title,
|
||||
text,
|
||||
type: 'error',
|
||||
supportData,
|
||||
})
|
||||
} finally {
|
||||
isSubmitting.value = false
|
||||
@@ -479,26 +601,10 @@ const messages = defineMessages({
|
||||
id: 'dashboard.creator-withdraw-modal.stage.method-selection',
|
||||
defaultMessage: 'Method',
|
||||
},
|
||||
tremendousDetailsStage: {
|
||||
id: 'dashboard.creator-withdraw-modal.stage.tremendous-details',
|
||||
defaultMessage: 'Details',
|
||||
},
|
||||
muralpayKycStage: {
|
||||
id: 'dashboard.creator-withdraw-modal.stage.muralpay-kyc',
|
||||
defaultMessage: 'Verification',
|
||||
},
|
||||
muralpayDetailsStage: {
|
||||
id: 'dashboard.creator-withdraw-modal.stage.muralpay-details',
|
||||
defaultMessage: 'Account Details',
|
||||
},
|
||||
completionStage: {
|
||||
id: 'dashboard.creator-withdraw-modal.stage.completion',
|
||||
defaultMessage: 'Complete',
|
||||
},
|
||||
detailsLabel: {
|
||||
id: 'dashboard.creator-withdraw-modal.details-label',
|
||||
defaultMessage: 'Details',
|
||||
},
|
||||
completeTaxForm: {
|
||||
id: 'dashboard.creator-withdraw-modal.complete-tax-form',
|
||||
defaultMessage: 'Complete tax form',
|
||||
@@ -507,14 +613,14 @@ const messages = defineMessages({
|
||||
id: 'dashboard.creator-withdraw-modal.continue-with-limit',
|
||||
defaultMessage: 'Continue with limit',
|
||||
},
|
||||
detailsLabel: {
|
||||
id: 'dashboard.creator-withdraw-modal.details-label',
|
||||
defaultMessage: 'Details',
|
||||
},
|
||||
withdrawButton: {
|
||||
id: 'dashboard.creator-withdraw-modal.withdraw-button',
|
||||
defaultMessage: 'Withdraw',
|
||||
},
|
||||
closeButton: {
|
||||
id: 'dashboard.withdraw.completion.close-button',
|
||||
defaultMessage: 'Close',
|
||||
},
|
||||
transactionsButton: {
|
||||
id: 'dashboard.withdraw.completion.transactions-button',
|
||||
defaultMessage: 'Transactions',
|
||||
@@ -570,7 +676,40 @@ const messages = defineMessages({
|
||||
errorGenericText: {
|
||||
id: 'dashboard.withdraw.error.generic.text',
|
||||
defaultMessage:
|
||||
'We were unable to submit your withdrawal request, please check your details or contact support.',
|
||||
'We were unable to submit your withdrawal request, please check your details or contact support.\n{error}',
|
||||
},
|
||||
errorInsufficientBalanceTitle: {
|
||||
id: 'dashboard.withdraw.error.insufficient-balance.title',
|
||||
defaultMessage: 'Insufficient balance',
|
||||
},
|
||||
errorInsufficientBalanceText: {
|
||||
id: 'dashboard.withdraw.error.insufficient-balance.text',
|
||||
defaultMessage: 'You do not have enough funds to make this withdrawal.',
|
||||
},
|
||||
errorEmailVerificationTitle: {
|
||||
id: 'dashboard.withdraw.error.email-verification.title',
|
||||
defaultMessage: 'Email verification required',
|
||||
},
|
||||
errorEmailVerificationText: {
|
||||
id: 'dashboard.withdraw.error.email-verification.text',
|
||||
defaultMessage: 'You must verify your email address before withdrawing funds.',
|
||||
},
|
||||
errorAccountNotLinkedTitle: {
|
||||
id: 'dashboard.withdraw.error.account-not-linked.title',
|
||||
defaultMessage: 'Account not linked',
|
||||
},
|
||||
errorAccountNotLinkedText: {
|
||||
id: 'dashboard.withdraw.error.account-not-linked.text',
|
||||
defaultMessage: 'Please link your payment account before withdrawing.',
|
||||
},
|
||||
errorPaypalCountryMismatchTitle: {
|
||||
id: 'dashboard.withdraw.error.paypal-country-mismatch.title',
|
||||
defaultMessage: 'PayPal region mismatch',
|
||||
},
|
||||
errorPaypalCountryMismatchText: {
|
||||
id: 'dashboard.withdraw.error.paypal-country-mismatch.text',
|
||||
defaultMessage:
|
||||
'Please use the correct PayPal transfer option for your region (US or International).',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user