mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
Compare commits
172
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6b38ee008 | ||
|
|
651cdaacdf | ||
|
|
d0bdeb1bc6 | ||
|
|
832240a45f | ||
|
|
fc1aa28aa4 | ||
|
|
84b4f8e474 | ||
|
|
b14fad4237 | ||
|
|
ff1f86a0f4 | ||
|
|
e8f8722b70 | ||
|
|
518bcd414a | ||
|
|
79013c21c2 | ||
|
|
2e4a050151 | ||
|
|
f780736d89 | ||
|
|
916daa684d | ||
|
|
8ece0bd31c | ||
|
|
e2085c43c5 | ||
|
|
30e23e5cc2 | ||
|
|
8e44f20eec | ||
|
|
932858b5f5 | ||
|
|
8b6f0ec695 | ||
|
|
ee2ad5f05b | ||
|
|
9bfa7c7e4a | ||
|
|
e52ae416a8 | ||
|
|
6319832465 | ||
|
|
7144f08f0f | ||
|
|
c579925f03 | ||
|
|
6b569e4ee4 | ||
|
|
6b62e3b480 | ||
|
|
543cb42210 | ||
|
|
86c6fb8239 | ||
|
|
14e0abb273 | ||
|
|
df653d3e43 | ||
|
|
4aeb6cf9ff | ||
|
|
cb154e205b | ||
|
|
dad5970e8d | ||
|
|
1947d083b3 | ||
|
|
905204cc5f | ||
|
|
8cca911775 | ||
|
|
cafe58dc3c | ||
|
|
13e6ebf4e0 | ||
|
|
1884912126 | ||
|
|
818a9db9f7 | ||
|
|
c431d1fc89 | ||
|
|
4a09ee7ac9 | ||
|
|
31ef22767e | ||
|
|
706d46a6e2 | ||
|
|
ed9394f2f7 | ||
|
|
9e1e8788e2 | ||
|
|
7c4df7442b | ||
|
|
e1556a8ee3 | ||
|
|
1741d12b7b | ||
|
|
0b38cecc74 | ||
|
|
8680e61883 | ||
|
|
ea86db450b | ||
|
|
bbdaa171e3 | ||
|
|
af8daca059 | ||
|
|
2434f0c45b | ||
|
|
332dfe1074 | ||
|
|
c07727aa49 | ||
|
|
57a977f7f3 | ||
|
|
323d088ebd | ||
|
|
46f94bd067 | ||
|
|
e877167db7 | ||
|
|
623b51e6ea | ||
|
|
5face9e56a | ||
|
|
40aff1e8bb | ||
|
|
5f8837604d | ||
|
|
795dad040f | ||
|
|
9ca181dc1a | ||
|
|
c84b658e41 | ||
|
|
9006dce2b0 | ||
|
|
efdfb51149 | ||
|
|
79cc5fef72 | ||
|
|
ddefc28ca6 | ||
|
|
654757f9fb | ||
|
|
407641ee7c | ||
|
|
96ab120cd0 | ||
|
|
3ed75a146a | ||
|
|
5a1c2a46bc | ||
|
|
df8ebbd3e0 | ||
|
|
517c3d2d72 | ||
|
|
7f15772f59 | ||
|
|
0905ea72f6 | ||
|
|
8d20fd82db | ||
|
|
c831e38e32 | ||
|
|
40b8fb3a4a | ||
|
|
977bb2ff58 | ||
|
|
732bdfc79b | ||
|
|
1cce1eb248 | ||
|
|
76320f227f | ||
|
|
34228a5b6c | ||
|
|
6d66aee4ec | ||
|
|
fc7be043c7 | ||
|
|
7fa88e5d4d | ||
|
|
21508e0637 | ||
|
|
ad4912d64d | ||
|
|
0002ae2479 | ||
|
|
e4568330a7 | ||
|
|
b0108e0624 | ||
|
|
ac63abadb7 | ||
|
|
fa749b5aff | ||
|
|
a2adbe18c4 | ||
|
|
0fcbe51816 | ||
|
|
23cfeca91d | ||
|
|
db830ef65c | ||
|
|
08f44b3582 | ||
|
|
8ffc4e2599 | ||
|
|
58a5619073 | ||
|
|
4a6fa9fc3d | ||
|
|
b26d048a63 | ||
|
|
d5be2bd739 | ||
|
|
0dac5684af | ||
|
|
ca0b8d5ca4 | ||
|
|
b6651efe52 | ||
|
|
eb28121c0a | ||
|
|
a5ebc85356 | ||
|
|
c530671be1 | ||
|
|
bb6d8a6fc4 | ||
|
|
256e8f946a | ||
|
|
7e5590b8b9 | ||
|
|
d20f05fb04 | ||
|
|
a00a7971d1 | ||
|
|
26e98b7155 | ||
|
|
77b06f679e | ||
|
|
50e9472dd9 | ||
|
|
b569354793 | ||
|
|
b667b3ae9e | ||
|
|
16de6182e4 | ||
|
|
364fed52dd | ||
|
|
0fe695721a | ||
|
|
692f22b749 | ||
|
|
ed7792097d | ||
|
|
c56ce6c9ee | ||
|
|
91bc58b8ee | ||
|
|
38d757b66a | ||
|
|
862b54f00d | ||
|
|
c2f4835fe7 | ||
|
|
b97c191d75 | ||
|
|
b0c6a06909 | ||
|
|
fc3e384f54 | ||
|
|
87ff8fd4d9 | ||
|
|
288c1fb970 | ||
|
|
f6e6ac28d4 | ||
|
|
4a972bca73 | ||
|
|
b09c26f616 | ||
|
|
204bd52a5a | ||
|
|
b59f327b04 | ||
|
|
89e643fa50 | ||
|
|
cee25fdbbc | ||
|
|
b95a2d875a | ||
|
|
1067b02830 | ||
|
|
ebf4a6ef5f | ||
|
|
e4376c2b15 | ||
|
|
5fe07de187 | ||
|
|
80d66d3c6e | ||
|
|
64f7fb811e | ||
|
|
734720e11e | ||
|
|
ef4044534f | ||
|
|
6fc741f7c0 | ||
|
|
527757d158 | ||
|
|
f4a2999b20 | ||
|
|
586cdc90f9 | ||
|
|
e56f3ae18a | ||
|
|
c392c85917 | ||
|
|
29110890e1 | ||
|
|
a18f67bf0c | ||
|
|
623e01dbff | ||
|
|
14c728c8e3 | ||
|
|
a1b2073f57 | ||
|
|
45c417e406 | ||
|
|
3c60cc6f08 | ||
|
|
06353bbc14 |
@@ -81,6 +81,6 @@ Please follow these rules precisely:
|
||||
Use existing patterns from our codebase:
|
||||
|
||||
- Variables/plurals: see `apps/frontend/src/pages/frog.vue`
|
||||
- Rich-text link tags: see `apps/frontend/src/pages/auth/welcome.vue` and `apps/frontend/src/error.vue`
|
||||
- Rich-text link tags: see `apps/frontend/src/error.vue`
|
||||
|
||||
When you finish, there should be no hard-coded English strings left in the template—everything comes from `formatMessage` or `<IntlFormatted>`.
|
||||
|
||||
@@ -76,13 +76,6 @@ jobs:
|
||||
env:
|
||||
SCCACHE_DIR: ${{ needs.skip-if-clean.outputs.internal == 'true' && '/mnt/sccache' || '' }}
|
||||
SCCACHE_CACHE_SIZE: ${{ needs.skip-if-clean.outputs.internal == 'true' && '10G' || '' }}
|
||||
SCCACHE_MULTILEVEL_CHAIN: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'disk,s3' || '' }}
|
||||
SCCACHE_S3_KEY_PREFIX: ${{ needs.skip-if-clean.outputs.internal == 'true' && format('{0}/', github.repository) || '' }}
|
||||
SCCACHE_BUCKET: ${{ secrets.SCCACHE_BUCKET }}
|
||||
SCCACHE_REGION: ${{ secrets.SCCACHE_REGION }}
|
||||
SCCACHE_ENDPOINT: ${{ secrets.SCCACHE_ENDPOINT }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_S3_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_S3_SECRET_ACCESS_KEY }}
|
||||
RUSTC_WRAPPER: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'sccache' || '' }}
|
||||
needs: [skip-if-clean]
|
||||
if: ${{ needs.skip-if-clean.outputs.skip != 'true' }}
|
||||
@@ -96,6 +89,9 @@ jobs:
|
||||
rustflags: ''
|
||||
cache: false
|
||||
|
||||
- name: Setup mold
|
||||
uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 / Mold 2.41.0
|
||||
|
||||
- name: Cache Cargo registry and index
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
@@ -105,6 +101,10 @@ jobs:
|
||||
~/.cargo/bin
|
||||
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Ensure sccache directory exists
|
||||
if: needs.skip-if-clean.outputs.internal == 'true'
|
||||
run: sudo mkdir -p /mnt/sccache && sudo chown $(id -u):$(id -g) /mnt/sccache
|
||||
|
||||
- name: Mount sccache disk cache
|
||||
if: needs.skip-if-clean.outputs.internal == 'true'
|
||||
uses: useblacksmith/stickydisk@13af8883542ca949a717e70fef89d15edbb29d88 # v1.2.0
|
||||
|
||||
@@ -76,6 +76,8 @@ jobs:
|
||||
|
||||
- name: Deploy Storybook preview
|
||||
uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3.15.0
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
with:
|
||||
apiToken: ${{ secrets.CF_API_TOKEN }}
|
||||
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
||||
@@ -85,7 +87,11 @@ jobs:
|
||||
command: versions upload --preview-alias git-${{ steps.meta.outputs.sha_short }}
|
||||
|
||||
comment:
|
||||
if: github.repository_owner == 'modrinth' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
if: |
|
||||
!cancelled()
|
||||
&& github.repository_owner == 'modrinth'
|
||||
&& github.event.pull_request.head.repo.full_name == github.repository
|
||||
&& needs.deploy.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
needs: [deploy, deploy-storybook]
|
||||
steps:
|
||||
@@ -99,16 +105,25 @@ jobs:
|
||||
id: urls
|
||||
env:
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
STORYBOOK_RESULT: ${{ needs.deploy-storybook.result }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
STAGING_PREVIEW_URL=$(cat deployment-url-staging-preview.txt)
|
||||
PRODUCTION_PREVIEW_URL=$(cat deployment-url-production-preview.txt)
|
||||
|
||||
if [ "$STORYBOOK_RESULT" = "success" ]; then
|
||||
STORYBOOK_PREVIEW_URL="https://git-${HEAD_SHA::8}-storybook.modrinth.workers.dev"
|
||||
else
|
||||
STORYBOOK_PREVIEW_URL="⚠️ Deployment $STORYBOOK_RESULT ([logs]($RUN_URL))"
|
||||
fi
|
||||
|
||||
echo "Production preview URL: $PRODUCTION_PREVIEW_URL"
|
||||
echo "Staging preview URL: $STAGING_PREVIEW_URL"
|
||||
echo "Storybook preview URL: $STORYBOOK_PREVIEW_URL"
|
||||
|
||||
echo "staging-preview-url=$STAGING_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
echo "production-preview-url=$PRODUCTION_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
echo "storybook-preview-url=https://git-${HEAD_SHA::8}-storybook.modrinth.workers.dev" >> $GITHUB_OUTPUT
|
||||
echo "storybook-preview-url=$STORYBOOK_PREVIEW_URL" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Find comment
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
@@ -78,14 +78,8 @@ jobs:
|
||||
GIT_HASH: ${{ github.sha }}
|
||||
SCCACHE_DIR: ${{ needs.skip-if-clean.outputs.internal == 'true' && '/mnt/sccache' || '' }}
|
||||
SCCACHE_CACHE_SIZE: ${{ needs.skip-if-clean.outputs.internal == 'true' && '10G' || '' }}
|
||||
SCCACHE_MULTILEVEL_CHAIN: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'disk,s3' || '' }}
|
||||
SCCACHE_S3_KEY_PREFIX: ${{ needs.skip-if-clean.outputs.internal == 'true' && format('{0}/', github.repository) || '' }}
|
||||
SCCACHE_BUCKET: ${{ secrets.SCCACHE_BUCKET }}
|
||||
SCCACHE_REGION: ${{ secrets.SCCACHE_REGION }}
|
||||
SCCACHE_ENDPOINT: ${{ secrets.SCCACHE_ENDPOINT }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_S3_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_S3_SECRET_ACCESS_KEY }}
|
||||
RUSTC_WRAPPER: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'sccache' || '' }}
|
||||
RUST_MIN_STACK: '16777216'
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
@@ -100,10 +94,11 @@ jobs:
|
||||
uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 / Mold 2.41.0
|
||||
|
||||
- name: Install build dependencies
|
||||
uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0
|
||||
with:
|
||||
packages: cmake libcurl4-openssl-dev
|
||||
version: v2 # cache key
|
||||
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends cmake libcurl4-openssl-dev
|
||||
#uses: awalsh128/cache-apt-pkgs-action@acb598e5ddbc6f68a970c5da0688d2f3a9f04d05 # v1.6.0
|
||||
#with:
|
||||
# packages: cmake libcurl4-openssl-dev
|
||||
# version: v2 # cache key
|
||||
|
||||
- name: Cache Cargo registry and index
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
@@ -114,6 +109,10 @@ jobs:
|
||||
~/.cargo/bin
|
||||
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Ensure sccache directory exists
|
||||
if: needs.skip-if-clean.outputs.internal == 'true'
|
||||
run: sudo mkdir -p /mnt/sccache && sudo chown $(id -u):$(id -g) /mnt/sccache
|
||||
|
||||
- name: Mount sccache disk cache
|
||||
if: needs.skip-if-clean.outputs.internal == 'true'
|
||||
uses: useblacksmith/stickydisk@13af8883542ca949a717e70fef89d15edbb29d88 # v1.2.0
|
||||
|
||||
@@ -84,6 +84,10 @@ jobs:
|
||||
rustflags: ''
|
||||
target: ${{ contains(matrix.platform, 'macos') && 'x86_64-apple-darwin' || '' }}
|
||||
|
||||
- name: Setup mold
|
||||
if: contains(matrix.platform, 'ubuntu')
|
||||
uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 / Mold 2.41.0
|
||||
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10
|
||||
|
||||
|
||||
@@ -81,13 +81,6 @@ jobs:
|
||||
# blacksmith runner)
|
||||
SCCACHE_DIR: ${{ needs.skip-if-clean.outputs.internal == 'true' && '/mnt/sccache' || '' }}
|
||||
SCCACHE_CACHE_SIZE: ${{ needs.skip-if-clean.outputs.internal == 'true' && '10G' || '' }}
|
||||
SCCACHE_MULTILEVEL_CHAIN: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'disk,s3' || '' }}
|
||||
SCCACHE_S3_KEY_PREFIX: ${{ needs.skip-if-clean.outputs.internal == 'true' && format('{0}/', github.repository) || '' }}
|
||||
SCCACHE_BUCKET: ${{ secrets.SCCACHE_BUCKET }}
|
||||
SCCACHE_REGION: ${{ secrets.SCCACHE_REGION }}
|
||||
SCCACHE_ENDPOINT: ${{ secrets.SCCACHE_ENDPOINT }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_S3_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_S3_SECRET_ACCESS_KEY }}
|
||||
RUSTC_WRAPPER: ${{ needs.skip-if-clean.outputs.internal == 'true' && 'sccache' || '' }}
|
||||
|
||||
steps:
|
||||
@@ -129,6 +122,9 @@ jobs:
|
||||
components: clippy, rustfmt
|
||||
cache: false
|
||||
|
||||
- name: Setup mold
|
||||
uses: rui314/setup-mold@9c9c13bf4c3f1adef0cc596abc155580bcb04444 # v1 / Mold 2.41.0
|
||||
|
||||
- name: Cache Cargo registry and index
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae #v5.0.5
|
||||
with:
|
||||
|
||||
@@ -50,7 +50,7 @@ Run these from the **root** folder before opening a pull request - do not run th
|
||||
- **App frontend:** `pnpm prepr:frontend:app`
|
||||
- **Frontend libs:** `pnpm prepr:frontend:lib`
|
||||
- **All frontend (app+web):** `pnpm prepr`
|
||||
- **Labrinth (backend):** See `apps/labrinth/CLAUDE.md`
|
||||
- **Labrinth (backend):** See `apps/labrinth/AGENTS.md`
|
||||
|
||||
The website and app `prepr` commands
|
||||
|
||||
@@ -62,7 +62,7 @@ The website and app `prepr` commands
|
||||
|
||||
## Project-Specific Instructions
|
||||
|
||||
Each project may have its own `CLAUDE.md` with detailed instructions:
|
||||
Each project may have its own file with detailed instructions:
|
||||
|
||||
- [`apps/labrinth/AGENTS.md`](apps/labrinth/AGENTS.md) — Backend API
|
||||
- [`apps/frontend/CLAUDE.md`](apps/frontend/CLAUDE.md) - Frontend Website
|
||||
|
||||
Generated
+729
-108
File diff suppressed because it is too large
Load Diff
+17
-3
@@ -9,9 +9,11 @@ members = [
|
||||
"packages/ariadne",
|
||||
"packages/daedalus",
|
||||
"packages/labrinth-derive",
|
||||
"packages/modrinth-content-management",
|
||||
"packages/modrinth-log",
|
||||
"packages/modrinth-maxmind",
|
||||
"packages/modrinth-util",
|
||||
"packages/neverbounce",
|
||||
"packages/path-util",
|
||||
]
|
||||
|
||||
@@ -32,7 +34,6 @@ actix-ws = "0.3.0"
|
||||
arc-swap = "1.7.1"
|
||||
argon2 = { version = "0.5.3", features = ["std"] }
|
||||
ariadne = { path = "packages/ariadne" }
|
||||
async-compression = { version = "0.4.32", default-features = false }
|
||||
async-minecraft-ping = { path = "packages/async-minecraft-ping" }
|
||||
async-recursion = "1.1.1"
|
||||
async-stripe = { version = "0.41.0", default-features = false, features = [
|
||||
@@ -51,6 +52,7 @@ aws-sdk-s3 = { version = "=1.122.0", default-features = false, features = [
|
||||
] }
|
||||
base64 = "0.22.1"
|
||||
bitflags = "2.9.4"
|
||||
bon = "3.9.3"
|
||||
bytemuck = "1.24.0"
|
||||
bytes = "1.10.1"
|
||||
censor = "0.3.0"
|
||||
@@ -87,10 +89,12 @@ fs4 = { version = "0.13.1", default-features = false }
|
||||
futures = "0.3.31"
|
||||
futures-lite = "2.6.1"
|
||||
futures-util = "0.3.31"
|
||||
governor = "0.10.4"
|
||||
heck = "0.5.0"
|
||||
hex = "0.4.3"
|
||||
hickory-resolver = "0.25.2"
|
||||
hmac = "0.12.1"
|
||||
httpdate = "1.0.3"
|
||||
hyper = "1.7.0"
|
||||
hyper-rustls = { version = "0.27.7", default-features = false, features = [
|
||||
"aws-lc-rs",
|
||||
@@ -117,13 +121,21 @@ lettre = { version = "0.11.19", default-features = false, features = [
|
||||
"tokio1",
|
||||
"tokio1-rustls",
|
||||
] }
|
||||
lz4_flex = { version = "0.11.5", default-features = false, features = [
|
||||
"checked-decode",
|
||||
"safe-decode",
|
||||
"safe-encode",
|
||||
"std",
|
||||
] }
|
||||
maxminddb = "0.26.0"
|
||||
meilisearch-sdk = { version = "0.30.0", default-features = false }
|
||||
modrinth-content-management = { path = "packages/modrinth-content-management" }
|
||||
modrinth-log = { path = "packages/modrinth-log" }
|
||||
modrinth-util = { path = "packages/modrinth-util" }
|
||||
muralpay = { path = "packages/muralpay" }
|
||||
murmur2 = "0.1.0"
|
||||
native-dialog = "0.9.2"
|
||||
neverbounce = { path = "packages/neverbounce" }
|
||||
notify = { version = "8.2.0", default-features = false }
|
||||
notify-debouncer-mini = { version = "0.7.0", default-features = false }
|
||||
objc2-app-kit = { version = "0.3.2", default-features = false }
|
||||
@@ -133,6 +145,7 @@ paste = "1.0.15"
|
||||
path-util = { path = "packages/path-util" }
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
png = "0.18.0"
|
||||
postcard = { version = "1.1.3", default-features = false, features = ["alloc"] }
|
||||
proc-macro2 = { version = "1.0" }
|
||||
prometheus = "0.14.0"
|
||||
quartz_nbt = "0.2.9"
|
||||
@@ -157,6 +170,7 @@ rust-s3 = { version = "0.37.0", default-features = false, features = [
|
||||
] }
|
||||
rustls = "0.23.32"
|
||||
rusty-money = "0.4.1"
|
||||
scalar_api_reference = { version = "0.2.2", default-features = false }
|
||||
secrecy = "0.10.3"
|
||||
sentry = { version = "0.45.0", default-features = false, features = [
|
||||
"backtrace",
|
||||
@@ -216,10 +230,10 @@ typed-path = "0.12.0"
|
||||
url = "2.5.7"
|
||||
urlencoding = "2.1.3"
|
||||
utoipa = { version = "5.4.0", features = ["actix_extras", "chrono", "decimal"] }
|
||||
utoipa-actix-web = { version = "0.1.2" }
|
||||
utoipa-scalar = { version = "0.3.0", default-features = false }
|
||||
uuid = "1.18.1"
|
||||
validator = "0.20.0"
|
||||
webauthn-rs = "0.5.5"
|
||||
webauthn-rs-proto = "0.5.5"
|
||||
webp = { version = "0.3.1", default-features = false }
|
||||
webview2-com = "0.38.0" # Should be updated in lockstep with wry
|
||||
whoami = "1.6.1"
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Modrinth Monorepo
|
||||
|
||||
Welcome to the Modrinth Monorepo, the primary codebase for the Modrinth web interface and app. It contains  lines of code and has  contributors!
|
||||
Welcome to the Modrinth Monorepo, the primary codebase for the Modrinth web interface and app. It contains  lines of code and has  contributors!
|
||||
|
||||
If you're not a developer and you've stumbled upon this repository, you can access the web interface on the [Modrinth website](https://modrinth.com) and download the latest release of the app [here](https://modrinth.com/app).
|
||||
|
||||
|
||||
@@ -8,8 +8,11 @@ extend-exclude = [
|
||||
"packages/blog/",
|
||||
# contains licenses like `CC-BY-ND-4.0`
|
||||
"packages/moderation/src/data/stages/license.ts",
|
||||
"packages/moderation/src/utils.ts",
|
||||
# contains payment card IDs like `IY1VMST1MOXS` which are flagged
|
||||
"apps/labrinth/src/queue/payouts/mod.rs",
|
||||
# contains domain names with deliberate typos
|
||||
"apps/labrinth/assets/disposable_email_blocklist.txt"
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
|
||||
+145
-34
@@ -89,14 +89,21 @@ import SplashScreen from '@/components/ui/SplashScreen.vue'
|
||||
import WindowControls from '@/components/ui/WindowControls.vue'
|
||||
import { useCheckDisableMouseover } from '@/composables/macCssFix.js'
|
||||
import { config } from '@/config'
|
||||
import { hide_ads_window, init_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import {
|
||||
ads_consent_listener,
|
||||
get_ads_consent_required,
|
||||
hide_ads_window,
|
||||
init_ads_window,
|
||||
perform_ads_consent_action,
|
||||
show_ads_window,
|
||||
} from '@/helpers/ads.js'
|
||||
import { debugAnalytics, initAnalytics, trackEvent } from '@/helpers/analytics'
|
||||
import { check_reachable } from '@/helpers/auth.js'
|
||||
import { get_user, get_version } from '@/helpers/cache.js'
|
||||
import { command_listener, notification_listener, warning_listener } from '@/helpers/events.js'
|
||||
import { install_create_modpack_instance, install_get_modpack_preview } from '@/helpers/install'
|
||||
import { list, run } from '@/helpers/instance'
|
||||
import { cancelLogin, get as getCreds, login, logout } from '@/helpers/mr_auth.ts'
|
||||
import { create_profile_and_install_from_file } from '@/helpers/pack'
|
||||
import { list } from '@/helpers/profile.js'
|
||||
import { mergeUrlQuery, parseModrinthLink } from '@/helpers/project-links.ts'
|
||||
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
|
||||
import { get_opening_command, initialize_state } from '@/helpers/state'
|
||||
@@ -110,6 +117,7 @@ import {
|
||||
isNetworkMetered,
|
||||
setRestartAfterPendingUpdate,
|
||||
} from '@/helpers/utils.js'
|
||||
import { start_join_server, start_join_singleplayer_world } from '@/helpers/worlds.ts'
|
||||
import i18n from '@/i18n.config'
|
||||
import {
|
||||
appUpdateState,
|
||||
@@ -183,6 +191,8 @@ const { handleError, addNotification } = notificationManager
|
||||
const popupNotificationManager = new AppPopupNotificationManager()
|
||||
providePopupNotificationManager(popupNotificationManager)
|
||||
const { addPopupNotification } = popupNotificationManager
|
||||
let adsConsentPopupId = null
|
||||
let unlistenAdsConsent
|
||||
|
||||
const appVersion = getVersion()
|
||||
const tauriApiClient = new TauriModrinthClient({
|
||||
@@ -212,9 +222,20 @@ const { data: authenticatedModrinthUser } = useQuery({
|
||||
enabled: () => !!credentials.value?.session,
|
||||
retry: false,
|
||||
})
|
||||
const hasPlus = computed(
|
||||
() =>
|
||||
!!credentials.value?.user &&
|
||||
(hasMidasBadge(credentials.value.user) ||
|
||||
hasActivePride26Midas(authenticatedModrinthUser.value?.campaigns?.pride_26)),
|
||||
)
|
||||
const showAd = computed(
|
||||
() => sidebarVisible.value && !hasPlus.value && credentials.value !== undefined,
|
||||
)
|
||||
const adConsentAvailable = computed(() => credentials.value !== undefined && !hasPlus.value)
|
||||
providePageContext({
|
||||
hierarchicalSidebarAvailable: ref(true),
|
||||
showAds: ref(false),
|
||||
showAds: showAd,
|
||||
adConsentAvailable,
|
||||
floatingActionBarOffsets: {
|
||||
left: ref(APP_LEFT_NAV_WIDTH),
|
||||
right: computed(() => (sidebarVisible.value ? `${APP_SIDEBAR_WIDTH}px` : '0px')),
|
||||
@@ -294,6 +315,12 @@ const authUnreachable = computed(() => {
|
||||
|
||||
onMounted(async () => {
|
||||
await useCheckDisableMouseover()
|
||||
try {
|
||||
unlistenAdsConsent = await ads_consent_listener(handleAdsConsentRequired)
|
||||
handleAdsConsentRequired(await get_ads_consent_required())
|
||||
} catch (error) {
|
||||
handleError(error)
|
||||
}
|
||||
|
||||
document.querySelector('body').addEventListener('click', handleClick)
|
||||
document.querySelector('body').addEventListener('auxclick', handleAuxClick)
|
||||
@@ -307,6 +334,7 @@ onUnmounted(async () => {
|
||||
unsubscribeSidebarToggle()
|
||||
clearDelayedUpdatePopup()
|
||||
|
||||
await unlistenAdsConsent?.()
|
||||
await unlistenUpdateDownload?.()
|
||||
})
|
||||
|
||||
@@ -331,8 +359,77 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'Minecraft authentication servers may be down right now. Check your internet connection and try again later.',
|
||||
},
|
||||
adsConsentTitle: {
|
||||
id: 'app.ads-consent.title',
|
||||
defaultMessage: 'Your privacy and how ads support Modrinth',
|
||||
},
|
||||
adsConsentBody: {
|
||||
id: 'app.ads-consent.body',
|
||||
defaultMessage:
|
||||
'Ads make Modrinth possible and fund creator payouts. Our partners may store or access cookies in the app to personalize ads and measure performance.',
|
||||
},
|
||||
adsConsentManage: {
|
||||
id: 'app.ads-consent.manage',
|
||||
defaultMessage: 'Manage preferences',
|
||||
},
|
||||
adsConsentReject: {
|
||||
id: 'app.ads-consent.reject',
|
||||
defaultMessage: 'Reject all',
|
||||
},
|
||||
adsConsentAccept: {
|
||||
id: 'app.ads-consent.accept',
|
||||
defaultMessage: 'Accept all',
|
||||
},
|
||||
})
|
||||
|
||||
function handleAdsConsentRequired(required) {
|
||||
if (!required) {
|
||||
if (adsConsentPopupId !== null) {
|
||||
popupNotificationManager.removeNotification(adsConsentPopupId)
|
||||
adsConsentPopupId = null
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
adsConsentPopupId !== null &&
|
||||
popupNotificationManager.getNotifications().some((item) => item.id === adsConsentPopupId)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const notification = addPopupNotification({
|
||||
title: formatMessage(messages.adsConsentTitle),
|
||||
text: formatMessage(messages.adsConsentBody),
|
||||
type: 'info',
|
||||
hideIcon: true,
|
||||
autoCloseMs: null,
|
||||
dismissible: false,
|
||||
buttons: [
|
||||
{
|
||||
label: formatMessage(messages.adsConsentManage),
|
||||
action: () => perform_ads_consent_action('manage').catch(handleError),
|
||||
color: 'standard',
|
||||
keepOpen: true,
|
||||
},
|
||||
{
|
||||
label: formatMessage(messages.adsConsentReject),
|
||||
action: () => perform_ads_consent_action('reject').catch(handleError),
|
||||
color: 'brand',
|
||||
keepOpen: true,
|
||||
},
|
||||
{
|
||||
label: formatMessage(messages.adsConsentAccept),
|
||||
action: () => perform_ads_consent_action('accept').catch(handleError),
|
||||
color: 'brand',
|
||||
keepOpen: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
adsConsentPopupId = notification.id
|
||||
}
|
||||
|
||||
async function setupApp() {
|
||||
const {
|
||||
native_decorations,
|
||||
@@ -402,7 +499,7 @@ async function setupApp() {
|
||||
addNotification({
|
||||
title: 'Warning',
|
||||
text: e.message,
|
||||
type: 'warn',
|
||||
type: 'warning',
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -702,17 +799,6 @@ async function logOut() {
|
||||
await fetchCredentials()
|
||||
}
|
||||
|
||||
const hasPlus = computed(
|
||||
() =>
|
||||
!!credentials.value?.user &&
|
||||
(hasMidasBadge(credentials.value.user) ||
|
||||
hasActivePride26Midas(authenticatedModrinthUser.value?.campaigns?.pride_26)),
|
||||
)
|
||||
|
||||
const showAd = computed(
|
||||
() => sidebarVisible.value && !hasPlus.value && credentials.value !== undefined,
|
||||
)
|
||||
|
||||
async function fetchIntercomToken() {
|
||||
const creds = await getCreds()
|
||||
if (!creds?.session) {
|
||||
@@ -739,13 +825,21 @@ async function fetchIntercomToken() {
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
watch(showAd, () => {
|
||||
if (!showAd.value) {
|
||||
hide_ads_window(true)
|
||||
} else {
|
||||
init_ads_window(true)
|
||||
}
|
||||
})
|
||||
watch(
|
||||
[showAd, adConsentAvailable],
|
||||
async ([showAds, canManageConsent]) => {
|
||||
if (showAds) {
|
||||
await init_ads_window(true)
|
||||
return
|
||||
}
|
||||
|
||||
await hide_ads_window(true)
|
||||
if (canManageConsent) {
|
||||
await init_ads_window()
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
invoke('show_window')
|
||||
@@ -852,13 +946,31 @@ async function handleCommand(e) {
|
||||
if (e.event === 'RunMRPack') {
|
||||
// RunMRPack should directly install a local mrpack given a path
|
||||
if (e.path.endsWith('.mrpack')) {
|
||||
await create_profile_and_install_from_file(e.path, (createProfile, fileName) =>
|
||||
unknownPackWarningModal.value?.show(createProfile, fileName),
|
||||
).catch(handleError)
|
||||
const location = { type: 'fromFile', path: e.path }
|
||||
const preview = await install_get_modpack_preview(location).catch(handleError)
|
||||
if (preview?.unknownFile || preview?.externalFilesInModpack.length > 0) {
|
||||
const splitPath = e.path.split(/[\\/]/)
|
||||
const fileName = splitPath ? splitPath[splitPath.length - 1] : e.path
|
||||
unknownPackWarningModal.value?.show(
|
||||
() => install_create_modpack_instance(location).then(() => undefined),
|
||||
fileName,
|
||||
preview.externalFilesInModpack,
|
||||
)
|
||||
} else {
|
||||
await install_create_modpack_instance(location).catch(handleError)
|
||||
}
|
||||
trackEvent('InstanceCreate', {
|
||||
source: 'CreationModalFileDrop',
|
||||
})
|
||||
}
|
||||
} else if (e.event === 'LaunchInstance') {
|
||||
if (e.server) {
|
||||
await start_join_server(e.id, e.server).catch(handleError)
|
||||
} else if (e.singleplayer_world) {
|
||||
await start_join_singleplayer_world(e.id, e.singleplayer_world).catch(handleError)
|
||||
} else {
|
||||
await run(e.id).catch(handleError)
|
||||
}
|
||||
} else if (e.event === 'InstallServer') {
|
||||
await router.push(`/project/${e.id}`)
|
||||
await playServerProject(e.id).catch(handleError)
|
||||
@@ -1323,12 +1435,11 @@ async function processPendingSurveys() {
|
||||
const creds = await getCreds().catch(handleError)
|
||||
const userId = creds?.user_id
|
||||
|
||||
const instances = await list().catch(handleError)
|
||||
const isActivePlayer =
|
||||
instances.findIndex(
|
||||
(instance) =>
|
||||
isWithinLastTwoWeeks(instance.last_played) && !isWithinLastTwoWeeks(instance.created),
|
||||
) >= 0
|
||||
const instances = (await list().catch(handleError)) ?? []
|
||||
const isActivePlayer = instances.some(
|
||||
(instance) =>
|
||||
isWithinLastTwoWeeks(instance.last_played) && !isWithinLastTwoWeeks(instance.created),
|
||||
)
|
||||
|
||||
let surveys = []
|
||||
try {
|
||||
@@ -1719,8 +1830,8 @@ provideAppUpdateDownloadProgress(appUpdateDownload)
|
||||
@create-anyway="handleContentInstallModpackDuplicateCreateAnyway"
|
||||
@go-to-instance="handleContentInstallModpackDuplicateGoToInstance"
|
||||
/>
|
||||
<InstallToPlayModal ref="installToPlayModal" />
|
||||
<UpdateToPlayModal ref="updateToPlayModal" />
|
||||
<InstallToPlayModal ref="installToPlayModal" :show-external-warnings="false" />
|
||||
<UpdateToPlayModal ref="updateToPlayModal" :show-external-warnings="false" />
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -24,7 +24,8 @@ import { computed, ref } from 'vue'
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import ConfirmDeleteInstanceModal from '@/components/ui/modal/ConfirmDeleteInstanceModal.vue'
|
||||
import { duplicate, remove } from '@/helpers/profile.js'
|
||||
import { install_duplicate_instance } from '@/helpers/install'
|
||||
import { remove } from '@/helpers/instance'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
@@ -48,21 +49,21 @@ const instanceComponents = ref(null)
|
||||
const currentDeleteInstance = ref(null)
|
||||
const confirmModal = ref(null)
|
||||
|
||||
async function deleteProfile() {
|
||||
async function deleteInstance() {
|
||||
if (currentDeleteInstance.value) {
|
||||
instanceComponents.value = instanceComponents.value.filter(
|
||||
(x) => x.instance.path !== currentDeleteInstance.value,
|
||||
(x) => x.instance.id !== currentDeleteInstance.value,
|
||||
)
|
||||
await remove(currentDeleteInstance.value).catch(handleError)
|
||||
}
|
||||
}
|
||||
|
||||
async function duplicateProfile(p) {
|
||||
await duplicate(p).catch(handleError)
|
||||
async function duplicateInstance(p) {
|
||||
await install_duplicate_instance(p).catch(handleError)
|
||||
}
|
||||
|
||||
const handleRightClick = (event, profilePathId) => {
|
||||
const item = instanceComponents.value.find((x) => x.instance.path === profilePathId)
|
||||
const handleRightClick = (event, instanceId) => {
|
||||
const item = instanceComponents.value.find((x) => x.instance.id === instanceId)
|
||||
const baseOptions = [
|
||||
{ name: 'add_content' },
|
||||
{ type: 'divider' },
|
||||
@@ -114,16 +115,16 @@ const handleOptionsClick = async (args) => {
|
||||
break
|
||||
case 'duplicate':
|
||||
if (args.item.instance.install_stage == 'installed')
|
||||
await duplicateProfile(args.item.instance.path)
|
||||
await duplicateInstance(args.item.instance.id)
|
||||
break
|
||||
case 'open':
|
||||
await args.item.openFolder()
|
||||
break
|
||||
case 'copy':
|
||||
await navigator.clipboard.writeText(args.item.instance.path)
|
||||
await navigator.clipboard.writeText(args.item.instance.id)
|
||||
break
|
||||
case 'delete':
|
||||
currentDeleteInstance.value = args.item.instance.path
|
||||
currentDeleteInstance.value = args.item.instance.id
|
||||
confirmModal.value.show()
|
||||
break
|
||||
}
|
||||
@@ -321,13 +322,13 @@ const filteredResults = computed(() => {
|
||||
<Instance
|
||||
v-for="instance in instanceSection.value"
|
||||
ref="instanceComponents"
|
||||
:key="instance.path + instance.install_stage"
|
||||
:key="instance.id + instance.install_stage"
|
||||
:instance="instance"
|
||||
@contextmenu.prevent.stop="(event) => handleRightClick(event, instance.path)"
|
||||
@contextmenu.prevent.stop="(event) => handleRightClick(event, instance.id)"
|
||||
/>
|
||||
</section>
|
||||
</Accordion>
|
||||
<ConfirmDeleteInstanceModal ref="confirmModal" @delete="deleteProfile" />
|
||||
<ConfirmDeleteInstanceModal ref="confirmModal" @delete="deleteInstance" />
|
||||
<ContextMenu ref="instanceOptions" @option-clicked="handleOptionsClick">
|
||||
<template #play> <PlayIcon /> Play </template>
|
||||
<template #stop> <StopCircleIcon /> Stop </template>
|
||||
|
||||
@@ -21,9 +21,10 @@ import Instance from '@/components/ui/Instance.vue'
|
||||
import LegacyProjectCard from '@/components/ui/LegacyProjectCard.vue'
|
||||
import ConfirmDeleteInstanceModal from '@/components/ui/modal/ConfirmDeleteInstanceModal.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_by_profile_path } from '@/helpers/process.js'
|
||||
import { duplicate, kill, remove, run } from '@/helpers/profile.js'
|
||||
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||
import { install_duplicate_instance } from '@/helpers/install'
|
||||
import { kill, remove, run } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process.js'
|
||||
import { showInstanceInFolder } from '@/helpers/utils.js'
|
||||
import { injectContentInstall } from '@/providers/content-install'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
|
||||
@@ -60,14 +61,14 @@ const deleteConfirmModal = ref(null)
|
||||
|
||||
const currentDeleteInstance = ref(null)
|
||||
|
||||
async function deleteProfile() {
|
||||
async function deleteInstance() {
|
||||
if (currentDeleteInstance.value) {
|
||||
await remove(currentDeleteInstance.value).catch(handleError)
|
||||
}
|
||||
}
|
||||
|
||||
async function duplicateProfile(p) {
|
||||
await duplicate(p).catch(handleError)
|
||||
async function duplicateInstance(p) {
|
||||
await install_duplicate_instance(p).catch(handleError)
|
||||
}
|
||||
|
||||
const handleInstanceRightClick = async (event, passedInstance) => {
|
||||
@@ -85,7 +86,7 @@ const handleInstanceRightClick = async (event, passedInstance) => {
|
||||
},
|
||||
]
|
||||
|
||||
const runningProcesses = await get_by_profile_path(passedInstance.path).catch(handleError)
|
||||
const runningProcesses = await get_by_instance_id(passedInstance.id).catch(handleError)
|
||||
|
||||
const options =
|
||||
runningProcesses.length > 0
|
||||
@@ -126,16 +127,14 @@ const handleProjectClick = (event, passedInstance) => {
|
||||
const handleOptionsClick = async (args) => {
|
||||
switch (args.option) {
|
||||
case 'play':
|
||||
await run(args.item.path).catch((err) =>
|
||||
handleSevereError(err, { profilePath: args.item.path }),
|
||||
)
|
||||
await run(args.item.id).catch((err) => handleSevereError(err, { instanceId: args.item.id }))
|
||||
trackEvent('InstanceStart', {
|
||||
loader: args.item.loader,
|
||||
game_version: args.item.game_version,
|
||||
})
|
||||
break
|
||||
case 'stop':
|
||||
await kill(args.item.path).catch(handleError)
|
||||
await kill(args.item.id).catch(handleError)
|
||||
trackEvent('InstanceStop', {
|
||||
loader: args.item.loader,
|
||||
game_version: args.item.game_version,
|
||||
@@ -144,26 +143,26 @@ const handleOptionsClick = async (args) => {
|
||||
case 'add_content':
|
||||
await router.push({
|
||||
path: `/browse/${args.item.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
||||
query: { i: args.item.path },
|
||||
query: { i: args.item.id },
|
||||
})
|
||||
break
|
||||
case 'edit':
|
||||
await router.push({
|
||||
path: `/instance/${encodeURIComponent(args.item.path)}`,
|
||||
path: `/instance/${encodeURIComponent(args.item.id)}`,
|
||||
})
|
||||
break
|
||||
case 'duplicate':
|
||||
if (args.item.install_stage == 'installed') await duplicateProfile(args.item.path)
|
||||
if (args.item.install_stage == 'installed') await duplicateInstance(args.item.id)
|
||||
break
|
||||
case 'delete':
|
||||
currentDeleteInstance.value = args.item.path
|
||||
currentDeleteInstance.value = args.item.id
|
||||
deleteConfirmModal.value.show()
|
||||
break
|
||||
case 'open_folder':
|
||||
await showProfileInFolder(args.item.path)
|
||||
await showInstanceInFolder(args.item.id)
|
||||
break
|
||||
case 'copy_path':
|
||||
await navigator.clipboard.writeText(args.item.path)
|
||||
await navigator.clipboard.writeText(args.item.id)
|
||||
break
|
||||
case 'install': {
|
||||
await installVersion(
|
||||
@@ -239,7 +238,7 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmDeleteInstanceModal ref="deleteConfirmModal" @delete="deleteProfile" />
|
||||
<ConfirmDeleteInstanceModal ref="deleteConfirmModal" @delete="deleteInstance" />
|
||||
<div ref="rowContainer" class="flex flex-col gap-4">
|
||||
<div v-for="row in actualInstances" ref="rows" :key="row.label" class="row">
|
||||
<HeadingLink class="mt-1" :to="row.route">
|
||||
@@ -256,7 +255,7 @@ onUnmounted(() => {
|
||||
0,
|
||||
row.compact ? maxInstancesPerCompactRow : maxInstancesPerRow,
|
||||
)"
|
||||
:key="row.label + instance.path"
|
||||
:key="row.label + instance.id"
|
||||
:instance="instance"
|
||||
:compact="row.compact"
|
||||
:first="instanceIndex === 0"
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ButtonStyled, injectNotificationManager, OverflowMenu } from '@modrinth
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { add_project_from_path } from '@/helpers/profile.js'
|
||||
import { add_project_from_path } from '@/helpers/instance'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
@@ -22,14 +22,14 @@ const handleAddContentFromFile = async () => {
|
||||
if (!newProject) return
|
||||
|
||||
for (const project of newProject) {
|
||||
await add_project_from_path(props.instance.path, project.path ?? project).catch(handleError)
|
||||
await add_project_from_path(props.instance.id, project.path ?? project).catch(handleError)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSearchContent = async () => {
|
||||
await router.push({
|
||||
path: `/browse/${props.instance.loader === 'vanilla' ? 'resourcepack' : 'mod'}`,
|
||||
query: { i: props.instance.path },
|
||||
query: { i: props.instance.id },
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -14,31 +14,7 @@
|
||||
<UnplugIcon class="text-secondary" />
|
||||
<span class="text-sm text-contrast"> {{ formatMessage(messages.offline) }} </span>
|
||||
</div>
|
||||
<ButtonStyled color="brand" type="outlined" hover-color-fill="background">
|
||||
<button
|
||||
v-if="showUpdatePill"
|
||||
type="button"
|
||||
class="!h-[34px] overflow-hidden text-sm !transition-[width,opacity,transform,background-color,color,filter] !duration-200 ease-out"
|
||||
:class="[
|
||||
updatePillWidthClass,
|
||||
{
|
||||
'update-pill-ready-hidden': finishedDownloading && !animateReadyPill,
|
||||
'update-pill-ready-visible': finishedDownloading && animateReadyPill,
|
||||
},
|
||||
]"
|
||||
:disabled="isUpdateDownloading"
|
||||
:aria-busy="isUpdateDownloading"
|
||||
@click="handleUpdateClick"
|
||||
>
|
||||
<RefreshCwIcon v-if="finishedDownloading" :class="{ 'animate-spin': restarting }" />
|
||||
<DownloadIcon v-else />
|
||||
<span v-if="isUpdateDownloading">
|
||||
{{ formatMessage(messages.downloadingUpdate) }}
|
||||
<span class="inline-block w-[3ch] text-right tabular-nums">{{ downloadPercent }}%</span>
|
||||
</span>
|
||||
<span v-else>{{ updateLabel }}</span>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<AppUpdateButton />
|
||||
<div
|
||||
class="flex border-solid border-surface-5 text-sm items-center gap-2 py-1.5 px-3 rounded-xl border"
|
||||
>
|
||||
@@ -47,28 +23,28 @@
|
||||
<div class="text-contrast flex items-center gap-2">
|
||||
<router-link
|
||||
v-tooltip="formatMessage(messages.viewInstance)"
|
||||
:to="`/instance/${encodeURIComponent(selectedProcess.profile.path)}`"
|
||||
:to="`/instance/${encodeURIComponent(selectedProcess.instance.id)}`"
|
||||
class="hover:underline"
|
||||
>
|
||||
{{ selectedProcess.profile.name }}
|
||||
{{ selectedProcess.instance.name }}
|
||||
</router-link>
|
||||
<Dropdown
|
||||
v-if="currentProcesses.length > 1"
|
||||
placement="bottom"
|
||||
:triggers="['click']"
|
||||
:hide-triggers="['click']"
|
||||
@show="showProfiles = true"
|
||||
@hide="showProfiles = false"
|
||||
@show="showInstances = true"
|
||||
@hide="showInstances = false"
|
||||
>
|
||||
<ButtonStyled type="transparent" circular size="small">
|
||||
<button
|
||||
v-tooltip="
|
||||
showProfiles
|
||||
showInstances
|
||||
? formatMessage(messages.hideMoreRunningInstances)
|
||||
: formatMessage(messages.showMoreRunningInstances)
|
||||
"
|
||||
>
|
||||
<DropdownIcon :class="{ 'rotate-180': !!showProfiles }" />
|
||||
<DropdownIcon :class="{ 'rotate-180': !!showInstances }" />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<template #popper>
|
||||
@@ -93,7 +69,7 @@
|
||||
>
|
||||
<OnlineIndicatorIcon />
|
||||
<span class="mr-auto text-contrast flex items-center gap-2">
|
||||
{{ process.profile.name }}
|
||||
{{ process.instance.name }}
|
||||
<StarIcon v-if="process.uuid === selectedProcess.uuid" class="text-orange" />
|
||||
</span>
|
||||
</button>
|
||||
@@ -107,7 +83,7 @@
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.viewLogs)"
|
||||
class="active:scale-95 flex"
|
||||
@click.stop="goToTerminal(process.profile.path)"
|
||||
@click.stop="goToTerminal(process.instance.id)"
|
||||
>
|
||||
<TerminalSquareIcon class="text-secondary size-5" />
|
||||
</button>
|
||||
@@ -144,7 +120,6 @@ import {
|
||||
DownloadIcon,
|
||||
DropdownIcon,
|
||||
OnlineIndicatorIcon,
|
||||
RefreshCwIcon,
|
||||
StarIcon,
|
||||
StopCircleIcon,
|
||||
TerminalSquareIcon,
|
||||
@@ -161,21 +136,18 @@ import {
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { Dropdown } from 'floating-vue'
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import AppUpdateButton from '@/components/ui/app-update-button/index.vue'
|
||||
import { useInstallJobNotifications } from '@/composables/browse/install-job-notifications'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { loading_listener, process_listener } from '@/helpers/events'
|
||||
import { get_many as getInstances } from '@/helpers/instance'
|
||||
import { get_all as getRunningProcesses, kill as killProcess } from '@/helpers/process'
|
||||
import { get_many as getInstances } from '@/helpers/profile.js'
|
||||
import type { LoadingBar } from '@/helpers/state'
|
||||
import { progress_bars_list } from '@/helpers/state'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import {
|
||||
appUpdateState,
|
||||
downloadAvailableAppUpdate,
|
||||
installAvailableAppUpdate,
|
||||
} from '@/providers/app-update'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const popupNotificationManager = injectPopupNotificationManager()
|
||||
@@ -183,12 +155,12 @@ const { formatMessage } = useVIntl()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const showProfiles = ref(false)
|
||||
const showInstances = ref(false)
|
||||
|
||||
interface RunningProcess {
|
||||
uuid: string
|
||||
profile_path: string
|
||||
profile: GameInstance
|
||||
instance_id: string
|
||||
instance: GameInstance
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -240,96 +212,8 @@ const messages = defineMessages({
|
||||
id: 'app.action-bar.view-active-downloads',
|
||||
defaultMessage: 'View active downloads',
|
||||
},
|
||||
update: {
|
||||
id: 'app.action-bar.update',
|
||||
defaultMessage: 'Update',
|
||||
},
|
||||
downloadingUpdate: {
|
||||
id: 'app.action-bar.downloading-update',
|
||||
defaultMessage: 'Downloading update',
|
||||
},
|
||||
reloadToUpdate: {
|
||||
id: 'app.action-bar.reload-to-update',
|
||||
defaultMessage: 'Reload to update',
|
||||
},
|
||||
})
|
||||
|
||||
const {
|
||||
downloading,
|
||||
downloadPercent,
|
||||
downloadProgress,
|
||||
finishedDownloading,
|
||||
isVisible: isUpdateVisible,
|
||||
metered,
|
||||
restarting,
|
||||
} = appUpdateState
|
||||
|
||||
const isUpdateDownloading = computed(
|
||||
() =>
|
||||
downloading.value ||
|
||||
(downloadProgress.value > 0 && downloadProgress.value < 1 && !finishedDownloading.value),
|
||||
)
|
||||
const showUpdatePill = computed(
|
||||
() => isUpdateVisible.value && (finishedDownloading.value || metered.value),
|
||||
)
|
||||
const animateReadyPill = ref(false)
|
||||
const updateLabel = computed(() => {
|
||||
if (isUpdateDownloading.value) {
|
||||
return formatMessage(messages.downloadingUpdate)
|
||||
}
|
||||
|
||||
if (finishedDownloading.value) {
|
||||
return formatMessage(messages.reloadToUpdate)
|
||||
}
|
||||
|
||||
return formatMessage(messages.update)
|
||||
})
|
||||
const updatePillWidthClass = computed(() => {
|
||||
if (isUpdateDownloading.value) {
|
||||
return 'w-[219px]'
|
||||
}
|
||||
|
||||
if (finishedDownloading.value) {
|
||||
return 'w-[166px]'
|
||||
}
|
||||
|
||||
return '!w-[96px]'
|
||||
})
|
||||
let readyPillAnimationFrame: number | null = null
|
||||
watch([showUpdatePill, finishedDownloading], async ([show, ready], [wasShown, wasReady]) => {
|
||||
if (readyPillAnimationFrame !== null) {
|
||||
cancelAnimationFrame(readyPillAnimationFrame)
|
||||
readyPillAnimationFrame = null
|
||||
}
|
||||
|
||||
if (!show || !ready) {
|
||||
animateReadyPill.value = false
|
||||
return
|
||||
}
|
||||
|
||||
if (wasShown && wasReady) {
|
||||
return
|
||||
}
|
||||
|
||||
animateReadyPill.value = false
|
||||
await nextTick()
|
||||
readyPillAnimationFrame = requestAnimationFrame(() => {
|
||||
animateReadyPill.value = true
|
||||
readyPillAnimationFrame = null
|
||||
})
|
||||
})
|
||||
async function handleUpdateClick() {
|
||||
if (isUpdateDownloading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (finishedDownloading.value) {
|
||||
await installAvailableAppUpdate()
|
||||
} else {
|
||||
await downloadAvailableAppUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
const currentProcesses = ref<RunningProcess[]>([])
|
||||
const selectedProcess = ref<RunningProcess | undefined>()
|
||||
|
||||
@@ -337,22 +221,22 @@ const refresh = async () => {
|
||||
const processes = ((await getRunningProcesses().catch((error) => {
|
||||
handleError(error)
|
||||
return []
|
||||
})) ?? []) as Array<{ uuid: string; profile_path: string }>
|
||||
const paths = processes.map((process) => process.profile_path)
|
||||
const profiles: GameInstance[] = await getInstances(paths).catch((error) => {
|
||||
})) ?? []) as Array<{ uuid: string; instance_id: string }>
|
||||
const instanceIds = processes.map((process) => process.instance_id)
|
||||
const instances: GameInstance[] = await getInstances(instanceIds).catch((error) => {
|
||||
handleError(error)
|
||||
return []
|
||||
})
|
||||
|
||||
currentProcesses.value = processes
|
||||
.map((process) => {
|
||||
const profile = profiles.find((item) => process.profile_path === item.path)
|
||||
if (!profile) {
|
||||
const instance = instances.find((item) => process.instance_id === item.id)
|
||||
if (!instance) {
|
||||
return null
|
||||
}
|
||||
return {
|
||||
...process,
|
||||
profile,
|
||||
instance,
|
||||
}
|
||||
})
|
||||
.filter((process): process is RunningProcess => process !== null)
|
||||
@@ -385,8 +269,8 @@ const stop = async (process: RunningProcess) => {
|
||||
await killProcess(process.uuid).catch(handleError)
|
||||
|
||||
trackEvent('InstanceStop', {
|
||||
loader: process.profile.loader,
|
||||
game_version: process.profile.game_version,
|
||||
loader: process.instance.loader,
|
||||
game_version: process.instance.game_version,
|
||||
source: 'AppBar',
|
||||
})
|
||||
} catch (e) {
|
||||
@@ -395,12 +279,12 @@ const stop = async (process: RunningProcess) => {
|
||||
await refresh()
|
||||
}
|
||||
|
||||
function goToTerminal(path?: string) {
|
||||
const selectedPath = path ?? selectedProcess.value?.profile.path
|
||||
if (!selectedPath) {
|
||||
function goToTerminal(instanceId?: string) {
|
||||
const selectedInstanceId = instanceId ?? selectedProcess.value?.instance.id
|
||||
if (!selectedInstanceId) {
|
||||
return
|
||||
}
|
||||
router.push(`/instance/${encodeURIComponent(selectedPath)}/logs`)
|
||||
router.push(`/instance/${encodeURIComponent(selectedInstanceId)}/logs`)
|
||||
}
|
||||
|
||||
const currentLoadingBars = ref<LoadingBar[]>([])
|
||||
@@ -420,8 +304,7 @@ function getLoadingProgress(loadingBar: LoadingBar): number {
|
||||
}
|
||||
|
||||
function getLoadingText(loadingBar: LoadingBar): string {
|
||||
const percent = Math.floor(getLoadingProgress(loadingBar) * 100)
|
||||
return loadingBar.message ? `${percent}% ${loadingBar.message}` : `${percent}%`
|
||||
return loadingBar.message ?? ''
|
||||
}
|
||||
|
||||
function getDisplayIconUrl(icon: string | null | undefined): string | null {
|
||||
@@ -453,25 +336,33 @@ function removeNotification(): void {
|
||||
}
|
||||
|
||||
function buildDownloadItems(): PopupNotificationProgressItem[] {
|
||||
return currentLoadingBars.value.map((bar) => ({
|
||||
id: getLoadingBarKey(bar),
|
||||
title: bar.title ?? '',
|
||||
text: getLoadingText(bar),
|
||||
iconUrl: currentLoadingBarIconUrls.value[getLoadingBarKey(bar)] ?? null,
|
||||
progress: getLoadingProgress(bar),
|
||||
waiting: !bar.total || bar.total <= 0,
|
||||
}))
|
||||
return [
|
||||
...installJobNotifications.progressItems.value,
|
||||
...currentLoadingBars.value.map((bar) => ({
|
||||
id: getLoadingBarKey(bar),
|
||||
title: bar.title ?? '',
|
||||
text: getLoadingText(bar),
|
||||
iconUrl: currentLoadingBarIconUrls.value[getLoadingBarKey(bar)] ?? null,
|
||||
progress: getLoadingProgress(bar),
|
||||
waiting: !bar.total || bar.total <= 0,
|
||||
progressType: 'percentage',
|
||||
progressCurrent: bar.current,
|
||||
progressTotal: bar.total,
|
||||
})),
|
||||
]
|
||||
}
|
||||
|
||||
const hasVisibleActiveDownloadToasts = computed(() => !!getNotification())
|
||||
const hasActiveLoadingBars = computed(() => currentLoadingBars.value.length > 0)
|
||||
const hasActiveLoadingBars = computed(
|
||||
() => currentLoadingBars.value.length > 0 || installJobNotifications.active.value,
|
||||
)
|
||||
|
||||
function updateNotification(resummon = false): void {
|
||||
if (resummon) {
|
||||
dismissed.value = false
|
||||
}
|
||||
|
||||
if (currentLoadingBars.value.length === 0) {
|
||||
if (currentLoadingBars.value.length === 0 && !installJobNotifications.active.value) {
|
||||
removeNotification()
|
||||
dismissed.value = false
|
||||
return
|
||||
@@ -490,17 +381,23 @@ function updateNotification(resummon = false): void {
|
||||
const progressItems = buildDownloadItems()
|
||||
|
||||
if (notif) {
|
||||
notif.title = formatMessage(messages.downloads)
|
||||
notif.title = installJobNotifications.active.value
|
||||
? installJobNotifications.title.value
|
||||
: formatMessage(messages.downloads)
|
||||
notif.text = undefined
|
||||
notif.progressItems = progressItems
|
||||
notif.buttons = installJobNotifications.buttons.value
|
||||
notif.progress = undefined
|
||||
notif.waiting = undefined
|
||||
} else {
|
||||
notif = popupNotificationManager.addPopupNotification({
|
||||
title: formatMessage(messages.downloads),
|
||||
title: installJobNotifications.active.value
|
||||
? installJobNotifications.title.value
|
||||
: formatMessage(messages.downloads),
|
||||
type: 'download',
|
||||
autoCloseMs: null,
|
||||
progressItems,
|
||||
buttons: installJobNotifications.buttons.value,
|
||||
})
|
||||
notificationId.value = notif.id
|
||||
}
|
||||
@@ -513,8 +410,8 @@ function formatLoadingBars(loadingBar: LoadingBar): LoadingBar {
|
||||
version: formatted.bar_type.version,
|
||||
})
|
||||
}
|
||||
if (formatted.bar_type?.profile_path) {
|
||||
formatted.title = formatted.bar_type.profile_path
|
||||
if (formatted.bar_type?.instance_id) {
|
||||
formatted.title = formatted.bar_type.instance_name ?? formatted.bar_type.instance_id
|
||||
}
|
||||
if (formatted.bar_type?.pack_name) {
|
||||
formatted.title = formatted.bar_type.pack_name
|
||||
@@ -530,31 +427,41 @@ async function refreshLoadingBars() {
|
||||
|
||||
currentLoadingBars.value = Object.values(bars)
|
||||
.map(formatLoadingBars)
|
||||
.filter((bar) => bar?.bar_type?.type !== 'launcher_update')
|
||||
.filter(
|
||||
(bar) =>
|
||||
bar?.bar_type?.type !== 'launcher_update' &&
|
||||
![
|
||||
'java_download',
|
||||
'pack_file_download',
|
||||
'pack_download',
|
||||
'minecraft_download',
|
||||
'copy_instance',
|
||||
].includes(bar?.bar_type?.type ?? ''),
|
||||
)
|
||||
|
||||
const profilePaths = Array.from(
|
||||
const instanceIds = Array.from(
|
||||
new Set(
|
||||
currentLoadingBars.value
|
||||
.map((bar) => bar.bar_type?.profile_path)
|
||||
.filter((path): path is string => !!path),
|
||||
.map((bar) => bar.bar_type?.instance_id)
|
||||
.filter((instanceId): instanceId is string => !!instanceId),
|
||||
),
|
||||
)
|
||||
const profiles = profilePaths.length
|
||||
? await getInstances(profilePaths).catch((error) => {
|
||||
const instances = instanceIds.length
|
||||
? await getInstances(instanceIds).catch((error) => {
|
||||
handleError(error)
|
||||
return []
|
||||
})
|
||||
: []
|
||||
const profileIconUrls = new Map(
|
||||
profiles.map((profile) => [profile.path, getDisplayIconUrl(profile.icon_path)]),
|
||||
const instanceIconUrls = new Map(
|
||||
instances.map((instance) => [instance.id, getDisplayIconUrl(instance.icon_path)]),
|
||||
)
|
||||
currentLoadingBarIconUrls.value = Object.fromEntries(
|
||||
currentLoadingBars.value.map((bar) => {
|
||||
const barIconUrl = getDisplayIconUrl(bar.bar_type?.icon)
|
||||
const profileIconUrl = bar.bar_type?.profile_path
|
||||
? profileIconUrls.get(bar.bar_type.profile_path)
|
||||
const instanceIconUrl = bar.bar_type?.instance_id
|
||||
? instanceIconUrls.get(bar.bar_type.instance_id)
|
||||
: null
|
||||
return [getLoadingBarKey(bar), barIconUrl ?? profileIconUrl ?? null]
|
||||
return [getLoadingBarKey(bar), barIconUrl ?? instanceIconUrl ?? null]
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -567,6 +474,12 @@ async function refreshLoadingBars() {
|
||||
updateNotification()
|
||||
}
|
||||
|
||||
const installJobNotifications = await useInstallJobNotifications({
|
||||
router,
|
||||
handleError,
|
||||
onChange: updateNotification,
|
||||
})
|
||||
|
||||
await refreshLoadingBars()
|
||||
|
||||
const unlistenLoading = await loading_listener(async () => {
|
||||
@@ -588,20 +501,6 @@ onBeforeUnmount(() => {
|
||||
window.removeEventListener('online', handleOnline)
|
||||
unlistenProcess()
|
||||
unlistenLoading()
|
||||
if (readyPillAnimationFrame !== null) {
|
||||
cancelAnimationFrame(readyPillAnimationFrame)
|
||||
}
|
||||
installJobNotifications.dispose()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.update-pill-ready-hidden {
|
||||
opacity: 0;
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.update-pill-ready-visible {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div v-for="(option, index) in options" :key="index" @click.stop="optionClicked(option.name)">
|
||||
<hr v-if="option.type === 'divider'" class="divider" />
|
||||
<div
|
||||
v-else-if="!(isLinkedData(item) && option.name === `add_content`)"
|
||||
v-else-if="!(isInstanceLink(item) && option.name === `add_content`)"
|
||||
class="item clickable"
|
||||
:class="[option.color ?? 'base']"
|
||||
>
|
||||
@@ -64,10 +64,10 @@ defineExpose({
|
||||
},
|
||||
})
|
||||
|
||||
const isLinkedData = (item) => {
|
||||
if (item.instance != undefined && item.instance.linked_data) {
|
||||
const isInstanceLink = (item) => {
|
||||
if (item.instance != undefined && item.instance.link) {
|
||||
return true
|
||||
} else if (item != undefined && item.linked_data) {
|
||||
} else if (item != undefined && item.link) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -16,7 +16,7 @@ import { ChatIcon } from '@/assets/icons'
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
|
||||
import { install } from '@/helpers/profile.js'
|
||||
import { install_existing_instance } from '@/helpers/install'
|
||||
import { cancel_directory_change } from '@/helpers/settings.ts'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
|
||||
@@ -72,7 +72,7 @@ defineExpose({
|
||||
title.value = 'No loader selected'
|
||||
errorType.value = 'no_loader_version'
|
||||
supportLink.value = 'https://support.modrinth.com'
|
||||
metadata.value.profilePath = context.profilePath
|
||||
metadata.value.instanceId = context.instanceId
|
||||
} else if (source === 'state_init') {
|
||||
title.value = 'Error initializing Modrinth App'
|
||||
errorType.value = 'state_init'
|
||||
@@ -125,7 +125,7 @@ const loadingRepair = ref(false)
|
||||
async function repairInstance() {
|
||||
loadingRepair.value = true
|
||||
try {
|
||||
await install(metadata.value.profilePath, false)
|
||||
await install_existing_instance(metadata.value.instanceId, false)
|
||||
errorModal.value.hide()
|
||||
} catch (err) {
|
||||
handleSevereError(err)
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
<script setup>
|
||||
import { WrenchIcon, XIcon } from '@modrinth/assets'
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Accordion,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
FileTreeSelect,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { save } from '@tauri-apps/plugin-dialog'
|
||||
import { readDir, stat } from '@tauri-apps/plugin-fs'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { PackageIcon, VersionIcon } from '@/assets/icons'
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { export_profile_mrpack, get_pack_export_candidates } from '@/helpers/profile.js'
|
||||
import { PackageIcon } from '@/assets/icons'
|
||||
import {
|
||||
export_instance_mrpack,
|
||||
get_full_path,
|
||||
get_pack_export_candidates,
|
||||
} from '@/helpers/instance'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
header: { id: 'app.export-modal.header', defaultMessage: 'Export modpack' },
|
||||
modpackNameLabel: { id: 'app.export-modal.modpack-name-label', defaultMessage: 'Modpack Name' },
|
||||
modpackNameLabel: { id: 'app.export-modal.modpack-name-label', defaultMessage: 'Modpack name' },
|
||||
modpackNamePlaceholder: {
|
||||
id: 'app.export-modal.modpack-name-placeholder',
|
||||
defaultMessage: 'Modpack name',
|
||||
@@ -39,15 +43,7 @@ const messages = defineMessages({
|
||||
id: 'app.export-modal.description-placeholder',
|
||||
defaultMessage: 'Enter modpack description...',
|
||||
},
|
||||
selectFilesLabel: {
|
||||
id: 'app.export-modal.select-files-label',
|
||||
defaultMessage: 'Configure which files are included in this export',
|
||||
},
|
||||
exportButton: { id: 'app.export-modal.export-button', defaultMessage: 'Export' },
|
||||
includeFile: {
|
||||
id: 'app.export-modal.include-file-accessibility-label',
|
||||
defaultMessage: 'Include "{file}"?',
|
||||
},
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
@@ -59,8 +55,9 @@ const props = defineProps({
|
||||
|
||||
defineExpose({
|
||||
show: () => {
|
||||
resetExportState()
|
||||
exportModal.value.show()
|
||||
initFiles()
|
||||
void initFiles().catch(handleError)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -69,62 +66,33 @@ const nameInput = ref(props.instance.name)
|
||||
const exportDescription = ref('')
|
||||
const versionInput = ref('1.0.0')
|
||||
const files = ref([])
|
||||
const folders = ref([])
|
||||
const selectedFilePaths = ref([])
|
||||
const fileTreeKey = ref(0)
|
||||
const filesLoadId = ref(0)
|
||||
const instanceRoot = ref('')
|
||||
const loadedDirectories = ref(new Set())
|
||||
|
||||
const initFiles = async () => {
|
||||
const newFolders = new Map()
|
||||
const sep = '/'
|
||||
files.value = []
|
||||
await get_pack_export_candidates(props.instance.path).then((filePaths) =>
|
||||
filePaths
|
||||
.map((folder) => ({
|
||||
path: folder,
|
||||
name: folder.split(sep).pop(),
|
||||
selected:
|
||||
folder.startsWith('mods') ||
|
||||
folder.startsWith('datapacks') ||
|
||||
folder.startsWith('resourcepacks') ||
|
||||
folder.startsWith('shaderpacks') ||
|
||||
folder.startsWith('config'),
|
||||
disabled:
|
||||
folder === 'profile.json' ||
|
||||
folder.startsWith('modrinth_logs') ||
|
||||
folder.startsWith('.fabric') ||
|
||||
folder.startsWith('__MACOSX'),
|
||||
}))
|
||||
.forEach((pathData) => {
|
||||
const parent = pathData.path.split(sep).slice(0, -1).join(sep)
|
||||
if (parent !== '') {
|
||||
if (newFolders.has(parent)) {
|
||||
newFolders.get(parent).push(pathData)
|
||||
} else {
|
||||
newFolders.set(parent, [pathData])
|
||||
}
|
||||
} else {
|
||||
files.value.push(pathData)
|
||||
}
|
||||
}),
|
||||
)
|
||||
folders.value = [...newFolders.entries()].map(([name, value]) => [
|
||||
{
|
||||
name,
|
||||
showingMore: false,
|
||||
},
|
||||
value,
|
||||
async function initFiles() {
|
||||
const loadId = ++filesLoadId.value
|
||||
const [filePaths, root] = await Promise.all([
|
||||
get_pack_export_candidates(props.instance.id),
|
||||
get_full_path(props.instance.id),
|
||||
])
|
||||
if (loadId !== filesLoadId.value) return
|
||||
|
||||
instanceRoot.value = root
|
||||
const exportCandidates = await Promise.all(
|
||||
filePaths.map((path) => buildExportCandidateItem(root, path)),
|
||||
)
|
||||
if (loadId !== filesLoadId.value) return
|
||||
|
||||
files.value = exportCandidates
|
||||
selectedFilePaths.value = files.value
|
||||
.filter((file) => !file.disabled && isDefaultSelectedExportCandidate(file.path))
|
||||
.map((file) => file.path)
|
||||
}
|
||||
|
||||
await initFiles()
|
||||
|
||||
const exportPack = async () => {
|
||||
const filesToExport = files.value.filter((file) => file.selected).map((file) => file.path)
|
||||
folders.value.forEach((args) => {
|
||||
args[1].forEach((child) => {
|
||||
if (child.selected) {
|
||||
filesToExport.push(child.path)
|
||||
}
|
||||
})
|
||||
})
|
||||
const outputPath = await save({
|
||||
defaultPath: `${nameInput.value} ${versionInput.value}.mrpack`,
|
||||
filters: [
|
||||
@@ -136,10 +104,10 @@ const exportPack = async () => {
|
||||
})
|
||||
|
||||
if (outputPath) {
|
||||
export_profile_mrpack(
|
||||
props.instance.path,
|
||||
export_instance_mrpack(
|
||||
props.instance.id,
|
||||
outputPath,
|
||||
filesToExport,
|
||||
selectedFilePaths.value,
|
||||
versionInput.value,
|
||||
exportDescription.value,
|
||||
nameInput.value,
|
||||
@@ -147,94 +115,176 @@ const exportPack = async () => {
|
||||
exportModal.value.hide()
|
||||
}
|
||||
}
|
||||
|
||||
function resetExportState() {
|
||||
nameInput.value = props.instance.name
|
||||
exportDescription.value = ''
|
||||
versionInput.value = '1.0.0'
|
||||
files.value = []
|
||||
selectedFilePaths.value = []
|
||||
fileTreeKey.value += 1
|
||||
instanceRoot.value = ''
|
||||
loadedDirectories.value = new Set()
|
||||
}
|
||||
|
||||
async function loadExportDirectory(path) {
|
||||
if (!path || !instanceRoot.value || loadedDirectories.value.has(path)) return
|
||||
|
||||
const loadId = filesLoadId.value
|
||||
loadedDirectories.value.add(path)
|
||||
|
||||
try {
|
||||
const entries = await readDir(`${instanceRoot.value}/${path}`)
|
||||
const childItems = await Promise.all(
|
||||
entries.map((entry) => buildExportDirectoryChildItem(instanceRoot.value, path, entry)),
|
||||
)
|
||||
if (loadId !== filesLoadId.value) return
|
||||
|
||||
appendExportItems(childItems)
|
||||
} catch {
|
||||
loadedDirectories.value.delete(path)
|
||||
}
|
||||
}
|
||||
|
||||
async function buildExportCandidateItem(instanceRoot, path) {
|
||||
try {
|
||||
const entries = await readDir(`${instanceRoot}/${path}`)
|
||||
const metadata = await getExportCandidateMetadata(instanceRoot, path)
|
||||
return {
|
||||
path,
|
||||
type: 'directory',
|
||||
disabled: isExportCandidateDisabled(path),
|
||||
modified: metadata.modified,
|
||||
count: entries.length,
|
||||
}
|
||||
} catch {
|
||||
return buildExportFileItem(instanceRoot, path)
|
||||
}
|
||||
}
|
||||
|
||||
async function buildExportDirectoryChildItem(instanceRoot, parentPath, entry) {
|
||||
const path = `${parentPath}/${entry.name}`
|
||||
if (entry.isDirectory) {
|
||||
const metadata = await getExportCandidateMetadata(instanceRoot, path)
|
||||
return {
|
||||
path,
|
||||
type: 'directory',
|
||||
disabled: isExportCandidateDisabled(path),
|
||||
modified: metadata.modified,
|
||||
}
|
||||
}
|
||||
|
||||
return buildExportFileItem(instanceRoot, path)
|
||||
}
|
||||
|
||||
async function buildExportFileItem(instanceRoot, path) {
|
||||
const metadata = await getExportCandidateMetadata(instanceRoot, path)
|
||||
return {
|
||||
path,
|
||||
type: 'file',
|
||||
disabled: isExportCandidateDisabled(path),
|
||||
size: metadata.size,
|
||||
modified: metadata.modified,
|
||||
}
|
||||
}
|
||||
|
||||
function appendExportItems(items) {
|
||||
const nextFiles = new Map(files.value.map((file) => [normalizeExportPath(file.path), file]))
|
||||
for (const item of items) {
|
||||
nextFiles.set(normalizeExportPath(item.path), item)
|
||||
}
|
||||
files.value = [...nextFiles.values()]
|
||||
}
|
||||
|
||||
async function getExportCandidateMetadata(instanceRoot, path) {
|
||||
try {
|
||||
const metadata = await stat(`${instanceRoot}/${path}`)
|
||||
return {
|
||||
size: metadata.size,
|
||||
modified: metadata.mtime ? Math.floor(metadata.mtime.getTime() / 1000) : undefined,
|
||||
}
|
||||
} catch {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeExportPath(path) {
|
||||
return path.replaceAll('\\', '/').split('/').filter(Boolean).join('/')
|
||||
}
|
||||
|
||||
function isDefaultSelectedExportCandidate(path) {
|
||||
return (
|
||||
path.startsWith('mods') ||
|
||||
path.startsWith('datapacks') ||
|
||||
path.startsWith('resourcepacks') ||
|
||||
path.startsWith('shaderpacks') ||
|
||||
path.startsWith('config')
|
||||
)
|
||||
}
|
||||
|
||||
function isExportCandidateDisabled(path) {
|
||||
return (
|
||||
path === 'profile.json' ||
|
||||
path.startsWith('modrinth_logs') ||
|
||||
path.startsWith('.fabric') ||
|
||||
path.startsWith('__MACOSX')
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="exportModal" :header="formatMessage(messages.header)">
|
||||
<div class="flex flex-col gap-4 w-[40rem]">
|
||||
<NewModal
|
||||
ref="exportModal"
|
||||
:header="formatMessage(messages.header)"
|
||||
scrollable
|
||||
width="46rem"
|
||||
max-width="calc(100vw - 2rem)"
|
||||
>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="labeled_input">
|
||||
<p>{{ formatMessage(messages.modpackNameLabel) }}</p>
|
||||
<div class="labeled_input w-full">
|
||||
<p class="text-contrast font-semibold">{{ formatMessage(messages.modpackNameLabel) }}</p>
|
||||
<StyledInput
|
||||
v-model="nameInput"
|
||||
:icon="PackageIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.modpackNamePlaceholder)"
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="labeled_input">
|
||||
<p>{{ formatMessage(messages.versionNumberLabel) }}</p>
|
||||
<div class="labeled_input w-full">
|
||||
<p class="text-contrast font-semibold">
|
||||
{{ formatMessage(messages.versionNumberLabel) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
v-model="versionInput"
|
||||
:icon="VersionIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.versionNumberPlaceholder)"
|
||||
clearable
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<p class="m-0">{{ formatMessage(commonMessages.descriptionLabel) }}</p>
|
||||
<div class="flex flex-col gap-2 min-w-0">
|
||||
<p class="m-0 text-contrast font-semibold">
|
||||
{{ formatMessage(commonMessages.descriptionLabel) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
v-model="exportDescription"
|
||||
multiline
|
||||
:placeholder="formatMessage(messages.descriptionPlaceholder)"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<Accordion
|
||||
class="w-full bg-surface-4 border border-solid border-surface-5 rounded-2xl overflow-clip"
|
||||
button-class="p-4 w-full border-b border-solid border-b-surface-5 bg-surface-2 -mb-px hover:brightness-[--hover-brightness] group"
|
||||
>
|
||||
<template #title>
|
||||
<span class="flex items-center gap-3 text-contrast group-active:scale-[0.98]">
|
||||
<WrenchIcon aria-hidden="true" class="size-5 text-secondary" />
|
||||
Configure which files are included in this export
|
||||
</span>
|
||||
</template>
|
||||
<div class="flex flex-col [&>*:nth-child(even)]:bg-surface-3">
|
||||
<div v-for="[path, children] in folders" :key="path.name" class="flex flex-col">
|
||||
<Accordion
|
||||
class="flex flex-col"
|
||||
button-class="flex gap-3 pr-4 hover:bg-surface-5 group"
|
||||
>
|
||||
<template #title>
|
||||
<Checkbox
|
||||
:model-value="children.every((child) => child.selected)"
|
||||
:indeterminate="
|
||||
!children.every((child) => child.selected) &&
|
||||
children.some((child) => child.selected)
|
||||
"
|
||||
:description="formatMessage(messages.includeFile, { file: path.name })"
|
||||
class="pl-4 py-2"
|
||||
:disabled="children.every((x) => x.disabled)"
|
||||
@update:model-value="
|
||||
(newValue) => children.forEach((child) => (child.selected = newValue))
|
||||
"
|
||||
@click.stop
|
||||
/>
|
||||
<span class="ml-2 group-active:scale-95">{{ path.name }}/</span>
|
||||
</template>
|
||||
<div v-for="child in children" :key="child.path">
|
||||
<Checkbox
|
||||
v-model="child.selected"
|
||||
:label="child.name"
|
||||
class="w-full px-8 py-2 hover:bg-surface-4 text-primary"
|
||||
:disabled="child.disabled"
|
||||
/>
|
||||
</div>
|
||||
</Accordion>
|
||||
</div>
|
||||
<Checkbox
|
||||
v-for="file in files"
|
||||
:key="file.path"
|
||||
v-model="file.selected"
|
||||
:label="file.name"
|
||||
:disabled="file.disabled"
|
||||
class="w-full px-4 py-2 hover:bg-surface-4 text-primary"
|
||||
/>
|
||||
</div>
|
||||
</Accordion>
|
||||
<FileTreeSelect
|
||||
:key="fileTreeKey"
|
||||
v-model="selectedFilePaths"
|
||||
class="min-w-0"
|
||||
:items="files"
|
||||
@navigate="loadExportDirectory"
|
||||
/>
|
||||
</div>
|
||||
<template #actions>
|
||||
<div class="flex items-center justify-end gap-2">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="exportModal.hide">
|
||||
@@ -249,6 +299,6 @@ const exportPack = async () => {
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
@@ -15,9 +15,10 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { get_by_profile_path } from '@/helpers/process'
|
||||
import { finish_install, kill, run } from '@/helpers/profile'
|
||||
import { showProfileInFolder } from '@/helpers/utils.js'
|
||||
import { install_existing_instance, install_pack_to_existing_instance } from '@/helpers/install'
|
||||
import { kill, run } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process'
|
||||
import { showInstanceInFolder } from '@/helpers/utils.js'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
@@ -54,11 +55,11 @@ const installed = computed(() => props.instance.install_stage === 'installed')
|
||||
const router = useRouter()
|
||||
|
||||
const seeInstance = async () => {
|
||||
await router.push(`/instance/${encodeURIComponent(props.instance.path)}`)
|
||||
await router.push(`/instance/${encodeURIComponent(props.instance.id)}`)
|
||||
}
|
||||
|
||||
const checkProcess = async () => {
|
||||
const runningProcesses = await get_by_profile_path(props.instance.path).catch(handleError)
|
||||
const runningProcesses = await get_by_instance_id(props.instance.id).catch(handleError)
|
||||
|
||||
playing.value = runningProcesses.length > 0
|
||||
}
|
||||
@@ -66,8 +67,8 @@ const checkProcess = async () => {
|
||||
const play = async (e, context) => {
|
||||
e?.stopPropagation()
|
||||
loading.value = true
|
||||
await run(props.instance.path)
|
||||
.catch((err) => handleSevereError(err, { profilePath: props.instance.path }))
|
||||
await run(props.instance.id)
|
||||
.catch((err) => handleSevereError(err, { instanceId: props.instance.id }))
|
||||
.finally(() => {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: props.instance.loader,
|
||||
@@ -82,7 +83,7 @@ const stop = async (e, context) => {
|
||||
e?.stopPropagation()
|
||||
playing.value = false
|
||||
|
||||
await kill(props.instance.path).catch(handleError)
|
||||
await kill(props.instance.id).catch(handleError)
|
||||
|
||||
trackEvent('InstanceStop', {
|
||||
loader: props.instance.loader,
|
||||
@@ -94,17 +95,30 @@ const stop = async (e, context) => {
|
||||
const repair = async (e) => {
|
||||
e?.stopPropagation()
|
||||
|
||||
await finish_install(props.instance).catch(handleError)
|
||||
if (
|
||||
props.instance.install_stage !== 'pack_installed' &&
|
||||
(props.instance.link?.type === 'modrinth_modpack' ||
|
||||
props.instance.link?.type === 'server_project_modpack')
|
||||
) {
|
||||
await install_pack_to_existing_instance(props.instance.id, {
|
||||
type: 'fromVersionId',
|
||||
project_id: props.instance.link.project_id ?? props.instance.link.server_project_id ?? '',
|
||||
version_id: props.instance.link.version_id ?? props.instance.link.content_version_id ?? '',
|
||||
title: props.instance.name,
|
||||
}).catch(handleError)
|
||||
} else {
|
||||
await install_existing_instance(props.instance.id, false).catch(handleError)
|
||||
}
|
||||
}
|
||||
|
||||
const openFolder = async () => {
|
||||
await showProfileInFolder(props.instance.path)
|
||||
await showInstanceInFolder(props.instance.id)
|
||||
}
|
||||
|
||||
const addContent = async () => {
|
||||
await router.push({
|
||||
path: `/browse/${props.instance.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
||||
query: { i: props.instance.path },
|
||||
query: { i: props.instance.id },
|
||||
})
|
||||
}
|
||||
|
||||
@@ -120,7 +134,7 @@ defineExpose({
|
||||
const currentEvent = ref(null)
|
||||
|
||||
const unlisten = await process_listener((e) => {
|
||||
if (e.profile_path_id === props.instance.path) {
|
||||
if (e.instance_id === props.instance.id) {
|
||||
currentEvent.value = e.event
|
||||
if (e.event === 'finished') {
|
||||
playing.value = false
|
||||
@@ -142,7 +156,7 @@ onUnmounted(() => unlisten())
|
||||
<Avatar
|
||||
size="48px"
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
:tint-by="instance.path"
|
||||
:tint-by="instance.id"
|
||||
alt="Mod card"
|
||||
/>
|
||||
<div class="h-full flex items-center font-bold text-contrast leading-normal">
|
||||
@@ -191,7 +205,7 @@ onUnmounted(() => unlisten())
|
||||
<Avatar
|
||||
size="48px"
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
:tint-by="instance.path"
|
||||
:tint-by="instance.id"
|
||||
alt="Mod card"
|
||||
:class="`transition-all ${modLoading || installing ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
|
||||
/>
|
||||
|
||||
@@ -22,7 +22,7 @@ const props = withDefaults(
|
||||
)
|
||||
|
||||
const instanceLink = computed(() => {
|
||||
const base = `/instance/${encodeURIComponent(props.instance.path)}`
|
||||
const base = `/instance/${encodeURIComponent(props.instance.id)}`
|
||||
return props.backTab ? `${base}/${props.backTab}` : base
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import { SwapIcon } from '@/assets/icons/index.js'
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { update_managed_modrinth_version } from '@/helpers/profile'
|
||||
import { update_managed_modrinth_version } from '@/helpers/instance'
|
||||
import { releaseColor } from '@/helpers/utils'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -32,14 +32,14 @@ const filteredVersions = computed(() => {
|
||||
})
|
||||
|
||||
const modpackVersionModal = ref(null)
|
||||
const installedVersion = computed(() => props.instance?.linked_data?.version_id)
|
||||
const installedVersion = computed(() => props.instance?.link?.version_id)
|
||||
const installing = computed(() => props.instance.install_stage !== 'installed')
|
||||
const inProgress = ref(false)
|
||||
|
||||
const switchVersion = async (versionId) => {
|
||||
modpackVersionModal.value.hide()
|
||||
inProgress.value = true
|
||||
await update_managed_modrinth_version(props.instance.path, versionId)
|
||||
await update_managed_modrinth_version(props.instance.id, versionId)
|
||||
inProgress.value = false
|
||||
emit('finish-install')
|
||||
}
|
||||
@@ -59,7 +59,7 @@ const onHide = () => {
|
||||
:on-hide="onHide"
|
||||
>
|
||||
<div class="modal-body">
|
||||
<div v-if="instance.linked_data" class="mod-card">
|
||||
<div v-if="instance.link" class="mod-card">
|
||||
<div class="table">
|
||||
<div class="table-row with-columns table-head">
|
||||
<div class="table-cell table-text download-cell" />
|
||||
|
||||
@@ -6,16 +6,16 @@ import dayjs from 'dayjs'
|
||||
import { onUnmounted, ref } from 'vue'
|
||||
|
||||
import NavButton from '@/components/ui/NavButton.vue'
|
||||
import { profile_listener } from '@/helpers/events.js'
|
||||
import { list } from '@/helpers/profile'
|
||||
import { instance_listener } from '@/helpers/events.js'
|
||||
import { list } from '@/helpers/instance'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const recentInstances = ref([])
|
||||
const getInstances = async () => {
|
||||
const profiles = await list().catch(handleError)
|
||||
const instances = await list().catch(handleError)
|
||||
|
||||
recentInstances.value = profiles
|
||||
recentInstances.value = instances
|
||||
.sort((a, b) => {
|
||||
const dateACreated = dayjs(a.created)
|
||||
const dateAPlayed = a.last_played ? dayjs(a.last_played) : dayjs(0)
|
||||
@@ -37,24 +37,24 @@ const getInstances = async () => {
|
||||
|
||||
await getInstances()
|
||||
|
||||
const unlistenProfile = await profile_listener(async (event) => {
|
||||
const unlistenInstance = await instance_listener(async (event) => {
|
||||
if (event.event !== 'synced') {
|
||||
await getInstances()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unlistenProfile()
|
||||
unlistenInstance()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-for="instance in recentInstances" :key="instance.id" v-tooltip.right="instance.name">
|
||||
<NavButton :to="`/instance/${encodeURIComponent(instance.path)}`" class="relative">
|
||||
<NavButton :to="`/instance/${encodeURIComponent(instance.id)}`" class="relative">
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
size="28px"
|
||||
:tint-by="instance.path"
|
||||
:tint-by="instance.id"
|
||||
:class="`transition-all ${instance.install_stage !== 'installed' ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
|
||||
/>
|
||||
<div
|
||||
@@ -65,10 +65,7 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</NavButton>
|
||||
</div>
|
||||
<div
|
||||
v-if="instances && recentInstances.length > 0"
|
||||
class="h-px w-6 mx-auto my-2 bg-divider"
|
||||
></div>
|
||||
<div v-if="recentInstances.length > 0" class="h-px w-6 mx-auto my-2 bg-divider"></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<ButtonStyled color="brand" type="outlined" hover-color-fill="background">
|
||||
<button
|
||||
v-if="showUpdatePill"
|
||||
type="button"
|
||||
class="!h-[34px] text-sm !transition-[opacity,transform,background-color,color,filter] !duration-200 ease-out"
|
||||
:class="{
|
||||
'opacity-0 scale-[0.96]': finishedDownloading && !animateReadyPill,
|
||||
'opacity-100 scale-100': finishedDownloading && animateReadyPill,
|
||||
}"
|
||||
:disabled="isUpdateDownloading"
|
||||
:aria-busy="isUpdateDownloading"
|
||||
@click="handleUpdateClick"
|
||||
>
|
||||
<RefreshCwIcon v-if="finishedDownloading" :class="{ 'animate-spin': restarting }" />
|
||||
<DownloadIcon v-else />
|
||||
<span v-if="isUpdateDownloading">
|
||||
{{ formatMessage(messages.downloadingUpdate) }}
|
||||
<span class="inline-block w-[3ch] text-right tabular-nums">{{ downloadPercent }}%</span>
|
||||
</span>
|
||||
<span v-else>{{ updateLabel }}</span>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, RefreshCwIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
|
||||
|
||||
import {
|
||||
appUpdateState,
|
||||
downloadAvailableAppUpdate,
|
||||
installAvailableAppUpdate,
|
||||
} from '@/providers/app-update'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
update: {
|
||||
id: 'app.action-bar.update',
|
||||
defaultMessage: 'Update',
|
||||
},
|
||||
downloadingUpdate: {
|
||||
id: 'app.action-bar.downloading-update',
|
||||
defaultMessage: 'Downloading update',
|
||||
},
|
||||
reloadToUpdate: {
|
||||
id: 'app.action-bar.reload-to-update',
|
||||
defaultMessage: 'Reload to update',
|
||||
},
|
||||
})
|
||||
|
||||
const {
|
||||
downloading,
|
||||
downloadPercent,
|
||||
downloadProgress,
|
||||
finishedDownloading,
|
||||
isVisible: isUpdateVisible,
|
||||
metered,
|
||||
restarting,
|
||||
} = appUpdateState
|
||||
|
||||
const isUpdateDownloading = computed(
|
||||
() =>
|
||||
downloading.value ||
|
||||
(downloadProgress.value > 0 && downloadProgress.value < 1 && !finishedDownloading.value),
|
||||
)
|
||||
const showUpdatePill = computed(
|
||||
() => isUpdateVisible.value && (finishedDownloading.value || metered.value),
|
||||
)
|
||||
const animateReadyPill = ref(false)
|
||||
const updateLabel = computed(() => {
|
||||
if (isUpdateDownloading.value) {
|
||||
return formatMessage(messages.downloadingUpdate)
|
||||
}
|
||||
|
||||
if (finishedDownloading.value) {
|
||||
return formatMessage(messages.reloadToUpdate)
|
||||
}
|
||||
|
||||
return formatMessage(messages.update)
|
||||
})
|
||||
let readyPillAnimationFrame: number | null = null
|
||||
watch([showUpdatePill, finishedDownloading], async ([show, ready], [wasShown, wasReady]) => {
|
||||
if (readyPillAnimationFrame !== null) {
|
||||
cancelAnimationFrame(readyPillAnimationFrame)
|
||||
readyPillAnimationFrame = null
|
||||
}
|
||||
|
||||
if (!show || !ready) {
|
||||
animateReadyPill.value = false
|
||||
return
|
||||
}
|
||||
|
||||
if (wasShown && wasReady) {
|
||||
return
|
||||
}
|
||||
|
||||
animateReadyPill.value = false
|
||||
await nextTick()
|
||||
readyPillAnimationFrame = requestAnimationFrame(() => {
|
||||
animateReadyPill.value = true
|
||||
readyPillAnimationFrame = null
|
||||
})
|
||||
})
|
||||
async function handleUpdateClick() {
|
||||
if (isUpdateDownloading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (finishedDownloading.value) {
|
||||
await installAvailableAppUpdate()
|
||||
} else {
|
||||
await downloadAvailableAppUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (readyPillAnimationFrame !== null) {
|
||||
cancelAnimationFrame(readyPillAnimationFrame)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { MailIcon, SendIcon, UserIcon, UserPlusIcon, XIcon } from '@modrinth/assets'
|
||||
import { MailIcon, SearchIcon, SendIcon, UserIcon, UserPlusIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
@@ -301,11 +301,12 @@ const messages = defineMessages({
|
||||
</ButtonStyled>
|
||||
<StyledInput
|
||||
v-model="search"
|
||||
:icon="SearchIcon"
|
||||
type="text"
|
||||
:placeholder="formatMessage(messages.searchFriends)"
|
||||
clearable
|
||||
variant="outlined"
|
||||
wrapper-class="flex-1"
|
||||
input-class="!bg-transparent !border !border-solid !border-button-bg !text-primary !placeholder:text-primary"
|
||||
wrapper-class="flex-1 [&>svg]:!text-primary [&>svg]:!opacity-100"
|
||||
@keyup.esc="search = ''"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -7,26 +7,28 @@ import {
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { useQueryClient } from '@tanstack/vue-query'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { list } from '@/helpers/profile'
|
||||
import { add_server_to_profile, get_profile_worlds } from '@/helpers/worlds.ts'
|
||||
import { list } from '@/helpers/instance'
|
||||
import { add_server_to_instance, get_instance_worlds } from '@/helpers/worlds.ts'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const modal = ref()
|
||||
const searchFilter = ref('')
|
||||
const profiles = ref([])
|
||||
const instances = ref([])
|
||||
|
||||
const serverName = ref('')
|
||||
const serverAddress = ref('')
|
||||
|
||||
const shownProfiles = computed(() =>
|
||||
profiles.value.filter((profile) => {
|
||||
return profile.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||
const shownInstances = computed(() =>
|
||||
instances.value.filter((instance) => {
|
||||
return instance.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -36,15 +38,15 @@ defineExpose({
|
||||
serverAddress.value = address
|
||||
searchFilter.value = ''
|
||||
|
||||
const profilesVal = await list().catch(handleError)
|
||||
const instanceValues = await list().catch(handleError)
|
||||
await Promise.allSettled(
|
||||
profilesVal.map(async (profile) => {
|
||||
profile.adding = false
|
||||
profile.added = false
|
||||
instanceValues.map(async (instance) => {
|
||||
instance.adding = false
|
||||
instance.added = false
|
||||
|
||||
try {
|
||||
const worlds = await get_profile_worlds(profile.path)
|
||||
profile.added = worlds.some(
|
||||
const worlds = await get_instance_worlds(instance.id)
|
||||
instance.added = worlds.some(
|
||||
(w) => w.type === 'server' && w.address === serverAddress.value,
|
||||
)
|
||||
} catch {
|
||||
@@ -53,28 +55,29 @@ defineExpose({
|
||||
}),
|
||||
)
|
||||
|
||||
profiles.value = profilesVal
|
||||
instances.value = instanceValues
|
||||
modal.value.show()
|
||||
|
||||
trackEvent('AddServerToInstanceStart', { source: 'AddServerToInstanceModal' })
|
||||
},
|
||||
})
|
||||
|
||||
async function addServer(profile) {
|
||||
profile.adding = true
|
||||
async function addServer(instance) {
|
||||
instance.adding = true
|
||||
try {
|
||||
await add_server_to_profile(profile.path, serverName.value, serverAddress.value, 'prompt')
|
||||
profile.added = true
|
||||
await add_server_to_instance(instance.id, serverName.value, serverAddress.value, 'prompt')
|
||||
instance.added = true
|
||||
await queryClient.invalidateQueries({ queryKey: ['worlds', instance.id] })
|
||||
|
||||
trackEvent('AddServerToInstance', {
|
||||
server_name: serverName.value,
|
||||
instance_name: profile.name,
|
||||
instance_name: instance.name,
|
||||
source: 'AddServerToInstanceModal',
|
||||
})
|
||||
} catch (err) {
|
||||
handleError(err)
|
||||
}
|
||||
profile.adding = false
|
||||
instance.adding = false
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -91,26 +94,26 @@ async function addServer(profile) {
|
||||
/>
|
||||
<div class="max-h-[21rem] overflow-y-auto">
|
||||
<div
|
||||
v-for="profile in shownProfiles"
|
||||
:key="profile.path"
|
||||
v-for="instance in shownInstances"
|
||||
:key="instance.id"
|
||||
class="flex w-full items-center justify-between gap-2 bg-bg-raised text-icon shadow-none"
|
||||
>
|
||||
<router-link
|
||||
class="btn btn-transparent p-2 text-left"
|
||||
:to="`/instance/${encodeURIComponent(profile.path)}`"
|
||||
:to="`/instance/${encodeURIComponent(instance.id)}`"
|
||||
@click="modal.hide()"
|
||||
>
|
||||
<Avatar
|
||||
:src="profile.icon_path ? convertFileSrc(profile.icon_path) : null"
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
class="mr-2 [--size:2rem]"
|
||||
/>
|
||||
{{ profile.name }}
|
||||
{{ instance.name }}
|
||||
</router-link>
|
||||
<ButtonStyled>
|
||||
<button :disabled="profile.added || profile.adding" @click="addServer(profile)">
|
||||
<PlusIcon v-if="!profile.added && !profile.adding" />
|
||||
<CheckIcon v-else-if="profile.added" />
|
||||
{{ profile.adding ? 'Adding...' : profile.added ? 'Added' : 'Add' }}
|
||||
<button :disabled="instance.added || instance.adding" @click="addServer(instance)">
|
||||
<PlusIcon v-if="!instance.added && !instance.adding" />
|
||||
<CheckIcon v-else-if="instance.added" />
|
||||
{{ instance.adding ? 'Adding...' : instance.added ? 'Added' : 'Add' }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
@@ -1,108 +1,41 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.header)" :on-hide="reset">
|
||||
<div class="max-w-[31rem] flex flex-col gap-6">
|
||||
<Admonition
|
||||
type="warning"
|
||||
:header="formatMessage(messages.warningTitle)"
|
||||
:body="formatMessage(messages.warningBody)"
|
||||
/>
|
||||
<div v-if="fileName" class="overflow-x-auto whitespace-nowrap text-sm text-secondary">
|
||||
{{ fileName }}
|
||||
</div>
|
||||
<div>
|
||||
<p class="mt-0 leading-tight">
|
||||
{{ formatMessage(messages.body) }}
|
||||
</p>
|
||||
<p class="text-orange font-semibold mb-0 leading-tight">
|
||||
{{ formatMessage(messages.malwareStatement) }}
|
||||
</p>
|
||||
</div>
|
||||
<Checkbox v-model="dontShowAgain" :label="formatMessage(messages.dontShowAgain)" />
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="cancel">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="orange">
|
||||
<button :disabled="isProceeding" @click="proceed">
|
||||
<SpinnerIcon v-if="isProceeding" class="animate-spin" />
|
||||
<CircleArrowRightIcon v-else />
|
||||
{{ formatMessage(messages.installAnyway) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
<UnknownFileWarningModal
|
||||
ref="modal"
|
||||
:mode="externalFilesInModpack.length > 0 ? 'modpack' : 'mod'"
|
||||
:file-name="fileName"
|
||||
:external-files-in-modpack="externalFilesInModpack"
|
||||
@cancel="reset"
|
||||
@continue="proceed"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CircleArrowRightIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { UnknownFileWarningModal } from '@modrinth/ui'
|
||||
import { ref, useTemplateRef } from 'vue'
|
||||
|
||||
import { get as getSettings, set as setSettings } from '@/helpers/settings'
|
||||
import { useTheming } from '@/store/state'
|
||||
import type { FeatureFlag } from '@/store/theme.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const themeStore = useTheming()
|
||||
const skipUnknownPackWarningFeatureFlag = 'skip_unknown_pack_warning' as FeatureFlag
|
||||
|
||||
const dontShowAgain = ref(false)
|
||||
const modal = useTemplateRef('modal')
|
||||
const onProceed = ref<() => Promise<void>>()
|
||||
const isProceeding = ref(false)
|
||||
const fileName = ref('')
|
||||
const externalFilesInModpack = ref<string[]>([])
|
||||
|
||||
const messages = defineMessages({
|
||||
header: {
|
||||
id: 'unknown-pack-warning-modal.header',
|
||||
defaultMessage: 'Confirm installation',
|
||||
},
|
||||
warningTitle: {
|
||||
id: 'unknown-pack-warning-modal.warning.title',
|
||||
defaultMessage: 'Unknown file warning',
|
||||
},
|
||||
warningBody: {
|
||||
id: 'unknown-pack-warning-modal.warning.body',
|
||||
defaultMessage: `We couldn't find this file on Modrinth. We strongly recommend only installing files from sources you trust.`,
|
||||
},
|
||||
body: {
|
||||
id: 'unknown-pack-warning-modal.body',
|
||||
defaultMessage: `A file is only reviewed if it’s uploaded to Modrinth, regardless of its file format (including .mrpack).`,
|
||||
},
|
||||
malwareStatement: {
|
||||
id: 'unknown-pack-warning-modal.malware-statement',
|
||||
defaultMessage: `Malware is often distributed through modpack files by sharing them on platforms like Discord.`,
|
||||
},
|
||||
dontShowAgain: {
|
||||
id: 'unknown-pack-warning-modal.dont-show-again',
|
||||
defaultMessage: `Don't show this warning again`,
|
||||
},
|
||||
installAnyway: {
|
||||
id: 'unknown-pack-warning-modal.install-anyway',
|
||||
defaultMessage: `Install anyway`,
|
||||
},
|
||||
})
|
||||
|
||||
function show(createInstance: () => Promise<void>, selectedFileName = '') {
|
||||
function show(
|
||||
createInstance: () => Promise<void>,
|
||||
selectedFileName = '',
|
||||
selectedExternalFiles: string[] = [],
|
||||
) {
|
||||
onProceed.value = createInstance
|
||||
fileName.value = selectedFileName
|
||||
dontShowAgain.value = false
|
||||
externalFilesInModpack.value = selectedExternalFiles
|
||||
|
||||
if (themeStore.getFeatureFlag(skipUnknownPackWarningFeatureFlag)) {
|
||||
// noinspection ES6MissingAwait
|
||||
createInstance()
|
||||
void createInstance()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -112,18 +45,11 @@ function show(createInstance: () => Promise<void>, selectedFileName = '') {
|
||||
function reset() {
|
||||
onProceed.value = undefined
|
||||
fileName.value = ''
|
||||
externalFilesInModpack.value = []
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
async function proceed() {
|
||||
if (!onProceed.value) {
|
||||
return
|
||||
}
|
||||
|
||||
if (dontShowAgain.value) {
|
||||
async function proceed(dontShowAgain: boolean) {
|
||||
if (dontShowAgain) {
|
||||
themeStore.featureFlags[skipUnknownPackWarningFeatureFlag] = true
|
||||
const settings = await getSettings()
|
||||
settings.feature_flags[skipUnknownPackWarningFeatureFlag] = true
|
||||
@@ -131,9 +57,8 @@ async function proceed() {
|
||||
}
|
||||
|
||||
const createInstance = onProceed.value
|
||||
modal.value?.hide()
|
||||
// noinspection ES6MissingAwait
|
||||
createInstance()
|
||||
reset()
|
||||
if (createInstance) void createInstance()
|
||||
}
|
||||
|
||||
defineExpose({ show })
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
<template>
|
||||
<PageHeader :title="instance.name">
|
||||
<template #leading>
|
||||
<Avatar :src="iconSrc" :alt="instance.name" size="64px" :tint-by="instance.id" />
|
||||
</template>
|
||||
|
||||
<template #metadata>
|
||||
<InstanceHeaderServerMetadata
|
||||
v-if="isServerInstance"
|
||||
:loading-server-ping="loadingServerPing"
|
||||
:players-online="playersOnline"
|
||||
:status-online="statusOnline"
|
||||
:recent-plays="recentPlays"
|
||||
:ping="ping"
|
||||
:minecraft-server="minecraftServer"
|
||||
:linked-project-v3="linkedProjectV3"
|
||||
:instance-id="instance.id"
|
||||
/>
|
||||
<PageHeaderMetadata v-else>
|
||||
<PageHeaderMetadataItem :icon="Gamepad2Icon" tooltip="Minecraft version">
|
||||
Minecraft {{ instance.game_version }}
|
||||
</PageHeaderMetadataItem>
|
||||
<PageHeaderMetadataItem
|
||||
:icon="ServerLoaderIcon"
|
||||
:icon-props="{ loader: loaderDisplayName }"
|
||||
tooltip="Mod loader"
|
||||
>
|
||||
{{ loaderLabel }}
|
||||
</PageHeaderMetadataItem>
|
||||
<PageHeaderMetadataItem
|
||||
v-if="showInstancePlayTime"
|
||||
:icon="TimerIcon"
|
||||
tooltip="Total playtime"
|
||||
>
|
||||
{{ playtimeLabel }}
|
||||
</PageHeaderMetadataItem>
|
||||
</PageHeaderMetadata>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<PageHeaderActions>
|
||||
<ButtonStyled v-if="isInstalling" color="brand" size="large">
|
||||
<button type="button" disabled>
|
||||
{{ formatMessage(commonMessages.installingLabel) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else-if="instance.install_stage !== 'installed'" color="brand" size="large">
|
||||
<button type="button" @click="emit('repair')">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(messages.repair) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else-if="playing" color="red" size="large">
|
||||
<button type="button" :disabled="stopping" @click="emit('stop')">
|
||||
<StopCircleIcon />
|
||||
{{
|
||||
stopping ? formatMessage(messages.stopping) : formatMessage(commonMessages.stopButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<JoinedButtons
|
||||
v-else-if="!loading && isServerInstance"
|
||||
:actions="serverPlayActions"
|
||||
color="brand"
|
||||
size="large"
|
||||
/>
|
||||
<ButtonStyled v-else-if="!loading" color="brand" size="large">
|
||||
<button type="button" @click="emit('play')">
|
||||
<PlayIcon />
|
||||
{{ formatMessage(commonMessages.playButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-else color="brand" size="large">
|
||||
<button type="button" disabled>{{ formatMessage(messages.starting) }}</button>
|
||||
</ButtonStyled>
|
||||
|
||||
<ButtonStyled circular size="large">
|
||||
<button
|
||||
v-tooltip="formatMessage(messages.instanceSettings)"
|
||||
type="button"
|
||||
:aria-label="formatMessage(messages.instanceSettings)"
|
||||
@click="emit('settings')"
|
||||
>
|
||||
<SettingsIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled circular size="large" type="transparent">
|
||||
<TeleportOverflowMenu
|
||||
:options="moreActions"
|
||||
:tooltip="formatMessage(messages.moreActions)"
|
||||
:aria-label="formatMessage(messages.moreActions)"
|
||||
>
|
||||
<MoreVerticalIcon />
|
||||
</TeleportOverflowMenu>
|
||||
</ButtonStyled>
|
||||
</PageHeaderActions>
|
||||
</template>
|
||||
</PageHeader>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
DownloadIcon,
|
||||
ExternalIcon,
|
||||
FolderOpenIcon,
|
||||
MoreVerticalIcon,
|
||||
PackageIcon,
|
||||
PlayIcon,
|
||||
SettingsIcon,
|
||||
StopCircleIcon,
|
||||
TagCategoryGamepad2Icon as Gamepad2Icon,
|
||||
TimerIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatLoaderLabel,
|
||||
type JoinedButtonAction,
|
||||
JoinedButtons,
|
||||
LoaderIcon as ServerLoaderIcon,
|
||||
PageHeader,
|
||||
PageHeaderActions,
|
||||
PageHeaderMetadata,
|
||||
PageHeaderMetadataItem,
|
||||
type ServerLoader,
|
||||
TeleportOverflowMenu,
|
||||
type TeleportOverflowMenuItem,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
|
||||
import InstanceHeaderServerMetadata from './instance-page-header-server-metadata.vue'
|
||||
|
||||
const messages = defineMessages({
|
||||
createShortcut: {
|
||||
id: 'instance.action.create-shortcut',
|
||||
defaultMessage: 'Create shortcut',
|
||||
},
|
||||
exportModpack: {
|
||||
id: 'instance.action.export-modpack',
|
||||
defaultMessage: 'Export modpack',
|
||||
},
|
||||
instanceSettings: {
|
||||
id: 'instance.action.settings',
|
||||
defaultMessage: 'Instance settings',
|
||||
},
|
||||
launchInstance: {
|
||||
id: 'instance.action.launch-instance',
|
||||
defaultMessage: 'Launch instance',
|
||||
},
|
||||
moreActions: {
|
||||
id: 'instance.action.more-actions',
|
||||
defaultMessage: 'More actions',
|
||||
},
|
||||
neverPlayed: {
|
||||
id: 'instance.playtime.never-played',
|
||||
defaultMessage: 'Never played',
|
||||
},
|
||||
openFolder: {
|
||||
id: 'instance.action.open-folder',
|
||||
defaultMessage: 'Open folder',
|
||||
},
|
||||
repair: {
|
||||
id: 'instance.action.repair',
|
||||
defaultMessage: 'Repair',
|
||||
},
|
||||
starting: {
|
||||
id: 'instance.action.starting',
|
||||
defaultMessage: 'Starting...',
|
||||
},
|
||||
stopping: {
|
||||
id: 'instance.action.stopping',
|
||||
defaultMessage: 'Stopping...',
|
||||
},
|
||||
})
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
instance: GameInstance
|
||||
iconSrc?: string | null
|
||||
isServerInstance?: boolean
|
||||
showInstancePlayTime?: boolean
|
||||
timePlayed?: number
|
||||
playing?: boolean
|
||||
loading?: boolean
|
||||
stopping?: boolean
|
||||
loadingServerPing?: boolean
|
||||
playersOnline?: number
|
||||
statusOnline?: boolean
|
||||
recentPlays?: number
|
||||
ping?: number
|
||||
minecraftServer?: Labrinth.Projects.v3.Project['minecraft_server']
|
||||
linkedProjectV3?: Labrinth.Projects.v3.Project
|
||||
}>(),
|
||||
{
|
||||
iconSrc: null,
|
||||
isServerInstance: false,
|
||||
showInstancePlayTime: false,
|
||||
timePlayed: 0,
|
||||
playing: false,
|
||||
loading: false,
|
||||
stopping: false,
|
||||
loadingServerPing: false,
|
||||
playersOnline: undefined,
|
||||
statusOnline: false,
|
||||
recentPlays: undefined,
|
||||
ping: undefined,
|
||||
minecraftServer: undefined,
|
||||
linkedProjectV3: undefined,
|
||||
},
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
repair: []
|
||||
stop: []
|
||||
play: []
|
||||
playServer: []
|
||||
settings: []
|
||||
openFolder: []
|
||||
export: []
|
||||
createShortcut: []
|
||||
}>()
|
||||
|
||||
const installingStages = [
|
||||
'installing',
|
||||
'pack_installing',
|
||||
'pack_installed',
|
||||
'not_installed',
|
||||
'minecraft_installing',
|
||||
]
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const isInstalling = computed(() => installingStages.includes(props.instance.install_stage))
|
||||
const loaderDisplayName = computed(() => formatLoaderLabel(props.instance.loader) as ServerLoader)
|
||||
const loaderLabel = computed(() =>
|
||||
[loaderDisplayName.value, props.instance.loader_version].filter(Boolean).join(' '),
|
||||
)
|
||||
const playtimeLabel = computed(() => {
|
||||
if (props.timePlayed <= 0) return formatMessage(messages.neverPlayed)
|
||||
|
||||
const hours = Math.floor(props.timePlayed / 3600)
|
||||
if (hours >= 1) {
|
||||
return `${hours} hour${hours > 1 ? 's' : ''}`
|
||||
}
|
||||
|
||||
const minutes = Math.floor(props.timePlayed / 60)
|
||||
if (minutes >= 1) {
|
||||
return `${minutes} minute${minutes > 1 ? 's' : ''}`
|
||||
}
|
||||
|
||||
const seconds = Math.floor(props.timePlayed)
|
||||
return `${seconds} second${seconds > 1 ? 's' : ''}`
|
||||
})
|
||||
const serverPlayActions = computed<JoinedButtonAction[]>(() => [
|
||||
{
|
||||
id: 'join_server',
|
||||
label: formatMessage(commonMessages.playButton),
|
||||
icon: PlayIcon,
|
||||
action: () => emit('playServer'),
|
||||
},
|
||||
{
|
||||
id: 'launch_instance',
|
||||
label: formatMessage(messages.launchInstance),
|
||||
icon: PlayIcon,
|
||||
action: () => emit('play'),
|
||||
},
|
||||
])
|
||||
const moreActions = computed<TeleportOverflowMenuItem[]>(() => [
|
||||
{
|
||||
id: 'open-folder',
|
||||
label: formatMessage(messages.openFolder),
|
||||
icon: FolderOpenIcon,
|
||||
action: () => emit('openFolder'),
|
||||
},
|
||||
{
|
||||
id: 'export-mrpack',
|
||||
label: formatMessage(messages.exportModpack),
|
||||
icon: PackageIcon,
|
||||
action: () => emit('export'),
|
||||
},
|
||||
{
|
||||
id: 'create-shortcut',
|
||||
label: formatMessage(messages.createShortcut),
|
||||
icon: ExternalIcon,
|
||||
action: () => emit('createShortcut'),
|
||||
},
|
||||
])
|
||||
</script>
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div class="flex items-center flex-wrap gap-2">
|
||||
<template v-if="loadingServerPing">
|
||||
<ServerOnlinePlayers
|
||||
v-if="playersOnline !== undefined"
|
||||
:online="playersOnline"
|
||||
:status-online="statusOnline"
|
||||
hide-label
|
||||
/>
|
||||
<ServerRecentPlays :recent-plays="recentPlays ?? 0" hide-label />
|
||||
<div
|
||||
v-if="
|
||||
(playersOnline !== undefined || recentPlays !== undefined) &&
|
||||
(minecraftServer?.region || ping)
|
||||
"
|
||||
class="w-1.5 h-1.5 rounded-full bg-surface-5"
|
||||
></div>
|
||||
<ServerPing v-if="ping" :ping="ping" />
|
||||
</template>
|
||||
|
||||
<ServerRegion v-if="minecraftServer?.region" :region="minecraftServer?.region" />
|
||||
|
||||
<div v-if="minecraftServer?.region || ping" class="w-1.5 h-1.5 rounded-full bg-surface-5"></div>
|
||||
|
||||
<div v-if="linkedProjectV3" class="flex gap-1.5 items-center font-medium text-primary">
|
||||
Linked to
|
||||
<Avatar
|
||||
:src="linkedProjectV3.icon_url"
|
||||
:alt="linkedProjectV3.name"
|
||||
:tint-by="instanceId"
|
||||
size="24px"
|
||||
/>
|
||||
<router-link
|
||||
:to="`/project/${linkedProjectV3.slug ?? linkedProjectV3.id}`"
|
||||
class="hover:underline text-primary truncate"
|
||||
>
|
||||
{{ linkedProjectV3.name }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
Avatar,
|
||||
ServerOnlinePlayers,
|
||||
ServerPing,
|
||||
ServerRecentPlays,
|
||||
ServerRegion,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
defineProps<{
|
||||
loadingServerPing?: boolean
|
||||
playersOnline?: number
|
||||
statusOnline?: boolean
|
||||
recentPlays?: number
|
||||
ping?: number
|
||||
minecraftServer?: Labrinth.Projects.v3.Project['minecraft_server']
|
||||
linkedProjectV3?: Labrinth.Projects.v3.Project
|
||||
instanceId?: string
|
||||
}>()
|
||||
</script>
|
||||
@@ -19,7 +19,8 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
import ConfirmDeleteInstanceModal from '@/components/ui/modal/ConfirmDeleteInstanceModal.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { duplicate, edit, edit_icon, list, remove } from '@/helpers/profile'
|
||||
import { install_duplicate_instance } from '@/helpers/install'
|
||||
import { edit, edit_icon, list, remove } from '@/helpers/instance'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { GameInstance } from '../../../helpers/types'
|
||||
@@ -32,14 +33,14 @@ const queryClient = useQueryClient()
|
||||
const deleteConfirmModal = ref()
|
||||
|
||||
const { instance } = injectInstanceSettings()
|
||||
type ReleaseChannel = GameInstance['preferred_update_channel']
|
||||
type ReleaseChannel = GameInstance['update_channel']
|
||||
const releaseChannelOptions: ReleaseChannel[] = ['release', 'beta', 'alpha']
|
||||
|
||||
const title = ref(instance.value.name)
|
||||
const icon: Ref<string | undefined> = ref(instance.value.icon_path)
|
||||
const groups = ref([...instance.value.groups])
|
||||
const savingReleaseChannel = ref(false)
|
||||
const selectedReleaseChannel = ref<ReleaseChannel>(instance.value.preferred_update_channel)
|
||||
const selectedReleaseChannel = ref<ReleaseChannel>(instance.value.update_channel)
|
||||
const releaseChannelDisabledItems = computed<ReleaseChannel[]>(() =>
|
||||
savingReleaseChannel.value ? [...releaseChannelOptions] : [],
|
||||
)
|
||||
@@ -48,8 +49,8 @@ const newCategoryInput = ref('')
|
||||
|
||||
const installing = computed(() => instance.value.install_stage !== 'installed')
|
||||
|
||||
async function duplicateProfile() {
|
||||
await duplicate(instance.value.path).catch(handleError)
|
||||
async function duplicateInstance() {
|
||||
await install_duplicate_instance(instance.value.id).catch(handleError)
|
||||
trackEvent('InstanceDuplicate', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
@@ -84,22 +85,22 @@ function formatReleaseChannelDescription(channel: ReleaseChannel) {
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [instance.value.path, instance.value.preferred_update_channel] as const,
|
||||
() => [instance.value.id, instance.value.update_channel] as const,
|
||||
() => {
|
||||
if (!savingReleaseChannel.value) {
|
||||
selectedReleaseChannel.value = instance.value.preferred_update_channel
|
||||
selectedReleaseChannel.value = instance.value.update_channel
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(selectedReleaseChannel, async (channel, previousChannel) => {
|
||||
const previousReleaseChannel = previousChannel ?? instance.value.preferred_update_channel
|
||||
if (channel === instance.value.preferred_update_channel) return
|
||||
const previousReleaseChannel = previousChannel ?? instance.value.update_channel
|
||||
if (channel === instance.value.update_channel) return
|
||||
|
||||
savingReleaseChannel.value = true
|
||||
const profilePath = instance.value.path
|
||||
await edit(profilePath, { preferred_update_channel: channel })
|
||||
.then(() => queryClient.invalidateQueries({ queryKey: ['linkedModpackInfo', profilePath] }))
|
||||
const instanceId = instance.value.id
|
||||
await edit(instanceId, { update_channel: channel })
|
||||
.then(() => queryClient.invalidateQueries({ queryKey: ['linkedModpackInfo', instanceId] }))
|
||||
.catch((error) => {
|
||||
selectedReleaseChannel.value = previousReleaseChannel
|
||||
handleError(error)
|
||||
@@ -109,7 +110,7 @@ watch(selectedReleaseChannel, async (channel, previousChannel) => {
|
||||
|
||||
async function resetIcon() {
|
||||
icon.value = undefined
|
||||
await edit_icon(instance.value.path, null).catch(handleError)
|
||||
await edit_icon(instance.value.id, null).catch(handleError)
|
||||
trackEvent('InstanceRemoveIcon')
|
||||
}
|
||||
|
||||
@@ -127,12 +128,12 @@ async function setIcon() {
|
||||
if (!value) return
|
||||
|
||||
icon.value = value
|
||||
await edit_icon(instance.value.path, icon.value).catch(handleError)
|
||||
await edit_icon(instance.value.id, icon.value).catch(handleError)
|
||||
|
||||
trackEvent('InstanceSetIcon')
|
||||
}
|
||||
|
||||
const editProfileObject = computed(() => ({
|
||||
const editInstanceObject = computed(() => ({
|
||||
name: title.value.trim().substring(0, 32) ?? 'Instance',
|
||||
groups: groups.value.map((x) => x.trim().substring(0, 32)).filter((x) => x.length > 0),
|
||||
}))
|
||||
@@ -158,15 +159,15 @@ watch(
|
||||
[title, groups, groups],
|
||||
async () => {
|
||||
if (removing.value) return
|
||||
await edit(instance.value.path, editProfileObject.value).catch(handleError)
|
||||
await edit(instance.value.id, editInstanceObject.value).catch(handleError)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
const removing = ref(false)
|
||||
async function removeProfile() {
|
||||
async function removeInstance() {
|
||||
removing.value = true
|
||||
const path = instance.value.path
|
||||
const path = instance.value.id
|
||||
|
||||
trackEvent('InstanceRemove', {
|
||||
loader: instance.value.loader,
|
||||
@@ -284,7 +285,7 @@ const messages = defineMessages({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmDeleteInstanceModal ref="deleteConfirmModal" @delete="removeProfile" />
|
||||
<ConfirmDeleteInstanceModal ref="deleteConfirmModal" @delete="removeInstance" />
|
||||
<div class="block">
|
||||
<div class="float-end ml-10 relative group w-fit">
|
||||
<div class="flex flex-col gap-1">
|
||||
@@ -310,7 +311,7 @@ const messages = defineMessages({
|
||||
:src="icon ? convertFileSrc(icon) : icon"
|
||||
size="108px"
|
||||
class="transition-[filter] group-hover:brightness-75"
|
||||
:tint-by="instance.path"
|
||||
:tint-by="instance.id"
|
||||
no-shadow
|
||||
/>
|
||||
<div
|
||||
@@ -350,7 +351,7 @@ const messages = defineMessages({
|
||||
aria-labelledby="duplicate-instance-label"
|
||||
:disabled="installing"
|
||||
class="w-max !shadow-none"
|
||||
@click="duplicateProfile"
|
||||
@click="duplicateInstance"
|
||||
>
|
||||
<CopyIcon /> {{ formatMessage(messages.duplicateButton) }}
|
||||
</button>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
import { edit } from '@/helpers/instance'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
@@ -28,21 +28,21 @@ const overrideHooks = ref(
|
||||
)
|
||||
const hooks = ref(instance.value.hooks ?? globalSettings.hooks)
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
const editProfile: {
|
||||
const editInstanceObject = computed(() => {
|
||||
const editInstancePatch: {
|
||||
hooks?: Hooks
|
||||
} = {}
|
||||
|
||||
// When hooks are not overridden per-instance, we want to clear them
|
||||
editProfile.hooks = overrideHooks.value ? hooks.value : {}
|
||||
editInstancePatch.hooks = overrideHooks.value ? hooks.value : {}
|
||||
|
||||
return editProfile
|
||||
return editInstancePatch
|
||||
})
|
||||
|
||||
watch(
|
||||
[overrideHooks, hooks],
|
||||
async () => {
|
||||
await edit(instance.value.path, editProfileObject.value)
|
||||
await edit(instance.value.id, editInstanceObject.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatLoaderLabel,
|
||||
injectFilePicker,
|
||||
injectNotificationManager,
|
||||
InstallationSettingsLayout,
|
||||
provideAppBackup,
|
||||
@@ -17,30 +18,41 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_project_versions, get_version } from '@/helpers/cache'
|
||||
import { get_loader_versions } from '@/helpers/metadata'
|
||||
import {
|
||||
duplicate,
|
||||
install_duplicate_instance,
|
||||
install_existing_instance,
|
||||
install_pack_to_existing_instance,
|
||||
installJobInstanceId,
|
||||
wait_for_install_job,
|
||||
} from '@/helpers/install'
|
||||
import {
|
||||
edit,
|
||||
get_linked_modpack_info,
|
||||
install,
|
||||
list,
|
||||
update_managed_modrinth_version,
|
||||
update_repair_modrinth,
|
||||
} from '@/helpers/profile'
|
||||
} from '@/helpers/instance'
|
||||
import { get_loader_versions } from '@/helpers/metadata'
|
||||
import { get_game_versions, get_loaders } from '@/helpers/tags'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
import { useTheming } from '@/store/state'
|
||||
|
||||
import type { Manifest } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const filePicker = injectFilePicker()
|
||||
const { formatMessage } = useVIntl()
|
||||
const queryClient = useQueryClient()
|
||||
const debug = useDebugLogger('AppInstallationSettings')
|
||||
const themeStore = useTheming()
|
||||
|
||||
const { instance, offline, isMinecraftServer, onUnlinked, closeModal } = injectInstanceSettings()
|
||||
const skipNonEssentialWarnings = computed(() =>
|
||||
themeStore.getFeatureFlag('skip_non_essential_warnings'),
|
||||
)
|
||||
|
||||
debug('metadata load: start', {
|
||||
instancePath: instance.value.path,
|
||||
instanceId: instance.value.id,
|
||||
loader: instance.value.loader,
|
||||
gameVersion: instance.value.game_version,
|
||||
installStage: instance.value.install_stage,
|
||||
@@ -91,15 +103,22 @@ const metadataLoading = computed(() =>
|
||||
)
|
||||
|
||||
debug('metadata queries configured', {
|
||||
instancePath: instance.value.path,
|
||||
instanceId: instance.value.id,
|
||||
loader: instance.value.loader,
|
||||
gameVersion: instance.value.game_version,
|
||||
})
|
||||
|
||||
const isModrinthLinkedModpack = computed(
|
||||
() =>
|
||||
instance.value.link?.type === 'modrinth_modpack' ||
|
||||
instance.value.link?.type === 'server_project_modpack',
|
||||
)
|
||||
const isImportedModpack = computed(() => instance.value.link?.type === 'imported_modpack')
|
||||
|
||||
const modpackInfoQuery = useQuery({
|
||||
queryKey: computed(() => ['linkedModpackInfo', instance.value.path]),
|
||||
queryFn: () => get_linked_modpack_info(instance.value.path, 'must_revalidate'),
|
||||
enabled: computed(() => !!instance.value.linked_data?.project_id && !offline),
|
||||
queryKey: computed(() => ['linkedModpackInfo', instance.value.id]),
|
||||
queryFn: () => get_linked_modpack_info(instance.value.id, 'must_revalidate'),
|
||||
enabled: computed(() => isModrinthLinkedModpack.value && !offline),
|
||||
})
|
||||
const modpackInfo = modpackInfoQuery.data
|
||||
|
||||
@@ -129,22 +148,39 @@ function getManifest(loader: string) {
|
||||
return manifest
|
||||
}
|
||||
|
||||
async function installLocalModpackFromPicker() {
|
||||
const picked = await filePicker.pickModpackFile({ readFile: false })
|
||||
if (!picked?.path) return false
|
||||
|
||||
const job = await install_pack_to_existing_instance(instance.value.id, {
|
||||
type: 'fromFile',
|
||||
path: picked.path,
|
||||
}).catch(handleError)
|
||||
if (!job) return false
|
||||
|
||||
const completed = await wait_for_install_job(job.job_id).catch(handleError)
|
||||
return !!completed
|
||||
}
|
||||
|
||||
provideAppBackup({
|
||||
async createBackup() {
|
||||
debug('createBackup: start', {
|
||||
instancePath: instance.value.path,
|
||||
instanceId: instance.value.id,
|
||||
instanceName: instance.value.name,
|
||||
})
|
||||
const allProfiles = await list()
|
||||
const allInstances = await list()
|
||||
const prefix = `${instance.value.name} - Backup #`
|
||||
const existingNums = allProfiles
|
||||
const existingNums = allInstances
|
||||
.filter((p) => p.name.startsWith(prefix))
|
||||
.map((p) => parseInt(p.name.slice(prefix.length), 10))
|
||||
.filter((n) => !isNaN(n))
|
||||
const nextNum = existingNums.length > 0 ? Math.max(...existingNums) + 1 : 1
|
||||
const newPath = await duplicate(instance.value.path)
|
||||
await edit(newPath, { name: `${prefix}${nextNum}` })
|
||||
debug('createBackup: done', { newPath, backupName: `${prefix}${nextNum}` })
|
||||
const job = await install_duplicate_instance(instance.value.id)
|
||||
const newInstanceId = installJobInstanceId(job)
|
||||
if (newInstanceId) {
|
||||
await edit(newInstanceId, { name: `${prefix}${nextNum}` })
|
||||
}
|
||||
debug('createBackup: done', { newInstanceId, backupName: `${prefix}${nextNum}` })
|
||||
},
|
||||
})
|
||||
|
||||
@@ -172,7 +208,7 @@ provideInstallationSettings({
|
||||
}
|
||||
return rows
|
||||
}),
|
||||
isLinked: computed(() => !!instance.value.linked_data?.locked),
|
||||
isLinked: computed(() => isModrinthLinkedModpack.value || isImportedModpack.value),
|
||||
isBusy: computed(
|
||||
() =>
|
||||
instance.value.install_stage !== 'installed' ||
|
||||
@@ -180,7 +216,16 @@ provideInstallationSettings({
|
||||
reinstalling.value ||
|
||||
!!offline,
|
||||
),
|
||||
skipNonEssentialWarnings,
|
||||
modpack: computed(() => {
|
||||
if (isImportedModpack.value && instance.value.link?.type === 'imported_modpack') {
|
||||
return {
|
||||
iconUrl: instance.value.icon_path,
|
||||
title: instance.value.link.name ?? instance.value.name,
|
||||
versionNumber: instance.value.link.version_number ?? undefined,
|
||||
filename: instance.value.link.filename ?? undefined,
|
||||
}
|
||||
}
|
||||
if (!modpackInfo.value) return null
|
||||
return {
|
||||
iconUrl: modpackInfo.value.project.icon_url,
|
||||
@@ -224,16 +269,31 @@ provideInstallationSettings({
|
||||
debug('resolveLoaderVersions: no manifest', { loader, gameVersion })
|
||||
return []
|
||||
}
|
||||
if (loader === 'fabric' || loader === 'quilt') {
|
||||
const result = manifest.gameVersions[0]?.loaders ?? []
|
||||
debug('resolveLoaderVersions: fabric/quilt result', {
|
||||
const entry = manifest.gameVersions?.find((item) => item.id === gameVersion)
|
||||
if (entry?.versionGroup) {
|
||||
const result =
|
||||
manifest.versionGroups?.find((group) => group.id === entry.versionGroup)?.loaders ?? []
|
||||
debug('resolveLoaderVersions: version group result', {
|
||||
loader,
|
||||
gameVersion,
|
||||
versionGroup: entry.versionGroup,
|
||||
count: result.length,
|
||||
})
|
||||
return result
|
||||
}
|
||||
const placeholder = manifest.gameVersions?.find((item) => item.id === '${modrinth.gameVersion}')
|
||||
if (placeholder) {
|
||||
const result = manifest.gameVersions?.some((item) => item.id === gameVersion)
|
||||
? placeholder.loaders
|
||||
: []
|
||||
debug('resolveLoaderVersions: placeholder result', {
|
||||
loader,
|
||||
gameVersion,
|
||||
count: result.length,
|
||||
})
|
||||
return result
|
||||
}
|
||||
const result = manifest.gameVersions?.find((item) => item.id === gameVersion)?.loaders ?? []
|
||||
const result = entry?.loaders ?? []
|
||||
debug('resolveLoaderVersions: result', { loader, gameVersion, count: result.length })
|
||||
return result
|
||||
},
|
||||
@@ -261,25 +321,25 @@ provideInstallationSettings({
|
||||
|
||||
async save(platform, gameVersion, loaderVersionId) {
|
||||
debug('save: called', {
|
||||
instancePath: instance.value.path,
|
||||
instanceId: instance.value.id,
|
||||
platform,
|
||||
gameVersion,
|
||||
loaderVersionId,
|
||||
})
|
||||
const editProfile: Record<string, string | undefined> = {
|
||||
const editInstancePatch: Record<string, string | undefined> = {
|
||||
loader: platform,
|
||||
game_version: gameVersion,
|
||||
}
|
||||
if (platform !== 'vanilla' && loaderVersionId) {
|
||||
editProfile.loader_version = loaderVersionId
|
||||
editInstancePatch.loader_version = loaderVersionId
|
||||
}
|
||||
await edit(instance.value.path, editProfile).catch(handleError)
|
||||
debug('save: edit complete', { editProfile })
|
||||
await edit(instance.value.id, editInstancePatch).catch(handleError)
|
||||
debug('save: edit complete', { editInstancePatch })
|
||||
},
|
||||
|
||||
afterSave: async () => {
|
||||
debug('afterSave: installing', { instancePath: instance.value.path })
|
||||
await install(instance.value.path, false).catch(handleError)
|
||||
debug('afterSave: installing', { instanceId: instance.value.id })
|
||||
await install_existing_instance(instance.value.id, false).catch(handleError)
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
@@ -288,9 +348,9 @@ provideInstallationSettings({
|
||||
},
|
||||
|
||||
async repair() {
|
||||
debug('repair: called', { instancePath: instance.value.path })
|
||||
debug('repair: called', { instanceId: instance.value.id })
|
||||
repairing.value = true
|
||||
await install(instance.value.path, true).catch(handleError)
|
||||
await install_existing_instance(instance.value.id, true).catch(handleError)
|
||||
repairing.value = false
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
@@ -300,24 +360,52 @@ provideInstallationSettings({
|
||||
},
|
||||
|
||||
async reinstallModpack() {
|
||||
debug('reinstallModpack: called', { instancePath: instance.value.path })
|
||||
debug('reinstallModpack: called', { instanceId: instance.value.id })
|
||||
reinstalling.value = true
|
||||
await update_repair_modrinth(instance.value.path).catch(handleError)
|
||||
reinstalling.value = false
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
let shouldTrack = false
|
||||
try {
|
||||
if (isImportedModpack.value) {
|
||||
shouldTrack = await installLocalModpackFromPicker()
|
||||
} else {
|
||||
await update_repair_modrinth(instance.value.id).catch(handleError)
|
||||
shouldTrack = true
|
||||
}
|
||||
} finally {
|
||||
reinstalling.value = false
|
||||
}
|
||||
if (shouldTrack) {
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
}
|
||||
debug('reinstallModpack: done')
|
||||
},
|
||||
|
||||
async swapModpack() {
|
||||
debug('swapModpack: called', { instanceId: instance.value.id })
|
||||
reinstalling.value = true
|
||||
try {
|
||||
const installed = await installLocalModpackFromPicker()
|
||||
if (installed) {
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
reinstalling.value = false
|
||||
}
|
||||
debug('swapModpack: done')
|
||||
},
|
||||
|
||||
async unlinkModpack() {
|
||||
debug('unlinkModpack: called', { instancePath: instance.value.path })
|
||||
await edit(instance.value.path, {
|
||||
linked_data: null as unknown as undefined,
|
||||
debug('unlinkModpack: called', { instanceId: instance.value.id })
|
||||
await edit(instance.value.id, {
|
||||
link: null as unknown as undefined,
|
||||
})
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['linkedModpackInfo', instance.value.path],
|
||||
queryKey: ['linkedModpackInfo', instance.value.id],
|
||||
})
|
||||
onUnlinked()
|
||||
debug('unlinkModpack: done')
|
||||
@@ -326,11 +414,9 @@ provideInstallationSettings({
|
||||
getCachedModpackVersions: () => null,
|
||||
async fetchModpackVersions() {
|
||||
debug('fetchModpackVersions: called', {
|
||||
projectId: instance.value.linked_data?.project_id,
|
||||
projectId: instance.value.link?.project_id,
|
||||
})
|
||||
const versions = await get_project_versions(instance.value.linked_data!.project_id!).catch(
|
||||
handleError,
|
||||
)
|
||||
const versions = await get_project_versions(instance.value.link!.project_id!).catch(handleError)
|
||||
debug('fetchModpackVersions: done', { count: versions?.length ?? 0 })
|
||||
return (versions ?? []) as Labrinth.Versions.v2.Version[]
|
||||
},
|
||||
@@ -345,19 +431,18 @@ provideInstallationSettings({
|
||||
async onModpackVersionConfirm(version) {
|
||||
debug('onModpackVersionConfirm: called', {
|
||||
versionId: version.id,
|
||||
instancePath: instance.value.path,
|
||||
instanceId: instance.value.id,
|
||||
})
|
||||
await update_managed_modrinth_version(instance.value.path, version.id)
|
||||
await update_managed_modrinth_version(instance.value.id, version.id)
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['linkedModpackInfo', instance.value.path],
|
||||
queryKey: ['linkedModpackInfo', instance.value.id],
|
||||
})
|
||||
debug('onModpackVersionConfirm: done')
|
||||
},
|
||||
|
||||
updaterModalProps: computed(() => ({
|
||||
isApp: true,
|
||||
currentVersionId:
|
||||
modpackInfo.value?.update_version_id ?? instance.value.linked_data?.version_id ?? '',
|
||||
currentVersionId: modpackInfo.value?.update_version_id ?? instance.value.link?.version_id ?? '',
|
||||
projectIconUrl: modpackInfo.value?.project?.icon_url,
|
||||
projectName: modpackInfo.value?.project?.title ?? 'Modpack',
|
||||
currentGameVersion: instance.value.game_version,
|
||||
@@ -366,7 +451,10 @@ provideInstallationSettings({
|
||||
|
||||
isServer: false,
|
||||
isApp: true,
|
||||
showModpackVersionActions: !isMinecraftServer.value,
|
||||
showModpackVersionActions: computed(
|
||||
() => isModrinthLinkedModpack.value && !isMinecraftServer.value,
|
||||
),
|
||||
isLocalFile: isImportedModpack,
|
||||
repairing,
|
||||
reinstalling,
|
||||
})
|
||||
|
||||
@@ -23,7 +23,7 @@ import { computed, readonly, ref, watch } from 'vue'
|
||||
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
|
||||
import useJavaTest from '@/composables/useJavaTest'
|
||||
import useMemorySlider from '@/composables/useMemorySlider'
|
||||
import { edit, get_optimal_jre_key } from '@/helpers/profile'
|
||||
import { edit, get_optimal_jre_key } from '@/helpers/instance'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
@@ -36,7 +36,7 @@ const { instance } = injectInstanceSettings()
|
||||
|
||||
const globalSettings = (await get().catch(handleError)) as unknown as AppSettings
|
||||
|
||||
const optimalJava = readonly(await get_optimal_jre_key(instance.value.path).catch(handleError))
|
||||
const optimalJava = readonly(await get_optimal_jre_key(instance.value.id).catch(handleError))
|
||||
|
||||
const overrideJavaInstall = ref(!!instance.value.java_path)
|
||||
const javaPath = ref(instance.value.java_path ?? optimalJava?.path ?? '')
|
||||
@@ -104,7 +104,7 @@ const { maxMemory, snapPoints } = (await useMemorySlider().catch(handleError)) a
|
||||
snapPoints: number[]
|
||||
}
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
const editInstanceObject = computed(() => {
|
||||
return {
|
||||
java_path:
|
||||
overrideJavaInstall.value && javaPath.value
|
||||
@@ -136,7 +136,7 @@ watch(
|
||||
memory,
|
||||
],
|
||||
async () => {
|
||||
await edit(instance.value.path, editProfileObject.value)
|
||||
await edit(instance.value.id, editInstanceObject.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from '@modrinth/ui'
|
||||
import { computed, type Ref, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
import { edit } from '@/helpers/instance'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
@@ -32,7 +32,7 @@ const fullscreenSetting: Ref<boolean> = ref(
|
||||
instance.value.force_fullscreen ?? globalSettings.force_fullscreen,
|
||||
)
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
const editInstanceObject = computed(() => {
|
||||
if (!overrideWindowSettings.value) {
|
||||
return {
|
||||
force_fullscreen: null,
|
||||
@@ -48,7 +48,7 @@ const editProfileObject = computed(() => {
|
||||
watch(
|
||||
[overrideWindowSettings, resolution, fullscreenSetting],
|
||||
async () => {
|
||||
await edit(instance.value.path, editProfileObject.value)
|
||||
await edit(instance.value.id, editInstanceObject.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.installToPlay)" :closable="true">
|
||||
<div v-if="requiredContentProject" class="flex flex-col gap-6 max-w-[500px]">
|
||||
<Admonition type="info" :header="formatMessage(messages.contentRequired)">
|
||||
{{ formatMessage(messages.serverRequiresMods) }}
|
||||
</Admonition>
|
||||
<NewModal
|
||||
ref="modal"
|
||||
:header="formatMessage(messages.installToPlay)"
|
||||
:closable="true"
|
||||
:on-hide="show_ads_window"
|
||||
max-width="640px"
|
||||
width="640px"
|
||||
>
|
||||
<div v-if="requiredContentProject" class="flex w-full flex-col gap-6">
|
||||
<p class="m-0 text-primary">
|
||||
{{ formatMessage(messages.inviteWarning) }}
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="font-semibold text-contrast">{{
|
||||
formatMessage(messages.requiredModpack)
|
||||
}}</span>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ formatMessage(messages.sharedInstance) }}
|
||||
</span>
|
||||
|
||||
<ButtonStyled type="transparent">
|
||||
<button @click="openViewContents">
|
||||
@@ -19,14 +26,16 @@
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 rounded-xl bg-surface-2 p-3">
|
||||
<div class="flex items-center gap-3 rounded-2xl bg-surface-2 p-3">
|
||||
<Avatar
|
||||
:src="requiredContentProject.icon_url"
|
||||
:alt="requiredContentProject.title"
|
||||
size="48px"
|
||||
size="56px"
|
||||
no-shadow
|
||||
class="!rounded-2xl"
|
||||
/>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="font-semibold text-contrast">
|
||||
<div class="flex min-w-0 flex-col gap-0.5">
|
||||
<span class="truncate font-semibold text-contrast">
|
||||
<template v-if="usingCustomModpack && modpackVersion">
|
||||
{{ modpackVersion.name }}
|
||||
</template>
|
||||
@@ -34,7 +43,7 @@
|
||||
{{ requiredContentProject.title }}
|
||||
</template>
|
||||
</span>
|
||||
<span class="text-sm text-secondary">
|
||||
<span class="truncate text-sm font-medium text-secondary">
|
||||
{{ loaderDisplay }} {{ requiredContentProject.game_versions?.[0] }}
|
||||
<template v-if="modCount">
|
||||
· {{ formatMessage(messages.modCount, { count: modCount }) }}
|
||||
@@ -43,24 +52,105 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex justify-end gap-2">
|
||||
<ButtonStyled>
|
||||
<button @click="handleDecline">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="handleAccept">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(messages.installButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Admonition
|
||||
v-if="hasExternalFiles"
|
||||
type="warning"
|
||||
:header="formatMessage(messages.unknownFilesWarning)"
|
||||
>
|
||||
{{ formatMessage(messages.unknownFilesDescription) }}
|
||||
</Admonition>
|
||||
|
||||
<div v-if="hasExternalFiles" class="relative w-full">
|
||||
<div
|
||||
ref="externalFileTable"
|
||||
class="max-h-[242px] overflow-y-auto rounded-2xl"
|
||||
@scroll="checkTableScrollState"
|
||||
>
|
||||
<Table
|
||||
:columns="externalFileColumns"
|
||||
:data="externalFileRows"
|
||||
row-key="id"
|
||||
virtualized
|
||||
:virtual-row-height="48"
|
||||
class="shadow-sm"
|
||||
>
|
||||
<template #cell-name="{ value }">
|
||||
<span class="block truncate" :title="String(value)">{{ value }}</span>
|
||||
</template>
|
||||
</Table>
|
||||
</div>
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-200 ease-out"
|
||||
enter-from-class="opacity-0 max-h-0"
|
||||
enter-to-class="opacity-100 max-h-2"
|
||||
leave-active-class="transition-all duration-200 ease-in"
|
||||
leave-from-class="opacity-100 max-h-2"
|
||||
leave-to-class="opacity-0 max-h-0"
|
||||
>
|
||||
<div
|
||||
v-if="showTableTopFade"
|
||||
class="pointer-events-none absolute left-0 right-0 top-0 z-10 h-2 bg-gradient-to-b from-bg-raised to-transparent"
|
||||
/>
|
||||
</Transition>
|
||||
<Transition
|
||||
enter-active-class="transition-all duration-200 ease-out"
|
||||
enter-from-class="opacity-0 max-h-0"
|
||||
enter-to-class="opacity-100 max-h-2"
|
||||
leave-active-class="transition-all duration-200 ease-in"
|
||||
leave-from-class="opacity-100 max-h-2"
|
||||
leave-to-class="opacity-0 max-h-0"
|
||||
>
|
||||
<div
|
||||
v-if="showTableBottomFade"
|
||||
class="pointer-events-none absolute bottom-0 left-0 right-0 z-10 h-2 bg-gradient-to-t from-bg-raised to-transparent"
|
||||
/>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<p v-if="hasExternalFiles" class="m-0 text-primary">
|
||||
{{ formatMessage(messages.reviewedFiles) }}
|
||||
</p>
|
||||
|
||||
<div class="flex w-full items-center justify-between gap-2">
|
||||
<ButtonStyled type="transparent" color="red">
|
||||
<button @click="handleReport">
|
||||
<ReportIcon />
|
||||
{{ formatMessage(commonMessages.reportButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<template v-if="hasExternalFiles">
|
||||
<ButtonStyled type="transparent" color="orange">
|
||||
<button @click="handleAccept">
|
||||
{{ formatMessage(messages.installAnyway) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="handleDecline">
|
||||
<BanIcon />
|
||||
{{ formatMessage(messages.dontInstall) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
<template v-else>
|
||||
<ButtonStyled>
|
||||
<button @click="handleDecline">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="handleAccept">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(messages.installButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NewModal>
|
||||
|
||||
<ModpackContentModal
|
||||
@@ -72,33 +162,56 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { DownloadIcon, EyeIcon, XIcon } from '@modrinth/assets'
|
||||
import type { ContentItem } from '@modrinth/ui'
|
||||
import { BanIcon, DownloadIcon, EyeIcon, ReportIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
type ContentItem,
|
||||
defineMessages,
|
||||
formatLoader,
|
||||
ModpackContentModal,
|
||||
NewModal,
|
||||
Table,
|
||||
type TableColumn,
|
||||
useScrollIndicator,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import { computed, nextTick, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads'
|
||||
import { get_project, get_project_many, get_version, get_version_many } from '@/helpers/cache.js'
|
||||
import { injectServerInstall } from '@/providers/server-install'
|
||||
|
||||
type ExternalFileColumn = 'name'
|
||||
type ExternalFileRow = {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const modpackVersionId = ref<string | null>(null)
|
||||
const modpackVersion = ref<Labrinth.Versions.v2.Version | null>(null)
|
||||
const project = ref<Labrinth.Projects.v3.Project | null>(null)
|
||||
const requiredContentProject = ref<Labrinth.Projects.v2.Project | null>(null)
|
||||
const externalFiles = ref<string[]>([])
|
||||
const externalFileTable = ref<HTMLElement | null>(null)
|
||||
const onInstallComplete = ref<() => void>(() => {})
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<{
|
||||
showExternalWarnings?: boolean
|
||||
}>()
|
||||
|
||||
const { installServerProject, startInstallingServer, stopInstallingServer } = injectServerInstall()
|
||||
const {
|
||||
showTopFade: showTableTopFade,
|
||||
showBottomFade: showTableBottomFade,
|
||||
checkScrollState: checkTableScrollState,
|
||||
forceCheck: forceCheckTableScroll,
|
||||
} = useScrollIndicator(externalFileTable)
|
||||
|
||||
const usingCustomModpack = computed(() => {
|
||||
return requiredContentProject.value?.id === project.value?.id
|
||||
@@ -111,13 +224,36 @@ const loaderDisplay = computed(() => {
|
||||
})
|
||||
|
||||
const modCount = computed(() => modpackVersion.value?.dependencies?.length)
|
||||
const hasExternalFiles = computed(
|
||||
() => Boolean(props.showExternalWarnings) && externalFiles.value.length > 0,
|
||||
)
|
||||
const externalFileRows = computed<ExternalFileRow[]>(() =>
|
||||
externalFiles.value.map((name, index) => ({
|
||||
id: `${index}-${name}`,
|
||||
name,
|
||||
})),
|
||||
)
|
||||
|
||||
async function fetchData(versionId: string) {
|
||||
// cache is making version null for some reason so bypassing for now
|
||||
modpackVersion.value = await get_version(versionId, 'bypass')
|
||||
const version = await get_version(versionId, 'bypass')
|
||||
modpackVersion.value = version
|
||||
|
||||
if (modpackVersion.value?.project_id) {
|
||||
requiredContentProject.value = await get_project(modpackVersion.value.project_id, 'bypass')
|
||||
if (version?.project_id) {
|
||||
requiredContentProject.value = await get_project(version.project_id, 'bypass')
|
||||
externalFiles.value = [
|
||||
...new Set(
|
||||
(version.dependencies ?? [])
|
||||
.filter(
|
||||
(dependency) =>
|
||||
dependency.dependency_type === 'embedded' &&
|
||||
!dependency.project_id &&
|
||||
!dependency.version_id &&
|
||||
dependency.file_name,
|
||||
)
|
||||
.flatMap((dependency) => (dependency.file_name ? [dependency.file_name] : [])),
|
||||
),
|
||||
].sort((left, right) => left.localeCompare(right))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +275,12 @@ function handleDecline() {
|
||||
hide()
|
||||
}
|
||||
|
||||
function handleReport() {
|
||||
if (project.value?.id) {
|
||||
openUrl(`https://modrinth.com/report?item=project&itemID=${project.value.id}`)
|
||||
}
|
||||
}
|
||||
|
||||
const modpackContentModal = ref<InstanceType<typeof ModpackContentModal>>()
|
||||
|
||||
async function openViewContents() {
|
||||
@@ -217,17 +359,19 @@ async function show(
|
||||
modpackVersionId.value = modpackVersionIdVal
|
||||
modpackVersion.value = null
|
||||
requiredContentProject.value = null
|
||||
externalFiles.value = []
|
||||
onInstallComplete.value = callback
|
||||
|
||||
if (modpackVersionIdVal) await fetchData(modpackVersionIdVal)
|
||||
|
||||
hide_ads_window()
|
||||
modal.value?.show(e)
|
||||
await nextTick()
|
||||
forceCheckTableScroll()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -235,22 +379,10 @@ const messages = defineMessages({
|
||||
id: 'app.modal.install-to-play.header',
|
||||
defaultMessage: 'Install to play',
|
||||
},
|
||||
sharedServerInstance: {
|
||||
id: 'app.modal.install-to-play.shared-server-instance',
|
||||
defaultMessage: 'Shared server instance',
|
||||
},
|
||||
contentRequired: {
|
||||
id: 'app.modal.install-to-play.content-required',
|
||||
defaultMessage: 'Content required',
|
||||
},
|
||||
serverRequiresMods: {
|
||||
id: 'app.modal.install-to-play.server-requires-mods',
|
||||
inviteWarning: {
|
||||
id: 'app.modal.install-to-play.invite-warning',
|
||||
defaultMessage:
|
||||
'This server requires mods to play. Click Install to set up the required files from Modrinth, then launch directly into the server.',
|
||||
},
|
||||
requiredModpack: {
|
||||
id: 'app.modal.install-to-play.required-modpack',
|
||||
defaultMessage: 'Required modpack',
|
||||
'This invite was created by another Modrinth user, not Modrinth. Only accept invites from people you trust.',
|
||||
},
|
||||
sharedInstance: {
|
||||
id: 'app.modal.install-to-play.shared-instance',
|
||||
@@ -268,7 +400,41 @@ const messages = defineMessages({
|
||||
id: 'app.modal.install-to-play.view-contents',
|
||||
defaultMessage: 'View contents',
|
||||
},
|
||||
unknownFilesWarning: {
|
||||
id: 'app.modal.install-to-play.unknown-files-warning',
|
||||
defaultMessage: 'Unknown files warning',
|
||||
},
|
||||
unknownFilesDescription: {
|
||||
id: 'app.modal.install-to-play.unknown-files-description',
|
||||
defaultMessage:
|
||||
'This server modpack contains files that aren’t published on Modrinth. We strongly recommend only installing files from sources you trust.',
|
||||
},
|
||||
unrecognizedFiles: {
|
||||
id: 'app.modal.install-to-play.unrecognized-files',
|
||||
defaultMessage: 'Unrecognized files',
|
||||
},
|
||||
reviewedFiles: {
|
||||
id: 'app.modal.install-to-play.reviewed-files',
|
||||
defaultMessage:
|
||||
'A file is only reviewed if it’s published to Modrinth, regardless of its file format (including .mrpack).',
|
||||
},
|
||||
installAnyway: {
|
||||
id: 'app.modal.install-to-play.install-anyway',
|
||||
defaultMessage: 'Install anyway',
|
||||
},
|
||||
dontInstall: {
|
||||
id: 'app.modal.install-to-play.dont-install',
|
||||
defaultMessage: 'Dont install',
|
||||
},
|
||||
})
|
||||
|
||||
const externalFileColumns = computed<TableColumn<ExternalFileColumn>[]>(() => [
|
||||
{
|
||||
key: 'name',
|
||||
label: formatMessage(messages.unrecognizedFiles),
|
||||
cellClass: '!h-12',
|
||||
},
|
||||
])
|
||||
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
|
||||
@@ -14,7 +14,7 @@ defineProps<{
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : undefined"
|
||||
size="24px"
|
||||
:tint-by="instance.path"
|
||||
:tint-by="instance.id"
|
||||
/>
|
||||
{{ instance.name }} <ChevronRightIcon />
|
||||
</span>
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { PlatformTag } from '@modrinth/utils'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
|
||||
@@ -27,14 +27,15 @@ import InstallationSettings from '@/components/ui/instance_settings/Installation
|
||||
import JavaSettings from '@/components/ui/instance_settings/JavaSettings.vue'
|
||||
import WindowSettings from '@/components/ui/instance_settings/WindowSettings.vue'
|
||||
import { get_project_v3 } from '@/helpers/cache'
|
||||
import { get_linked_modpack_info } from '@/helpers/instance'
|
||||
import { get_loader_versions } from '@/helpers/metadata'
|
||||
import { get_linked_modpack_info } from '@/helpers/profile'
|
||||
import { get_game_versions, get_loaders } from '@/helpers/tags'
|
||||
import { provideInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { GameInstance } from '../../../helpers/types'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const props = defineProps<{
|
||||
instance: GameInstance
|
||||
@@ -66,8 +67,8 @@ watch(
|
||||
() => props.instance,
|
||||
(instance) => {
|
||||
isMinecraftServer.value = false
|
||||
if (instance.linked_data?.project_id) {
|
||||
get_project_v3(instance.linked_data.project_id, 'must_revalidate')
|
||||
if (instance.link?.project_id) {
|
||||
get_project_v3(instance.link.project_id, 'must_revalidate')
|
||||
.then((project: Labrinth.Projects.v3.Project | undefined) => {
|
||||
if (project?.minecraft_server != null) {
|
||||
isMinecraftServer.value = true
|
||||
@@ -156,12 +157,18 @@ useQuery({
|
||||
queryFn: getSupportedModpackLoaders,
|
||||
})
|
||||
useQuery({
|
||||
queryKey: computed(() => ['linkedModpackInfo', props.instance.path]),
|
||||
queryFn: () => get_linked_modpack_info(props.instance.path, 'stale_while_revalidate'),
|
||||
enabled: computed(() => !!props.instance.linked_data?.project_id && !props.offline),
|
||||
queryKey: computed(() => ['linkedModpackInfo', props.instance.id]),
|
||||
queryFn: () => get_linked_modpack_info(props.instance.id, 'stale_while_revalidate'),
|
||||
enabled: computed(() => !!props.instance.link?.project_id && !props.offline),
|
||||
})
|
||||
|
||||
function show(tabIndex?: number) {
|
||||
if (props.instance.link?.project_id) {
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['linkedModpackInfo', props.instance.id],
|
||||
queryFn: () => get_linked_modpack_info(props.instance.id, 'stale_while_revalidate'),
|
||||
})
|
||||
}
|
||||
tabbedModal.value?.show()
|
||||
if (tabIndex !== undefined) {
|
||||
nextTick(() => tabbedModal.value?.setTab(tabIndex))
|
||||
@@ -182,7 +189,7 @@ defineExpose({ show, hide })
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : undefined"
|
||||
size="24px"
|
||||
:tint-by="props.instance.path"
|
||||
:tint-by="props.instance.id"
|
||||
/>
|
||||
{{ instance.name }} <ChevronRightIcon />
|
||||
<span class="font-extrabold text-contrast">{{
|
||||
|
||||
@@ -68,17 +68,17 @@ const messages = defineMessages({
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'go-to-instance', instancePath: string): void
|
||||
(e: 'go-to-instance', instanceId: string): void
|
||||
(e: 'create-anyway'): void
|
||||
}>()
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const instanceName = ref('')
|
||||
const instancePath = ref('')
|
||||
const instanceId = ref('')
|
||||
|
||||
function show(name: string, path: string) {
|
||||
function show(name: string, id: string) {
|
||||
instanceName.value = name
|
||||
instancePath.value = path
|
||||
instanceId.value = id
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ function handleCancel() {
|
||||
|
||||
function handleGoToInstance() {
|
||||
modal.value?.hide()
|
||||
emit('go-to-instance', instancePath.value)
|
||||
emit('go-to-instance', instanceId.value)
|
||||
}
|
||||
|
||||
function handleCreateAnyway() {
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
<ContentDiffModal
|
||||
ref="diffModal"
|
||||
:header="formatMessage(messages.updateToPlay)"
|
||||
:admonition-header="formatMessage(messages.updateRequired)"
|
||||
:description="
|
||||
instance ? formatMessage(messages.updateRequiredDescription, { name: instance.name }) : ''
|
||||
"
|
||||
:diffs="normalizedDiffs"
|
||||
:version-date="versionDate"
|
||||
:show-external-warnings="showExternalWarnings"
|
||||
:confirm-label="formatMessage(commonMessages.updateButton)"
|
||||
:confirm-icon="DownloadIcon"
|
||||
:show-report-button="true"
|
||||
:removed-label="formatMessage(messages.removed)"
|
||||
@confirm="handleUpdate"
|
||||
@cancel="handleDecline"
|
||||
@report="handleReport"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -26,12 +26,12 @@ import {
|
||||
defineMessages,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { get_project_many, get_version, get_version_many } from '@/helpers/cache.js'
|
||||
import { update_managed_modrinth_version } from '@/helpers/profile'
|
||||
import { wait_for_install_job } from '@/helpers/install'
|
||||
import { update_managed_modrinth_version } from '@/helpers/instance'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { injectServerInstall } from '@/providers/server-install'
|
||||
|
||||
@@ -76,6 +76,10 @@ const { formatMessage } = useVIntl()
|
||||
const { startInstallingServer, stopInstallingServer } = injectServerInstall()
|
||||
type UpdateCompleteCallback = () => void | Promise<void>
|
||||
|
||||
defineProps<{
|
||||
showExternalWarnings?: boolean
|
||||
}>()
|
||||
|
||||
const diffModal = ref<InstanceType<typeof ContentDiffModal>>()
|
||||
const instance = ref<GameInstance | null>(null)
|
||||
const onUpdateComplete = ref<UpdateCompleteCallback>(() => {})
|
||||
@@ -86,6 +90,7 @@ const modpackVersion = ref<Version | null>(null)
|
||||
const normalizedDiffs = computed<ContentDiffItem[]>(() =>
|
||||
diffs.value.map((diff) => ({
|
||||
type: diff.type,
|
||||
external: Boolean(diff.fileName && !diff.project),
|
||||
projectName: diff.project?.title,
|
||||
fileName: diff.fileName,
|
||||
currentVersionName: diff.currentVersion?.version_number,
|
||||
@@ -93,6 +98,12 @@ const normalizedDiffs = computed<ContentDiffItem[]>(() =>
|
||||
})),
|
||||
)
|
||||
|
||||
const versionDate = computed(() =>
|
||||
modpackVersion.value?.date_published
|
||||
? dayjs(modpackVersion.value.date_published).format('MMMM D, YYYY')
|
||||
: undefined,
|
||||
)
|
||||
|
||||
async function computeDependencyDiffs(
|
||||
currentDeps: Dependency[],
|
||||
latestDeps: Dependency[],
|
||||
@@ -189,6 +200,10 @@ async function computeDependencyDiffs(
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const aExternal = Boolean(a.fileName && !a.project)
|
||||
const bExternal = Boolean(b.fileName && !b.project)
|
||||
if (aExternal !== bExternal) return aExternal ? -1 : 1
|
||||
|
||||
const typeOrder = { added: 0, updated: 1, removed: 2 }
|
||||
const typeCompare = typeOrder[a.type] - typeOrder[b.type]
|
||||
if (typeCompare !== 0) return typeCompare
|
||||
@@ -202,15 +217,15 @@ async function computeDependencyDiffs(
|
||||
}
|
||||
|
||||
async function checkUpdateAvailable(inst: GameInstance): Promise<DependencyDiff[] | null> {
|
||||
if (!inst.linked_data) return null
|
||||
if (!modpackVersionId.value || !inst.linked_data.version_id) return null
|
||||
if (!inst.link) return null
|
||||
if (!modpackVersionId.value || !inst.link.version_id) return null
|
||||
|
||||
try {
|
||||
// For server projects, linked_data.project_id is the server project but
|
||||
// linked_data.version_id references a content modpack version from a different project.
|
||||
// Detect this by comparing the version's project_id with linked_data.project_id.
|
||||
// For server projects, link.project_id is the server project but
|
||||
// link.version_id references a content modpack version from a different project.
|
||||
// Detect this by comparing the version's project_id with link.project_id.
|
||||
modpackVersion.value = await get_version(modpackVersionId.value, 'bypass')
|
||||
const instanceModpackVersion = await get_version(inst.linked_data.version_id, 'bypass')
|
||||
const instanceModpackVersion = await get_version(inst.link.version_id, 'bypass')
|
||||
|
||||
// Compute dependency diffs between current and latest version
|
||||
if (instanceModpackVersion && modpackVersion.value) {
|
||||
@@ -226,23 +241,14 @@ async function checkUpdateAvailable(inst: GameInstance): Promise<DependencyDiff[
|
||||
return null
|
||||
}
|
||||
|
||||
watch(
|
||||
() => instance.value,
|
||||
async (newInstance) => {
|
||||
if (!newInstance) return
|
||||
const result = await checkUpdateAvailable(newInstance)
|
||||
diffs.value = result || []
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
)
|
||||
|
||||
async function handleUpdate() {
|
||||
hide()
|
||||
const serverProjectId = instance.value?.linked_data?.project_id
|
||||
const serverProjectId = instance.value?.link?.project_id
|
||||
if (serverProjectId) startInstallingServer(serverProjectId)
|
||||
try {
|
||||
if (modpackVersionId.value && instance.value) {
|
||||
await update_managed_modrinth_version(instance.value.path, modpackVersionId.value)
|
||||
const job = await update_managed_modrinth_version(instance.value.id, modpackVersionId.value)
|
||||
await wait_for_install_job(job.job_id)
|
||||
await onUpdateComplete.value()
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -252,14 +258,6 @@ async function handleUpdate() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleReport() {
|
||||
if (instance.value?.linked_data?.project_id) {
|
||||
openUrl(
|
||||
`https://modrinth.com/report?item=project&itemID=${instance.value.linked_data.project_id}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function handleDecline() {
|
||||
hide()
|
||||
}
|
||||
@@ -272,8 +270,15 @@ function show(
|
||||
) {
|
||||
instance.value = instanceVal
|
||||
modpackVersionId.value = modpackVersionIdVal
|
||||
modpackVersion.value = null
|
||||
diffs.value = []
|
||||
onUpdateComplete.value = callback
|
||||
diffModal.value?.show(e)
|
||||
void checkUpdateAvailable(instanceVal).then((result) => {
|
||||
if (instance.value?.id === instanceVal.id && modpackVersionId.value === modpackVersionIdVal) {
|
||||
diffs.value = result || []
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function hide() {
|
||||
@@ -285,23 +290,20 @@ const messages = defineMessages({
|
||||
id: 'app.modal.update-to-play.header',
|
||||
defaultMessage: 'Update to play',
|
||||
},
|
||||
updateRequired: {
|
||||
id: 'app.modal.update-to-play.update-required',
|
||||
defaultMessage: 'Update required',
|
||||
},
|
||||
updateRequiredDescription: {
|
||||
id: 'app.modal.update-to-play.update-required-description',
|
||||
defaultMessage:
|
||||
'An update is required to play {name}. Please update to the latest version to launch the game.',
|
||||
},
|
||||
removed: {
|
||||
id: 'app.modal.update-to-play.removed',
|
||||
defaultMessage: 'Removed',
|
||||
},
|
||||
})
|
||||
|
||||
const hasUpdate = computed(() => {
|
||||
if (!instance.value?.linked_data) return false
|
||||
return (
|
||||
modpackVersionId.value != null &&
|
||||
modpackVersionId.value !== instance.value.linked_data.version_id
|
||||
)
|
||||
if (!instance.value?.link) return false
|
||||
return modpackVersionId.value != null && modpackVersionId.value !== instance.value.link.version_id
|
||||
})
|
||||
|
||||
defineExpose({ show, hide, hasUpdate })
|
||||
|
||||
@@ -11,6 +11,7 @@ const themeStore = useTheming()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const worldsInHomeFlag: FeatureFlag = 'worlds_in_home'
|
||||
const skipNonEssentialWarningsFlag: FeatureFlag = 'skip_non_essential_warnings'
|
||||
const skipUnknownPackWarningFlag: FeatureFlag = 'skip_unknown_pack_warning'
|
||||
const showPlayTimeFlag: FeatureFlag = 'show_instance_play_time'
|
||||
|
||||
@@ -101,6 +102,15 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
"If you attempt to install a Modrinth Pack file (.mrpack) that isn't hosted on Modrinth, we'll make sure you understand the risks before installing it.",
|
||||
},
|
||||
skipNonEssentialWarningsTitle: {
|
||||
id: 'app.appearance-settings.skip-non-essential-warnings.title',
|
||||
defaultMessage: 'Skip non-essential warnings',
|
||||
},
|
||||
skipNonEssentialWarningsDescription: {
|
||||
id: 'app.appearance-settings.skip-non-essential-warnings.description',
|
||||
defaultMessage:
|
||||
'Automatically skips low-risk confirmations like duplicate modpack installs, normal content deletion, bulk updates, unlinking modpacks, and repair prompts. Dangerous warnings will still be shown.',
|
||||
},
|
||||
showPlayTimeTitle: {
|
||||
id: 'app.appearance-settings.show-play-time.title',
|
||||
defaultMessage: 'Show play time',
|
||||
@@ -285,6 +295,25 @@ watch(
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.skipNonEssentialWarningsTitle) }}
|
||||
</h2>
|
||||
<p class="m-0 mt-1">{{ formatMessage(messages.skipNonEssentialWarningsDescription) }}</p>
|
||||
</div>
|
||||
<Toggle
|
||||
:model-value="themeStore.getFeatureFlag(skipNonEssentialWarningsFlag)"
|
||||
@update:model-value="
|
||||
() => {
|
||||
const newValue = !themeStore.getFeatureFlag(skipNonEssentialWarningsFlag)
|
||||
themeStore.featureFlags[skipNonEssentialWarningsFlag] = newValue
|
||||
settings.feature_flags[skipNonEssentialWarningsFlag] = newValue
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">
|
||||
|
||||
@@ -1,12 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import { Toggle } from '@modrinth/ui'
|
||||
import { Settings2Icon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
injectPageContext,
|
||||
Toggle,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { open_ads_consent_preferences } from '@/helpers/ads.js'
|
||||
import { optInAnalytics, optOutAnalytics } from '@/helpers/analytics'
|
||||
import { get, set } from '@/helpers/settings.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { adConsentAvailable } = injectPageContext()
|
||||
const settings = ref(await get())
|
||||
|
||||
const messages = defineMessages({
|
||||
adsConsentTitle: {
|
||||
id: 'app.ads-consent.title',
|
||||
defaultMessage: 'Your privacy and how ads support Modrinth',
|
||||
},
|
||||
adsConsentIntro: {
|
||||
id: 'app.settings.privacy.ads-consent.intro',
|
||||
defaultMessage:
|
||||
'Ads make Modrinth possible and fund creator payouts. Our partners may store or access cookies in the app to personalize ads and measure performance. You can opt out or manage your preferences below.',
|
||||
},
|
||||
adsConsentManage: {
|
||||
id: 'app.ads-consent.manage',
|
||||
defaultMessage: 'Manage preferences',
|
||||
},
|
||||
})
|
||||
|
||||
async function manageAdsPreferences() {
|
||||
await open_ads_consent_preferences().catch(handleError)
|
||||
}
|
||||
|
||||
watch(
|
||||
settings,
|
||||
async () => {
|
||||
@@ -23,18 +55,26 @@ watch(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Personalized ads</h2>
|
||||
<p class="m-0 mt-1 text-sm">
|
||||
Modrinth's ad provider, Aditude, shows ads based on your preferences. By disabling this
|
||||
option, you opt out and ads will no longer be shown based on your interests.
|
||||
</p>
|
||||
<div v-if="adConsentAvailable">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.adsConsentTitle) }}
|
||||
</h2>
|
||||
<div class="mt-1 flex flex-col gap-2.5 items-start">
|
||||
<div class="flex flex-col gap-1 items-start">
|
||||
<div class="text-sm">
|
||||
{{ formatMessage(messages.adsConsentIntro) }}
|
||||
</div>
|
||||
</div>
|
||||
<ButtonStyled>
|
||||
<button class="!shadow-none" @click="manageAdsPreferences">
|
||||
<Settings2Icon aria-hidden="true" />
|
||||
{{ formatMessage(messages.adsConsentManage) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<Toggle id="personalized-ads" v-model="settings.personalized_ads" />
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between gap-4">
|
||||
<div class="mt-8 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Telemetry</h2>
|
||||
<p class="m-0 mt-1 text-sm">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { BoxIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
||||
import { BoxIcon, FolderOpenIcon, FolderSearchIcon, TrashIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager, Slider, StyledInput } from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref, watch } from 'vue'
|
||||
@@ -7,9 +7,13 @@ import { ref, watch } from 'vue'
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||
import { purge_cache_types } from '@/helpers/cache.js'
|
||||
import { get, set } from '@/helpers/settings.ts'
|
||||
import { showAppDbBackupsFolder } from '@/helpers/utils.js'
|
||||
import { useTheming } from '@/store/state'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const themeStore = useTheming()
|
||||
const settings = ref(await get())
|
||||
const purgeCacheConfirmModal = ref(null)
|
||||
|
||||
watch(
|
||||
settings,
|
||||
@@ -48,6 +52,19 @@ async function purgeCache() {
|
||||
]).catch(handleError)
|
||||
}
|
||||
|
||||
function handlePurgeCacheClick() {
|
||||
if (themeStore.getFeatureFlag('skip_non_essential_warnings')) {
|
||||
void purgeCache()
|
||||
return
|
||||
}
|
||||
|
||||
purgeCacheConfirmModal.value?.show()
|
||||
}
|
||||
|
||||
async function openDbBackupsFolder() {
|
||||
await showAppDbBackupsFolder().catch(handleError)
|
||||
}
|
||||
|
||||
async function findLauncherDir() {
|
||||
const newDir = await open({
|
||||
multiple: false,
|
||||
@@ -97,7 +114,7 @@ async function findLauncherDir() {
|
||||
@proceed="purgeCache"
|
||||
/>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">App cache</h2>
|
||||
<button id="purge-cache" class="btn min-w-max" @click="$refs.purgeCacheConfirmModal.show()">
|
||||
<button id="purge-cache" class="btn min-w-max" @click="handlePurgeCacheClick">
|
||||
<TrashIcon />
|
||||
Purge cache
|
||||
</button>
|
||||
@@ -136,5 +153,16 @@ async function findLauncherDir() {
|
||||
value if you are frequently getting I/O errors. (app restart required to take effect)
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h2 class="mt-0 m-0 text-lg font-semibold text-contrast">App database backups</h2>
|
||||
<button id="open-db-backups-folder" class="btn min-w-max" @click="openDbBackupsFolder">
|
||||
<FolderOpenIcon />
|
||||
Open backups folder
|
||||
</button>
|
||||
<p class="m-0 leading-tight text-secondary">
|
||||
Backups of important app data are stored here in case you need to recover them later.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<SkinPreviewRenderer
|
||||
:variant="variant"
|
||||
:texture-src="previewSkin || ''"
|
||||
:ears-texture-src="uploadedTextureUrl?.original ?? currentSkin?.texture"
|
||||
:cape-src="selectedCapeTexture"
|
||||
framing="modal"
|
||||
:initial-rotation="Math.PI / 8"
|
||||
|
||||
@@ -27,10 +27,10 @@ import { useRouter } from 'vue-router'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_project } from '@/helpers/cache'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { get_by_profile_path } from '@/helpers/process'
|
||||
import { kill, run } from '@/helpers/profile'
|
||||
import { kill, run } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { showProfileInFolder } from '@/helpers/utils'
|
||||
import { showInstanceInFolder } from '@/helpers/utils'
|
||||
import { handleSevereError } from '@/store/error'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
@@ -52,13 +52,13 @@ const props = defineProps<{
|
||||
last_played: Dayjs
|
||||
}>()
|
||||
|
||||
const loadingModpack = ref(!!props.instance.linked_data)
|
||||
const loadingModpack = ref(!!props.instance.link)
|
||||
|
||||
const modpack = ref()
|
||||
|
||||
if (props.instance.linked_data) {
|
||||
if (props.instance.link) {
|
||||
nextTick().then(async () => {
|
||||
modpack.value = await get_project(props.instance.linked_data?.project_id, 'must_revalidate')
|
||||
modpack.value = await get_project(props.instance.link?.project_id, 'must_revalidate')
|
||||
loadingModpack.value = false
|
||||
})
|
||||
}
|
||||
@@ -81,8 +81,8 @@ const playing = ref(false)
|
||||
const play = async (event: MouseEvent) => {
|
||||
event?.stopPropagation()
|
||||
loading.value = true
|
||||
await run(props.instance.path)
|
||||
.catch((err) => handleSevereError(err, { profilePath: props.instance.path }))
|
||||
await run(props.instance.id)
|
||||
.catch((err) => handleSevereError(err, { instanceId: props.instance.id }))
|
||||
.finally(() => {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: props.instance.loader,
|
||||
@@ -97,7 +97,7 @@ const play = async (event: MouseEvent) => {
|
||||
const stop = async (event: MouseEvent) => {
|
||||
event?.stopPropagation()
|
||||
loading.value = true
|
||||
await kill(props.instance.path).catch(handleError)
|
||||
await kill(props.instance.id).catch(handleError)
|
||||
trackEvent('InstanceStop', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
@@ -112,7 +112,7 @@ const unlistenProcesses = await process_listener(async () => {
|
||||
})
|
||||
|
||||
const checkProcess = async () => {
|
||||
const runningProcesses = await get_by_profile_path(props.instance.path).catch(handleError)
|
||||
const runningProcesses = await get_by_instance_id(props.instance.id).catch(handleError)
|
||||
|
||||
playing.value = runningProcesses.length > 0
|
||||
}
|
||||
@@ -130,7 +130,7 @@ onUnmounted(() => {
|
||||
<template #clickable>
|
||||
<router-link
|
||||
class="no-click-animation"
|
||||
:to="`/instance/${encodeURIComponent(instance.path)}`"
|
||||
:to="`/instance/${encodeURIComponent(instance.id)}`"
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
@@ -138,7 +138,7 @@ onUnmounted(() => {
|
||||
>
|
||||
<Avatar
|
||||
:src="instanceIcon ? convertFileSrc(instanceIcon) : undefined"
|
||||
:tint-by="instance.path"
|
||||
:tint-by="instance.id"
|
||||
size="48px"
|
||||
/>
|
||||
<div class="flex flex-col col-span-2 justify-between h-full">
|
||||
@@ -206,12 +206,12 @@ onUnmounted(() => {
|
||||
:options="[
|
||||
{
|
||||
id: 'open-instance',
|
||||
shown: !!instance.path,
|
||||
action: () => router.push(encodeURI(`/instance/${instance.path}`)),
|
||||
shown: !!instance.id,
|
||||
action: () => router.push(encodeURI(`/instance/${instance.id}`)),
|
||||
},
|
||||
{
|
||||
id: 'open-folder',
|
||||
action: () => showProfileInFolder(instance.path),
|
||||
action: () => showInstanceInFolder(instance.id),
|
||||
},
|
||||
]"
|
||||
>
|
||||
|
||||
@@ -10,13 +10,13 @@ import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import InstanceItem from '@/components/ui/world/InstanceItem.vue'
|
||||
import WorldItem from '@/components/ui/world/WorldItem.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { process_listener, profile_listener } from '@/helpers/events'
|
||||
import { instance_listener, process_listener } from '@/helpers/events'
|
||||
import { kill, run } from '@/helpers/instance'
|
||||
import { get_all } from '@/helpers/process'
|
||||
import { kill, run } from '@/helpers/profile'
|
||||
import { get_game_versions } from '@/helpers/tags'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import {
|
||||
get_profile_protocol_version,
|
||||
get_instance_protocol_version,
|
||||
get_recent_worlds,
|
||||
getWorldIdentifier,
|
||||
hasServerQuickPlaySupport,
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
type ServerWorld,
|
||||
start_join_server,
|
||||
start_join_singleplayer_world,
|
||||
type WorldWithProfile,
|
||||
type WorldWithInstance,
|
||||
} from '@/helpers/worlds.ts'
|
||||
import { handleSevereError } from '@/store/error'
|
||||
import { useTheming } from '@/store/theme.ts'
|
||||
@@ -66,7 +66,7 @@ type InstanceJumpBackInItem = BaseJumpBackInItem & {
|
||||
|
||||
type WorldJumpBackInItem = BaseJumpBackInItem & {
|
||||
type: 'world'
|
||||
world: WorldWithProfile
|
||||
world: WorldWithInstance
|
||||
}
|
||||
|
||||
type JumpBackInItem = InstanceJumpBackInItem | WorldJumpBackInItem
|
||||
@@ -100,7 +100,7 @@ async function populateJumpBackIn() {
|
||||
const worlds = await get_recent_worlds(MAX_JUMP_BACK_IN, ['normal', 'favorite'])
|
||||
|
||||
worlds.forEach((world) => {
|
||||
const instance = props.recentInstances.find((instance) => instance.path === world.profile)
|
||||
const instance = props.recentInstances.find((instance) => instance.id === world.instance_id)
|
||||
|
||||
if (!instance || !world.last_played) {
|
||||
return
|
||||
@@ -115,23 +115,23 @@ async function populateJumpBackIn() {
|
||||
})
|
||||
|
||||
const servers: {
|
||||
instancePath: string
|
||||
instanceId: string
|
||||
address: string
|
||||
}[] = worldItems
|
||||
.filter((item) => item.world.type === 'server' && item.instance)
|
||||
.map((item) => ({
|
||||
instancePath: item.instance.path,
|
||||
instanceId: item.instance.id,
|
||||
address: (item.world as ServerWorld).address,
|
||||
}))
|
||||
|
||||
// fetch protocol versions for all unique MC versions with server worlds
|
||||
const uniqueServerInstances = new Set<string>(servers.map((x) => x.instancePath))
|
||||
const uniqueServerInstances = new Set<string>(servers.map((x) => x.instanceId))
|
||||
await Promise.all(
|
||||
[...uniqueServerInstances].map((path) =>
|
||||
get_profile_protocol_version(path)
|
||||
.then((protoVer) => (protocolVersions.value[path] = protoVer))
|
||||
[...uniqueServerInstances].map((instanceId) =>
|
||||
get_instance_protocol_version(instanceId)
|
||||
.then((protoVer) => (protocolVersions.value[instanceId] = protoVer))
|
||||
.catch(() => {
|
||||
console.error(`Failed to get profile protocol for: ${path} `)
|
||||
console.error(`Failed to get instance protocol for: ${instanceId} `)
|
||||
}),
|
||||
),
|
||||
)
|
||||
@@ -145,14 +145,14 @@ async function populateJumpBackIn() {
|
||||
}
|
||||
})
|
||||
|
||||
servers.forEach(({ instancePath, address }) =>
|
||||
refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address),
|
||||
servers.forEach(({ instanceId, address }) =>
|
||||
refreshServerData(serverData.value[address], protocolVersions.value[instanceId], address),
|
||||
)
|
||||
}
|
||||
|
||||
const instanceItems: InstanceJumpBackInItem[] = []
|
||||
for (const instance of props.recentInstances) {
|
||||
const worldItem = worldItems.find((item) => item.instance.path === instance.path)
|
||||
const worldItem = worldItems.find((item) => item.instance.id === instance.id)
|
||||
if ((worldItem && worldItem.last_played.isAfter(TWO_WEEKS_AGO)) || !instance.last_played) {
|
||||
continue
|
||||
}
|
||||
@@ -171,14 +171,14 @@ async function populateJumpBackIn() {
|
||||
.slice(0, MAX_JUMP_BACK_IN)
|
||||
}
|
||||
|
||||
function refreshServer(address: string, instancePath: string) {
|
||||
refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address)
|
||||
function refreshServer(address: string, instanceId: string) {
|
||||
refreshServerData(serverData.value[address], protocolVersions.value[instanceId], address)
|
||||
}
|
||||
|
||||
async function joinWorld(world: WorldWithProfile, instance?: GameInstance) {
|
||||
async function joinWorld(world: WorldWithInstance, instance?: GameInstance) {
|
||||
console.log(`Joining world ${getWorldIdentifier(world)}`)
|
||||
if (world.type === 'server') {
|
||||
await start_join_server(world.profile, world.address).catch(handleError)
|
||||
await start_join_server(world.instance_id, world.address).catch(handleError)
|
||||
if (instance) {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: instance.loader,
|
||||
@@ -187,13 +187,13 @@ async function joinWorld(world: WorldWithProfile, instance?: GameInstance) {
|
||||
})
|
||||
}
|
||||
} else if (world.type === 'singleplayer') {
|
||||
await start_join_singleplayer_world(world.profile, world.path).catch(handleError)
|
||||
await start_join_singleplayer_world(world.instance_id, world.path).catch(handleError)
|
||||
}
|
||||
}
|
||||
|
||||
async function playInstance(instance: GameInstance) {
|
||||
await run(instance.path)
|
||||
.catch((err) => handleSevereError(err, { profilePath: instance.path }))
|
||||
await run(instance.id)
|
||||
.catch((err) => handleSevereError(err, { instanceId: instance.id }))
|
||||
.finally(() => {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: instance.loader,
|
||||
@@ -210,14 +210,14 @@ async function stopInstance(path: string) {
|
||||
})
|
||||
}
|
||||
|
||||
const currentProfile = ref<string>()
|
||||
const currentInstance = ref<string>()
|
||||
const currentWorld = ref<string>()
|
||||
|
||||
const unlistenProcesses = await process_listener(async () => {
|
||||
await checkProcesses()
|
||||
})
|
||||
|
||||
const unlistenProfiles = await profile_listener(async () => {
|
||||
const unlistenInstances = await instance_listener(async () => {
|
||||
await populateJumpBackIn().catch(() => {
|
||||
console.error('Failed to populate jump back in')
|
||||
})
|
||||
@@ -227,18 +227,18 @@ const runningInstances = ref<string[]>([])
|
||||
|
||||
type ProcessMetadata = {
|
||||
uuid: string
|
||||
profile_path: string
|
||||
instance_id: string
|
||||
start_time: string
|
||||
}
|
||||
|
||||
const checkProcesses = async () => {
|
||||
const runningProcesses: ProcessMetadata[] = await get_all().catch(handleError)
|
||||
|
||||
const runningPaths = runningProcesses.map((x) => x.profile_path)
|
||||
const runningPaths = runningProcesses.map((x) => x.instance_id)
|
||||
|
||||
const stoppedInstances = runningInstances.value.filter((x) => !runningPaths.includes(x))
|
||||
if (currentProfile.value && stoppedInstances.includes(currentProfile.value)) {
|
||||
currentProfile.value = undefined
|
||||
if (currentInstance.value && stoppedInstances.includes(currentInstance.value)) {
|
||||
currentInstance.value = undefined
|
||||
currentWorld.value = undefined
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ onMounted(() => {
|
||||
|
||||
onUnmounted(() => {
|
||||
unlistenProcesses()
|
||||
unlistenProfiles()
|
||||
unlistenInstances()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -278,14 +278,14 @@ onUnmounted(() => {
|
||||
<div class="grid-when-huge flex flex-col w-full gap-2">
|
||||
<template
|
||||
v-for="item in jumpBackInItems"
|
||||
:key="`${item.instance.path}-${item.type === 'world' ? getWorldIdentifier(item.world) : 'instance'}`"
|
||||
:key="`${item.instance.id}-${item.type === 'world' ? getWorldIdentifier(item.world) : 'instance'}`"
|
||||
>
|
||||
<WorldItem
|
||||
v-if="item.type === 'world'"
|
||||
:world="item.world"
|
||||
:playing-instance="runningInstances.includes(item.instance.path)"
|
||||
:playing-instance="runningInstances.includes(item.instance.id)"
|
||||
:playing-world="
|
||||
currentProfile === item.instance.path && currentWorld === getWorldIdentifier(item.world)
|
||||
currentInstance === item.instance.id && currentWorld === getWorldIdentifier(item.world)
|
||||
"
|
||||
:refreshing="
|
||||
item.world.type === 'server'
|
||||
@@ -306,34 +306,34 @@ onUnmounted(() => {
|
||||
:rendered-motd="
|
||||
item.world.type === 'server' ? serverData[item.world.address].renderedMotd : undefined
|
||||
"
|
||||
:current-protocol="protocolVersions[item.instance.path]"
|
||||
:current-protocol="protocolVersions[item.instance.id]"
|
||||
:game-mode="
|
||||
item.world.type === 'singleplayer' ? GAME_MODES[item.world.game_mode] : undefined
|
||||
"
|
||||
:instance-path="item.instance.path"
|
||||
:instance-id="item.instance.id"
|
||||
:instance-name="item.instance.name"
|
||||
:instance-icon="item.instance.icon_path"
|
||||
@refresh="
|
||||
() =>
|
||||
item.world.type === 'server'
|
||||
? refreshServer(item.world.address, item.instance.path)
|
||||
? refreshServer(item.world.address, item.instance.id)
|
||||
: {}
|
||||
"
|
||||
@update="() => populateJumpBackIn()"
|
||||
@play="
|
||||
() => {
|
||||
currentProfile = item.instance.path
|
||||
currentInstance = item.instance.id
|
||||
currentWorld = getWorldIdentifier(item.world)
|
||||
joinWorld(item.world, item.instance)
|
||||
}
|
||||
"
|
||||
@play-instance="
|
||||
() => {
|
||||
currentProfile = item.instance.path
|
||||
currentInstance = item.instance.id
|
||||
playInstance(item.instance)
|
||||
}
|
||||
"
|
||||
@stop="() => stopInstance(item.instance.path)"
|
||||
@stop="() => stopInstance(item.instance.id)"
|
||||
/>
|
||||
<InstanceItem v-else :instance="item.instance" :last_played="item.last_played" />
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import {
|
||||
ClipboardCopyIcon,
|
||||
EditIcon,
|
||||
ExternalIcon,
|
||||
EyeIcon,
|
||||
FolderOpenIcon,
|
||||
IssuesIcon,
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
SmartClickable,
|
||||
TagItem,
|
||||
@@ -39,7 +41,7 @@ import type { Component } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { copyToClipboard } from '@/helpers/utils'
|
||||
import { copyToClipboard, createInstanceShortcut } from '@/helpers/utils'
|
||||
import type {
|
||||
ProtocolVersion,
|
||||
ServerStatus,
|
||||
@@ -60,6 +62,7 @@ const formatDateTime = useFormatDateTime({
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'play' | 'play-instance' | 'update' | 'stop' | 'refresh' | 'edit' | 'delete'): void
|
||||
@@ -91,9 +94,10 @@ const props = withDefaults(
|
||||
managed?: boolean
|
||||
|
||||
// Instance
|
||||
instancePath?: string
|
||||
instanceId?: string
|
||||
instanceName?: string
|
||||
instanceIcon?: string
|
||||
shortcutInstanceId?: string
|
||||
}>(),
|
||||
{
|
||||
playingInstance: false,
|
||||
@@ -110,9 +114,10 @@ const props = withDefaults(
|
||||
gameMode: undefined,
|
||||
managed: false,
|
||||
|
||||
instancePath: undefined,
|
||||
instanceId: undefined,
|
||||
instanceName: undefined,
|
||||
instanceIcon: undefined,
|
||||
shortcutInstanceId: undefined,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -131,6 +136,33 @@ const serverIncompatible = computed(
|
||||
|
||||
const locked = computed(() => props.world.type === 'singleplayer' && props.world.locked)
|
||||
const managed = computed(() => props.managed)
|
||||
const shortcutInstanceId = computed(() => props.shortcutInstanceId ?? props.instanceId)
|
||||
|
||||
async function createShortcut() {
|
||||
if (!shortcutInstanceId.value) return
|
||||
|
||||
try {
|
||||
const shortcutPath = await createInstanceShortcut(
|
||||
props.world.name,
|
||||
shortcutInstanceId.value,
|
||||
props.world.type === 'server'
|
||||
? { server: (props.world as ServerWorld).address }
|
||||
: { singleplayerWorld: (props.world as SingleplayerWorld).path },
|
||||
)
|
||||
if (!shortcutPath) return
|
||||
|
||||
addNotification({
|
||||
type: 'success',
|
||||
title: 'Shortcut created',
|
||||
})
|
||||
} catch (error) {
|
||||
addNotification({
|
||||
type: 'error',
|
||||
title: 'Failed to create shortcut',
|
||||
text: error instanceof Error ? error.message : '',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
hardcore: {
|
||||
@@ -185,6 +217,10 @@ const messages = defineMessages({
|
||||
id: 'instance.worlds.dont_show_on_home',
|
||||
defaultMessage: `Don't show on Home`,
|
||||
},
|
||||
createShortcut: {
|
||||
id: 'instance.worlds.create_shortcut',
|
||||
defaultMessage: 'Create shortcut',
|
||||
},
|
||||
linkedServer: {
|
||||
id: 'instance.worlds.linked_server',
|
||||
defaultMessage: 'Managed by server project',
|
||||
@@ -209,10 +245,10 @@ const messages = defineMessages({
|
||||
</script>
|
||||
<template>
|
||||
<SmartClickable>
|
||||
<template v-if="instancePath" #clickable>
|
||||
<template v-if="instanceId" #clickable>
|
||||
<router-link
|
||||
class="no-click-animation"
|
||||
:to="`/instance/${encodeURIComponent(instancePath)}/worlds?highlight=${encodeURIComponent(getWorldIdentifier(world))}`"
|
||||
:to="`/instance/${encodeURIComponent(instanceId)}/worlds?highlight=${encodeURIComponent(getWorldIdentifier(world))}`"
|
||||
/>
|
||||
</template>
|
||||
<div
|
||||
@@ -324,16 +360,16 @@ const messages = defineMessages({
|
||||
</template>
|
||||
<template v-else> {{ formatMessage(messages.notPlayedYet) }} </template>
|
||||
</div>
|
||||
<template v-if="instancePath">
|
||||
<template v-if="instanceId">
|
||||
•
|
||||
<router-link
|
||||
class="flex items-center gap-1 truncate hover:underline text-secondary smart-clickable:allow-pointer-events"
|
||||
:to="`/instance/${instancePath}`"
|
||||
:to="`/instance/${instanceId}`"
|
||||
>
|
||||
<Avatar
|
||||
:src="instanceIcon ? convertFileSrc(instanceIcon) : undefined"
|
||||
size="16px"
|
||||
:tint-by="instancePath"
|
||||
:tint-by="instanceId"
|
||||
class="shrink-0"
|
||||
/>
|
||||
<span class="truncate">{{ instanceName }}</span>
|
||||
@@ -420,14 +456,14 @@ const messages = defineMessages({
|
||||
:options="[
|
||||
{
|
||||
id: 'play-instance',
|
||||
shown: !!instancePath,
|
||||
shown: !!instanceId,
|
||||
disabled: playingInstance,
|
||||
action: () => emit('play-instance'),
|
||||
},
|
||||
{
|
||||
id: 'open-instance',
|
||||
shown: !!instancePath,
|
||||
action: () => router.push(encodeURI(`/instance/${instancePath}`)),
|
||||
shown: !!instanceId,
|
||||
action: () => router.push(`/instance/${encodeURIComponent(instanceId)}`),
|
||||
},
|
||||
{
|
||||
id: 'refresh',
|
||||
@@ -442,7 +478,7 @@ const messages = defineMessages({
|
||||
{
|
||||
id: 'edit',
|
||||
action: () => emit('edit'),
|
||||
shown: !instancePath,
|
||||
shown: !instanceId,
|
||||
disabled: locked || managed,
|
||||
tooltip: locked
|
||||
? formatMessage(messages.worldInUse)
|
||||
@@ -457,14 +493,14 @@ const messages = defineMessages({
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
shown: !!instancePath,
|
||||
shown: !!instanceId,
|
||||
},
|
||||
{
|
||||
id: 'dont-show-on-home',
|
||||
shown: !!instancePath,
|
||||
shown: !!instanceId,
|
||||
action: () => {
|
||||
set_world_display_status(
|
||||
instancePath,
|
||||
instanceId,
|
||||
world.type,
|
||||
getWorldIdentifier(world),
|
||||
'hidden',
|
||||
@@ -473,16 +509,21 @@ const messages = defineMessages({
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'create-shortcut',
|
||||
shown: !!shortcutInstanceId,
|
||||
action: () => createShortcut(),
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
shown: !instancePath,
|
||||
shown: !instanceId,
|
||||
},
|
||||
{
|
||||
id: 'delete',
|
||||
color: 'red',
|
||||
hoverFilled: true,
|
||||
action: () => emit('delete'),
|
||||
shown: !instancePath,
|
||||
shown: !instanceId,
|
||||
disabled: locked || managed,
|
||||
tooltip: locked
|
||||
? formatMessage(messages.worldInUse)
|
||||
@@ -517,6 +558,10 @@ const messages = defineMessages({
|
||||
<UpdatedIcon aria-hidden="true" />
|
||||
{{ formatMessage(commonMessages.refreshButton) }}
|
||||
</template>
|
||||
<template #create-shortcut>
|
||||
<ExternalIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.createShortcut) }}
|
||||
</template>
|
||||
<template #dont-show-on-home>
|
||||
<XIcon aria-hidden="true" />
|
||||
{{ formatMessage(messages.dontShowOnHome) }}
|
||||
|
||||
@@ -12,7 +12,11 @@ import { ref } from 'vue'
|
||||
|
||||
import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { add_server_to_profile, type ServerPackStatus, type ServerWorld } from '@/helpers/worlds.ts'
|
||||
import {
|
||||
add_server_to_instance,
|
||||
type ServerPackStatus,
|
||||
type ServerWorld,
|
||||
} from '@/helpers/worlds.ts'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
@@ -35,8 +39,8 @@ async function addServer(play: boolean) {
|
||||
const serverName = name.value ? name.value : address.value
|
||||
const resourcePackStatus = resourcePack.value
|
||||
const index =
|
||||
(await add_server_to_profile(
|
||||
props.instance.path,
|
||||
(await add_server_to_instance(
|
||||
props.instance.id,
|
||||
serverName,
|
||||
address.value,
|
||||
resourcePackStatus,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
<script setup lang="ts">
|
||||
import { TrashIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import type { World } from '@/helpers/worlds.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<{
|
||||
world: World | null
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
confirm: [world: World]
|
||||
}>()
|
||||
|
||||
const messages = defineMessages({
|
||||
removeServerTitle: {
|
||||
id: 'app.instance.worlds.remove-server-modal.title',
|
||||
defaultMessage: 'Remove server',
|
||||
},
|
||||
deleteWorldTitle: {
|
||||
id: 'app.instance.worlds.delete-world-modal.title',
|
||||
defaultMessage: 'Delete world',
|
||||
},
|
||||
removeServerWarningHeader: {
|
||||
id: 'app.instance.worlds.remove-server-modal.warning-header',
|
||||
defaultMessage: 'Removing {name}',
|
||||
},
|
||||
deleteWorldWarningHeader: {
|
||||
id: 'app.instance.worlds.delete-world-modal.warning-header',
|
||||
defaultMessage: 'Deleting {name}',
|
||||
},
|
||||
removeServerWarningBody: {
|
||||
id: 'app.instance.worlds.remove-server-modal.warning-body',
|
||||
defaultMessage:
|
||||
'This server will be removed from your server list and from the in-game server list. You can add it again later if you know the address.',
|
||||
},
|
||||
deleteWorldWarningBody: {
|
||||
id: 'app.instance.worlds.delete-world-modal.warning-body',
|
||||
defaultMessage:
|
||||
'This world will be permanently deleted from this instance. This action cannot be undone.',
|
||||
},
|
||||
removeServerButton: {
|
||||
id: 'app.instance.worlds.remove-server-modal.remove-button',
|
||||
defaultMessage: 'Remove server',
|
||||
},
|
||||
deleteWorldButton: {
|
||||
id: 'app.instance.worlds.delete-world-modal.delete-button',
|
||||
defaultMessage: 'Delete world',
|
||||
},
|
||||
})
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
|
||||
const isServer = computed(() => props.world?.type === 'server')
|
||||
const isSingleplayer = computed(() => props.world?.type === 'singleplayer')
|
||||
const titleMessage = computed(() =>
|
||||
isServer.value ? messages.removeServerTitle : messages.deleteWorldTitle,
|
||||
)
|
||||
const actionMessage = computed(() =>
|
||||
isServer.value ? messages.removeServerButton : messages.deleteWorldButton,
|
||||
)
|
||||
const warningHeaderMessage = computed(() =>
|
||||
isServer.value ? messages.removeServerWarningHeader : messages.deleteWorldWarningHeader,
|
||||
)
|
||||
const warningBodyMessage = computed(() =>
|
||||
isServer.value ? messages.removeServerWarningBody : messages.deleteWorldWarningBody,
|
||||
)
|
||||
|
||||
function show() {
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
if (!props.world) return
|
||||
emit('confirm', props.world)
|
||||
hide()
|
||||
}
|
||||
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(titleMessage)" fade="danger" max-width="500px">
|
||||
<div class="flex flex-col gap-4">
|
||||
<Admonition
|
||||
type="critical"
|
||||
:header="formatMessage(warningHeaderMessage, { name: world?.name })"
|
||||
>
|
||||
{{ formatMessage(warningBodyMessage) }}
|
||||
</Admonition>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button @click="hide">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="red">
|
||||
<button :disabled="!isServer && !isSingleplayer" @click="confirm">
|
||||
<TrashIcon />
|
||||
{{ formatMessage(actionMessage) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
@@ -15,7 +15,7 @@ import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import {
|
||||
type DisplayStatus,
|
||||
edit_server_in_profile,
|
||||
edit_server_in_instance,
|
||||
type ServerPackStatus,
|
||||
type ServerWorld,
|
||||
set_world_display_status,
|
||||
@@ -46,8 +46,8 @@ const newDisplayStatus = computed(() => (hideFromHome.value ? 'hidden' : 'normal
|
||||
async function saveServer() {
|
||||
const serverName = name.value ? name.value : address.value
|
||||
const resourcePackStatus = resourcePack.value
|
||||
await edit_server_in_profile(
|
||||
props.instance.path,
|
||||
await edit_server_in_instance(
|
||||
props.instance.id,
|
||||
index.value,
|
||||
serverName,
|
||||
address.value,
|
||||
@@ -56,7 +56,7 @@ async function saveServer() {
|
||||
|
||||
if (newDisplayStatus.value !== displayStatus.value) {
|
||||
await set_world_display_status(
|
||||
props.instance.path,
|
||||
props.instance.id,
|
||||
'server',
|
||||
address.value,
|
||||
newDisplayStatus.value,
|
||||
|
||||
@@ -40,14 +40,14 @@ const hideFromHome = ref(false)
|
||||
const newDisplayStatus = computed(() => (hideFromHome.value ? 'hidden' : 'normal'))
|
||||
|
||||
async function saveWorld() {
|
||||
await rename_world(props.instance.path, path.value, name.value).catch(handleError)
|
||||
await rename_world(props.instance.id, path.value, name.value).catch(handleError)
|
||||
|
||||
if (removeIcon.value) {
|
||||
await reset_world_icon(props.instance.path, path.value).catch(handleError)
|
||||
await reset_world_icon(props.instance.id, path.value).catch(handleError)
|
||||
}
|
||||
if (newDisplayStatus.value !== displayStatus.value) {
|
||||
await set_world_display_status(
|
||||
props.instance.path,
|
||||
props.instance.id,
|
||||
'singleplayer',
|
||||
path.value,
|
||||
newDisplayStatus.value,
|
||||
|
||||
@@ -0,0 +1,745 @@
|
||||
import { CheckIcon, CopyIcon, UpdatedIcon } from '@modrinth/assets'
|
||||
import {
|
||||
defineMessages,
|
||||
type PopupNotificationButton,
|
||||
type PopupNotificationProgressItem,
|
||||
type PopupNotificationProgressType,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { Router } from 'vue-router'
|
||||
|
||||
import { install_job_listener } from '@/helpers/events'
|
||||
import {
|
||||
install_job_dismiss,
|
||||
install_job_list,
|
||||
install_job_retry,
|
||||
install_job_support_details,
|
||||
installJobInstanceId,
|
||||
type InstallJobSnapshot,
|
||||
type InstallJobStatus,
|
||||
type InstallPhaseId,
|
||||
type InstallProgress,
|
||||
} from '@/helpers/install'
|
||||
import { get_many as getInstances } from '@/helpers/instance'
|
||||
|
||||
const messages = defineMessages({
|
||||
installs: {
|
||||
id: 'app.action-bar.installs',
|
||||
defaultMessage: 'Installs',
|
||||
},
|
||||
retry: {
|
||||
id: 'app.action-bar.install.retry',
|
||||
defaultMessage: 'Retry',
|
||||
},
|
||||
copyDetails: {
|
||||
id: 'app.action-bar.install.copy-details',
|
||||
defaultMessage: 'Copy details',
|
||||
},
|
||||
copied: {
|
||||
id: 'app.action-bar.install.copied-details',
|
||||
defaultMessage: 'Copied',
|
||||
},
|
||||
dismiss: {
|
||||
id: 'app.action-bar.install.dismiss',
|
||||
defaultMessage: 'Dismiss',
|
||||
},
|
||||
openInstance: {
|
||||
id: 'app.action-bar.install.open-instance',
|
||||
defaultMessage: 'Open instance',
|
||||
},
|
||||
unknownInstance: {
|
||||
id: 'app.action-bar.install.unknown-instance',
|
||||
defaultMessage: 'Unknown instance',
|
||||
},
|
||||
})
|
||||
|
||||
const phaseMessages = defineMessages({
|
||||
preparing_instance: {
|
||||
id: 'app.install.phase.preparing_instance',
|
||||
defaultMessage: 'Queued to install',
|
||||
},
|
||||
resolving_pack: {
|
||||
id: 'app.install.phase.resolving_pack',
|
||||
defaultMessage: 'Resolving content',
|
||||
},
|
||||
downloading_pack_file: {
|
||||
id: 'app.install.phase.downloading_pack_file',
|
||||
defaultMessage: 'Downloading pack file',
|
||||
},
|
||||
reading_pack_manifest: {
|
||||
id: 'app.install.phase.reading_pack_manifest',
|
||||
defaultMessage: 'Reading pack manifest',
|
||||
},
|
||||
downloading_content: {
|
||||
id: 'app.install.phase.downloading_content',
|
||||
defaultMessage: 'Downloading content',
|
||||
},
|
||||
extracting_overrides: {
|
||||
id: 'app.install.phase.extracting_overrides',
|
||||
defaultMessage: 'Extracting overrides',
|
||||
},
|
||||
resolving_minecraft: {
|
||||
id: 'app.install.phase.resolving_minecraft',
|
||||
defaultMessage: 'Resolving Minecraft',
|
||||
},
|
||||
resolving_loader: {
|
||||
id: 'app.install.phase.resolving_loader',
|
||||
defaultMessage: 'Resolving loader',
|
||||
},
|
||||
preparing_java: {
|
||||
id: 'app.install.phase.preparing_java',
|
||||
defaultMessage: 'Preparing Java',
|
||||
},
|
||||
downloading_minecraft: {
|
||||
id: 'app.install.phase.downloading_minecraft',
|
||||
defaultMessage: 'Downloading Minecraft',
|
||||
},
|
||||
running_loader_processors: {
|
||||
id: 'app.install.phase.running_loader_processors',
|
||||
defaultMessage: 'Running loader processors',
|
||||
},
|
||||
finalizing: {
|
||||
id: 'app.install.phase.finalizing',
|
||||
defaultMessage: 'Finalizing',
|
||||
},
|
||||
rolling_back: {
|
||||
id: 'app.install.phase.rolling_back',
|
||||
defaultMessage: 'Rolling back',
|
||||
},
|
||||
})
|
||||
|
||||
const javaStepMessages = defineMessages({
|
||||
resolving: {
|
||||
id: 'app.install.phase.preparing_java.resolving',
|
||||
defaultMessage: 'Preparing Java {version}',
|
||||
},
|
||||
fetching_metadata: {
|
||||
id: 'app.install.phase.preparing_java.fetching-metadata',
|
||||
defaultMessage: 'Fetching Java {version}',
|
||||
},
|
||||
downloading: {
|
||||
id: 'app.install.phase.preparing_java.downloading',
|
||||
defaultMessage: 'Downloading Java {version}',
|
||||
},
|
||||
extracting: {
|
||||
id: 'app.install.phase.preparing_java.extracting',
|
||||
defaultMessage: 'Extracting Java {version}',
|
||||
},
|
||||
validating: {
|
||||
id: 'app.install.phase.preparing_java.validating',
|
||||
defaultMessage: 'Validating Java {version}',
|
||||
},
|
||||
})
|
||||
|
||||
const failureSummaryMessages = defineMessages({
|
||||
canceled: {
|
||||
id: 'app.action-bar.install.summary.canceled',
|
||||
defaultMessage: 'Canceled',
|
||||
},
|
||||
appClosed: {
|
||||
id: 'app.action-bar.install.summary.app-closing',
|
||||
defaultMessage: 'Canceled due to app closing',
|
||||
},
|
||||
downloadFailed: {
|
||||
id: 'app.action-bar.install.summary.download-failed',
|
||||
defaultMessage: "Download couldn't finish",
|
||||
},
|
||||
modrinthUnreachable: {
|
||||
id: 'app.action-bar.install.summary.modrinth-unreachable',
|
||||
defaultMessage: "Couldn't reach Modrinth",
|
||||
},
|
||||
packDownloadFailed: {
|
||||
id: 'app.action-bar.install.summary.pack-download-failed',
|
||||
defaultMessage: "Couldn't download pack",
|
||||
},
|
||||
badModpackFile: {
|
||||
id: 'app.action-bar.install.summary.bad-modpack-file',
|
||||
defaultMessage: "Couldn't read modpack",
|
||||
},
|
||||
invalidModpack: {
|
||||
id: 'app.action-bar.install.summary.invalid-modpack',
|
||||
defaultMessage: 'Modpack data invalid',
|
||||
},
|
||||
contentDownloadFailed: {
|
||||
id: 'app.action-bar.install.summary.content-download-failed',
|
||||
defaultMessage: "Couldn't download files",
|
||||
},
|
||||
corruptDownload: {
|
||||
id: 'app.action-bar.install.summary.corrupt-download',
|
||||
defaultMessage: 'Downloaded file is corrupt',
|
||||
},
|
||||
invalidModpackFiles: {
|
||||
id: 'app.action-bar.install.summary.invalid-modpack-files',
|
||||
defaultMessage: 'Modpack files have invalid metadata',
|
||||
},
|
||||
noWritePermission: {
|
||||
id: 'app.action-bar.install.summary.no-write-permission',
|
||||
defaultMessage: 'No permission to write',
|
||||
},
|
||||
couldNotSaveFiles: {
|
||||
id: 'app.action-bar.install.summary.could-not-save-files',
|
||||
defaultMessage: "Couldn't save files",
|
||||
},
|
||||
invalidFilePath: {
|
||||
id: 'app.action-bar.install.summary.invalid-file-path',
|
||||
defaultMessage: 'File path is invalid',
|
||||
},
|
||||
instanceNotFound: {
|
||||
id: 'app.action-bar.install.summary.instance-not-found',
|
||||
defaultMessage: "Instance couldn't be found",
|
||||
},
|
||||
cleanupIncomplete: {
|
||||
id: 'app.action-bar.install.summary.cleanup-incomplete',
|
||||
defaultMessage: "Cleanup didn't finish",
|
||||
},
|
||||
javaSetupFailed: {
|
||||
id: 'app.action-bar.install.summary.java-setup-failed',
|
||||
defaultMessage: "Java setup couldn't finish",
|
||||
},
|
||||
minecraftSetupFailed: {
|
||||
id: 'app.action-bar.install.summary.minecraft-setup-failed',
|
||||
defaultMessage: 'Minecraft setup failed',
|
||||
},
|
||||
loaderSetupFailed: {
|
||||
id: 'app.action-bar.install.summary.loader-setup-failed',
|
||||
defaultMessage: 'Loader setup failed',
|
||||
},
|
||||
localDataError: {
|
||||
id: 'app.action-bar.install.summary.local-data-error',
|
||||
defaultMessage: "Couldn't update local data",
|
||||
},
|
||||
unexpectedError: {
|
||||
id: 'app.action-bar.install.summary.unexpected-error',
|
||||
defaultMessage: 'Something went wrong',
|
||||
},
|
||||
})
|
||||
|
||||
const visibleJobStatuses = new Set<InstallJobStatus>(['queued', 'running', 'failed', 'interrupted'])
|
||||
const copyDetailsStallMs = 30_000
|
||||
|
||||
interface ProgressSnapshot {
|
||||
signature: string
|
||||
changedAt: number
|
||||
timeout: number | null
|
||||
}
|
||||
|
||||
function getDisplayIconUrl(icon: string | null | undefined): string | null {
|
||||
if (!icon) return null
|
||||
if (/^(https?:|data:|blob:|asset:|tauri:)/.test(icon)) return icon
|
||||
return convertFileSrc(icon)
|
||||
}
|
||||
|
||||
export async function useInstallJobNotifications(opts: {
|
||||
router: Router
|
||||
handleError: (err: unknown) => void
|
||||
onChange: () => void
|
||||
}) {
|
||||
const { formatMessage } = useVIntl()
|
||||
const jobs = ref<InstallJobSnapshot[]>([])
|
||||
const iconUrls = ref<Record<string, string | null>>({})
|
||||
const instanceNames = ref<Record<string, string>>({})
|
||||
const copiedJobIds = ref<Set<string>>(new Set())
|
||||
const jobOrder = new Map<string, number>()
|
||||
let refreshRequest = 0
|
||||
let metadataRequest = 0
|
||||
let nextJobOrder = 0
|
||||
const copiedResetTimeouts = new Map<string, number>()
|
||||
const progressSnapshots = new Map<string, ProgressSnapshot>()
|
||||
|
||||
function getTitle(job: InstallJobSnapshot): string {
|
||||
if (job.display?.title) return job.display.title
|
||||
if (job.details.type === 'instance') return job.details.name
|
||||
if (job.details.type === 'modpack' && job.details.title) return job.details.title
|
||||
const instanceId = installJobInstanceId(job)
|
||||
return (
|
||||
(instanceId ? instanceNames.value[instanceId] : null) ??
|
||||
formatMessage(messages.unknownInstance)
|
||||
)
|
||||
}
|
||||
|
||||
function getText(job: InstallJobSnapshot): string {
|
||||
if (job.status === 'failed' || job.status === 'interrupted') {
|
||||
return getFailureSummary(job)
|
||||
}
|
||||
if (job.phase === 'preparing_java' && job.details.type === 'java') {
|
||||
return formatMessage(javaStepMessages[job.details.step], {
|
||||
version: job.details.major_version,
|
||||
})
|
||||
}
|
||||
return formatMessage(phaseMessages[job.phase])
|
||||
}
|
||||
|
||||
function getFailureSummary(job: InstallJobSnapshot): string {
|
||||
const code = job.error?.code
|
||||
const phase = job.error?.phase ?? job.phase
|
||||
|
||||
if (code === 'app_closed' || (job.status === 'interrupted' && code === 'interrupted')) {
|
||||
return formatMessage(failureSummaryMessages.appClosed)
|
||||
}
|
||||
if (code === 'canceled') {
|
||||
return formatMessage(failureSummaryMessages.canceled)
|
||||
}
|
||||
if (job.rollback_error || code === 'rollback_error') {
|
||||
return formatMessage(failureSummaryMessages.cleanupIncomplete)
|
||||
}
|
||||
if (hasPermissionError(job)) {
|
||||
return formatMessage(failureSummaryMessages.noWritePermission)
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 'network_error':
|
||||
return formatMessage(
|
||||
phase === 'downloading_pack_file'
|
||||
? failureSummaryMessages.packDownloadFailed
|
||||
: failureSummaryMessages.downloadFailed,
|
||||
)
|
||||
case 'api_error':
|
||||
return formatMessage(failureSummaryMessages.modrinthUnreachable)
|
||||
case 'pack_error':
|
||||
return formatMessage(
|
||||
phase === 'downloading_pack_file'
|
||||
? failureSummaryMessages.packDownloadFailed
|
||||
: failureSummaryMessages.invalidModpack,
|
||||
)
|
||||
case 'archive_error':
|
||||
return formatMessage(failureSummaryMessages.badModpackFile)
|
||||
case 'parse_error':
|
||||
return formatMessage(failureSummaryMessages.invalidModpack)
|
||||
case 'content_error':
|
||||
return formatMessage(failureSummaryMessages.invalidModpackFiles)
|
||||
case 'hash_error':
|
||||
return formatMessage(failureSummaryMessages.corruptDownload)
|
||||
case 'filesystem_error':
|
||||
return formatMessage(failureSummaryMessages.couldNotSaveFiles)
|
||||
case 'path_error':
|
||||
return formatMessage(failureSummaryMessages.invalidFilePath)
|
||||
case 'instance_error':
|
||||
return formatMessage(failureSummaryMessages.instanceNotFound)
|
||||
case 'java_error':
|
||||
return formatMessage(failureSummaryMessages.javaSetupFailed)
|
||||
case 'loader_error':
|
||||
case 'processor_error':
|
||||
return formatMessage(failureSummaryMessages.loaderSetupFailed)
|
||||
case 'database_error':
|
||||
return formatMessage(failureSummaryMessages.localDataError)
|
||||
case 'launcher_error':
|
||||
case 'metadata_error':
|
||||
return getFailureSummaryForPhase(phase)
|
||||
default:
|
||||
return getFailureSummaryForPhase(phase)
|
||||
}
|
||||
}
|
||||
|
||||
function getFailureSummaryForPhase(phase: InstallPhaseId): string {
|
||||
switch (phase) {
|
||||
case 'downloading_pack_file':
|
||||
return formatMessage(failureSummaryMessages.packDownloadFailed)
|
||||
case 'resolving_pack':
|
||||
case 'reading_pack_manifest':
|
||||
return formatMessage(failureSummaryMessages.invalidModpack)
|
||||
case 'downloading_content':
|
||||
return formatMessage(failureSummaryMessages.contentDownloadFailed)
|
||||
case 'extracting_overrides':
|
||||
return formatMessage(failureSummaryMessages.couldNotSaveFiles)
|
||||
case 'resolving_minecraft':
|
||||
case 'downloading_minecraft':
|
||||
return formatMessage(failureSummaryMessages.minecraftSetupFailed)
|
||||
case 'resolving_loader':
|
||||
case 'running_loader_processors':
|
||||
return formatMessage(failureSummaryMessages.loaderSetupFailed)
|
||||
case 'preparing_java':
|
||||
return formatMessage(failureSummaryMessages.javaSetupFailed)
|
||||
case 'preparing_instance':
|
||||
return formatMessage(failureSummaryMessages.instanceNotFound)
|
||||
case 'rolling_back':
|
||||
return formatMessage(failureSummaryMessages.cleanupIncomplete)
|
||||
default:
|
||||
return formatMessage(failureSummaryMessages.unexpectedError)
|
||||
}
|
||||
}
|
||||
|
||||
function hasPermissionError(job: InstallJobSnapshot): boolean {
|
||||
const message = job.error?.message.toLowerCase() ?? ''
|
||||
return (
|
||||
message.includes('permission denied') ||
|
||||
message.includes('access is denied') ||
|
||||
message.includes('operation not permitted')
|
||||
)
|
||||
}
|
||||
|
||||
function getProgressType(job: InstallJobSnapshot): PopupNotificationProgressType | undefined {
|
||||
if (!getEffectiveProgress(job)) return undefined
|
||||
if (
|
||||
job.phase === 'preparing_java' &&
|
||||
job.details.type === 'java' &&
|
||||
job.details.step === 'downloading'
|
||||
) {
|
||||
return 'bytes'
|
||||
}
|
||||
if (job.phase === 'downloading_content') {
|
||||
return job.progress?.secondary ? 'bytes' : 'count'
|
||||
}
|
||||
if (
|
||||
job.phase === 'downloading_pack_file' ||
|
||||
job.phase === 'extracting_overrides' ||
|
||||
job.phase === 'downloading_minecraft'
|
||||
) {
|
||||
return 'bytes'
|
||||
}
|
||||
if (job.phase === 'running_loader_processors') {
|
||||
return 'count'
|
||||
}
|
||||
return 'percentage'
|
||||
}
|
||||
|
||||
function getEffectiveProgress(job: InstallJobSnapshot): InstallProgress | null | undefined {
|
||||
if (job.phase === 'downloading_content' && job.progress?.secondary) {
|
||||
return job.progress.secondary
|
||||
}
|
||||
|
||||
return job.progress
|
||||
}
|
||||
|
||||
function getProgress(job: InstallJobSnapshot): number {
|
||||
if (job.status === 'succeeded') return 1
|
||||
if (job.status === 'failed' || job.status === 'interrupted') return 0
|
||||
const progress = getEffectiveProgress(job)
|
||||
if (!progress || progress.total <= 0) return 0
|
||||
return Math.max(0, Math.min(1, progress.current / progress.total))
|
||||
}
|
||||
|
||||
function isTerminalJob(job: InstallJobSnapshot): boolean {
|
||||
return job.status === 'failed' || job.status === 'interrupted'
|
||||
}
|
||||
|
||||
function canShowStalledProgressDetails(job: InstallJobSnapshot): boolean {
|
||||
return (
|
||||
job.status === 'running' &&
|
||||
job.phase !== 'preparing_instance' &&
|
||||
job.phase !== 'finalizing' &&
|
||||
job.phase !== 'rolling_back'
|
||||
)
|
||||
}
|
||||
|
||||
function getJobSortRank(job: InstallJobSnapshot): number {
|
||||
if (isTerminalJob(job)) return 0
|
||||
if (job.status === 'queued' || job.phase === 'preparing_instance') return 2
|
||||
return 1
|
||||
}
|
||||
|
||||
function progressSignature(job: InstallJobSnapshot): string {
|
||||
const progress = job.progress
|
||||
const secondary = progress?.secondary
|
||||
return [
|
||||
job.status,
|
||||
job.phase,
|
||||
JSON.stringify(job.details),
|
||||
progress?.current ?? '',
|
||||
progress?.total ?? '',
|
||||
secondary?.current ?? '',
|
||||
secondary?.total ?? '',
|
||||
].join(':')
|
||||
}
|
||||
|
||||
function clearCopied(jobId: string) {
|
||||
if (!copiedJobIds.value.has(jobId)) {
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = copiedResetTimeouts.get(jobId)
|
||||
if (timeout != null) {
|
||||
window.clearTimeout(timeout)
|
||||
copiedResetTimeouts.delete(jobId)
|
||||
}
|
||||
|
||||
const nextCopiedJobIds = new Set(copiedJobIds.value)
|
||||
nextCopiedJobIds.delete(jobId)
|
||||
copiedJobIds.value = nextCopiedJobIds
|
||||
}
|
||||
|
||||
function clearProgressSnapshot(jobId: string) {
|
||||
const snapshot = progressSnapshots.get(jobId)
|
||||
if (snapshot?.timeout != null) {
|
||||
window.clearTimeout(snapshot.timeout)
|
||||
}
|
||||
progressSnapshots.delete(jobId)
|
||||
}
|
||||
|
||||
function scheduleStaleProgressRefresh(jobId: string) {
|
||||
const snapshot = progressSnapshots.get(jobId)
|
||||
if (!snapshot) {
|
||||
return
|
||||
}
|
||||
|
||||
snapshot.timeout = window.setTimeout(() => {
|
||||
const snapshot = progressSnapshots.get(jobId)
|
||||
if (!snapshot) {
|
||||
return
|
||||
}
|
||||
|
||||
snapshot.timeout = null
|
||||
opts.onChange()
|
||||
}, copyDetailsStallMs)
|
||||
}
|
||||
|
||||
function syncProgressSnapshots(nextJobs: InstallJobSnapshot[]) {
|
||||
const trackedJobIds = new Set<string>()
|
||||
const now = Date.now()
|
||||
|
||||
for (const job of nextJobs) {
|
||||
if (!canShowStalledProgressDetails(job)) {
|
||||
continue
|
||||
}
|
||||
|
||||
trackedJobIds.add(job.job_id)
|
||||
const signature = progressSignature(job)
|
||||
const snapshot = progressSnapshots.get(job.job_id)
|
||||
if (snapshot?.signature === signature) {
|
||||
continue
|
||||
}
|
||||
|
||||
clearProgressSnapshot(job.job_id)
|
||||
clearCopied(job.job_id)
|
||||
progressSnapshots.set(job.job_id, {
|
||||
signature,
|
||||
changedAt: now,
|
||||
timeout: null,
|
||||
})
|
||||
scheduleStaleProgressRefresh(job.job_id)
|
||||
}
|
||||
|
||||
for (const jobId of progressSnapshots.keys()) {
|
||||
if (!trackedJobIds.has(jobId)) {
|
||||
clearProgressSnapshot(jobId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hasStalledProgress(job: InstallJobSnapshot): boolean {
|
||||
const snapshot = progressSnapshots.get(job.job_id)
|
||||
return !!snapshot && Date.now() - snapshot.changedAt >= copyDetailsStallMs
|
||||
}
|
||||
|
||||
function shouldShowCopyDetails(job: InstallJobSnapshot): boolean {
|
||||
return isTerminalJob(job) || (canShowStalledProgressDetails(job) && hasStalledProgress(job))
|
||||
}
|
||||
|
||||
function isCopied(job: InstallJobSnapshot): boolean {
|
||||
return copiedJobIds.value.has(job.job_id)
|
||||
}
|
||||
|
||||
function setCopied(job: InstallJobSnapshot) {
|
||||
copiedJobIds.value = new Set([...copiedJobIds.value, job.job_id])
|
||||
const existingTimeout = copiedResetTimeouts.get(job.job_id)
|
||||
if (existingTimeout != null) {
|
||||
window.clearTimeout(existingTimeout)
|
||||
}
|
||||
copiedResetTimeouts.set(
|
||||
job.job_id,
|
||||
window.setTimeout(() => {
|
||||
copiedResetTimeouts.delete(job.job_id)
|
||||
if (!copiedJobIds.value.has(job.job_id)) {
|
||||
return
|
||||
}
|
||||
const nextCopiedJobIds = new Set(copiedJobIds.value)
|
||||
nextCopiedJobIds.delete(job.job_id)
|
||||
copiedJobIds.value = nextCopiedJobIds
|
||||
opts.onChange()
|
||||
}, 1_000),
|
||||
)
|
||||
opts.onChange()
|
||||
}
|
||||
|
||||
async function copyJobDetails(job: InstallJobSnapshot) {
|
||||
const details = await install_job_support_details(job.job_id).catch((error) => {
|
||||
opts.handleError(error)
|
||||
return null
|
||||
})
|
||||
if (!details) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await navigator.clipboard.writeText(details)
|
||||
setCopied(job)
|
||||
} catch (error) {
|
||||
opts.handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
function getButtons(job: InstallJobSnapshot): PopupNotificationButton[] {
|
||||
const buttons: PopupNotificationButton[] = []
|
||||
|
||||
if (isTerminalJob(job)) {
|
||||
buttons.push({
|
||||
label: formatMessage(messages.retry),
|
||||
icon: UpdatedIcon,
|
||||
color: 'brand',
|
||||
keepOpen: true,
|
||||
action: async () => {
|
||||
await install_job_retry(job.job_id).catch(opts.handleError)
|
||||
await refresh()
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (shouldShowCopyDetails(job)) {
|
||||
const copied = isCopied(job)
|
||||
buttons.push({
|
||||
label: formatMessage(copied ? messages.copied : messages.copyDetails),
|
||||
icon: copied ? CheckIcon : CopyIcon,
|
||||
color: 'standard',
|
||||
keepOpen: true,
|
||||
action: async () => {
|
||||
await copyJobDetails(job)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return buttons
|
||||
}
|
||||
|
||||
function setJobs(nextJobs: InstallJobSnapshot[]) {
|
||||
for (const job of nextJobs) {
|
||||
if (!jobOrder.has(job.job_id)) {
|
||||
jobOrder.set(job.job_id, nextJobOrder++)
|
||||
}
|
||||
}
|
||||
|
||||
const visibleJobs = nextJobs.filter((job) => visibleJobStatuses.has(job.status))
|
||||
syncProgressSnapshots(visibleJobs)
|
||||
|
||||
jobs.value = visibleJobs.sort(
|
||||
(a, b) =>
|
||||
getJobSortRank(a) - getJobSortRank(b) ||
|
||||
a.created.localeCompare(b.created) ||
|
||||
(jobOrder.get(a.job_id) ?? 0) - (jobOrder.get(b.job_id) ?? 0),
|
||||
)
|
||||
}
|
||||
|
||||
const progressItems = computed<PopupNotificationProgressItem[]>(() =>
|
||||
jobs.value.map((job) => {
|
||||
const progress = getEffectiveProgress(job)
|
||||
|
||||
return {
|
||||
id: job.job_id,
|
||||
title: getTitle(job),
|
||||
text: getText(job),
|
||||
iconUrl: iconUrls.value[job.job_id] ?? null,
|
||||
progress: getProgress(job),
|
||||
waiting: !job.progress && ['queued', 'running'].includes(job.status),
|
||||
showProgress: !isTerminalJob(job),
|
||||
wrapText: isTerminalJob(job),
|
||||
progressType: isTerminalJob(job) ? undefined : getProgressType(job),
|
||||
progressCurrent: isTerminalJob(job) ? undefined : progress?.current,
|
||||
progressTotal: isTerminalJob(job) ? undefined : progress?.total,
|
||||
buttons: getButtons(job),
|
||||
onDismiss: isTerminalJob(job)
|
||||
? async () => {
|
||||
await install_job_dismiss(job.job_id).catch(opts.handleError)
|
||||
await refresh()
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const buttons = computed<PopupNotificationButton[] | undefined>(() => undefined)
|
||||
|
||||
async function refreshMetadata(notify = true) {
|
||||
const request = ++metadataRequest
|
||||
const sourceJobs = jobs.value
|
||||
const instanceIds = Array.from(
|
||||
new Set(
|
||||
sourceJobs
|
||||
.map((job) => installJobInstanceId(job))
|
||||
.filter((instanceId): instanceId is string => !!instanceId),
|
||||
),
|
||||
)
|
||||
const instances = instanceIds.length
|
||||
? await getInstances(instanceIds).catch((error) => {
|
||||
opts.handleError(error)
|
||||
return []
|
||||
})
|
||||
: []
|
||||
|
||||
if (request !== metadataRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
const instanceIconUrls = new Map(
|
||||
instances.map((instance) => [instance.id, getDisplayIconUrl(instance.icon_path)]),
|
||||
)
|
||||
instanceNames.value = Object.fromEntries(
|
||||
instances.map((instance) => [instance.id, instance.name]),
|
||||
)
|
||||
iconUrls.value = Object.fromEntries(
|
||||
sourceJobs.map((job) => [
|
||||
job.job_id,
|
||||
getDisplayIconUrl(job.display?.icon) ??
|
||||
instanceIconUrls.get(installJobInstanceId(job) ?? '') ??
|
||||
null,
|
||||
]),
|
||||
)
|
||||
|
||||
if (notify) {
|
||||
opts.onChange()
|
||||
}
|
||||
}
|
||||
|
||||
async function refresh(notify = true) {
|
||||
const request = ++refreshRequest
|
||||
const nextJobs = await install_job_list(false).catch((error) => {
|
||||
opts.handleError(error)
|
||||
return []
|
||||
})
|
||||
|
||||
if (request !== refreshRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
setJobs(nextJobs)
|
||||
await refreshMetadata(false)
|
||||
|
||||
if (request !== refreshRequest) {
|
||||
return
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
opts.onChange()
|
||||
}
|
||||
}
|
||||
|
||||
function applyJobUpdate(job: InstallJobSnapshot) {
|
||||
refreshRequest += 1
|
||||
const existingJob = jobs.value.find((item) => item.job_id === job.job_id)
|
||||
if (existingJob && existingJob.modified.localeCompare(job.modified) > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
setJobs([...jobs.value.filter((item) => item.job_id !== job.job_id), job])
|
||||
opts.onChange()
|
||||
void refreshMetadata()
|
||||
}
|
||||
|
||||
await refresh(false)
|
||||
const unlisten = await install_job_listener((job: InstallJobSnapshot) => applyJobUpdate(job))
|
||||
|
||||
return {
|
||||
active: computed(() => jobs.value.length > 0),
|
||||
title: computed(() => formatMessage(messages.installs)),
|
||||
progressItems,
|
||||
buttons,
|
||||
refresh,
|
||||
dispose: () => {
|
||||
for (const timeout of copiedResetTimeouts.values()) {
|
||||
window.clearTimeout(timeout)
|
||||
}
|
||||
for (const jobId of progressSnapshots.keys()) {
|
||||
clearProgressSnapshot(jobId)
|
||||
}
|
||||
unlisten()
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,24 @@ import type { Labrinth } from '@modrinth/api-client'
|
||||
import { CheckIcon, PlayIcon, PlusIcon, StopCircleIcon } from '@modrinth/assets'
|
||||
import type { CardAction } from '@modrinth/ui'
|
||||
import { commonMessages, defineMessages, useDebugLogger, useVIntl } from '@modrinth/ui'
|
||||
import { useQueryClient } from '@tanstack/vue-query'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import type { ComputedRef, Ref } from 'vue'
|
||||
import { onUnmounted, ref, shallowRef } from 'vue'
|
||||
import type { Router } from 'vue-router'
|
||||
|
||||
import {
|
||||
fetchCachedServerStatus,
|
||||
getFreshCachedServerStatus,
|
||||
} from '@/composables/instances/use-server-status-query'
|
||||
import { process_listener } from '@/helpers/events'
|
||||
import { get_by_profile_path } from '@/helpers/process'
|
||||
import { kill, list as listInstances } from '@/helpers/profile.js'
|
||||
import { kill, list as listInstances } from '@/helpers/instance'
|
||||
import { get_by_instance_id } from '@/helpers/process'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { add_server_to_profile, getServerLatency } from '@/helpers/worlds'
|
||||
import { getServerAddress } from '@/store/install.js'
|
||||
import { add_server_to_instance, getServerAddress } from '@/helpers/worlds'
|
||||
|
||||
interface BrowseServerInstance {
|
||||
id: string
|
||||
name: string
|
||||
path: string
|
||||
}
|
||||
@@ -65,14 +70,13 @@ const messages = defineMessages({
|
||||
|
||||
export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
const { formatMessage } = useVIntl()
|
||||
const queryClient = useQueryClient()
|
||||
const debugLog = useDebugLogger('BrowseServer')
|
||||
const serverPings = shallowRef<Record<string, number | undefined>>({})
|
||||
const serverPingCache = new Map<string, number | undefined>()
|
||||
const pendingServerPings = new Map<string, Promise<number | undefined>>()
|
||||
const runningServerProjects = ref<Record<string, string>>({})
|
||||
const lastServerHits = shallowRef<Labrinth.Search.v3.ResultSearchProject[]>([])
|
||||
const contextMenuRef = ref<ContextMenuHandle | null>(null)
|
||||
let serverPingCacheActive = true
|
||||
let serverPingsActive = true
|
||||
let unlistenProcesses: (() => void) | null = null
|
||||
|
||||
async function checkServerRunningStates(hits: Labrinth.Search.v3.ResultSearchProject[]) {
|
||||
@@ -83,13 +87,11 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
})
|
||||
const newRunning: Record<string, string> = {}
|
||||
for (const hit of hits) {
|
||||
const inst = packs.find(
|
||||
(pack: GameInstance) => pack.linked_data?.project_id === hit.project_id,
|
||||
)
|
||||
const inst = packs.find((pack: GameInstance) => pack.link?.project_id === hit.project_id)
|
||||
if (inst) {
|
||||
const processes = await get_by_profile_path(inst.path).catch(() => [])
|
||||
const processes = await get_by_instance_id(inst.id).catch(() => [])
|
||||
if (Array.isArray(processes) && processes.length > 0) {
|
||||
newRunning[hit.project_id] = inst.path
|
||||
newRunning[hit.project_id] = inst.id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,9 +101,9 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
|
||||
async function handleStopServerProject(projectId: string) {
|
||||
debugLog('handleStopServerProject', projectId)
|
||||
const instancePath = runningServerProjects.value[projectId]
|
||||
if (!instancePath) return
|
||||
await kill(instancePath).catch(() => {})
|
||||
const instanceId = runningServerProjects.value[projectId]
|
||||
if (!instanceId) return
|
||||
await kill(instanceId).catch(() => {})
|
||||
const { [projectId]: _, ...rest } = runningServerProjects.value
|
||||
runningServerProjects.value = rest
|
||||
}
|
||||
@@ -118,9 +120,10 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
if (!address) return
|
||||
|
||||
if (options.instance.value) {
|
||||
const instanceId = options.instance.value.id
|
||||
try {
|
||||
await add_server_to_profile(
|
||||
options.instance.value.path,
|
||||
await add_server_to_instance(
|
||||
instanceId,
|
||||
project.name,
|
||||
address,
|
||||
'prompt',
|
||||
@@ -128,6 +131,7 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
project.minecraft_java_server?.content?.kind,
|
||||
)
|
||||
options.newlyInstalled.value.push(project.project_id)
|
||||
await queryClient.invalidateQueries({ queryKey: ['worlds', instanceId] })
|
||||
} catch (error) {
|
||||
options.handleError(error)
|
||||
}
|
||||
@@ -145,37 +149,26 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
})
|
||||
const nextPings = { ...serverPings.value }
|
||||
for (const { hit, address } of pingsToFetch) {
|
||||
if (serverPingCache.has(address)) {
|
||||
nextPings[hit.project_id] = serverPingCache.get(address)
|
||||
const cachedStatus = getFreshCachedServerStatus(queryClient, address)
|
||||
if (cachedStatus) {
|
||||
nextPings[hit.project_id] = cachedStatus.ping
|
||||
}
|
||||
}
|
||||
serverPings.value = nextPings
|
||||
|
||||
await Promise.all(
|
||||
pingsToFetch.map(async ({ hit, address }) => {
|
||||
if (serverPingCache.has(address)) return
|
||||
if (getFreshCachedServerStatus(queryClient, address)) return
|
||||
|
||||
let pending = pendingServerPings.get(address)
|
||||
if (!pending) {
|
||||
pending = getServerLatency(address)
|
||||
.then((latency) => {
|
||||
if (serverPingCacheActive) serverPingCache.set(address, latency)
|
||||
return latency
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`Failed to ping server ${address}:`, error)
|
||||
if (serverPingCacheActive) serverPingCache.set(address, undefined)
|
||||
return undefined
|
||||
})
|
||||
.finally(() => {
|
||||
pendingServerPings.delete(address)
|
||||
})
|
||||
pendingServerPings.set(address, pending)
|
||||
try {
|
||||
const status = await fetchCachedServerStatus(queryClient, address)
|
||||
if (!serverPingsActive) return
|
||||
serverPings.value = { ...serverPings.value, [hit.project_id]: status.ping }
|
||||
} catch (error) {
|
||||
console.error(`Failed to ping server ${address}:`, error)
|
||||
if (!serverPingsActive) return
|
||||
serverPings.value = { ...serverPings.value, [hit.project_id]: undefined }
|
||||
}
|
||||
|
||||
const latency = await pending
|
||||
if (!serverPingCacheActive) return
|
||||
serverPings.value = { ...serverPings.value, [hit.project_id]: latency }
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -289,11 +282,11 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
process_listener((event: { event: string; profile_path_id: string }) => {
|
||||
process_listener((event: { event: string; instance_id: string }) => {
|
||||
debugLog('process event', event)
|
||||
if (event.event === 'finished') {
|
||||
const projectId = Object.entries(runningServerProjects.value).find(
|
||||
([, path]) => path === event.profile_path_id,
|
||||
([, path]) => path === event.instance_id,
|
||||
)?.[0]
|
||||
if (projectId) {
|
||||
const { [projectId]: _, ...rest } = runningServerProjects.value
|
||||
@@ -307,10 +300,8 @@ export function useAppServerBrowse(options: UseAppServerBrowseOptions) {
|
||||
.catch(options.handleError)
|
||||
|
||||
onUnmounted(() => {
|
||||
serverPingCacheActive = false
|
||||
serverPingsActive = false
|
||||
unlistenProcesses?.()
|
||||
serverPingCache.clear()
|
||||
pendingServerPings.clear()
|
||||
})
|
||||
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import type { QueryClient } from '@tanstack/vue-query'
|
||||
|
||||
import {
|
||||
get_server_status,
|
||||
normalizeServerAddress,
|
||||
type ProtocolVersion,
|
||||
type ServerStatus,
|
||||
} from '@/helpers/worlds'
|
||||
|
||||
export const SERVER_STATUS_CACHE_MS = 10 * 60 * 1000
|
||||
|
||||
function getProtocolVersionKey(protocolVersion: ProtocolVersion | null) {
|
||||
if (!protocolVersion) return 'default'
|
||||
return `${protocolVersion.version}:${protocolVersion.legacy ? 'legacy' : 'modern'}`
|
||||
}
|
||||
|
||||
export function getServerStatusQueryKey(
|
||||
address: string,
|
||||
protocolVersion: ProtocolVersion | null = null,
|
||||
) {
|
||||
return [
|
||||
'minecraft-server-status',
|
||||
normalizeServerAddress(address) || address.trim().toLowerCase(),
|
||||
getProtocolVersionKey(protocolVersion),
|
||||
] as const
|
||||
}
|
||||
|
||||
export function getFreshCachedServerStatus(
|
||||
queryClient: QueryClient,
|
||||
address: string,
|
||||
protocolVersion: ProtocolVersion | null = null,
|
||||
) {
|
||||
const queryKey = getServerStatusQueryKey(address, protocolVersion)
|
||||
const updatedAt = queryClient.getQueryState(queryKey)?.dataUpdatedAt ?? 0
|
||||
if (!updatedAt || Date.now() - updatedAt >= SERVER_STATUS_CACHE_MS) return undefined
|
||||
return queryClient.getQueryData<ServerStatus>(queryKey)
|
||||
}
|
||||
|
||||
export async function fetchCachedServerStatus(
|
||||
queryClient: QueryClient,
|
||||
address: string,
|
||||
protocolVersion: ProtocolVersion | null = null,
|
||||
) {
|
||||
return await queryClient.fetchQuery({
|
||||
queryKey: getServerStatusQueryKey(address, protocolVersion),
|
||||
queryFn: () => get_server_status(address, protocolVersion),
|
||||
staleTime: SERVER_STATUS_CACHE_MS,
|
||||
gcTime: SERVER_STATUS_CACHE_MS,
|
||||
})
|
||||
}
|
||||
@@ -22,8 +22,8 @@ interface InstanceConsoleEntry {
|
||||
|
||||
const instances = new Map<string, InstanceConsoleEntry>()
|
||||
|
||||
function getOrCreate(profilePathId: string): InstanceConsoleEntry {
|
||||
let entry = instances.get(profilePathId)
|
||||
function getOrCreate(instanceId: string): InstanceConsoleEntry {
|
||||
let entry = instances.get(instanceId)
|
||||
if (entry) return entry
|
||||
|
||||
entry = {
|
||||
@@ -32,25 +32,25 @@ function getOrCreate(profilePathId: string): InstanceConsoleEntry {
|
||||
historicalCache: new Map(),
|
||||
logList: null,
|
||||
}
|
||||
instances.set(profilePathId, entry)
|
||||
instances.set(instanceId, entry)
|
||||
return entry
|
||||
}
|
||||
|
||||
async function hydrate(profilePathId: string): Promise<void> {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
async function hydrate(instanceId: string): Promise<void> {
|
||||
const entry = getOrCreate(instanceId)
|
||||
if (entry.liveConsole.output.value.length > 0) return
|
||||
|
||||
const buffer = await get_live_log_buffer(profilePathId)
|
||||
const buffer = await get_live_log_buffer(instanceId)
|
||||
if (buffer) {
|
||||
entry.liveConsole.addLegacyLog(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
async function getHistoricalLogs(profilePathId: string, instancePath: string): Promise<LogEntry[]> {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
async function getHistoricalLogs(instanceId: string): Promise<LogEntry[]> {
|
||||
const entry = getOrCreate(instanceId)
|
||||
if (entry.logList) return entry.logList
|
||||
|
||||
const logs: LogEntry[] = await get_logs(instancePath, true)
|
||||
const logs: LogEntry[] = await get_logs(instanceId, true)
|
||||
entry.logList = logs
|
||||
|
||||
for (const log of logs) {
|
||||
@@ -62,38 +62,38 @@ async function getHistoricalLogs(profilePathId: string, instancePath: string): P
|
||||
return logs
|
||||
}
|
||||
|
||||
function getHistoricalContent(profilePathId: string, filename: string): string | undefined {
|
||||
return instances.get(profilePathId)?.historicalCache.get(filename)
|
||||
function getHistoricalContent(instanceId: string, filename: string): string | undefined {
|
||||
return instances.get(instanceId)?.historicalCache.get(filename)
|
||||
}
|
||||
|
||||
function invalidate(profilePathId: string): void {
|
||||
const entry = instances.get(profilePathId)
|
||||
function invalidate(instanceId: string): void {
|
||||
const entry = instances.get(instanceId)
|
||||
if (!entry) return
|
||||
entry.historicalCache.clear()
|
||||
entry.logList = null
|
||||
}
|
||||
|
||||
async function clearLive(profilePathId: string): Promise<void> {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
async function clearLive(instanceId: string): Promise<void> {
|
||||
const entry = getOrCreate(instanceId)
|
||||
entry.liveConsole.clear()
|
||||
await clear_log_buffer(profilePathId).catch(() => {})
|
||||
await clear_log_buffer(instanceId).catch(() => {})
|
||||
}
|
||||
|
||||
async function destroy(profilePathId: string): Promise<void> {
|
||||
instances.delete(profilePathId)
|
||||
await clear_log_buffer(profilePathId).catch(() => {})
|
||||
async function destroy(instanceId: string): Promise<void> {
|
||||
instances.delete(instanceId)
|
||||
await clear_log_buffer(instanceId).catch(() => {})
|
||||
}
|
||||
|
||||
export function useInstanceConsole(profilePathId: string) {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
export function useInstanceConsole(instanceId: string) {
|
||||
const entry = getOrCreate(instanceId)
|
||||
return {
|
||||
liveConsole: entry.liveConsole,
|
||||
historicalConsole: entry.historicalConsole,
|
||||
hydrate: () => hydrate(profilePathId),
|
||||
getHistoricalLogs: (instancePath: string) => getHistoricalLogs(profilePathId, instancePath),
|
||||
getHistoricalContent: (filename: string) => getHistoricalContent(profilePathId, filename),
|
||||
invalidate: () => invalidate(profilePathId),
|
||||
clearLive: () => clearLive(profilePathId),
|
||||
destroy: () => destroy(profilePathId),
|
||||
hydrate: () => hydrate(instanceId),
|
||||
getHistoricalLogs: () => getHistoricalLogs(instanceId),
|
||||
getHistoricalContent: (filename: string) => getHistoricalContent(instanceId, filename),
|
||||
invalidate: () => invalidate(instanceId),
|
||||
clearLive: () => clearLive(instanceId),
|
||||
destroy: () => destroy(instanceId),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { listen } from '@tauri-apps/api/event'
|
||||
|
||||
export async function init_ads_window(overrideShown = false) {
|
||||
return await invoke('plugin:ads|init_ads_window', {
|
||||
@@ -15,6 +16,22 @@ export async function hide_ads_window(reset) {
|
||||
return await invoke('plugin:ads|hide_ads_window', { reset })
|
||||
}
|
||||
|
||||
export async function get_ads_consent_required() {
|
||||
return await invoke('plugin:ads|get_ads_consent_required')
|
||||
}
|
||||
|
||||
export async function perform_ads_consent_action(action) {
|
||||
return await invoke('plugin:ads|perform_ads_consent_action', { action })
|
||||
}
|
||||
|
||||
export async function open_ads_consent_preferences() {
|
||||
return await invoke('plugin:ads|open_ads_consent_preferences')
|
||||
}
|
||||
|
||||
export async function ads_consent_listener(callback) {
|
||||
return await listen('ads-consent-required', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
export async function record_ads_click() {
|
||||
return await invoke('plugin:ads|record_ads_click')
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
@@ -31,8 +31,8 @@ import { listen } from '@tauri-apps/api/event'
|
||||
pack_name: name of the pack
|
||||
pack_id, optional, the id of the modpack
|
||||
pack_version, optional, the version of the modpack
|
||||
profile_name: name of the profile
|
||||
profile_uuid: unique identification of the profile
|
||||
instance_name: name of the instance
|
||||
instance_id: unique identification of the instance
|
||||
|
||||
}
|
||||
loader_uuid: unique identification of the loading bar
|
||||
@@ -57,18 +57,32 @@ export async function process_listener(callback) {
|
||||
return await listen('process', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'profile' event
|
||||
/// Payload for the 'instance' event
|
||||
/*
|
||||
ProfilePayload {
|
||||
uuid: unique identification of the process in the state (currently identified by path, but that will change)
|
||||
name: name of the profile
|
||||
profile_path: relative path toprofile_listener profile (used for path identification)
|
||||
path: path to profile (used for opening the profile in the OS file explorer)
|
||||
InstancePayload {
|
||||
instance_id: unique identification of the instance
|
||||
event: event type ("Created", "Added", "Edited", "Removed")
|
||||
}
|
||||
*/
|
||||
export async function profile_listener(callback) {
|
||||
return await listen('profile', (event) => callback(event.payload))
|
||||
export async function instance_listener(callback) {
|
||||
return await listen('instance', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'instance_bulk_update_progress' event
|
||||
/*
|
||||
InstanceBulkUpdateProgress {
|
||||
instanceId: string
|
||||
stage: "resolving_versions" | "downloading" | "finishing"
|
||||
current: number
|
||||
total: number
|
||||
}
|
||||
*/
|
||||
export async function instance_bulk_update_progress_listener(callback) {
|
||||
return await listen('instance_bulk_update_progress', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
export async function install_job_listener(callback) {
|
||||
return await listen('install_job', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'command' event
|
||||
@@ -105,7 +119,7 @@ export async function notification_listener(callback) {
|
||||
/// Payload for the 'log' event
|
||||
/*
|
||||
LogPayload {
|
||||
profile_path_id: string,
|
||||
instance_id: string,
|
||||
type: "log4j" | "legacy",
|
||||
// log4j fields (when type === "log4j"):
|
||||
timestamp_millis?: number,
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { ModrinthCredentials } from '@/helpers/mr_auth'
|
||||
|
||||
export type UserStatus = {
|
||||
user_id: string
|
||||
profile_name: string | null
|
||||
instance_name: string | null
|
||||
last_update: string
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { create } from './profile'
|
||||
import { install_import_instance } from './install'
|
||||
|
||||
/*
|
||||
API for importing instances from other launchers
|
||||
@@ -32,19 +32,8 @@ export async function get_importable_instances(launcherType, basePath) {
|
||||
}
|
||||
|
||||
/// Import an instance from a launcher type and base path
|
||||
/// eg: import_instance("profile-name-to-go-to", "MultiMC", "C:/MultiMC", "Instance 1")
|
||||
export async function import_instance(launcherType, basePath, instanceFolder) {
|
||||
// create a basic, empty instance (most properties will be filled in by the import process)
|
||||
// We do NOT watch the fs for changes to avoid duplicate events during installation
|
||||
// fs watching will be enabled once the instance is imported
|
||||
const profilePath = await create(instanceFolder, '1.19.4', 'vanilla', 'latest', null, true)
|
||||
|
||||
return await invoke('plugin:import|import_instance', {
|
||||
profilePath,
|
||||
launcherType,
|
||||
basePath,
|
||||
instanceFolder,
|
||||
})
|
||||
return await install_import_instance(launcherType, basePath, instanceFolder)
|
||||
}
|
||||
|
||||
/// Checks if this instance is valid for importing, given a certain launcher type
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { install_job_listener } from './events'
|
||||
import type { InstanceLink, InstanceLoader } from './types'
|
||||
|
||||
export interface PackLocationVersionId {
|
||||
type: 'fromVersionId'
|
||||
project_id: string
|
||||
version_id: string
|
||||
title: string
|
||||
icon_url?: string | null
|
||||
}
|
||||
|
||||
export interface PackLocationFile {
|
||||
type: 'fromFile'
|
||||
path: string
|
||||
}
|
||||
|
||||
export type CreatePackLocation = PackLocationVersionId | PackLocationFile
|
||||
|
||||
export interface InstallModpackPreview {
|
||||
name: string
|
||||
gameVersion: string
|
||||
modloader: InstanceLoader
|
||||
loaderVersion: string | null
|
||||
icon?: string | null
|
||||
iconUrl?: string | null
|
||||
link?: InstanceLink | null
|
||||
unknownFile: boolean
|
||||
externalFilesInModpack: string[]
|
||||
}
|
||||
|
||||
export interface InstallCreateInstanceRequest {
|
||||
name: string
|
||||
gameVersion: string
|
||||
loader: InstanceLoader
|
||||
loaderVersion: string | null
|
||||
iconPath: string | null
|
||||
link?: InstanceLink | null
|
||||
}
|
||||
|
||||
export interface InstallPostInstallEdit {
|
||||
name?: string | null
|
||||
iconPath?: string | null
|
||||
link?: InstanceLink | null
|
||||
}
|
||||
|
||||
export type InstallJobStatus =
|
||||
| 'queued'
|
||||
| 'running'
|
||||
| 'succeeded'
|
||||
| 'failed'
|
||||
| 'interrupted'
|
||||
| 'canceled'
|
||||
|
||||
export type InstallPhaseId =
|
||||
| 'preparing_instance'
|
||||
| 'resolving_pack'
|
||||
| 'downloading_pack_file'
|
||||
| 'reading_pack_manifest'
|
||||
| 'downloading_content'
|
||||
| 'extracting_overrides'
|
||||
| 'resolving_minecraft'
|
||||
| 'resolving_loader'
|
||||
| 'preparing_java'
|
||||
| 'downloading_minecraft'
|
||||
| 'running_loader_processors'
|
||||
| 'finalizing'
|
||||
| 'rolling_back'
|
||||
|
||||
export interface InstallProgress {
|
||||
current: number
|
||||
total: number
|
||||
secondary?: InstallProgressSecondary | null
|
||||
}
|
||||
|
||||
export interface InstallProgressSecondary {
|
||||
current: number
|
||||
total: number
|
||||
}
|
||||
|
||||
export type InstallJavaStep =
|
||||
| 'resolving'
|
||||
| 'fetching_metadata'
|
||||
| 'downloading'
|
||||
| 'extracting'
|
||||
| 'validating'
|
||||
|
||||
export interface InstallErrorView {
|
||||
code: string
|
||||
phase?: InstallPhaseId | null
|
||||
message: string
|
||||
api?: {
|
||||
error: string
|
||||
status?: number | null
|
||||
method?: string | null
|
||||
url?: string | null
|
||||
route?: string | null
|
||||
} | null
|
||||
context?: {
|
||||
operation: string
|
||||
source_path?: string | null
|
||||
target_path?: string | null
|
||||
file_path?: string | null
|
||||
entry_path?: string | null
|
||||
urls?: string[]
|
||||
expected_hash?: string | null
|
||||
expected_size?: number | null
|
||||
project_id?: string | null
|
||||
version_id?: string | null
|
||||
minecraft_version?: string | null
|
||||
loader?: string | null
|
||||
java_version?: number | null
|
||||
os?: string | null
|
||||
arch?: string | null
|
||||
} | null
|
||||
}
|
||||
|
||||
export interface InstallJobSnapshot {
|
||||
job_id: string
|
||||
instance_id?: string | null
|
||||
kind:
|
||||
| 'create_instance'
|
||||
| 'create_modpack_instance'
|
||||
| 'import_instance'
|
||||
| 'duplicate_instance'
|
||||
| 'install_existing_instance'
|
||||
| 'install_pack_to_existing_instance'
|
||||
status: InstallJobStatus
|
||||
target:
|
||||
| { type: 'new_instance'; instance_id?: string | null }
|
||||
| { type: 'existing_instance'; instance_id: string }
|
||||
phase: InstallPhaseId
|
||||
progress?: InstallProgress | null
|
||||
details:
|
||||
| { type: 'empty' }
|
||||
| { type: 'instance'; name: string }
|
||||
| { type: 'minecraft'; game_version: string; loader: InstanceLoader }
|
||||
| { type: 'java'; major_version: number; step: InstallJavaStep }
|
||||
| {
|
||||
type: 'modpack'
|
||||
project_id?: string | null
|
||||
version_id?: string | null
|
||||
title?: string | null
|
||||
}
|
||||
| { type: 'import'; launcher_type: string; instance_folder: string }
|
||||
display?: { title: string; icon?: string | null } | null
|
||||
error?: InstallErrorView | null
|
||||
rollback_error?: InstallErrorView | null
|
||||
created: string
|
||||
modified: string
|
||||
finished?: string | null
|
||||
}
|
||||
|
||||
export async function install_get_modpack_preview(location: CreatePackLocation) {
|
||||
return await invoke<InstallModpackPreview>('plugin:install|install_get_modpack_preview', {
|
||||
location,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_create_instance(request: InstallCreateInstanceRequest) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_create_instance', { request })
|
||||
}
|
||||
|
||||
export async function install_create_modpack_instance(
|
||||
location: CreatePackLocation,
|
||||
postInstallEdit?: InstallPostInstallEdit | null,
|
||||
) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_create_modpack_instance', {
|
||||
location,
|
||||
postInstallEdit,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_import_instance(
|
||||
launcherType: string,
|
||||
basePath: string,
|
||||
instanceFolder: string,
|
||||
) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_import_instance', {
|
||||
launcherType,
|
||||
basePath,
|
||||
instanceFolder,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_duplicate_instance(sourceInstanceId: string) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_duplicate_instance', {
|
||||
sourceInstanceId,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_existing_instance(instanceId: string, force: boolean) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_existing_instance', {
|
||||
instanceId,
|
||||
force,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_pack_to_existing_instance(
|
||||
instanceId: string,
|
||||
location: CreatePackLocation,
|
||||
postInstallEdit?: InstallPostInstallEdit | null,
|
||||
) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_pack_to_existing_instance', {
|
||||
instanceId,
|
||||
location,
|
||||
postInstallEdit,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_job_list(includeFinished: boolean) {
|
||||
return await invoke<InstallJobSnapshot[]>('plugin:install|install_job_list', { includeFinished })
|
||||
}
|
||||
|
||||
export async function install_job_get(jobId: string) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_job_get', { jobId })
|
||||
}
|
||||
|
||||
export async function install_job_retry(jobId: string) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_job_retry', { jobId })
|
||||
}
|
||||
|
||||
export async function install_job_cancel(jobId: string) {
|
||||
return await invoke<InstallJobSnapshot>('plugin:install|install_job_cancel', { jobId })
|
||||
}
|
||||
|
||||
export async function install_job_dismiss(jobId: string) {
|
||||
return await invoke<void>('plugin:install|install_job_dismiss', { jobId })
|
||||
}
|
||||
|
||||
export async function install_job_support_details(jobId: string) {
|
||||
return await invoke<string>('plugin:install|install_job_support_details', { jobId })
|
||||
}
|
||||
|
||||
export function installJobInstanceId(job: InstallJobSnapshot): string | null {
|
||||
return job.instance_id ?? job.target.instance_id ?? null
|
||||
}
|
||||
|
||||
export function isInstallJobFinished(status: InstallJobStatus) {
|
||||
return (
|
||||
status === 'succeeded' ||
|
||||
status === 'failed' ||
|
||||
status === 'interrupted' ||
|
||||
status === 'canceled'
|
||||
)
|
||||
}
|
||||
|
||||
function settleInstallJob(job: InstallJobSnapshot) {
|
||||
if (job.status === 'succeeded') return job
|
||||
|
||||
throw new Error(job.error?.message ?? `Install job ${job.job_id} ${job.status}`)
|
||||
}
|
||||
|
||||
export async function wait_for_install_job(jobId: string) {
|
||||
const current = await install_job_get(jobId)
|
||||
if (isInstallJobFinished(current.status)) return settleInstallJob(current)
|
||||
|
||||
return await new Promise<InstallJobSnapshot>((resolve, reject) => {
|
||||
let finished = false
|
||||
let unlisten: (() => void) | null = null
|
||||
|
||||
const cleanup = () => {
|
||||
if (unlisten) {
|
||||
unlisten()
|
||||
unlisten = null
|
||||
}
|
||||
}
|
||||
|
||||
const resolveJob = (job: InstallJobSnapshot) => {
|
||||
if (finished || job.job_id !== jobId || !isInstallJobFinished(job.status)) return
|
||||
|
||||
finished = true
|
||||
cleanup()
|
||||
|
||||
try {
|
||||
resolve(settleInstallJob(job))
|
||||
} catch (err) {
|
||||
reject(err)
|
||||
}
|
||||
}
|
||||
|
||||
const rejectWait = (err: unknown) => {
|
||||
if (finished) return
|
||||
finished = true
|
||||
cleanup()
|
||||
reject(err)
|
||||
}
|
||||
|
||||
install_job_listener(resolveJob)
|
||||
.then((listener) => {
|
||||
if (finished) {
|
||||
listener()
|
||||
return
|
||||
}
|
||||
|
||||
unlisten = listener
|
||||
install_job_get(jobId).then(resolveJob).catch(rejectWait)
|
||||
})
|
||||
.catch(rejectWait)
|
||||
})
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
get_content_items,
|
||||
get_linked_modpack_info,
|
||||
type LinkedModpackInfo,
|
||||
} from '@/helpers/profile'
|
||||
} from '@/helpers/instance'
|
||||
import { get_categories } from '@/helpers/tags.js'
|
||||
import type { CacheBehaviour } from '@/helpers/types'
|
||||
|
||||
|
||||
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import type { ContentItem, ContentOwner } from '@modrinth/ui'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import type { InstallJobSnapshot } from './install'
|
||||
import type {
|
||||
CacheBehaviour,
|
||||
ContentFile,
|
||||
ContentFileProjectType,
|
||||
GameInstance,
|
||||
InstanceLoader,
|
||||
} from './types'
|
||||
|
||||
export async function remove(instanceId: string): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_remove', { instanceId })
|
||||
}
|
||||
|
||||
export async function get(instanceId: string): Promise<GameInstance | null> {
|
||||
return await invoke('plugin:instance|instance_get', { instanceId })
|
||||
}
|
||||
|
||||
export async function get_many(instanceIds: string[]): Promise<GameInstance[]> {
|
||||
return await invoke('plugin:instance|instance_get_many', { instanceIds })
|
||||
}
|
||||
|
||||
export async function get_projects(
|
||||
instanceId: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<Record<string, ContentFile>> {
|
||||
return await invoke('plugin:instance|instance_get_projects', { instanceId, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function get_installed_project_ids(instanceId: string): Promise<string[]> {
|
||||
return await invoke('plugin:instance|instance_get_installed_project_ids', { instanceId })
|
||||
}
|
||||
|
||||
export type InstanceInstallTarget = {
|
||||
game_version: string
|
||||
loader: string
|
||||
}
|
||||
|
||||
export type InstanceInstallCandidate = {
|
||||
id: string
|
||||
name: string
|
||||
icon_path?: string | null
|
||||
game_version: string
|
||||
loader: InstanceLoader
|
||||
installed: boolean
|
||||
compatible: boolean
|
||||
}
|
||||
|
||||
export async function get_install_candidates(
|
||||
projectId: string,
|
||||
projectType: string,
|
||||
targets: InstanceInstallTarget[],
|
||||
): Promise<InstanceInstallCandidate[]> {
|
||||
return await invoke('plugin:instance|instance_get_install_candidates', {
|
||||
projectId,
|
||||
projectType,
|
||||
targets,
|
||||
})
|
||||
}
|
||||
|
||||
// Get content items with rich metadata for an instance
|
||||
// Returns content items filtered to exclude modpack files (if linked),
|
||||
// sorted alphabetically by project name
|
||||
export async function get_content_items(
|
||||
instanceId: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:instance|instance_get_content_items', { instanceId, cacheBehaviour })
|
||||
}
|
||||
|
||||
// Linked modpack info returned from backend
|
||||
export interface LinkedModpackInfo {
|
||||
project: Labrinth.Projects.v2.Project
|
||||
version: Labrinth.Versions.v2.Version
|
||||
owner: ContentOwner | null
|
||||
has_update: boolean
|
||||
update_version_id: string | null
|
||||
update_version: Labrinth.Versions.v2.Version | null
|
||||
}
|
||||
|
||||
// Get linked modpack info for an instance
|
||||
// Returns project, version, and owner information for the linked modpack,
|
||||
// or null if the instance is not linked to a modpack
|
||||
export async function get_linked_modpack_info(
|
||||
instanceId: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<LinkedModpackInfo | null> {
|
||||
return await invoke('plugin:instance|instance_get_linked_modpack_info', {
|
||||
instanceId,
|
||||
cacheBehaviour,
|
||||
})
|
||||
}
|
||||
|
||||
// Get content items that are part of the linked modpack
|
||||
// Returns the modpack's dependencies as ContentItem list
|
||||
// Returns empty array if the instance is not linked to a modpack
|
||||
export async function get_linked_modpack_content(
|
||||
instanceId: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:instance|instance_get_linked_modpack_content', {
|
||||
instanceId,
|
||||
cacheBehaviour,
|
||||
})
|
||||
}
|
||||
|
||||
// Convert a list of dependencies into ContentItems with rich metadata
|
||||
export async function get_dependencies_as_content_items(
|
||||
dependencies: Labrinth.Versions.v3.Dependency[],
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:instance|instance_get_dependencies_as_content_items', {
|
||||
dependencies,
|
||||
cacheBehaviour,
|
||||
})
|
||||
}
|
||||
|
||||
export async function get_full_path(instanceId: string): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_get_full_path', { instanceId })
|
||||
}
|
||||
|
||||
export async function get_mod_full_path(instanceId: string, projectPath: string): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_get_mod_full_path', { instanceId, projectPath })
|
||||
}
|
||||
|
||||
export interface JavaVersion {
|
||||
parsed_version: number
|
||||
version: string
|
||||
architecture: string
|
||||
path: string
|
||||
}
|
||||
|
||||
export async function get_optimal_jre_key(instanceId: string): Promise<JavaVersion | null> {
|
||||
return await invoke('plugin:instance|instance_get_optimal_jre_key', { instanceId })
|
||||
}
|
||||
|
||||
export async function list(): Promise<GameInstance[]> {
|
||||
return await invoke('plugin:instance|instance_list')
|
||||
}
|
||||
|
||||
export async function check_installed(instanceId: string, projectId: string): Promise<boolean> {
|
||||
return await invoke('plugin:instance|instance_check_installed', { instanceId, projectId })
|
||||
}
|
||||
|
||||
export async function update_all(instanceId: string): Promise<Record<string, string>> {
|
||||
return await invoke('plugin:instance|instance_update_all', { instanceId })
|
||||
}
|
||||
|
||||
// Updates a specified project
|
||||
export async function update_project(instanceId: string, projectPath: string): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_update_project', { instanceId, projectPath })
|
||||
}
|
||||
|
||||
// Add a project to an instance from a version
|
||||
// Returns a path to the new project file
|
||||
export type DownloadReason = 'standalone' | 'dependency' | 'modpack' | 'update'
|
||||
|
||||
export interface ResolutionPreferences {
|
||||
game_versions?: string[]
|
||||
loaders?: string[]
|
||||
}
|
||||
|
||||
export interface ResolveContentRequest {
|
||||
project_id: string
|
||||
version_id?: string | null
|
||||
content_type: Labrinth.Content.v3.ContentType
|
||||
selected?: ResolutionPreferences
|
||||
}
|
||||
|
||||
export interface ResolvedContent {
|
||||
project_id: string
|
||||
version_id: string
|
||||
dependent_on_version_id?: string | null
|
||||
}
|
||||
|
||||
export interface ResolveContentPlan {
|
||||
primary: ResolvedContent
|
||||
dependencies: ResolvedContent[]
|
||||
skipped: Array<{
|
||||
project_id: string
|
||||
version_id?: string | null
|
||||
dependent_on_version_id?: string | null
|
||||
reason: string
|
||||
}>
|
||||
}
|
||||
|
||||
export async function add_project_from_version(
|
||||
instanceId: string,
|
||||
versionId: string,
|
||||
reason: DownloadReason,
|
||||
dependentOnVersionId?: string,
|
||||
): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_add_project_from_version', {
|
||||
instanceId,
|
||||
versionId,
|
||||
reason,
|
||||
dependentOnVersionId,
|
||||
})
|
||||
}
|
||||
|
||||
export async function install_project_with_dependencies(
|
||||
instanceId: string,
|
||||
request: ResolveContentRequest,
|
||||
): Promise<ResolveContentPlan> {
|
||||
return await invoke('plugin:instance|instance_install_project_with_dependencies', {
|
||||
instanceId,
|
||||
request,
|
||||
})
|
||||
}
|
||||
|
||||
export async function switch_project_version_with_dependencies(
|
||||
instanceId: string,
|
||||
projectPath: string,
|
||||
versionId: string,
|
||||
): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_switch_project_version_with_dependencies', {
|
||||
instanceId,
|
||||
projectPath,
|
||||
versionId,
|
||||
})
|
||||
}
|
||||
|
||||
// Add a project to an instance from a path + project_type
|
||||
// Returns a path to the new project file
|
||||
export async function add_project_from_path(
|
||||
instanceId: string,
|
||||
projectPath: string,
|
||||
projectType?: ContentFileProjectType,
|
||||
): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_add_project_from_path', {
|
||||
instanceId,
|
||||
projectPath,
|
||||
projectType,
|
||||
})
|
||||
}
|
||||
|
||||
export async function is_file_on_modrinth(projectPath: string): Promise<boolean> {
|
||||
return await invoke('plugin:instance|instance_is_file_on_modrinth', { projectPath })
|
||||
}
|
||||
|
||||
// Toggle disabling a project
|
||||
export async function toggle_disable_project(
|
||||
instanceId: string,
|
||||
projectPath: string,
|
||||
desiredEnabled?: boolean,
|
||||
): Promise<string> {
|
||||
return await invoke('plugin:instance|instance_toggle_disable_project', {
|
||||
instanceId,
|
||||
projectPath,
|
||||
desiredEnabled,
|
||||
})
|
||||
}
|
||||
|
||||
// Remove a project
|
||||
export async function remove_project(instanceId: string, projectPath: string): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_remove_project', { instanceId, projectPath })
|
||||
}
|
||||
|
||||
// Update a managed Modrinth instance to a specific version
|
||||
export async function update_managed_modrinth_version(
|
||||
instanceId: string,
|
||||
versionId: string,
|
||||
): Promise<InstallJobSnapshot> {
|
||||
return await invoke('plugin:instance|instance_update_managed_modrinth_version', {
|
||||
instanceId,
|
||||
versionId,
|
||||
})
|
||||
}
|
||||
|
||||
// Repair a managed Modrinth instance
|
||||
export async function update_repair_modrinth(instanceId: string): Promise<InstallJobSnapshot> {
|
||||
return await invoke('plugin:instance|instance_repair_managed_modrinth', { instanceId })
|
||||
}
|
||||
|
||||
// Export an instance to .mrpack
|
||||
// included_overrides is an array of paths to override folders to include (ie: 'mods', 'resource_packs')
|
||||
// Version id is optional (ie: 1.1.5)
|
||||
export async function export_instance_mrpack(
|
||||
instanceId: string,
|
||||
exportLocation: string,
|
||||
includedOverrides: string[],
|
||||
versionId?: string,
|
||||
description?: string,
|
||||
name?: string,
|
||||
): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_export_mrpack', {
|
||||
instanceId,
|
||||
exportLocation,
|
||||
includedOverrides,
|
||||
versionId,
|
||||
description,
|
||||
name,
|
||||
})
|
||||
}
|
||||
|
||||
// Given a folder path, populate an array of all the subfolders
|
||||
// Intended to be used for finding potential override folders
|
||||
// profile
|
||||
// -- mods
|
||||
// -- resourcepacks
|
||||
// -- file1
|
||||
// => [mods, resourcepacks]
|
||||
// allows selection for 'included_overrides' in export_instance_mrpack
|
||||
export async function get_pack_export_candidates(instanceId: string): Promise<string[]> {
|
||||
return await invoke('plugin:instance|instance_get_pack_export_candidates', { instanceId })
|
||||
}
|
||||
|
||||
// Run Minecraft using an instance
|
||||
// Returns PID of child
|
||||
export async function run(
|
||||
instanceId: string,
|
||||
serverAddress: string | null = null,
|
||||
): Promise<unknown> {
|
||||
return await invoke('plugin:instance|instance_run', { instanceId, serverAddress })
|
||||
}
|
||||
|
||||
export async function kill(instanceId: string): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_kill', { instanceId })
|
||||
}
|
||||
|
||||
// Edits an instance
|
||||
export async function edit(instanceId: string, editInstance: Partial<GameInstance>): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_edit', { instanceId, editInstance })
|
||||
}
|
||||
|
||||
// Edits an instance's icon
|
||||
export async function edit_icon(instanceId: string, iconPath: string | null): Promise<void> {
|
||||
return await invoke('plugin:instance|instance_edit_icon', { instanceId, iconPath })
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
@@ -14,41 +14,41 @@ pub struct Logs {
|
||||
}
|
||||
*/
|
||||
|
||||
/// Get all logs that exist for a given profile
|
||||
/// Get all logs that exist for a given instance
|
||||
/// This is returned as an array of Log objects, sorted by filename (the folder name, when the log was created)
|
||||
export async function get_logs(profilePath, clearContents) {
|
||||
return await invoke('plugin:logs|logs_get_logs', { profilePath, clearContents })
|
||||
export async function get_logs(instanceId, clearContents) {
|
||||
return await invoke('plugin:logs|logs_get_logs', { instanceId, clearContents })
|
||||
}
|
||||
|
||||
/// Get a profile's log by filename
|
||||
export async function get_logs_by_filename(profilePath, logType, filename) {
|
||||
return await invoke('plugin:logs|logs_get_logs_by_filename', { profilePath, logType, filename })
|
||||
/// Get an instance's log by filename
|
||||
export async function get_logs_by_filename(instanceId, logType, filename) {
|
||||
return await invoke('plugin:logs|logs_get_logs_by_filename', { instanceId, logType, filename })
|
||||
}
|
||||
|
||||
/// Get a profile's log text only by filename
|
||||
export async function get_output_by_filename(profilePath, logType, filename) {
|
||||
/// Get an instance's log text only by filename
|
||||
export async function get_output_by_filename(instanceId, logType, filename) {
|
||||
return await invoke('plugin:logs|logs_get_output_by_filename', {
|
||||
profilePath,
|
||||
instanceId,
|
||||
logType,
|
||||
filename,
|
||||
})
|
||||
}
|
||||
|
||||
/// Delete a profile's log by filename
|
||||
export async function delete_logs_by_filename(profilePath, logType, filename) {
|
||||
/// Delete an instance's log by filename
|
||||
export async function delete_logs_by_filename(instanceId, logType, filename) {
|
||||
return await invoke('plugin:logs|logs_delete_logs_by_filename', {
|
||||
profilePath,
|
||||
instanceId,
|
||||
logType,
|
||||
filename,
|
||||
})
|
||||
}
|
||||
|
||||
/// Delete all logs for a given profile
|
||||
export async function delete_logs(profilePath) {
|
||||
return await invoke('plugin:logs|logs_delete_logs', { profilePath })
|
||||
/// Delete all logs for a given instance
|
||||
export async function delete_logs(instanceId) {
|
||||
return await invoke('plugin:logs|logs_delete_logs', { instanceId })
|
||||
}
|
||||
|
||||
/// Get the latest log for a given profile and cursor (startpoint to read withi nthe file)
|
||||
/// Get the latest log for a given instance and cursor (startpoint to read within the file)
|
||||
/// Returns:
|
||||
/*
|
||||
{
|
||||
@@ -59,16 +59,16 @@ export async function delete_logs(profilePath) {
|
||||
*/
|
||||
|
||||
// From latest.log directly
|
||||
export async function get_latest_log_cursor(profilePath, cursor) {
|
||||
return await invoke('plugin:logs|logs_get_latest_log_cursor', { profilePath, cursor })
|
||||
export async function get_latest_log_cursor(instanceId, cursor) {
|
||||
return await invoke('plugin:logs|logs_get_latest_log_cursor', { instanceId, cursor })
|
||||
}
|
||||
|
||||
/// Get all buffered live log lines for a profile from the Rust ring buffer
|
||||
export async function get_live_log_buffer(profilePath) {
|
||||
return await invoke('plugin:logs|logs_get_live_log_buffer', { profilePath })
|
||||
/// Get all buffered live log lines for an instance from the Rust ring buffer
|
||||
export async function get_live_log_buffer(instanceId) {
|
||||
return await invoke('plugin:logs|logs_get_live_log_buffer', { instanceId })
|
||||
}
|
||||
|
||||
/// Clear the live log buffer for a profile on the Rust side
|
||||
export async function clear_log_buffer(profilePath) {
|
||||
return await invoke('plugin:logs|logs_clear_live_log_buffer', { profilePath })
|
||||
/// Clear the live log buffer for an instance on the Rust side
|
||||
export async function clear_log_buffer(instanceId) {
|
||||
return await invoke('plugin:logs|logs_clear_live_log_buffer', { instanceId })
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { create } from './profile'
|
||||
import type { InstanceLoader } from './types'
|
||||
|
||||
interface PackProfileCreator {
|
||||
name: string
|
||||
gameVersion: string
|
||||
modloader: InstanceLoader
|
||||
loaderVersion: string | null
|
||||
unknownFile: boolean
|
||||
}
|
||||
|
||||
interface PackLocationVersionId {
|
||||
type: 'fromVersionId'
|
||||
project_id: string
|
||||
version_id: string
|
||||
title: string
|
||||
icon_url?: string
|
||||
}
|
||||
|
||||
interface PackLocationFile {
|
||||
type: 'fromFile'
|
||||
path: string
|
||||
}
|
||||
|
||||
export async function create_profile_and_install(
|
||||
projectId: string,
|
||||
versionId: string,
|
||||
packTitle: string,
|
||||
iconUrl?: string,
|
||||
createInstanceCallback: (profile: string) => void = () => {},
|
||||
): Promise<void> {
|
||||
const location: PackLocationVersionId = {
|
||||
type: 'fromVersionId',
|
||||
project_id: projectId,
|
||||
version_id: versionId,
|
||||
title: packTitle,
|
||||
icon_url: iconUrl,
|
||||
}
|
||||
const profile_creator = await invoke<PackProfileCreator>(
|
||||
'plugin:pack|pack_get_profile_from_pack',
|
||||
{ location },
|
||||
)
|
||||
const profile = await create(
|
||||
profile_creator.name,
|
||||
profile_creator.gameVersion,
|
||||
profile_creator.modloader,
|
||||
profile_creator.loaderVersion,
|
||||
null,
|
||||
true,
|
||||
)
|
||||
createInstanceCallback(profile)
|
||||
|
||||
return await invoke('plugin:pack|pack_install', { location, profile })
|
||||
}
|
||||
|
||||
export async function install_to_existing_profile(
|
||||
projectId: string,
|
||||
versionId: string,
|
||||
title: string,
|
||||
profilePath: string,
|
||||
): Promise<void> {
|
||||
const location: PackLocationVersionId = {
|
||||
type: 'fromVersionId',
|
||||
project_id: projectId,
|
||||
version_id: versionId,
|
||||
title,
|
||||
}
|
||||
return await invoke('plugin:pack|pack_install', { location, profile: profilePath })
|
||||
}
|
||||
|
||||
export async function create_profile_and_install_from_file(
|
||||
path: string,
|
||||
showUnknownPackWarningModal?: (createProfile: () => Promise<void>, fileName: string) => void,
|
||||
): Promise<void> {
|
||||
const location: PackLocationFile = {
|
||||
type: 'fromFile',
|
||||
path,
|
||||
}
|
||||
const profile_creator = await invoke<PackProfileCreator>(
|
||||
'plugin:pack|pack_get_profile_from_pack',
|
||||
{ location },
|
||||
)
|
||||
|
||||
const createProfile = async () => {
|
||||
const profile = await create(
|
||||
profile_creator.name,
|
||||
profile_creator.gameVersion,
|
||||
profile_creator.modloader,
|
||||
profile_creator.loaderVersion,
|
||||
null,
|
||||
true,
|
||||
)
|
||||
await invoke('plugin:pack|pack_install', { location, profile })
|
||||
}
|
||||
|
||||
if (profile_creator.unknownFile && showUnknownPackWarningModal) {
|
||||
const splitPath = path.split(/[\\/]/)
|
||||
const fileName = splitPath ? splitPath[splitPath.length - 1] : path
|
||||
showUnknownPackWarningModal(createProfile, fileName)
|
||||
} else {
|
||||
await createProfile()
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
/// Gets all running process IDs with a given profile path
|
||||
/// Gets all running process IDs with a given instance ID
|
||||
/// Returns [u32]
|
||||
export async function get_by_profile_path(path) {
|
||||
return await invoke('plugin:process|process_get_by_profile_path', { path })
|
||||
export async function get_by_instance_id(instanceId) {
|
||||
return await invoke('plugin:process|process_get_by_instance_id', { instanceId })
|
||||
}
|
||||
|
||||
/// Gets all running process IDs with a given profile path
|
||||
/// Gets all running process IDs
|
||||
/// Returns [u32]
|
||||
export async function get_all() {
|
||||
return await invoke('plugin:process|process_get_all')
|
||||
|
||||
@@ -1,317 +0,0 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import type { ContentItem, ContentOwner } from '@modrinth/ui'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { install_to_existing_profile } from '@/helpers/pack'
|
||||
|
||||
import type {
|
||||
CacheBehaviour,
|
||||
ContentFile,
|
||||
ContentFileProjectType,
|
||||
GameInstance,
|
||||
InstanceLoader,
|
||||
} from './types'
|
||||
|
||||
// Add instance
|
||||
/*
|
||||
name: String, // the name of the profile, and relative path to create
|
||||
game_version: String, // the game version of the profile
|
||||
modloader: ModLoader, // the modloader to use
|
||||
- ModLoader is an enum, with the following variants: Vanilla, Forge, Fabric, Quilt
|
||||
loader_version: String, // the modloader version to use, set to "latest", "stable", or the ID of your chosen loader
|
||||
icon: Path, // the icon for the profile
|
||||
- icon is a path to an image file, which will be copied into the profile directory
|
||||
*/
|
||||
|
||||
export async function create(
|
||||
name: string,
|
||||
gameVersion: string,
|
||||
modloader: InstanceLoader,
|
||||
loaderVersion: string | null,
|
||||
icon: string | null,
|
||||
skipInstall: boolean,
|
||||
linkedData?: { project_id: string; version_id: string; locked: boolean } | null,
|
||||
): Promise<string> {
|
||||
// Trim string name to avoid "Unable to find directory"
|
||||
name = name.trim()
|
||||
return await invoke('plugin:profile-create|profile_create', {
|
||||
name,
|
||||
gameVersion,
|
||||
modloader,
|
||||
loaderVersion,
|
||||
icon,
|
||||
skipInstall,
|
||||
linkedData,
|
||||
})
|
||||
}
|
||||
|
||||
// duplicate a profile
|
||||
export async function duplicate(path: string): Promise<string> {
|
||||
return await invoke('plugin:profile-create|profile_duplicate', { path })
|
||||
}
|
||||
|
||||
// Remove a profile
|
||||
export async function remove(path: string): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_remove', { path })
|
||||
}
|
||||
|
||||
// Get a profile by path
|
||||
// Returns a Profile
|
||||
export async function get(path: string): Promise<GameInstance | null> {
|
||||
return await invoke('plugin:profile|profile_get', { path })
|
||||
}
|
||||
|
||||
export async function get_many(paths: string[]): Promise<GameInstance[]> {
|
||||
return await invoke('plugin:profile|profile_get_many', { paths })
|
||||
}
|
||||
|
||||
// Get a profile's projects
|
||||
// Returns a map of a path to profile file
|
||||
export async function get_projects(
|
||||
path: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<Record<string, ContentFile>> {
|
||||
return await invoke('plugin:profile|profile_get_projects', { path, cacheBehaviour })
|
||||
}
|
||||
|
||||
// Get just the installed project IDs for a profile (lightweight, skips update checks)
|
||||
export async function get_installed_project_ids(path: string): Promise<string[]> {
|
||||
return await invoke('plugin:profile|profile_get_installed_project_ids', { path })
|
||||
}
|
||||
|
||||
// Get content items with rich metadata for a profile
|
||||
// Returns content items filtered to exclude modpack files (if linked),
|
||||
// sorted alphabetically by project name
|
||||
export async function get_content_items(
|
||||
path: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:profile|profile_get_content_items', { path, cacheBehaviour })
|
||||
}
|
||||
|
||||
// Linked modpack info returned from backend
|
||||
export interface LinkedModpackInfo {
|
||||
project: Labrinth.Projects.v2.Project
|
||||
version: Labrinth.Versions.v2.Version
|
||||
owner: ContentOwner | null
|
||||
has_update: boolean
|
||||
update_version_id: string | null
|
||||
update_version: Labrinth.Versions.v2.Version | null
|
||||
}
|
||||
|
||||
// Get linked modpack info for a profile
|
||||
// Returns project, version, and owner information for the linked modpack,
|
||||
// or null if the profile is not linked to a modpack
|
||||
export async function get_linked_modpack_info(
|
||||
path: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<LinkedModpackInfo | null> {
|
||||
return await invoke('plugin:profile|profile_get_linked_modpack_info', { path, cacheBehaviour })
|
||||
}
|
||||
|
||||
// Get content items that are part of the linked modpack
|
||||
// Returns the modpack's dependencies as ContentItem list
|
||||
// Returns empty array if the profile is not linked to a modpack
|
||||
export async function get_linked_modpack_content(
|
||||
path: string,
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:profile|profile_get_linked_modpack_content', { path, cacheBehaviour })
|
||||
}
|
||||
|
||||
// Convert a list of dependencies into ContentItems with rich metadata
|
||||
export async function get_dependencies_as_content_items(
|
||||
dependencies: Labrinth.Versions.v3.Dependency[],
|
||||
cacheBehaviour?: CacheBehaviour,
|
||||
): Promise<ContentItem[]> {
|
||||
return await invoke('plugin:profile|profile_get_dependencies_as_content_items', {
|
||||
dependencies,
|
||||
cacheBehaviour,
|
||||
})
|
||||
}
|
||||
|
||||
// Get a profile's full fs path
|
||||
// Returns a path
|
||||
export async function get_full_path(path: string): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_get_full_path', { path })
|
||||
}
|
||||
|
||||
// Get's a mod's full fs path
|
||||
// Returns a path
|
||||
export async function get_mod_full_path(path: string, projectPath: string): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_get_mod_full_path', { path, projectPath })
|
||||
}
|
||||
|
||||
export interface JavaVersion {
|
||||
parsed_version: number
|
||||
version: string
|
||||
architecture: string
|
||||
path: string
|
||||
}
|
||||
|
||||
// Get optimal java version from profile
|
||||
// Returns a java version
|
||||
export async function get_optimal_jre_key(path: string): Promise<JavaVersion | null> {
|
||||
return await invoke('plugin:profile|profile_get_optimal_jre_key', { path })
|
||||
}
|
||||
|
||||
// Get a copy of the profile set
|
||||
// Returns hashmap of path -> Profile
|
||||
export async function list(): Promise<GameInstance[]> {
|
||||
return await invoke('plugin:profile|profile_list')
|
||||
}
|
||||
|
||||
export async function check_installed(path: string, projectId: string): Promise<boolean> {
|
||||
return await invoke('plugin:profile|profile_check_installed', { path, projectId })
|
||||
}
|
||||
|
||||
export async function check_installed_batch(projectId: string): Promise<Record<string, boolean>> {
|
||||
return await invoke('plugin:profile|profile_check_installed_batch', { projectId })
|
||||
}
|
||||
|
||||
// Installs/Repairs a profile
|
||||
export async function install(path: string, force: boolean): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_install', { path, force })
|
||||
}
|
||||
|
||||
// Updates all of a profile's projects
|
||||
export async function update_all(path: string): Promise<Record<string, string>> {
|
||||
return await invoke('plugin:profile|profile_update_all', { path })
|
||||
}
|
||||
|
||||
// Updates a specified project
|
||||
export async function update_project(path: string, projectPath: string): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_update_project', { path, projectPath })
|
||||
}
|
||||
|
||||
// Add a project to a profile from a version
|
||||
// Returns a path to the new project file
|
||||
export type DownloadReason = 'standalone' | 'dependency' | 'modpack' | 'update'
|
||||
|
||||
export async function add_project_from_version(
|
||||
path: string,
|
||||
versionId: string,
|
||||
reason: DownloadReason,
|
||||
dependentOnVersionId?: string,
|
||||
): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_add_project_from_version', {
|
||||
path,
|
||||
versionId,
|
||||
reason,
|
||||
dependentOnVersionId,
|
||||
})
|
||||
}
|
||||
|
||||
// Add a project to a profile from a path + project_type
|
||||
// Returns a path to the new project file
|
||||
export async function add_project_from_path(
|
||||
path: string,
|
||||
projectPath: string,
|
||||
projectType?: ContentFileProjectType,
|
||||
): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_add_project_from_path', {
|
||||
path,
|
||||
projectPath,
|
||||
projectType,
|
||||
})
|
||||
}
|
||||
|
||||
// Toggle disabling a project
|
||||
export async function toggle_disable_project(path: string, projectPath: string): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_toggle_disable_project', { path, projectPath })
|
||||
}
|
||||
|
||||
// Remove a project
|
||||
export async function remove_project(path: string, projectPath: string): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_remove_project', { path, projectPath })
|
||||
}
|
||||
|
||||
// Update a managed Modrinth profile to a specific version
|
||||
export async function update_managed_modrinth_version(
|
||||
path: string,
|
||||
versionId: string,
|
||||
): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_update_managed_modrinth_version', {
|
||||
path,
|
||||
versionId,
|
||||
})
|
||||
}
|
||||
|
||||
// Repair a managed Modrinth profile
|
||||
export async function update_repair_modrinth(path: string): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_repair_managed_modrinth', { path })
|
||||
}
|
||||
|
||||
// Export a profile to .mrpack
|
||||
// included_overrides is an array of paths to override folders to include (ie: 'mods', 'resource_packs')
|
||||
// Version id is optional (ie: 1.1.5)
|
||||
export async function export_profile_mrpack(
|
||||
path: string,
|
||||
exportLocation: string,
|
||||
includedOverrides: string[],
|
||||
versionId?: string,
|
||||
description?: string,
|
||||
name?: string,
|
||||
): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_export_mrpack', {
|
||||
path,
|
||||
exportLocation,
|
||||
includedOverrides,
|
||||
versionId,
|
||||
description,
|
||||
name,
|
||||
})
|
||||
}
|
||||
|
||||
// Given a folder path, populate an array of all the subfolders
|
||||
// Intended to be used for finding potential override folders
|
||||
// profile
|
||||
// -- mods
|
||||
// -- resourcepacks
|
||||
// -- file1
|
||||
// => [mods, resourcepacks]
|
||||
// allows selection for 'included_overrides' in export_profile_mrpack
|
||||
export async function get_pack_export_candidates(profilePath: string): Promise<string[]> {
|
||||
return await invoke('plugin:profile|profile_get_pack_export_candidates', { profilePath })
|
||||
}
|
||||
|
||||
// Run Minecraft using a pathed profile
|
||||
// Returns PID of child
|
||||
export async function run(path: string, serverAddress: string | null = null): Promise<unknown> {
|
||||
return await invoke('plugin:profile|profile_run', { path, serverAddress })
|
||||
}
|
||||
|
||||
export async function kill(path: string): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_kill', { path })
|
||||
}
|
||||
|
||||
// Edits a profile
|
||||
export async function edit(path: string, editProfile: Partial<GameInstance>): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_edit', { path, editProfile })
|
||||
}
|
||||
|
||||
// Edits a profile's icon
|
||||
export async function edit_icon(path: string, iconPath: string | null): Promise<void> {
|
||||
return await invoke('plugin:profile|profile_edit_icon', { path, iconPath })
|
||||
}
|
||||
|
||||
export async function finish_install(instance: GameInstance): Promise<void> {
|
||||
if (instance.install_stage !== 'pack_installed') {
|
||||
const linkedData = instance.linked_data
|
||||
if (linkedData) {
|
||||
await install_to_existing_profile(
|
||||
linkedData.project_id,
|
||||
linkedData.version_id,
|
||||
instance.name,
|
||||
instance.path,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
await install(instance.path, false)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
import { ClassicPlayerModel, SlimPlayerModel } from '@modrinth/assets'
|
||||
import {
|
||||
applyCapeTexture,
|
||||
applyEarsMod,
|
||||
createTransparentTexture,
|
||||
disposeCaches,
|
||||
loadTexture,
|
||||
removeEarsMod,
|
||||
setupSkinModel,
|
||||
} from '@modrinth/ui'
|
||||
import * as THREE from 'three'
|
||||
@@ -71,12 +74,13 @@ class BatchSkinRenderer {
|
||||
textureUrl: string,
|
||||
modelUrl: string,
|
||||
capeUrl?: string,
|
||||
earsTextureUrl?: string,
|
||||
): Promise<RawRenderResult> {
|
||||
this.initializeRenderer()
|
||||
|
||||
this.clearScene()
|
||||
|
||||
await this.setupModel(modelUrl, textureUrl, capeUrl)
|
||||
await this.setupModel(modelUrl, textureUrl, capeUrl, earsTextureUrl)
|
||||
|
||||
const headPart = this.currentModel!.getObjectByName('Head')
|
||||
let lookAtTarget: [number, number, number]
|
||||
@@ -123,17 +127,29 @@ class BatchSkinRenderer {
|
||||
})
|
||||
}
|
||||
|
||||
private async setupModel(modelUrl: string, textureUrl: string, capeUrl?: string): Promise<void> {
|
||||
private async setupModel(
|
||||
modelUrl: string,
|
||||
textureUrl: string,
|
||||
capeUrl?: string,
|
||||
earsTextureUrl?: string,
|
||||
): Promise<void> {
|
||||
if (!this.scene) {
|
||||
throw new Error('Renderer not initialized')
|
||||
}
|
||||
|
||||
const { model } = await setupSkinModel(modelUrl, textureUrl, capeUrl)
|
||||
const [{ model }, earsTexture] = await Promise.all([
|
||||
setupSkinModel(modelUrl, textureUrl, capeUrl),
|
||||
earsTextureUrl ? loadTexture(earsTextureUrl) : Promise.resolve(null),
|
||||
])
|
||||
|
||||
if (!capeUrl) {
|
||||
applyCapeTexture(model, null, this.getTransparentTexture())
|
||||
}
|
||||
|
||||
if (earsTexture) {
|
||||
applyEarsMod(model, earsTexture)
|
||||
}
|
||||
|
||||
const group = new THREE.Group()
|
||||
group.add(model)
|
||||
group.position.set(0, 0.3, 1.95)
|
||||
@@ -154,6 +170,7 @@ class BatchSkinRenderer {
|
||||
private clearScene(): void {
|
||||
if (!this.scene || !this.currentModel) return
|
||||
|
||||
removeEarsMod(this.currentModel)
|
||||
this.scene.remove(this.currentModel)
|
||||
this.currentModel.clear()
|
||||
this.currentModel = null
|
||||
@@ -193,6 +210,7 @@ function getModelUrlForVariant(variant: string): string {
|
||||
export const skinBlobUrlMap = reactive(new Map<string, RenderResult>())
|
||||
export const headBlobUrlMap = reactive(new Map<string, string>())
|
||||
const DEBUG_MODE = false
|
||||
const SKIN_PREVIEW_RENDER_VERSION = 'ears-2'
|
||||
|
||||
let sharedRenderer: BatchSkinRenderer | null = null
|
||||
let latestPreviewGeneration = 0
|
||||
@@ -205,6 +223,10 @@ function getSharedRenderer(): BatchSkinRenderer {
|
||||
return sharedRenderer
|
||||
}
|
||||
|
||||
export function getSkinPreviewKey(skin: Skin): string {
|
||||
return `${SKIN_PREVIEW_RENDER_VERSION}+${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`
|
||||
}
|
||||
|
||||
export function disposeSharedRenderer(): void {
|
||||
if (sharedRenderer) {
|
||||
sharedRenderer.dispose()
|
||||
@@ -217,7 +239,7 @@ export async function cleanupUnusedPreviews(skins: Skin[]): Promise<void> {
|
||||
const validHeadKeys = new Set<string>()
|
||||
|
||||
for (const skin of skins) {
|
||||
const key = `${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`
|
||||
const key = getSkinPreviewKey(skin)
|
||||
const headKey = `${skin.texture_key}-head`
|
||||
validKeys.add(key)
|
||||
validHeadKeys.add(headKey)
|
||||
@@ -382,9 +404,7 @@ async function generateSkinPreviewsForGeneration(
|
||||
const isCurrentGeneration = () => generation === latestPreviewGeneration
|
||||
|
||||
try {
|
||||
const skinKeys = skins.map(
|
||||
(skin) => `${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`,
|
||||
)
|
||||
const skinKeys = skins.map(getSkinPreviewKey)
|
||||
const headKeys = skins.map((skin) => `${skin.texture_key}-head`)
|
||||
|
||||
const [cachedSkinPreviews, cachedHeadPreviews] = await Promise.all([
|
||||
@@ -415,7 +435,7 @@ async function generateSkinPreviewsForGeneration(
|
||||
for (const skin of skins) {
|
||||
if (!isCurrentGeneration()) return
|
||||
|
||||
const key = `${skin.texture_key}+${skin.variant}+${skin.cape_id ?? 'no-cape'}`
|
||||
const key = getSkinPreviewKey(skin)
|
||||
|
||||
if (skinBlobUrlMap.has(key)) {
|
||||
if (DEBUG_MODE) {
|
||||
@@ -443,6 +463,7 @@ async function generateSkinPreviewsForGeneration(
|
||||
await get_normalized_skin_texture(skin),
|
||||
modelUrl,
|
||||
cape?.texture,
|
||||
skin.texture,
|
||||
)
|
||||
|
||||
if (!isCurrentGeneration()) return
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
@@ -8,7 +8,8 @@ import { invoke } from '@tauri-apps/api/core'
|
||||
export interface LoadingBarType {
|
||||
type?: string
|
||||
version?: string
|
||||
profile_path?: string
|
||||
instance_id?: string
|
||||
instance_name?: string
|
||||
pack_name?: string
|
||||
icon?: string | null
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* All theseus API calls return serialized values (both return values and errors);
|
||||
* So, for example, addDefaultInstance creates a blank Profile object, where the Rust struct is serialized,
|
||||
* So, for example, addDefaultInstance creates a blank instance object, where the Rust struct is serialized,
|
||||
* and deserialized into a usable JS object.
|
||||
*/
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
+60
-7
@@ -1,20 +1,23 @@
|
||||
import type { ModrinthId } from '@modrinth/utils'
|
||||
|
||||
export type GameInstance = {
|
||||
id: string
|
||||
path: string
|
||||
install_stage: InstallStage
|
||||
launcher_feature_version: string
|
||||
|
||||
name: string
|
||||
icon_path?: string
|
||||
|
||||
game_version: string
|
||||
protocol_version?: number
|
||||
loader: InstanceLoader
|
||||
loader_version?: string
|
||||
|
||||
groups: string[]
|
||||
|
||||
linked_data?: LinkedData
|
||||
preferred_update_channel: ReleaseChannel
|
||||
link?: InstanceLink | null
|
||||
update_channel: ReleaseChannel
|
||||
|
||||
created: Date
|
||||
modified: Date
|
||||
@@ -40,18 +43,61 @@ type InstallStage =
|
||||
| 'pack_installing'
|
||||
| 'not_installed'
|
||||
|
||||
type LinkedData = {
|
||||
project_id: ModrinthId
|
||||
version_id: ModrinthId
|
||||
|
||||
locked: boolean
|
||||
type InstanceLinkIdentity = {
|
||||
project_id?: ModrinthId | null
|
||||
version_id?: ModrinthId | null
|
||||
server_project_id?: ModrinthId | null
|
||||
content_project_id?: ModrinthId | null
|
||||
content_version_id?: ModrinthId | null
|
||||
}
|
||||
|
||||
export type InstanceLink = InstanceLinkIdentity &
|
||||
(
|
||||
| {
|
||||
type: 'modrinth_modpack'
|
||||
project_id: ModrinthId
|
||||
version_id: ModrinthId
|
||||
}
|
||||
| {
|
||||
type: 'server_project'
|
||||
project_id: ModrinthId
|
||||
}
|
||||
| {
|
||||
type: 'server_project_modpack'
|
||||
server_project_id: ModrinthId
|
||||
content_project_id?: ModrinthId | null
|
||||
content_version_id: ModrinthId
|
||||
project_id?: ModrinthId
|
||||
version_id?: ModrinthId
|
||||
}
|
||||
| {
|
||||
type: 'imported_modpack'
|
||||
project_id?: ModrinthId | null
|
||||
version_id?: ModrinthId | null
|
||||
name?: string | null
|
||||
version_number?: string | null
|
||||
filename?: string | null
|
||||
}
|
||||
| {
|
||||
type: 'modrinth_hosting'
|
||||
server_id: string
|
||||
instance_ids: string[]
|
||||
active_instance_id?: string | null
|
||||
}
|
||||
| {
|
||||
type: 'shared_instance'
|
||||
shared_instance_id: string
|
||||
}
|
||||
)
|
||||
|
||||
export type Instance = GameInstance
|
||||
|
||||
type ReleaseChannel = 'release' | 'beta' | 'alpha'
|
||||
|
||||
export type InstanceLoader = 'vanilla' | 'forge' | 'fabric' | 'quilt' | 'neoforge'
|
||||
|
||||
type ContentFile = {
|
||||
enabled: boolean
|
||||
metadata?: {
|
||||
project_id: string
|
||||
version_id: string
|
||||
@@ -87,11 +133,18 @@ type Hooks = {
|
||||
|
||||
type Manifest = {
|
||||
gameVersions: ManifestGameVersion[]
|
||||
versionGroups?: ManifestVersionGroup[]
|
||||
}
|
||||
|
||||
type ManifestGameVersion = {
|
||||
id: string
|
||||
stable: boolean
|
||||
versionGroup?: string
|
||||
loaders: ManifestLoaderVersion[]
|
||||
}
|
||||
|
||||
type ManifestVersionGroup = {
|
||||
id: string
|
||||
loaders: ManifestLoaderVersion[]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { save } from '@tauri-apps/plugin-dialog'
|
||||
|
||||
import { get_full_path, get_mod_full_path } from '@/helpers/profile'
|
||||
import { get_full_path, get_mod_full_path } from '@/helpers/instance'
|
||||
|
||||
export async function isDev() {
|
||||
return await invoke('is_dev')
|
||||
@@ -47,14 +48,34 @@ export async function showLauncherLogsFolder() {
|
||||
return await invoke('plugin:utils|show_launcher_logs_folder', {})
|
||||
}
|
||||
|
||||
// Opens a profile's folder in the OS file explorer
|
||||
export async function showProfileInFolder(path) {
|
||||
const fullPath = await get_full_path(path)
|
||||
export async function createInstanceShortcut(instanceName, instanceId, options = {}) {
|
||||
const outputPath = await save({
|
||||
defaultPath: `Modrinth - ${instanceName}`,
|
||||
})
|
||||
|
||||
if (!outputPath) return null
|
||||
|
||||
return await invoke('plugin:shortcuts|create_instance_shortcut', {
|
||||
instanceName,
|
||||
instanceId,
|
||||
outputPath,
|
||||
server: options.server,
|
||||
singleplayerWorld: options.singleplayerWorld,
|
||||
})
|
||||
}
|
||||
|
||||
export async function showAppDbBackupsFolder() {
|
||||
return await invoke('plugin:utils|show_app_db_backups_folder', {})
|
||||
}
|
||||
|
||||
// Opens an instance's folder in the OS file explorer
|
||||
export async function showInstanceInFolder(instanceId) {
|
||||
const fullPath = await get_full_path(instanceId)
|
||||
return await openPath(fullPath)
|
||||
}
|
||||
|
||||
export async function highlightModInProfile(profilePath, projectPath) {
|
||||
const fullPath = await get_mod_full_path(profilePath, projectPath)
|
||||
export async function highlightModInInstance(instanceId, projectPath) {
|
||||
const fullPath = await get_mod_full_path(instanceId, projectPath)
|
||||
return await highlightInFolder(fullPath)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { autoToHTML } from '@sfirew/minecraft-motd-parser'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import { get_full_path } from '@/helpers/profile'
|
||||
import { get_full_path } from '@/helpers/instance'
|
||||
import { openPath } from '@/helpers/utils'
|
||||
|
||||
type BaseWorld = {
|
||||
@@ -36,8 +36,8 @@ export type ServerWorld = BaseWorld & {
|
||||
|
||||
export type World = SingleplayerWorld | ServerWorld
|
||||
|
||||
export type WorldWithProfile = {
|
||||
profile: string
|
||||
export type WorldWithInstance = {
|
||||
instance_id: string
|
||||
} & World
|
||||
|
||||
export type SingleplayerGameMode = 'survival' | 'creative' | 'adventure' | 'spectator'
|
||||
@@ -88,12 +88,12 @@ export type ProtocolVersion = {
|
||||
export async function get_recent_worlds(
|
||||
limit: number,
|
||||
displayStatuses?: DisplayStatus[],
|
||||
): Promise<WorldWithProfile[]> {
|
||||
): Promise<WorldWithInstance[]> {
|
||||
return await invoke('plugin:worlds|get_recent_worlds', { limit, displayStatuses })
|
||||
}
|
||||
|
||||
export async function get_profile_worlds(path: string): Promise<World[]> {
|
||||
return await invoke('plugin:worlds|get_profile_worlds', { path })
|
||||
export async function get_instance_worlds(instanceId: string): Promise<World[]> {
|
||||
return await invoke('plugin:worlds|get_instance_worlds', { instanceId })
|
||||
}
|
||||
|
||||
export async function get_singleplayer_world(
|
||||
@@ -137,16 +137,16 @@ export async function delete_world(instance: string, world: string): Promise<voi
|
||||
return await invoke('plugin:worlds|delete_world', { instance, world })
|
||||
}
|
||||
|
||||
export async function add_server_to_profile(
|
||||
path: string,
|
||||
export async function add_server_to_instance(
|
||||
instanceId: string,
|
||||
name: string,
|
||||
address: string,
|
||||
packStatus: ServerPackStatus,
|
||||
projectId?: string,
|
||||
contentKind?: string,
|
||||
): Promise<number> {
|
||||
return await invoke('plugin:worlds|add_server_to_profile', {
|
||||
path,
|
||||
return await invoke('plugin:worlds|add_server_to_instance', {
|
||||
instanceId,
|
||||
name,
|
||||
address,
|
||||
packStatus,
|
||||
@@ -155,15 +155,15 @@ export async function add_server_to_profile(
|
||||
})
|
||||
}
|
||||
|
||||
export async function edit_server_in_profile(
|
||||
path: string,
|
||||
export async function edit_server_in_instance(
|
||||
instanceId: string,
|
||||
index: number,
|
||||
name: string,
|
||||
address: string,
|
||||
packStatus: ServerPackStatus,
|
||||
): Promise<void> {
|
||||
return await invoke('plugin:worlds|edit_server_in_profile', {
|
||||
path,
|
||||
return await invoke('plugin:worlds|edit_server_in_instance', {
|
||||
instanceId,
|
||||
index,
|
||||
name,
|
||||
address,
|
||||
@@ -171,12 +171,17 @@ export async function edit_server_in_profile(
|
||||
})
|
||||
}
|
||||
|
||||
export async function remove_server_from_profile(path: string, index: number): Promise<void> {
|
||||
return await invoke('plugin:worlds|remove_server_from_profile', { path, index })
|
||||
export async function remove_server_from_instance(
|
||||
instanceId: string,
|
||||
index: number,
|
||||
): Promise<void> {
|
||||
return await invoke('plugin:worlds|remove_server_from_instance', { instanceId, index })
|
||||
}
|
||||
|
||||
export async function get_profile_protocol_version(path: string): Promise<ProtocolVersion | null> {
|
||||
return await invoke('plugin:worlds|get_profile_protocol_version', { path })
|
||||
export async function get_instance_protocol_version(
|
||||
instanceId: string,
|
||||
): Promise<ProtocolVersion | null> {
|
||||
return await invoke('plugin:worlds|get_instance_protocol_version', { instanceId })
|
||||
}
|
||||
|
||||
export async function get_server_status(
|
||||
@@ -186,16 +191,19 @@ export async function get_server_status(
|
||||
return await invoke('plugin:worlds|get_server_status', { address, protocolVersion })
|
||||
}
|
||||
|
||||
export async function start_join_singleplayer_world(path: string, world: string): Promise<unknown> {
|
||||
return await invoke('plugin:worlds|start_join_singleplayer_world', { path, world })
|
||||
export async function start_join_singleplayer_world(
|
||||
instanceId: string,
|
||||
world: string,
|
||||
): Promise<unknown> {
|
||||
return await invoke('plugin:worlds|start_join_singleplayer_world', { instanceId, world })
|
||||
}
|
||||
|
||||
export async function start_join_server(path: string, address: string): Promise<unknown> {
|
||||
return await invoke('plugin:worlds|start_join_server', { path, address })
|
||||
export async function start_join_server(instanceId: string, address: string): Promise<unknown> {
|
||||
return await invoke('plugin:worlds|start_join_server', { instanceId, address })
|
||||
}
|
||||
|
||||
export async function showWorldInFolder(instancePath: string, worldPath: string) {
|
||||
const fullPath = await get_full_path(instancePath)
|
||||
export async function showWorldInFolder(instanceId: string, worldPath: string) {
|
||||
const fullPath = await get_full_path(instanceId)
|
||||
return await openPath(fullPath + '/saves/' + worldPath)
|
||||
}
|
||||
|
||||
@@ -348,6 +356,28 @@ export function resolveManagedServerWorld(
|
||||
)
|
||||
}
|
||||
|
||||
export function getServerAddress(javaServer?: { address?: string | null } | null) {
|
||||
if (!javaServer) return null
|
||||
return javaServer.address ?? null
|
||||
}
|
||||
|
||||
export async function ensureManagedServerWorldExists(
|
||||
instanceId: string,
|
||||
serverName: string,
|
||||
serverAddress: string | null,
|
||||
) {
|
||||
if (!instanceId || !serverAddress) return
|
||||
try {
|
||||
const worlds = await get_instance_worlds(instanceId)
|
||||
const managedWorld = resolveManagedServerWorld(worlds, serverName, serverAddress)
|
||||
if (!managedWorld) {
|
||||
await add_server_to_instance(instanceId, serverName, serverAddress, 'prompt')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to ensure managed server world exists:', err)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getServerLatency(
|
||||
address: string,
|
||||
protocolVersion: ProtocolVersion | null = null,
|
||||
@@ -374,28 +404,35 @@ export async function refreshServerData(
|
||||
): Promise<void> {
|
||||
const refreshTime = Date.now()
|
||||
serverData.refreshing = true
|
||||
await get_server_status(address, protocolVersion)
|
||||
.then((status) => {
|
||||
if (serverData.lastSuccessfulRefresh && serverData.lastSuccessfulRefresh > refreshTime) {
|
||||
// Don't update if there was a more recent successful refresh
|
||||
return
|
||||
}
|
||||
serverData.lastSuccessfulRefresh = Date.now()
|
||||
serverData.status = status
|
||||
if (status.description) {
|
||||
serverData.rawMotd = status.description
|
||||
serverData.renderedMotd = autoToHTML(status.description)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
serverData.refreshing = false
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(`Refreshing addr ${address}`, protocolVersion, err)
|
||||
if (!protocolVersion?.legacy) {
|
||||
refreshServerData(serverData, { version: 74, legacy: true }, address)
|
||||
}
|
||||
})
|
||||
try {
|
||||
const status = await get_server_status(address, protocolVersion)
|
||||
if (serverData.lastSuccessfulRefresh && serverData.lastSuccessfulRefresh > refreshTime) {
|
||||
// Don't update if there was a more recent successful refresh
|
||||
return
|
||||
}
|
||||
serverData.lastSuccessfulRefresh = Date.now()
|
||||
serverData.status = status
|
||||
if (status.description) {
|
||||
serverData.rawMotd = status.description
|
||||
serverData.renderedMotd = autoToHTML(status.description)
|
||||
} else {
|
||||
delete serverData.rawMotd
|
||||
delete serverData.renderedMotd
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Refreshing addr ${address}`, protocolVersion, err)
|
||||
if (!protocolVersion?.legacy) {
|
||||
await refreshServerData(serverData, { version: 74, legacy: true }, address)
|
||||
return
|
||||
}
|
||||
if (!serverData.lastSuccessfulRefresh || serverData.lastSuccessfulRefresh <= refreshTime) {
|
||||
delete serverData.status
|
||||
delete serverData.rawMotd
|
||||
delete serverData.renderedMotd
|
||||
}
|
||||
} finally {
|
||||
serverData.refreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
export function refreshServers(
|
||||
@@ -414,15 +451,15 @@ export function refreshServers(
|
||||
}
|
||||
})
|
||||
|
||||
// noinspection ES6MissingAwait - handled with .then by refreshServerData already
|
||||
// noinspection ES6MissingAwait - handled by refreshServerData
|
||||
Object.keys(serverData).forEach((address) =>
|
||||
refreshServerData(serverData[address], protocolVersion, address),
|
||||
)
|
||||
}
|
||||
|
||||
export async function refreshWorld(worlds: World[], instancePath: string, worldPath: string) {
|
||||
export async function refreshWorld(worlds: World[], instanceId: string, worldPath: string) {
|
||||
const index = worlds.findIndex((w) => w.type === 'singleplayer' && w.path === worldPath)
|
||||
const newWorld = await get_singleplayer_world(instancePath, worldPath)
|
||||
const newWorld = await get_singleplayer_world(instanceId, worldPath)
|
||||
if (index !== -1) {
|
||||
worlds[index] = newWorld
|
||||
} else {
|
||||
@@ -432,13 +469,13 @@ export async function refreshWorld(worlds: World[], instancePath: string, worldP
|
||||
sortWorlds(worlds)
|
||||
}
|
||||
|
||||
export async function handleDefaultProfileUpdateEvent(
|
||||
export async function handleDefaultInstanceUpdateEvent(
|
||||
worlds: World[],
|
||||
instancePath: string,
|
||||
e: ProfileEvent,
|
||||
instanceId: string,
|
||||
e: InstanceEvent,
|
||||
) {
|
||||
if (e.event === 'world_updated') {
|
||||
await refreshWorld(worlds, instancePath, e.world)
|
||||
await refreshWorld(worlds, instanceId, e.world)
|
||||
}
|
||||
|
||||
if (e.event === 'server_joined') {
|
||||
@@ -456,9 +493,9 @@ export async function handleDefaultProfileUpdateEvent(
|
||||
}
|
||||
}
|
||||
|
||||
export async function refreshWorlds(instancePath: string): Promise<World[]> {
|
||||
const worlds = await get_profile_worlds(instancePath).catch((err) => {
|
||||
console.error(`Error refreshing worlds for instance: ${instancePath}`, err)
|
||||
export async function refreshWorlds(instanceId: string): Promise<World[]> {
|
||||
const worlds = await get_instance_worlds(instanceId).catch((err) => {
|
||||
console.error(`Error refreshing worlds for instance: ${instanceId}`, err)
|
||||
})
|
||||
if (worlds) {
|
||||
sortWorlds(worlds)
|
||||
@@ -489,7 +526,7 @@ export function hasWorldQuickPlaySupport(gameVersions: GameVersion[], currentVer
|
||||
return versionIndex !== -1 && targetIndex !== -1 && versionIndex <= targetIndex
|
||||
}
|
||||
|
||||
export type ProfileEvent = { profile_path_id: string } & (
|
||||
export type InstanceEvent = { instance_id: string } & (
|
||||
| {
|
||||
event: 'servers_updated'
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "إخفاء المزيد من الحالات قيد التشغيل"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "تم النسخ"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "نسخ التفاصيل"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "التجاهل"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "فتح المثيل"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "إعادة المحاولة"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "تم الإلغاء بسبب إغلاق التطبيق"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "تعذّر قراءة حزمة التعديلات"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "تم الإلغاء"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "لم تكتمل عملية التنظيف"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "تعذّر تنزيل الملفات"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "الملف الذي تم تنزيله تالف"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "تعذّر حفظ الملفات"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "لم يكتمل التنزيل"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "تعذّر العثور على المثيل"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "مسار الملف غير صالح"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "بيانات حزمة التعديلات غير صالحة"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "تحتوي ملفات حزمة التعديلات على بيانات وصفية غير صالحة"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "لم يكتمل إعداد Java"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "فشل إعداد أداة التحميل"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "تعذر تحديث البيانات المحلية"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "فشل إعداد Minecraft"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "لم أتمكن من الوصول إلى Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "لا يوجد إذن للكتابة"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "تعذر تنزيل الحزمة"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "حدث خطأ ما"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "مثيل غير معروف"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "عمليات التثبيت"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "إنشاء نسخة أساسية"
|
||||
},
|
||||
@@ -74,12 +155,63 @@
|
||||
"app.appearance-settings.hide-nametag.title": {
|
||||
"message": "إخفاء عرض الاسم"
|
||||
},
|
||||
"app.appearance-settings.jump-back-into-worlds.description": {
|
||||
"message": "يتضمن العوالم الحديثة في قسم \"العودة إلى اللعب\" على الصفحة الرئيسية."
|
||||
},
|
||||
"app.appearance-settings.jump-back-into-worlds.title": {
|
||||
"message": "العودة إلى العوالم"
|
||||
},
|
||||
"app.appearance-settings.minimize-launcher.description": {
|
||||
"message": "قم بتصغير نافذة المشغل عند بدء تشغيل عملية Minecraft."
|
||||
},
|
||||
"app.appearance-settings.minimize-launcher.title": {
|
||||
"message": "تصغير نافذة المشغل"
|
||||
},
|
||||
"app.appearance-settings.native-decorations.description": {
|
||||
"message": "استخدام إطار نافذة النظام (يتطلب إعادة تشغيل التطبيق)."
|
||||
},
|
||||
"app.appearance-settings.native-decorations.title": {
|
||||
"message": "الزخارف التقليدية"
|
||||
},
|
||||
"app.appearance-settings.select-option": {
|
||||
"message": "حدد خياراً"
|
||||
},
|
||||
"app.appearance-settings.show-play-time.description": {
|
||||
"message": "يعرض مقدار الوقت الذي قضيته في لعب إحدى المهام."
|
||||
},
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "إظهار مدة التشغيل"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "يتخطى تلقائيًا عمليات التأكيد ذات المخاطر المنخفضة، مثل تثبيت حزم التعديلات المكررة، وحذف المحتوى العادي، والتحديثات الجماعية، وإلغاء ربط حزم التعديلات، ومطالبات الإصلاح. وسيستمر عرض التحذيرات الخطيرة."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "تخطي التحذيرات غير الضرورية"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "يتيح إمكانية إظهار الشريط الجانبي أو إخفائه."
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.title": {
|
||||
"message": "تبديل الشريط الجانبي"
|
||||
},
|
||||
"app.appearance-settings.unknown-pack-warning.description": {
|
||||
"message": "إذا حاولت تثبيت ملف Modrinth Pack (.mrpack) غير مستضاف على Modrinth، فسنتأكد من أنك على دراية بالمخاطر قبل تثبيته."
|
||||
},
|
||||
"app.appearance-settings.unknown-pack-warning.title": {
|
||||
"message": "أخبرني قبل تثبيت حزم التعديلات غير المعروفة"
|
||||
},
|
||||
"app.auth-servers.unreachable.body": {
|
||||
"message": "قد تكون خوادم مصادقة ماينكرافت معطلة حاليًا. تحقق من اتصالك بالإنترنت وحاول مرة أخرى لاحقًا."
|
||||
},
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "تعذر الوصول إلى خوادم المصادقة"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "إضافة خادم إلى المثيل"
|
||||
},
|
||||
"app.browse.add-to-an-instance": {
|
||||
"message": "إضافة إلى مثيل"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "أضف للنموذج"
|
||||
},
|
||||
@@ -102,16 +234,19 @@
|
||||
"message": "استكشف خوادم"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "إخفاء الخوادم المضافة مسبقًا"
|
||||
"message": "إخفاء الخوادم التي تمت إضافتها بالفعل"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "حزم التعديل"
|
||||
},
|
||||
"app.browse.server-instance-content-warning": {
|
||||
"message": "قد تؤدي إضافة المحتوى إلى حدوث مشاكل في التوافق عند الاتصال بالخادم. كما سيُفقد أي محتوى تمت إضافته عند تحديث محتوى مثيل الخادم."
|
||||
},
|
||||
"app.browse.server.installing": {
|
||||
"message": "جاري التثبيت"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "تنزيل الحزم"
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "لا توجد إصدارات متاحة تتوافق مع {compatibilityLabel}. اختر إصدارًا لتثبيته على أي حال. لن يتم تثبيت التبعيات تلقائيًا."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "أدخل وصف التعديل..."
|
||||
@@ -128,15 +263,66 @@
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "إسم حزمة التعديل"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "أختيار الملفات التي سيتم تصديرها"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "رقم الإصدار"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "تنزيل المحتوى"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "تنزيل لعبة Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "تنزيل ملف الحزمة"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "استخراج التجاوزات"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "وضع اللمسات الأخيرة"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "في قائمة الانتظار للتثبيت"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "التحضير لـ Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "تنزيل Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "استخراج Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "جلب Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "التحضير لـ Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "التحقق من صحة إصدار Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "قراءة قائمة المحتويات"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "معالج التحميل"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "حل مشكلة Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "معالجة المحتوى"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "التراجع"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "تشغيل معالجات التحميل"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "سيتم حذف جميع البيانات الخاصة لنموذجك نهائيًا، بما في ذلك عوالمك والتكوينات وكل المحتوى المثبت."
|
||||
},
|
||||
@@ -161,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "النموذج"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "جاري تنزيل {current, number}/{total, number} مشروعًا..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "آخر المستجدات حول عملية التشطيب..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "تحديد الإصدارات..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "مشروع"
|
||||
},
|
||||
@@ -185,11 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "تصفح الخوادم"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "سيتم حذف '{name}' **نهائيا**, و لن هناك أي طريقة لاسترداده."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "حذف العالم"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "هل أنت متيقِّن من رغبتك بحذف هذا العالم نهائيا؟"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "حذف العالم"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "سيتم حذف هذا العالم نهائيًا من هذه النسخة. لا يمكن التراجع عن هذا الإجراء."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "حذف {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "معدّل"
|
||||
@@ -209,24 +410,21 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "لم تتم إضافة أي من الخوادم أو العوالم"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "ستتم إزالة '{name}' من قائمتك, إضافة لما داخل اللعبة, و لن يكون هناك أي طريقة لاسترداده."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "إزالة الخادم"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "ستتم إزالة '{name}' ({address}) من قائمتك, إضافة لما داخل اللعبة, و لن يكون هناك أي طريقة لاسترداده."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "إزالة الخادم"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "هل أنت متيقِّن من رغبتك في إزالة {name}؟"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "سيتم حذف هذا الخادم من قائمة الخوادم الخاصة بك ومن قائمة الخوادم داخل اللعبة. يمكنك إضافته مرة أخرى لاحقًا إذا كنت تعرف عنوانه."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "إزالة {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "ابحث بين ال{count} عوالم..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "هذا الخادم"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "المحتوى مطلوب"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "نزل للعب"
|
||||
},
|
||||
@@ -236,35 +434,38 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# تعديل} other {# تعديلات}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "حُزْمَة التعديل مطلوبة"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "يتطلب هذا الخادم تعديلات للعب. انقر فوق \"تثبيت\" لإعداد الملفات المطلوبة من Modrinth، ثم قم بتشغيله مباشرة إلى الخادم."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "النماذج المشتركة"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "نماذج الخادم مشتركة"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "عرض المحتويات"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "حدث للعب"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "يلزم التحديث"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "هناك تحديث مطلوب للعب بـ {name}. الرجاء التحديث إلى أحدث اصدار لتشغيل اللعبة."
|
||||
},
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "هذا المشروع مُثبَّت بالفعل"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "تغيير الإصدار"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "العودة إلى الاستكشاف"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "تثبيت المحتويات الى النموذج"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "جميع الإصدارات"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "التنزيل من المتصفح"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "التثبيت"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "مثبت بالفعل"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "تم تفعيل وضع المطوّر."
|
||||
@@ -308,6 +509,12 @@
|
||||
"app.skins.delete-modal.title": {
|
||||
"message": "هل أنت متأكد من حذف المظهر هذا؟"
|
||||
},
|
||||
"app.skins.dropped-file-error.text": {
|
||||
"message": "فشل قراءة الملف الذي تم إسقاطه."
|
||||
},
|
||||
"app.skins.dropped-file-error.title": {
|
||||
"message": "حدث خطأ أثناء معالجة الملف"
|
||||
},
|
||||
"app.skins.edit-button": {
|
||||
"message": "تعديل المظهر"
|
||||
},
|
||||
@@ -317,6 +524,15 @@
|
||||
"app.skins.modal.add-title": {
|
||||
"message": "إضافة المظهر"
|
||||
},
|
||||
"app.skins.modal.arm-style-section": {
|
||||
"message": "طراز الأذرع"
|
||||
},
|
||||
"app.skins.modal.arm-style-slim": {
|
||||
"message": "نحيف"
|
||||
},
|
||||
"app.skins.modal.arm-style-wide": {
|
||||
"message": "عريض"
|
||||
},
|
||||
"app.skins.modal.cape-fallback-name": {
|
||||
"message": "رداء"
|
||||
},
|
||||
@@ -335,12 +551,18 @@
|
||||
"app.skins.modal.none-cape-option": {
|
||||
"message": "لا شيء"
|
||||
},
|
||||
"app.skins.modal.replace-texture-button": {
|
||||
"message": "استبدال النسيج"
|
||||
},
|
||||
"app.skins.modal.save-skin-button": {
|
||||
"message": "حفظ المظهر"
|
||||
},
|
||||
"app.skins.modal.saving-tooltip": {
|
||||
"message": "حفظ..."
|
||||
},
|
||||
"app.skins.modal.texture-section": {
|
||||
"message": "النسيج"
|
||||
},
|
||||
"app.skins.modal.upload-skin-first-tooltip": {
|
||||
"message": "أرفع المظهر أولا !"
|
||||
},
|
||||
@@ -350,9 +572,69 @@
|
||||
"app.skins.previewing-badge": {
|
||||
"message": "أستعراض"
|
||||
},
|
||||
"app.skins.rate-limit.text": {
|
||||
"message": "أنت تقوم بتغيير مظهرك بشكل متكرر جدًّا. وقد قامت خوادم Mojang بحظر الطلبات الإضافية مؤقتًا. يرجى الانتظار قليلاً قبل إعادة المحاولة."
|
||||
},
|
||||
"app.skins.rate-limit.title": {
|
||||
"message": "تمهل !"
|
||||
},
|
||||
"app.skins.reorder-error.text": {
|
||||
"message": "تعذر حفظ طلبك المتعلق بشكل الشخصية."
|
||||
},
|
||||
"app.skins.reorder-error.title": {
|
||||
"message": "فشل إعادة ترتيب أشكال الشخصيات"
|
||||
},
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "البناة والبيئات الحيوية"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "الفوضى المربعة"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "انطلق نحو السماء"
|
||||
},
|
||||
"app.skins.section.default-skins": {
|
||||
"message": "شكل الشخصية الافتراضية"
|
||||
},
|
||||
"app.skins.section.minecon-earth-2017": {
|
||||
"message": "MINECON Earth 2017"
|
||||
},
|
||||
"app.skins.section.modrinth": {
|
||||
"message": "Modrinth"
|
||||
},
|
||||
"app.skins.section.modrinth-pride": {
|
||||
"message": "فخر Modrinth"
|
||||
},
|
||||
"app.skins.section.modrinth-pride.tooltip": {
|
||||
"message": "لقد حصلت على هذه أشكال الشخصيات مقابل تبرعك لحملة جمع التبرعات التي نظمتها Modrinth Pride خلال شهر الفخر."
|
||||
},
|
||||
"app.skins.section.mounts-of-mayhem": {
|
||||
"message": "جبال الفوضى"
|
||||
},
|
||||
"app.skins.section.saved-skins": {
|
||||
"message": "المظاهر المحفوظة"
|
||||
},
|
||||
"app.skins.section.striding-hero": {
|
||||
"message": "البطل السائر بخطوات واسعة"
|
||||
},
|
||||
"app.skins.section.the-copper-age": {
|
||||
"message": "العصر النحاسي"
|
||||
},
|
||||
"app.skins.section.the-garden-awakens": {
|
||||
"message": "الحديقة تستيقظ"
|
||||
},
|
||||
"app.skins.section.tiny-takeover": {
|
||||
"message": "الاستحواذ الصغير"
|
||||
},
|
||||
"app.skins.sign-in.button": {
|
||||
"message": "تسجيل الدخول"
|
||||
},
|
||||
"app.skins.sign-in.description": {
|
||||
"message": "يرجى تسجيل الدخول إلى حسابك في Minecraft لاستخدام ميزات إدارة أشكال الشخصيات في تطبيق Modrinth."
|
||||
},
|
||||
"app.skins.sign-in.rinthbot-alt": {
|
||||
"message": "روبوت Modrinth المتحمس"
|
||||
},
|
||||
"app.skins.sign-in.title": {
|
||||
"message": "الرجاء تسجيل الدخول"
|
||||
},
|
||||
@@ -377,6 +659,9 @@
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "اكتمل التنزيل"
|
||||
},
|
||||
"app.update-popup.reload": {
|
||||
"message": "أعد التحميل للتحديث"
|
||||
},
|
||||
"app.update-popup.title": {
|
||||
"message": "تحديث متاح"
|
||||
},
|
||||
@@ -575,6 +860,30 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "الاسم"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel": {
|
||||
"message": "تحديث القناة"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha": {
|
||||
"message": "نسخة أولية"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha.description": {
|
||||
"message": "ستظهر الإصدارات النهائية والإصدارات التجريبية والإصدارات الأولية كـ«تحديثات متاحة»."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "بيتا"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta.description": {
|
||||
"message": "ستظهر الإصدارات النهائية والإصدارات التجريبية كـ«تحديثات متاحة»."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release": {
|
||||
"message": "إصدار ثابت"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release.description": {
|
||||
"message": "لن تظهر سوى الإصدارات النهائية ضمن التحديثات المتاحة."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.select": {
|
||||
"message": "اختر قناة التحديث"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "إجراءات تشغيل إضافية"
|
||||
},
|
||||
@@ -623,6 +932,24 @@
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "جافا والذاكرة"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-environment-variables": {
|
||||
"message": "متغيرات البيئة المخصصة"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-java-arguments": {
|
||||
"message": "معلمات Java المخصصة"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-java-installation": {
|
||||
"message": "تثبيت Java المخصص"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-memory-allocation": {
|
||||
"message": "تخصيص الذاكرة حسب الطلب"
|
||||
},
|
||||
"instance.settings.tabs.java.enter-environment-variables": {
|
||||
"message": "أدخل المتغيرات البيئية..."
|
||||
},
|
||||
"instance.settings.tabs.java.enter-java-arguments": {
|
||||
"message": "أدخل معلمات Java..."
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "المتغيرات البيئية"
|
||||
},
|
||||
@@ -680,6 +1007,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "نسخ العنوان"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "إنشاء اختصار"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "عدم العرض في الصفحة الرئيسية"
|
||||
},
|
||||
@@ -719,6 +1049,12 @@
|
||||
"minecraft-account.label": {
|
||||
"message": "حساب ماينكرافت"
|
||||
},
|
||||
"minecraft-account.not-signed-in": {
|
||||
"message": "لم يتم تسجيل الدخول"
|
||||
},
|
||||
"minecraft-account.remove-account": {
|
||||
"message": "حذف الحساب"
|
||||
},
|
||||
"minecraft-account.select-account": {
|
||||
"message": "اختيار الحساب"
|
||||
},
|
||||
@@ -748,8 +1084,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "يتم توفير المحمّل من قبل الخادم"
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "لا تعرض هذا التحذير مجددا"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,27 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Skrýt více spuštěných instancí"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Zkopírováno"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Zavřít"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Otevřít instanci"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Zkusit znovu"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Zrušeno"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Neznámá instance"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Instalace"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Nastavit jako primární instanci"
|
||||
},
|
||||
@@ -33,7 +54,7 @@
|
||||
"message": "Zastavit instanci"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "Aktualizace"
|
||||
"message": "Aktualizovat"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "Zobrazit probíhající stahování"
|
||||
@@ -101,8 +122,14 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Zobrazit odehraný čas"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Automaticky přeskočí nízko riziková potrvzení jako duplicitní instalace modpacků, běžné mazání obsahu, hromadné aktualizace, odpojování modpacků a výzvy k opravě. Nebezpečná upozornění se budou nadále zobrazovat."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Přeskočit nedůležitá upozornění"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Umožní přepínat zobrazení postranního panelu."
|
||||
"message": "Umožňí přepínat zobrazení postranního panelu."
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.title": {
|
||||
"message": "Přepnout postranní panel"
|
||||
@@ -141,13 +168,10 @@
|
||||
"message": "Zpět k instanci"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Objevovat obsah"
|
||||
"message": "Objevit obsah"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Objevovat servery"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Skrýt již přidané servery"
|
||||
"message": "Objevit servery"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacky"
|
||||
@@ -159,13 +183,7 @@
|
||||
"message": "Instalování"
|
||||
},
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Žádná dostupná verze se neshoduje s verzí {compatibilityLabel}. Vyber verzi, abys ji i přesto nainstaloval/a. Závislosti nebudou automaticky nainstalovány."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Probíhá instalace modpacku..."
|
||||
"message": "Žádné dostupné verze se neshodují s {compatibilityLabel}. Vyberte verzi, kterou chcete přesto nainstalovat. Závislosti nebudou nainstalovány automaticky."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Zadej popis modpacku..."
|
||||
@@ -176,24 +194,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportovat modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Zahrnout \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Název modpacku"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Název modpacku"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Nastavte, které soubory mají být do tohoto exportu zahrnuty"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Číslo verze"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Stahování obsahu"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Stahování Minecraftu"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Stahování pack souboru"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Rozbalování souborů overrides"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Dokončení instalace"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Ve frontě na instalaci"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Příprava Javy"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Stahování Javy {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Rozbalování Javy {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Získávání Javy {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Připravení Javy {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validace Javy {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Čtení pack manifestu"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Vyhodnocování loaderu"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Vyhodnocování Minecraftu"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Vyhodnocování obsahu"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Obnovování do předchozího stavu"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Spuštění loader procesů"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Všechna data tvé instance budou trvale smazána, včetně světů, konfigurací a veškerého nainstalovaného obsahu."
|
||||
},
|
||||
@@ -201,7 +267,7 @@
|
||||
"message": "Tato akce nemůže být vrácena"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Odstranit instanci"
|
||||
"message": "Smazat instanci"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Odstranění instance"
|
||||
@@ -218,6 +284,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Stahování {current, number}/{total, number} projektů..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Dokončení aktualizace..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Vyhodnocování verzí..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
@@ -242,14 +317,20 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Procházet servery"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' bude **navždy smazán** a nebude možné jej obnovit."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Smazat svět"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Jsi si jistý, že chceš trvale smazat tento svět?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Smazat svět"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Tento svět bude trvale smazán z této instance. Tuto akci nelze vrátit zpět."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Mazání {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Módovaný"
|
||||
"message": "Módované"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
@@ -261,29 +342,26 @@
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Přidej server nebo začni procházet"
|
||||
"message": "Začněte přidáním serveru nebo procházením obsahu"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Žádné servery nebo světy nebyly přidány"
|
||||
"message": "Nejsou přidané žádné servery nebo světy"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' bude odstraněn z tvého seznamu i ze hry a nebude možné jej obnovit."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Odebrat server"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) bude odstraněn z tvého seznamu i ze hry a nebude možné jej obnovit."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Odebrat server"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Opravdu chceš odstranit {name}?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Tento server bude odebrán z vašeho seznamu serverů i ze seznamu serverů ve hře. Pokud znáte jeho adresu, můžete ho později znovu přidat."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Odebírání {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Hledat v {count} světech..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "tento server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Požadovaný obsah"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Nainstaluj pro hraní"
|
||||
},
|
||||
@@ -293,38 +371,35 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mód} few {# módy} other {# módů}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Požadovaný modpack"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Tento server k hraní vyžaduje módy. Klikni na instalovat pro získání potřebných módů z Modrinth a poté se rovnou připoj na server."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Sdílená instance"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Sdílená serverová instance"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Zobrazit obsah"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualizuj pro hraní"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Je vyžadována aktualizace"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Pro hraní {name} je vyžadována aktualizace. Prosím aktualizuj na nejnovější verzi, abys mohl hru spustit."
|
||||
},
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Tento projekt je již nainstalován"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Změnit verzi"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Zpět k Objevování"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Nainstalovat obsah do instance"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Všechny verze"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Stáhnout v prohlížeči"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Již staženo"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Vývojářský režim povolen."
|
||||
@@ -363,7 +438,7 @@
|
||||
"message": "Smazat skin"
|
||||
},
|
||||
"app.skins.delete-modal.description": {
|
||||
"message": "Tahle akce navždy smaže vybraný skin a nejde vrátit zpět."
|
||||
"message": "Tímto dojde k trvalému smazání vybreného skinu. Tuto akci nelze vrátit zpět."
|
||||
},
|
||||
"app.skins.delete-modal.title": {
|
||||
"message": "Opravdu chceš smazat tenhle skin?"
|
||||
@@ -446,6 +521,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -492,19 +570,19 @@
|
||||
"message": "Nadšený Modrinth Bot"
|
||||
},
|
||||
"app.skins.sign-in.title": {
|
||||
"message": "Přihlas se prosím"
|
||||
"message": "Přihlaš se prosím"
|
||||
},
|
||||
"app.skins.title": {
|
||||
"message": "Výběr skinu"
|
||||
},
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Stahování aplikace Modrinth v{version} bylo dokončeno. Aktualizujte ji znovunačtením nebo se automaticky aktualizuje po zavření."
|
||||
"message": "Stahování Modrinth App v{version} bylo dokončeno. Aktualizujte ji znovunačtením nebo se automaticky aktualizuje po zavření."
|
||||
},
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Aplikace Modrinth v{version} je k dispozici. Aktualizujte ji pomocí svého správce balíčků, abyste získali nejnovější funkce a opravy!"
|
||||
"message": "Modrinth App v{version} je k dispozici. Aktualizujte ji pomocí svého správce balíčků, abyste získali nejnovější funkce a opravy!"
|
||||
},
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Aplikace Modrinth v{version} je nyní k dispozici! Protože jste v měřené síti, nebyla stažena automaticky."
|
||||
"message": "Modrinth App v{version} je nyní k dispozici! Protože jste v měřené síti, nebyla stažena automaticky."
|
||||
},
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Seznam změn"
|
||||
@@ -717,13 +795,13 @@
|
||||
"message": "Jméno"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel": {
|
||||
"message": "Aktualizační kanál"
|
||||
"message": "Kanál aktualizací"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha": {
|
||||
"message": "Alfa"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha.description": {
|
||||
"message": "Vydané, beta a alfa verze se zobrazí jako dostupné aktualizace."
|
||||
"message": "Verze typu release, beta a alpha se budou zobrazovat jako dostupné aktualizace."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "Beta"
|
||||
@@ -863,6 +941,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopírovat adresu"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Vytvořit záložku"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nezobrazovat na domovské stránce"
|
||||
},
|
||||
@@ -937,26 +1018,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader zprostředkovává server"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Soubor je zkontrolován pouze v případě, že je nahrán na Modrinth, bez ohledu na jeho formát (včetně formátu .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Toto varování znovu nezobrazovat"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Potvrdit instalaci"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Přesto nainstalovat"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Malware se často šíří prostřednictvím souborů s modpacky, které se sdílejí na platformách jako Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Tento soubor jsme na Modrinthu nenašli. Důrazně doporučujeme instalovat pouze soubory z důvěryhodných zdrojů."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Upozornění na neznámý soubor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,18 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Gem flere kørende instances"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Tilsidesæt"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Åben instance"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Prøv igen"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Ukendt instance"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Gør til primære instance"
|
||||
},
|
||||
@@ -141,7 +153,7 @@
|
||||
"message": "Opdag servere"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Gem allerede tilføjet til servere"
|
||||
"message": "Gem servere som allerede er tilføjet"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
@@ -155,12 +167,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Ingen tilgængelige versioner passer til {compatibilityLabel}. Vælg en version for at installere. Afhængigheder bliver ikke installeret automatisk."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Installere modpack..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Indtast modpack beskrivelse..."
|
||||
},
|
||||
@@ -170,24 +176,27 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Eksporter modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Inkludere \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpack Navn"
|
||||
"message": "Modpack navn"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpack navn"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Konfigurer hvilke filer inkludere i denne eksport"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versionsnummer"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Downloader indhold"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Downloader Minecraft"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Downloader Java {version}"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Al' data for din instance vil blive permanent slettet, dette inkludere dine verdener, konfigurationer, og alt installeret indhold."
|
||||
},
|
||||
@@ -212,6 +221,9 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Downloader {current, number}/{total, number} projekter..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
@@ -236,9 +248,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Søg servere"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Er du sikker på din vil slette denne verden permanent?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Moddet"
|
||||
},
|
||||
@@ -257,18 +266,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Ingen servere eller verdener tilføjet"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Er du sikker på din vil fjerne {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Søg {count} verdener..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "denne server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Indhold krævet"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installer for at spille"
|
||||
},
|
||||
@@ -278,27 +278,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack krævet"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Denne server kræver mods for at spille. Tryk på installer for at sætte de krævet filler fra modrinth op, så lancer direkte til serveren."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Delt instance"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Delt server instance"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Vis indhold"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Opdater for at spille"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Opdatering krævet"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "En opdatering er krævet for at spille {name}. Venligst opdater til den seneste version for at køre spillet."
|
||||
},
|
||||
@@ -308,8 +296,8 @@
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Tilbage til udforsk"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Installer indhold til instance"
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Allerede installeret"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Udvikler-tilstand aktiveret."
|
||||
@@ -416,6 +404,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -485,6 +476,9 @@
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Download færdiggjort"
|
||||
},
|
||||
"app.update-popup.reload": {
|
||||
"message": "Genindlæs for at opdater"
|
||||
},
|
||||
"app.update-popup.title": {
|
||||
"message": "Opdatering tilgængelig"
|
||||
},
|
||||
@@ -683,6 +677,12 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Navn"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha": {
|
||||
"message": "Alpha"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "Beta"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Startkommandoer"
|
||||
},
|
||||
@@ -865,20 +865,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader er givet af serveren"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "En fil behandles kun, hvis den uploades til Modrinth, uanset filformat (herunder .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Vis ikke denne advarsel igen"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Bekræft installation"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Installer alligevel"
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Ukendt fil advarsel"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Weitere laufende Instanzen ausblenden"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Kopiert"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Details kopieren"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Ignorieren"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Instanz öffnen"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Wiederholen"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Aufgrund von Schließung der App abgebrochen"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Modpack konnte nicht gelesen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Abgebrochen"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "Bereinigung konnte nicht abgeschlossen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Dateien konnte nicht heruntergeladen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Heruntergeladene Datei ist beschädigt"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Dateien konnten nicht gespeichert werden"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Download konnte nicht abgeschlossen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "Instanz konnte nicht gefunden werden"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "Dateipfad ist ungültig"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Daten des Modpacks sind ungültig"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Dateien des Modpacks enthalten ungültige Metadaten"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Die Einrichtung von Java konnte nicht abgeschlossen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Einrichtung des Loaders ist fehlgeschlagen"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Lokale Daten konnten nicht aktualisiert werden"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Einrichtung von Minecraft ist fehlgeschlagen"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Modrinth konnte nicht erreicht werden"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Keine Berechtigung zum Schreiben"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Das Pack konnte nicht heruntergeladen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Irgendwas ist schiefgelaufen"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Unbekannte Instanz"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installationen"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Zur primären Instanz machen"
|
||||
},
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Spielzeit anzeigen"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Bestätigungen mit geringem Risiko, wie z. B. die Installation doppelter Modpacks, das Löschen normaler Inhalte, Massenaktualisierungen, das Aufheben von Verknüpfungen zu Modpacks und Reparaturaufrufe, werden automatisch übersprungen. Gefährliche Warnungen werden weiterhin angezeigt."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Unwichtige Warnungen überspringen"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Ermöglicht das Umschalten der Seitenleiste."
|
||||
},
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Keine verfügbaren Versionen stimmen mit {compatibilityLabel} überein. Wähle eine Version aus, um sie trotzdem zu installieren. Abhängigkeiten werden nicht automatisch installiert."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Modpack wird installiert..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Modpaketbeschreibung eingeben..."
|
||||
},
|
||||
@@ -176,24 +257,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Modpack exportieren"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "\"{file}\" einschliessen?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpaketname"
|
||||
"message": "Name des Modpacks"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpaketname"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Konfiguriere, welche Dateien in diesem Export miteinbezogen werden"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versionsnummer"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Inhalte werden heruntergeladen"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Minecraft wird heruntergeladen"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Paketdatei wird herunterladen"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Überschreibungen werden extrahiert"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Wird finalisiert"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Installation in Warteschlange"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Java wird vorbereitet"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Java {version} wird heruntergeladen"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Java {version} wird extrahiert"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Java {version} wird abgerufen"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Java {version} wird vorbereitet"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Java {version} wird validiert"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Paketmanifest wird gelesen"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Loader wird ermittelt"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Minecraft wird ermittelt"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Inhalte werden ermittelt"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Wird rückgängig gemacht"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Loader-Prozesse werden ausgeführt"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle Daten deiner Instanz werden permanent gelöscht, inlusive deiner Welten, Konfigurationen und allen installierten Inhalten."
|
||||
},
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instanz"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "{current, number}/{total, number} Projekte werden heruntergeladen..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Update wird fertiggestellt..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Versionen werden ermittelt..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "Projekt"
|
||||
},
|
||||
@@ -242,8 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Server durchsuchen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Möchtest du diese Welt wirklich endgültig löschen?"
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Welt löschen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Welt löschen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Diese Welt wird permanent von dieser Instanz gelöscht. Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Lösche {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modifiziert"
|
||||
@@ -263,38 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Keine Server oder Welten hinzugefügt"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Möchtest du {name} wirklich entfernen?"
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Server entfernen"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Server entfernen"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Dieser Server wird aus deiner Serverliste und aus der Serverliste im Spiel entfernt. Du kannst ihn später wieder hinzufügen, wenn du die Adresse kennst."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Entferne {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Durchsuche {count} Welten..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "dieser Server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Inhalte benötigt"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Nicht Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installieren zum Spielen"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Trotzdem Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Diese Einladung wurde von einem anderen Modrinth-Nutzer erstellt, nicht von Modrinth. Nimm nur Einladungen von Personen an, denen du vertraust."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# Mod} other {# Mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Benötigtes Modpack"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Dieser Server benötigt Mods zum spielen. Klicke auf Installieren um die nötigen Dateien von Modrinth herunterzuladen und dannach direkt dem Server beizutreten."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Eine Datei wird nur geprüft, wenn sie auf Modrinth veröffentlicht wird, unabhängig von ihrem Dateiformat (auch .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Geteilte Instanz"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Geteilte Server Instanz"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Dieses Server-Modpack enthält Dateien, die nicht auf Modrinth veröffentlicht sind. Wir empfehlen dringend, nur Dateien aus vertrauenswürdigen Quellen zu installieren."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Warnung vor unbekannten Dateien"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Nicht erkannte Dateien"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Inhalte ansehen"
|
||||
@@ -302,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualisieren zum Spielen"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aktualisierung benötigt"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Eine aktualisierung zum spielen von {name} ist benötigt. Bitte aktualisiere auf die neuste Version um das Spiel zu starten."
|
||||
@@ -311,11 +473,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Dieses Projekt ist bereits installiert"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Version wechseln"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Zurück zu Entdecken"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Inhalt in Instanz installieren"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Alle Versionen"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Im Browser herunterladen"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Bereits installiert"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Entwicklermodus aktiviert."
|
||||
@@ -437,6 +611,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -854,6 +1031,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Adresse kopieren"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Shortcut erstellen"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nicht auf Startseite anzeigen"
|
||||
},
|
||||
@@ -928,26 +1108,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader wird vom Server bereitgestellt"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Eine Datei wird nur geprüft, wenn sie auf Modrinth hochgeladen wird, unabhängig von ihrem Dateiformat (auch .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Diese Warnung nicht mehr anzeigen"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Installation bestätigen"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Trotzdem installieren"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Schadsoftware wird häufig über Modpack-Dateien verbreitet, indem diese auf Plattformen wie Discord geteilt werden."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Wir konnten diese Datei auf Modrinth nicht finden. Wir empfehlen dringend, nur Dateien aus vertrauenswürdigen Quellen zu installieren."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Warnung vor unbekannter Datei"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Weitere laufende Instanzen ausblenden"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Kopiert"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Details kopieren"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Ausblenden"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Instanz öffnen"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Erneut versuchen"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Aufgrund von Schließung der App abgebrochen"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Modpack konnte nicht gelesen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Abgebrochen"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "Bereinigung konnte nicht abgeschlossen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Dateien konnte nicht heruntergeladen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Heruntergeladene Datei ist beschädigt"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Dateien konnten nicht gespeichert werden"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Download konnte nicht abgeschlossen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "Instanz konnte nicht gefunden werden"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "Dateipfad ist ungültig"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Daten des Modpacks sind ungültig"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Dateien des Modpacks enthalten ungültige Metadaten"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Die Einrichtung von Java konnte nicht abgeschlossen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Einrichtung des Loaders ist fehlgeschlagen"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Lokale Daten konnten nicht aktualisiert werden"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Einrichtung von Minecraft ist fehlgeschlagen"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Modrinth konnte nicht erreicht werden"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Keine Berechtigung zum Schreiben"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Das Pack konnte nicht heruntergeladen werden"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Irgendwas ist schiefgelaufen"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Unbekannte Instanz"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installationen"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Zur primären Instanz machen"
|
||||
},
|
||||
@@ -87,7 +168,7 @@
|
||||
"message": "Launcher minimieren"
|
||||
},
|
||||
"app.appearance-settings.native-decorations.description": {
|
||||
"message": "Fensterdekorationen des Systems verwenden (Neustart der App erforderlich)."
|
||||
"message": "Fensterrahmen des Systems verwenden (Neustart der App erforderlich)."
|
||||
},
|
||||
"app.appearance-settings.native-decorations.title": {
|
||||
"message": "Native Dekorationen"
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Spielzeit anzeigen"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Bestätigungen mit geringem Risiko, wie z. B. die Installation doppelter Modpacks, das Löschen normaler Inhalte, Massenaktualisierungen, das Aufheben von Verknüpfungen zu Modpacks und Reparaturaufrufe, werden automatisch übersprungen. Gefährliche Warnungen werden weiterhin angezeigt."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Unwichtige Warnungen überspringen"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Ermöglicht das Umschalten der Seitenleiste."
|
||||
},
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Keine verfügbaren Versionen stimmen mit {compatibilityLabel} überein. Wähle eine Version aus, um sie trotzdem zu installieren. Abhängigkeiten werden nicht automatisch installiert."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Modpack wird installiert..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Beschreibung des Modpacks eingeben..."
|
||||
},
|
||||
@@ -176,17 +257,11 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Modpack exportieren"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "\"{file}\" einschließen?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpackname"
|
||||
"message": "Name des Modpacks"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpackname"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Konfiguriere, welche Dateien in diesen Export enthalten sind"
|
||||
"message": "Name des Modpacks"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versionsnummer"
|
||||
@@ -194,6 +269,60 @@
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Inhalte werden heruntergeladen"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Minecraft wird heruntergeladen"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Paketdatei wird herunterladen"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Überschreibungen werden extrahiert"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Wird finalisiert"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Installation in Warteschlange"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Java wird vorbereitet"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Java {version} wird heruntergeladen"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Java {version} wird extrahiert"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Java {version} wird abgerufen"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Java {version} wird vorbereitet"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Java {version} wird validiert"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Paketmanifest wird gelesen"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Loader wird ermittelt"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Minecraft wird ermittelt"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Inhalte werden ermittelt"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Wird rückgängig gemacht"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Loader-Prozesse werden ausgeführt"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle Daten deiner Instanz werden permanent gelöscht, einschließlich deiner Welten, Konfigurationen und allen installierten Inhalten."
|
||||
},
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instanz"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "{current, number}/{total, number} Projekte werden heruntergelanden..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Update wird fertiggestellt..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Versionen werden ermittelt..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "Projekt"
|
||||
},
|
||||
@@ -242,8 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Server durchsuchen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Möchtest du diese Welt wirklich endgültig löschen?"
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Welt löschen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Welt löschen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Die Welt wird permanent von der Instanz gelöscht. Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "{name} wird gelöscht"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modifiziert"
|
||||
@@ -263,38 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Keine Server oder Welten hinzugefügt"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Möchtest du {name} wirklich entfernen?"
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Server entfernen"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Server entfernen"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Dieser Server wird aus deiner Serverliste und aus der Serverliste im Spiel entfernt. Du kannst ihn später wieder hinzufügen, wenn du die Adresse kennst."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "{name} wird entfernt"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Durchsuche {count} Welten..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "dieser Server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Inhalte benötigt"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Nicht Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installieren zum Spielen"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Trotzdem Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Diese Einladung wurde von einem anderen Modrinth-Nutzer erstellt, nicht von Modrinth. Nimm nur Einladungen von Personen an, denen du vertraust."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# Mod} other {# Mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Benötigtes Modpack"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Dieser Server benötigt Mods zum Spielen. Klicke auf Installieren um die nötigen Dateien von Modrinth herunterzuladen und danach direkt dem Server beizutreten."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Eine Datei wird nur geprüft, wenn sie auf Modrinth veröffentlicht wird, unabhängig von ihrem Dateiformat (auch .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Geteilte Instanz"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Geteilte Serverinstanz"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Dieses Server-Modpack enthält Dateien, die nicht auf Modrinth veröffentlicht sind. Wir empfehlen dringend, nur Dateien aus vertrauenswürdigen Quellen zu installieren."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Warnung vor unbekannten Dateien"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Nicht erkannte Dateien"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Inhalte ansehen"
|
||||
@@ -302,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualisieren zum Spielen"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aktualisierung erforderlich"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Zum Spielen von {name} ist eine Aktualisierung erforderlich. Bitte aktualisiere auf die neueste Version, um das Spiel zu starten."
|
||||
@@ -311,11 +473,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Dieses Projekt ist bereits installiert"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Version wechseln"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Zurück zum Entdecken"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Inhalt in Instanz installieren"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Alle Versionen"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Im Browser herunterladen"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Bereits installiert"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Entwicklermodus aktiviert."
|
||||
@@ -437,6 +611,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -489,7 +666,7 @@
|
||||
"message": "Skin-Auswahl"
|
||||
},
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Neu laden, um jetzt zu aktualisieren, oder automatisch aktualisieren, wenn du die Modrinth App schließt."
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Jetzt neu laden, um sofort zu aktualisieren, oder beim Schließen der Modrinth-App automatisch aktualisieren."
|
||||
},
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} ist verfügbar. Verwende deinen Paketmanager, um die neuesten Funktionen und Fehlerbehebungen zu installieren!"
|
||||
@@ -522,7 +699,7 @@
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Wählen eine Option"
|
||||
"message": "Wähle eine Option"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Inkompatible Version {version}"
|
||||
@@ -854,6 +1031,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Adresse kopieren"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Verknüpfung erstellen"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nicht auf der Startseite anzeigen"
|
||||
},
|
||||
@@ -928,26 +1108,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader vom Server vorgegeben"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Eine Datei wird nur geprüft, wenn sie auf Modrinth hochgeladen wird, unabhängig von ihrem Dateiformat (auch .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Diese Warnung nicht mehr anzeigen"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Installation bestätigen"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Trotzdem installieren"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Schadsoftware wird häufig über Modpack-Dateien verbreitet, indem diese auf Plattformen wie Discord geteilt werden."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Wir konnten diese Datei auf Modrinth nicht finden. Wir empfehlen dringend, nur Dateien aus vertrauenswürdigen Quellen zu installieren."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Warnung vor unbekannter Datei"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Hide more running instances"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Copied"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Copy details"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Dismiss"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Open instance"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Retry"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Canceled due to app closing"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Couldn't read modpack"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Canceled"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "Cleanup didn't finish"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Couldn't download files"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Downloaded file is corrupt"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Couldn't save files"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Download couldn't finish"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "Instance couldn't be found"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "File path is invalid"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Modpack data invalid"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Modpack files have invalid metadata"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Java setup couldn't finish"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Loader setup failed"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Couldn't update local data"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Minecraft setup failed"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Couldn't reach Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "No permission to write"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Couldn't download pack"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Something went wrong"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Unknown instance"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installs"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Make primary instance"
|
||||
},
|
||||
@@ -44,6 +125,21 @@
|
||||
"app.action-bar.view-logs": {
|
||||
"message": "View logs"
|
||||
},
|
||||
"app.ads-consent.accept": {
|
||||
"message": "Accept all"
|
||||
},
|
||||
"app.ads-consent.body": {
|
||||
"message": "Ads make Modrinth possible and fund creator payouts. Our partners may store or access cookies in the app to personalize ads and measure performance."
|
||||
},
|
||||
"app.ads-consent.manage": {
|
||||
"message": "Manage preferences"
|
||||
},
|
||||
"app.ads-consent.reject": {
|
||||
"message": "Reject all"
|
||||
},
|
||||
"app.ads-consent.title": {
|
||||
"message": "Your privacy and how ads support Modrinth"
|
||||
},
|
||||
"app.appearance-settings.advanced-rendering.description": {
|
||||
"message": "Enables advanced rendering such as blur effects that may cause performance issues without hardware-accelerated rendering."
|
||||
},
|
||||
@@ -101,6 +197,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Show play time"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Automatically skips low-risk confirmations like duplicate modpack installs, normal content deletion, bulk updates, unlinking modpacks, and repair prompts. Dangerous warnings will still be shown."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Skip non-essential warnings"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Enables the ability to toggle the sidebar."
|
||||
},
|
||||
@@ -147,7 +249,7 @@
|
||||
"message": "Discover servers"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Hide already added servers"
|
||||
"message": "Hide servers already added"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
@@ -161,12 +263,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "No available versions match {compatibilityLabel}. Select a version to install anyway. Dependencies will not be installed automatically."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Installing modpack..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Enter modpack description..."
|
||||
},
|
||||
@@ -176,24 +272,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Export modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Include \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpack Name"
|
||||
"message": "Modpack name"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpack name"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Configure which files are included in this export"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Version number"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Downloading content"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Downloading Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Downloading pack file"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Extracting overrides"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Finalizing"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Queued to install"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Preparing Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Downloading Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Extracting Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Fetching Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Preparing Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validating Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Reading pack manifest"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Resolving loader"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Resolving Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Resolving content"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Rolling back"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Running loader processors"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "All data for your instance will be permanently deleted, including your worlds, configs, and all installed content."
|
||||
},
|
||||
@@ -218,6 +362,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Downloading {current, number}/{total, number} projects..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Finishing update..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Resolving versions..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "project"
|
||||
},
|
||||
@@ -242,11 +395,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Browse servers"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' will be **permanently deleted**, and there will be no way to recover it."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Delete world"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Are you sure you want to permanently delete this world?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Delete world"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "This world will be permanently deleted from this instance. This action cannot be undone."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Deleting {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modded"
|
||||
@@ -266,44 +425,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "No servers or worlds added"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' will be removed from your list, including in-game, and there will be no way to recover it."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Remove server"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) will be removed from your list, including in-game, and there will be no way to recover it."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Remove server"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Are you sure you want to remove {name}?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "This server will be removed from your server list and from the in-game server list. You can add it again later if you know the address."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Removing {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Search {count} worlds..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "this server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Content required"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Dont install"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Install to play"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Install anyway"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Install"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "This invite was created by another Modrinth user, not Modrinth. Only accept invites from people you trust."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Required modpack"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "This server requires mods to play. Click Install to set up the required files from Modrinth, then launch directly into the server."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "A file is only reviewed if it’s published to Modrinth, regardless of its file format (including .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Shared instance"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Shared server instance"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "This server modpack contains files that aren’t published on Modrinth. We strongly recommend only installing files from sources you trust."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Unknown files warning"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Unrecognized files"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "View contents"
|
||||
@@ -311,8 +479,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Update to play"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Update required"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Removed"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "An update is required to play {name}. Please update to the latest version to launch the game."
|
||||
@@ -320,11 +488,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "This project is already installed"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Switch version"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Back to discover"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Install content to instance"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "All versions"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Download in browser"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Installing"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Already installed"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Developer mode enabled."
|
||||
@@ -332,6 +512,9 @@
|
||||
"app.settings.downloading": {
|
||||
"message": "Downloading v{version}"
|
||||
},
|
||||
"app.settings.privacy.ads-consent.intro": {
|
||||
"message": "Ads make Modrinth possible and fund creator payouts. Our partners may store or access cookies in the app to personalize ads and measure performance. You can opt out or manage your preferences below."
|
||||
},
|
||||
"app.settings.tabs.appearance": {
|
||||
"message": "Appearance"
|
||||
},
|
||||
@@ -374,6 +557,9 @@
|
||||
"app.skins.dropped-file-error.title": {
|
||||
"message": "Error processing file"
|
||||
},
|
||||
"app.skins.ears-feature-notice": {
|
||||
"message": "This skin uses features from the {ears} mod"
|
||||
},
|
||||
"app.skins.edit-button": {
|
||||
"message": "Edit skin"
|
||||
},
|
||||
@@ -446,6 +632,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -497,6 +686,12 @@
|
||||
"app.skins.title": {
|
||||
"message": "Skin selector"
|
||||
},
|
||||
"app.skins.toggle-ears-features-off": {
|
||||
"message": "Toggle off"
|
||||
},
|
||||
"app.skins.toggle-ears-features-on": {
|
||||
"message": "Toggle on"
|
||||
},
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} has finished downloading. Reload to update now, or automatically when you close Modrinth App."
|
||||
},
|
||||
@@ -608,6 +803,33 @@
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Sign in to a Modrinth account</link> to add friends and see what they're playing!"
|
||||
},
|
||||
"instance.action.create-shortcut": {
|
||||
"message": "Create shortcut"
|
||||
},
|
||||
"instance.action.export-modpack": {
|
||||
"message": "Export modpack"
|
||||
},
|
||||
"instance.action.launch-instance": {
|
||||
"message": "Launch instance"
|
||||
},
|
||||
"instance.action.more-actions": {
|
||||
"message": "More actions"
|
||||
},
|
||||
"instance.action.open-folder": {
|
||||
"message": "Open folder"
|
||||
},
|
||||
"instance.action.repair": {
|
||||
"message": "Repair"
|
||||
},
|
||||
"instance.action.settings": {
|
||||
"message": "Instance settings"
|
||||
},
|
||||
"instance.action.starting": {
|
||||
"message": "Starting..."
|
||||
},
|
||||
"instance.action.stopping": {
|
||||
"message": "Stopping..."
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Add and play"
|
||||
},
|
||||
@@ -650,6 +872,9 @@
|
||||
"instance.files.save-as": {
|
||||
"message": "Save as..."
|
||||
},
|
||||
"instance.playtime.never-played": {
|
||||
"message": "Never played"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Address"
|
||||
},
|
||||
@@ -863,6 +1088,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copy address"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Create shortcut"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Don't show on Home"
|
||||
},
|
||||
@@ -937,26 +1165,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader is provided by the server"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "A file is only reviewed if it’s uploaded to Modrinth, regardless of its file format (including .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Don't show this warning again"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Confirm installation"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Install anyway"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Malware is often distributed through modpack files by sharing them on platforms like Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "We couldn't find this file on Modrinth. We strongly recommend only installing files from sources you trust."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Unknown file warning"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Ocultar más instancias en ejecución"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Copiado"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Copiar detalles"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Descartar"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Abrir instancia"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Reintentar"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Cancelado debido al cierre de la aplicación"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "No se pudo leer el modpack"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Cancelado"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "La limpieza no se completó"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "No se pudieron descargar los archivos"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "El archivo descargado está dañado"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "No se pudieron guardar los archivos"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "No se pudo completar la descarga"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "No se pudo encontrar la instancia"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "La ruta del archivo no es válida"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Los datos del modpack no son válidos"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Los archivos del modpack tienen metadatos no válidos"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "No se pudo completar la configuración de Java"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "No se pudo configurar el cargador"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "No se pudieron actualizar los datos locales"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "La instalación de Minecraft falló"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "No pude comunicarme con Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "No tiene permiso para escribir"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "No se pudo descargar el modpack"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Algo salió mal"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Instancia desconocida"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Instalaciones"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Hacer instancia principal"
|
||||
},
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Mostrar tiempo de juego"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Omite automáticamente las confirmaciones de bajo riesgo, como las instalaciones duplicadas de paquetes de mods, la eliminación de contenido normal, las actualizaciones masivas, la desvinculación de paquetes de mods y las solicitudes de reparación. Las advertencias peligrosas seguirán mostrándose."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Omitir advertencias que no sean esenciales"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Permite mostrar u ocultar la barra lateral."
|
||||
},
|
||||
@@ -147,7 +234,7 @@
|
||||
"message": "Descubrir servidores"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Ocultar servidores ya añadidos"
|
||||
"message": "Ocultar los servidores ya agregados"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "No hay versiones disponibles que coincidan con {compatibilityLabel}. Selecciona una versión para instalarla de todas formas. Las dependencias no se instalarán automáticamente."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Instalando modpack..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Introduce la descripción del modpack..."
|
||||
},
|
||||
@@ -176,24 +257,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportar modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "¿Incluir \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nombre del modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nombre del modpack"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Configura que archivos incluir en esta exportación"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Número de la versión"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Descargando contenido"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Descargando Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Descargando el archivo del paquete"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Extracción de anulaciones"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Finalizando"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "En cola para instalarse"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Preparando Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Descargando Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Descomprimiendo Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Obteniendo Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Preparando Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validación de Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Leer el manifiesto del paquete"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Resolviendo el cargador"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Resolviendo Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Resolviendo el contenido"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Revertir"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Ejecutando los procesadores del cargador"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Todos los datos de tu instancia se eliminarán permanentemente, incluidos tus mundos, configuraciones y todo el contenido instalado."
|
||||
},
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instancia"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Descargando {current, number}/{total, number} proyectos..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Finalizando la actualización..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Resolviendo versiones..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "proyecto"
|
||||
},
|
||||
@@ -242,8 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Explorar servidores"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "¿Estás seguro de que quieres eliminar este mundo de forma permanente?"
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Eliminar mundo"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Eliminar mundo"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Este mundo se eliminará de forma permanente de esta instancia. Esta acción no se puede deshacer."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Eliminando {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Con mods"
|
||||
@@ -263,38 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "No hay servidores ni mundos añadidos"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "¿Estás seguro de que quieres eliminar {name}?"
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Eliminar servidor"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Eliminar servidor"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Este servidor se eliminará de tu lista de servidores y de la lista de servidores del juego. Puedes volver a agregarlo más adelante si conoces la dirección."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Se está eliminando {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Buscar en {count} mundos..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "este servidor"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Contenido requerido"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "No instalar"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instalar para jugar"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Instalar de todos modos"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Esta invitación la creó otro usuario de Modrinth, no Modrinth. Solo acepta invitaciones de personas en las que confíes."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requerido"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requiere mods para poder jugar. Haz clic en Instalar para configurar los archivos requeridos desde Modrinth, después se ejecutará para entrar directamente al servidor."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Un archivo solo se revisa si se publica en Modrinth, sin importar su formato (incluido el .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instancia compartida"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instancia de servidor compartida"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Este modpack para servidor contiene archivos que no están publicados en Modrinth. Recomendamos encarecidamente instalar únicamente archivos de fuentes de confianza."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Advertencia sobre archivos desconocidos"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Archivos no reconocidos"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Ver contenidos"
|
||||
@@ -302,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Actualizar para jugar"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Actualización requerida"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Eliminado"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Se requiere una actualización para jugar {name}. Por favor, actualiza a la versión más reciente para iniciar el juego."
|
||||
@@ -311,11 +473,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Este proyecto ya está instalado"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Cambiar versión"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Volver al explorador"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Instalar contenido a la instancia"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Todas las versiones"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Descargar en el navegador"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Instalando"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Ya instalado"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
@@ -437,6 +611,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Constructores y Biomas"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Caos al cubo"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Persigue los Cielos"
|
||||
},
|
||||
@@ -854,6 +1031,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copiar dirección"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Crear un acceso directo"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "No mostrar en la página de inicio"
|
||||
},
|
||||
@@ -928,26 +1108,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "El loader es proporcionado por el servidor"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Un archivo solo es revisado si es subido a Modrinth, independientemente de su formato de archivo (incluyendo .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "No volver a mostrar esta advertencia"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Confirmar instalación"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Instalar de todos modos"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "El malware a menudo es distribuido mediante modpacks compartidos en aplicaciones como Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "No pudimos encontrar este archivo en Modrinth. Recomendamos solo instalar archivos de sitios de confianza."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Advertencia de archivo desconocido"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,21 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Ocultar más instancias en ejecución"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Descartar"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Abrir instancia"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Reintentar"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Instancia desconocida"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Instalaciones"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Establecer como instancia principal"
|
||||
},
|
||||
@@ -101,6 +116,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Mostrar tiempo de juego"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Automáticamente omite confirmaciones de bajo riesgo como modpacks duplicados, eliminación de contenido normal, actualizaciones masivas, desvinculando modpacks, y mensajes de reparación. Advertencias importantes seguirán siendo mostradas."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Omitir advertencias no esenciales"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Activa la posibilidad de alternar la barra lateral."
|
||||
},
|
||||
@@ -146,9 +167,6 @@
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descubrir servidores"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Ocultar servidores ya añadidos"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
},
|
||||
@@ -161,12 +179,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "No hay versiones disponibles que coincidan con {compatibilityLabel}. Selecciona una versión para instalarla de todas formas. Las dependencias no se instalarán automáticamente."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Instalando modpack..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Escribe la descripción del modpack..."
|
||||
},
|
||||
@@ -176,18 +188,12 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportar modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "¿Incluir \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nombre del modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nombre del modpack"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Configura que archivos se incluirán en esta instancia"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Número de versión"
|
||||
},
|
||||
@@ -242,12 +248,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Explorar servidores"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' será **permanentemente eliminado**, y habrá forma de recuperarlo."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "¿Estás seguro de qué quieres eliminar permanentemente este mundo?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modeado"
|
||||
},
|
||||
@@ -266,24 +266,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "No hay servidores o mundos añadidos"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' será eliminado de tu lista, incluyendo dentro del juego, y no habrá forma de recuperarlo."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) será eliminado de tu lista, incluyendo dentro del juego, y no habrá forma de recuperarlo."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "¿Estás seguro de qué quieres eliminar {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Buscar {count} mundos..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "este servidor"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Contenido obligatorio"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instala para jugar"
|
||||
},
|
||||
@@ -293,27 +278,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requerido"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requiere ciertos mods. Pulsa Instalar para instalar los archivos requeridos de Modrinth y luego el launcher te enviara directo al servidor."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instancia compartida"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instancia de servidor compartida"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Ver contenido"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Actualiza para jugar"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Actualización requerida"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Una actualización es requerida para jugar {name}. Por favor actualízala a la versión más reciente para ejecutar el juego."
|
||||
},
|
||||
@@ -323,9 +296,6 @@
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Volver a descubrir"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Instalar contenido"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
},
|
||||
@@ -937,26 +907,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader proporcionado por el servidor"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Un archivo solo es revisado si es subido a Modrinth, independientemente de su formato de archivo (incluyendo .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "No mostrar esta advertencia otra vez"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Confirmar instalación"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Instalar de todos modos"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "El malware es normalmente distribuido por archivos de modpack que son normalmente compartidas en aplicaciones como Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "No pudimos encontrar este archivo en Modrinth. Recomendamos solo instalar archivos de sitios de confianza."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Advertencia de archivo desconocido"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,30 @@
|
||||
"app.action-bar.downloading-java": {
|
||||
"message": "Ladataan Java-versiota {version}"
|
||||
},
|
||||
"app.action-bar.downloading-update": {
|
||||
"message": "Ladataan päivitystä"
|
||||
},
|
||||
"app.action-bar.downloads": {
|
||||
"message": "Lataukset"
|
||||
},
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Piilota enemmän käynnissä olevia instansseja"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Hylkää"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Avaa instanssi"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Yritä uudelleen"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Tuntematon instanssi"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Asennukset"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Aseta ensisijaiseksi instanssiksi"
|
||||
},
|
||||
@@ -20,12 +38,18 @@
|
||||
"app.action-bar.primary-instance": {
|
||||
"message": "Ensisijainen instanssi"
|
||||
},
|
||||
"app.action-bar.reload-to-update": {
|
||||
"message": "Lataa uudelleen päivittääksesi"
|
||||
},
|
||||
"app.action-bar.show-more-running-instances": {
|
||||
"message": "Näytä enemmän käynnissä olevia instansseja"
|
||||
},
|
||||
"app.action-bar.stop-instance": {
|
||||
"message": "Pysäytä instanssi"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "Päivitä"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "Näytä aktiiviset lataukset"
|
||||
},
|
||||
@@ -86,6 +110,18 @@
|
||||
"app.appearance-settings.select-option": {
|
||||
"message": "Valitse vaihtoehto"
|
||||
},
|
||||
"app.appearance-settings.show-play-time.description": {
|
||||
"message": "Näyttää, kuinka paljon aikaa olet käyttänyt instanssin pelaamiseen."
|
||||
},
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Näyttää peliaika"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Ohittaa automaattisesti vähäriskiset vahvistukset, kuten modpackien kaksoisasennukset, tavallisen sisällön poistamisen, massapäivitykset, modpackien linkityksen poistamisen ja korjauskehotteet. Vaaralliset varoitukset näytetään silti."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Ohita ei olennaiset varoitukset"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Laittaa päälle mahdollisuuden kytkeä sivupalkkia."
|
||||
},
|
||||
@@ -131,9 +167,6 @@
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Löydä palvelimia"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Piilota lisätyt palvelimet"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modipaketit"
|
||||
},
|
||||
@@ -146,12 +179,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Yhtään versiota ei ole saatavilla yhteensopivuudella {compatibilityLabel}. Valitse asennettava versio siitä huolimatta. Riippuvuuksia ei asenneta automaattisesti."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Asennetaan modipakettia..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Lisää modipaketin kuvaus..."
|
||||
},
|
||||
@@ -161,24 +188,66 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Vie modipaketti"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Sisällytä \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modipaketin nimi"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modipaketin nimi"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Muuta mitkä tiedostot sisältyvät tähän vientiin"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versio numero"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Ladataan sisältöä"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Ladataan Minecraftia"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Ladataan paketti tiedostoja"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Puretaan ohituksia"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Viimeistellään"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Valmistellaan Javaa"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Ladataan Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Puretaan Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Haetaan Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Valmistellaan Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Tarkistetaan Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Luetaan paketin manifestia"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Ratkaistaan lataajaa"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Ratkaistaan Minecraftia"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Ratkaistaan sisältöä"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Palautetaan muutoksia"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Suoritetaan lataajan käsittelijöitä"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Kaikki sinun instanssisi data poistetaan pysyvästi, sisältäen maailmasi, konfiguraatiosi ja asennetun sisällön."
|
||||
},
|
||||
@@ -203,6 +272,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instanssi"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Ladataan {current, number}/{total, number} projekteja..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Viimeistellään päivitystä..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Selvitetään versioita..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekti"
|
||||
},
|
||||
@@ -227,11 +305,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Selaa palvelimia"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' tullaan **poistamaan pysyvästi**, eikä tule olemaan mitään tapaa palauttaa sitä."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Poista maailma"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Oletko varma että haluat pysyvästi poistaa tämän maailman?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Poista maailma"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Tämä maailma poistetaan pysyvästi tästä instanssista. Tätä toimintoa ei voi kumota."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Poistetaan {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modattu"
|
||||
@@ -251,24 +335,21 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Ei palvelimia tai maailmoja lisättynä"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' tullaan poistamaan sinun listaltasi, mukaan lukien pelin sisällä, eikä tule olemaan mitään tapaa palauttaa sitä."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Poista palvelin"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) tullaan poistamaan sinun listaltasi, mukaan lukien pelin sisällä, eikä tule olemaan mitään tapaa palauttaa sitä."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Poista palvelin"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Oletko varma että haluat poistaa {name}?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Tämä palvelin poistetaan palvelinluettelostasi ja pelin sisäisestä palvelinluettelosta. Voit lisätä sen myöhemmin uudelleen, jos tiedät osoitteen."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Poistetaan {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Hae {count} maailmasta..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "tämän palvelimen"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Sisältö vaaditaan"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Asenna pelataksesi"
|
||||
},
|
||||
@@ -278,27 +359,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# modia}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Vaadittu modipaketti"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Tämä palvelin vaatii modeja toimiakseen. Klikkaa Asenna ladataksesi vaaditut tiedostot Modrinthista, ja käynnistä peli suoraan palvelimelle."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Jaettu instanssi"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Jaettu palvelininstanssi"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Tarkastele sisältöä"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Päivitä pelataksesi"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Päivitys vaaditaan"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Pävitys vaaditaan pelataksesi {name}. Päivitä viimeisimpään versioon pelataksesi."
|
||||
},
|
||||
@@ -308,9 +377,6 @@
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Takaisin sisällön löytöön"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Asenna sisältöä instanssiin"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Kehittäjätila käytössä."
|
||||
},
|
||||
@@ -335,15 +401,147 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Resurssien hallinta"
|
||||
},
|
||||
"app.skins.add-button": {
|
||||
"message": "Lisää ulkoasu"
|
||||
},
|
||||
"app.skins.add-button.drag-and-drop": {
|
||||
"message": "Raahaa ja pudota"
|
||||
},
|
||||
"app.skins.apply-button": {
|
||||
"message": "Käytä"
|
||||
},
|
||||
"app.skins.delete-button": {
|
||||
"message": "Poista ulkoasu"
|
||||
},
|
||||
"app.skins.delete-modal.description": {
|
||||
"message": "Tämä poistaa valitun skinin pysyvästi. Tätä toimintoa ei voi kumota."
|
||||
},
|
||||
"app.skins.delete-modal.title": {
|
||||
"message": "Haluatko varmasti poistaa ulkoasun?"
|
||||
},
|
||||
"app.skins.dropped-file-error.text": {
|
||||
"message": "Tiedoston lukeminen epäonnistui."
|
||||
},
|
||||
"app.skins.dropped-file-error.title": {
|
||||
"message": "Virhe prosessoidessa tiedostoa"
|
||||
},
|
||||
"app.skins.edit-button": {
|
||||
"message": "Muokkaa ulkoasua"
|
||||
},
|
||||
"app.skins.modal.add-skin-button": {
|
||||
"message": "Lisää ulkoasu"
|
||||
},
|
||||
"app.skins.modal.add-title": {
|
||||
"message": "Lisätään ulkoasua"
|
||||
},
|
||||
"app.skins.modal.arm-style-section": {
|
||||
"message": "Käsien tyyli"
|
||||
},
|
||||
"app.skins.modal.arm-style-slim": {
|
||||
"message": "Ohut"
|
||||
},
|
||||
"app.skins.modal.arm-style-wide": {
|
||||
"message": "Paksu"
|
||||
},
|
||||
"app.skins.modal.cape-fallback-name": {
|
||||
"message": "Viitta"
|
||||
},
|
||||
"app.skins.modal.cape-section": {
|
||||
"message": "Viitta"
|
||||
},
|
||||
"app.skins.modal.edit-title": {
|
||||
"message": "Muokataan ulkoasua"
|
||||
},
|
||||
"app.skins.modal.make-edit-first-tooltip": {
|
||||
"message": "Tee muokkaus ulkoasuun ensin!"
|
||||
},
|
||||
"app.skins.modal.no-cape-tooltip": {
|
||||
"message": "Ei viittaa"
|
||||
},
|
||||
"app.skins.modal.none-cape-option": {
|
||||
"message": "Ei mitään"
|
||||
},
|
||||
"app.skins.modal.replace-texture-button": {
|
||||
"message": "Korvaa tekstuuri"
|
||||
},
|
||||
"app.skins.modal.save-skin-button": {
|
||||
"message": "Tallenna ulkoasu"
|
||||
},
|
||||
"app.skins.modal.saving-tooltip": {
|
||||
"message": "Tallennetaan..."
|
||||
},
|
||||
"app.skins.modal.texture-section": {
|
||||
"message": "Tekstuuri"
|
||||
},
|
||||
"app.skins.modal.upload-skin-first-tooltip": {
|
||||
"message": "Lataa ulkoasu ensin!"
|
||||
},
|
||||
"app.skins.preview.edit-button": {
|
||||
"message": "Muokkaa ulkoasua"
|
||||
},
|
||||
"app.skins.previewing-badge": {
|
||||
"message": "Esikatsellaan"
|
||||
},
|
||||
"app.skins.rate-limit.text": {
|
||||
"message": "Vaihdat ulkoasua liian usein. Mojangin palvelimet ovat estäneet uudet pyynnöt väliaikaisesti. Yritä hetken kuluttua uudelleen."
|
||||
},
|
||||
"app.skins.rate-limit.title": {
|
||||
"message": "Hidasta vähän!"
|
||||
},
|
||||
"app.skins.reorder-error.text": {
|
||||
"message": "Ulkoasujen järjestystä ei voitu tallentaa."
|
||||
},
|
||||
"app.skins.reorder-error.title": {
|
||||
"message": "Skinien järjestyksen muuttaminen epäonnistui"
|
||||
},
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
"app.skins.section.default-skins": {
|
||||
"message": "Oletus ulkoasut"
|
||||
},
|
||||
"app.skins.section.minecon-earth-2017": {
|
||||
"message": "MINECON Earth 2017"
|
||||
},
|
||||
"app.skins.section.modrinth": {
|
||||
"message": "Modrinth"
|
||||
},
|
||||
"app.skins.section.modrinth-pride": {
|
||||
"message": "Modrinth Pride"
|
||||
},
|
||||
"app.skins.section.modrinth-pride.tooltip": {
|
||||
"message": "Sait nämä skinit lahjoittamalla Modrinthin Pride-keräykseen Pride-kuukauden aikana."
|
||||
},
|
||||
"app.skins.section.mounts-of-mayhem": {
|
||||
"message": "Sekasorron ratsut"
|
||||
},
|
||||
"app.skins.section.saved-skins": {
|
||||
"message": "Tallennetut ulkoasut"
|
||||
},
|
||||
"app.skins.section.striding-hero": {
|
||||
"message": "Striding Hero"
|
||||
},
|
||||
"app.skins.section.the-copper-age": {
|
||||
"message": "The Copper Age"
|
||||
},
|
||||
"app.skins.section.the-garden-awakens": {
|
||||
"message": "The Garden Awakens"
|
||||
},
|
||||
"app.skins.section.tiny-takeover": {
|
||||
"message": "Pienten vallankumous"
|
||||
},
|
||||
"app.skins.sign-in.button": {
|
||||
"message": "Kirjaudu sisään"
|
||||
},
|
||||
"app.skins.sign-in.description": {
|
||||
"message": "Kirjaudu Minecraft-tilillesi käyttääksesi Modrinth-sovelluksen ulkoasujen hallintaominaisuuksia."
|
||||
},
|
||||
"app.skins.sign-in.rinthbot-alt": {
|
||||
"message": "Innostunut Modrinth Botti"
|
||||
},
|
||||
"app.skins.sign-in.title": {
|
||||
"message": "Kirjaudu sisään"
|
||||
},
|
||||
@@ -569,15 +767,30 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Nimi"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel": {
|
||||
"message": "Päivitys kanava"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha": {
|
||||
"message": "Alfa"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha.description": {
|
||||
"message": "Release-, beta- ja alpha-versiot näytetään saatavilla olevina päivityksinä."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "Beta"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta.description": {
|
||||
"message": "Release- ja beta-versiot näytetään saatavilla olevina päivityksinä."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release": {
|
||||
"message": "Julkaisu"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release.description": {
|
||||
"message": "Vain release-versiot näytetään saatavilla olevina päivityksinä."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.select": {
|
||||
"message": "Valitse päivitys kanava"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Aloitustoiminnot"
|
||||
},
|
||||
@@ -701,6 +914,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopioi osoite"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Luo pikakuvake"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Älä näytä koti näkymässä"
|
||||
},
|
||||
@@ -775,26 +991,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Modialusta on palvelimen tarjoama"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Tiedosto tarkistetaan vain jos se on ladattu Modrinthiin, riippumatta tiedoston muodosta (mukaanlukien .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Älä näytä tätä varoitusta uudestaan"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Vahvista asennus"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Asenna jokatapauksessa"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Haittaohjelmia levitetään usein modipaketti tiedostojen kautta jakamalla niitä alustoilla kuten Discordissa."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Emme löytäneet tätä tiedostoa Modrinthista. Suosittelemme vahvasti että asennat tiedostoja vain lähteistä joihin luotat."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Tuntematon tiedosto varoitus"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Itago ang mas marami pang tumatakbong instansiya"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Subukan muli"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Gumawa ng pangunahing instansiya"
|
||||
},
|
||||
@@ -143,9 +146,6 @@
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Tumuklas ng mga server"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Itago ang mga nailagay na mga servers"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
},
|
||||
@@ -155,12 +155,6 @@
|
||||
"app.browse.server.installing": {
|
||||
"message": "Ini-install"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Ini-install ang modpack..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Ilagay ang paglalarawan ng modpack..."
|
||||
},
|
||||
@@ -170,18 +164,9 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Iluwas ang modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Salihin ang \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Pangalan ng Modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Pangalan ng modpack"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Isaayos kung anong mga file ang isasali sa pagluwas"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Numero ng bersiyon"
|
||||
},
|
||||
@@ -236,12 +221,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Mag-browse ng servers"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' ay **permanenteng mabubura**, at walang paraan upang maibalik muli."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Sigurado ka bang gusto mong permanenteng burahin ang world na ito?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modded"
|
||||
},
|
||||
@@ -260,24 +239,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Walang servers o worlds ang nalalagay"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' ay matatangal sa iyong listahan, pati sa loob ng laro, at walang paraan upang maibalik ito."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) ay matatangal sa iyong listahan, pati sa loob ng laro, at walang paraan upang maibalik ito."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Sigurado ka bang gusto mong tanggalin ang {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Hanapin sa {count} mundo..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "server na ito"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Nangangailangan ng kontento"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Mag-install upang malaro"
|
||||
},
|
||||
@@ -287,27 +251,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# na mod}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Kinailangan na modpack"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Ang server rna ito ay nangangailangan ng mga mod upang makalaro. Pindutin ang install upang maihanda ang mga kinakailangang file galing sa Modrinth, matapos ay ilunsad nang diretso sa server."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Binahaging instansiya"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Binahaging instansiyang pang-server"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Tingnan ang mga kontento"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Mag-update upang malaro"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Kailangang mag-update"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Kailangang mag-update upang malaro ang {name}. Mangyaring mag-update sa pinakabagong bersiyon upang ma-launch ang laro."
|
||||
},
|
||||
@@ -597,7 +549,7 @@
|
||||
"message": "Mga launch hook"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Mga custom na launch hook"
|
||||
"message": "Mga pasadyang launch hook"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Binibigyan-daan ng mga hook ang mga ekspertong tagagamit na makapagtakbo ng mga pansistemang utos o system command bago at pagkatapos ma-launch ang laro."
|
||||
@@ -660,7 +612,7 @@
|
||||
"message": "Window"
|
||||
},
|
||||
"instance.settings.tabs.window.custom-window-settings": {
|
||||
"message": "Mga setting sa custom na window"
|
||||
"message": "Mga setting sa pasadyang window"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen": {
|
||||
"message": "Fullscreen"
|
||||
@@ -769,26 +721,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Ang loader ay handog na ng server"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Ang file ay nasusuri lamang kapag ito ay na-upload sa Modrinth, walang pili sa file format nito (kabilang na ang .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Huwag ipakita ang babalang ito ulit"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Kumpirmahin ang installation"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "I-install pa rin"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Ang malware ay madalas naidadala sa mga modpack files sa pamamagitan ng pag-bigay ng mga ito sa mga platforms kagaya ng Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Hindi namin mahanap ang file na ito sa Modrinth. Mahalagang mag-install ka lamang ng files galing sa mga mapagkakatiwalang sources."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Hindi kilalang file"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,25 +9,106 @@
|
||||
"message": "Téléchargements"
|
||||
},
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Masquer plus d'instances en exécution"
|
||||
"message": "Masquer plus d'instances en cours d'exécution"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Copié"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Copier les détails"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Rejeter"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Ouvrir l'instance"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Réessayer"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Annulé en raison de la fermeture de l'application"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Impossible de lire le modpack"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Annulé"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "Le nettoyage n'a pas terminé"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Impossible de télécharger les fichiers"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Le fichier téléchargé est corrompu"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Impossible de sauvegarder les fichiers"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Impossible de terminer le téléchargement"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "L'instance est introuvable"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "Le chemin d'accès au fichier est invalide"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Les données du modpack sont invalides"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Les fichiers du modpack contiennent des métadonnées invalides"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "L'installation de Java n'a pas pu se terminer"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "La mise en place du loader a échoué"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Impossible de mettre à jour les données locales"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "La mise en place de Minecraft a échoué"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Impossible d'atteindre les serveurs Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Aucune permission d'écriture"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Impossible de télécharger le pack"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Quelque chose s'est mal passé"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Instance inconnue"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installations"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Définir en tante qu'instance première"
|
||||
"message": "Définir en tant qu'instance principale"
|
||||
},
|
||||
"app.action-bar.no-instances-running": {
|
||||
"message": "Aucune instance en exécution"
|
||||
"message": "Aucune instance en cours d'exécution"
|
||||
},
|
||||
"app.action-bar.offline": {
|
||||
"message": "Hors ligne"
|
||||
},
|
||||
"app.action-bar.primary-instance": {
|
||||
"message": "Instance première"
|
||||
"message": "Instance principale"
|
||||
},
|
||||
"app.action-bar.reload-to-update": {
|
||||
"message": "Recharger pour mettre à jour"
|
||||
},
|
||||
"app.action-bar.show-more-running-instances": {
|
||||
"message": "Montrer plus d'instances en exécution"
|
||||
"message": "Montrer plus d'instances en cours d'exécution"
|
||||
},
|
||||
"app.action-bar.stop-instance": {
|
||||
"message": "Arrêter l'instance"
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Afficher le temps de jeu"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Ignore automatiquement les confirmations à faible risque, comme l'installation de modpacks en double, la suppression de contenu standard, les mises à jour groupées, la dissociation des modpacks et les demandes de réparation. Les avertissements concernant les actions dangereuses continueront d'être affichés."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Cacher les alertes non essentielles"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Permet d'ouvrir ou de fermer la barre latérale."
|
||||
},
|
||||
@@ -147,7 +234,7 @@
|
||||
"message": "Découvrir des serveurs"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Masquer les serveurs déjà ajoutés"
|
||||
"message": "Masquer les serveurs déjà installés"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Aucune version disponible ne correspond à {compatibilityLabel}. Sélectionnez une version pour l'installer malgré tout. Les dépendances ne seront pas installées automatiquement."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Installation du modpack..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Saisir la description du modpack..."
|
||||
},
|
||||
@@ -176,24 +257,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exporter le modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Inclure « {file} » ?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nom du modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nom du modpack"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Configurez quels fichiers sont inclus dans cette exportation"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Numéro de version"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Téléchargement du contenu"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Téléchargement de Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Téléchargement du fichier de pack"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Extraction des fichiers personnalisés"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Finalisation"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "En attente d'installation"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Préparation de Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Téléchargement de Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Extraction de Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Récupération de Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Préparation de Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validation de Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Lecture du manifeste du pack"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Résolution du loader"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Résolution de Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Résolution du contenu"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Annulation"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Exécution des processeurs du chargeur"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Toutes les données pour votre instance seront supprimées à jamais, y compris vos mondes, vos configurations, et le contenu installé."
|
||||
},
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Téléchargement de {current, number}/{total, number} projets..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Finalisation de la mise à jour..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Résolution des versions..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projet"
|
||||
},
|
||||
@@ -242,8 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Parcourir des serveurs"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Êtes-vous sûr·e de vouloir supprimer ce monde pour toujours ?"
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Supprimer le monde"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Supprimer le monde"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Ce monde sera définitivement supprimé de cette instance. Cette action est irréversible."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Suppression de {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Moddé"
|
||||
@@ -263,38 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Aucun serveur ou monde ajoutés"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Êtes-vous sûr·e de vouloir retirer {name} ?"
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Enlever le serveur"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Enlever le serveur"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Ce serveur sera enlevé de votre liste de serveur et de la liste de serveur en jeu. Vous pourrez le rajouter plus tard si vous connaissez son adresse."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Retrait de {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Rechercher {count} mondes..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "ce serveur"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Contenu requis"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Ne pas installer"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installer pour jouer"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Installer quand même"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Cette invitation a été crée par un autre utilisateur Modrinth, pas par Modrinth. N'acceptez seulement les invitations de personnes en qui vous avez confiance."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requis"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Ce serveur a besoin de mods pour jouer. Cliquez sur Installer pour mettre en place les fichiers requis depuis Modrinth, puis lancez directement dans le serveur."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Un fichier est seulement examiné s'il est publié sur Modrinth, peu importe son extension (y compris .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instance partagée"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instance serveur partagée"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Ce modpack de serveur contient des fichiers qui ne sont pas publiés sur Modrinth. Nous recommandons fortement de seulement installer des fichiers de sources en qui vous avez confiance."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Avertissement de fichiers inconnus"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Fichiers non reconnus"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Voir le contenu"
|
||||
@@ -302,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Mettre à jour pour jouer"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Mise à jour requise"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Supprimé"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Une mise à jour est requise pour jouer à {name}. Veuillez mettre à jour à la dernière version pour lancer le jeu."
|
||||
@@ -311,11 +473,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Ce projet a déjà été installé"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Changer de version"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Retour vers la page découvrir"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Installer du contenu à l'instance"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Toutes les versions"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Télécharger dans le navigateur"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Déjà installé"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Mode développeur activé."
|
||||
@@ -437,6 +611,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Cubes du chaos"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chassez les cieux"
|
||||
},
|
||||
@@ -465,7 +642,7 @@
|
||||
"message": "Striding Hero"
|
||||
},
|
||||
"app.skins.section.the-copper-age": {
|
||||
"message": "The Copper Age"
|
||||
"message": "L'âge du cuivre"
|
||||
},
|
||||
"app.skins.section.the-garden-awakens": {
|
||||
"message": "L'éveil du jardin"
|
||||
@@ -851,6 +1028,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copier l'adresse"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Créer un raccourci"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Ne pas montrer dans l'Accueil"
|
||||
},
|
||||
@@ -925,26 +1105,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Le loader est procuré par le serveur"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Un fichier n’est révisé que s’il est téléchargé sur Modrinth, quel que soit son format de fichier (y compris .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Ne plus m'avertir à ce sujet"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Confirmer l'installation"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Installer tout de même"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Les logiciels malveillants sont souvent distribués via des fichiers modpack en les partageant sur des plateformes comme Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Nous ne pouvions pas trouver ce fichier sur Modrinth. Nous vous recommandons fortement de n'installer que des fichiers de sources de confiance."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Avertissement fichier inconnu"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,6 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "יצוא חבילת מודים"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "שם חבילת המודים"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "שם חבילת המודים"
|
||||
},
|
||||
@@ -119,12 +116,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "עיון בשרתים"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' יימחק לצמיתות, ולא תהיה דרך לשחזר אותו."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "האם אתה בטוח שברצונך למחוק לצמיתות את העולם הזה?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "עם מודים"
|
||||
},
|
||||
@@ -143,24 +134,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "אין שרתים אן עולמות שנוספו"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' יוסר מהרשימה שלך, כולל מתוך המשחק, ולא תהיה דרך לשחזר אותו."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) יוסר מהרשימה שלך, כולל מתוך המשחק, ולא תהיה דרך לשחזר אותו."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "אתה בטוח שאתה רוצה להסיר {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "חיפוש ב-{count} עולמות..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "השרת הזה"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "תוכן נדרש"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "צריך להתקין כדי לשחק"
|
||||
},
|
||||
@@ -170,27 +146,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {מוד אחד} other {# מודים}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "חבילת מודים נדרשת"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "שרת זה דורש מודים כדי לשחק. לחץ על \"התקן\" כדי להגדיר את הקבצים הנדרשים מ-Modrinth, ולאחר מכן הפעל ישירות לשרת."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "התקנה משותפת"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "התקנת שרת משותפת"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "הצג תוכן"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "צריך לעדכן כדי לשחק"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "עדכון נדרש"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "עדכון נדרש כדי לשחק ב{name}. ניתן להתחיל את המשחק רק לאחר עדכון לגרסה החדשה."
|
||||
},
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "További futó példányok elrejtése"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Másolva"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Részletek másolása"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Elutasítás"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Példány megnyitása"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Újra"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Az alkalmazás bezárása miatt megszakítva"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Nem sikerült beolvasni a modcsomagot"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Megszakítva"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "A tisztítás nem fejeződött be"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Nem sikerült letölteni a fájlokat"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "A letöltött fájl sérült"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Nem sikerült elmenteni a fájlokat"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "A letöltés nem sikerült"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "A játékprofil nem található"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "A fájl elérési útja érvénytelen"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "A modcsomag adatai érvénytelenek"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "A modcsomag fájljainak metaadatai érvénytelenek"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "A Java telepítése nem sikerült"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "A betöltő beállítása sikertelen volt"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "A helyi adatok frissítése nem sikerült"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "A Minecraft telepítése sikertelen volt"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Nem sikerült elérni Modrinthot"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Nincs felülírási jogosultság"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Nem sikerült letölteni a csomagot"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Valami hiba történt"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Ismeretlen játékprofil"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Telepítések"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Beállítás elsődleges példányként"
|
||||
},
|
||||
@@ -42,13 +123,13 @@
|
||||
"message": "Példányok megtekintése"
|
||||
},
|
||||
"app.action-bar.view-logs": {
|
||||
"message": "Naplók megtekintése"
|
||||
"message": "Naplózások megtekintése"
|
||||
},
|
||||
"app.appearance-settings.advanced-rendering.description": {
|
||||
"message": "Lehetővé teszi olyan speciális megjelenítési effektusok használatát, mint például az elmosódás, amelyek hardveres gyorsítás nélkül teljesítménycsökkenést okozhatnak."
|
||||
},
|
||||
"app.appearance-settings.advanced-rendering.title": {
|
||||
"message": "Fejlett renderelés"
|
||||
"message": "Haladó megjelenítési beállítások"
|
||||
},
|
||||
"app.appearance-settings.color-theme.description": {
|
||||
"message": "Válaszd ki a Modrinth Apphoz a kívánt színsémát."
|
||||
@@ -78,7 +159,7 @@
|
||||
"message": "A kezdőlap „Folytasd itt” részében a legújabb világok is megtalálhatók."
|
||||
},
|
||||
"app.appearance-settings.jump-back-into-worlds.title": {
|
||||
"message": "Visszaugrás a világokba"
|
||||
"message": "„Folytasd itt” a világokat is"
|
||||
},
|
||||
"app.appearance-settings.minimize-launcher.description": {
|
||||
"message": "Minimalizáld az indítót a Minecraft indításakor."
|
||||
@@ -96,11 +177,17 @@
|
||||
"message": "Válassz egy lehetőséget"
|
||||
},
|
||||
"app.appearance-settings.show-play-time.description": {
|
||||
"message": "Megmutatja, mennyi időt töltöttél játszva egy profillal."
|
||||
"message": "Megmutatja, mennyi időt töltöttél egy példányban."
|
||||
},
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Játékidő megjelenítése"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Az alacsony kockázatú megerősítéseket – például a modcsomagok ismételt telepítését, a szokásos tartalomtörlést, a tömeges frissítéseket, a modcsomagok kapcsolatának megszüntetését és a javítási felhívásokat – a rendszer automatikusan kihagyja. A veszélyes figyelmeztetéseket továbbra is megjeleníti."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Hagyd ki a lényegtelen figyelmeztetéseket"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Lehetővé teszi az oldalsáv be- és kikapcsolását."
|
||||
},
|
||||
@@ -147,7 +234,7 @@
|
||||
"message": "Szerverek böngészése"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Már hozzáadott szerverek elrejtése"
|
||||
"message": "A már hozzáadott szerverek elrejtése"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modcsomagok"
|
||||
@@ -156,17 +243,11 @@
|
||||
"message": "A tartalom hozzáadása ronthatja a kompatibilitást a szerverhez való csatlakozáskor. A hozzáadott tartalom elveszik, ha frissíted a szerverprofil tartalmát."
|
||||
},
|
||||
"app.browse.server.installing": {
|
||||
"message": "Letöltés..."
|
||||
"message": "Letöltés"
|
||||
},
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Nincs a(z) {compatibilityLabel} verziónak megfelelő elérhető verzió. Válassz ki egy verziót, ha mégis telepíteni szeretnéd. A függőségek nem települnek automatikusan."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Modcsomag telepítése..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Írd be a modcsomag leírását..."
|
||||
},
|
||||
@@ -176,26 +257,74 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Modcsomag exportálása"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Tartalmaz „{file}” fájlokat?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "A modcsomag neve"
|
||||
"message": "Modcsamag neve"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "A modcsomag neve"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Állítsd be, hogy mely fájlok kerüljenek bele az exportba"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Verziószám"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Tartalom letöltése"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Minecraft letöltése"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Csomagfájlok letöltése"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Felülírások kibontása"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Befejezés"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Telepítésre vár"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Java előkészítése"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "A Java {version} letöltése..."
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "A Java {version} kibontása..."
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "A Java {version} előkészítése..."
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "A Java {version} előkészítése..."
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "A Java {version} ellenőrzése"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Csomag adati kiolvasása"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": ""
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Minecraft Betöltése"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Tartalom betöltése"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Visszavonás"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Betöltő folyamatok futtatása"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Az profilodhoz tartozó összes adat véglegesen törlődik, beleértve a világokat, a beállításokat és az összes telepített tartalmat."
|
||||
"message": "A profilodhoz tartozó összes adat véglegesen törlődik, beleértve a világokat, a beállításokat és az összes telepített tartalmat."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Ezt a műveletet nem lehet visszavonni"
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Példány"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "{current, number}/{total, number} projekt letöltése..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Frissítés befejezése..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Verziók meghatározása..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
@@ -242,11 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Szerverek böngészése"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' **véglegesen törlődik**, és azt semmilyen módon nem lehet majd helyreállítani."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Törlés"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Biztosan véglegesen törölni szeretnéd ezt a világot?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Világ törlése"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Ez a világ véglegesen törölve lesz ebből a példányból. Ezt NEM tudod visszavonni!"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "{name} törlése"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modolt"
|
||||
@@ -266,44 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Nincs szerver vagy világ"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' eltávolításra kerül a listádról, beleértve a játékon belülieket is. Ezt a lépést nem tudod visszavonni."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Szerver eltávolítása"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) eltávolításra kerül a listádról, beleértve a játékon belülieket is. Ezt a lépést nem tudod visszavonni."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Szerver eltávolítása"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Biztosan el akarod távolítani ezt: {name}?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Ez a szerver el lesz távolítva a szerverlistádból és a játékbeli szerverlistából is. Később újra hozzáadhatod, ha tudod a címet."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "{name} eltávolítása"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Keresés {count} világ között..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "ez a szerver"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Szükséges tartalom"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Ne töltse le"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Telepítés a játékhoz"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Telepítés mindenképpen"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Telepítés"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Ezt a meghívót nem a Modrinth, hanem egy másik Modrinth-felhasználó hozta létre. Csak olyan személyektől fogadd el a meghívásokat, akikben megbízol."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count} mod"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Szükséges modcsomag"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Ehhez a szerverhez modok szükségesek a játékhoz. Kattints a Telepítés gombra, hogy telepítsd a szükséges fájlokat a Modrinth-ról, majd indítsd el közvetlenül a szervert."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Egy fájlt csak akkor vizsgálnak meg, ha azt a Modrinth-en közzétették, függetlenül a fájlformátumtól (beleértve a .mrpack formátumot is)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Megosztott profil"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Megosztott szerverprofil"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Ez a szerver-modpack olyan fájlokat tartalmaz, amelyek nem szerepelnek a Modrinth oldalon. Határozottan javasoljuk, hogy kizárólag olyan forrásokból telepíts fájlokat, amelyekben megbízol."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Figyelmeztetés ismeretlen fájlokról"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Felismerhetetlen fájlok"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Tartalom megtekintése"
|
||||
@@ -311,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Frissítsd a játékhoz"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Frissítés szükséges"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Törölve"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Frissítés szükséges ehhez: {name}. Kérlek, frissíts a legújabb verzióra a játék elindításához."
|
||||
@@ -320,11 +473,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Ez a projekt már telepítve van"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Verzió váltása"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Vissza a böngészéshez"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Tartalom telepítése a profilba"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Összes verzió"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Letöltés a böngészőben"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Telepítés..."
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Már le van töltve"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Fejlesztői mód bekapcsolva."
|
||||
@@ -437,9 +602,18 @@
|
||||
"app.skins.rate-limit.title": {
|
||||
"message": "Lassíts!"
|
||||
},
|
||||
"app.skins.reorder-error.text": {
|
||||
"message": "A kinézeted sorrendjét nem sikerült menteni."
|
||||
},
|
||||
"app.skins.reorder-error.title": {
|
||||
"message": "A skinek átrendezése sikertelen"
|
||||
},
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -483,7 +657,7 @@
|
||||
"message": "Kérlek jelentkezz be a Minecraft-fiókodba, hogy használni tudd a Modrinth App kinézetkezelési funkcióit."
|
||||
},
|
||||
"app.skins.sign-in.rinthbot-alt": {
|
||||
"message": "Izgatott Modrinth-bot"
|
||||
"message": "Izgatott Modrinth bot"
|
||||
},
|
||||
"app.skins.sign-in.title": {
|
||||
"message": "Kérlek jelentkezz be"
|
||||
@@ -729,7 +903,7 @@
|
||||
"message": "Kiadás"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release.description": {
|
||||
"message": "Csak a release verziók fognak megjelenni az elérhető frissítések között."
|
||||
"message": "Csak a 'kiadás' verziók fognak megjelenni az elérhető frissítések között."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.select": {
|
||||
"message": "Válaszd ki a frissítési csatornát"
|
||||
@@ -816,7 +990,7 @@
|
||||
"message": "Hozzárendelt memória"
|
||||
},
|
||||
"instance.settings.tabs.java.java-path-placeholder": {
|
||||
"message": "/path/to/java"
|
||||
"message": "/eleresi/ut/a/javahoz"
|
||||
},
|
||||
"instance.settings.tabs.window": {
|
||||
"message": "Ablak"
|
||||
@@ -857,11 +1031,14 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Cím másolása"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Gyorshivatkozás létrehozása"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Ne mutasd a kezdőlapon"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "A példány már el van indítva"
|
||||
"message": "A profil már el van indítva"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Hardcore mód"
|
||||
@@ -879,7 +1056,7 @@
|
||||
"message": "Csak Minecraft Alpha 1.0.5+-tól tudsz egyből szerverhez csatlakozni"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Csak Minecraft 1.20+-tól tudsz egyből egyjátékos világba belépni"
|
||||
"message": "Használj 1.20+ verziót az azonnali egyjátékos módba lépéshez"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Játék a profillal"
|
||||
@@ -927,30 +1104,9 @@
|
||||
"message": "Csak kliensoldali modok adhatók hozzá a szerverprofilhoz"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "A játékverziót a szerver biztosítja"
|
||||
"message": "A játékverzió a szerver által van megadva"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "A betöltőt a szerver biztosítja"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Egy fájlt csak akkor vizsgálunk meg, ha azt feltöltik a Modrinthra, függetlenül a fájlformátumtól (beleértve a .mrpack formátumot is)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Ne mutasd újra ezt a figyelmeztetést"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Telepítés megerősítése"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Letöltés mindenképpen"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "A rosszindulatú programokat gyakran modcsomag-fájlokon keresztül terjesztik, például a Discordhoz hasonló platformokon történő megosztás révén."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Ezt a fájlt nem találtuk meg a Modrinthon. Határozottan javasoljuk, hogy kizárólag megbízható forrásokból származó fájlokat telepíts."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Figyelmeztetés ismeretlen fájlról"
|
||||
"message": "A betöltő a szerver által van megadva"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,9 +146,6 @@
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Temukan server"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Sembunyikan server yang sudah ditambah"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Paket Mod"
|
||||
},
|
||||
@@ -161,12 +158,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Tidak ada versi tersedia yang cocok untuk {compatibilityLabel}. Anda tetap dapat memilih versi yang akan dipasang. Dependensi tidak akan dipasang secara otomatis."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Memasang paket mod..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Masukkan deskripsi paket mod..."
|
||||
},
|
||||
@@ -176,18 +167,9 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Ekspor paket mod"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Sertakan \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nama Paket Mod"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nama paket mod"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Konfigurasikan berkas mana yang disertakan dalam pengeksporan ini"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Nomor versi"
|
||||
},
|
||||
@@ -242,12 +224,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Telusuri server"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' akan **dihapus secara permanen**, dan Anda tidak akan dapat memulihkannya."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Apakah Anda yakin ingin menghapus dunia ini secara permanen?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Dimodifikasi"
|
||||
},
|
||||
@@ -266,24 +242,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Tidak ada server atau dunia yang ditambahkan"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' akan dihapus dari daftar Anda, termasuk di dalam permainan, dan Anda tidak akan dapat memulihkannya."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) akan dihapus dari daftar Anda, termasuk di dalam permainan, dan Anda tidak akan dapat memulihkannya."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Apakah Anda yakin ingin menghapus {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Cari {count} dunia..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "server ini"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Konten diperlukan"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Pasang untuk memainkan"
|
||||
},
|
||||
@@ -293,27 +254,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, other {# mod}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Paket mod yang diperlukan"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Mod diperlukan untuk bermain di server ini. Klik pasang untuk menyiapkan berkas-berkas yang diperlukan dari Modrinth, kemudian luncurkan langsung sari server."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instans terbagi"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instans server terbagi"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Lihat konten"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Perbarui untuk memainkan"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Perlu diperbarui"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "{name} perlu diperbarui sebelum dimainkan. Mohon perbarui ke versi terkini untuk meluncurkan permainan."
|
||||
},
|
||||
@@ -323,9 +272,6 @@
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Kembali ke halaman pencarian"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Pasang konten ke instans"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Mode pengembang dihidupkan."
|
||||
},
|
||||
@@ -937,26 +883,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Pemuat disediakan oleh server"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Berkas hanya akan ditinjau bila ia diunggah ke Modrinth, tak peduli format berkasnya (termasuk .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Jangan tampilkan peringatan ini lagi"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Konfirmasi pemasangan"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Tetap pasang"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Program jahat (malware) dibagikan melalui berkas paket mod dengan membagikannya melalui platform seperti Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Kami tidak dapat menemukan berkas ini di Modrinth. Kami sangat menyarankan Anda untuk hanya memasang berkas dari sumber-sumber terpercaya."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Peringatan berkas tidak dikenal"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Mostra meno istanze in esecuzione"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Copiati"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Copia dettagli"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Ignora"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Apri istanza"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Riprova"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Annullato per app chiusa"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Impossibile leggere il pacchetto"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Annullato"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "La pulizia è stata interrotta"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Impossibile scaricare i file"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Il file scaricato è corrotto"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Impossibile salvare i file"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Il download è stato interrotto"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "L'istanza non è stata trovata"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "Percorso del file errato"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Dati del pacchetto non validi"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Metadati del pacchetto non validi"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "La configurazione di Java è stata interrotta"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Il loader non è stato configurato"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Impossibile aggiornare i dati locali"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Minecraft non è stato configurato"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Impossibile collegarsi a Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Permessi di scrittura mancanti"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Impossibile scaricare il pacchetto"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Qualcosa è andato storto"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Istanza sconosciuta"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installazioni"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Rendi primaria"
|
||||
},
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Mostra le ore di gioco"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Salta automaticamente le conferme a basso rischio, come l'installazione di pacchetti di mod duplicati, la normale eliminazione di contenuti, gli aggiornamenti simultanei, lo scollegare i pacchetti di mod e le richieste di riparazione. Le avvertenze verranno comunque mostrate."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Salta le conferme poco importanti"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Mostra o nascondi la barra laterale."
|
||||
},
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Nessuna versione disponibile soddisfa {compatibilityLabel}. Puoi selezionare una versione da installare comunque. Le dipendenze non verranno scaricate automaticamente."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Installando il pacchetto..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Inserisci descrizione del pacchetto..."
|
||||
},
|
||||
@@ -176,24 +257,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Esporta pacchetto"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Includere \"{file}\" nell'esportazione?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nome del pacchetto"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nome del pacchetto"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Seleziona i file da includere in questa esportazione"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Numero di versione"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Download dei contenuti"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Download di Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Download del pacchetto"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Estrazione delle sovrascritture"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Finalizzazione"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "In coda per l'installazione"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Preparazione di Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Download di Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Estrazione di Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Recupero di Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Preparazione di Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validazione di Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Lettura del manifesto"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Risoluzione del loader"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Risoluzione di Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Risoluzione dei contenuti"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Annullamento"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Esecuzione dei processori del loader"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Tutti i dati della tua istanza verranno eliminati permanentemente, inclusi i tuoi mondi, configurazioni e tutti i contenuti installati."
|
||||
},
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Istanza"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "{current, number}/{total, number} progetti scaricati..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Finalizzando l'aggiornamento..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Risolvendo le versioni..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "progetto"
|
||||
},
|
||||
@@ -239,8 +377,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Esplora i server"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Vuoi davvero eliminare questo mondo per sempre?"
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Elimina mondo"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Eliminare il mondo"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Questo mondo verrà eliminato permanentemente da questa istanza. Questa azione non può essere annullata."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Eliminare {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Moddato"
|
||||
@@ -260,38 +407,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Nessun server o mondo aggiunto"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Vuoi davvero rimuovere {name}?"
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Rimuovi server"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Rimuovere il server"
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Questo server verrà rimosso dalla tua lista di server nell'app e nel gioco. Potrai aggiungerlo nuovamente se conosci l'indirizzo."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Rimuovere {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Cerca tra {count} mondi..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "questo server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Contenuto richiesto"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Non installare"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installa per continuare"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Installa comunque"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installa"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Questo invito è stato creato da un utente e non da Modrinth. Accetta solo gli inviti da persone fidate."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count} mod"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Pacchetto di mod richiesto"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Questo server richiede alcune mod. Clicca Installa per scaricarle direttamente da Modrinth, poi sarai pronto a giocare."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Solo i file pubblicati su Modrinth vengono esaminati, qualunque sia il loro formato (.mrpack inclusi)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Istanza condivisa"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Istanza del server condivisa"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Questo pacchetto contiene dei file che non sono su Modrinth. Consigliamo di installare file solo da fonti attendibili."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "File sconosciuti"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "File non riconosciuti"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Mostra contenuti"
|
||||
@@ -299,8 +461,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aggiorna per continuare"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aggiornamento richiesto"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Rimosso"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "{name} richiede degli aggiornamenti. Installa l'ultima versione per poter giocare."
|
||||
@@ -308,11 +470,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Questo progetto è già stato installato"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Cambia versione"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Torna a Esplora"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Installa il contenuto nell'istanza"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Tutte le versioni"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Scarica col browser"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Installazione"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Già installate"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modalità sviluppatore attiva."
|
||||
@@ -434,6 +608,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -851,6 +1028,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copia indirizzo"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Crea collegamento"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Non mostrare nella home"
|
||||
},
|
||||
@@ -925,26 +1105,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Il loader è determinato dal server"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Solo i file caricati su Modrinth vengono esaminati, qualunque sia il loro formato (.mrpack inclusi)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Non mostrare più questo avviso"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Conferma l'installazione"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Installa comunque"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Spesso i malware vengono nascosti nei pacchetti di mod, poi distribuiti su piattaforme come Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Non è stato possibile trovare questo file su Modrinth. Consigliamo di installare file solo da fonti attendibili."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Tipo di file sconosciuto"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,51 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "実行中のインスタンスの一部を非表示"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "コピーしました"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "詳細をコピー"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "閉じる"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "インスタンスを表示"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "再試行"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "アプリの終了によりキャンセルされました"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "ModPackを読み込むことができませんでした"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "キャンセルしました"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "クリーンアップが完了しませんでした"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "ファイルをダウンロードできませんでした"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "ダウンロードしたファイルが破損しています"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "ファイルを保存できませんでした"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "ダウンロードを完了することができませんでした"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "不明なインスタンス"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "インストール数"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "デフォルトのインスタンスを作成"
|
||||
},
|
||||
@@ -29,6 +74,9 @@
|
||||
"app.action-bar.stop-instance": {
|
||||
"message": "インスタンスを停止"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "アップデート"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "進行中のダウンロードを表示"
|
||||
},
|
||||
@@ -95,6 +143,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "プレイ時間を表示"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Modパックの重複インストール、通常のコンテンツ削除、一括更新、Modパックのリンク解除、修復の促しなど、リスクの低い確認画面は自動的にスキップされます。危険な警告は引き続き表示されます。"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "重要でない警告をスキップ"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "サイドバーの表示/非表示を切り替える機能を有効にします。"
|
||||
},
|
||||
@@ -125,6 +179,9 @@
|
||||
"app.browse.already-added": {
|
||||
"message": "すでに追加済み"
|
||||
},
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "インスタンスに戻る"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "コンテンツを探す"
|
||||
},
|
||||
@@ -140,12 +197,6 @@
|
||||
"app.browse.server.installing": {
|
||||
"message": "インストール中"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Modパックをインストール中..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Modパックの説明を入力…"
|
||||
},
|
||||
@@ -155,9 +206,6 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Modパックを書き出す"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modパック名"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modパック名"
|
||||
},
|
||||
@@ -167,6 +215,9 @@
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Java {version} をダウンロードしています"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "インスタンス内のすべてのデータは、ワールド、設定、インストール済みのコンテンツを含め、完全に削除されます。"
|
||||
},
|
||||
@@ -215,11 +266,8 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "サーバーを探す"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' は **完全に削除**され、元に戻すことはできません。"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "本当にこのワールドを完全に削除しますか?"
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "{name} を削除します"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Mod導入済み"
|
||||
@@ -239,24 +287,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "サーバー、ワールドは追加されていません"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' はゲーム内を含むサーバーリストから削除され、元に戻すことはできません。"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) はゲーム内を含むサーバーリストから削除され、元に戻すことはできません。"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "本当に {name} を削除しますか?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "{count} 個のワールドを検索…"
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "このサーバー"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "必須コンテンツ"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "インストールしてプレイ"
|
||||
},
|
||||
@@ -266,30 +299,21 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, other {#個のMod}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "必須のModパック"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "このサーバーをプレイするにはModが必要です。インストールをクリックしてModrinthから必要なファイルを設定し、サーバーに接続してください。"
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "共有インスタンス"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "共有サーバーインスタンス"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "コンテンツを見る"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "更新してプレイ"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "更新が必要です"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "{name}をプレイするには更新が必要です。ゲームを起動するには最新版に更新してください。"
|
||||
},
|
||||
"app.project.version.all-versions": {
|
||||
"message": "すべてのバージョン"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "開発者モードがオンになっています。"
|
||||
},
|
||||
@@ -329,8 +353,17 @@
|
||||
"app.skins.modal.no-cape-tooltip": {
|
||||
"message": "マントなし"
|
||||
},
|
||||
"app.skins.modal.none-cape-option": {
|
||||
"message": "無し"
|
||||
},
|
||||
"app.skins.modal.replace-texture-button": {
|
||||
"message": "置きかえる"
|
||||
"message": "アップロード"
|
||||
},
|
||||
"app.skins.modal.save-skin-button": {
|
||||
"message": "スキンを保存する"
|
||||
},
|
||||
"app.skins.modal.saving-tooltip": {
|
||||
"message": "保存しています…"
|
||||
},
|
||||
"app.skins.modal.texture-section": {
|
||||
"message": "テクスチャ"
|
||||
@@ -590,6 +623,12 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "名前"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "ベータ"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release": {
|
||||
"message": "リリース"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "起動フック"
|
||||
},
|
||||
@@ -769,26 +808,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "ローダーはサーバーによる条件です"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "ファイル形式に関わらず、Modrinthにアップロードされたファイルのみが確認されます。(.mrpackを含む)"
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "この警告を次回から表示しない"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "インストールの確認"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "インストールを続行"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "一般的にマルウェアは、Discord等のプラットフォーム上でModパックファイルを配布して拡散されます"
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "このファイルをModrinth上で見つけることができませんでした。信頼できるソースからインストールすることを強くお勧めします。"
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "不明なファイルの警告"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"message": "Java {version} 다운로드 중"
|
||||
},
|
||||
"app.action-bar.downloading-update": {
|
||||
"message": "업데이트 다운로드중"
|
||||
"message": "업데이트 다운로드 중"
|
||||
},
|
||||
"app.action-bar.downloads": {
|
||||
"message": "다운로드"
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "실행 중인 인스턴스 숨기기"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "복사됨"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "세부 정보 복사"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "무시"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "인스턴스 열기"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "재시도"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "앱이 종료되어 취소되었습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "모드팩을 읽을 수 없음"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "취소됨"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "파일 정리가 완료되지 않았습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "파일을 다운로드할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "다운로드한 파일이 손상되었습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "파일을 저장할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "다운로드를 완료할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "인스턴스를 찾을 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "파일 경로가 올바르지 않습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "모드팩 데이터가 올바르지 않습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "모드팩 파일이 올바르지 않은 메타데이터를 가지고 있습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Java 설치를 완료할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "로더 설치에 실패했습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "로컬 데이터를 업데이트할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Minecraft 설치에 실패했습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Modrinth에 연결할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "쓰기 권한이 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "팩을 다운로드할 수 없습니다"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "무언가 잘못되었습니다"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "알 수 없는 인스턴스"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "설치"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "기본 인스턴스로 지정"
|
||||
},
|
||||
@@ -23,12 +104,18 @@
|
||||
"app.action-bar.primary-instance": {
|
||||
"message": "기본 인스턴스"
|
||||
},
|
||||
"app.action-bar.reload-to-update": {
|
||||
"message": "업데이트하려면 다시 로드"
|
||||
},
|
||||
"app.action-bar.show-more-running-instances": {
|
||||
"message": "실행 중인 인스턴스 보이기"
|
||||
},
|
||||
"app.action-bar.stop-instance": {
|
||||
"message": "인스턴스 멈추기"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "업데이트"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "다운로드 목록 보기"
|
||||
},
|
||||
@@ -95,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "플레이 시간 표시"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "중복되는 모드팩 설치와 일반적인 콘텐츠 삭제, 동시 업데이트, 모드팩 링크 제거, 프롬프트 복구처럼 리스크가 적은 행위에 대한 확인 절차를 자동으로 넘깁니다. 위험한 경고는 여전히 표시됩니다."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "중요하지 않은 경고 넘기기"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "사이드바를 접거나 펼칠 수 있는 기능을 활성화합니다."
|
||||
},
|
||||
@@ -141,7 +234,7 @@
|
||||
"message": "서버 탐색하기"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "이미 추가된 서버 숨기기"
|
||||
"message": "이미 추가한 서버 숨기기"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "모드팩"
|
||||
@@ -155,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "{compatibilityLabel} 버전과 일치하는 버전이 없습니다. 설치할 버전을 선택하세요. 종속성은 자동으로 설치되지 않습니다."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "모드팩 설치중..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "모드팩 설명 입력..."
|
||||
},
|
||||
@@ -170,24 +257,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "모드팩 내보내기"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "\"{file}\"(을)를 포함할까요?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "모드팩 이름"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "모드팩 이름"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "내보내기에 어느 파일이 포함될지 구성"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "버전 구분"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "콘텐츠 다운로드 중"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Minecraft 다운로드 중"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "팩 파일 다운로드 중"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "재정의 콘텐츠 추출 중"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "마무리 중"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "설치 대기열에 추가됨"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Java 준비 중"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Java {version} 다운로드 중"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Java {version} 추출 중"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Java {version} 가져오는 중"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Java {version} 준비 중"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Java {version} 유효성 검사 중"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "팩 manifest 읽는 중"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "로더 해결 중"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Minecraft 해결 중"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "콘텐츠 해결 중"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "뒤로 돌리는 중"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "로더 진행기 실행 중"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "인스턴스의 모든 데이터가 삭제됩니다. 세계 폴더, 설정 폴더 등 설치된 모든 컨텐츠가 포함됩니다."
|
||||
},
|
||||
@@ -212,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "인스턴스"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "{current, number}/{total, number} 프로젝트 다운로드 중..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "업데이트 마무리 중..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "버전 해결 중..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "프로젝트"
|
||||
},
|
||||
@@ -236,11 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "서버 탐색하기"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}'이(가) **영구적으로 삭제**되며, 복구할 수 없습니다."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "세계 삭제"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "정말로 이 세계를 영구적으로 삭제하시겠습니까?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "세계 삭제"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "이 세계는 이 인스턴스로부터 영구적으로 삭제됩니다. 이 작업은 되돌릴 수 없습니다."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "{name} 삭제 중"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "수정됨"
|
||||
@@ -260,44 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "추가된 서버 또는 세계 없음"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}'이(가) 게임 내를 포함한 모든 목록에서 삭제되며, 복구할 수 없습니다."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "서버 제거"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address})이(가) 게임 내를 포함한 모든 목록에서 삭제되며, 복구할 수 없습니다."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "서버 제거"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "정말로 {name}을(를) 제거하시겠습니까?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "이 서버는 서버 목록과 게임 내 서버 목록으로부터 삭제됩니다. 주소를 안다면 추후 다시 추가할 수 있습니다."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "{name} 제거 중"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "{count}개의 세계 검색..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "이 서버"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "콘텐츠 설치 필요"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "설치하지 않음"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "설치하고 플레이"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "무시하고 설치"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "설치"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "이 초대장은 다른 Modrinth 사용자가 생성했으며, Modrinth에서 생성하지 않았습니다. 신뢰할 수 있는 초대장만 수락하십시오."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {모드 #개} other {모드 #개}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "필요한 모드팩"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "이 서버를 플레이하려면 모드가 필요합니다. '설치'를 클릭하여 Modrinth에서 필수 파일을 내려받은 후, 서버에 바로 접속하세요."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "모든 파일은 형식(.mrpack 포함)에 무관하게 Modrinth에 게시되어야만 검수를 거칩니다."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "인스턴스 공유됨"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "서버 인스턴스 공유됨"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "이 서버의 모드팩은 Modrinth에 게시되지 않은 파일을 포함하고 있습니다. 신뢰할 수 있는 출처의 파일만 설치하는 것을 강력히 권장합니다."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "출처를 알 수 없는 파일"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "확인되지 않은 파일"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "구성 요소 보기"
|
||||
@@ -305,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "업데이트하고 플레이"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "업데이트 필요"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "제거됨"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "{name}을(를) 플레이하려면 업데이트가 필요합니다. 게임을 실행하려면 최신 버전으로 업데이트해 주세요."
|
||||
@@ -314,12 +473,12 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "이미 설치되어 있음"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "버전 변경"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "탐색으로 돌아가기"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "인스턴스에 콘텐츠 설치"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "개발자 모드가 활성화되었습니다."
|
||||
},
|
||||
@@ -431,9 +590,18 @@
|
||||
"app.skins.rate-limit.title": {
|
||||
"message": "잠시 기다려주세요."
|
||||
},
|
||||
"app.skins.reorder-error.text": {
|
||||
"message": "이 스킨 정렬은 저장되지 않습니다."
|
||||
},
|
||||
"app.skins.reorder-error.title": {
|
||||
"message": "스킨 재정렬 실패"
|
||||
},
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "카오스 큐브"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -503,6 +671,9 @@
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "다운로드 완료"
|
||||
},
|
||||
"app.update-popup.reload": {
|
||||
"message": "새로고침하여 업데이트"
|
||||
},
|
||||
"app.update-popup.title": {
|
||||
"message": "업데이트 가능"
|
||||
},
|
||||
@@ -701,6 +872,30 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "이름"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel": {
|
||||
"message": "채널 업데이트"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha": {
|
||||
"message": "알파"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha.description": {
|
||||
"message": "릴리스와 베타, 알파 버전이 이용 가능한 업데이트에 표시됩니다."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "베타"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta.description": {
|
||||
"message": "릴리스와 베타 버전이 이용 가능한 업데이트에 표시됩니다."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release": {
|
||||
"message": "릴리스"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release.description": {
|
||||
"message": "릴리스 버전만 이용 가능한 업데이트에 표시됩니다."
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.select": {
|
||||
"message": "업데이트 채널 선택"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "실행 후크"
|
||||
},
|
||||
@@ -824,6 +1019,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "주소 복사"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "바로가기 만들기"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "홈에서 숨기기"
|
||||
},
|
||||
@@ -898,26 +1096,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "로더가 서버에 의해 제공됩니다"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "모든 파일은 형식(.mrpack 포함)에 무관하게 Modrinth에 업로드되어야만 검수를 거칩니다."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "이 경고를 다시 표시하지 않음"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "설치 확인"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "무시하고 설치"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "악성코드는 흔히 디스코드와 같은 플랫폼을 통해 모드팩 파일을 공유하는 방식으로 유포됩니다."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "이 파일을 Modrinth에서 찾을 수 없습니다. 신뢰할 수 있는 출처의 파일만 설치하는 것을 권장합니다."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "출처를 알 수 없는 파일 경고"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Sembunyikan lebih banyak pemasangan yang berjalan"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Ketepikan"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Cuba semula"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Jadikan pemasangan utama"
|
||||
},
|
||||
@@ -26,6 +32,9 @@
|
||||
"app.action-bar.stop-instance": {
|
||||
"message": "Hentikan pemasangan"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "Kemas kini"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "Lihat muat turun aktif"
|
||||
},
|
||||
@@ -86,6 +95,9 @@
|
||||
"app.appearance-settings.select-option": {
|
||||
"message": "Pilih satu pilihan"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Melangkau pengesahan berisiko rendah secara automatik seperti pemasangan pek mod pendua, pemadaman kandungan biasa, kemas kini pukal, menyahpautkan pek mod dan gesaan pembaikan. Amaran berbahaya masih akan ditunjukkan."
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Membolehkan keupayaan untuk menogol bar sisi."
|
||||
},
|
||||
@@ -131,9 +143,6 @@
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Temui pelayan"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Sembunyikan pelayan yang sudah ditambah"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Pek Mod"
|
||||
},
|
||||
@@ -146,12 +155,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Tiada versi tersedia yang sepadan dengan {compatibilityLabel}. Pilih versi untuk dipasang juga. Kebergantungan tidak akan dipasang secara automatik."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Sedang memasang pek mod..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Masukkan keterangan pek mod..."
|
||||
},
|
||||
@@ -161,24 +164,33 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Eksport pek mod"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Sertakan \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nama Pek Mod"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nama pek mod"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Konfigurasikan fail yang disertakan dalam eksport ini"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Nombor versi"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Sedang memuat turun Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Sedang mengekstrak Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Sedang mengambil Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Sedang menyediakan Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Sedang mengesahkan Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Sedang membaca manifest pek"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Semua data untuk pemasangan anda akan dipadamkan secara kekal, termasuk dunia, konfigurasi dan semua kandungan yang dipasang."
|
||||
},
|
||||
@@ -227,12 +239,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Layari pelayan"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' akan **dipadamkan secara kekal**, dan tiada cara untuk memulihkannya."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Adakah anda pasti mahu memadamkan dunia ini secara kekal?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Diubah Suai"
|
||||
},
|
||||
@@ -251,24 +257,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Tiada pelayan atau dunia ditambah"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' akan dialih keluar daripada senarai anda, termasuk dalam permainan, dan tiada cara untuk memulihkannya."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) akan dialih keluar daripada senarai anda, termasuk dalam permainan, dan tiada cara untuk memulihkannya."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Adakah anda pasti mahu mengalih keluar {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Cari {count} dunia..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "pelayan ini"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Kandungan yang diperlukan"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Pasang untuk mainkan"
|
||||
},
|
||||
@@ -278,27 +269,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, other {# mod}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Pek mod yang diperlukan"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Pelayan ini memerlukan mod untuk dimainkan. Klik Pasang untuk menyediakan fail yang diperlukan daripada Modrinth, kemudian lancarkan permainan terus ke dalam pelayan."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Pemasangan yang dikongsi"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Pemasangan pelayan yang dikongsi"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Lihat kandungan"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Kemas kini untuk mainkan"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Kemas kini diperlukan"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Kemas kini diperlukan untuk memainkan {name}. Sila kemas kini kepada versi terkini untuk melancarkan permainan."
|
||||
},
|
||||
@@ -308,9 +287,6 @@
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Kembali menemukan"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Pasang kandungan ke dalam pemasangan"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Mod pembangun didayakan."
|
||||
},
|
||||
@@ -656,6 +632,15 @@
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Nama"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.alpha": {
|
||||
"message": "Alfa"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.beta": {
|
||||
"message": "Beta"
|
||||
},
|
||||
"instance.settings.tabs.general.update-channel.release": {
|
||||
"message": "Terbitan"
|
||||
},
|
||||
"instance.settings.tabs.hooks": {
|
||||
"message": "Cangkuk pelancaran"
|
||||
},
|
||||
@@ -853,26 +838,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Pemuat adalah disediakan oleh pelayan"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Sesuatu fail hanya disemak jika ia dimuat naik ke Modrinth, tanpa mengira format failnya (termasuk .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Jangan tunjukkan amaran ini lagi"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Sahkan pemasangan"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Pasangkan juga"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Perisian hasad sering diedarkan melalui fail pek mod dengan berkongsinya di platform seperti Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Kami tidak dapat menemui fail ini di Modrinth. Kami sangat mengesyorkan anda untuk hanya memasang fail daripada sumber yang anda percayai."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Amaran fail tidak diketahui"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Verberg meer actieve instanties"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Gekopieerd"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Details kopiëren"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Sluiten"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Instantie openen"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Opnieuw proberen"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Geannuleerd vanwege het sluiten van de app"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Modpack kon niet gelezen worden"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Geannuleerd"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "Opschonen is niet voltooid"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Bestanden konden niet gedownload worden"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Gedownloade bestand is beschadigd"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Bestanden konden niet opgeslagen worden"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Downloaden kon niet worden voltooid"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "Instantie kon niet gevonden worden"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "Bestandspad is ongeldig"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Modpack-gegevens ongeldig"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Modpack-bestanden bevatten ongeldige metagegevens"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Installatie van Java kon niet worden voltooid"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Instellen van loader is mislukt"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Lokale gegevens konden niet bijgewerkt worden"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Instellen van Minecraft is mislukt"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Modrinth kon niet bereikt worden"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Geen schrijfrechten"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Pack kon niet gedownload worden"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Er is iets misgegaan"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Onbekende instantie"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installaties"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Maak primaire instantie"
|
||||
},
|
||||
@@ -33,7 +114,7 @@
|
||||
"message": "Stop instantie"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "Updaten"
|
||||
"message": "Bijwerken"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "Bekijk actieve downloads"
|
||||
@@ -60,7 +141,7 @@
|
||||
"message": "Wijzig de pagina waarop de launcher opent."
|
||||
},
|
||||
"app.appearance-settings.default-landing-page.home": {
|
||||
"message": "Home"
|
||||
"message": "Start"
|
||||
},
|
||||
"app.appearance-settings.default-landing-page.library": {
|
||||
"message": "Bibliotheek"
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Speeltijd laten zien"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Bevestigingen met een laag risico, zoals het installeren van dubbele modpacks, het verwijderen van normale inhoud, bulkupdates, het ontkoppelen van modpacks en reparatieverzoeken, worden automatisch overgeslagen. Waarschuwingen voor gevaarlijke dingen worden nog steeds weergegeven."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Niet-essentiële waarschuwingen overslaan"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Schakelt de mogelijkheid om de zijbalk in- of uit te schakelen in."
|
||||
},
|
||||
@@ -141,19 +228,19 @@
|
||||
"message": "Terug naar instantie"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Ontdek content"
|
||||
"message": "Inhoud ontdekken"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Ontdek servers"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Verberg al toegevoegde servers"
|
||||
"message": "Al toegevoegde servers verbergen"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpacks"
|
||||
},
|
||||
"app.browse.server-instance-content-warning": {
|
||||
"message": "Het toevoegen van content kan de compatibiliteit verbreken bij het verbinden met de server. Alle toegevoegde inhoud gaat ook verloren wanneer u de content van de serverinstantie bijwerkt."
|
||||
"message": "Het toevoegen van inhoud kan de compatibiliteit verstoren bij het verbinden met de server. Eventuele toegevoegde inhoud gaat bovendien verloren wanneer je de inhoud van de serverinstantie bijwerkt."
|
||||
},
|
||||
"app.browse.server.installing": {
|
||||
"message": "Installeren"
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Er zijn geen beschikbare versies die overeenkomen met {compatibilityLabel}. Selecteer toch een versie om te installeren. Afhankelijkheden worden niet automatisch geïnstalleerd."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Modpack aan het installeren..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Voeg modpack beschrijving in..."
|
||||
},
|
||||
@@ -176,26 +257,74 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exporteer modpack"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Betrek \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpack Naam"
|
||||
"message": "Naam van modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpack naam"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Configureer welke bestanden bij deze export zijn betrokken"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versie nummer"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Inhoud aan het downloaden"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Minecraft aan het downloaden"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Pakketbestand aan het downloaden"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Overschrijvingen eruit halen"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Aan het afronden"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "In de wachtrij voor installatie"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Java aan het voorbereiden"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Java {version} aan het downloaden"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Java {version} aan het uitpakken"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Java {version} aan het ophalen"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Java {version} aan het voorbereiden"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Java {version} aan het valideren"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Paketmanifest aan het lezen"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Loader wordt bepaald"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Minecraft wordt bepaald"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Inhoud aan het bepalen"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Aan het terugdraaien"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Loader-processors aan het uitvoeren"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle data van je instantie zal permanent verwijderd worden, inclusief al je werelden, voorkeuren, en alle geïnstalleerde content."
|
||||
"message": "Alle gegevens van je instantie worden definitief verwijderd, inclusief je werelden, configuraties en alle geïnstalleerde inhoud."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Deze actie kan niet ongedaan gemaakt worden"
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instantie"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "{current, number}/{total, number} projecten aan het downloaden..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Update aan het afronden..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Versies worden bepaald..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "project"
|
||||
},
|
||||
@@ -242,8 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Zoek servers"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Weet je zeker dat je deze wereld definitief wilt verwijderen?"
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Wereld verwijderen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Wereld verwijderen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Deze wereld wordt definitief uit deze instantie verwijderd. Deze actie kan niet ongedaan worden gemaakt."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "{name} verwijderen"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Gemod"
|
||||
@@ -263,53 +410,62 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Noch servers noch werelden toegevoegd"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' wordt uit je lijst verwijderd, ook in de game, en kan op geen enkele manier worden hersteld."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Server verwijderen"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) wordt uit je lijst verwijderd, ook in de game, en kan op geen enkele manier worden hersteld."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Server verwijderen"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Ben je zeker dat je {name} wil verwijderen?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Deze server wordt verwijderd uit je serverlijst en uit de serverlijst in het spel. Je kunt hem later weer toevoegen als je het adres weet."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "{name} verwijderen"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Zoek werelden"
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "deze server"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Content vereist"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Niet installeren"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installeer om te spelen"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Toch installeren"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Installeer"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Deze uitnodiging is aangemaakt door een andere Modrinth-gebruiker, niet door Modrinth zelf. Accepteer alleen uitnodigingen van mensen die je vertrouwt."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural,one {# mod}other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Vereist modpack"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Deze server vereist mods om te spelen. Klik op Installeer om de vereiste bestanden van Modrinth in te stellen, en start direct in de server."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Een bestand wordt alleen beoordeeld als het op Modrinth wordt gepubliceerd, ongeacht het bestandsformaat (inclusief .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Gedeelde instantie"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Gedeelde server instantie"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Dit server-modpack bevat bestanden die niet op Modrinth zijn gepubliceerd. We raden je ten zeerste aan om alleen bestanden te installeren uit bronnen die je vertrouwt."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Waarschuwing voor onbekende bestanden"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Onbekende bestanden"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Toon content"
|
||||
"message": "Inhoud bekijken"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Update om te spelen"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Update vereist"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Verwijderde"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Een update is vereist om {name} te spelen. Update naar de laatste versie om het spel te starten."
|
||||
@@ -317,12 +473,12 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Dit project is al geïnstalleerd"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Versie wijzigen"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Terug naar Ontdekken"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Installeer content naar instantie"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Ontwikkelaarsmodus ingeschakeld."
|
||||
},
|
||||
@@ -438,11 +594,14 @@
|
||||
"message": "Je skinvolgorde kon niet worden opgeslagen."
|
||||
},
|
||||
"app.skins.reorder-error.title": {
|
||||
"message": "Het herschikken van skins is mislukt."
|
||||
"message": "Herschikken van skins is mislukt"
|
||||
},
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -669,7 +828,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, zodra je een instantie verwijdert, is het niet meer mogelijk om deze te herstellen."
|
||||
"message": "Hiermee wordt een instantie definitief van je apparaat verwijderd, inclusief je werelden, instellingen en alle geïnstalleerde inhoud. Wees voorzichtig, want zodra je een instantie hebt verwijderd, kun je deze niet meer herstellen."
|
||||
},
|
||||
"instance.settings.tabs.general.deleting.button": {
|
||||
"message": "Verwijderen..."
|
||||
@@ -860,6 +1019,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopieer adres"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Snelkoppeling maken"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Niet tonen op de startpagina"
|
||||
},
|
||||
@@ -934,26 +1096,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader is gegeven door de server"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Een bestand wordt alleen beoordeeld als het naar Modrinth is geüpload, ongeacht het bestandsformaat (inclusief .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Toon deze waarschuwing niet opnieuw"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Bevestig installatie"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Installeer toch"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Malware wordt vaak verspreid via modpack-bestanden door ze te delen op platforms zoals Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "We konden dit bestand niet vinden op Modrinth. We raden ten zeerste aan om alleen bestanden te installeren van bronnen die u vertrouwt."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Waarschuwing voor onbekend bestand"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,220 @@
|
||||
{
|
||||
"app.action-bar.downloading-java": {
|
||||
"message": "Laster ned Java {version}"
|
||||
},
|
||||
"app.action-bar.downloading-update": {
|
||||
"message": "Laster ned oppdatering"
|
||||
},
|
||||
"app.action-bar.downloads": {
|
||||
"message": "Nedlastninger"
|
||||
},
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Skjul flere kjørende tilfeller"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Åpne tilfelle"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Prøv igjen"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Ukjent tilfelle"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Installeringer"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Gjør om til primærtilfelle"
|
||||
},
|
||||
"app.action-bar.no-instances-running": {
|
||||
"message": "Ingen kjørende tilfeller"
|
||||
},
|
||||
"app.action-bar.offline": {
|
||||
"message": "Uten nett"
|
||||
},
|
||||
"app.action-bar.primary-instance": {
|
||||
"message": "Primærtilfelle"
|
||||
},
|
||||
"app.action-bar.reload-to-update": {
|
||||
"message": "Last inn på nytt for å oppdatere"
|
||||
},
|
||||
"app.action-bar.show-more-running-instances": {
|
||||
"message": "Vis flere kjørende tilfeller"
|
||||
},
|
||||
"app.action-bar.stop-instance": {
|
||||
"message": "Stopp tilfelle"
|
||||
},
|
||||
"app.action-bar.update": {
|
||||
"message": "Oppdater"
|
||||
},
|
||||
"app.action-bar.view-active-downloads": {
|
||||
"message": "Vis aktive nedlastninger"
|
||||
},
|
||||
"app.action-bar.view-instance": {
|
||||
"message": "Vis tilfelle"
|
||||
},
|
||||
"app.action-bar.view-logs": {
|
||||
"message": "Vis logger"
|
||||
},
|
||||
"app.appearance-settings.advanced-rendering.description": {
|
||||
"message": "Skrur på avansert rendering, som for eksempel uskarphetseffekter, som kan forårsake ytelsesproblemer om man ikke har maskinvareaksellerert rendering."
|
||||
},
|
||||
"app.appearance-settings.advanced-rendering.title": {
|
||||
"message": "Avansert rendering"
|
||||
},
|
||||
"app.appearance-settings.color-theme.description": {
|
||||
"message": "Velg ditt foretrukne fargetema for Modrinth App."
|
||||
},
|
||||
"app.appearance-settings.color-theme.title": {
|
||||
"message": "Fargetema"
|
||||
},
|
||||
"app.appearance-settings.default-landing-page.description": {
|
||||
"message": "Endre sida som vises når launcheren åpnes."
|
||||
},
|
||||
"app.appearance-settings.default-landing-page.home": {
|
||||
"message": "Hjem"
|
||||
},
|
||||
"app.appearance-settings.default-landing-page.library": {
|
||||
"message": "Bibliotek"
|
||||
},
|
||||
"app.appearance-settings.default-landing-page.title": {
|
||||
"message": "Åpningsside"
|
||||
},
|
||||
"app.appearance-settings.hide-nametag.description": {
|
||||
"message": "Skjuler navnelappen over din spiller på utseende siden."
|
||||
},
|
||||
"app.appearance-settings.hide-nametag.title": {
|
||||
"message": "Gjøm navnelapp"
|
||||
},
|
||||
"app.appearance-settings.minimize-launcher.title": {
|
||||
"message": "Minimer launcheren"
|
||||
},
|
||||
"app.appearance-settings.select-option": {
|
||||
"message": "Velg et alternativ"
|
||||
},
|
||||
"app.appearance-settings.show-play-time.description": {
|
||||
"message": "Viser hvor lenge du har spilt et tilfelle."
|
||||
},
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Vis spilletid"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Hopper automatisk over lav-rissiko fastslåelser som modpakkeinstalasjonsduplikat, vanlig innholdsletting, bolkoppdateringer, avkoble modpakker, og reparasjonsprompter. Farlige advarsler vil fortsatt vises."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Hopp over mindre viktige advarsler"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Aktiverer evnen til å skru sidefeltet av/på."
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.title": {
|
||||
"message": "Sidefeltsveksling"
|
||||
},
|
||||
"app.appearance-settings.unknown-pack-warning.description": {
|
||||
"message": "Hvis du prøver å laste ned en Modrinth Pakke fil (.mrpack) som er ukjent for Modrinth så kommer vi til å forsikre oss om at du forstår risikoene før du installerer den."
|
||||
},
|
||||
"app.appearance-settings.unknown-pack-warning.title": {
|
||||
"message": "Advar meg før jeg installerer ukjente modpakker"
|
||||
},
|
||||
"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.browse.add-servers-to-instance": {
|
||||
"message": "Legger til server til tilfelle"
|
||||
},
|
||||
"app.browse.add-to-an-instance": {
|
||||
"message": "Legg til til et tilfelle"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Legg til til tilfelle"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Legg til til {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Lagt til"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Allerede lagt til"
|
||||
},
|
||||
"app.browse.back-to-instance": {
|
||||
"message": "Tilbake til tilfelle"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Oppdag innhold"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Oppdag servere"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Gjem servere som allerede er lagt til"
|
||||
},
|
||||
"app.browse.project-type.modpacks": {
|
||||
"message": "Modpakker"
|
||||
},
|
||||
"app.browse.server-instance-content-warning": {
|
||||
"message": "Å legge til innhold kan ødelegge komatibilitet når du blir med i serveren. Alt tilleggsinnhold vil også forsvinne når du oppdaterer servertilfelleinnholdet."
|
||||
},
|
||||
"app.browse.server.installing": {
|
||||
"message": "Installerer"
|
||||
},
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Ingen tilgjengelige versjoner matcher {compatibilityLabel}. Velg en versjon for å installere uansett. Avhengigheter vil ikke bli installert automatisk."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Skriv en modpakkebeskrivelse..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Eksperter"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Eksperter modpakke"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Navn på modpakke"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validerer Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Leser pakkemanifest"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Slett tilfelle"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Slett tilfelle"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Opprett"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpakka er allerede installert"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Tilfelle"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Laster ned {current, number}/{total, number} prosjekter..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Fullfører oppdatering..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "prosjekt"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" ble lagt til"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} prosjekter ble lagt til"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Sjekk ut prosjektene jeg bruker i min modpakke!"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installer for å spille"
|
||||
},
|
||||
@@ -12,20 +222,14 @@
|
||||
"message": "Installer"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {#mod} other {# mods}}"
|
||||
"message": "{count, plural, one {#mod} other {# modder}}"
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Delt instans"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Delt serverinstans"
|
||||
"message": "Delt tilfelle"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Oppdater for å spille"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Krever oppdatering"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Ei oppdatering er påkrevd for å spille {name}. Vær så snill å oppdater til den siste versjonen av spillet for å spille det."
|
||||
},
|
||||
@@ -39,7 +243,7 @@
|
||||
"message": "Utseende"
|
||||
},
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standard instansinstillinger"
|
||||
"message": "Vanlige tilfelleinstillinger"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java installasjoner"
|
||||
@@ -102,10 +306,10 @@
|
||||
"message": "Aktiv"
|
||||
},
|
||||
"friends.heading.offline": {
|
||||
"message": "Offline"
|
||||
"message": "Av"
|
||||
},
|
||||
"friends.heading.online": {
|
||||
"message": "Online"
|
||||
"message": "På"
|
||||
},
|
||||
"friends.heading.pending": {
|
||||
"message": "Ventende"
|
||||
@@ -246,10 +450,10 @@
|
||||
"message": "Før oppstart"
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.description": {
|
||||
"message": "Kørt før instansen startes."
|
||||
"message": "Kjøres før tilfellet startes."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch.enter": {
|
||||
"message": "Skriv inn kommando før start..."
|
||||
"message": "Skriv inn forstartskommando..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.title": {
|
||||
"message": "Spillstartkroker"
|
||||
@@ -258,7 +462,7 @@
|
||||
"message": "Wrapper"
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.description": {
|
||||
"message": "Wrapper-kommando for å starte Minecraft."
|
||||
"message": "Innpakningskommando for å starte Minecraft."
|
||||
},
|
||||
"instance.settings.tabs.hooks.wrapper.enter": {
|
||||
"message": "Skriv inn wrapper-kommando..."
|
||||
@@ -272,6 +476,9 @@
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java og minne"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-memory-allocation": {
|
||||
"message": "Egendefinert minneallokasjon"
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Miljøvariabler"
|
||||
},
|
||||
@@ -303,7 +510,7 @@
|
||||
"message": "Høyde"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Høyde av spillvindu når spillet startes."
|
||||
"message": "Høyden til spillvinduet når spillet startes."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Angi høyde..."
|
||||
@@ -312,7 +519,7 @@
|
||||
"message": "Bredde"
|
||||
},
|
||||
"instance.settings.tabs.window.width.description": {
|
||||
"message": "Bredde av spillvindu når spillet startes."
|
||||
"message": "Bredden til spillvinduet når spillet startes."
|
||||
},
|
||||
"instance.settings.tabs.window.width.enter": {
|
||||
"message": "Angi bredde..."
|
||||
@@ -330,7 +537,7 @@
|
||||
"message": "Ikke vis på Hjem"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instansen er allerede open"
|
||||
"message": "Tilfellet er allerede open"
|
||||
},
|
||||
"instance.worlds.hardcore": {
|
||||
"message": "Hardbarket modus"
|
||||
@@ -348,7 +555,7 @@
|
||||
"message": "Du kan bare hoppe rett inn i enkeltspiller-verdener på Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Spill instans"
|
||||
"message": "Spill tilfelle"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Vis instans"
|
||||
|
||||
@@ -9,13 +9,94 @@
|
||||
"message": "Pobrania"
|
||||
},
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Ukryj włączone instancje"
|
||||
"message": "Ukryj aktywne instancje"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Skopiowano"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Kopiuj szczegóły"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Odrzuć"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Otwórz instancję"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Spróbuj ponownie"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Anulowano z powodu zamknięcia aplikacji"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Nie można było odczytać paczki modów"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Anulowano"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "Czyszczenie nie powiodło się"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Nie udało się pobrać plików"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "Pobrany plik jest uszkodzony"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Nie udało się zapisać plików"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "Nie można było ukończyć pobierania"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "Nie znaleziono instancji"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "Ścieżka plików jest niewłaściwa"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Niewłaściwe dane paczki modów"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Pliki paczki modów zawierają niewłaściwe metadane"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Ustawianie Javy nie powiodło się"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Ustawianie loadera nie powiodło się"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Nie udało się zaktualizować danych lokalnych"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Ustawianie Minecraft nie powiodło się"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Nie udało się połączyć z serwerami Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Brak permisji, aby zapisać pliki"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Pobieranie paczki nie powiodło się"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Coś poszło nie tak"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Nieznana instancja"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Instalacje"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Ustaw jako główną instancję"
|
||||
},
|
||||
"app.action-bar.no-instances-running": {
|
||||
"message": "Żadna instancja nie jest włączona"
|
||||
"message": "Brak włączonych instancji"
|
||||
},
|
||||
"app.action-bar.offline": {
|
||||
"message": "Offline"
|
||||
@@ -24,7 +105,7 @@
|
||||
"message": "Główna instancja"
|
||||
},
|
||||
"app.action-bar.reload-to-update": {
|
||||
"message": "Załaduj ponownie, by zaktualizować"
|
||||
"message": "Załaduj ponownie, aby zaktualizować"
|
||||
},
|
||||
"app.action-bar.show-more-running-instances": {
|
||||
"message": "Pokaż więcej włączonych instancji"
|
||||
@@ -51,7 +132,7 @@
|
||||
"message": "Zaawansowane renderowanie"
|
||||
},
|
||||
"app.appearance-settings.color-theme.description": {
|
||||
"message": "Wybierz preferowany motyw w Modrinth App."
|
||||
"message": "Wybierz preferowany motyw kolorystyczny dla Modrinth App."
|
||||
},
|
||||
"app.appearance-settings.color-theme.title": {
|
||||
"message": "Motyw"
|
||||
@@ -69,10 +150,10 @@
|
||||
"message": "Domyślna strona główna"
|
||||
},
|
||||
"app.appearance-settings.hide-nametag.description": {
|
||||
"message": "Wyłącza nazwę użytkownika na stronie skórek."
|
||||
"message": "Wyłącza nazwę użytkownika nad modelem gracza na stronie skórek."
|
||||
},
|
||||
"app.appearance-settings.hide-nametag.title": {
|
||||
"message": "Schowaj nazwę"
|
||||
"message": "Ukryj nazwę"
|
||||
},
|
||||
"app.appearance-settings.jump-back-into-worlds.description": {
|
||||
"message": "Pokazuje ostatnie światy w sekcji \"Wskocz z powrotem do światów\" na stronie głównej."
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Pokaż czas gry"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Automatycznie pomija mało znaczące potwierdzenia takie jak duplikaty instalacji paczek modów, usuwanie zwykłej zawartości, masowe aktualizacje, odłączanie paczek modów i naprawianie. Ostrzeżenia o potencjalnie niebezpiecznych akcjach będą nadal pokazywane."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Pomiń mało znaczące ostrzeżenia"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Umożliwia przełączenie paska bocznego."
|
||||
},
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Nie znaleziono żadnych wersji pasujących do {compatibilityLabel}. Wybierz wersję, by zainstalować ją mimo tego. Zależności nie zostaną zainstalowane automatycznie."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Instalowanie paczki modów..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Wprowadź opis paczki modów..."
|
||||
},
|
||||
@@ -176,29 +257,77 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Eksportuj paczkę modów"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Dołączyć \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nazwa paczki modów"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nazwa paczki modów"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Skonfiguruje jakie pliki zostaną załączone w tym eksporcie"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Numer wersji"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Pobieranie zawartości"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Pobieranie Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Pobieranie pliku paczki"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Wyodrębnianie nadpisań"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Finalizowanie"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Oczekuje na instalację"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Przygotowywanie środowiska Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Pobieranie Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Wypakowywanie Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Pobieranie Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Przygotowywanie Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Sprawdzanie Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Sprawdzanie manifestu paczki"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Ustalanie loadera"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Ustalanie wersji Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Ustalanie treści"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Przywracanie"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Uruchamianie procesorów loadera"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Wszystkie dane z Twojej instancji zostaną trwale usunięte, w tym Twoje światy, pliki konfiguracji i jakakolwiek dodana zawartość."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Tej akcji nie można odwrócić"
|
||||
"message": "Tej akcji nie można cofnąć"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Usuń instancję"
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instalacja"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Pobieranie {current, number}/{total, number} projektów..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Kończenie aktualizacji..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Sprawdzanie wersji..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
@@ -225,13 +363,13 @@
|
||||
"message": "Dodano \"{name}\""
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Sprawdź projekty, które używam w mojej paczce modów!"
|
||||
"message": "Sprawdź projekty, których używam w mojej paczce modów!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Udostępnianie zawartości paczki modów"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Przesyłanie powiodło się"
|
||||
"message": "Przesyłanie zakończone sukcesem"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Dodaj serwer"
|
||||
@@ -239,11 +377,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Szukaj serwerów"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' zostanie **permanentnie usunięty** i nie ma możliwości go odzyskać."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Usuń świat"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Czy na pewno chcesz trwale usunąć ten świat?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Usuń świat"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Ten świat zostanie trwale usunięty z tej instancji. Tej akcji nie będzie można cofnąć."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Usuwanie {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Zmodowany"
|
||||
@@ -263,44 +407,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Nie dodano żadnych światów ani serwerów"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' zostanie usunięty z twojej listy, również z gry, i nie będzie możliwości go odzyskać."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Usuń serwer"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) zostanie usunięty z twojej listy, również z gry, i nie będzie możliwości go odzyskać."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Usuń serwer"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Czy jesteś pewny, że chcesz usunąć {name}?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "Ten serwer zostanie trwale usunięty z tej instancji. Tej akcji nie będzie można cofnąć."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Usuwanie {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Szukaj wśród {count} światów..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "ten serwer"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Wymagana zawartość"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Nie instaluj"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Zainstaluj, aby grać"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Instaluj mimo to"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Zainstaluj"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "To zaproszenie zostało utworzone przez innego użytkownika Modrinth, nie przez firmę Modrinth. Tylko akceptuj zaproszenia od osób, którym ufasz."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} few {# mody} other {# modów}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Wymagana paczka modów"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Ten serwer wymaga modów, aby na nim grać. Kliknij \"Zainstaluj\" aby otrzymać potrzebne pliki z Modrinth, a potem dołącz bezpośrednio do serwera."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Plik jest sprawdzony tylko, jeżeli został opublikowany na Modrinth, niezależnie od jego formatu (w tym pliki .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Wspólna instancja"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Wspólna instancja serwera"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Ta serwerowa paczka modów zawiera pliki, które nie zostały opublikowane na Modrinth. Zalecamy instalowanie plików tylko ze źródeł, którym ufasz."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Ostrzeżenie o nieznanych plikach"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Nieznane plki"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Pokaż zawartość"
|
||||
@@ -308,8 +461,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Zaktualizuj, by grać"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Wymagana jest aktualizacja"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Usunięto"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Aktualizacja jest wymagana, aby grać w {name}. Proszę zaktualizować do najnowszej wersji, aby uruchomić grę."
|
||||
@@ -317,11 +470,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Ten projekt jest już zainstalowany"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Zmień wersję"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Powróć do odkrywania"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Zainstaluj zasoby do instancji"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Wszystkie wersje"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Pobierz w przeglądarce"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Instalowanie"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Już zainstalowano"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Tryb dewelopera włączony."
|
||||
@@ -360,25 +525,25 @@
|
||||
"message": "Usuń skórkę"
|
||||
},
|
||||
"app.skins.delete-modal.description": {
|
||||
"message": "To trwale usunie wybraną skórkę. Tej akcji nie można odwrócić."
|
||||
"message": "To trwale usunie wybraną skórkę. Tej akcji nie można cofnąć."
|
||||
},
|
||||
"app.skins.delete-modal.title": {
|
||||
"message": "Czy na pewno chcesz usunąć tą skórkę?"
|
||||
"message": "Czy na pewno chcesz usunąć tę skórkę?"
|
||||
},
|
||||
"app.skins.dropped-file-error.text": {
|
||||
"message": "Nie udało się odczytać wybranego pliku."
|
||||
"message": "Nie udało się odczytać upuszczonego pliku."
|
||||
},
|
||||
"app.skins.dropped-file-error.title": {
|
||||
"message": "Błąd podczas przetwarzania pliku"
|
||||
},
|
||||
"app.skins.edit-button": {
|
||||
"message": "Edytuj skina"
|
||||
"message": "Edytuj skórkę"
|
||||
},
|
||||
"app.skins.modal.add-skin-button": {
|
||||
"message": "Dodaj skina"
|
||||
"message": "Dodaj skórkę"
|
||||
},
|
||||
"app.skins.modal.add-title": {
|
||||
"message": "Dodawanie skina"
|
||||
"message": "Dodawanie skórki"
|
||||
},
|
||||
"app.skins.modal.arm-style-section": {
|
||||
"message": "Styl ramion"
|
||||
@@ -396,10 +561,10 @@
|
||||
"message": "Peleryny"
|
||||
},
|
||||
"app.skins.modal.edit-title": {
|
||||
"message": "Edytuj skina"
|
||||
"message": "Edytowanie skórki"
|
||||
},
|
||||
"app.skins.modal.make-edit-first-tooltip": {
|
||||
"message": "Wpierw zmień jakoś skórkę!"
|
||||
"message": "Zmodyfikuj najpierw skórkę!"
|
||||
},
|
||||
"app.skins.modal.no-cape-tooltip": {
|
||||
"message": "Brak peleryny"
|
||||
@@ -411,7 +576,7 @@
|
||||
"message": "Zamień teksturę"
|
||||
},
|
||||
"app.skins.modal.save-skin-button": {
|
||||
"message": "Zapisz skina"
|
||||
"message": "Zapisz skórkę"
|
||||
},
|
||||
"app.skins.modal.saving-tooltip": {
|
||||
"message": "Zapisywanie..."
|
||||
@@ -443,6 +608,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Builders & Biomes"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -492,7 +660,7 @@
|
||||
"message": "Zaloguj się"
|
||||
},
|
||||
"app.skins.title": {
|
||||
"message": "Wybierz skórkę"
|
||||
"message": "Wybór skórki"
|
||||
},
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Wersja Modrinth App v{version} została pobrana. Załaduj ponownie, żeby zaktualizować teraz, albo automatycznie, gdy zamkniesz Modrinth App."
|
||||
@@ -792,7 +960,7 @@
|
||||
"message": "Niestandardowe argumenty Java"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-java-installation": {
|
||||
"message": "Niestandardowa instalacja Javy"
|
||||
"message": "Niestandardowa instalacja Java"
|
||||
},
|
||||
"instance.settings.tabs.java.custom-memory-allocation": {
|
||||
"message": "Niestandardowa alokacja pamięci"
|
||||
@@ -801,7 +969,7 @@
|
||||
"message": "Zmienne środowiskowe..."
|
||||
},
|
||||
"instance.settings.tabs.java.enter-java-arguments": {
|
||||
"message": "Argumenty Javy..."
|
||||
"message": "Argumenty Java..."
|
||||
},
|
||||
"instance.settings.tabs.java.environment-variables": {
|
||||
"message": "Zmienne środowiskowe"
|
||||
@@ -860,6 +1028,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Kopiuj adres"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Utwórz skrót"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nie pokazuj na stronie głównej"
|
||||
},
|
||||
@@ -934,26 +1105,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader jest dostarczony przez serwer"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Plik jest sprawdzony tylko, jeżeli został przesłany na Modrinth, niezależnie od formatu (w tym pliki .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Nie pokazuj ponownie"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Potwierdź instalację"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Instaluj mimo to"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "Wirusy są często kryte w plikach paczek modów przesyłanych na platformach takich jak Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Nie mogliśmy znaleźć tego pliku na Modrinth. Stanowczo zalecamy instalowanie plików tylko ze źródeł, którym ufasz."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Ostrzeżenie o nieznanym pliku"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,87 @@
|
||||
"app.action-bar.hide-more-running-instances": {
|
||||
"message": "Ocultar mais instâncias em execução"
|
||||
},
|
||||
"app.action-bar.install.copied-details": {
|
||||
"message": "Copiado"
|
||||
},
|
||||
"app.action-bar.install.copy-details": {
|
||||
"message": "Copiar detalhes"
|
||||
},
|
||||
"app.action-bar.install.dismiss": {
|
||||
"message": "Dispensar"
|
||||
},
|
||||
"app.action-bar.install.open-instance": {
|
||||
"message": "Abrir instância"
|
||||
},
|
||||
"app.action-bar.install.retry": {
|
||||
"message": "Tentar novamente"
|
||||
},
|
||||
"app.action-bar.install.summary.app-closing": {
|
||||
"message": "Cancelado devido ao aplicativo ter fechado"
|
||||
},
|
||||
"app.action-bar.install.summary.bad-modpack-file": {
|
||||
"message": "Não foi possível ler o pacote de mods"
|
||||
},
|
||||
"app.action-bar.install.summary.canceled": {
|
||||
"message": "Cancelado"
|
||||
},
|
||||
"app.action-bar.install.summary.cleanup-incomplete": {
|
||||
"message": "A limpeza não foi finalizada"
|
||||
},
|
||||
"app.action-bar.install.summary.content-download-failed": {
|
||||
"message": "Não foi possível baixar os arquivos"
|
||||
},
|
||||
"app.action-bar.install.summary.corrupt-download": {
|
||||
"message": "O arquivo baixado é corrupto"
|
||||
},
|
||||
"app.action-bar.install.summary.could-not-save-files": {
|
||||
"message": "Não foi possível salvar os arquivos"
|
||||
},
|
||||
"app.action-bar.install.summary.download-failed": {
|
||||
"message": "A transferência não foi finalizada"
|
||||
},
|
||||
"app.action-bar.install.summary.instance-not-found": {
|
||||
"message": "Instância não encontrada"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-file-path": {
|
||||
"message": "O caminho do arquivo é inválido"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack": {
|
||||
"message": "Os dados do pacote de mods é inválido"
|
||||
},
|
||||
"app.action-bar.install.summary.invalid-modpack-files": {
|
||||
"message": "Os arquivos do pacote de mods possui metadados inválidos"
|
||||
},
|
||||
"app.action-bar.install.summary.java-setup-failed": {
|
||||
"message": "Configuração Java não foi finalizada"
|
||||
},
|
||||
"app.action-bar.install.summary.loader-setup-failed": {
|
||||
"message": "Falha na configuração do loader"
|
||||
},
|
||||
"app.action-bar.install.summary.local-data-error": {
|
||||
"message": "Não foi atualizar os dados locais"
|
||||
},
|
||||
"app.action-bar.install.summary.minecraft-setup-failed": {
|
||||
"message": "Falha na configuração do Minecraft"
|
||||
},
|
||||
"app.action-bar.install.summary.modrinth-unreachable": {
|
||||
"message": "Não foi possível alcançar o Modrinth"
|
||||
},
|
||||
"app.action-bar.install.summary.no-write-permission": {
|
||||
"message": "Sem permissão para escrita"
|
||||
},
|
||||
"app.action-bar.install.summary.pack-download-failed": {
|
||||
"message": "Não foi possível baixar o pacote"
|
||||
},
|
||||
"app.action-bar.install.summary.unexpected-error": {
|
||||
"message": "Algo deu errado"
|
||||
},
|
||||
"app.action-bar.install.unknown-instance": {
|
||||
"message": "Instância desconhecida"
|
||||
},
|
||||
"app.action-bar.installs": {
|
||||
"message": "Instalações"
|
||||
},
|
||||
"app.action-bar.make-primary-instance": {
|
||||
"message": "Tornar instância principal"
|
||||
},
|
||||
@@ -101,6 +182,12 @@
|
||||
"app.appearance-settings.show-play-time.title": {
|
||||
"message": "Exibir tempo jogado"
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.description": {
|
||||
"message": "Pula automaticamente as confirmações desnecessárias como duplica de instalação de pacotes de mods, exclusão de conteúdo normal, atualizações em massa, desvinculo de pacotes de mods e diálogos de reparo. Os avisos de perigo ainda serão exibidos."
|
||||
},
|
||||
"app.appearance-settings.skip-non-essential-warnings.title": {
|
||||
"message": "Pular avisos desnecessários"
|
||||
},
|
||||
"app.appearance-settings.toggle-sidebar.description": {
|
||||
"message": "Permite alternar a barra lateral."
|
||||
},
|
||||
@@ -161,12 +248,6 @@
|
||||
"app.content-install.no-compatible-versions": {
|
||||
"message": "Nenhuma versão disponível corresponde a {compatibilityLabel}. Selecione uma versão para instalar mesmo assim. As dependências não serão instaladas automaticamente."
|
||||
},
|
||||
"app.creation-modal.installing-modpack.description": {
|
||||
"message": "{fileName}"
|
||||
},
|
||||
"app.creation-modal.installing-modpack.title": {
|
||||
"message": "Instalando pacote de mods..."
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Insira uma descrição para o pacote de mods..."
|
||||
},
|
||||
@@ -176,24 +257,72 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportar pacote de mods"
|
||||
},
|
||||
"app.export-modal.include-file-accessibility-label": {
|
||||
"message": "Incluir \"{file}\"?"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nome do pacote de mods"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nome do pacote de mods"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Configure quais arquivos serão incluídos na exportação"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Número da versão"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.install.phase.downloading_content": {
|
||||
"message": "Instalando conteúdo"
|
||||
},
|
||||
"app.install.phase.downloading_minecraft": {
|
||||
"message": "Instalando Minecraft"
|
||||
},
|
||||
"app.install.phase.downloading_pack_file": {
|
||||
"message": "Instalando arquivo de pacote"
|
||||
},
|
||||
"app.install.phase.extracting_overrides": {
|
||||
"message": "Extraindo substitutos"
|
||||
},
|
||||
"app.install.phase.finalizing": {
|
||||
"message": "Finalizando"
|
||||
},
|
||||
"app.install.phase.preparing_instance": {
|
||||
"message": "Na fila"
|
||||
},
|
||||
"app.install.phase.preparing_java": {
|
||||
"message": "Preparando Java"
|
||||
},
|
||||
"app.install.phase.preparing_java.downloading": {
|
||||
"message": "Baixando Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.extracting": {
|
||||
"message": "Extraindo Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.fetching-metadata": {
|
||||
"message": "Obtendo Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.resolving": {
|
||||
"message": "Preparando Java {version}"
|
||||
},
|
||||
"app.install.phase.preparing_java.validating": {
|
||||
"message": "Validando Java {version}"
|
||||
},
|
||||
"app.install.phase.reading_pack_manifest": {
|
||||
"message": "Lendo manifestação de pacote"
|
||||
},
|
||||
"app.install.phase.resolving_loader": {
|
||||
"message": "Resolvendo loader"
|
||||
},
|
||||
"app.install.phase.resolving_minecraft": {
|
||||
"message": "Resolvendo Minecraft"
|
||||
},
|
||||
"app.install.phase.resolving_pack": {
|
||||
"message": "Resolvendo conteúdo"
|
||||
},
|
||||
"app.install.phase.rolling_back": {
|
||||
"message": "Indo de volta"
|
||||
},
|
||||
"app.install.phase.running_loader_processors": {
|
||||
"message": "Executando processadores de loader"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Todos os dados para sua instância serão excluídos permanentemente, incluindo seus mundos, configs e todo o conteúdo instalado."
|
||||
},
|
||||
@@ -218,6 +347,15 @@
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instância"
|
||||
},
|
||||
"app.instance.mods.bulk-update.downloading-projects": {
|
||||
"message": "Instalando {current, number}/{total, number} projeto(s)..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.finishing": {
|
||||
"message": "Finalizando atualização..."
|
||||
},
|
||||
"app.instance.mods.bulk-update.resolving-versions": {
|
||||
"message": "Resolvendo versões..."
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projeto"
|
||||
},
|
||||
@@ -242,11 +380,17 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Explorar servidores"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "'{name}' será **excluído permanentemente**, e não poderá ser recuperado."
|
||||
"app.instance.worlds.delete-world-modal.delete-button": {
|
||||
"message": "Excluir mundo"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Deseja mesmo excluir este mundo permanentemente?"
|
||||
"app.instance.worlds.delete-world-modal.title": {
|
||||
"message": "Excluir mundo"
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-body": {
|
||||
"message": "Este mundo será permanentemente excluído desta instância. Esta ação não pode ser desfeita."
|
||||
},
|
||||
"app.instance.worlds.delete-world-modal.warning-header": {
|
||||
"message": "Excluindo {name}"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modificado"
|
||||
@@ -266,44 +410,53 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Nenhum servidor ou mundo adicionado"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "'{name}' será removido da lista, inclusive no jogo, e não poderá ser recuperado."
|
||||
"app.instance.worlds.remove-server-modal.remove-button": {
|
||||
"message": "Remover servidor"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "'{name}' ({address}) será removido da lista, inclusive no jogo, e não poderá ser recuperado."
|
||||
"app.instance.worlds.remove-server-modal.title": {
|
||||
"message": "Remover servidor"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Deseja mesmo remover {name}?"
|
||||
"app.instance.worlds.remove-server-modal.warning-body": {
|
||||
"message": "O servidor será removido da lista de servidores e da lista de servidores no jogo. Você pode re-adicioná-lo depois se souber o endereço."
|
||||
},
|
||||
"app.instance.worlds.remove-server-modal.warning-header": {
|
||||
"message": "Removendo {name}"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Buscar {count} mundos..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "este servidor"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Conteúdo necessário"
|
||||
"app.modal.install-to-play.dont-install": {
|
||||
"message": "Não instalar"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instale para jogar"
|
||||
},
|
||||
"app.modal.install-to-play.install-anyway": {
|
||||
"message": "Instalar mesmo assim"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"app.modal.install-to-play.invite-warning": {
|
||||
"message": "Este convite foi criado por outro usuário do Modrinth, não pelo próprio Modrinth. Só aceite convites de pessoas que você confia."
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, =0 {Nenhum mod} one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Pacote de mods necessário"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor exige mods para jogar. Clique em instalar para configurar os arquivos necessários através do Modrinth, e então iniciar diretamente no servidor."
|
||||
"app.modal.install-to-play.reviewed-files": {
|
||||
"message": "Um arquivo só é revisado se for publicado no Modrinth, independente do formato de arquivo (incluindo .mrpack)."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instância compartilhada"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instância de servidor compartilhada"
|
||||
"app.modal.install-to-play.unknown-files-description": {
|
||||
"message": "Este pacote de mods do servidor contém arquivos não publicados no Modrinth. Recomendamos fortemente a instalar apenas arquivos de fontes que você confia."
|
||||
},
|
||||
"app.modal.install-to-play.unknown-files-warning": {
|
||||
"message": "Aviso de arquivos desconhecidos"
|
||||
},
|
||||
"app.modal.install-to-play.unrecognized-files": {
|
||||
"message": "Arquivos não reconhecidos"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Ver conteúdo"
|
||||
@@ -311,8 +464,8 @@
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Atualize para jogar"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Atualização necessária"
|
||||
"app.modal.update-to-play.removed": {
|
||||
"message": "Removido"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Uma atualização é necessária para jogar {name}. Atualize para a versão mais recente para iniciar o jogo."
|
||||
@@ -320,11 +473,23 @@
|
||||
"app.project.install-button.already-installed": {
|
||||
"message": "Este projeto já foi instalado"
|
||||
},
|
||||
"app.project.install-button.switch-version": {
|
||||
"message": "Trocar versão"
|
||||
},
|
||||
"app.project.install-context.back-to-browse": {
|
||||
"message": "Voltar a descobrir"
|
||||
},
|
||||
"app.project.install-context.install-content-to-instance": {
|
||||
"message": "Instalar conteúdo para a instância"
|
||||
"app.project.version.all-versions": {
|
||||
"message": "Todas as versões"
|
||||
},
|
||||
"app.project.version.download-in-browser": {
|
||||
"message": "Baixar no navegador"
|
||||
},
|
||||
"app.project.version.installing": {
|
||||
"message": "Instalando"
|
||||
},
|
||||
"app.project.versions.already-installed": {
|
||||
"message": "Já instalado"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desenvolvedor ativado."
|
||||
@@ -446,6 +611,9 @@
|
||||
"app.skins.section.builders-and-biomes": {
|
||||
"message": "Construtores & Biomas"
|
||||
},
|
||||
"app.skins.section.chaos-cubed": {
|
||||
"message": "Chaos Cubed"
|
||||
},
|
||||
"app.skins.section.chase-the-skies": {
|
||||
"message": "Chase the Skies"
|
||||
},
|
||||
@@ -510,7 +678,7 @@
|
||||
"message": "Mudanças"
|
||||
},
|
||||
"app.update-popup.download": {
|
||||
"message": "Baixar ({size})"
|
||||
"message": "Instalar ({size})"
|
||||
},
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Instalação concluída"
|
||||
@@ -863,6 +1031,9 @@
|
||||
"instance.worlds.copy_address": {
|
||||
"message": "Copiar endereço"
|
||||
},
|
||||
"instance.worlds.create_shortcut": {
|
||||
"message": "Criar atalho"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Não exibir na página inicial"
|
||||
},
|
||||
@@ -937,26 +1108,5 @@
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "O loader é fornecido pelo servidor"
|
||||
},
|
||||
"unknown-pack-warning-modal.body": {
|
||||
"message": "Um arquivo só é revisado se for enviado no Modrinth, independente do formato do arquivo (incluindo .mrpack)."
|
||||
},
|
||||
"unknown-pack-warning-modal.dont-show-again": {
|
||||
"message": "Não exibir aviso novamente"
|
||||
},
|
||||
"unknown-pack-warning-modal.header": {
|
||||
"message": "Confirmar instalação"
|
||||
},
|
||||
"unknown-pack-warning-modal.install-anyway": {
|
||||
"message": "Instalar mesmo assim"
|
||||
},
|
||||
"unknown-pack-warning-modal.malware-statement": {
|
||||
"message": "O malware é distribuído frequentemente através de arquivos de pacote de mods compartilhados em plataformas como Discord."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.body": {
|
||||
"message": "Não encontramos este arquivo no Modrinth. Nós recomendamos fortemente instalar arquivos apenas de fontes confiáveis."
|
||||
},
|
||||
"unknown-pack-warning-modal.warning.title": {
|
||||
"message": "Aviso de arquivo desconhecido"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,9 +110,6 @@
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportar modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Nome do Modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Nome do Modpack"
|
||||
},
|
||||
@@ -170,9 +167,6 @@
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Procurar servidores"
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Tens a certeza que queres apagar permanentemente este mundo?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Com Mods"
|
||||
},
|
||||
@@ -191,18 +185,9 @@
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Sem servidores ou mundos adicionados"
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Tens a certeza que queres remover {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Pesquisar {count} mundos..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "este servidor"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Conteúdo necessário"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instala para jogar"
|
||||
},
|
||||
@@ -212,27 +197,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {mod} other {mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requerido"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requer mods para jogares. Clica Instalar para transferir os ficheiros necessários do Modrinth, e então entrar diretamente no servidor."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instância partilhada"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instância de servidor partilhada"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Ver conteúdo"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Atualiza para jogar"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Atualização necessária"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Uma atualização é necessária para jogar {name}. Por favor atualiza para a versão mais recente para iniciar o jogo."
|
||||
},
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Nu se pot accesa serverele de autentificare"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Conținut necesar"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Instalați pentru a juca"
|
||||
},
|
||||
@@ -17,27 +14,15 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural,one {#mod} other {# moduri}}"
|
||||
},
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Pachet de mod necesar"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Acest server necesită modificări pentru a juca. Faceți clic pe Instalare pentru a configura fișierele necesare din Modrinth, apoi lansați direct pe server."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Instanță comună"
|
||||
},
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instanță de server partajată"
|
||||
},
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Vizualizați conținutul"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Actualizați pentru a juca"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Actualizare necesară"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Este necesară o actualizare pentru a juca {name}. Vă rugăm să actualizați la cea mai recentă versiune pentru a lansa jocul."
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user