mirror of
https://github.com/modrinth/code.git
synced 2026-07-31 21:26:40 +00:00
Compare commits
225
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c3e448239 | ||
|
|
e368ffd3d7 | ||
|
|
89df2464b9 | ||
|
|
30ea90938b | ||
|
|
cb93c641d6 | ||
|
|
eebb353547 | ||
|
|
694ab09a01 | ||
|
|
da47c50320 | ||
|
|
bee4391df1 | ||
|
|
d1b122fb21 | ||
|
|
281bf066de | ||
|
|
68fde3ff97 | ||
|
|
7d6d938b99 | ||
|
|
065759d1b8 | ||
|
|
9b3fe6390e | ||
|
|
2236dd8ade | ||
|
|
3a44def301 | ||
|
|
176d4301c3 | ||
|
|
3e32901737 | ||
|
|
ab623dc325 | ||
|
|
bb6e24640c | ||
|
|
15fc6d4e38 | ||
|
|
ed2f04322f | ||
|
|
b9e7b54b4e | ||
|
|
dd51c08a18 | ||
|
|
5244060588 | ||
|
|
9483656881 | ||
|
|
7c642f7078 | ||
|
|
3c2cc7568d | ||
|
|
7b5c746757 | ||
|
|
5b5c8c06e3 | ||
|
|
4d68f3cea4 | ||
|
|
546b117437 | ||
|
|
3d5f29a7a2 | ||
|
|
37b0f7ff98 | ||
|
|
1603796856 | ||
|
|
7c9a9f22d4 | ||
|
|
d38d23dbf3 | ||
|
|
f12bd7b4b8 | ||
|
|
baee34b0b6 | ||
|
|
74bad7456c | ||
|
|
a6f67581d7 | ||
|
|
02be7a8b82 | ||
|
|
d5ad1cb823 | ||
|
|
b666747bc2 | ||
|
|
c1b0e4a692 | ||
|
|
0713814d0c | ||
|
|
0b8b4fb516 | ||
|
|
d6e366b488 | ||
|
|
0682cc3c4f | ||
|
|
693a371d61 | ||
|
|
a2a97d1313 | ||
|
|
71e4f7cb91 | ||
|
|
1a51e58297 | ||
|
|
a9c417d1d1 | ||
|
|
de4f0bffb0 | ||
|
|
e71a8c10fa | ||
|
|
c4b3c6e8d6 | ||
|
|
54c45ac9f3 | ||
|
|
e5f600ddd7 | ||
|
|
4a7525d0a1 | ||
|
|
d0d3aaf09b | ||
|
|
bb3506823d | ||
|
|
3091021194 | ||
|
|
dc96043adc | ||
|
|
92bf2e5c29 | ||
|
|
a6d359e9c1 | ||
|
|
ddd1a36506 | ||
|
|
933fdba388 | ||
|
|
fa4711ff7b | ||
|
|
c52abece44 | ||
|
|
35033ccc03 | ||
|
|
97734a98f9 | ||
|
|
3978e3dead | ||
|
|
5939d2a4e7 | ||
|
|
4224ef45b3 | ||
|
|
e2bfed177d | ||
|
|
7f92706e5f | ||
|
|
90deb7310e | ||
|
|
4cd6c1a72d | ||
|
|
3a8561cf35 | ||
|
|
a3f80dcb66 | ||
|
|
0ee58867e8 | ||
|
|
d4c2fdb9ef | ||
|
|
e6b061f38c | ||
|
|
87122cf9bd | ||
|
|
fc87506745 | ||
|
|
6ba41ba17f | ||
|
|
628634772e | ||
|
|
b68aeddedc | ||
|
|
c5a0c71424 | ||
|
|
4394092928 | ||
|
|
ef1ffa6577 | ||
|
|
b11b54cbc9 | ||
|
|
36f62a3285 | ||
|
|
381ea51cce | ||
|
|
706eb800cb | ||
|
|
f1648298c4 | ||
|
|
3c3cde1908 | ||
|
|
274325d97c | ||
|
|
da48a12551 | ||
|
|
bf24ed8d12 | ||
|
|
0731654a1c | ||
|
|
81f19eeb8d | ||
|
|
4b4282cfbf | ||
|
|
7b3471944d | ||
|
|
d2abeb434c | ||
|
|
0aecfa3140 | ||
|
|
f9004dc2f6 | ||
|
|
cf7c77700a | ||
|
|
c09f7fd5e6 | ||
|
|
67fd759d9b | ||
|
|
a3eb981058 | ||
|
|
92eddbe832 | ||
|
|
9e6a6cd385 | ||
|
|
3c5bd0756d | ||
|
|
00e81adbbd | ||
|
|
2128fa7ade | ||
|
|
93c81631a9 | ||
|
|
3b604cfdc0 | ||
|
|
922b72d1a4 | ||
|
|
1d10af09f5 | ||
|
|
cf1b5f5e2d | ||
|
|
61754efca4 | ||
|
|
235934abd7 | ||
|
|
22d1b900f6 | ||
|
|
1cfbefff02 | ||
|
|
7852529915 | ||
|
|
c556624d0e | ||
|
|
87c86c7d0d | ||
|
|
58c1e225c8 | ||
|
|
900a4df1b7 | ||
|
|
5b968a1486 | ||
|
|
3a917631d5 | ||
|
|
63ea8230ba | ||
|
|
496bbae8a0 | ||
|
|
1848ba3b29 | ||
|
|
681ae5d1d8 | ||
|
|
d0c7575a23 | ||
|
|
d9c7608ade | ||
|
|
7d3935a38d | ||
|
|
a67f596524 | ||
|
|
7fa0a277c6 | ||
|
|
01c9dee612 | ||
|
|
d50a8efb26 | ||
|
|
be5ebacd84 | ||
|
|
989f282de3 | ||
|
|
8a2125ef16 | ||
|
|
31b541007d | ||
|
|
4792985e52 | ||
|
|
86c0937616 | ||
|
|
51deba8cd1 | ||
|
|
b2d40af9cd | ||
|
|
fc382e957b | ||
|
|
c9547bb988 | ||
|
|
adef71b89a | ||
|
|
c44cc38b3a | ||
|
|
455a4f527d | ||
|
|
f918df2d7a | ||
|
|
c8279481f8 | ||
|
|
d14360aba5 | ||
|
|
991b4d8c13 | ||
|
|
cc9059fb4a | ||
|
|
32d76b8025 | ||
|
|
ba06c89a0e | ||
|
|
52d46b8aaa | ||
|
|
bdc204eebd | ||
|
|
7d92e4ec7f | ||
|
|
f0224dfff7 | ||
|
|
1c1683adb6 | ||
|
|
407e6217f5 | ||
|
|
83ea7f684b | ||
|
|
3b21944a75 | ||
|
|
086508be23 | ||
|
|
8b04303eca | ||
|
|
2b8175ad66 | ||
|
|
0c98f6bf45 | ||
|
|
9a8712c76e | ||
|
|
f62c60a681 | ||
|
|
9b2f0c88cd | ||
|
|
01b8ee6909 | ||
|
|
5a51a755eb | ||
|
|
4cfac2c8a2 | ||
|
|
f6fcdd336f | ||
|
|
5594771ad8 | ||
|
|
5d04992a28 | ||
|
|
c9c8079853 | ||
|
|
97051cc64d | ||
|
|
0a04478149 | ||
|
|
789ec8966c | ||
|
|
51a83b4536 | ||
|
|
73abe272d1 | ||
|
|
4a0c610fc5 | ||
|
|
913dee9090 | ||
|
|
43eb53eda5 | ||
|
|
c381adff85 | ||
|
|
ace2659861 | ||
|
|
507d03eeba | ||
|
|
d4932d3089 | ||
|
|
4b6de7526c | ||
|
|
b95e4ced22 | ||
|
|
200b4f56c6 | ||
|
|
83d53dafe7 | ||
|
|
98175a58a6 | ||
|
|
20cbe1ad8f | ||
|
|
9d5d34fde8 | ||
|
|
2d5c26896f | ||
|
|
ea3bb334a8 | ||
|
|
024e079a7d | ||
|
|
d902b281f7 | ||
|
|
c4a0008708 | ||
|
|
835f80ee50 | ||
|
|
155f4091a6 | ||
|
|
e1ee9c364b | ||
|
|
0029a22569 | ||
|
|
211ec20970 | ||
|
|
34997bada5 | ||
|
|
63daac917b | ||
|
|
51ceb9d851 | ||
|
|
51066c476a | ||
|
|
47ef7ee42e | ||
|
|
6fba33d443 | ||
|
|
017f6a5afb | ||
|
|
1ab722411a | ||
|
|
45387e5fb6 |
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: api-module
|
||||
description: Add a new API endpoint module to packages/api-client from an OpenAPI schema. Use when adding new backend endpoints, creating API client modules, or when an openapi.yml is provided.
|
||||
argument-hint: <path-to-openapi.yml>
|
||||
---
|
||||
|
||||
Refer to the standard: @standards/frontend/ADDING_API_MODULES.md
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Read the OpenAPI schema** at `$ARGUMENTS` — identify the endpoints, request/response shapes, and path parameters.
|
||||
2. **Read the standard above** for naming conventions, type rules, and the module registration pattern.
|
||||
3. **Determine the service and version** — the URL path prefix tells you which service directory and version namespace to use (e.g. `/v3/projects` → `labrinth/v3/`).
|
||||
4. **Define types in `types.ts`** — types must match the API response 1:1. Use the OpenAPI schema as the source of truth. Do not reshape or rename fields.
|
||||
5. **Create the module class** — extend `BaseModule`, implement each endpoint as a method. Use the correct HTTP verb and request options pattern from the standard.
|
||||
6. **Register in `MODULE_REGISTRY`** — add the module entry so it's auto-instantiated on the client.
|
||||
7. **Export types** from the service's barrel `index.ts`.
|
||||
8. **Verify** — check that the module compiles and the types are accessible from `@modrinth/api-client`.
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: cross-platform-pages
|
||||
description: Convert a page to the cross-platform page system so it works in both the website and the desktop app. Use when moving a page into packages/ui/src/layouts/, creating shared or wrapped layouts, or setting up DI contracts for platform abstraction.
|
||||
argument-hint: <path-to-page>
|
||||
---
|
||||
|
||||
Refer to the standards: @standards/frontend/CROSS_PLATFORM_PAGES.md and @standards/frontend/DEPENDENCY_INJECTION.md
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Read the target page** at `$ARGUMENTS` and understand its data sources, mutations, and navigation.
|
||||
2. **Read the standards above** to understand the shared vs wrapped distinction and the DI pattern.
|
||||
3. **Decide the category:**
|
||||
- **Wrapped** (`layouts/wrapped/`) — if the page uses the same API source on both platforms (e.g. web requests, not Tauri plugins). Just move the page component into `packages/ui` and import it from both frontends.
|
||||
- **Shared** (`layouts/shared/`) — if the page has different data-fetching logic per platform (e.g. website uses `api-client`, app uses Tauri `invoke`). Requires a DI contract.
|
||||
4. **For shared layouts:**
|
||||
- Define a DI contract interface in `providers/` capturing all platform-specific operations.
|
||||
- Create the layout component that injects the context and handles all UI logic.
|
||||
- Extract reusable stateful logic (search, filtering, selection) into `composables/`.
|
||||
- Implement the contract separately in each frontend (`apps/frontend/`, `apps/app-frontend/`).
|
||||
5. **For wrapped pages:**
|
||||
- Move the page component into `packages/ui/src/layouts/wrapped/` matching the route structure.
|
||||
- Replace any platform-specific imports with shared utilities.
|
||||
- Import and render the wrapped page from both frontends as a simple component.
|
||||
- If the layout uses TanStack Query for initial route paint with `ReadyTransition` / `useReadyState`, each platform route shell must call `ensureQueryData` for those queries with matching keys and fetchers — see **Platform route shells: prefetch with `ensureQueryData`** in `standards/frontend/CROSS_PLATFORM_PAGES.md`.
|
||||
6. **Verify** the page renders correctly by checking for missing imports and that all DI contracts are satisfied.
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: figma-mcp
|
||||
description: Use the Figma MCP server to translate a Figma design into a Vue page or component layout. Use when the user provides a Figma URL, asks to implement a design, or wants to draft a page layout from Figma.
|
||||
argument-hint: <figma-url>
|
||||
---
|
||||
|
||||
Refer to the standard: @standards/frontend/FIGMA_MCP_USAGE.md
|
||||
Also read @packages/ui/CLAUDE.md for color token mapping and component conventions.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Parse the Figma URL** from `$ARGUMENTS` — extract the `fileKey` and `nodeId`. Convert `-` to `:` in the node ID.
|
||||
2. **Read the standards above** for the available tools, adaptation rules, and color usage.
|
||||
3. **Call `get_design_context`** with the extracted `nodeId` and `fileKey`, using `clientLanguages: "typescript,html,css"` and `clientFrameworks: "vue"`. This is always the first tool to call.
|
||||
5. **Adapt the output to the Modrinth codebase:**
|
||||
- Map Figma color variables to `surface-*` / `text-*` tokens — never use Figma's aliased names directly.
|
||||
- Check `packages/ui/src/components/` for existing components that match elements in the design (buttons, cards, modals, inputs, etc.).
|
||||
- Check `packages/assets/styles/variables.scss` for tokens not exposed in Figma.
|
||||
- Match spacing values exactly from the design.
|
||||
6. **Use `get_screenshot`** if you need a closer visual reference of specific nodes.
|
||||
7. **Use `get_variable_defs`** to verify which design tokens are applied to ambiguous elements.
|
||||
8. **Build the component** as a Vue SFC using Tailwind classes and the project's existing component library.
|
||||
@@ -0,0 +1,24 @@
|
||||
---
|
||||
name: i18n-pass
|
||||
description: Perform an i18n localization pass on changed files or a pull request, converting hard-coded English strings to the @modrinth/ui i18n system. Use when internationalizing a set of changes, reviewing a PR for untranslated strings, or converting a specific component.
|
||||
argument-hint: [file-path-or-pr-number]
|
||||
---
|
||||
|
||||
Refer to the standard: @standards/frontend/INTERNATIONALIZATION.md
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Identify the scope of changes:**
|
||||
- If `$ARGUMENTS` is a PR number, run `gh pr diff $ARGUMENTS` to get the changed files.
|
||||
- If `$ARGUMENTS` is a file path, use that directly.
|
||||
- If no argument, check `git diff` for uncommitted changes.
|
||||
2. **Read the standard above** for the message definition pattern, ICU format rules, and `IntlFormatted` usage.
|
||||
3. **Filter to Vue SFCs** — only `.vue` files need i18n passes. Skip non-component files.
|
||||
4. **For each file, scan for hard-coded strings:**
|
||||
- `<template>`: inner text, `alt`, `placeholder`, `aria-label`, button labels, tooltip text.
|
||||
- `<script>`: string literals passed to user-visible UI (notification messages, dropdown labels, error messages).
|
||||
- Skip: dynamic expressions, HTML tag names, CSS classes, internal identifiers, log messages.
|
||||
5. **Define messages** with `defineMessages` — use descriptive, stable `id`s based on the component's domain (e.g. `project.settings.title`).
|
||||
6. **Replace strings in templates** with `formatMessage()` calls, or `<IntlFormatted>` for strings containing links or markup.
|
||||
7. **Handle ICU edge cases** — add a space before `}}` if an ICU placeholder ends at a Vue template delimiter boundary.
|
||||
8. **Verify** no hard-coded English strings remain in the changed templates. Do not alter logic, layout, or reactivity.
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: review-changelog
|
||||
description: Review the latest changelog entry in packages/blog/changelog.ts against the project's changelog style guide and flag bullets that need rewriting. Use when checking a freshly added changelog entry before opening a PR, or when the user asks to review/lint the latest changelog.
|
||||
argument-hint: [product?]
|
||||
---
|
||||
|
||||
Refer to the standard: @standards/maintaining/CHANGELOG.md
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Locate the latest entry:**
|
||||
- Open `packages/blog/changelog.ts`.
|
||||
- The latest entries are at the top of the `VERSIONS` array.
|
||||
- If `$ARGUMENTS` specifies a product (`web`, `hosting`, `app`), review the most recent entry for that product. Otherwise, review the most recent entry overall, plus any sibling entries sharing the same `date` (coordinated releases ship together).
|
||||
|
||||
2. **Read the standard above** in full before reviewing. The bullet rules, section/verb agreement, and "Don't" list are the source of truth.
|
||||
|
||||
3. **Check the entry shell:**
|
||||
- `date` is a valid ISO 8601 timestamp.
|
||||
- `product` is one of `web`, `hosting`, `app`.
|
||||
- `version` is present for `app` entries and omitted for `web`/`hosting`.
|
||||
- Section headings use `## Added`, `## Changed`, `## Fixed`, `## Security` (or a featured-release linked heading). Flag legacy `## Improvements`.
|
||||
|
||||
4. **Review each bullet** against the standard. For each bullet, check:
|
||||
- Voice/tense matches the section heading.
|
||||
- Opening verb agrees with its section.
|
||||
- Describes observable behavior, not implementation.
|
||||
- Specific enough to identify the surface (names the tab/page/modal).
|
||||
- One sentence, ends with a period, sentence case.
|
||||
- Uses branded names (Modrinth App, Modrinth Hosting) correctly.
|
||||
- No filler ("issue with", "issue where", "various", "some"), no vague intensifiers, no apologies, no PR/commit references (unless crediting a third-party contributor with a linked GitHub profile).
|
||||
- Not a duplicate sub-fix of a bigger change already listed.
|
||||
|
||||
5. **Report findings** as a short list grouped by entry. For each problem bullet, show the original line and a suggested rewrite. If the entry is clean, say so explicitly. Do not edit the file unless the user asks - this skill is a review pass, not a rewrite pass.
|
||||
|
||||
6. **If the user then asks to apply fixes**, edit `packages/blog/changelog.ts` directly using the suggested rewrites. Preserve tab indentation and template literal formatting.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
name: tanstack-query
|
||||
description: Convert a page or component from useAsyncData/manual ref patterns to TanStack Query for server state management. Use when migrating data fetching to useQuery/useMutation, adding cache invalidation, or replacing useAsyncData with TanStack Query.
|
||||
argument-hint: <path-to-file>
|
||||
---
|
||||
|
||||
Refer to the standard: @standards/frontend/FETCHING_DATA.md
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Read the target file** at `$ARGUMENTS` and identify all data-fetching patterns: `useAsyncData`, `useFetch`, manual `ref()` + `await`, or `onMounted` fetch calls.
|
||||
2. **Read the standard above** for the query/mutation patterns, query key conventions, and optimistic update approach.
|
||||
3. **Convert queries:**
|
||||
- Replace `useAsyncData` / `useFetch` / manual fetches with `useQuery`.
|
||||
- Use the `api-client` via `injectModrinthClient()` for the `queryFn`.
|
||||
- Design query keys with the `['resource', 'version', ...params]` convention.
|
||||
- Use `computed` query keys for reactive parameters.
|
||||
- Use the `enabled` option for conditional queries that depend on other data.
|
||||
4. **Convert mutations:**
|
||||
- Replace manual `try/catch` + `ref` patterns with `useMutation`.
|
||||
- Add `onSuccess` handlers that invalidate or update related query caches.
|
||||
- Consider optimistic updates for UI-critical mutations (follow the pattern in the standard).
|
||||
5. **Clean up:**
|
||||
- Remove manual loading/error `ref()`s that are now handled by TanStack Query's return values (`isPending`, `isError`, `error`).
|
||||
- Remove manual `onMounted` fetch calls.
|
||||
- Ensure SSR compatibility — queries in Nuxt pages are automatically awaited during SSR.
|
||||
6. **Verify** the page still renders correctly and that cache invalidation triggers re-fetches where expected.
|
||||
@@ -0,0 +1,121 @@
|
||||
name: Changelog Comment
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, reopened]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: 'PR number to post the changelog comment on (for testing)'
|
||||
required: true
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
name: Post changelog comment
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: 💬 Post or update changelog comment
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.CROWDIN_GH_TOKEN }}
|
||||
script: |
|
||||
const marker = '<!-- changelog -->';
|
||||
const mergedMarker = '<!-- changelog-merged -->';
|
||||
|
||||
const sections = ['### Added', '', '### Changed', '', '### Deprecated', '', '### Removed', '', '### Fixed', '', '### Security'].join('\n');
|
||||
const productBlock = (name) => `<details>\n<summary>${name}</summary>\n\n${sections}\n\n</details>`;
|
||||
|
||||
const template = [
|
||||
marker,
|
||||
'## Pull request changelog',
|
||||
'',
|
||||
'<!-- Fill in the changelog under each product area this PR affects.',
|
||||
' Empty sections are ignored. Leave a product collapsed/empty',
|
||||
' if it doesn\'t apply. -->',
|
||||
'',
|
||||
productBlock('App'),
|
||||
'',
|
||||
productBlock('Website'),
|
||||
'',
|
||||
productBlock('Hosting'),
|
||||
].join('\n');
|
||||
|
||||
// Resolve PR number from event or workflow_dispatch input
|
||||
const prNumber = context.payload.pull_request?.number
|
||||
?? parseInt('${{ github.event.inputs.pr_number }}', 10);
|
||||
|
||||
if (!prNumber || isNaN(prNumber)) {
|
||||
core.setFailed('Could not determine PR number');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get PR details (need base ref for child PR detection)
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: prNumber,
|
||||
});
|
||||
|
||||
// Check if bot comment already exists
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
});
|
||||
|
||||
const existingComment = comments.find(c => c.body.includes(marker));
|
||||
if (existingComment) {
|
||||
core.info('Changelog comment already exists, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
// Post the template comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
body: template,
|
||||
});
|
||||
|
||||
core.info(`Posted changelog comment on PR #${prNumber}`);
|
||||
|
||||
// Detect child PR: check if this PR's base branch is another open PR's head branch
|
||||
const baseRef = pr.base.ref;
|
||||
|
||||
if (baseRef === 'main' || baseRef === 'prod') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for a parent PR whose head branch matches our base branch
|
||||
const { data: candidatePRs } = await github.rest.pulls.list({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
head: `${context.repo.owner}:${baseRef}`,
|
||||
});
|
||||
|
||||
if (candidatePRs.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentPR = candidatePRs[0];
|
||||
core.info(`Detected parent PR #${parentPR.number} for child PR #${prNumber}`);
|
||||
|
||||
// Add admonition to child PR's changelog comment
|
||||
const { data: childComments } = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: prNumber,
|
||||
});
|
||||
|
||||
const childChangelogComment = childComments.find(c => c.body.includes(marker));
|
||||
if (childChangelogComment && !childChangelogComment.body.includes(mergedMarker)) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: childChangelogComment.id,
|
||||
body: `${mergedMarker}\n> [!NOTE]\n> This changelog has been merged into the changelog for #${parentPR.number}\n\n${childChangelogComment.body}`,
|
||||
});
|
||||
}
|
||||
@@ -50,14 +50,15 @@ jobs:
|
||||
uses: peter-evans/find-comment@v3
|
||||
id: fc
|
||||
with:
|
||||
token: ${{ secrets.CROWDIN_GH_TOKEN }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-author: 'github-actions[bot]'
|
||||
body-includes: Frontend previews
|
||||
|
||||
- name: Comment deploy URL on PR
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: peter-evans/create-or-update-comment@v5
|
||||
with:
|
||||
token: ${{ secrets.CROWDIN_GH_TOKEN }}
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
body: |
|
||||
|
||||
@@ -21,10 +21,21 @@ on:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
environment:
|
||||
description: Environment
|
||||
type: choice
|
||||
options:
|
||||
- prod
|
||||
- staging
|
||||
- prod-with-staging-archon
|
||||
default: prod
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
env:
|
||||
VITE_STRIPE_PUBLISHABLE_KEY: pk_live_51JbFxJJygY5LJFfKLVVldb10HlLt24p421OWRsTOWc5sXYFOnFUXWieSc6HD3PHo25ktx8db1WcHr36XGFvZFVUz00V9ixrCs5
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -94,12 +105,14 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
APP_VERSION="$(git describe --tags --always | sed -E 's/-([0-9]+)-(g[0-9a-fA-F]+)$/-canary+\1.\2/')"
|
||||
BUILD_ENVIRONMENT="${{ inputs.environment || 'prod' }}"
|
||||
echo "Setting application version to $APP_VERSION"
|
||||
echo "Using environment $BUILD_ENVIRONMENT"
|
||||
dasel put -f apps/app/Cargo.toml -t string -v "${APP_VERSION#v}" 'package.version'
|
||||
dasel put -f packages/app-lib/Cargo.toml -t string -v "${APP_VERSION#v}" 'package.version'
|
||||
dasel put -f apps/app-frontend/package.json -t string -v "${APP_VERSION#v}" 'version'
|
||||
|
||||
cp packages/app-lib/.env.prod packages/app-lib/.env
|
||||
cp "packages/app-lib/.env.${BUILD_ENVIRONMENT}" packages/app-lib/.env
|
||||
|
||||
- name: Setup Turbo cache
|
||||
uses: rharkor/caching-for-turbo@v1.8
|
||||
|
||||
@@ -1,47 +1,68 @@
|
||||
name: Modrinth App release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version-tag:
|
||||
description: Version tag to release to the wide public
|
||||
type: string
|
||||
required: true
|
||||
release-notes:
|
||||
description: Release notes to include in the Tauri version manifest
|
||||
default: A new release of the Modrinth App is available!
|
||||
type: string
|
||||
required: true
|
||||
workflow_run:
|
||||
workflows: ['Modrinth App build']
|
||||
types: [completed]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release Modrinth App
|
||||
if: >-
|
||||
github.event.workflow_run.conclusion == 'success' &&
|
||||
github.event.workflow_run.event == 'push' &&
|
||||
startsWith(github.event.workflow_run.head_branch, 'v')
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
VERSION_TAG: ${{ github.event.workflow_run.head_branch }}
|
||||
LINUX_X64_BUNDLE_ARTIFACT_NAME: App bundle (x86_64-unknown-linux-gnu)
|
||||
WINDOWS_X64_BUNDLE_ARTIFACT_NAME: App bundle (x86_64-pc-windows-msvc)
|
||||
MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME: App bundle (universal-apple-darwin)
|
||||
LAUNCHER_FILES_BUCKET_BASE_URL: https://launcher-files.modrinth.com
|
||||
|
||||
steps:
|
||||
- name: 📥 Check out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🔒 Verify ref is a tag
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
|
||||
run: |
|
||||
tag_sha=$(gh api "repos/${{ github.repository }}/git/refs/tags/${VERSION_TAG}" --jq '.object.sha' 2>/dev/null || true)
|
||||
if [ -z "$tag_sha" ]; then
|
||||
echo "::error::${VERSION_TAG} is not a git tag in this repo"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$tag_sha" != "$HEAD_SHA" ]; then
|
||||
commit_sha=$(gh api "repos/${{ github.repository }}/git/tags/${tag_sha}" --jq '.object.sha' 2>/dev/null || echo "$tag_sha")
|
||||
if [ "$commit_sha" != "$HEAD_SHA" ]; then
|
||||
echo "::error::Tag ${VERSION_TAG} (${commit_sha}) does not match build head_sha (${HEAD_SHA})"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "Verified ${VERSION_TAG} is a tag pointing at ${HEAD_SHA}"
|
||||
|
||||
- name: 📥 Download Modrinth App artifacts
|
||||
uses: dawidd6/action-download-artifact@v11
|
||||
with:
|
||||
workflow: theseus-build.yml
|
||||
workflow_conclusion: success
|
||||
event: push
|
||||
branch: ${{ inputs.version-tag }}
|
||||
branch: ${{ env.VERSION_TAG }}
|
||||
use_unzip: true
|
||||
|
||||
- name: 🛠️ Generate version manifest
|
||||
- name: 📝 Extract app changelog
|
||||
env:
|
||||
VERSION_TAG: ${{ inputs.version-tag }}
|
||||
RELEASE_NOTES: ${{ inputs.release-notes }}
|
||||
VERSION: ${{ env.VERSION_TAG }}
|
||||
run: npx --yes tsx scripts/build-theseus-release-notes.ts
|
||||
|
||||
- name: 🛠️ Generate version manifest
|
||||
run: |
|
||||
# Reference: https://tauri.app/plugin/updater/#server-support
|
||||
jq -nc \
|
||||
--arg versionTag "${VERSION_TAG#v}" \
|
||||
--arg releaseNotes "$RELEASE_NOTES" \
|
||||
--rawfile releaseNotes release-notes.md \
|
||||
--rawfile macOsAarch64UpdateArtifactSignature "${MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME}/universal-apple-darwin/release/bundle/macos/Modrinth App.app.tar.gz.sig" \
|
||||
--rawfile macOsX64UpdateArtifactSignature "${MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME}/universal-apple-darwin/release/bundle/macos/Modrinth App.app.tar.gz.sig" \
|
||||
--rawfile linuxX64UpdateArtifactSignature "${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/appimage/Modrinth App_${VERSION_TAG#v}_amd64.AppImage.tar.gz.sig" \
|
||||
@@ -83,7 +104,6 @@ jobs:
|
||||
|
||||
- name: 📤 Upload release artifacts
|
||||
env:
|
||||
VERSION_TAG: ${{ inputs.version-tag }}
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.LAUNCHER_FILES_BUCKET_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.LAUNCHER_FILES_BUCKET_SECRET_ACCESS_KEY }}
|
||||
AWS_BUCKET: ${{ secrets.LAUNCHER_FILES_BUCKET_NAME }}
|
||||
@@ -116,3 +136,18 @@ jobs:
|
||||
done
|
||||
|
||||
aws s3 cp updates.json "s3://${AWS_BUCKET}"
|
||||
|
||||
- name: 🏷️ Create GitHub release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
VERSION="${VERSION_TAG#v}"
|
||||
|
||||
gh release create "$VERSION_TAG" \
|
||||
--title "Modrinth App ${VERSION}" \
|
||||
--notes-file release-notes.md \
|
||||
"${WINDOWS_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/nsis/Modrinth App_${VERSION}_x64-setup.exe" \
|
||||
"${MACOS_UNIVERSAL_BUNDLE_ARTIFACT_NAME}/universal-apple-darwin/release/bundle/dmg/Modrinth App_${VERSION}_universal.dmg" \
|
||||
"${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/appimage/Modrinth App_${VERSION}_amd64.AppImage" \
|
||||
"${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/deb/Modrinth App_${VERSION}_amd64.deb" \
|
||||
"${LINUX_X64_BUNDLE_ARTIFACT_NAME}/release/bundle/rpm/Modrinth App-${VERSION}-1.x86_64.rpm"
|
||||
|
||||
+8
-1
@@ -64,7 +64,8 @@ generated
|
||||
app-playground-data/*
|
||||
|
||||
.astro
|
||||
.claude
|
||||
.claude/*
|
||||
!.claude/skills/
|
||||
.letta
|
||||
|
||||
# labrinth demo fixtures
|
||||
@@ -77,3 +78,9 @@ storybook-static
|
||||
|
||||
# frontend robots.txt
|
||||
apps/frontend/src/public/robots.txt
|
||||
|
||||
# Oh My Code
|
||||
.omc/
|
||||
|
||||
# Local dry-run output for scripts/build-theseus-release-notes.mjs
|
||||
/test_result.md
|
||||
|
||||
Vendored
+3
-1
@@ -29,5 +29,7 @@
|
||||
},
|
||||
"[rust]": {
|
||||
"editor.defaultFormatter": "rust-lang.rust-analyzer"
|
||||
}
|
||||
},
|
||||
"css.lint.unknownAtRules": "ignore",
|
||||
"scss.lint.unknownAtRules": "ignore"
|
||||
}
|
||||
|
||||
@@ -1,63 +1,110 @@
|
||||
# Architecture
|
||||
# Modrinth Monorepo
|
||||
|
||||
Use TAB instead of spaces.
|
||||
This is the Modrinth monorepo — it contains all Modrinth projects, both frontend and backend. When entering a project, either to edit or analyse, you should read it's CLAUDE.md.
|
||||
|
||||
## Frontend
|
||||
## Architecture
|
||||
|
||||
There are two similar frontends in the Modrinth monorepo, the website (apps/frontend) and the app frontend (apps/app-frontend).
|
||||
- **Monorepo tooling:** [Turborepo](https://turbo.build/) (`turbo.jsonc`) + [pnpm workspaces](https://pnpm.io/workspaces) (`pnpm-workspace.yaml`)
|
||||
- **Frontend:** Vue 3 / Nuxt 3, Tailwind CSS v3
|
||||
- **Backend:** Rust (Labrinth API), Postgres, Clickhouse
|
||||
- **Indentation:** Use TAB everywhere, never spaces
|
||||
|
||||
Both use Tailwind v3, and their respective configs can be seen at `tailwind.config.ts` and `tailwind.config.js` respectively.
|
||||
### Apps (`apps/`)
|
||||
|
||||
Both utilize shared and common components from `@modrinth/ui` which can be found at `packages/ui`, and stylings from `@modrinth/assets` which can be found at `packages/assets`.
|
||||
| App | Description |
|
||||
| ----------------- | ------------------------------ |
|
||||
| `frontend` | Main Modrinth website (Nuxt 3) |
|
||||
| `app-frontend` | Desktop/app frontend (Vue 3) |
|
||||
| `app` | Desktop/app shell (Tauri) |
|
||||
| `app-playground` | Testing playground for app |
|
||||
| `labrinth` | Backend API service |
|
||||
| `daedalus_client` | Daedalus client implementation |
|
||||
| `docs` | Documentation site (Astro) |
|
||||
|
||||
Both can utilize icons from `@modrinth/assets`, which are automatically generated based on what's available within the `icons` folder of the `packages/assets` directory. You can see the generated icons list in `generated-icons.ts`.
|
||||
### Packages (`packages/`)
|
||||
|
||||
Both have access to our dependency injection framework, examples as seen in `packages/ui/src/providers/`. Ideally any state which is shared between a page and it's subpages should be shared using this dependency injection framework.
|
||||
| Package | Description |
|
||||
| ------------------ | ----------------------------------------------------- |
|
||||
| `ui` | Shared Vue component library (`@modrinth/ui`) |
|
||||
| `assets` | Styling and auto-generated icons (`@modrinth/assets`) |
|
||||
| `api-client` | API client for Nuxt, Tauri, and Node/browser |
|
||||
| `app-lib` | Shared app library |
|
||||
| `blog` | Blog system and changelog data |
|
||||
| `utils` | Shared utility functions (mostly deprecated) |
|
||||
| `moderation` | Moderation utilities |
|
||||
| `daedalus` | Daedalus protocol |
|
||||
| `tooling-config` | ESLint, Prettier, TypeScript configs |
|
||||
| `ariadne` | Analytics library |
|
||||
| `modrinth-log` | Logging utilities |
|
||||
| `modrinth-maxmind` | MaxMind GeoIP |
|
||||
| `modrinth-util` | General utilities |
|
||||
| `muralpay` | Payment processing |
|
||||
| `path-util` | Path utilities |
|
||||
| `sqlx-tracing` | SQLx query tracing |
|
||||
|
||||
### Website (apps/frontend)
|
||||
## Pre-PR Commands
|
||||
|
||||
Before a pull request can be opened for the website, run `pnpm prepr:frontend:web` from the root folder, otherwise CI will fail.
|
||||
Run these from the **root** folder before opening a pull request - do not run these after each prompt the user gives you, only run when asked, ask the user a question if they want to run it if the user indicates that they are about to create a pull request.
|
||||
|
||||
To run a development version of the frontend, you must first copy over the relevant `.env` template file (prod, staging or local, usually prod) within the `apps/frontend` folder into `apps/frontend/.env`. Then you can run the frontend by running `pnpm web:dev` in the root folder.
|
||||
- **Website:** `pnpm prepr:frontend:web`
|
||||
- **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`
|
||||
|
||||
### App Frontend (apps/app-frontend)
|
||||
The website and app `prepr` commands
|
||||
|
||||
Before a pull request can be opened for the app frontend, run `pnpm prepr:frontend:app` from the root folder, otherwise CI will fail.
|
||||
## Dev Commands
|
||||
|
||||
To run a development version of the app frontend, you must first copy over the relevant `.env` template file (prod, staging or local, usually prod) within `packages/app-lib` into `packages/app-lib/.env`. Then you must run the app itself by running `pnpm app:dev` in the root folder.
|
||||
- **Website:** `pnpm web:dev` (copy `.env` template in `apps/frontend/` first)
|
||||
- **App:** `pnpm app:dev` (copy `.env` template in `packages/app-lib/` first)
|
||||
- **Storybook (packages/ui):** `pnpm storybook`
|
||||
|
||||
### Localization
|
||||
## Project-Specific Instructions
|
||||
|
||||
Refer to `.github/instructions/i18n-convert.instructions.md` if the user asks you to perform any i18n conversion work on a component, set of components, pages or sets of pages.
|
||||
Each project may have its own `CLAUDE.md` with detailed instructions:
|
||||
|
||||
## Labrinth
|
||||
- [`apps/labrinth/CLAUDE.md`](apps/labrinth/CLAUDE.md) — Backend API
|
||||
- [`apps/frontend/CLAUDE.md`](apps/frontend/CLAUDE.md) - Frontend Website
|
||||
|
||||
Labrinth is the backend API service for Modrinth.
|
||||
## Code Guidelines
|
||||
|
||||
### Testing
|
||||
### Comments
|
||||
- DO NOT use "heading" comments like: `=== Helper methods ===`.
|
||||
- Use doc comments, but avoid inline comments unless ABSOLUTELY necessary for clarity. Code should aim to be self documenting!
|
||||
|
||||
Before a pull request can be opened, run `cargo clippy -p labrinth --all-targets` and make sure there are ZERO warnings, otherwise CI will fail.
|
||||
## Bash Guidelines
|
||||
|
||||
Use `cargo test -p labrinth --all-targets` to test your changes. All tests must pass, otherwise CI will fail.
|
||||
### Output handling
|
||||
- DO NOT pipe output through `head`, `tail`, `less`, or `more`
|
||||
- NEVER use `| head -n X` or `| tail -n X` to truncate output
|
||||
- IMPORTANT: Run commands directly without pipes when possible
|
||||
- IMPORTANT: If you need to limit output, use command-specific flags (e.g. `git log -n 10` instead of `git log | head -10`)
|
||||
- ALWAYS read the full output — never pipe through filters
|
||||
|
||||
To prepare the sqlx cache, cd into `apps/labrinth` and run `cargo sqlx prepare`. Make sure to NEVER run `cargo sqlx prepare --workspace`.
|
||||
### General
|
||||
- Do not create new non-source code files (e.g. Bash scripts, SQL scripts) unless explicitly prompted to
|
||||
- For Frontend, when doing lint checks, only use the `prepr` commands, do not use `typecheck` or `tsc` etc.
|
||||
- Types in `@modrinth/utils` are considered highly outdated, if a component needs them, check if you can switch said component to use types from `packages/api-client`
|
||||
- When provided problems, do not say "I didn't introduce these problems" (shifting the blame/effort) - just fix them.
|
||||
|
||||
Read the root `docker-compose.yml` to see what running services are available while developing. Use `docker exec` to access these services.
|
||||
## Edit Tool - Whitespace Handling (CLAUDE ONLY)
|
||||
|
||||
When the user refers to "performing pre-PR checks", do the following:
|
||||
The Read tool uses `→` to mark where line numbers end and file content begins.
|
||||
|
||||
- Run clippy as described above
|
||||
- DO NOT run tests unless explicitly requested (they take a long time)
|
||||
- Prepare the sqlx cache
|
||||
**Rule:** Copy the EXACT whitespace that appears after the `→` marker.
|
||||
- Whatever appears between `→` and the code text is what's actually in the file
|
||||
- That whitespace must be used EXACTLY in Edit tool's old_string
|
||||
- Don't count arrows, don't interpret - just copy what's after the `→`
|
||||
|
||||
### Clickhouse
|
||||
**Example:**
|
||||
14→ private byte tag;
|
||||
For Edit, use: ` private byte tag;` (copy everything after →, including the two tabs)
|
||||
|
||||
Use `docker exec labrinth-clickhouse clickhouse-client` to access the Clickhouse instance. We use the `staging_ariadne` database to store data in testing.
|
||||
**If Edit fails:** Stop and explain the problem. Do not attempt sed/awk/bash workarounds.
|
||||
|
||||
### Postgres
|
||||
**IMPORTANT**: Trust the Read tool output. Copy what's after `→` into Edit immediately. DO NOT verify with sed/od/grep first - that's wasting time and the instructions already tell you to stop if Edit fails, not to pre-verify.
|
||||
|
||||
Use `docker exec labrinth-postgres psql -U labrinth -d labrinth -c "SELECT 1"` to access the PostgreSQL instance, replacing the `SELECT 1` with your query.
|
||||
## Standards
|
||||
|
||||
# Guidelines
|
||||
|
||||
- Do not create new non-source code files (e.g. Bash scripts, SQL scripts) unless explicitly prompted to.
|
||||
Standards available at the @standards/ folder.
|
||||
|
||||
Generated
+371
-152
File diff suppressed because it is too large
Load Diff
+10
-2
@@ -8,6 +8,7 @@ members = [
|
||||
"packages/app-lib",
|
||||
"packages/ariadne",
|
||||
"packages/daedalus",
|
||||
"packages/labrinth-derive",
|
||||
"packages/modrinth-log",
|
||||
"packages/modrinth-maxmind",
|
||||
"packages/modrinth-util",
|
||||
@@ -32,6 +33,7 @@ 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 = [
|
||||
"runtime-tokio-hyper-rustls",
|
||||
@@ -58,6 +60,7 @@ color-eyre = "0.6.5"
|
||||
color-thief = "0.2.2"
|
||||
const_format = "0.2.34"
|
||||
daedalus = { path = "packages/daedalus" }
|
||||
darling = { version = "0.23" }
|
||||
dashmap = "6.1.0"
|
||||
data-url = "0.3.2"
|
||||
deadpool-redis = { git = "https://github.com/modrinth/deadpool", rev = "db5fb00b036ecc8fe5f18853c559b745ffe47bde", version = "0.22.1" }
|
||||
@@ -69,6 +72,7 @@ dotenv-build = "0.1.1"
|
||||
dotenvy = "0.15.7"
|
||||
dunce = "1.0.5"
|
||||
either = "1.15.0"
|
||||
elasticsearch = "9.1.0-alpha.1"
|
||||
encoding_rs = "0.8.35"
|
||||
enumset = "1.1.10"
|
||||
eyre = "0.6.12"
|
||||
@@ -121,9 +125,11 @@ paste = "1.0.15"
|
||||
path-util = { path = "packages/path-util" }
|
||||
phf = { version = "0.13.1", features = ["macros"] }
|
||||
png = "0.18.0"
|
||||
proc-macro2 = { version = "1.0" }
|
||||
prometheus = "0.14.0"
|
||||
quartz_nbt = "0.2.9"
|
||||
quick-xml = "0.38.3"
|
||||
quote = { version = "1.0" }
|
||||
rand = "=0.8.5" # Locked on 0.8 until argon2 and p256 update to 0.9
|
||||
rand_chacha = "=0.3.1" # Locked on 0.3 until we can update rand to 0.9
|
||||
redis = "0.32.7"
|
||||
@@ -166,13 +172,15 @@ spdx = "0.12.0"
|
||||
sqlx = { version = "0.8.6", default-features = false }
|
||||
sqlx-tracing = { path = "packages/sqlx-tracing" }
|
||||
strum = "0.27.2"
|
||||
syn = { version = "2.0" }
|
||||
sysinfo = { version = "0.37.2", default-features = false }
|
||||
tar = "0.4.44"
|
||||
tauri = "2.8.5"
|
||||
tauri-build = "2.4.1"
|
||||
tauri-plugin-deep-link = "2.4.3"
|
||||
tauri-plugin-dialog = "2.4.0"
|
||||
tauri-plugin-http = "2.5.2"
|
||||
tauri-plugin-fs = "2.4.5"
|
||||
tauri-plugin-http = "2.5.7"
|
||||
tauri-plugin-opener = "2.5.0"
|
||||
tauri-plugin-os = "2.3.1"
|
||||
tauri-plugin-single-instance = "2.3.4"
|
||||
@@ -200,7 +208,7 @@ 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-swagger-ui = { version = "9.0.2", features = ["actix-web", "vendored"] }
|
||||
utoipa-scalar = { version = "0.3.0", default-features = false }
|
||||
uuid = "1.18.1"
|
||||
validator = "0.20.0"
|
||||
webp = { version = "0.3.1", default-features = false }
|
||||
|
||||
@@ -22,24 +22,26 @@
|
||||
"@tanstack/vue-query": "^5.90.7",
|
||||
"@tauri-apps/api": "^2.5.0",
|
||||
"@tauri-apps/plugin-dialog": "^2.2.1",
|
||||
"@tauri-apps/plugin-http": "^2.5.0",
|
||||
"@tauri-apps/plugin-fs": "^2.4.5",
|
||||
"@tauri-apps/plugin-http": "~2.5.7",
|
||||
"@tauri-apps/plugin-opener": "^2.2.6",
|
||||
"@tauri-apps/plugin-os": "^2.2.1",
|
||||
"@tauri-apps/plugin-updater": "^2.7.1",
|
||||
"@tauri-apps/plugin-window-state": "^2.2.2",
|
||||
"@types/three": "^0.172.0",
|
||||
"intl-messageformat": "^10.7.7",
|
||||
"vue-i18n": "^10.0.0",
|
||||
"@vueuse/core": "^11.1.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"floating-vue": "^5.2.2",
|
||||
"fuse.js": "^6.6.2",
|
||||
"intl-messageformat": "^10.7.7",
|
||||
"ofetch": "^1.3.4",
|
||||
"overlayscrollbars": "^2.15.1",
|
||||
"pinia": "^3.0.0",
|
||||
"posthog-js": "^1.158.2",
|
||||
"three": "^0.172.0",
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-multiselect": "3.0.0",
|
||||
"vue-i18n": "^10.0.0",
|
||||
"vue-router": "^4.6.0",
|
||||
"vue-virtual-scroller": "v2.0.0-beta.8"
|
||||
},
|
||||
@@ -58,7 +60,7 @@
|
||||
"sass": "^1.74.1",
|
||||
"tailwindcss": "^3.4.4",
|
||||
"typescript": "^5.5.4",
|
||||
"vite": "^6.0.0",
|
||||
"vite": "^8.0.0",
|
||||
"vue-component-type-helpers": "^3.1.8",
|
||||
"vue-tsc": "^2.1.6"
|
||||
},
|
||||
|
||||
+449
-232
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,14 @@
|
||||
color-scheme: dark;
|
||||
--view-width: calc(100% - 5rem);
|
||||
--expanded-view-width: calc(100% - 13rem);
|
||||
--medal-promotion-bg: #000;
|
||||
--medal-promotion-bg-orange: rgba(208, 246, 255, 0.25);
|
||||
--medal-promotion-text-orange: #42abff;
|
||||
--medal-promotion-bg-gradient: linear-gradient(
|
||||
90deg,
|
||||
rgba(66, 170, 255, 0.15),
|
||||
rgba(0, 0, 0, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -77,12 +85,10 @@ body {
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-link);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
-webkit-font-smoothing: antialiased;
|
||||
will-change: filter;
|
||||
}
|
||||
|
||||
.badge {
|
||||
@@ -155,4 +161,82 @@ img {
|
||||
box-shadow: var(--shadow-card);
|
||||
}
|
||||
|
||||
// From the Bootstrap project
|
||||
// The MIT License (MIT)
|
||||
// Copyright (c) 2011-2023 The Bootstrap Authors
|
||||
// https://github.com/twbs/bootstrap/blob/2f617215755b066904248525a8c56ea425dde871/scss/mixins/_visually-hidden.scss#L8
|
||||
.visually-hidden {
|
||||
width: 1px !important;
|
||||
height: 1px !important;
|
||||
padding: 0 !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
clip: rect(0, 0, 0, 0) !important;
|
||||
white-space: nowrap !important;
|
||||
border: 0 !important;
|
||||
|
||||
&:not(caption) {
|
||||
position: absolute !important;
|
||||
}
|
||||
}
|
||||
|
||||
button,
|
||||
input[type='button'] {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
}
|
||||
|
||||
@import '@modrinth/assets/omorphia.scss';
|
||||
|
||||
input {
|
||||
border-radius: var(--size-rounded-sm);
|
||||
box-sizing: border-box;
|
||||
border: 2px solid transparent;
|
||||
// safari iOS rounds inputs by default
|
||||
// set the appearance to none to prevent this
|
||||
appearance: none !important;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-weight: var(--font-weight-regular);
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
background: var(--color-button-bg);
|
||||
color: var(--color-text);
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: var(--font-weight-medium);
|
||||
border: none;
|
||||
outline: 2px solid transparent;
|
||||
box-shadow:
|
||||
var(--shadow-inset-sm),
|
||||
0 0 0 0 transparent;
|
||||
transition: box-shadow 0.1s ease-in-out;
|
||||
min-height: 36px;
|
||||
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
box-shadow:
|
||||
inset 0 0 0 transparent,
|
||||
0 0 0 0.25rem var(--color-brand-shadow);
|
||||
color: var(--color-button-text-active);
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&[disabled='true'] {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:focus::placeholder {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-button-text);
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
TrashIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Accordion,
|
||||
DropdownSelect,
|
||||
formatLoader,
|
||||
injectNotificationManager,
|
||||
@@ -22,7 +23,7 @@ import { computed, ref } from 'vue'
|
||||
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||
import ConfirmDeleteInstanceModal from '@/components/ui/modal/ConfirmDeleteInstanceModal.vue'
|
||||
import { duplicate, remove } from '@/helpers/profile.js'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
@@ -133,12 +134,33 @@ const state = useStorage(
|
||||
{
|
||||
group: 'Group',
|
||||
sortBy: 'Name',
|
||||
collapsedGroups: [],
|
||||
},
|
||||
localStorage,
|
||||
{ mergeDefaults: true },
|
||||
)
|
||||
|
||||
const search = ref('')
|
||||
const collapsedSectionKeys = computed(() => new Set(state.value.collapsedGroups ?? []))
|
||||
|
||||
const getSectionKey = (sectionName) => `${state.value.group}:${sectionName}`
|
||||
|
||||
const isSectionCollapsed = (sectionName) => {
|
||||
return collapsedSectionKeys.value.has(getSectionKey(sectionName))
|
||||
}
|
||||
|
||||
const setSectionCollapsed = (sectionName, collapsed) => {
|
||||
const sectionKey = getSectionKey(sectionName)
|
||||
const collapsedSections = new Set(state.value.collapsedGroups ?? [])
|
||||
|
||||
if (collapsed) {
|
||||
collapsedSections.add(sectionKey)
|
||||
} else {
|
||||
collapsedSections.delete(sectionKey)
|
||||
}
|
||||
|
||||
state.value.collapsedGroups = [...collapsedSections]
|
||||
}
|
||||
|
||||
const filteredResults = computed(() => {
|
||||
const { group = 'Group', sortBy = 'Name' } = state.value
|
||||
@@ -280,18 +302,21 @@ const filteredResults = computed(() => {
|
||||
<span class="font-semibold text-secondary">{{ selected }}</span>
|
||||
</DropdownSelect>
|
||||
</div>
|
||||
<div
|
||||
<Accordion
|
||||
v-for="instanceSection in Array.from(filteredResults, ([key, value]) => ({
|
||||
key,
|
||||
value,
|
||||
}))"
|
||||
:key="instanceSection.key"
|
||||
:divider="instanceSection.key !== 'None'"
|
||||
:open-by-default="!isSectionCollapsed(instanceSection.key)"
|
||||
class="row"
|
||||
@on-open="setSectionCollapsed(instanceSection.key, false)"
|
||||
@on-close="setSectionCollapsed(instanceSection.key, true)"
|
||||
>
|
||||
<div v-if="instanceSection.key !== 'None'" class="divider">
|
||||
<p>{{ instanceSection.key }}</p>
|
||||
<hr aria-hidden="true" />
|
||||
</div>
|
||||
<template v-if="instanceSection.key !== 'None'" #title>
|
||||
<span class="text-base">{{ instanceSection.key }}</span>
|
||||
</template>
|
||||
<section class="instances">
|
||||
<Instance
|
||||
v-for="instance in instanceSection.value"
|
||||
@@ -301,15 +326,8 @@ const filteredResults = computed(() => {
|
||||
@contextmenu.prevent.stop="(event) => handleRightClick(event, instance.path)"
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
<ConfirmModalWrapper
|
||||
ref="confirmModal"
|
||||
title="Are you sure you want to delete this instance?"
|
||||
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||
:has-to-type="false"
|
||||
proceed-label="Delete"
|
||||
@proceed="deleteProfile"
|
||||
/>
|
||||
</Accordion>
|
||||
<ConfirmDeleteInstanceModal ref="confirmModal" @delete="deleteProfile" />
|
||||
<ContextMenu ref="instanceOptions" @option-clicked="handleOptionsClick">
|
||||
<template #play> <PlayIcon /> Play </template>
|
||||
<template #stop> <StopCircleIcon /> Stop </template>
|
||||
@@ -323,73 +341,7 @@ const filteredResults = computed(() => {
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
|
||||
.divider {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
white-space: nowrap;
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: var(--color-gray);
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
align-items: inherit;
|
||||
margin: 1rem 1rem 0 !important;
|
||||
padding: 1rem;
|
||||
width: calc(100% - 2rem);
|
||||
|
||||
.iconified-input {
|
||||
flex-grow: 1;
|
||||
|
||||
input {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.sort-dropdown {
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
.filter-dropdown {
|
||||
width: 15rem;
|
||||
}
|
||||
|
||||
.group-dropdown {
|
||||
width: 10rem;
|
||||
}
|
||||
|
||||
.labeled_button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.instances {
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
<script setup>
|
||||
import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||
|
||||
import { useLoading } from '@/store/state.js'
|
||||
|
||||
const props = defineProps({
|
||||
throttle: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
duration: {
|
||||
type: Number,
|
||||
default: 1000,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'var(--loading-bar-gradient)',
|
||||
},
|
||||
})
|
||||
|
||||
const indicator = useLoadingIndicator({
|
||||
duration: props.duration,
|
||||
throttle: props.throttle,
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => indicator.clear)
|
||||
|
||||
const loading = useLoading()
|
||||
|
||||
watch(loading, (newValue) => {
|
||||
if (newValue.barEnabled) {
|
||||
if (newValue.loading) {
|
||||
indicator.start()
|
||||
} else {
|
||||
indicator.finish()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function useLoadingIndicator(opts) {
|
||||
const progress = ref(0)
|
||||
const isLoading = ref(false)
|
||||
const step = computed(() => 10000 / opts.duration)
|
||||
|
||||
let _timer = null
|
||||
let _throttle = null
|
||||
|
||||
function start() {
|
||||
clear()
|
||||
progress.value = 0
|
||||
if (opts.throttle) {
|
||||
_throttle = setTimeout(() => {
|
||||
isLoading.value = true
|
||||
_startTimer()
|
||||
}, opts.throttle)
|
||||
} else {
|
||||
isLoading.value = true
|
||||
_startTimer()
|
||||
}
|
||||
}
|
||||
|
||||
function finish() {
|
||||
progress.value = 100
|
||||
_hide()
|
||||
}
|
||||
|
||||
function clear() {
|
||||
clearInterval(_timer)
|
||||
clearTimeout(_throttle)
|
||||
_timer = null
|
||||
_throttle = null
|
||||
}
|
||||
|
||||
function _increase(num) {
|
||||
progress.value = Math.min(100, progress.value + num)
|
||||
}
|
||||
|
||||
function _hide() {
|
||||
clear()
|
||||
setTimeout(() => {
|
||||
isLoading.value = false
|
||||
setTimeout(() => {
|
||||
progress.value = 0
|
||||
}, 400)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function _startTimer() {
|
||||
_timer = setInterval(() => {
|
||||
_increase(step.value)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
return { progress, isLoading, start, finish, clear }
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="loading-indicator-bar"
|
||||
:style="{
|
||||
'--_width': `${indicator.progress.value}%`,
|
||||
'--_height': `${indicator.isLoading.value ? props.height : 0}px`,
|
||||
'--_opacity': `${indicator.isLoading.value ? 1 : 0}`,
|
||||
top: `0`,
|
||||
right: `0`,
|
||||
left: `${props.offsetWidth}`,
|
||||
pointerEvents: 'none',
|
||||
width: `var(--_width)`,
|
||||
height: `var(--_height)`,
|
||||
borderRadius: `var(--_height)`,
|
||||
// opacity: `var(--_opacity)`,
|
||||
background: `${props.color}`,
|
||||
backgroundSize: `${(100 / indicator.progress.value) * 100}% auto`,
|
||||
transition: 'width 0.1s ease-in-out, height 0.1s ease-out',
|
||||
zIndex: 6,
|
||||
}"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.loading-indicator-bar::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: var(--_width);
|
||||
bottom: 0;
|
||||
background-image: radial-gradient(80% 100% at 20% 0%, var(--color-brand) 0%, transparent 80%);
|
||||
opacity: calc(var(--_opacity) * 0.1);
|
||||
z-index: 5;
|
||||
transition:
|
||||
width 0.1s ease-in-out,
|
||||
opacity 0.1s ease-out;
|
||||
}
|
||||
</style>
|
||||
@@ -19,15 +19,16 @@ import { useRouter } from 'vue-router'
|
||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||
import Instance from '@/components/ui/Instance.vue'
|
||||
import LegacyProjectCard from '@/components/ui/LegacyProjectCard.vue'
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.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 { injectContentInstall } from '@/providers/content-install'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
import { install as installVersion } from '@/store/install.js'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { install: installVersion } = injectContentInstall()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -238,14 +239,7 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmModalWrapper
|
||||
ref="deleteConfirmModal"
|
||||
title="Are you sure you want to delete this instance?"
|
||||
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||
:has-to-type="false"
|
||||
proceed-label="Delete"
|
||||
@proceed="deleteProfile"
|
||||
/>
|
||||
<ConfirmDeleteInstanceModal ref="deleteConfirmModal" @delete="deleteProfile" />
|
||||
<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">
|
||||
|
||||
@@ -1,64 +1,158 @@
|
||||
<template>
|
||||
<div data-tauri-drag-region class="flex items-center gap-1 pl-3">
|
||||
<Button v-if="false" class="breadcrumbs__back transparent" icon-only @click="$router.back()">
|
||||
<ChevronLeftIcon />
|
||||
</Button>
|
||||
<Button
|
||||
v-if="false"
|
||||
class="breadcrumbs__forward transparent"
|
||||
icon-only
|
||||
@click="$router.forward()"
|
||||
<div
|
||||
ref="outerRef"
|
||||
data-tauri-drag-region
|
||||
class="min-w-0 overflow-hidden pl-3"
|
||||
:class="{ 'breadcrumb-fade-mask': isOverflowing }"
|
||||
:style="isOverflowing ? { '--scroll-distance': `-${overflowAmount}px` } : undefined"
|
||||
@mouseenter="onMouseEnter"
|
||||
@mouseleave="onMouseLeave"
|
||||
>
|
||||
<div
|
||||
ref="innerRef"
|
||||
data-tauri-drag-region
|
||||
class="flex w-fit items-center gap-1"
|
||||
:class="{ 'breadcrumbs-scroll': isAnimating }"
|
||||
@animationiteration="onAnimationIteration"
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</Button>
|
||||
{{ breadcrumbData.resetToNames(breadcrumbs) }}
|
||||
<template v-for="breadcrumb in breadcrumbs" :key="breadcrumb.name">
|
||||
<router-link
|
||||
v-if="breadcrumb.link"
|
||||
:to="{
|
||||
path: breadcrumb.link.replace('{id}', encodeURIComponent($route.params.id)),
|
||||
query: breadcrumb.query,
|
||||
}"
|
||||
class="text-primary"
|
||||
>{{
|
||||
breadcrumb.name.charAt(0) === '?'
|
||||
? breadcrumbData.getName(breadcrumb.name.slice(1))
|
||||
: breadcrumb.name
|
||||
}}
|
||||
</router-link>
|
||||
<span
|
||||
v-else
|
||||
data-tauri-drag-region
|
||||
class="text-contrast font-semibold cursor-default select-none"
|
||||
>{{
|
||||
breadcrumb.name.charAt(0) === '?'
|
||||
? breadcrumbData.getName(breadcrumb.name.slice(1))
|
||||
: breadcrumb.name
|
||||
}}</span
|
||||
>
|
||||
<ChevronRightIcon v-if="breadcrumb.link" data-tauri-drag-region class="w-5 h-5" />
|
||||
</template>
|
||||
{{ breadcrumbData.resetToNames(breadcrumbs) }}
|
||||
<template v-for="breadcrumb in breadcrumbs" :key="breadcrumb.name">
|
||||
<router-link
|
||||
v-if="breadcrumb.link"
|
||||
:to="{
|
||||
path: breadcrumb.link.replace('{id}', encodeURIComponent($route.params.id as string)),
|
||||
query: breadcrumb.query,
|
||||
}"
|
||||
class="shrink-0 whitespace-nowrap text-primary"
|
||||
>
|
||||
{{ resolveLabel(breadcrumb.name) }}
|
||||
</router-link>
|
||||
<span
|
||||
v-else
|
||||
data-tauri-drag-region
|
||||
class="shrink-0 whitespace-nowrap text-contrast font-semibold cursor-default select-none"
|
||||
>
|
||||
{{ resolveLabel(breadcrumb.name) }}
|
||||
</span>
|
||||
<ChevronRightIcon v-if="breadcrumb.link" data-tauri-drag-region class="w-5 h-5 shrink-0" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from '@modrinth/assets'
|
||||
import { Button } from '@modrinth/ui'
|
||||
import { computed } from 'vue'
|
||||
<script setup lang="ts">
|
||||
import { ChevronRightIcon } from '@modrinth/assets'
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||
|
||||
const route = useRoute()
|
||||
interface Breadcrumb {
|
||||
name: string
|
||||
link?: string
|
||||
query?: Record<string, string>
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const breadcrumbData = useBreadcrumbs()
|
||||
const breadcrumbs = computed(() => {
|
||||
|
||||
const breadcrumbs = computed<Breadcrumb[]>(() => {
|
||||
const additionalContext =
|
||||
route.meta.useContext === true
|
||||
? breadcrumbData.context
|
||||
: route.meta.useRootContext === true
|
||||
? breadcrumbData.rootContext
|
||||
: null
|
||||
return additionalContext ? [additionalContext, ...route.meta.breadcrumb] : route.meta.breadcrumb
|
||||
const crumbs = (route.meta.breadcrumb ?? []) as Breadcrumb[]
|
||||
return additionalContext ? [additionalContext as Breadcrumb, ...crumbs] : crumbs
|
||||
})
|
||||
|
||||
function resolveLabel(name: string): string {
|
||||
return name.charAt(0) === '?' ? breadcrumbData.getName(name.slice(1)) : name
|
||||
}
|
||||
|
||||
// Overflow detection
|
||||
const outerRef = ref<HTMLDivElement | null>(null)
|
||||
const innerRef = ref<HTMLDivElement | null>(null)
|
||||
const isOverflowing = ref(false)
|
||||
const isAnimating = ref(false)
|
||||
const overflowAmount = ref(0)
|
||||
|
||||
let hovered = false
|
||||
let stopping = false
|
||||
|
||||
function checkOverflow() {
|
||||
if (!outerRef.value || !innerRef.value) return
|
||||
const overflow = innerRef.value.scrollWidth - outerRef.value.clientWidth
|
||||
isOverflowing.value = overflow > 0
|
||||
overflowAmount.value = overflow + 12
|
||||
}
|
||||
|
||||
function onMouseEnter() {
|
||||
hovered = true
|
||||
stopping = false
|
||||
if (isOverflowing.value) {
|
||||
isAnimating.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseLeave() {
|
||||
hovered = false
|
||||
if (isAnimating.value) {
|
||||
stopping = true
|
||||
}
|
||||
}
|
||||
|
||||
function onAnimationIteration() {
|
||||
if (stopping && !hovered) {
|
||||
isAnimating.value = false
|
||||
stopping = false
|
||||
}
|
||||
}
|
||||
|
||||
let resizeObserver: ResizeObserver | null = null
|
||||
|
||||
onMounted(() => {
|
||||
checkOverflow()
|
||||
resizeObserver = new ResizeObserver(checkOverflow)
|
||||
if (outerRef.value) resizeObserver.observe(outerRef.value)
|
||||
if (innerRef.value) resizeObserver.observe(innerRef.value)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
resizeObserver?.disconnect()
|
||||
})
|
||||
|
||||
watch(breadcrumbs, () => {
|
||||
requestAnimationFrame(checkOverflow)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.breadcrumb-fade-mask {
|
||||
mask-image: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
black 12px,
|
||||
black calc(100% - 12px),
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
.breadcrumbs-scroll {
|
||||
animation: breadcrumb-scroll 10s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes breadcrumb-scroll {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
35%,
|
||||
65% {
|
||||
transform: translateX(var(--scroll-distance));
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
HammerIcon,
|
||||
LogInIcon,
|
||||
UpdatedIcon,
|
||||
WrenchIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { ButtonStyled, Collapsible, injectNotificationManager } from '@modrinth/ui'
|
||||
@@ -155,7 +156,7 @@ async function copyToClipboard(text) {
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="errorModal" :header="title" :closable="closable">
|
||||
<div class="modal-body">
|
||||
<div class="modal-body max-w-[550px]">
|
||||
<div class="markdown-body">
|
||||
<template v-if="errorType === 'minecraft_auth'">
|
||||
<template v-if="metadata.network">
|
||||
@@ -280,7 +281,7 @@ async function copyToClipboard(text) {
|
||||
{{ debugInfo }}
|
||||
</template>
|
||||
<template v-if="hasDebugInfo">
|
||||
<hr />
|
||||
<div class="w-full h-[1px] bg-surface-5 mb-3"></div>
|
||||
<p>
|
||||
If nothing is working and you need help, visit
|
||||
<a :href="supportLink">our support page</a>
|
||||
@@ -296,28 +297,47 @@ async function copyToClipboard(text) {
|
||||
<ButtonStyled v-if="closable">
|
||||
<button @click="errorModal.hide()"><XIcon /> Close</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="hasDebugInfo">
|
||||
<button :disabled="copied" @click="copyToClipboard(debugInfo)">
|
||||
<template v-if="copied"> <CheckIcon class="text-green" /> Copied! </template>
|
||||
<template v-else> <CopyIcon /> Copy debug info </template>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<template v-if="hasDebugInfo">
|
||||
<div class="bg-button-bg rounded-xl mt-2 overflow-clip">
|
||||
<button
|
||||
class="flex items-center justify-between w-full bg-transparent border-0 px-4 py-3 cursor-pointer"
|
||||
@click="errorCollapsed = !errorCollapsed"
|
||||
>
|
||||
<span class="text-contrast font-extrabold m-0">Debug information:</span>
|
||||
<DropdownIcon
|
||||
class="h-5 w-5 text-secondary transition-transform"
|
||||
:class="{ 'rotate-180': !errorCollapsed }"
|
||||
/>
|
||||
</button>
|
||||
<Collapsible :collapsed="errorCollapsed">
|
||||
<pre class="m-0 px-4 py-3 bg-bg rounded-none">{{ debugInfo }}</pre>
|
||||
</Collapsible>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="w-full h-[1px] bg-surface-5"></div>
|
||||
|
||||
<div class="overflow-clip">
|
||||
<button
|
||||
class="flex items-center justify-between w-full bg-transparent border-0 py-4 cursor-pointer"
|
||||
@click="errorCollapsed = !errorCollapsed"
|
||||
>
|
||||
<span class="flex items-center gap-2 text-contrast font-extrabold m-0">
|
||||
<WrenchIcon class="h-4 w-4" />
|
||||
Debug information
|
||||
</span>
|
||||
<DropdownIcon
|
||||
class="h-5 w-5 text-secondary transition-transform"
|
||||
:class="{ 'rotate-180': !errorCollapsed }"
|
||||
/>
|
||||
</button>
|
||||
<Collapsible :collapsed="errorCollapsed">
|
||||
<div
|
||||
class="p-3 bg-surface-2 rounded-2xl text-xs grid grid-cols-[1fr_auto] max-w-full items-start"
|
||||
>
|
||||
<div
|
||||
class="m-0 p-0 rounded-none bg-transparent text-sm font-mono break-words overflow-auto"
|
||||
>
|
||||
{{ debugInfo }}
|
||||
</div>
|
||||
<ButtonStyled circular>
|
||||
<button
|
||||
v-tooltip="'Copy debug info'"
|
||||
:disabled="copied"
|
||||
@click="copyToClipboard(debugInfo)"
|
||||
>
|
||||
<template v-if="copied"> <CheckIcon class="text-green" /> </template>
|
||||
<template v-else> <CopyIcon /> </template>
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</Collapsible>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
<script setup>
|
||||
import { PlusIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, Checkbox, injectNotificationManager, StyledInput } from '@modrinth/ui'
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { ref } from 'vue'
|
||||
|
||||
@@ -9,6 +17,33 @@ import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { export_profile_mrpack, get_pack_export_candidates } from '@/helpers/profile.js'
|
||||
|
||||
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' },
|
||||
modpackNamePlaceholder: {
|
||||
id: 'app.export-modal.modpack-name-placeholder',
|
||||
defaultMessage: 'Modpack name',
|
||||
},
|
||||
versionNumberLabel: {
|
||||
id: 'app.export-modal.version-number-label',
|
||||
defaultMessage: 'Version number',
|
||||
},
|
||||
versionNumberPlaceholder: {
|
||||
id: 'app.export-modal.version-number-placeholder',
|
||||
defaultMessage: '1.0.0',
|
||||
},
|
||||
descriptionPlaceholder: {
|
||||
id: 'app.export-modal.description-placeholder',
|
||||
defaultMessage: 'Enter modpack description...',
|
||||
},
|
||||
selectFilesLabel: {
|
||||
id: 'app.export-modal.select-files-label',
|
||||
defaultMessage: 'Select files and folders to include in pack',
|
||||
},
|
||||
exportButton: { id: 'app.export-modal.export-button', defaultMessage: 'Export' },
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
instance: {
|
||||
@@ -106,36 +141,36 @@ const exportPack = async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="exportModal" header="Export modpack">
|
||||
<ModalWrapper ref="exportModal" :header="formatMessage(messages.header)">
|
||||
<div class="modal-body">
|
||||
<div class="labeled_input">
|
||||
<p>Modpack Name</p>
|
||||
<p>{{ formatMessage(messages.modpackNameLabel) }}</p>
|
||||
<StyledInput
|
||||
v-model="nameInput"
|
||||
:icon="PackageIcon"
|
||||
type="text"
|
||||
placeholder="Modpack name"
|
||||
:placeholder="formatMessage(messages.modpackNamePlaceholder)"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="labeled_input">
|
||||
<p>Version number</p>
|
||||
<p>{{ formatMessage(messages.versionNumberLabel) }}</p>
|
||||
<StyledInput
|
||||
v-model="versionInput"
|
||||
:icon="VersionIcon"
|
||||
type="text"
|
||||
placeholder="1.0.0"
|
||||
:placeholder="formatMessage(messages.versionNumberPlaceholder)"
|
||||
clearable
|
||||
/>
|
||||
</div>
|
||||
<div class="adjacent-input">
|
||||
<div class="labeled_input">
|
||||
<p>Description</p>
|
||||
<p>{{ formatMessage(commonMessages.descriptionLabel) }}</p>
|
||||
|
||||
<StyledInput
|
||||
v-model="exportDescription"
|
||||
multiline
|
||||
placeholder="Enter modpack description..."
|
||||
:placeholder="formatMessage(messages.descriptionPlaceholder)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -143,7 +178,7 @@ const exportPack = async () => {
|
||||
<div class="table">
|
||||
<div class="table-head">
|
||||
<div class="table-cell row-wise">
|
||||
Select files and folders to include in pack
|
||||
{{ formatMessage(messages.selectFilesLabel) }}
|
||||
<Button
|
||||
class="sleek-primary collapsed-button"
|
||||
icon-only
|
||||
@@ -202,11 +237,11 @@ const exportPack = async () => {
|
||||
<div class="button-row push-right">
|
||||
<Button @click="exportModal.hide">
|
||||
<XIcon />
|
||||
Cancel
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</Button>
|
||||
<Button color="primary" @click="exportPack">
|
||||
<PackageIcon />
|
||||
Export
|
||||
{{ formatMessage(messages.exportButton) }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -69,7 +69,7 @@ const play = async (e, context) => {
|
||||
await run(props.instance.path)
|
||||
.catch((err) => handleSevereError(err, { profilePath: props.instance.path }))
|
||||
.finally(() => {
|
||||
trackEvent('InstancePlay', {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
source: context,
|
||||
|
||||
@@ -1,662 +0,0 @@
|
||||
<template>
|
||||
<ModalWrapper ref="modal" header="Creating an instance">
|
||||
<div class="modal-header">
|
||||
<Chips v-model="creationType" :items="['custom', 'from file', 'import from launcher']" />
|
||||
</div>
|
||||
<hr class="card-divider" />
|
||||
<div v-if="creationType === 'custom'" class="modal-body">
|
||||
<div class="image-upload">
|
||||
<Avatar :src="display_icon" size="md" :rounded="true" />
|
||||
<div class="image-input">
|
||||
<Button @click="upload_icon()">
|
||||
<UploadIcon />
|
||||
Select icon
|
||||
</Button>
|
||||
<Button :disabled="!display_icon" @click="reset_icon">
|
||||
<XIcon />
|
||||
Remove icon
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<p class="input-label">Name</p>
|
||||
<StyledInput
|
||||
v-model="profile_name"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter a name for your instance..."
|
||||
:maxlength="100"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<p class="input-label">Loader</p>
|
||||
<Chips v-model="loader" :items="loaders" />
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<p class="input-label">Game version</p>
|
||||
<div class="flex gap-4 items-center">
|
||||
<multiselect
|
||||
v-model="game_version"
|
||||
class="selector"
|
||||
:options="game_versions"
|
||||
:multiple="false"
|
||||
:searchable="true"
|
||||
placeholder="Select game version"
|
||||
open-direction="top"
|
||||
:show-labels="false"
|
||||
/>
|
||||
<Checkbox v-model="showSnapshots" class="shrink-0" label="Show all versions" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="loader !== 'vanilla'" class="input-row">
|
||||
<p class="input-label">Loader version</p>
|
||||
<Chips v-model="loader_version" :items="['stable', 'latest', 'other']" />
|
||||
</div>
|
||||
<div v-if="loader_version === 'other' && loader !== 'vanilla'">
|
||||
<div v-if="game_version" class="input-row">
|
||||
<p class="input-label">Select version</p>
|
||||
<multiselect
|
||||
v-model="specified_loader_version"
|
||||
class="selector"
|
||||
:options="selectable_versions"
|
||||
:searchable="true"
|
||||
placeholder="Select loader version"
|
||||
open-direction="top"
|
||||
:show-labels="false"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="input-row">
|
||||
<p class="warning">Select a game version before you select a loader version</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group push-right">
|
||||
<Button @click="hide()">
|
||||
<XIcon />
|
||||
Cancel
|
||||
</Button>
|
||||
<Button color="primary" :disabled="!check_valid || creating" @click="create_instance()">
|
||||
<PlusIcon v-if="!creating" />
|
||||
{{ creating ? 'Creating...' : 'Create' }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="creationType === 'from file'" class="modal-body">
|
||||
<Button @click="openFile"> <FolderOpenIcon /> Import from file </Button>
|
||||
<div class="info"><InfoIcon /> Or drag and drop your .mrpack file</div>
|
||||
</div>
|
||||
<div v-else class="modal-body">
|
||||
<Chips
|
||||
v-model="selectedProfileType"
|
||||
:items="profileOptions"
|
||||
:format-label="(profile) => profile?.name"
|
||||
/>
|
||||
<div class="path-selection">
|
||||
<h3>{{ selectedProfileType.name }} path</h3>
|
||||
<div class="path-input">
|
||||
<StyledInput
|
||||
v-model="selectedProfileType.path"
|
||||
:icon="FolderOpenIcon"
|
||||
type="text"
|
||||
placeholder="Path to launcher"
|
||||
clearable
|
||||
@change="setPath"
|
||||
/>
|
||||
<Button icon-only @click="selectLauncherPath">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
<Button icon-only @click="reload">
|
||||
<UpdatedIcon />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table">
|
||||
<div class="table-head table-row">
|
||||
<div class="toggle-all table-cell">
|
||||
<Checkbox
|
||||
class="select-checkbox"
|
||||
:model-value="
|
||||
profiles.get(selectedProfileType.name)?.every((child) => child.selected)
|
||||
"
|
||||
@update:model-value="
|
||||
(newValue) =>
|
||||
profiles
|
||||
.get(selectedProfileType.name)
|
||||
?.forEach((child) => (child.selected = newValue))
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="name-cell table-cell">Profile name</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
profiles.get(selectedProfileType.name) &&
|
||||
profiles.get(selectedProfileType.name).length > 0
|
||||
"
|
||||
class="table-content"
|
||||
>
|
||||
<div
|
||||
v-for="(profile, index) in profiles.get(selectedProfileType.name)"
|
||||
:key="index"
|
||||
class="table-row"
|
||||
>
|
||||
<div class="checkbox-cell table-cell">
|
||||
<Checkbox v-model="profile.selected" class="select-checkbox" />
|
||||
</div>
|
||||
<div class="name-cell table-cell">
|
||||
{{ profile.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="table-content empty">No profiles found</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<Button
|
||||
:disabled="
|
||||
loading ||
|
||||
!Array.from(profiles.values())
|
||||
.flatMap((e) => e)
|
||||
.some((e) => e.selected)
|
||||
"
|
||||
color="primary"
|
||||
@click="next"
|
||||
>
|
||||
{{
|
||||
loading
|
||||
? 'Importing...'
|
||||
: Array.from(profiles.values())
|
||||
.flatMap((e) => e)
|
||||
.some((e) => e.selected)
|
||||
? `Import ${
|
||||
Array.from(profiles.values())
|
||||
.flatMap((e) => e)
|
||||
.filter((e) => e.selected).length
|
||||
} profiles`
|
||||
: 'Select profiles to import'
|
||||
}}
|
||||
</Button>
|
||||
<ProgressBar
|
||||
v-if="loading"
|
||||
:progress="(importedProfiles / (totalProfiles + 0.0001)) * 100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
FolderOpenIcon,
|
||||
FolderSearchIcon,
|
||||
InfoIcon,
|
||||
PlusIcon,
|
||||
UpdatedIcon,
|
||||
UploadIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Checkbox,
|
||||
Chips,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { getCurrentWebview } from '@tauri-apps/api/webview'
|
||||
import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { computed, onUnmounted, ref, shallowRef } from 'vue'
|
||||
import Multiselect from 'vue-multiselect'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import {
|
||||
get_default_launcher_path,
|
||||
get_importable_instances,
|
||||
import_instance,
|
||||
} from '@/helpers/import.js'
|
||||
import { get_game_versions, get_loader_versions } from '@/helpers/metadata'
|
||||
import { create_profile_and_install_from_file } from '@/helpers/pack.js'
|
||||
import { create } from '@/helpers/profile'
|
||||
import { get_loaders } from '@/helpers/tags'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const profile_name = ref('')
|
||||
const game_version = ref('')
|
||||
const loader = ref('vanilla')
|
||||
const loader_version = ref('stable')
|
||||
const specified_loader_version = ref('')
|
||||
const icon = ref(null)
|
||||
const display_icon = ref(null)
|
||||
const creating = ref(false)
|
||||
const showSnapshots = ref(false)
|
||||
const creationType = ref('custom')
|
||||
const isShowing = ref(false)
|
||||
|
||||
defineExpose({
|
||||
show: async () => {
|
||||
game_version.value = ''
|
||||
specified_loader_version.value = ''
|
||||
profile_name.value = ''
|
||||
creating.value = false
|
||||
showSnapshots.value = false
|
||||
loader.value = 'vanilla'
|
||||
loader_version.value = 'stable'
|
||||
icon.value = null
|
||||
display_icon.value = null
|
||||
isShowing.value = true
|
||||
modal.value.show()
|
||||
|
||||
unlistener.value = await getCurrentWebview().onDragDropEvent(async (event) => {
|
||||
// Only if modal is showing
|
||||
if (!isShowing.value) return
|
||||
if (event.payload.type !== 'drop') return
|
||||
if (creationType.value !== 'from file') return
|
||||
hide()
|
||||
const { paths } = event.payload
|
||||
if (paths && paths.length > 0 && paths[0].endsWith('.mrpack')) {
|
||||
await create_profile_and_install_from_file(paths[0]).catch(handleError)
|
||||
trackEvent('InstanceCreate', {
|
||||
source: 'CreationModalFileDrop',
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
trackEvent('InstanceCreateStart', { source: 'CreationModal' })
|
||||
},
|
||||
})
|
||||
|
||||
const unlistener = ref(null)
|
||||
const hide = () => {
|
||||
isShowing.value = false
|
||||
modal.value.hide()
|
||||
if (unlistener.value) {
|
||||
unlistener.value()
|
||||
unlistener.value = null
|
||||
}
|
||||
}
|
||||
onUnmounted(() => {
|
||||
if (unlistener.value) {
|
||||
unlistener.value()
|
||||
unlistener.value = null
|
||||
}
|
||||
})
|
||||
|
||||
const [
|
||||
fabric_versions,
|
||||
forge_versions,
|
||||
quilt_versions,
|
||||
neoforge_versions,
|
||||
all_game_versions,
|
||||
loaders,
|
||||
] = await Promise.all([
|
||||
get_loader_versions('fabric').then(shallowRef).catch(handleError),
|
||||
get_loader_versions('forge').then(shallowRef).catch(handleError),
|
||||
get_loader_versions('quilt').then(shallowRef).catch(handleError),
|
||||
get_loader_versions('neo').then(shallowRef).catch(handleError),
|
||||
get_game_versions().then(shallowRef).catch(handleError),
|
||||
get_loaders()
|
||||
.then((value) =>
|
||||
ref(
|
||||
value
|
||||
.filter((item) => item.supported_project_types.includes('modpack'))
|
||||
.map((item) => item.name.toLowerCase()),
|
||||
),
|
||||
)
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
return ref([])
|
||||
}),
|
||||
])
|
||||
loaders.value.unshift('vanilla')
|
||||
|
||||
const game_versions = computed(() => {
|
||||
return all_game_versions.value.versions
|
||||
.filter((item) => {
|
||||
let defaultVal = item.type === 'release' || showSnapshots.value
|
||||
if (loader.value === 'fabric') {
|
||||
defaultVal &= fabric_versions.value.gameVersions.some((x) => item.id === x.id)
|
||||
} else if (loader.value === 'forge') {
|
||||
defaultVal &= forge_versions.value.gameVersions.some((x) => item.id === x.id)
|
||||
} else if (loader.value === 'quilt') {
|
||||
defaultVal &= quilt_versions.value.gameVersions.some((x) => item.id === x.id)
|
||||
} else if (loader.value === 'neoforge') {
|
||||
defaultVal &= neoforge_versions.value.gameVersions.some((x) => item.id === x.id)
|
||||
}
|
||||
|
||||
return defaultVal
|
||||
})
|
||||
.map((item) => item.id)
|
||||
})
|
||||
|
||||
const modal = ref(null)
|
||||
|
||||
const check_valid = computed(() => {
|
||||
return (
|
||||
profile_name.value.trim() &&
|
||||
game_version.value &&
|
||||
game_versions.value.includes(game_version.value)
|
||||
)
|
||||
})
|
||||
|
||||
const create_instance = async () => {
|
||||
creating.value = true
|
||||
const loader_version_value =
|
||||
loader_version.value === 'other' ? specified_loader_version.value : loader_version.value
|
||||
const loaderVersion = loader.value === 'vanilla' ? null : (loader_version_value ?? 'stable')
|
||||
|
||||
hide()
|
||||
creating.value = false
|
||||
|
||||
await create(
|
||||
profile_name.value,
|
||||
game_version.value,
|
||||
loader.value,
|
||||
loader.value === 'vanilla' ? null : (loader_version_value ?? 'stable'),
|
||||
icon.value,
|
||||
).catch(handleError)
|
||||
|
||||
trackEvent('InstanceCreate', {
|
||||
profile_name: profile_name.value,
|
||||
game_version: game_version.value,
|
||||
loader: loader.value,
|
||||
loader_version: loaderVersion,
|
||||
has_icon: !!icon.value,
|
||||
source: 'CreationModal',
|
||||
})
|
||||
}
|
||||
|
||||
const upload_icon = async () => {
|
||||
const res = await open({
|
||||
multiple: false,
|
||||
filters: [
|
||||
{
|
||||
name: 'Image',
|
||||
extensions: ['png', 'jpeg', 'svg', 'webp', 'gif', 'jpg'],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
icon.value = res.path ?? res
|
||||
|
||||
if (!icon.value) return
|
||||
display_icon.value = convertFileSrc(icon.value)
|
||||
}
|
||||
|
||||
const reset_icon = () => {
|
||||
icon.value = null
|
||||
display_icon.value = null
|
||||
}
|
||||
|
||||
const selectable_versions = computed(() => {
|
||||
if (game_version.value) {
|
||||
if (loader.value === 'fabric') {
|
||||
return fabric_versions.value.gameVersions[0].loaders.map((item) => item.id)
|
||||
} else if (loader.value === 'forge') {
|
||||
return forge_versions.value.gameVersions
|
||||
.find((item) => item.id === game_version.value)
|
||||
.loaders.map((item) => item.id)
|
||||
} else if (loader.value === 'quilt') {
|
||||
return quilt_versions.value.gameVersions[0].loaders.map((item) => item.id)
|
||||
} else if (loader.value === 'neoforge') {
|
||||
return neoforge_versions.value.gameVersions
|
||||
.find((item) => item.id === game_version.value)
|
||||
.loaders.map((item) => item.id)
|
||||
}
|
||||
}
|
||||
return []
|
||||
})
|
||||
|
||||
const openFile = async () => {
|
||||
const newProject = await open({ multiple: false })
|
||||
if (!newProject) return
|
||||
hide()
|
||||
await create_profile_and_install_from_file(newProject.path ?? newProject).catch(handleError)
|
||||
|
||||
trackEvent('InstanceCreate', {
|
||||
source: 'CreationModalFileOpen',
|
||||
})
|
||||
}
|
||||
|
||||
const profiles = ref(
|
||||
new Map([
|
||||
['MultiMC', []],
|
||||
['GDLauncher', []],
|
||||
['ATLauncher', []],
|
||||
['Curseforge', []],
|
||||
['PrismLauncher', []],
|
||||
]),
|
||||
)
|
||||
|
||||
const loading = ref(false)
|
||||
const importedProfiles = ref(0)
|
||||
const totalProfiles = ref(0)
|
||||
|
||||
const selectedProfileType = ref('MultiMC')
|
||||
const profileOptions = ref([
|
||||
{ name: 'MultiMC', path: '' },
|
||||
{ name: 'GDLauncher', path: '' },
|
||||
{ name: 'ATLauncher', path: '' },
|
||||
{ name: 'Curseforge', path: '' },
|
||||
{ name: 'PrismLauncher', path: '' },
|
||||
])
|
||||
|
||||
// Attempt to get import profiles on default paths
|
||||
const promises = profileOptions.value.map(async (option) => {
|
||||
const path = await get_default_launcher_path(option.name).catch(handleError)
|
||||
if (!path || path === '') return
|
||||
|
||||
// Try catch to allow failure and simply ignore default path attempt
|
||||
try {
|
||||
const instances = await get_importable_instances(option.name, path)
|
||||
|
||||
if (!instances) return
|
||||
profileOptions.value.find((profile) => profile.name === option.name).path = path
|
||||
profiles.value.set(
|
||||
option.name,
|
||||
instances.map((name) => ({ name, selected: false })),
|
||||
)
|
||||
} catch {
|
||||
// Allow failure silently
|
||||
}
|
||||
})
|
||||
await Promise.all(promises)
|
||||
|
||||
const selectLauncherPath = async () => {
|
||||
selectedProfileType.value.path = await open({ multiple: false, directory: true })
|
||||
|
||||
if (selectedProfileType.value.path) {
|
||||
await reload()
|
||||
}
|
||||
}
|
||||
|
||||
const reload = async () => {
|
||||
const instances = await get_importable_instances(
|
||||
selectedProfileType.value.name,
|
||||
selectedProfileType.value.path,
|
||||
).catch(handleError)
|
||||
if (instances) {
|
||||
profiles.value.set(
|
||||
selectedProfileType.value.name,
|
||||
instances.map((name) => ({ name, selected: false })),
|
||||
)
|
||||
} else {
|
||||
profiles.value.set(selectedProfileType.value.name, [])
|
||||
}
|
||||
}
|
||||
|
||||
const setPath = () => {
|
||||
profileOptions.value.find((profile) => profile.name === selectedProfileType.value.name).path =
|
||||
selectedProfileType.value.path
|
||||
}
|
||||
|
||||
const next = async () => {
|
||||
importedProfiles.value = 0
|
||||
totalProfiles.value = Array.from(profiles.value.values())
|
||||
.map((profiles) => profiles.filter((profile) => profile.selected).length)
|
||||
.reduce((a, b) => a + b, 0)
|
||||
loading.value = true
|
||||
for (const launcher of Array.from(profiles.value.entries()).map(([launcher, profiles]) => ({
|
||||
launcher,
|
||||
path: profileOptions.value.find((option) => option.name === launcher).path,
|
||||
profiles,
|
||||
}))) {
|
||||
for (const profile of launcher.profiles.filter((profile) => profile.selected)) {
|
||||
await import_instance(launcher.launcher, launcher.path, profile.name)
|
||||
.catch(handleError)
|
||||
.then(() => console.log(`Successfully Imported ${profile.name} from ${launcher.launcher}`))
|
||||
profile.selected = false
|
||||
importedProfiles.value++
|
||||
}
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap-md);
|
||||
margin-top: var(--gap-lg);
|
||||
}
|
||||
|
||||
.input-label {
|
||||
font-size: 1rem;
|
||||
font-weight: bolder;
|
||||
color: var(--color-contrast);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.text-input {
|
||||
width: 20rem;
|
||||
}
|
||||
|
||||
.image-upload {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.image-input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.warning {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
:deep(button.checkbox) {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.selector {
|
||||
max-width: 20rem;
|
||||
}
|
||||
|
||||
.labeled-divider {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.labeled-divider:after {
|
||||
background-color: var(--color-raised-bg);
|
||||
content: 'Or';
|
||||
color: var(--color-base);
|
||||
padding: var(--gap-sm);
|
||||
position: relative;
|
||||
top: -0.5rem;
|
||||
}
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.path-selection {
|
||||
padding: var(--gap-xl);
|
||||
background-color: var(--color-bg);
|
||||
border-radius: var(--radius-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--gap-md);
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.path-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
gap: var(--gap-sm);
|
||||
|
||||
.iconified-input {
|
||||
flex-grow: 1;
|
||||
:deep(input) {
|
||||
width: 100%;
|
||||
flex-basis: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
border: 1px solid var(--color-bg);
|
||||
}
|
||||
|
||||
.table-row {
|
||||
grid-template-columns: min-content auto;
|
||||
}
|
||||
|
||||
.table-content {
|
||||
max-height: calc(5 * (18px + 2rem));
|
||||
height: calc(5 * (18px + 2rem));
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.select-checkbox {
|
||||
button.checkbox {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.button-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--gap-md);
|
||||
|
||||
.transparent {
|
||||
padding: var(--gap-sm) 0;
|
||||
}
|
||||
}
|
||||
|
||||
.empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bolder;
|
||||
color: var(--color-contrast);
|
||||
}
|
||||
|
||||
.card-divider {
|
||||
margin: var(--gap-md) var(--gap-lg) 0 var(--gap-lg);
|
||||
}
|
||||
</style>
|
||||
@@ -2,6 +2,7 @@
|
||||
import { GameIcon, LeftArrowIcon } from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled, FormattedTag } from '@modrinth/ui'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { computed } from 'vue'
|
||||
|
||||
type Instance = {
|
||||
game_version: string
|
||||
@@ -12,18 +13,23 @@ type Instance = {
|
||||
name: string
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
instance: Instance
|
||||
}>()
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
instance: Instance
|
||||
backTab?: string
|
||||
}>(),
|
||||
{ backTab: undefined },
|
||||
)
|
||||
|
||||
const instanceLink = computed(() => {
|
||||
const base = `/instance/${encodeURIComponent(props.instance.path)}`
|
||||
return props.backTab ? `${base}/${props.backTab}` : base
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-between items-center border-0 border-b border-solid border-divider pb-4">
|
||||
<router-link
|
||||
:to="`/instance/${encodeURIComponent(instance.path)}`"
|
||||
tabindex="-1"
|
||||
class="flex flex-col gap-4 text-primary"
|
||||
>
|
||||
<router-link :to="instanceLink" tabindex="-1" class="flex flex-col gap-4 text-primary">
|
||||
<span class="flex items-center gap-2">
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : undefined"
|
||||
@@ -43,9 +49,7 @@ defineProps<{
|
||||
</span>
|
||||
</router-link>
|
||||
<ButtonStyled>
|
||||
<router-link :to="`/instance/${encodeURIComponent(instance.path)}`">
|
||||
<LeftArrowIcon /> Back to instance
|
||||
</router-link>
|
||||
<router-link :to="instanceLink"> <LeftArrowIcon /> Back to instance </router-link>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup>
|
||||
import { DownloadIcon, HeartIcon, TagIcon } from '@modrinth/assets'
|
||||
import { Avatar, FormattedTag, TagItem } from '@modrinth/ui'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
import { Avatar, FormattedTag, TagItem, useCompactNumber } from '@modrinth/ui'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { computed } from 'vue'
|
||||
@@ -11,6 +10,8 @@ dayjs.extend(relativeTime)
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const { formatCompactNumber } = useCompactNumber()
|
||||
|
||||
const props = defineProps({
|
||||
project: {
|
||||
type: Object,
|
||||
@@ -96,13 +97,13 @@ const toTransparent = computed(() => {
|
||||
class="flex items-center gap-1 pr-2 border-0 border-r-[1px] border-solid border-button-border"
|
||||
>
|
||||
<DownloadIcon />
|
||||
{{ formatNumber(project.downloads) }}
|
||||
{{ formatCompactNumber(project.downloads) }}
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center gap-1 pr-2 border-0 border-r-[1px] border-solid border-button-border"
|
||||
>
|
||||
<HeartIcon />
|
||||
{{ formatNumber(project.follows) }}
|
||||
{{ formatCompactNumber(project.follows) }}
|
||||
</div>
|
||||
<div class="flex items-center gap-1 pr-2">
|
||||
<TagIcon />
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
v-if="typeof to === 'string'"
|
||||
:to="to"
|
||||
v-bind="$attrs"
|
||||
:active-class="isSubpage ? '' : undefined"
|
||||
:class="{
|
||||
'router-link-active': isPrimary && isPrimary(route),
|
||||
'subpage-active': isSubpage && isSubpage(route),
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<nav
|
||||
class="card-shadow experimental-styles-within relative flex w-fit overflow-clip rounded-full bg-bg-raised p-1 text-sm font-bold"
|
||||
>
|
||||
<RouterLink
|
||||
v-for="(link, index) in filteredLinks"
|
||||
v-show="link.shown === undefined ? true : link.shown"
|
||||
:key="index"
|
||||
ref="tabLinkElements"
|
||||
:to="query ? (link.href ? `?${query}=${link.href}` : '?') : link.href"
|
||||
:class="`button-animation z-[1] flex flex-row items-center gap-2 px-4 py-2 focus:rounded-full ${activeIndex === index && !subpageSelected ? 'text-button-textSelected' : activeIndex === index && subpageSelected ? 'text-contrast' : 'text-primary'}`"
|
||||
>
|
||||
<component :is="link.icon" v-if="link.icon" class="size-5" />
|
||||
<span class="text-nowrap">{{ link.label }}</span>
|
||||
</RouterLink>
|
||||
<div
|
||||
:class="`navtabs-transition pointer-events-none absolute h-[calc(100%-0.5rem)] overflow-hidden rounded-full p-1 ${subpageSelected ? 'bg-button-bg' : 'bg-button-bgSelected'}`"
|
||||
:style="{
|
||||
left: sliderLeftPx,
|
||||
top: sliderTopPx,
|
||||
right: sliderRightPx,
|
||||
bottom: sliderBottomPx,
|
||||
opacity: sliderLeft === 4 && sliderLeft === sliderRight ? 0 : activeIndex === -1 ? 0 : 1,
|
||||
}"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import type { RouteLocationRaw } from 'vue-router'
|
||||
import { RouterLink, useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
interface Tab {
|
||||
label: string
|
||||
href: string | RouteLocationRaw
|
||||
shown?: boolean
|
||||
icon?: unknown
|
||||
subpages?: string[]
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
links: Tab[]
|
||||
query?: string
|
||||
}>()
|
||||
|
||||
const sliderLeft = ref(4)
|
||||
const sliderTop = ref(4)
|
||||
const sliderRight = ref(4)
|
||||
const sliderBottom = ref(4)
|
||||
const activeIndex = ref(-1)
|
||||
const oldIndex = ref(-1)
|
||||
const subpageSelected = ref(false)
|
||||
|
||||
const filteredLinks = computed(() =>
|
||||
props.links.filter((x) => (x.shown === undefined ? true : x.shown)),
|
||||
)
|
||||
const sliderLeftPx = computed(() => `${sliderLeft.value}px`)
|
||||
const sliderTopPx = computed(() => `${sliderTop.value}px`)
|
||||
const sliderRightPx = computed(() => `${sliderRight.value}px`)
|
||||
const sliderBottomPx = computed(() => `${sliderBottom.value}px`)
|
||||
|
||||
function pickLink() {
|
||||
let index = -1
|
||||
subpageSelected.value = false
|
||||
for (let i = filteredLinks.value.length - 1; i >= 0; i--) {
|
||||
const link = filteredLinks.value[i]
|
||||
|
||||
if (route.path === (typeof link.href === 'string' ? link.href : link.href.path)) {
|
||||
index = i
|
||||
break
|
||||
} else if (link.subpages && link.subpages.some((subpage) => route.path.includes(subpage))) {
|
||||
index = i
|
||||
subpageSelected.value = true
|
||||
break
|
||||
}
|
||||
}
|
||||
activeIndex.value = index
|
||||
|
||||
if (activeIndex.value !== -1) {
|
||||
startAnimation()
|
||||
} else {
|
||||
oldIndex.value = -1
|
||||
sliderLeft.value = 0
|
||||
sliderRight.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
const tabLinkElements = ref()
|
||||
|
||||
function startAnimation() {
|
||||
const el = tabLinkElements.value[activeIndex.value].$el
|
||||
|
||||
if (!el || !el.offsetParent) return
|
||||
|
||||
const newValues = {
|
||||
left: el.offsetLeft,
|
||||
top: el.offsetTop,
|
||||
right: el.offsetParent.offsetWidth - el.offsetLeft - el.offsetWidth,
|
||||
bottom: el.offsetParent.offsetHeight - el.offsetTop - el.offsetHeight,
|
||||
}
|
||||
|
||||
if (sliderLeft.value === 4 && sliderRight.value === 4) {
|
||||
sliderLeft.value = newValues.left
|
||||
sliderRight.value = newValues.right
|
||||
sliderTop.value = newValues.top
|
||||
sliderBottom.value = newValues.bottom
|
||||
} else {
|
||||
const delay = 200
|
||||
|
||||
if (newValues.left < sliderLeft.value) {
|
||||
sliderLeft.value = newValues.left
|
||||
setTimeout(() => {
|
||||
sliderRight.value = newValues.right
|
||||
}, delay)
|
||||
} else {
|
||||
sliderRight.value = newValues.right
|
||||
setTimeout(() => {
|
||||
sliderLeft.value = newValues.left
|
||||
}, delay)
|
||||
}
|
||||
|
||||
if (newValues.top < sliderTop.value) {
|
||||
sliderTop.value = newValues.top
|
||||
setTimeout(() => {
|
||||
sliderBottom.value = newValues.bottom
|
||||
}, delay)
|
||||
} else {
|
||||
sliderBottom.value = newValues.bottom
|
||||
setTimeout(() => {
|
||||
sliderTop.value = newValues.top
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', pickLink)
|
||||
pickLink()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', pickLink)
|
||||
})
|
||||
|
||||
watch(route, () => {
|
||||
pickLink()
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.navtabs-transition {
|
||||
/* Delay on opacity is to hide any jankiness as the page loads */
|
||||
transition:
|
||||
all 150ms cubic-bezier(0.4, 0, 0.2, 1) 0s,
|
||||
opacity 250ms cubic-bezier(0.5, 0, 0.2, 1) 50ms;
|
||||
}
|
||||
</style>
|
||||
@@ -49,27 +49,26 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NavButton
|
||||
v-for="instance in recentInstances"
|
||||
:key="instance.id"
|
||||
v-tooltip.right="instance.name"
|
||||
:to="`/instance/${encodeURIComponent(instance.path)}`"
|
||||
class="relative"
|
||||
>
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
size="28px"
|
||||
:tint-by="instance.path"
|
||||
:class="`transition-all ${instance.install_stage !== 'installed' ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
|
||||
/>
|
||||
<div
|
||||
v-if="instance.install_stage !== 'installed'"
|
||||
class="absolute inset-0 flex items-center justify-center z-10"
|
||||
>
|
||||
<SpinnerIcon class="animate-spin w-4 h-4" />
|
||||
</div>
|
||||
</NavButton>
|
||||
<div v-if="recentInstances.length > 0" class="h-px w-6 mx-auto my-2 bg-divider"></div>
|
||||
<div v-for="instance in recentInstances" :key="instance.id" v-tooltip.right="instance.name">
|
||||
<NavButton :to="`/instance/${encodeURIComponent(instance.path)}`" class="relative">
|
||||
<Avatar
|
||||
:src="instance.icon_path ? convertFileSrc(instance.icon_path) : null"
|
||||
size="28px"
|
||||
:tint-by="instance.path"
|
||||
:class="`transition-all ${instance.install_stage !== 'installed' ? `brightness-[0.25] scale-[0.85]` : `group-hover:brightness-75`}`"
|
||||
/>
|
||||
<div
|
||||
v-if="instance.install_stage !== 'installed'"
|
||||
class="absolute inset-0 flex items-center justify-center z-10 pointer-events-none"
|
||||
>
|
||||
<SpinnerIcon class="animate-spin w-4 h-4" />
|
||||
</div>
|
||||
</NavButton>
|
||||
</div>
|
||||
<div
|
||||
v-if="instances && recentInstances.length > 0"
|
||||
class="h-px w-6 mx-auto my-2 bg-divider"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -52,10 +52,12 @@
|
||||
<h3 class="info-title">
|
||||
{{ loadingBar.title }}
|
||||
</h3>
|
||||
<ProgressBar :progress="Math.floor((100 * loadingBar.current) / loadingBar.total)" />
|
||||
<div class="row">
|
||||
{{ Math.floor((100 * loadingBar.current) / loadingBar.total) }}%
|
||||
{{ loadingBar.message }}
|
||||
<div class="flex flex-col gap-2 w-full">
|
||||
<ProgressBar :progress="Math.floor((100 * loadingBar.current) / loadingBar.total)" />
|
||||
<div class="row">
|
||||
{{ Math.floor((100 * loadingBar.current) / loadingBar.total) }}%
|
||||
{{ loadingBar.message }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -346,7 +348,7 @@ onBeforeUnmount(() => {
|
||||
.info-card {
|
||||
position: absolute;
|
||||
top: 3.5rem;
|
||||
right: 0.5rem;
|
||||
right: 2rem;
|
||||
z-index: 9;
|
||||
width: 20rem;
|
||||
background-color: var(--color-raised-bg);
|
||||
@@ -420,7 +422,7 @@ onBeforeUnmount(() => {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
gap: 0.75rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
<template>
|
||||
<ProjectCard
|
||||
:title="project.title"
|
||||
:link="
|
||||
() => {
|
||||
emit('open')
|
||||
$router.push({
|
||||
path: `/project/${project.project_id ?? project.id}`,
|
||||
query: { i: props.instance ? props.instance.path : undefined },
|
||||
})
|
||||
}
|
||||
"
|
||||
:author="{ name: project.author, link: `https://modrinth.com/user/${project.author}` }"
|
||||
:icon-url="project.icon_url"
|
||||
:summary="project.description"
|
||||
:tags="project.display_categories"
|
||||
:all-tags="project.categories"
|
||||
:downloads="project.downloads"
|
||||
:followers="project.follows"
|
||||
:date-updated="project.date_modified"
|
||||
:banner="project.featured_gallery ?? undefined"
|
||||
:color="project.color ?? undefined"
|
||||
:environment="
|
||||
projectType
|
||||
? ['mod', 'modpack'].includes(projectType)
|
||||
? {
|
||||
clientSide: project.client_side,
|
||||
serverSide: project.server_side,
|
||||
}
|
||||
: undefined
|
||||
: undefined
|
||||
"
|
||||
layout="list"
|
||||
>
|
||||
<template #actions>
|
||||
<ButtonStyled color="brand" type="outlined">
|
||||
<button
|
||||
:disabled="installed || installing"
|
||||
class="shrink-0 no-wrap"
|
||||
@click.stop="install()"
|
||||
>
|
||||
<template v-if="!installed">
|
||||
<DownloadIcon v-if="modpack || instance" />
|
||||
<PlusIcon v-else />
|
||||
</template>
|
||||
<CheckIcon v-else />
|
||||
{{
|
||||
installing
|
||||
? 'Installing'
|
||||
: installed
|
||||
? 'Installed'
|
||||
: modpack || instance
|
||||
? 'Install'
|
||||
: 'Add to an instance'
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
</ProjectCard>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { CheckIcon, DownloadIcon, PlusIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager, ProjectCard } from '@modrinth/ui'
|
||||
import dayjs from 'dayjs'
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import { install as installVersion } from '@/store/install.js'
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
backgroundImage: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
project: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
instance: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
featured: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
installed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
projectType: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['open', 'install'])
|
||||
|
||||
const installing = ref(false)
|
||||
|
||||
async function install() {
|
||||
installing.value = true
|
||||
await installVersion(
|
||||
props.project.project_id ?? props.project.id,
|
||||
null,
|
||||
props.instance ? props.instance.path : null,
|
||||
'SearchCard',
|
||||
() => {
|
||||
installing.value = false
|
||||
emit('install', props.project.project_id ?? props.project.id)
|
||||
},
|
||||
(profile) => {
|
||||
router.push(`/instance/${profile}`)
|
||||
},
|
||||
).catch(handleError)
|
||||
}
|
||||
|
||||
const modpack = computed(() => props.project.project_type === 'modpack')
|
||||
</script>
|
||||
File diff suppressed because one or more lines are too long
@@ -1,38 +1,33 @@
|
||||
<script setup>
|
||||
import { Button, injectNotificationManager } from '@modrinth/ui'
|
||||
import { Button, injectNotificationManager, ProjectCard } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import SearchCard from '@/components/ui/SearchCard.vue'
|
||||
import { get_project, get_version } from '@/helpers/cache.js'
|
||||
import { get_categories } from '@/helpers/tags.js'
|
||||
import { install as installVersion } from '@/store/install.js'
|
||||
import { get_project_v3, get_version } from '@/helpers/cache.js'
|
||||
import { injectContentInstall } from '@/providers/content-install'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { install: installVersion } = injectContentInstall()
|
||||
|
||||
const confirmModal = ref(null)
|
||||
const project = ref(null)
|
||||
const version = ref(null)
|
||||
const categories = ref(null)
|
||||
const installing = ref(false)
|
||||
|
||||
defineExpose({
|
||||
async show(event) {
|
||||
if (event.event === 'InstallVersion') {
|
||||
version.value = await get_version(event.id, 'must_revalidate').catch(handleError)
|
||||
project.value = await get_project(version.value.project_id, 'must_revalidate').catch(
|
||||
project.value = await get_project_v3(version.value.project_id, 'must_revalidate').catch(
|
||||
handleError,
|
||||
)
|
||||
} else {
|
||||
project.value = await get_project(event.id, 'must_revalidate').catch(handleError)
|
||||
project.value = await get_project_v3(event.id, 'must_revalidate').catch(handleError)
|
||||
version.value = await get_version(
|
||||
project.value.versions[project.value.versions.length - 1],
|
||||
'must_revalidate',
|
||||
).catch(handleError)
|
||||
}
|
||||
categories.value = (await get_categories().catch(handleError)).filter(
|
||||
(cat) => project.value.categories.includes(cat.name) && cat.project_type === 'mod',
|
||||
)
|
||||
confirmModal.value.show()
|
||||
},
|
||||
})
|
||||
@@ -51,13 +46,22 @@ async function install() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="confirmModal" :header="`Install ${project?.title}`">
|
||||
<ModalWrapper ref="confirmModal" :header="`Install ${project?.name}`">
|
||||
<div class="modal-body">
|
||||
<SearchCard
|
||||
:project="project"
|
||||
<ProjectCard
|
||||
:title="project.name"
|
||||
:link="() => confirmModal.hide()"
|
||||
:icon-url="project.icon_url"
|
||||
:summary="project.summary"
|
||||
:tags="project.display_categories"
|
||||
:all-tags="project.categories"
|
||||
:downloads="project.downloads"
|
||||
:followers="project.follows"
|
||||
:date-updated="project.date_modified"
|
||||
:banner="project.featured_gallery ?? undefined"
|
||||
:color="project.color ?? undefined"
|
||||
layout="list"
|
||||
class="project-card"
|
||||
:categories="categories"
|
||||
@open="confirmModal.hide()"
|
||||
/>
|
||||
<div class="button-row">
|
||||
<div class="markdown-body">
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { onMounted, onUnmounted, ref } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const dismissed = ref(false)
|
||||
const availableUpdate = ref<{ version: string } | null>(null)
|
||||
|
||||
let checkInterval: ReturnType<typeof setInterval> | null = null
|
||||
|
||||
async function checkForUpdate() {
|
||||
try {
|
||||
const [response, currentVersion] = await Promise.all([
|
||||
fetch('https://launcher-files.modrinth.com/updates.json'),
|
||||
getVersion(),
|
||||
])
|
||||
const updates = await response.json()
|
||||
const latestVersion = updates?.version
|
||||
|
||||
if (latestVersion && latestVersion !== currentVersion) {
|
||||
if (latestVersion !== availableUpdate.value?.version) {
|
||||
availableUpdate.value = { version: latestVersion }
|
||||
dismissed.value = false
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to check for updates:', e)
|
||||
}
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
dismissed.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
checkForUpdate()
|
||||
checkInterval = setInterval(checkForUpdate, 5 * 60 * 1000)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (checkInterval) {
|
||||
clearInterval(checkInterval)
|
||||
}
|
||||
})
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.update-toast.title',
|
||||
defaultMessage: 'Update available',
|
||||
},
|
||||
body: {
|
||||
id: 'app.update-toast.body.linux',
|
||||
defaultMessage:
|
||||
'Modrinth App v{version} is available. Use your package manager to update for the latest features and fixes!',
|
||||
},
|
||||
download: {
|
||||
id: 'app.update-toast.download-page',
|
||||
defaultMessage: 'Download',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
v-if="availableUpdate && !dismissed"
|
||||
class="grid grid-cols-[min-content] fixed card-shadow rounded-2xl top-[--top-bar-height] mt-6 right-6 p-4 z-10 bg-bg-raised border-surface-5 border-solid border-[2px]"
|
||||
>
|
||||
<div class="flex min-w-[25rem] gap-4">
|
||||
<h2 class="whitespace-nowrap text-base text-contrast font-semibold m-0 grow">
|
||||
{{ formatMessage(messages.title) }}
|
||||
</h2>
|
||||
<ButtonStyled size="small" circular>
|
||||
<button v-tooltip="formatMessage(commonMessages.closeButton)" @click="dismiss">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<p class="text-sm mt-2 mb-0">
|
||||
{{ formatMessage(messages.body, { version: availableUpdate.version }) }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,130 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { DownloadIcon, ExternalIcon, RefreshCwIcon, SpinnerIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, commonMessages, defineMessages, ProgressBar, useVIntl } from '@modrinth/ui'
|
||||
import { formatBytes } from '@modrinth/utils'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { injectAppUpdateDownloadProgress } from '@/providers/download-progress.ts'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'close' | 'restart' | 'download'): void
|
||||
}>()
|
||||
|
||||
defineProps<{
|
||||
version: string
|
||||
size: number | null
|
||||
metered: boolean
|
||||
}>()
|
||||
|
||||
const downloading = ref(false)
|
||||
const { progress } = injectAppUpdateDownloadProgress()
|
||||
|
||||
function download() {
|
||||
emit('download')
|
||||
downloading.value = true
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
title: {
|
||||
id: 'app.update-toast.title',
|
||||
defaultMessage: 'Update available',
|
||||
},
|
||||
body: {
|
||||
id: 'app.update-toast.body',
|
||||
defaultMessage:
|
||||
'Modrinth App v{version} is ready to install! Reload to update now, or automatically when you close Modrinth App.',
|
||||
},
|
||||
reload: {
|
||||
id: 'app.update-toast.reload',
|
||||
defaultMessage: 'Reload',
|
||||
},
|
||||
download: {
|
||||
id: 'app.update-toast.download',
|
||||
defaultMessage: 'Download ({size})',
|
||||
},
|
||||
downloading: {
|
||||
id: 'app.update-toast.downloading',
|
||||
defaultMessage: 'Downloading...',
|
||||
},
|
||||
changelog: {
|
||||
id: 'app.update-toast.changelog',
|
||||
defaultMessage: 'Changelog',
|
||||
},
|
||||
meteredBody: {
|
||||
id: 'app.update-toast.body.metered',
|
||||
defaultMessage: `Modrinth App v{version} is available now! Since you're on a metered network, we didn't automatically download it.`,
|
||||
},
|
||||
downloadCompleteTitle: {
|
||||
id: 'app.update-toast.title.download-complete',
|
||||
defaultMessage: 'Download complete',
|
||||
},
|
||||
downloadedBody: {
|
||||
id: 'app.update-toast.body.download-complete',
|
||||
defaultMessage: `Modrinth App v{version} has finished downloading. Reload to update now, or automatically when you close Modrinth App.`,
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="grid grid-cols-[min-content] fixed card-shadow rounded-2xl top-[--top-bar-height] mt-6 right-6 p-4 z-10 bg-bg-raised border-surface-5 border-solid border-[2px]"
|
||||
:class="{
|
||||
'download-complete': progress === 1,
|
||||
}"
|
||||
>
|
||||
<div class="flex min-w-[25rem] gap-4">
|
||||
<h2 class="whitespace-nowrap text-base text-contrast font-semibold m-0 grow">
|
||||
{{
|
||||
formatMessage(metered && progress === 1 ? messages.downloadCompleteTitle : messages.title)
|
||||
}}
|
||||
</h2>
|
||||
<ButtonStyled size="small" circular>
|
||||
<button v-tooltip="formatMessage(commonMessages.closeButton)" @click="emit('close')">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<p class="text-sm mt-2 mb-0">
|
||||
{{
|
||||
formatMessage(
|
||||
metered
|
||||
? progress === 1
|
||||
? messages.downloadedBody
|
||||
: messages.meteredBody
|
||||
: messages.body,
|
||||
{ version },
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<p
|
||||
v-if="metered && progress < 1"
|
||||
class="text-sm text-secondary mt-2 mb-0 flex items-center gap-1"
|
||||
>
|
||||
<template v-if="progress > 0">
|
||||
<ProgressBar :progress="progress" class="max-w-[unset]" />
|
||||
</template>
|
||||
</p>
|
||||
<div class="flex gap-2 mt-4">
|
||||
<ButtonStyled color="brand">
|
||||
<button v-if="metered && progress < 1" :disabled="downloading" @click="download">
|
||||
<SpinnerIcon v-if="downloading" class="animate-spin" />
|
||||
<DownloadIcon v-else />
|
||||
{{
|
||||
formatMessage(downloading ? messages.downloading : messages.download, {
|
||||
size: formatBytes(size ?? 0),
|
||||
})
|
||||
}}
|
||||
</button>
|
||||
<button v-else @click="emit('restart')">
|
||||
<RefreshCwIcon /> {{ formatMessage(messages.reload) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<a href="https://modrinth.com/news/changelog?filter=app">
|
||||
{{ formatMessage(messages.changelog) }} <ExternalIcon />
|
||||
</a>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<section v-if="showControls" class="window-controls" data-tauri-drag-region-exclude>
|
||||
<ButtonStyled type="transparent" circular>
|
||||
<button class="titlebar-button" @click="() => getCurrentWindow().minimize()">
|
||||
<MinimizeIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled type="transparent" circular>
|
||||
<button class="titlebar-button" @click="() => getCurrentWindow().toggleMaximize()">
|
||||
<RestoreIcon v-if="isMaximized" />
|
||||
<MaximizeIcon v-else />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled type="transparent" circular>
|
||||
<button class="titlebar-button close" @click="handleClose">
|
||||
<XIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { MaximizeIcon, MinimizeIcon, RestoreIcon, XIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled } from '@modrinth/ui'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
|
||||
import { get as getSettings } from '@/helpers/settings.ts'
|
||||
import { getOS } from '@/helpers/utils.js'
|
||||
|
||||
const WINDOW_CONTROLS_WIDTH = '8rem'
|
||||
|
||||
const nativeDecorations = ref(true)
|
||||
const isMaximized = ref(false)
|
||||
const os = ref('')
|
||||
|
||||
const showControls = computed(() => !nativeDecorations.value && os.value !== 'MacOS')
|
||||
watch(
|
||||
showControls,
|
||||
(visible) => {
|
||||
if (typeof document === 'undefined') return
|
||||
if (visible) {
|
||||
document.documentElement.style.setProperty('--window-controls-width', WINDOW_CONTROLS_WIDTH)
|
||||
} else {
|
||||
document.documentElement.style.removeProperty('--window-controls-width')
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
os.value = await getOS()
|
||||
|
||||
const settings = await getSettings()
|
||||
nativeDecorations.value = settings.native_decorations
|
||||
|
||||
if (os.value !== 'MacOS') {
|
||||
await getCurrentWindow().setDecorations(nativeDecorations.value)
|
||||
}
|
||||
|
||||
isMaximized.value = await getCurrentWindow().isMaximized()
|
||||
|
||||
const unlisten = await getCurrentWindow().onResized(async () => {
|
||||
isMaximized.value = await getCurrentWindow().isMaximized()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
unlisten()
|
||||
document.documentElement.style.removeProperty('--window-controls-width')
|
||||
})
|
||||
})
|
||||
|
||||
const handleClose = async () => {
|
||||
await saveWindowState(StateFlags.ALL)
|
||||
await getCurrentWindow().close()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.window-controls {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 10001;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: var(--top-bar-height, 3rem);
|
||||
padding-right: 0.5rem;
|
||||
gap: 0.25rem;
|
||||
|
||||
.titlebar-button.close:hover {
|
||||
background-color: var(--color-red);
|
||||
color: var(--color-accent-contrast);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -288,7 +288,7 @@ const messages = defineMessages({
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<div v-if="userCredentials && !loading" class="flex gap-1 items-center mb-3 ml-2 mr-1">
|
||||
<div v-if="userCredentials && !loading" class="flex gap-1 items-center mb-3 -ml-1">
|
||||
<template v-if="sortedFriends.length > 0">
|
||||
<ButtonStyled circular type="transparent">
|
||||
<button
|
||||
@@ -309,7 +309,7 @@ const messages = defineMessages({
|
||||
@keyup.esc="search = ''"
|
||||
/>
|
||||
</template>
|
||||
<h3 v-else class="ml-2 w-full text-base text-primary font-medium m-0">
|
||||
<h3 v-else class="w-full text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.friends) }}
|
||||
</h3>
|
||||
<ButtonStyled v-if="incomingRequests.length > 0" circular type="transparent">
|
||||
@@ -331,11 +331,11 @@ const messages = defineMessages({
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<div class="flex flex-col gap-3">
|
||||
<h3 v-if="loading" class="ml-4 mr-1 text-base text-primary font-medium m-0">
|
||||
<h3 v-if="loading" class="text-base text-primary font-medium m-0">
|
||||
{{ formatMessage(messages.friends) }}
|
||||
</h3>
|
||||
<template v-if="loading">
|
||||
<div v-for="n in 5" :key="n" class="flex gap-2 items-center animate-pulse ml-4 mr-1">
|
||||
<div v-for="n in 5" :key="n" class="flex gap-2 items-center animate-pulse">
|
||||
<div class="min-w-9 min-h-9 bg-button-bg rounded-full"></div>
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="h-3 bg-button-bg rounded-full w-1/2 mb-1"></div>
|
||||
@@ -344,7 +344,7 @@ const messages = defineMessages({
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="sortedFriends.length === 0">
|
||||
<div class="text-sm ml-4 mr-1">
|
||||
<div class="text-sm">
|
||||
<div v-if="!userCredentials">
|
||||
<IntlFormatted :message-id="messages.signInToAddFriends">
|
||||
<template #link="{ children }">
|
||||
|
||||
@@ -106,7 +106,7 @@ const messages = defineMessages({
|
||||
:open-by-default="openByDefault"
|
||||
:force-open="isSearching"
|
||||
:button-class="
|
||||
'pl-4 pr-3 flex w-full items-center bg-transparent border-0 p-0' +
|
||||
'flex w-full items-center bg-transparent border-0 p-0' +
|
||||
(isSearching
|
||||
? ''
|
||||
: ' cursor-pointer hover:brightness-[--hover-brightness] active:scale-[0.98] transition-all')
|
||||
@@ -122,7 +122,7 @@ const messages = defineMessages({
|
||||
<div
|
||||
v-for="friend in friends"
|
||||
:key="friend.username"
|
||||
class="group grid items-center grid-cols-[auto_1fr_auto] gap-2 hover:bg-button-bg transition-colors rounded-full ml-4 mr-1"
|
||||
class="group grid items-center grid-cols-[auto_1fr_auto] gap-2 hover:bg-button-bg transition-colors rounded-full mr-1"
|
||||
@contextmenu.prevent.stop="
|
||||
(event) => friendOptions?.showMenu(event, friend, createContextMenuOptions(friend))
|
||||
"
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
<script setup>
|
||||
import { CheckIcon, PlusIcon, SearchIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
injectNotificationManager,
|
||||
StyledInput,
|
||||
} from '@modrinth/ui'
|
||||
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'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const modal = ref()
|
||||
const searchFilter = ref('')
|
||||
const profiles = ref([])
|
||||
|
||||
const serverName = ref('')
|
||||
const serverAddress = ref('')
|
||||
|
||||
const shownProfiles = computed(() =>
|
||||
profiles.value.filter((profile) => {
|
||||
return profile.name.toLowerCase().includes(searchFilter.value.toLowerCase())
|
||||
}),
|
||||
)
|
||||
|
||||
defineExpose({
|
||||
show: async (name, address) => {
|
||||
serverName.value = name
|
||||
serverAddress.value = address
|
||||
searchFilter.value = ''
|
||||
|
||||
const profilesVal = await list().catch(handleError)
|
||||
await Promise.allSettled(
|
||||
profilesVal.map(async (profile) => {
|
||||
profile.adding = false
|
||||
profile.added = false
|
||||
|
||||
try {
|
||||
const worlds = await get_profile_worlds(profile.path)
|
||||
profile.added = worlds.some(
|
||||
(w) => w.type === 'server' && w.address === serverAddress.value,
|
||||
)
|
||||
} catch {
|
||||
// Ignore - will show as not added
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
profiles.value = profilesVal
|
||||
modal.value.show()
|
||||
|
||||
trackEvent('AddServerToInstanceStart', { source: 'AddServerToInstanceModal' })
|
||||
},
|
||||
})
|
||||
|
||||
async function addServer(profile) {
|
||||
profile.adding = true
|
||||
try {
|
||||
await add_server_to_profile(profile.path, serverName.value, serverAddress.value, 'prompt')
|
||||
profile.added = true
|
||||
|
||||
trackEvent('AddServerToInstance', {
|
||||
server_name: serverName.value,
|
||||
instance_name: profile.name,
|
||||
source: 'AddServerToInstanceModal',
|
||||
})
|
||||
} catch (err) {
|
||||
handleError(err)
|
||||
}
|
||||
profile.adding = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="modal" header="Add server to instance">
|
||||
<div class="flex flex-col gap-4 min-w-[350px]">
|
||||
<Admonition type="warning" body="This server may not be compatible with all instances." />
|
||||
<StyledInput
|
||||
v-model="searchFilter"
|
||||
:icon="SearchIcon"
|
||||
type="search"
|
||||
placeholder="Search for an instance"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div class="max-h-[21rem] overflow-y-auto">
|
||||
<div
|
||||
v-for="profile in shownProfiles"
|
||||
:key="profile.path"
|
||||
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)}`"
|
||||
@click="modal.hide()"
|
||||
>
|
||||
<Avatar
|
||||
:src="profile.icon_path ? convertFileSrc(profile.icon_path) : null"
|
||||
class="mr-2 [--size:2rem]"
|
||||
/>
|
||||
{{ profile.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>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group push-right">
|
||||
<ButtonStyled>
|
||||
<button @click="modal.hide()">Cancel</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
@@ -17,31 +17,17 @@
|
||||
<tr class="content">
|
||||
<td class="data">{{ instance?.loader }} {{ instance?.game_version }}</td>
|
||||
<td>
|
||||
<multiselect
|
||||
<Combobox
|
||||
v-if="versions?.length > 1"
|
||||
v-model="selectedVersion"
|
||||
:options="versions"
|
||||
v-model="selectedVersionId"
|
||||
:options="versionOptions"
|
||||
:searchable="true"
|
||||
placeholder="Select version"
|
||||
open-direction="top"
|
||||
:show-labels="false"
|
||||
:custom-label="
|
||||
(version) =>
|
||||
`${version?.name} (${version?.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')} - ${version?.game_versions.join(', ')})`
|
||||
"
|
||||
force-direction="up"
|
||||
:max-height="150"
|
||||
/>
|
||||
<span v-else>
|
||||
<span>
|
||||
{{ selectedVersion?.name }} ({{
|
||||
selectedVersion?.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')
|
||||
}}
|
||||
- {{ selectedVersion?.game_versions.join(', ') }})
|
||||
</span>
|
||||
<span>{{ selectedVersionLabel }}</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -59,9 +45,8 @@
|
||||
|
||||
<script setup>
|
||||
import { DownloadIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, formatLoader, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
import Multiselect from 'vue-multiselect'
|
||||
import { Button, Combobox, formatLoader, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
@@ -79,11 +64,35 @@ const installing = ref(false)
|
||||
|
||||
const onInstall = ref(() => {})
|
||||
|
||||
const selectedVersionLabel = computed(() => {
|
||||
if (!selectedVersion.value) return ''
|
||||
return `${selectedVersion.value.name} (${selectedVersion.value.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')} - ${selectedVersion.value.game_versions.join(', ')})`
|
||||
})
|
||||
|
||||
const versionOptions = computed(() =>
|
||||
(versions.value ?? []).map((version) => ({
|
||||
value: version.id,
|
||||
label: `${version.name} (${version.loaders
|
||||
.map((name) => formatLoader(formatMessage, name))
|
||||
.join(', ')} - ${version.game_versions.join(', ')})`,
|
||||
})),
|
||||
)
|
||||
|
||||
const selectedVersionId = computed({
|
||||
get: () => selectedVersion.value?.id ?? null,
|
||||
set: (value) => {
|
||||
if (!value) return
|
||||
selectedVersion.value = (versions.value ?? []).find((version) => version.id === value) ?? null
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
show: (instanceVal, projectVal, projectVersions, selected, callback) => {
|
||||
instance.value = instanceVal
|
||||
versions.value = projectVersions
|
||||
selectedVersion.value = selected ?? projectVersions[0]
|
||||
versions.value = projectVersions ?? []
|
||||
selectedVersion.value = selected ?? projectVersions?.[0] ?? null
|
||||
|
||||
project.value = projectVal
|
||||
|
||||
@@ -162,9 +171,5 @@ td:first-child {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
:deep(.animated-dropdown .options) {
|
||||
max-height: 13.375rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
<script setup>
|
||||
import { DownloadIcon, XIcon } from '@modrinth/assets'
|
||||
import { Button, injectNotificationManager } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { create_profile_and_install as pack_install } from '@/helpers/pack'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
|
||||
const versionId = ref()
|
||||
const project = ref()
|
||||
const confirmModal = ref(null)
|
||||
const installing = ref(false)
|
||||
|
||||
const onInstall = ref(() => {})
|
||||
const onCreateInstance = ref(() => {})
|
||||
|
||||
defineExpose({
|
||||
show: (projectVal, versionIdVal, callback, createInstanceCallback) => {
|
||||
project.value = projectVal
|
||||
versionId.value = versionIdVal
|
||||
installing.value = false
|
||||
confirmModal.value.show()
|
||||
|
||||
onInstall.value = callback
|
||||
onCreateInstance.value = createInstanceCallback
|
||||
|
||||
trackEvent('PackInstallStart')
|
||||
},
|
||||
})
|
||||
|
||||
async function install() {
|
||||
installing.value = true
|
||||
confirmModal.value.hide()
|
||||
|
||||
await pack_install(
|
||||
project.value.id,
|
||||
versionId.value,
|
||||
project.value.title,
|
||||
project.value.icon_url,
|
||||
onCreateInstance.value,
|
||||
).catch(handleError)
|
||||
trackEvent('PackInstall', {
|
||||
id: project.value.id,
|
||||
version_id: versionId.value,
|
||||
title: project.value.title,
|
||||
source: 'ConfirmModal',
|
||||
})
|
||||
|
||||
onInstall.value(versionId.value)
|
||||
installing.value = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModalWrapper ref="confirmModal" header="Are you sure?" :on-hide="onInstall">
|
||||
<div class="modal-body">
|
||||
<p>You already have this modpack installed. Are you sure you want to install it again?</p>
|
||||
<div class="input-group push-right">
|
||||
<Button @click="() => $refs.confirmModal.hide()"><XIcon />Cancel</Button>
|
||||
<Button color="primary" :disabled="installing" @click="install()"
|
||||
><DownloadIcon /> {{ installing ? 'Installing' : 'Install' }}</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
@@ -16,6 +16,7 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_project_v3_many } from '@/helpers/cache.js'
|
||||
import {
|
||||
add_project_from_version as installMod,
|
||||
check_installed,
|
||||
@@ -81,6 +82,22 @@ defineExpose({
|
||||
handleError,
|
||||
)
|
||||
}
|
||||
|
||||
const linkedProjectIds = profilesVal
|
||||
.filter((p) => p.linked_data?.project_id)
|
||||
.map((p) => p.linked_data.project_id)
|
||||
if (linkedProjectIds.length > 0) {
|
||||
const linkedProjects = await get_project_v3_many(linkedProjectIds, 'must_revalidate').catch(
|
||||
() => [],
|
||||
)
|
||||
const serverProjectIds = new Set(
|
||||
linkedProjects.filter((p) => p?.minecraft_server != null).map((p) => p.id),
|
||||
)
|
||||
for (const profile of profilesVal) {
|
||||
profile.isServerInstance = serverProjectIds.has(profile.linked_data?.project_id)
|
||||
}
|
||||
}
|
||||
|
||||
profiles.value = profilesVal
|
||||
|
||||
installModal.value.show()
|
||||
|
||||
@@ -15,11 +15,12 @@ import { open } from '@tauri-apps/plugin-dialog'
|
||||
import { computed, type Ref, ref, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||
import ConfirmDeleteInstanceModal from '@/components/ui/modal/ConfirmDeleteInstanceModal.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { duplicate, edit, edit_icon, list, remove } from '@/helpers/profile'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { GameInstance, InstanceSettingsTabProps } from '../../../helpers/types'
|
||||
import type { GameInstance } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
@@ -27,21 +28,21 @@ const router = useRouter()
|
||||
|
||||
const deleteConfirmModal = ref()
|
||||
|
||||
const props = defineProps<InstanceSettingsTabProps>()
|
||||
const { instance } = injectInstanceSettings()
|
||||
|
||||
const title = ref(props.instance.name)
|
||||
const icon: Ref<string | undefined> = ref(props.instance.icon_path)
|
||||
const groups = ref(props.instance.groups)
|
||||
const title = ref(instance.value.name)
|
||||
const icon: Ref<string | undefined> = ref(instance.value.icon_path)
|
||||
const groups = ref([...instance.value.groups])
|
||||
|
||||
const newCategoryInput = ref('')
|
||||
|
||||
const installing = computed(() => props.instance.install_stage !== 'installed')
|
||||
const installing = computed(() => instance.value.install_stage !== 'installed')
|
||||
|
||||
async function duplicateProfile() {
|
||||
await duplicate(props.instance.path).catch(handleError)
|
||||
await duplicate(instance.value.path).catch(handleError)
|
||||
trackEvent('InstanceDuplicate', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ const availableGroups = computed(() => [
|
||||
|
||||
async function resetIcon() {
|
||||
icon.value = undefined
|
||||
await edit_icon(props.instance.path, null).catch(handleError)
|
||||
await edit_icon(instance.value.path, null).catch(handleError)
|
||||
trackEvent('InstanceRemoveIcon')
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ async function setIcon() {
|
||||
if (!value) return
|
||||
|
||||
icon.value = value
|
||||
await edit_icon(props.instance.path, icon.value).catch(handleError)
|
||||
await edit_icon(instance.value.path, icon.value).catch(handleError)
|
||||
|
||||
trackEvent('InstanceSetIcon')
|
||||
}
|
||||
@@ -100,7 +101,8 @@ const addCategory = () => {
|
||||
watch(
|
||||
[title, groups, groups],
|
||||
async () => {
|
||||
await edit(props.instance.path, editProfileObject.value)
|
||||
if (removing.value) return
|
||||
await edit(instance.value.path, editProfileObject.value).catch(handleError)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
@@ -108,15 +110,15 @@ watch(
|
||||
const removing = ref(false)
|
||||
async function removeProfile() {
|
||||
removing.value = true
|
||||
await remove(props.instance.path).catch(handleError)
|
||||
removing.value = false
|
||||
const path = instance.value.path
|
||||
|
||||
trackEvent('InstanceRemove', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
|
||||
await router.push({ path: '/' })
|
||||
await remove(path).catch(handleError)
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -194,55 +196,50 @@ const messages = defineMessages({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmModalWrapper
|
||||
ref="deleteConfirmModal"
|
||||
title="Are you sure you want to delete this instance?"
|
||||
description="If you proceed, all data for your instance will be permanently erased, including your worlds. You will not be able to recover it."
|
||||
:has-to-type="false"
|
||||
proceed-label="Delete"
|
||||
:show-ad-on-close="false"
|
||||
@proceed="removeProfile"
|
||||
/>
|
||||
<ConfirmDeleteInstanceModal ref="deleteConfirmModal" @delete="removeProfile" />
|
||||
<div class="block">
|
||||
<div class="float-end ml-4 relative group">
|
||||
<OverflowMenu
|
||||
v-tooltip="formatMessage(messages.editIcon)"
|
||||
class="bg-transparent border-none appearance-none p-0 m-0 cursor-pointer group-active:scale-95 transition-transform"
|
||||
:options="[
|
||||
{
|
||||
id: 'select',
|
||||
action: () => setIcon(),
|
||||
},
|
||||
{
|
||||
id: 'remove',
|
||||
color: 'danger',
|
||||
action: () => resetIcon(),
|
||||
shown: !!icon,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<Avatar
|
||||
:src="icon ? convertFileSrc(icon) : icon"
|
||||
size="108px"
|
||||
class="!border-4 group-hover:brightness-75"
|
||||
:tint-by="props.instance.path"
|
||||
no-shadow
|
||||
/>
|
||||
<div class="absolute top-0 right-0 m-2">
|
||||
<div
|
||||
class="p-2 m-0 text-primary flex items-center justify-center aspect-square bg-button-bg rounded-full border-button-border border-solid border-[1px] hovering-icon-shadow"
|
||||
<div class="float-end ml-10 relative group w-fit">
|
||||
<div class="flex flex-col gap-1">
|
||||
<span class="text-lg font-semibold text-contrast">Icon</span>
|
||||
<div class="group relative w-fit">
|
||||
<OverflowMenu
|
||||
v-tooltip="formatMessage(messages.editIcon)"
|
||||
class="bg-transparent border-none appearance-none p-0 m-0 cursor-pointer group-active:scale-95 transition-transform"
|
||||
:options="[
|
||||
{
|
||||
id: 'select',
|
||||
action: () => setIcon(),
|
||||
},
|
||||
{
|
||||
id: 'remove',
|
||||
color: 'danger',
|
||||
action: () => resetIcon(),
|
||||
shown: !!icon,
|
||||
},
|
||||
]"
|
||||
>
|
||||
<EditIcon aria-hidden="true" class="h-4 w-4 text-primary" />
|
||||
</div>
|
||||
<Avatar
|
||||
:src="icon ? convertFileSrc(icon) : icon"
|
||||
size="108px"
|
||||
class="transition-[filter] group-hover:brightness-75"
|
||||
:tint-by="instance.path"
|
||||
no-shadow
|
||||
/>
|
||||
<div
|
||||
class="absolute top-0 h-full w-full flex items-center justify-center opacity-0 transition-all group-hover:opacity-100"
|
||||
>
|
||||
<EditIcon aria-hidden="true" class="h-10 w-10 text-primary" />
|
||||
</div>
|
||||
<template #select>
|
||||
<UploadIcon />
|
||||
{{ icon ? formatMessage(messages.replaceIcon) : formatMessage(messages.selectIcon) }}
|
||||
</template>
|
||||
<template #remove> <TrashIcon /> {{ formatMessage(messages.removeIcon) }} </template>
|
||||
</OverflowMenu>
|
||||
</div>
|
||||
<template #select>
|
||||
<UploadIcon />
|
||||
{{ icon ? formatMessage(messages.replaceIcon) : formatMessage(messages.selectIcon) }}
|
||||
</template>
|
||||
<template #remove> <TrashIcon /> {{ formatMessage(messages.removeIcon) }} </template>
|
||||
</OverflowMenu>
|
||||
</div>
|
||||
</div>
|
||||
<label for="instance-name" class="m-0 mb-1 text-lg font-extrabold text-contrast block">
|
||||
<label for="instance-name" class="m-0 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.name) }}
|
||||
</label>
|
||||
<div class="flex">
|
||||
@@ -255,76 +252,82 @@ const messages = defineMessages({
|
||||
/>
|
||||
</div>
|
||||
<template v-if="instance.install_stage == 'installed'">
|
||||
<div>
|
||||
<h2
|
||||
id="duplicate-instance-label"
|
||||
class="m-0 mt-4 mb-1 text-lg font-extrabold text-contrast block"
|
||||
>
|
||||
<div class="flex flex-col gap-2.5 mt-6">
|
||||
<h2 id="duplicate-instance-label" class="m-0 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.duplicateInstance) }}
|
||||
</h2>
|
||||
<p class="m-0 mb-2">
|
||||
<ButtonStyled>
|
||||
<button
|
||||
v-tooltip="installing ? formatMessage(messages.duplicateButtonTooltipInstalling) : null"
|
||||
aria-labelledby="duplicate-instance-label"
|
||||
:disabled="installing"
|
||||
class="w-max !shadow-none"
|
||||
@click="duplicateProfile"
|
||||
>
|
||||
<CopyIcon /> {{ formatMessage(messages.duplicateButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.duplicateInstanceDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<ButtonStyled>
|
||||
</template>
|
||||
<div class="flex flex-col gap-2.5 mt-6">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.libraryGroups) }}
|
||||
</h2>
|
||||
|
||||
<div class="flex flex-col gap-1">
|
||||
<Checkbox
|
||||
v-for="group in availableGroups"
|
||||
:key="group"
|
||||
:model-value="groups.includes(group)"
|
||||
:label="group"
|
||||
@click="toggleGroup(group)"
|
||||
/>
|
||||
<div class="flex gap-2 items-center">
|
||||
<StyledInput
|
||||
v-model="newCategoryInput"
|
||||
:placeholder="formatMessage(messages.libraryGroupsEnterName)"
|
||||
class="w-full max-w-[300px]"
|
||||
@submit="() => addCategory"
|
||||
/>
|
||||
<ButtonStyled>
|
||||
<button class="w-fit !shadow-none" @click="() => addCategory()">
|
||||
<PlusIcon /> {{ formatMessage(messages.libraryGroupsCreate) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.libraryGroupsDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2.5 mt-6">
|
||||
<h2 id="delete-instance-label" class="m-0 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.deleteInstance) }}
|
||||
</h2>
|
||||
<ButtonStyled color="red">
|
||||
<button
|
||||
v-tooltip="installing ? formatMessage(messages.duplicateButtonTooltipInstalling) : null"
|
||||
aria-labelledby="duplicate-instance-label"
|
||||
:disabled="installing"
|
||||
@click="duplicateProfile"
|
||||
aria-labelledby="delete-instance-label"
|
||||
:disabled="removing"
|
||||
class="w-fit !shadow-none"
|
||||
@click="deleteConfirmModal.show()"
|
||||
>
|
||||
<CopyIcon /> {{ formatMessage(messages.duplicateButton) }}
|
||||
<SpinnerIcon v-if="removing" class="animate-spin" />
|
||||
<TrashIcon v-else />
|
||||
{{
|
||||
removing
|
||||
? formatMessage(messages.deletingInstanceButton)
|
||||
: formatMessage(messages.deleteInstanceButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
<h2 class="m-0 mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.libraryGroups) }}
|
||||
</h2>
|
||||
<p class="m-0 mb-2">
|
||||
{{ formatMessage(messages.libraryGroupsDescription) }}
|
||||
</p>
|
||||
<div class="flex flex-col gap-1">
|
||||
<Checkbox
|
||||
v-for="group in availableGroups"
|
||||
:key="group"
|
||||
:model-value="groups.includes(group)"
|
||||
:label="group"
|
||||
@click="toggleGroup(group)"
|
||||
/>
|
||||
<div class="flex gap-2 items-center">
|
||||
<StyledInput
|
||||
v-model="newCategoryInput"
|
||||
:placeholder="formatMessage(messages.libraryGroupsEnterName)"
|
||||
@submit="() => addCategory"
|
||||
/>
|
||||
<ButtonStyled>
|
||||
<button class="w-fit" @click="() => addCategory()">
|
||||
<PlusIcon /> {{ formatMessage(messages.libraryGroupsCreate) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.deleteInstanceDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<h2 id="delete-instance-label" class="m-0 mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.deleteInstance) }}
|
||||
</h2>
|
||||
<p class="m-0 mb-2">
|
||||
{{ formatMessage(messages.deleteInstanceDescription) }}
|
||||
</p>
|
||||
<ButtonStyled color="red">
|
||||
<button
|
||||
aria-labelledby="delete-instance-label"
|
||||
:disabled="removing"
|
||||
@click="deleteConfirmModal.show()"
|
||||
>
|
||||
<SpinnerIcon v-if="removing" class="animate-spin" />
|
||||
<TrashIcon v-else />
|
||||
{{
|
||||
removing
|
||||
? formatMessage(messages.deletingInstanceButton)
|
||||
: formatMessage(messages.deleteInstanceButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -10,22 +10,23 @@ import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { AppSettings, Hooks, InstanceSettingsTabProps } from '../../../helpers/types'
|
||||
import type { AppSettings, Hooks } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<InstanceSettingsTabProps>()
|
||||
const { instance } = injectInstanceSettings()
|
||||
|
||||
const globalSettings = (await get().catch(handleError)) as AppSettings
|
||||
|
||||
const overrideHooks = ref(
|
||||
!!props.instance.hooks.pre_launch ||
|
||||
!!props.instance.hooks.wrapper ||
|
||||
!!props.instance.hooks.post_exit,
|
||||
!!instance.value.hooks.pre_launch ||
|
||||
!!instance.value.hooks.wrapper ||
|
||||
!!instance.value.hooks.post_exit,
|
||||
)
|
||||
const hooks = ref(props.instance.hooks ?? globalSettings.hooks)
|
||||
const hooks = ref(instance.value.hooks ?? globalSettings.hooks)
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
const editProfile: {
|
||||
@@ -41,7 +42,7 @@ const editProfileObject = computed(() => {
|
||||
watch(
|
||||
[overrideHooks, hooks],
|
||||
async () => {
|
||||
await edit(props.instance.path, editProfileObject.value)
|
||||
await edit(instance.value.path, editProfileObject.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
@@ -100,57 +101,57 @@ const messages = defineMessages({
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="m-0 mb-1 text-lg font-extrabold text-contrast">
|
||||
<h2 class="m-0 m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.hooks) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideHooks" :label="formatMessage(messages.customHooks)" class="my-2.5" />
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.hooksDescription) }}
|
||||
</p>
|
||||
<Checkbox v-model="overrideHooks" :label="formatMessage(messages.customHooks)" class="mt-2" />
|
||||
|
||||
<h2 class="mt-2 mb-1 text-lg font-extrabold text-contrast">
|
||||
<h2 class="mt-6 m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.preLaunch) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.preLaunchDescription) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
id="pre-launch"
|
||||
v-model="hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
:placeholder="formatMessage(messages.preLaunchEnter)"
|
||||
wrapper-class="w-full mt-2"
|
||||
wrapper-class="w-full my-2.5"
|
||||
/>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.preLaunchDescription) }}
|
||||
</p>
|
||||
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast">
|
||||
<h2 class="mt-6 m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.wrapper) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.wrapperDescription) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
id="wrapper"
|
||||
v-model="hooks.wrapper"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
:placeholder="formatMessage(messages.wrapperEnter)"
|
||||
wrapper-class="w-full mt-2"
|
||||
wrapper-class="w-full my-2.5"
|
||||
/>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.wrapperDescription) }}
|
||||
</p>
|
||||
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast">
|
||||
<h2 class="mt-6 m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.postExit) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.postExitDescription) }}
|
||||
</p>
|
||||
<StyledInput
|
||||
id="post-exit"
|
||||
v-model="hooks.post_exit"
|
||||
autocomplete="off"
|
||||
:disabled="!overrideHooks"
|
||||
:placeholder="formatMessage(messages.postExitEnter)"
|
||||
wrapper-class="w-full mt-2"
|
||||
wrapper-class="w-full my-2.5"
|
||||
/>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.postExitDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,59 +1,41 @@
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
DownloadIcon,
|
||||
getLoaderIcon,
|
||||
HammerIcon,
|
||||
IssuesIcon,
|
||||
SpinnerIcon,
|
||||
TransferIcon,
|
||||
UndoIcon,
|
||||
UnlinkIcon,
|
||||
UnplugIcon,
|
||||
WrenchIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
Chips,
|
||||
Combobox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatLoader,
|
||||
formatLoaderLabel,
|
||||
injectNotificationManager,
|
||||
InstallationSettingsLayout,
|
||||
provideAppBackup,
|
||||
provideInstallationSettings,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { GameVersionTag, PlatformTag, Project, Version } from '@modrinth/utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, type ComputedRef, type Ref, ref, shallowRef, watch } from 'vue'
|
||||
import type { GameVersionTag, PlatformTag } from '@modrinth/utils'
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { computed, ref, shallowRef } from 'vue'
|
||||
|
||||
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
|
||||
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
|
||||
import { trackEvent } from '@/helpers/analytics'
|
||||
import { get_project, get_version_many } from '@/helpers/cache'
|
||||
import { get_project_versions, get_version } from '@/helpers/cache'
|
||||
import { get_loader_versions } from '@/helpers/metadata'
|
||||
import { edit, install, update_repair_modrinth } from '@/helpers/profile'
|
||||
import {
|
||||
duplicate,
|
||||
edit,
|
||||
get_linked_modpack_info,
|
||||
install,
|
||||
list,
|
||||
update_managed_modrinth_version,
|
||||
update_repair_modrinth,
|
||||
} from '@/helpers/profile'
|
||||
import { get_game_versions, get_loaders } from '@/helpers/tags'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type {
|
||||
InstanceSettingsTabProps,
|
||||
Manifest,
|
||||
ManifestLoaderVersion,
|
||||
} from '../../../helpers/types'
|
||||
import type { Manifest } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const repairConfirmModal = ref()
|
||||
const modpackVersionModal = ref()
|
||||
const modalConfirmUnpair = ref()
|
||||
const modalConfirmReinstall = ref()
|
||||
|
||||
const props = defineProps<InstanceSettingsTabProps>()
|
||||
|
||||
const loader = ref(props.instance.loader)
|
||||
const gameVersion = ref(props.instance.game_version)
|
||||
|
||||
const showSnapshots = ref(false)
|
||||
const { instance, offline, isMinecraftServer, onUnlinked } = injectInstanceSettings()
|
||||
|
||||
const [
|
||||
fabric_versions,
|
||||
@@ -90,730 +72,211 @@ const [
|
||||
.catch(handleError),
|
||||
])
|
||||
|
||||
const modpackProject: Ref<Project | null> = ref(null)
|
||||
const modpackVersion: Ref<Version | null> = ref(null)
|
||||
const modpackVersions: Ref<Version[] | null> = ref(null)
|
||||
const fetching = ref(true)
|
||||
|
||||
if (props.instance.linked_data && props.instance.linked_data.project_id && !props.offline) {
|
||||
get_project(props.instance.linked_data.project_id, 'must_revalidate')
|
||||
.then((project) => {
|
||||
modpackProject.value = project
|
||||
|
||||
if (project && project.versions) {
|
||||
get_version_many(project.versions, 'must_revalidate')
|
||||
.then((versions: Version[]) => {
|
||||
modpackVersions.value = versions.sort((a, b) =>
|
||||
dayjs(b.date_published).diff(dayjs(a.date_published)),
|
||||
)
|
||||
modpackVersion.value =
|
||||
versions.find(
|
||||
(version: Version) => version.id === props.instance.linked_data?.version_id,
|
||||
) ?? null
|
||||
})
|
||||
.catch(handleError)
|
||||
.finally(() => {
|
||||
fetching.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
handleError(err)
|
||||
fetching.value = false
|
||||
})
|
||||
} else {
|
||||
fetching.value = false
|
||||
}
|
||||
|
||||
const currentLoaderIcon = computed(() => getLoaderIcon(props.instance.loader))
|
||||
|
||||
const gameVersionsForLoader = computed(() => {
|
||||
return all_game_versions?.value.filter((item) => {
|
||||
if (loader.value === 'fabric') {
|
||||
return !!fabric_versions?.value.gameVersions.some((x) => item.version === x.id)
|
||||
} else if (loader.value === 'forge') {
|
||||
return !!forge_versions?.value.gameVersions.some((x) => item.version === x.id)
|
||||
} else if (loader.value === 'quilt') {
|
||||
return !!quilt_versions?.value.gameVersions.some((x) => item.version === x.id)
|
||||
} else if (loader.value === 'neoforge') {
|
||||
return !!neoforge_versions?.value.gameVersions.some((x) => item.version === x.id)
|
||||
}
|
||||
|
||||
return []
|
||||
})
|
||||
const { data: modpackInfo } = 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),
|
||||
})
|
||||
|
||||
const hasSnapshots = computed(() =>
|
||||
gameVersionsForLoader.value?.some((x) => x.version_type !== 'release'),
|
||||
)
|
||||
|
||||
const selectableGameVersionNumbers = computed(() => {
|
||||
return gameVersionsForLoader.value
|
||||
?.filter((x) => x.version_type === 'release' || showSnapshots.value)
|
||||
.map((x) => x.version)
|
||||
})
|
||||
|
||||
const gameVersionOptions = computed(() =>
|
||||
(selectableGameVersionNumbers.value ?? []).map((v) => ({ value: v, label: v })),
|
||||
)
|
||||
|
||||
const loaderVersionOptions = computed(() =>
|
||||
(selectableLoaderVersions.value ?? []).map((opt, index) => ({ value: index, label: opt.id })),
|
||||
)
|
||||
|
||||
const loaderVersionLabel = computed(() => {
|
||||
const idx = loaderVersionIndex.value
|
||||
return idx >= 0 && selectableLoaderVersions.value
|
||||
? selectableLoaderVersions.value[idx]?.id
|
||||
: 'Select version'
|
||||
})
|
||||
|
||||
const selectableLoaderVersions: ComputedRef<ManifestLoaderVersion[] | undefined> = computed(() => {
|
||||
if (gameVersion.value) {
|
||||
if (loader.value === 'fabric') {
|
||||
return fabric_versions?.value.gameVersions[0].loaders
|
||||
} else if (loader.value === 'forge') {
|
||||
return forge_versions?.value?.gameVersions?.find((item) => item.id === gameVersion.value)
|
||||
?.loaders
|
||||
} else if (loader.value === 'quilt') {
|
||||
return quilt_versions?.value.gameVersions[0].loaders
|
||||
} else if (loader.value === 'neoforge') {
|
||||
return neoforge_versions?.value?.gameVersions?.find((item) => item.id === gameVersion.value)
|
||||
?.loaders
|
||||
}
|
||||
}
|
||||
return []
|
||||
})
|
||||
const loaderVersionIndex: Ref<number> = ref(-1)
|
||||
|
||||
resetLoaderVersionIndex()
|
||||
|
||||
function resetLoaderVersionIndex() {
|
||||
loaderVersionIndex.value =
|
||||
selectableLoaderVersions.value?.findIndex((x) => x.id === props.instance.loader_version) ?? -1
|
||||
}
|
||||
|
||||
const isValid = computed(() => {
|
||||
return (
|
||||
selectableGameVersionNumbers.value?.includes(gameVersion.value) &&
|
||||
((loaderVersionIndex.value !== undefined && loaderVersionIndex.value >= 0) ||
|
||||
loader.value === 'vanilla')
|
||||
)
|
||||
})
|
||||
|
||||
const isChanged = computed(() => {
|
||||
return (
|
||||
loader.value !== props.instance.loader ||
|
||||
gameVersion.value !== props.instance.game_version ||
|
||||
(loader.value !== 'vanilla' &&
|
||||
loaderVersionIndex.value !== undefined &&
|
||||
loaderVersionIndex.value >= 0 &&
|
||||
selectableLoaderVersions.value?.[loaderVersionIndex.value].id !==
|
||||
props.instance.loader_version)
|
||||
)
|
||||
})
|
||||
|
||||
watch(loader, () => {
|
||||
loaderVersionIndex.value = 0
|
||||
})
|
||||
|
||||
const editing = ref(false)
|
||||
|
||||
async function saveGvLoaderEdits() {
|
||||
editing.value = true
|
||||
|
||||
const editProfile: { loader?: string; game_version?: string; loader_version?: string } = {}
|
||||
editProfile.loader = loader.value
|
||||
editProfile.game_version = gameVersion.value
|
||||
|
||||
if (loader.value !== 'vanilla' && loaderVersionIndex.value !== undefined) {
|
||||
editProfile.loader_version = selectableLoaderVersions.value?.[loaderVersionIndex.value].id
|
||||
} else {
|
||||
loaderVersionIndex.value = -1
|
||||
}
|
||||
console.log('Editing:')
|
||||
console.log(loader.value)
|
||||
|
||||
await edit(props.instance.path, editProfile).catch(handleError)
|
||||
await repairProfile(false)
|
||||
|
||||
editing.value = false
|
||||
}
|
||||
|
||||
const installing = computed(() => props.instance.install_stage !== 'installed')
|
||||
const repairing = ref(false)
|
||||
const reinstalling = ref(false)
|
||||
const changingVersion = ref(false)
|
||||
|
||||
async function repairProfile(force: boolean) {
|
||||
if (force) {
|
||||
repairing.value = true
|
||||
}
|
||||
await install(props.instance.path, force).catch(handleError)
|
||||
if (force) {
|
||||
repairing.value = false
|
||||
}
|
||||
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
})
|
||||
}
|
||||
|
||||
async function unpairProfile() {
|
||||
await edit(props.instance.path, {
|
||||
linked_data: null,
|
||||
})
|
||||
modpackProject.value = null
|
||||
modpackVersion.value = null
|
||||
modpackVersions.value = null
|
||||
modalConfirmUnpair.value.hide()
|
||||
}
|
||||
|
||||
async function repairModpack() {
|
||||
reinstalling.value = true
|
||||
await update_repair_modrinth(props.instance.path).catch(handleError)
|
||||
reinstalling.value = false
|
||||
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
})
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
cannotWhileInstalling: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.cannot-while-installing',
|
||||
defaultMessage: 'Cannot {action} while installing',
|
||||
},
|
||||
cannotWhileOffline: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.cannot-while-offline',
|
||||
defaultMessage: 'Cannot {action} while offline',
|
||||
},
|
||||
cannotWhileRepairing: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.cannot-while-repairing',
|
||||
defaultMessage: 'Cannot {action} while repairing',
|
||||
},
|
||||
currentlyInstalled: {
|
||||
id: 'instance.settings.tabs.installation.currently-installed',
|
||||
defaultMessage: 'Currently installed',
|
||||
},
|
||||
platform: {
|
||||
id: 'instance.settings.tabs.installation.platform',
|
||||
defaultMessage: 'Platform',
|
||||
},
|
||||
gameVersion: {
|
||||
id: 'instance.settings.tabs.installation.game-version',
|
||||
defaultMessage: 'Game version',
|
||||
},
|
||||
loaderVersion: {
|
||||
id: 'instance.settings.tabs.installation.loader-version',
|
||||
defaultMessage: '{loader} version',
|
||||
},
|
||||
showAllVersions: {
|
||||
id: 'instance.settings.tabs.installation.show-all-versions',
|
||||
defaultMessage: 'Show all versions',
|
||||
})
|
||||
|
||||
function getManifest(loader: string) {
|
||||
const map: Record<string, typeof fabric_versions> = {
|
||||
fabric: fabric_versions,
|
||||
forge: forge_versions,
|
||||
quilt: quilt_versions,
|
||||
neoforge: neoforge_versions,
|
||||
}
|
||||
return map[loader]
|
||||
}
|
||||
|
||||
provideAppBackup({
|
||||
async createBackup() {
|
||||
const allProfiles = await list()
|
||||
const prefix = `${instance.value.name} - Backup #`
|
||||
const existingNums = allProfiles
|
||||
.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}` })
|
||||
},
|
||||
install: {
|
||||
id: 'instance.settings.tabs.installation.install',
|
||||
defaultMessage: 'Install',
|
||||
})
|
||||
|
||||
provideInstallationSettings({
|
||||
loading: ref(false),
|
||||
installationInfo: computed(() => {
|
||||
const rows = [
|
||||
{
|
||||
label: formatMessage(commonMessages.platformLabel),
|
||||
value: formatLoaderLabel(instance.value.loader),
|
||||
},
|
||||
{
|
||||
label: formatMessage(commonMessages.gameVersionLabel),
|
||||
value: instance.value.game_version,
|
||||
},
|
||||
]
|
||||
if (instance.value.loader !== 'vanilla' && instance.value.loader_version) {
|
||||
rows.push({
|
||||
label: formatMessage(messages.loaderVersion, {
|
||||
loader: formatLoaderLabel(instance.value.loader),
|
||||
}),
|
||||
value: instance.value.loader_version,
|
||||
})
|
||||
}
|
||||
return rows
|
||||
}),
|
||||
isLinked: computed(() => !!instance.value.linked_data?.locked),
|
||||
isBusy: computed(
|
||||
() =>
|
||||
instance.value.install_stage !== 'installed' ||
|
||||
repairing.value ||
|
||||
reinstalling.value ||
|
||||
!!offline,
|
||||
),
|
||||
modpack: computed(() => {
|
||||
if (!modpackInfo.value) return null
|
||||
return {
|
||||
iconUrl: modpackInfo.value.project.icon_url,
|
||||
title: modpackInfo.value.project.title,
|
||||
link: `/project/${modpackInfo.value.project.slug ?? modpackInfo.value.project.id}`,
|
||||
versionNumber: modpackInfo.value.version?.version_number,
|
||||
}
|
||||
}),
|
||||
currentPlatform: computed(() => instance.value.loader),
|
||||
currentGameVersion: computed(() => instance.value.game_version),
|
||||
currentLoaderVersion: computed(() => instance.value.loader_version ?? ''),
|
||||
availablePlatforms: loaders?.value?.map((x) => x.name) ?? [],
|
||||
|
||||
resolveGameVersions(loader, showSnapshots) {
|
||||
const versions = all_game_versions?.value ?? []
|
||||
const filtered = versions.filter((item) => {
|
||||
if (loader === 'vanilla') return true
|
||||
const manifest = getManifest(loader)
|
||||
return !!manifest?.value?.gameVersions?.some((x) => item.version === x.id)
|
||||
})
|
||||
return (showSnapshots ? filtered : filtered.filter((x) => x.version_type === 'release')).map(
|
||||
(x) => ({ value: x.version, label: x.version }),
|
||||
)
|
||||
},
|
||||
resetSelections: {
|
||||
id: 'instance.settings.tabs.installation.reset-selections',
|
||||
defaultMessage: 'Reset to current',
|
||||
|
||||
resolveLoaderVersions(loader, gameVersion) {
|
||||
if (loader === 'vanilla' || !gameVersion) return []
|
||||
const manifest = getManifest(loader)
|
||||
if (!manifest?.value) return []
|
||||
if (loader === 'fabric' || loader === 'quilt') {
|
||||
return manifest.value.gameVersions[0]?.loaders ?? []
|
||||
}
|
||||
return manifest.value.gameVersions?.find((item) => item.id === gameVersion)?.loaders ?? []
|
||||
},
|
||||
unknownVersion: {
|
||||
id: 'instance.settings.tabs.installation.unknown-version',
|
||||
defaultMessage: '(unknown version)',
|
||||
|
||||
resolveHasSnapshots(loader) {
|
||||
const versions = all_game_versions?.value ?? []
|
||||
if (loader === 'vanilla') return versions.some((x) => x.version_type !== 'release')
|
||||
const manifest = getManifest(loader)
|
||||
const supported = versions.filter(
|
||||
(item) => !!manifest?.value?.gameVersions?.some((x) => item.version === x.id),
|
||||
)
|
||||
return supported.some((x) => x.version_type !== 'release')
|
||||
},
|
||||
repairConfirmTitle: {
|
||||
id: 'instance.settings.tabs.installation.repair.confirm.title',
|
||||
defaultMessage: 'Repair instance?',
|
||||
|
||||
async save(platform, gameVersion, loaderVersionId) {
|
||||
const editProfile: Record<string, string | undefined> = {
|
||||
loader: platform,
|
||||
game_version: gameVersion,
|
||||
}
|
||||
if (platform !== 'vanilla' && loaderVersionId) {
|
||||
editProfile.loader_version = loaderVersionId
|
||||
}
|
||||
await edit(instance.value.path, editProfile).catch(handleError)
|
||||
},
|
||||
repairConfirmDescription: {
|
||||
id: 'instance.settings.tabs.installation.repair.confirm.description',
|
||||
defaultMessage:
|
||||
'Repairing reinstalls Minecraft dependencies and checks for corruption. This may resolve issues if your game is not launching due to launcher-related errors, but will not resolve issues or crashes related to installed mods.',
|
||||
|
||||
afterSave: async () => {
|
||||
await install(instance.value.path, false).catch(handleError)
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
},
|
||||
repairButton: {
|
||||
id: 'instance.settings.tabs.installation.repair.button',
|
||||
defaultMessage: 'Repair',
|
||||
|
||||
async repair() {
|
||||
repairing.value = true
|
||||
await install(instance.value.path, true).catch(handleError)
|
||||
repairing.value = false
|
||||
trackEvent('InstanceRepair', {
|
||||
loader: instance.value.loader,
|
||||
game_version: instance.value.game_version,
|
||||
})
|
||||
},
|
||||
repairingButton: {
|
||||
id: 'instance.settings.tabs.installation.repair.button.repairing',
|
||||
defaultMessage: 'Repairing',
|
||||
|
||||
async reinstallModpack() {
|
||||
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,
|
||||
})
|
||||
},
|
||||
repairInProgress: {
|
||||
id: 'instance.settings.tabs.installation.repair.in-progress',
|
||||
defaultMessage: 'Repair in progress',
|
||||
|
||||
async unlinkModpack() {
|
||||
await edit(instance.value.path, {
|
||||
linked_data: null as unknown as undefined,
|
||||
})
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['linkedModpackInfo', instance.value.path],
|
||||
})
|
||||
onUnlinked()
|
||||
},
|
||||
repairAction: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.action.repair',
|
||||
defaultMessage: 'repair',
|
||||
|
||||
getCachedModpackVersions: () => null,
|
||||
async fetchModpackVersions() {
|
||||
const versions = await get_project_versions(instance.value.linked_data!.project_id!).catch(
|
||||
handleError,
|
||||
)
|
||||
return (versions ?? []) as Labrinth.Versions.v2.Version[]
|
||||
},
|
||||
changeVersionCannotWhileFetching: {
|
||||
id: 'instance.settings.tabs.installation.change-version.cannot-while-fetching',
|
||||
defaultMessage: 'Fetching modpack versions',
|
||||
|
||||
async getVersionChangelog(versionId: string) {
|
||||
return (await get_version(versionId, 'must_revalidate').catch(
|
||||
() => null,
|
||||
)) as Labrinth.Versions.v2.Version | null
|
||||
},
|
||||
changeVersionButton: {
|
||||
id: 'instance.settings.tabs.installation.change-version.button',
|
||||
defaultMessage: 'Change version',
|
||||
},
|
||||
changeVersionAction: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.action.change-version',
|
||||
defaultMessage: 'change version',
|
||||
},
|
||||
installingButton: {
|
||||
id: 'instance.settings.tabs.installation.change-version.button.installing',
|
||||
defaultMessage: 'Installing',
|
||||
},
|
||||
installInProgress: {
|
||||
id: 'instance.settings.tabs.installation.install.in-progress',
|
||||
defaultMessage: 'Installation in progress',
|
||||
},
|
||||
installButton: {
|
||||
id: 'instance.settings.tabs.installation.change-version.button.install',
|
||||
defaultMessage: 'Install',
|
||||
},
|
||||
alreadyInstalledVanilla: {
|
||||
id: 'instance.settings.tabs.installation.change-version.already-installed.vanilla',
|
||||
defaultMessage: 'Vanilla {game_version} already installed',
|
||||
},
|
||||
alreadyInstalledModded: {
|
||||
id: 'instance.settings.tabs.installation.change-version.already-installed.modded',
|
||||
defaultMessage: '{platform} {version} for Minecraft {game_version} already installed',
|
||||
},
|
||||
installAction: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.action.install',
|
||||
defaultMessage: 'install',
|
||||
},
|
||||
installingNewVersion: {
|
||||
id: 'instance.settings.tabs.installation.change-version.in-progress',
|
||||
defaultMessage: 'Installing new version',
|
||||
},
|
||||
minecraftVersion: {
|
||||
id: 'instance.settings.tabs.installation.minecraft-version',
|
||||
defaultMessage: 'Minecraft {version}',
|
||||
},
|
||||
noLoaderVersions: {
|
||||
id: 'instance.settings.tabs.installation.no-loader-versions',
|
||||
defaultMessage: '{loader} is not available for Minecraft {version}. Try another mod loader.',
|
||||
},
|
||||
noConnection: {
|
||||
id: 'instance.settings.tabs.installation.no-connection',
|
||||
defaultMessage: 'Cannot fetch linked modpack details. Please check your internet connection.',
|
||||
},
|
||||
noModpackFound: {
|
||||
id: 'instance.settings.tabs.installation.no-modpack-found',
|
||||
defaultMessage:
|
||||
'This instance is linked to a modpack, but the modpack could not be found on Modrinth.',
|
||||
},
|
||||
debugInformation: {
|
||||
id: 'instance.settings.tabs.installation.debug-information',
|
||||
defaultMessage: 'Debug information:',
|
||||
},
|
||||
fetchingModpackDetails: {
|
||||
id: 'instance.settings.tabs.installation.fetching-modpack-details',
|
||||
defaultMessage: 'Fetching modpack details',
|
||||
},
|
||||
unlinkInstanceTitle: {
|
||||
id: 'instance.settings.tabs.installation.unlink.title',
|
||||
defaultMessage: 'Unlink from modpack',
|
||||
},
|
||||
unlinkInstanceDescription: {
|
||||
id: 'instance.settings.tabs.installation.unlink.description',
|
||||
defaultMessage: `This instance is linked to a modpack, which means mods can't be updated and you can't change the mod loader or Minecraft version. Unlinking will permanently disconnect this instance from the modpack.`,
|
||||
},
|
||||
unlinkInstanceButton: {
|
||||
id: 'instance.settings.tabs.installation.unlink.button',
|
||||
defaultMessage: 'Unlink instance',
|
||||
},
|
||||
unlinkInstanceConfirmTitle: {
|
||||
id: 'instance.settings.tabs.installation.unlink.confirm.title',
|
||||
defaultMessage: 'Are you sure you want to unlink this instance?',
|
||||
},
|
||||
unlinkInstanceConfirmDescription: {
|
||||
id: 'instance.settings.tabs.installation.unlink.confirm.description',
|
||||
defaultMessage:
|
||||
'If you proceed, you will not be able to re-link it without creating an entirely new instance. You will no longer receive modpack updates and it will become a normal.',
|
||||
},
|
||||
reinstallModpackConfirmTitle: {
|
||||
id: 'instance.settings.tabs.installation.reinstall.confirm.title',
|
||||
defaultMessage: 'Are you sure you want to reinstall this instance?',
|
||||
},
|
||||
reinstallModpackConfirmDescription: {
|
||||
id: 'instance.settings.tabs.installation.reinstall.confirm.description',
|
||||
defaultMessage: `Reinstalling will reset all installed or modified content to what is provided by the modpack, removing any mods or content you have added on top of the original installation. This may fix unexpected behavior if changes have been made to the instance, but if your worlds now depend on additional installed content, it may break existing worlds.`,
|
||||
},
|
||||
reinstallModpackTitle: {
|
||||
id: 'instance.settings.tabs.installation.reinstall.title',
|
||||
defaultMessage: 'Reinstall modpack',
|
||||
},
|
||||
reinstallModpackDescription: {
|
||||
id: 'instance.settings.tabs.installation.reinstall.description',
|
||||
defaultMessage: `Resets the instance's content to its original state, removing any mods or content you have added on top of the original modpack.`,
|
||||
},
|
||||
reinstallModpackButton: {
|
||||
id: 'instance.settings.tabs.installation.reinstall.button',
|
||||
defaultMessage: 'Reinstall modpack',
|
||||
},
|
||||
reinstallingModpackButton: {
|
||||
id: 'instance.settings.tabs.installation.reinstall.button.reinstalling',
|
||||
defaultMessage: 'Reinstalling modpack',
|
||||
},
|
||||
reinstallAction: {
|
||||
id: 'instance.settings.tabs.installation.tooltip.action.reinstall',
|
||||
defaultMessage: 'reinstall',
|
||||
|
||||
async onModpackVersionConfirm(version) {
|
||||
await update_managed_modrinth_version(instance.value.path, version.id)
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['linkedModpackInfo', instance.value.path],
|
||||
})
|
||||
},
|
||||
|
||||
updaterModalProps: computed(() => ({
|
||||
isApp: true,
|
||||
currentVersionId:
|
||||
modpackInfo.value?.update_version_id ?? instance.value.linked_data?.version_id ?? '',
|
||||
projectIconUrl: modpackInfo.value?.project?.icon_url,
|
||||
projectName: modpackInfo.value?.project?.title ?? 'Modpack',
|
||||
currentGameVersion: instance.value.game_version,
|
||||
currentLoader: instance.value.loader,
|
||||
})),
|
||||
|
||||
isServer: false,
|
||||
isApp: true,
|
||||
showModpackVersionActions: !isMinecraftServer.value,
|
||||
repairing,
|
||||
reinstalling,
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ConfirmModalWrapper
|
||||
ref="repairConfirmModal"
|
||||
:title="formatMessage(messages.repairConfirmTitle)"
|
||||
:description="formatMessage(messages.repairConfirmDescription)"
|
||||
:proceed-icon="HammerIcon"
|
||||
:proceed-label="formatMessage(messages.repairButton)"
|
||||
:danger="false"
|
||||
:show-ad-on-close="false"
|
||||
@proceed="() => repairProfile(true)"
|
||||
/>
|
||||
<ModpackVersionModal
|
||||
v-if="instance.linked_data && modpackVersions"
|
||||
ref="modpackVersionModal"
|
||||
:instance="instance"
|
||||
:versions="modpackVersions"
|
||||
@finish-install="
|
||||
() => {
|
||||
changingVersion = false
|
||||
modpackVersion =
|
||||
modpackVersions?.find(
|
||||
(version: Version) => version.id === props.instance.linked_data?.version_id,
|
||||
) ?? null
|
||||
}
|
||||
"
|
||||
/>
|
||||
<ConfirmModalWrapper
|
||||
ref="modalConfirmUnpair"
|
||||
:title="formatMessage(messages.unlinkInstanceConfirmTitle)"
|
||||
:description="formatMessage(messages.unlinkInstanceConfirmDescription)"
|
||||
:proceed-icon="UnlinkIcon"
|
||||
:proceed-label="formatMessage(messages.unlinkInstanceButton)"
|
||||
:show-ad-on-close="false"
|
||||
@proceed="() => unpairProfile()"
|
||||
/>
|
||||
<ConfirmModalWrapper
|
||||
ref="modalConfirmReinstall"
|
||||
:title="formatMessage(messages.reinstallModpackConfirmTitle)"
|
||||
:description="formatMessage(messages.reinstallModpackConfirmDescription)"
|
||||
:proceed-icon="DownloadIcon"
|
||||
:proceed-label="formatMessage(messages.reinstallModpackButton)"
|
||||
:show-ad-on-close="false"
|
||||
@proceed="() => repairModpack()"
|
||||
/>
|
||||
<div>
|
||||
<h2 id="project-name" class="m-0 mb-1 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.currentlyInstalled) }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="!modpackProject && instance.linked_data && offline && !fetching"
|
||||
class="text-secondary font-medium mb-2"
|
||||
>
|
||||
<UnplugIcon class="top-[3px] relative" /> {{ formatMessage(messages.noConnection) }}
|
||||
</div>
|
||||
<div v-else-if="!modpackProject && instance.linked_data && !fetching" class="mb-2">
|
||||
<p class="text-brand-red font-medium mt-0">
|
||||
<IssuesIcon class="top-[3px] relative" />
|
||||
{{ formatMessage(messages.noModpackFound) }}
|
||||
</p>
|
||||
<p>{{ formatMessage(messages.debugInformation) }}</p>
|
||||
<div class="bg-bg p-6 rounded-2xl mt-2 text-sm text-secondary">
|
||||
{{ instance.linked_data }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-4 items-center justify-between p-4 bg-bg rounded-2xl">
|
||||
<div v-if="fetching" class="flex items-center gap-2 h-10">
|
||||
<SpinnerIcon class="animate-spin" />
|
||||
{{ formatMessage(messages.fetchingModpackDetails) }}
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="flex gap-2 items-center">
|
||||
<Avatar v-if="modpackProject" :src="modpackProject?.icon_url" size="40px" />
|
||||
<div
|
||||
v-else
|
||||
class="w-10 h-10 flex items-center justify-center rounded-full bg-button-bg border-solid border-[1px] border-button-border p-2 [&_svg]:h-full [&_svg]:w-full"
|
||||
>
|
||||
<component :is="currentLoaderIcon" v-if="currentLoaderIcon" />
|
||||
<WrenchIcon v-else />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 justify-center">
|
||||
<span class="font-semibold leading-none">
|
||||
{{
|
||||
modpackProject
|
||||
? modpackProject.title
|
||||
: formatMessage(messages.minecraftVersion, {
|
||||
version: instance.game_version,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<span class="text-sm text-secondary leading-none">
|
||||
{{
|
||||
modpackProject
|
||||
? modpackVersion
|
||||
? modpackVersion?.version_number
|
||||
: 'Unknown version'
|
||||
: formatLoader(formatMessage, instance.loader)
|
||||
}}
|
||||
<template v-if="instance.loader !== 'vanilla' && !modpackProject">
|
||||
{{ instance.loader_version || formatMessage(messages.unknownVersion) }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<ButtonStyled color="orange" type="transparent" hover-color-fill="background">
|
||||
<button
|
||||
v-tooltip="
|
||||
repairing
|
||||
? formatMessage(messages.repairInProgress)
|
||||
: installing || reinstalling
|
||||
? formatMessage(messages.cannotWhileInstalling, {
|
||||
action: formatMessage(messages.repairAction),
|
||||
})
|
||||
: offline
|
||||
? formatMessage(messages.cannotWhileOffline, {
|
||||
action: formatMessage(messages.repairAction),
|
||||
})
|
||||
: null
|
||||
"
|
||||
:disabled="installing || repairing || reinstalling || offline"
|
||||
@click="repairConfirmModal.show()"
|
||||
>
|
||||
<SpinnerIcon v-if="repairing" class="animate-spin" />
|
||||
<HammerIcon v-else />
|
||||
{{
|
||||
repairing
|
||||
? formatMessage(messages.repairingButton)
|
||||
: formatMessage(messages.repairButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled v-if="modpackProject" hover-color-fill="background">
|
||||
<button
|
||||
v-tooltip="
|
||||
changingVersion
|
||||
? formatMessage(messages.installingNewVersion)
|
||||
: repairing
|
||||
? formatMessage(messages.cannotWhileRepairing, {
|
||||
action: formatMessage(messages.changeVersionAction),
|
||||
})
|
||||
: installing || reinstalling
|
||||
? formatMessage(messages.cannotWhileInstalling, {
|
||||
action: formatMessage(messages.changeVersionAction),
|
||||
})
|
||||
: fetching && !modpackVersions
|
||||
? formatMessage(messages.changeVersionCannotWhileFetching)
|
||||
: offline
|
||||
? formatMessage(messages.cannotWhileOffline, {
|
||||
action: formatMessage(messages.changeVersionAction),
|
||||
})
|
||||
: null
|
||||
"
|
||||
:disabled="
|
||||
changingVersion ||
|
||||
repairing ||
|
||||
installing ||
|
||||
reinstalling ||
|
||||
offline ||
|
||||
fetching ||
|
||||
!modpackVersions
|
||||
"
|
||||
@click="
|
||||
() => {
|
||||
changingVersion = true
|
||||
modpackVersionModal.show()
|
||||
}
|
||||
"
|
||||
>
|
||||
<SpinnerIcon v-if="changingVersion" class="animate-spin" />
|
||||
<TransferIcon v-else />
|
||||
{{
|
||||
changingVersion
|
||||
? formatMessage(messages.installingButton)
|
||||
: formatMessage(messages.changeVersionButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<template v-if="!instance.linked_data || !instance.linked_data.locked">
|
||||
<h2 class="m-0 mt-4 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.platform) }}
|
||||
</h2>
|
||||
<Chips v-if="loaders" v-model="loader" :items="loaders.map((x) => x.name)" class="mt-2" />
|
||||
<h2 class="m-0 mt-4 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.gameVersion) }}
|
||||
</h2>
|
||||
<div class="flex flex-wrap mt-2 gap-2">
|
||||
<Combobox
|
||||
v-if="selectableGameVersionNumbers !== undefined"
|
||||
v-model="gameVersion"
|
||||
:options="gameVersionOptions"
|
||||
:display-value="gameVersion || formatMessage(messages.unknownVersion)"
|
||||
/>
|
||||
<Checkbox
|
||||
v-if="hasSnapshots"
|
||||
v-model="showSnapshots"
|
||||
:label="formatMessage(messages.showAllVersions)"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="loader !== 'vanilla'">
|
||||
<h2 class="m-0 mt-4 text-lg font-extrabold text-contrast block">
|
||||
{{
|
||||
formatMessage(messages.loaderVersion, {
|
||||
loader: formatLoader(formatMessage, loader),
|
||||
})
|
||||
}}
|
||||
</h2>
|
||||
<Combobox
|
||||
v-if="selectableLoaderVersions"
|
||||
v-model="loaderVersionIndex"
|
||||
:options="loaderVersionOptions"
|
||||
:display-value="loaderVersionLabel"
|
||||
name="Version selector"
|
||||
class="mt-2"
|
||||
/>
|
||||
<div v-else class="mt-2 text-brand-red flex gap-2 items-center">
|
||||
<IssuesIcon />
|
||||
{{
|
||||
formatMessage(messages.noLoaderVersions, {
|
||||
loader: loader,
|
||||
version: gameVersion,
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<ButtonStyled color="brand">
|
||||
<button
|
||||
v-tooltip="
|
||||
installing || reinstalling
|
||||
? formatMessage(messages.installInProgress)
|
||||
: !isChanged
|
||||
? formatMessage(
|
||||
loader === 'vanilla'
|
||||
? messages.alreadyInstalledVanilla
|
||||
: messages.alreadyInstalledModded,
|
||||
{
|
||||
platform: formatLoader(formatMessage, loader),
|
||||
version: instance.loader_version,
|
||||
game_version: gameVersion,
|
||||
},
|
||||
)
|
||||
: repairing
|
||||
? formatMessage(messages.cannotWhileRepairing, {
|
||||
action: formatMessage(messages.installAction),
|
||||
})
|
||||
: offline
|
||||
? formatMessage(messages.cannotWhileOffline, {
|
||||
action: formatMessage(messages.installAction),
|
||||
})
|
||||
: null
|
||||
"
|
||||
:disabled="!isValid || !isChanged || editing || offline || repairing"
|
||||
@click="saveGvLoaderEdits()"
|
||||
>
|
||||
<SpinnerIcon v-if="editing" class="animate-spin" />
|
||||
<DownloadIcon v-else />
|
||||
{{
|
||||
editing
|
||||
? formatMessage(messages.installingButton)
|
||||
: formatMessage(messages.installButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button
|
||||
:disabled="!isChanged"
|
||||
@click="
|
||||
() => {
|
||||
loader = instance.loader
|
||||
gameVersion = instance.game_version
|
||||
resetLoaderVersionIndex()
|
||||
}
|
||||
"
|
||||
>
|
||||
<UndoIcon />
|
||||
{{ formatMessage(messages.resetSelections) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="instance.linked_data && instance.linked_data.locked">
|
||||
<h2 class="mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
{{ formatMessage(messages.unlinkInstanceTitle) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.unlinkInstanceDescription) }}
|
||||
</p>
|
||||
<ButtonStyled>
|
||||
<button class="mt-2" @click="modalConfirmUnpair.show()">
|
||||
<UnlinkIcon /> {{ formatMessage(messages.unlinkInstanceButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<template v-if="modpackProject">
|
||||
<div>
|
||||
<h2 class="m-0 mb-1 text-lg font-extrabold text-contrast block mt-4">
|
||||
{{ formatMessage(messages.reinstallModpackTitle) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
{{ formatMessage(messages.reinstallModpackDescription) }}
|
||||
</p>
|
||||
</div>
|
||||
<ButtonStyled color="red" type="outlined">
|
||||
<button
|
||||
v-tooltip="
|
||||
reinstalling
|
||||
? formatMessage(messages.reinstallingModpackButton)
|
||||
: repairing
|
||||
? formatMessage(messages.cannotWhileRepairing, {
|
||||
action: formatMessage(messages.reinstallAction),
|
||||
})
|
||||
: installing
|
||||
? formatMessage(messages.cannotWhileInstalling, {
|
||||
action: formatMessage(messages.reinstallAction),
|
||||
})
|
||||
: offline
|
||||
? formatMessage(messages.cannotWhileOffline, {
|
||||
action: formatMessage(messages.reinstallAction),
|
||||
})
|
||||
: null
|
||||
"
|
||||
class="mt-2"
|
||||
:disabled="
|
||||
changingVersion ||
|
||||
repairing ||
|
||||
installing ||
|
||||
offline ||
|
||||
fetching ||
|
||||
!modpackVersions
|
||||
"
|
||||
@click="modalConfirmReinstall.show()"
|
||||
>
|
||||
<SpinnerIcon v-if="reinstalling" class="animate-spin" />
|
||||
<DownloadIcon v-else />
|
||||
{{
|
||||
reinstalling
|
||||
? formatMessage(messages.reinstallingModpackButton)
|
||||
: formatMessage(messages.reinstallModpackButton)
|
||||
}}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<InstallationSettingsLayout />
|
||||
</template>
|
||||
|
||||
@@ -14,34 +14,35 @@ import JavaSelector from '@/components/ui/JavaSelector.vue'
|
||||
import useMemorySlider from '@/composables/useMemorySlider'
|
||||
import { edit, get_optimal_jre_key } from '@/helpers/profile'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types'
|
||||
import type { AppSettings } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<InstanceSettingsTabProps>()
|
||||
const { instance } = injectInstanceSettings()
|
||||
|
||||
const globalSettings = (await get().catch(handleError)) as unknown as AppSettings
|
||||
|
||||
const overrideJavaInstall = ref(!!props.instance.java_path)
|
||||
const optimalJava = readonly(await get_optimal_jre_key(props.instance.path).catch(handleError))
|
||||
const javaInstall = ref({ path: optimalJava.path ?? props.instance.java_path })
|
||||
const overrideJavaInstall = ref(!!instance.value.java_path)
|
||||
const optimalJava = readonly(await get_optimal_jre_key(instance.value.path).catch(handleError))
|
||||
const javaInstall = ref({ path: optimalJava.path ?? instance.value.java_path })
|
||||
|
||||
const overrideJavaArgs = ref((props.instance.extra_launch_args?.length ?? 0) > 0)
|
||||
const overrideJavaArgs = ref((instance.value.extra_launch_args?.length ?? 0) > 0)
|
||||
const javaArgs = ref(
|
||||
(props.instance.extra_launch_args ?? globalSettings.extra_launch_args).join(' '),
|
||||
(instance.value.extra_launch_args ?? globalSettings.extra_launch_args).join(' '),
|
||||
)
|
||||
|
||||
const overrideEnvVars = ref((props.instance.custom_env_vars?.length ?? 0) > 0)
|
||||
const overrideEnvVars = ref((instance.value.custom_env_vars?.length ?? 0) > 0)
|
||||
const envVars = ref(
|
||||
(props.instance.custom_env_vars ?? globalSettings.custom_env_vars)
|
||||
(instance.value.custom_env_vars ?? globalSettings.custom_env_vars)
|
||||
.map((x) => x.join('='))
|
||||
.join(' '),
|
||||
)
|
||||
|
||||
const overrideMemorySettings = ref(!!props.instance.memory)
|
||||
const memory = ref(props.instance.memory ?? globalSettings.memory)
|
||||
const overrideMemorySettings = ref(!!instance.value.memory)
|
||||
const memory = ref(instance.value.memory ?? globalSettings.memory)
|
||||
const { maxMemory, snapPoints } = (await useMemorySlider().catch(handleError)) as unknown as {
|
||||
maxMemory: number
|
||||
snapPoints: number[]
|
||||
@@ -79,7 +80,7 @@ watch(
|
||||
memory,
|
||||
],
|
||||
async () => {
|
||||
await edit(props.instance.path, editProfileObject.value)
|
||||
await edit(instance.value.path, editProfileObject.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
@@ -110,10 +111,10 @@ const messages = defineMessages({
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2 id="project-name" class="m-0 mb-1 text-lg font-extrabold text-contrast block">
|
||||
<h2 id="project-name" class="m-0 mb-2.5 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.javaInstallation) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideJavaInstall" label="Custom Java installation" class="mb-2" />
|
||||
<Checkbox v-model="overrideJavaInstall" label="Custom Java installation" class="mb-2.5" />
|
||||
<template v-if="!overrideJavaInstall">
|
||||
<div class="flex my-2 items-center gap-2 font-semibold">
|
||||
<template v-if="javaInstall">
|
||||
@@ -143,10 +144,10 @@ const messages = defineMessages({
|
||||
</div>
|
||||
</template>
|
||||
<JavaSelector v-if="overrideJavaInstall || !javaInstall" v-model="javaInstall" />
|
||||
<h2 id="project-name" class="mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
<h2 id="project-name" class="mt-6 mb-2.5 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.javaMemory) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideMemorySettings" label="Custom memory allocation" class="mb-2" />
|
||||
<Checkbox v-model="overrideMemorySettings" label="Custom memory allocation" class="mb-2.5" />
|
||||
<Slider
|
||||
id="max-memory"
|
||||
v-model="memory.maximum"
|
||||
@@ -158,7 +159,7 @@ const messages = defineMessages({
|
||||
:snap-range="512"
|
||||
unit="MB"
|
||||
/>
|
||||
<h2 id="project-name" class="mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
<h2 id="project-name" class="mt-6 mb-2.5 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.javaArguments) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideJavaArgs" label="Custom java arguments" class="my-2" />
|
||||
@@ -170,10 +171,10 @@ const messages = defineMessages({
|
||||
placeholder="Enter java arguments..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 id="project-name" class="mt-4 mb-1 text-lg font-extrabold text-contrast block">
|
||||
<h2 id="project-name" class="mt-6 mb-2.5 text-lg font-semibold text-contrast block">
|
||||
{{ formatMessage(messages.javaEnvironmentVariables) }}
|
||||
</h2>
|
||||
<Checkbox v-model="overrideEnvVars" label="Custom environment variables" class="mb-2" />
|
||||
<Checkbox v-model="overrideEnvVars" label="Custom environment variables" class="mb-2.5" />
|
||||
<StyledInput
|
||||
id="env-vars"
|
||||
v-model="envVars"
|
||||
|
||||
@@ -11,24 +11,25 @@ import { computed, type Ref, ref, watch } from 'vue'
|
||||
|
||||
import { edit } from '@/helpers/profile'
|
||||
import { get } from '@/helpers/settings.ts'
|
||||
import { injectInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types'
|
||||
import type { AppSettings } from '../../../helpers/types'
|
||||
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<InstanceSettingsTabProps>()
|
||||
const { instance } = injectInstanceSettings()
|
||||
|
||||
const globalSettings = (await get().catch(handleError)) as AppSettings
|
||||
|
||||
const overrideWindowSettings = ref(
|
||||
!!props.instance.game_resolution || !!props.instance.force_fullscreen,
|
||||
!!instance.value.game_resolution || !!instance.value.force_fullscreen,
|
||||
)
|
||||
const resolution: Ref<[number, number]> = ref(
|
||||
props.instance.game_resolution ?? (globalSettings.game_resolution.slice() as [number, number]),
|
||||
instance.value.game_resolution ?? (globalSettings.game_resolution.slice() as [number, number]),
|
||||
)
|
||||
const fullscreenSetting: Ref<boolean> = ref(
|
||||
props.instance.force_fullscreen ?? globalSettings.force_fullscreen,
|
||||
instance.value.force_fullscreen ?? globalSettings.force_fullscreen,
|
||||
)
|
||||
|
||||
const editProfileObject = computed(() => {
|
||||
@@ -47,7 +48,7 @@ const editProfileObject = computed(() => {
|
||||
watch(
|
||||
[overrideWindowSettings, resolution, fullscreenSetting],
|
||||
async () => {
|
||||
await edit(props.instance.path, editProfileObject.value)
|
||||
await edit(instance.value.path, editProfileObject.value)
|
||||
},
|
||||
{ deep: true },
|
||||
)
|
||||
@@ -93,14 +94,14 @@ const messages = defineMessages({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex flex-col gap-6">
|
||||
<Checkbox
|
||||
v-model="overrideWindowSettings"
|
||||
:label="formatMessage(messages.customWindowSettings)"
|
||||
/>
|
||||
<div class="mt-2 flex items-center gap-4 justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 mb-1 text-lg font-extrabold text-contrast">
|
||||
<div class="flex items-center gap-4 justify-between">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.fullscreen) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
@@ -119,9 +120,9 @@ const messages = defineMessages({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-4 justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 mb-1 text-lg font-extrabold text-contrast">
|
||||
<div class="flex items-center gap-4 justify-between">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.width) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
@@ -138,9 +139,9 @@ const messages = defineMessages({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-4 justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 mb-1 text-lg font-extrabold text-contrast">
|
||||
<div class="flex items-center gap-4 justify-between">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">
|
||||
{{ formatMessage(messages.height) }}
|
||||
</h2>
|
||||
<p class="m-0">
|
||||
|
||||
+14
-3
@@ -10,6 +10,7 @@ import {
|
||||
import { Admonition, ButtonStyled, Collapsible, NewModal } from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { login as login_flow, set_default_user } from '@/helpers/auth.js'
|
||||
import { handleSevereError } from '@/store/error.js'
|
||||
|
||||
@@ -28,13 +29,19 @@ function show(errorVal: { message?: string }) {
|
||||
matchedError.value = minecraftAuthErrors.find((e) => rawError.value.includes(e.errorCode)) ?? null
|
||||
|
||||
debugCollapsed.value = true
|
||||
hide_ads_window()
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
onModalHide()
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
function onModalHide() {
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
hide,
|
||||
@@ -67,7 +74,7 @@ async function copyToClipboard(text: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NewModal ref="modal" header="Sign in Failed" :max-width="'548px'">
|
||||
<NewModal ref="modal" header="Sign in Failed" :max-width="'548px'" @hide="onModalHide">
|
||||
<div class="flex flex-col gap-6">
|
||||
<Admonition
|
||||
type="warning"
|
||||
@@ -161,8 +168,12 @@ async function copyToClipboard(text: string) {
|
||||
/>
|
||||
</button>
|
||||
<Collapsible :collapsed="debugCollapsed">
|
||||
<div class="p-3 bg-surface-2 rounded-2xl text-xs flex items-start">
|
||||
<div class="m-0 p-0 rounded-none bg-transparent text-sm font-mono">
|
||||
<div
|
||||
class="p-3 bg-surface-2 rounded-2xl text-xs grid grid-cols-[1fr_auto] max-w-full items-start"
|
||||
>
|
||||
<div
|
||||
class="m-0 p-0 rounded-none bg-transparent text-sm font-mono break-words overflow-auto"
|
||||
>
|
||||
{{ debugInfo }}
|
||||
</div>
|
||||
<ButtonStyled circular>
|
||||
|
||||
@@ -6,12 +6,13 @@ import {
|
||||
LanguagesIcon,
|
||||
ModrinthIcon,
|
||||
PaintbrushIcon,
|
||||
ReportIcon,
|
||||
SettingsIcon,
|
||||
ShieldIcon,
|
||||
ToggleRightIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
commonMessages,
|
||||
commonSettingsMessages,
|
||||
defineMessage,
|
||||
defineMessages,
|
||||
ProgressBar,
|
||||
@@ -20,9 +21,8 @@ import {
|
||||
} from '@modrinth/ui'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { platform as getOsPlatform, version as getOsVersion } from '@tauri-apps/plugin-os'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import AppearanceSettings from '@/components/ui/settings/AppearanceSettings.vue'
|
||||
import DefaultInstanceSettings from '@/components/ui/settings/DefaultInstanceSettings.vue'
|
||||
import FeatureFlagSettings from '@/components/ui/settings/FeatureFlagSettings.vue'
|
||||
@@ -96,25 +96,20 @@ const tabs = [
|
||||
content: ResourceManagementSettings,
|
||||
},
|
||||
{
|
||||
name: defineMessage({
|
||||
id: 'app.settings.tabs.feature-flags',
|
||||
defaultMessage: 'Feature flags',
|
||||
}),
|
||||
icon: ReportIcon,
|
||||
name: commonSettingsMessages.featureFlags,
|
||||
icon: ToggleRightIcon,
|
||||
content: FeatureFlagSettings,
|
||||
developerOnly: true,
|
||||
},
|
||||
]
|
||||
|
||||
const modal = ref()
|
||||
const modal = ref<InstanceType<typeof TabbedModal> | null>(null)
|
||||
|
||||
function show() {
|
||||
modal.value.show()
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
const isOpen = computed(() => modal.value?.isOpen)
|
||||
|
||||
defineExpose({ show, isOpen })
|
||||
defineExpose({ show })
|
||||
|
||||
const { progress, version: downloadingVersion } = injectAppUpdateDownloadProgress()
|
||||
|
||||
@@ -138,8 +133,8 @@ function devModeCount() {
|
||||
settings.value.developer_mode = !!themeStore.devMode
|
||||
devModeCounter.value = 0
|
||||
|
||||
if (!themeStore.devMode && tabs[modal.value.selectedTab].developerOnly) {
|
||||
modal.value.setTab(0)
|
||||
if (!themeStore.devMode && tabs[modal.value!.selectedTab].developerOnly) {
|
||||
modal.value!.setTab(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,49 +147,46 @@ const messages = defineMessages({
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
<TabbedModal ref="modal" :tabs="tabs.filter((t) => !t.developerOnly || themeStore.devMode)">
|
||||
<template #title>
|
||||
<span class="flex items-center gap-2 text-lg font-extrabold text-contrast">
|
||||
<SettingsIcon /> Settings
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<TabbedModal :tabs="tabs.filter((t) => !t.developerOnly || themeStore.devMode)">
|
||||
<template #footer>
|
||||
<div class="mt-auto text-secondary text-sm">
|
||||
<div class="mb-3">
|
||||
<template v-if="progress > 0 && progress < 1">
|
||||
<p class="m-0 mb-2">
|
||||
{{ formatMessage(messages.downloading, { version: downloadingVersion }) }}
|
||||
</p>
|
||||
<ProgressBar :progress="progress" />
|
||||
</template>
|
||||
</div>
|
||||
<p v-if="themeStore.devMode" class="text-brand font-semibold m-0 mb-2">
|
||||
{{ formatMessage(developerModeEnabled) }}
|
||||
</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<button
|
||||
class="p-0 m-0 bg-transparent border-none cursor-pointer button-animation"
|
||||
:class="{
|
||||
'text-brand': themeStore.devMode,
|
||||
'text-secondary': !themeStore.devMode,
|
||||
}"
|
||||
@click="devModeCount"
|
||||
>
|
||||
<ModrinthIcon class="w-6 h-6" />
|
||||
</button>
|
||||
<div>
|
||||
<p class="m-0">Modrinth App {{ version }}</p>
|
||||
<p class="m-0">
|
||||
<span v-if="osPlatform === 'macos'">macOS</span>
|
||||
<span v-else class="capitalize">{{ osPlatform }}</span>
|
||||
{{ osVersion }}
|
||||
</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="mt-auto text-secondary text-sm">
|
||||
<div class="mb-3">
|
||||
<template v-if="progress > 0 && progress < 1">
|
||||
<p class="m-0 mb-2">
|
||||
{{ formatMessage(messages.downloading, { version: downloadingVersion }) }}
|
||||
</p>
|
||||
<ProgressBar :progress="progress" />
|
||||
</template>
|
||||
</div>
|
||||
<p v-if="themeStore.devMode" class="text-brand font-semibold m-0 mb-2">
|
||||
{{ formatMessage(developerModeEnabled) }}
|
||||
</p>
|
||||
<div class="flex items-center gap-3">
|
||||
<button
|
||||
class="p-0 m-0 bg-transparent border-none cursor-pointer button-animation"
|
||||
:class="{
|
||||
'text-brand': themeStore.devMode,
|
||||
'text-secondary': !themeStore.devMode,
|
||||
}"
|
||||
@click="devModeCount"
|
||||
>
|
||||
<ModrinthIcon class="w-6 h-6" />
|
||||
</button>
|
||||
<div class="max-w-[200px]">
|
||||
<p class="m-0">Modrinth App {{ version }}</p>
|
||||
<p class="m-0">
|
||||
<span v-if="osPlatform === 'macos'">macOS</span>
|
||||
<span v-else class="capitalize">{{ osPlatform }}</span>
|
||||
{{ osVersion }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</TabbedModal>
|
||||
</ModalWrapper>
|
||||
</div>
|
||||
</template>
|
||||
</TabbedModal>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.header)" fade="danger" max-width="500px">
|
||||
<Admonition type="critical" :header="formatMessage(messages.admonitionHeader)">
|
||||
{{ formatMessage(messages.admonitionBody) }}
|
||||
</Admonition>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!border !border-surface-4" @click="modal?.hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="red">
|
||||
<button @click="confirm">
|
||||
<TrashIcon />
|
||||
{{ formatMessage(messages.deleteButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { TrashIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
header: {
|
||||
id: 'app.instance.confirm-delete.header',
|
||||
defaultMessage: 'Delete instance',
|
||||
},
|
||||
admonitionHeader: {
|
||||
id: 'app.instance.confirm-delete.admonition-header',
|
||||
defaultMessage: 'This action cannot be undone',
|
||||
},
|
||||
admonitionBody: {
|
||||
id: 'app.instance.confirm-delete.admonition-body',
|
||||
defaultMessage:
|
||||
'All data for your instance will be permanently deleted, including your worlds, configs, and all installed content.',
|
||||
},
|
||||
deleteButton: {
|
||||
id: 'app.instance.confirm-delete.delete-button',
|
||||
defaultMessage: 'Delete instance',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'delete'): void
|
||||
}>()
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
|
||||
function show() {
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
modal.value?.hide()
|
||||
emit('delete')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
})
|
||||
</script>
|
||||
@@ -1,13 +1,9 @@
|
||||
<!-- @deprecated Use ConfirmModal from @modrinth/ui directly. Ads/noblur now handled by injectModalBehavior. -->
|
||||
<script setup lang="ts">
|
||||
import { ConfirmModal } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
import { useTemplateRef } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { useTheming } from '@/store/theme.ts'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
confirmationText: {
|
||||
type: String,
|
||||
default: '',
|
||||
@@ -38,6 +34,7 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
/** @deprecated No longer used — ads are handled by provideModalBehavior */
|
||||
showAdOnClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@@ -49,25 +46,17 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const emit = defineEmits(['proceed'])
|
||||
const modal = ref(null)
|
||||
const modal = useTemplateRef('modal')
|
||||
|
||||
defineExpose({
|
||||
show: () => {
|
||||
hide_ads_window()
|
||||
modal.value.show()
|
||||
modal.value?.show()
|
||||
},
|
||||
hide: () => {
|
||||
onModalHide()
|
||||
modal.value.hide()
|
||||
modal.value?.hide()
|
||||
},
|
||||
})
|
||||
|
||||
function onModalHide() {
|
||||
if (props.showAdOnClose) {
|
||||
show_ads_window()
|
||||
}
|
||||
}
|
||||
|
||||
function proceed() {
|
||||
emit('proceed')
|
||||
}
|
||||
@@ -82,8 +71,6 @@ function proceed() {
|
||||
:description="description"
|
||||
:proceed-icon="proceedIcon"
|
||||
:proceed-label="proceedLabel"
|
||||
:on-hide="onModalHide"
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
:danger="danger"
|
||||
:markdown="markdown"
|
||||
@proceed="proceed"
|
||||
|
||||
@@ -1,36 +1,41 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.installToPlay)" :closable="true">
|
||||
<div class="flex flex-col gap-6 max-w-[500px]">
|
||||
<Admonition type="info" :header="formatMessage(messages.sharedServerInstance)">
|
||||
<div v-if="requiredContentProject" class="flex flex-col gap-6 max-w-[500px]">
|
||||
<Admonition type="info" :header="formatMessage(messages.contentRequired)">
|
||||
{{ formatMessage(messages.serverRequiresMods) }}
|
||||
</Admonition>
|
||||
|
||||
<div v-if="sharedBy?.name" class="flex items-center gap-2 text-sm text-secondary">
|
||||
<Avatar
|
||||
v-if="sharedBy?.icon_url"
|
||||
:src="sharedBy.icon_url"
|
||||
:alt="sharedBy.name"
|
||||
size="24px"
|
||||
/>
|
||||
<span>
|
||||
<IntlFormatted :message-id="messages.sharedByToday">
|
||||
<template #~name>
|
||||
<span class="font-semibold text-contrast">{{ sharedBy.name }}</span>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
</span>
|
||||
</div>
|
||||
<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">
|
||||
<span class="font-semibold text-contrast">
|
||||
{{ formatMessage(messages.sharedInstance) }}
|
||||
</span>
|
||||
<div class="flex items-center gap-3 rounded-xl bg-surface-4 p-3">
|
||||
<Avatar :src="project.icon_url" :alt="project.title" size="48px" />
|
||||
<ButtonStyled type="transparent">
|
||||
<button @click="openViewContents">
|
||||
<EyeIcon />
|
||||
{{ formatMessage(messages.viewContents) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 rounded-xl bg-surface-2 p-3">
|
||||
<Avatar
|
||||
:src="requiredContentProject.icon_url"
|
||||
:alt="requiredContentProject.title"
|
||||
size="48px"
|
||||
/>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="font-semibold text-contrast">{{ project.title }}</span>
|
||||
<span class="font-semibold text-contrast">
|
||||
<template v-if="usingCustomModpack && modpackVersion">
|
||||
{{ modpackVersion.name }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ requiredContentProject.title }}
|
||||
</template>
|
||||
</span>
|
||||
<span class="text-sm text-secondary">
|
||||
{{ loaderDisplay }} {{ project.game_versions?.[0] }}
|
||||
{{ loaderDisplay }} {{ requiredContentProject.game_versions?.[0] }}
|
||||
<template v-if="modCount">
|
||||
· {{ formatMessage(messages.modCount, { count: modCount }) }}
|
||||
</template>
|
||||
@@ -57,11 +62,18 @@
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
|
||||
<ModpackContentModal
|
||||
ref="modpackContentModal"
|
||||
:modpack-name="project?.name ?? ''"
|
||||
:modpack-icon-url="project?.icon_url ?? undefined"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { DownloadIcon, XIcon } from '@modrinth/assets'
|
||||
import { DownloadIcon, EyeIcon, XIcon } from '@modrinth/assets'
|
||||
import type { ContentItem } from '@modrinth/ui'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
@@ -69,75 +81,57 @@ import {
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
formatLoader,
|
||||
IntlFormatted,
|
||||
ModpackContentModal,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import { get_organization, get_team, get_version } from '@/helpers/cache.js'
|
||||
import { install } from '@/store/install.js'
|
||||
|
||||
const props = defineProps<{
|
||||
project: Labrinth.Projects.v2.Project
|
||||
}>()
|
||||
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'
|
||||
|
||||
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 onInstallComplete = ref<() => void>(() => {})
|
||||
const { formatMessage } = useVIntl()
|
||||
const { installServerProject, startInstallingServer, stopInstallingServer } = injectServerInstall()
|
||||
|
||||
const { data: organization } = useQuery({
|
||||
queryKey: computed(() => ['organization', props.project.organization]),
|
||||
queryFn: () => get_organization(props.project.organization!, 'must_revalidate'),
|
||||
enabled: computed(() => !!props.project.organization),
|
||||
})
|
||||
|
||||
const { data: teamMembers } = useQuery({
|
||||
queryKey: computed(() => ['team', props.project.team]),
|
||||
queryFn: () => get_team(props.project.team, 'must_revalidate'),
|
||||
enabled: computed(() => !!props.project.team && !props.project.organization),
|
||||
})
|
||||
|
||||
const sharedBy = computed(() => {
|
||||
if (organization.value) {
|
||||
return {
|
||||
name: organization.value.name,
|
||||
icon_url: organization.value.icon_url,
|
||||
}
|
||||
}
|
||||
if (teamMembers.value) {
|
||||
const owner = teamMembers.value.find((member: { is_owner: boolean }) => member.is_owner)
|
||||
if (owner) {
|
||||
return {
|
||||
name: owner.user.username,
|
||||
icon_url: owner.user.avatar_url,
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
const usingCustomModpack = computed(() => {
|
||||
return requiredContentProject.value?.id === project.value?.id
|
||||
})
|
||||
|
||||
const loaderDisplay = computed(() => {
|
||||
const loader = props.project.loaders?.[0]
|
||||
const loader = requiredContentProject.value?.loaders?.[0]
|
||||
if (!loader) return ''
|
||||
return formatLoader(formatMessage, loader)
|
||||
})
|
||||
|
||||
// Fetch the most recent version to get mod count from dependencies
|
||||
const latestVersionId = computed(() => props.project.versions?.[0] ?? null)
|
||||
const { data: latestVersion } = useQuery({
|
||||
queryKey: computed(() => ['version', latestVersionId.value]),
|
||||
queryFn: () => get_version(latestVersionId.value, 'must_revalidate'),
|
||||
enabled: computed(() => !!latestVersionId.value),
|
||||
})
|
||||
const modCount = computed(() => latestVersion.value?.dependencies?.length)
|
||||
const modCount = computed(() => modpackVersion.value?.dependencies?.length)
|
||||
|
||||
async function fetchData(versionId: string) {
|
||||
// cache is making version null for some reason so bypassing for now
|
||||
modpackVersion.value = await get_version(versionId, 'bypass')
|
||||
|
||||
if (modpackVersion.value?.project_id) {
|
||||
requiredContentProject.value = await get_project(modpackVersion.value.project_id, 'bypass')
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAccept() {
|
||||
hide()
|
||||
const serverProjectId = project.value?.id
|
||||
startInstallingServer(serverProjectId)
|
||||
try {
|
||||
await install(props.project.id, null, null, 'ProjectPageInstallToPlayModal')
|
||||
await installServerProject(serverProjectId)
|
||||
onInstallComplete.value()
|
||||
} catch (error) {
|
||||
console.error('Failed to install project from InstallToPlayModal:', error)
|
||||
console.error('Failed to install server project from InstallToPlayModal:', error)
|
||||
} finally {
|
||||
stopInstallingServer(serverProjectId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,12 +139,95 @@ function handleDecline() {
|
||||
hide()
|
||||
}
|
||||
|
||||
function show(e?: MouseEvent) {
|
||||
const modpackContentModal = ref<InstanceType<typeof ModpackContentModal>>()
|
||||
|
||||
async function openViewContents() {
|
||||
modpackContentModal.value?.showLoading()
|
||||
try {
|
||||
// Ensure version data is available — the useQuery may not have resolved yet
|
||||
const versionId = modpackVersionId.value
|
||||
const version =
|
||||
modpackVersion.value ?? (versionId ? await get_version(versionId, 'must_revalidate') : null)
|
||||
|
||||
const deps = version?.dependencies ?? []
|
||||
|
||||
const projectIds = deps
|
||||
.map((d: { project_id?: string }) => d.project_id)
|
||||
.filter((id: string | undefined): id is string => !!id)
|
||||
|
||||
const versionIds = deps
|
||||
.map((d: { version_id?: string }) => d.version_id)
|
||||
.filter((id: string | undefined): id is string => !!id)
|
||||
|
||||
const projects: Labrinth.Projects.v2.Project[] =
|
||||
projectIds.length > 0 ? await get_project_many(projectIds, 'must_revalidate') : []
|
||||
|
||||
const versions: Labrinth.Versions.v2.Version[] =
|
||||
versionIds.length > 0 ? await get_version_many(versionIds, 'must_revalidate') : []
|
||||
|
||||
const projectMap = new Map(projects.map((p: Labrinth.Projects.v2.Project) => [p.id, p]))
|
||||
|
||||
const contentItems: ContentItem[] = deps.map(
|
||||
(dep: Labrinth.Versions.v2.Dependency): ContentItem => {
|
||||
const depProject = dep.project_id ? projectMap.get(dep.project_id) : null
|
||||
// @ts-expect-error - version_id is missing from the type for some reason
|
||||
const depVersion = dep.version_id
|
||||
? // @ts-expect-error - version_id is missing from the type for some reason
|
||||
versions.find((v: Labrinth.Versions.v2.Version) => v.id === dep.version_id)
|
||||
: null
|
||||
|
||||
return {
|
||||
file_name: dep.file_name ?? depProject?.title ?? 'Unknown',
|
||||
project_type: depProject?.project_type ?? 'mod',
|
||||
has_update: false,
|
||||
update_version_id: null,
|
||||
project: {
|
||||
id: depProject?.id ?? dep.project_id ?? dep.file_name ?? 'unknown',
|
||||
slug: depProject?.slug ?? dep.project_id ?? 'unknown',
|
||||
title: depProject?.title ?? dep.file_name ?? 'Unknown',
|
||||
icon_url: depProject?.icon_url ?? undefined,
|
||||
},
|
||||
...(depVersion
|
||||
? {
|
||||
version: {
|
||||
id: depVersion.id,
|
||||
file_name: depVersion.files?.[0]?.filename ?? dep.file_name,
|
||||
version_number: depVersion.version_number ?? undefined,
|
||||
date_published: depVersion.date_published ?? undefined,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}
|
||||
},
|
||||
)
|
||||
modpackContentModal.value?.show(contentItems)
|
||||
} catch (err) {
|
||||
console.error('Failed to load modpack contents:', err)
|
||||
modpackContentModal.value?.show([])
|
||||
}
|
||||
}
|
||||
|
||||
async function show(
|
||||
projectVal: Labrinth.Projects.v3.Project,
|
||||
modpackVersionIdVal: string | null = null,
|
||||
callback: () => void = () => {},
|
||||
e?: MouseEvent,
|
||||
) {
|
||||
project.value = projectVal
|
||||
modpackVersionId.value = modpackVersionIdVal
|
||||
modpackVersion.value = null
|
||||
requiredContentProject.value = null
|
||||
onInstallComplete.value = callback
|
||||
|
||||
if (modpackVersionIdVal) await fetchData(modpackVersionIdVal)
|
||||
|
||||
hide_ads_window()
|
||||
modal.value?.show(e)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
show_ads_window()
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -162,14 +239,18 @@ const messages = defineMessages({
|
||||
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',
|
||||
defaultMessage:
|
||||
'This server requires mods to play. Click install to set up the required files from Modrinth.',
|
||||
'This server requires mods to play. Click Install to set up the required files from Modrinth, then launch directly into the server.',
|
||||
},
|
||||
sharedByToday: {
|
||||
id: 'app.modal.install-to-play.shared-by-today',
|
||||
defaultMessage: '{name} shared this instance with you today.',
|
||||
requiredModpack: {
|
||||
id: 'app.modal.install-to-play.required-modpack',
|
||||
defaultMessage: 'Required modpack',
|
||||
},
|
||||
sharedInstance: {
|
||||
id: 'app.modal.install-to-play.shared-instance',
|
||||
@@ -183,6 +264,10 @@ const messages = defineMessages({
|
||||
id: 'app.modal.install-to-play.install-button',
|
||||
defaultMessage: 'Install',
|
||||
},
|
||||
viewContents: {
|
||||
id: 'app.modal.install-to-play.view-contents',
|
||||
defaultMessage: 'View contents',
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({ show, hide })
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import {
|
||||
ChevronRightIcon,
|
||||
CodeIcon,
|
||||
@@ -15,23 +16,61 @@ import {
|
||||
type TabbedModalTab,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useQueryClient } from '@tanstack/vue-query'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import { ref } from 'vue'
|
||||
import { computed, nextTick, ref, watch } from 'vue'
|
||||
|
||||
import GeneralSettings from '@/components/ui/instance_settings/GeneralSettings.vue'
|
||||
import HooksSettings from '@/components/ui/instance_settings/HooksSettings.vue'
|
||||
import InstallationSettings from '@/components/ui/instance_settings/InstallationSettings.vue'
|
||||
import JavaSettings from '@/components/ui/instance_settings/JavaSettings.vue'
|
||||
import WindowSettings from '@/components/ui/instance_settings/WindowSettings.vue'
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import { get_project_v3 } from '@/helpers/cache'
|
||||
import { get_linked_modpack_info } from '@/helpers/profile'
|
||||
import { provideInstanceSettings } from '@/providers/instance-settings'
|
||||
|
||||
import type { InstanceSettingsTabProps } from '../../../helpers/types'
|
||||
import type { GameInstance } from '../../../helpers/types'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const props = defineProps<InstanceSettingsTabProps>()
|
||||
const props = defineProps<{
|
||||
instance: GameInstance
|
||||
offline?: boolean
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
unlinked: []
|
||||
}>()
|
||||
|
||||
const tabs: TabbedModalTab<InstanceSettingsTabProps>[] = [
|
||||
const isMinecraftServer = ref(false)
|
||||
const handleUnlinked = () => emit('unlinked')
|
||||
|
||||
const instanceRef = computed(() => props.instance)
|
||||
|
||||
provideInstanceSettings({
|
||||
instance: instanceRef,
|
||||
offline: props.offline,
|
||||
isMinecraftServer,
|
||||
onUnlinked: handleUnlinked,
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.instance,
|
||||
(instance) => {
|
||||
isMinecraftServer.value = false
|
||||
if (instance.linked_data?.project_id) {
|
||||
get_project_v3(instance.linked_data.project_id, 'must_revalidate')
|
||||
.then((project: Labrinth.Projects.v3.Project | undefined) => {
|
||||
if (project?.minecraft_server != null) {
|
||||
isMinecraftServer.value = true
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const tabs = computed<TabbedModalTab[]>(() => [
|
||||
{
|
||||
name: defineMessage({
|
||||
id: 'instance.settings.tabs.general',
|
||||
@@ -72,18 +111,33 @@ const tabs: TabbedModalTab<InstanceSettingsTabProps>[] = [
|
||||
icon: CodeIcon,
|
||||
content: HooksSettings,
|
||||
},
|
||||
]
|
||||
])
|
||||
|
||||
const modal = ref()
|
||||
const queryClient = useQueryClient()
|
||||
const tabbedModal = ref<InstanceType<typeof TabbedModal> | null>(null)
|
||||
|
||||
function show() {
|
||||
modal.value.show()
|
||||
function show(tabIndex?: number) {
|
||||
if (props.instance.linked_data?.project_id) {
|
||||
queryClient.prefetchQuery({
|
||||
queryKey: ['linkedModpackInfo', props.instance.path],
|
||||
queryFn: () => get_linked_modpack_info(props.instance.path, 'stale_while_revalidate'),
|
||||
})
|
||||
}
|
||||
tabbedModal.value?.show()
|
||||
if (tabIndex !== undefined) {
|
||||
nextTick(() => tabbedModal.value?.setTab(tabIndex))
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ show })
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
<TabbedModal
|
||||
ref="tabbedModal"
|
||||
:tabs="tabs"
|
||||
:max-width="'min(928px, calc(95vw - 10rem))'"
|
||||
:width="'min(928px, calc(95vw - 10rem))'"
|
||||
>
|
||||
<template #title>
|
||||
<span class="flex items-center gap-2 text-lg font-semibold text-primary">
|
||||
<Avatar
|
||||
@@ -97,7 +151,5 @@ defineExpose({ show })
|
||||
}}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<TabbedModal :tabs="tabs.map((tab) => ({ ...tab, props }))" />
|
||||
</ModalWrapper>
|
||||
</TabbedModal>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
<!-- @deprecated Use NewModal from @modrinth/ui directly. Ads/noblur now handled by injectModalBehavior. -->
|
||||
<script setup lang="ts">
|
||||
import { NewModal as Modal } from '@modrinth/ui'
|
||||
import { useTemplateRef } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { useTheming } from '@/store/theme.ts'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
const props = defineProps({
|
||||
header: {
|
||||
type: String,
|
||||
@@ -26,6 +22,7 @@ const props = defineProps({
|
||||
return () => {}
|
||||
},
|
||||
},
|
||||
/** @deprecated No longer used — ads are handled by provideModalBehavior */
|
||||
showAdOnClose: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@@ -35,31 +32,21 @@ const modal = useTemplateRef('modal')
|
||||
|
||||
defineExpose({
|
||||
show: (e: MouseEvent) => {
|
||||
hide_ads_window()
|
||||
modal.value?.show(e)
|
||||
},
|
||||
hide: () => {
|
||||
onModalHide()
|
||||
modal.value?.hide()
|
||||
},
|
||||
})
|
||||
|
||||
function onModalHide() {
|
||||
if (props.showAdOnClose) {
|
||||
show_ads_window()
|
||||
}
|
||||
props.onHide?.()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
ref="modal"
|
||||
:header="header"
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
:closable="closable"
|
||||
:hide-header="hideHeader"
|
||||
@hide="onModalHide"
|
||||
:on-hide="() => props.onHide?.()"
|
||||
>
|
||||
<template #title>
|
||||
<slot name="title" />
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.header)" fade="warning" max-width="500px">
|
||||
<p class="m-0 text-secondary">
|
||||
<IntlFormatted :message-id="messages.body" :values="{ instanceName }">
|
||||
<template #bold="{ children }">
|
||||
<span class="font-medium text-contrast"><component :is="() => children" /></span>
|
||||
</template>
|
||||
</IntlFormatted>
|
||||
</p>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!border !border-surface-4" @click="handleCancel">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="handleGoToInstance">
|
||||
{{ formatMessage(messages.instance) }}
|
||||
<RightArrowIcon />
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="orange">
|
||||
<button @click="handleCreateAnyway">
|
||||
<PlusIcon />
|
||||
{{ formatMessage(messages.create) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PlusIcon, RightArrowIcon, XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const messages = defineMessages({
|
||||
header: {
|
||||
id: 'app.instance.modpack-already-installed.header',
|
||||
defaultMessage: 'Modpack already installed',
|
||||
},
|
||||
body: {
|
||||
id: 'app.instance.modpack-already-installed.body',
|
||||
defaultMessage:
|
||||
'This modpack is already installed in the <bold>{instanceName}</bold> instance. Are you sure you want to duplicate it?',
|
||||
},
|
||||
instance: {
|
||||
id: 'app.instance.modpack-already-installed.instance',
|
||||
defaultMessage: 'Instance',
|
||||
},
|
||||
create: {
|
||||
id: 'app.instance.modpack-already-installed.create',
|
||||
defaultMessage: 'Create',
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'go-to-instance', instancePath: string): void
|
||||
(e: 'create-anyway'): void
|
||||
}>()
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const instanceName = ref('')
|
||||
const instancePath = ref('')
|
||||
|
||||
function show(name: string, path: string) {
|
||||
instanceName.value = name
|
||||
instancePath.value = path
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
function handleGoToInstance() {
|
||||
modal.value?.hide()
|
||||
emit('go-to-instance', instancePath.value)
|
||||
}
|
||||
|
||||
function handleCreateAnyway() {
|
||||
modal.value?.hide()
|
||||
emit('create-anyway')
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
})
|
||||
</script>
|
||||
@@ -1,12 +1,8 @@
|
||||
<!-- @deprecated Use ShareModal from @modrinth/ui directly. Ads/noblur now handled by injectModalBehavior. -->
|
||||
<script setup lang="ts">
|
||||
import { ShareModal } from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import { hide_ads_window, show_ads_window } from '@/helpers/ads.js'
|
||||
import { useTheming } from '@/store/theme.ts'
|
||||
|
||||
const themeStore = useTheming()
|
||||
|
||||
defineProps({
|
||||
header: {
|
||||
type: String,
|
||||
@@ -34,18 +30,12 @@ const modal = ref(null)
|
||||
|
||||
defineExpose({
|
||||
show: (passedContent) => {
|
||||
hide_ads_window()
|
||||
modal.value.show(passedContent)
|
||||
},
|
||||
hide: () => {
|
||||
onModalHide()
|
||||
modal.value.hide()
|
||||
},
|
||||
})
|
||||
|
||||
function onModalHide() {
|
||||
show_ads_window()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -56,7 +46,5 @@ function onModalHide() {
|
||||
:share-text="shareText"
|
||||
:link="link"
|
||||
:open-in-new-tab="openInNewTab"
|
||||
:on-hide="onModalHide"
|
||||
:noblur="!themeStore.advancedRendering"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,119 +1,39 @@
|
||||
<template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.updateToPlay)" :closable="true" no-padding>
|
||||
<div class="max-w-[500px]">
|
||||
<div class="flex flex-col gap-4 p-4">
|
||||
<Admonition type="warning" :header="formatMessage(messages.updateRequired)">
|
||||
{{ formatMessage(messages.updateRequiredDescription, { name: instance.name }) }}
|
||||
</Admonition>
|
||||
|
||||
<div v-if="diffs.length" class="flex flex-col gap-2">
|
||||
<span v-if="publishedDate" class="text-contrast font-semibold">{{
|
||||
formatMessage(messages.publishedDate, { date: publishedDate })
|
||||
}}</span>
|
||||
<div class="flex gap-2">
|
||||
<div v-if="removedCount" class="flex gap-1 items-center">
|
||||
<MinusIcon />
|
||||
{{ formatMessage(messages.removedCount, { count: removedCount }) }}
|
||||
</div>
|
||||
<div v-if="addedCount" class="flex gap-1 items-center">
|
||||
<PlusIcon />
|
||||
{{ formatMessage(messages.addedCount, { count: addedCount }) }}
|
||||
</div>
|
||||
<div v-if="updatedCount" class="flex gap-1 items-center">
|
||||
<RefreshCwIcon />
|
||||
{{ formatMessage(messages.updatedCount, { count: updatedCount }) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="diffs.length" class="flex flex-col bg-surface-2 p-4 max-h-[272px] overflow-y-auto">
|
||||
<div
|
||||
v-for="diff in diffs"
|
||||
:key="diff.project_id"
|
||||
class="grid grid-cols-[auto_1fr_1fr_1fr] items-center min-h-10 h-10 gap-2"
|
||||
>
|
||||
<div class="flex flex-col justify-between items-center">
|
||||
<div class="w-[1px] h-2"></div>
|
||||
<PlusIcon v-if="diff.type === 'added'" />
|
||||
<MinusIcon v-else-if="diff.type === 'removed'" />
|
||||
<RefreshCwIcon v-else />
|
||||
<div class="bg-surface-5 w-[1px] h-2 relative top-1"></div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-1 col-span-2">
|
||||
<span class="text-sm">{{ formatMessage(diffTypeMessages[diff.type]) }}</span>
|
||||
<span
|
||||
v-if="diff.project"
|
||||
v-tooltip="diff.project.title"
|
||||
class="text-sm text-contrast font-medium truncate"
|
||||
>
|
||||
{{ diff.project.title }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
v-if="getFilename(diff.newVersion) || getFilename(diff.currentVersion)"
|
||||
v-tooltip="getFilename(diff.newVersion) || getFilename(diff.currentVersion)"
|
||||
class="text-xs truncate text-right"
|
||||
>
|
||||
{{ getFilename(diff.newVersion) || getFilename(diff.currentVersion) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
<div class="flex justify-between gap-2">
|
||||
<ButtonStyled color="red" type="transparent">
|
||||
<button @click="handleReport">
|
||||
<ReportIcon />
|
||||
{{ formatMessage(commonMessages.reportButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<div class="flex gap-2">
|
||||
<ButtonStyled>
|
||||
<button @click="handleDecline">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button @click="handleUpdate">
|
||||
<DownloadIcon />
|
||||
{{ formatMessage(commonMessages.updateButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
<ContentDiffModal
|
||||
ref="diffModal"
|
||||
:header="formatMessage(messages.updateToPlay)"
|
||||
:admonition-header="formatMessage(messages.updateRequired)"
|
||||
:description="
|
||||
instance ? formatMessage(messages.updateRequiredDescription, { name: instance.name }) : ''
|
||||
"
|
||||
:diffs="normalizedDiffs"
|
||||
:confirm-label="formatMessage(commonMessages.updateButton)"
|
||||
:confirm-icon="DownloadIcon"
|
||||
:show-report-button="true"
|
||||
@confirm="handleUpdate"
|
||||
@cancel="handleDecline"
|
||||
@report="handleReport"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Labrinth } from '@modrinth/api-client'
|
||||
import { DownloadIcon } from '@modrinth/assets'
|
||||
import {
|
||||
DownloadIcon,
|
||||
MinusIcon,
|
||||
PlusIcon,
|
||||
RefreshCwIcon,
|
||||
ReportIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
type ContentDiffItem,
|
||||
ContentDiffModal,
|
||||
defineMessages,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { openUrl } from '@tauri-apps/plugin-opener'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { get_project, get_project_many, get_version_many } from '@/helpers/cache.js'
|
||||
import { get_project_many, get_version, get_version_many } from '@/helpers/cache.js'
|
||||
import { update_managed_modrinth_version } from '@/helpers/profile'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
import { injectServerInstall } from '@/providers/server-install'
|
||||
|
||||
type Dependency = Labrinth.Versions.v3.Dependency
|
||||
type Version = Labrinth.Versions.v2.Version
|
||||
@@ -129,6 +49,7 @@ interface BaseDiff {
|
||||
newVersionId?: string
|
||||
currentVersion?: Version
|
||||
newVersion?: Version
|
||||
fileName?: string
|
||||
}
|
||||
interface AddedDiff extends BaseDiff {
|
||||
type: 'added'
|
||||
@@ -151,44 +72,52 @@ type ProjectInfo = {
|
||||
slug: string
|
||||
}
|
||||
|
||||
const { instance } = defineProps<{
|
||||
instance: GameInstance
|
||||
}>()
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const { startInstallingServer, stopInstallingServer } = injectServerInstall()
|
||||
type UpdateCompleteCallback = () => void | Promise<void>
|
||||
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
const diffModal = ref<InstanceType<typeof ContentDiffModal>>()
|
||||
const instance = ref<GameInstance | null>(null)
|
||||
const onUpdateComplete = ref<UpdateCompleteCallback>(() => {})
|
||||
const diffs = ref<DependencyDiff[]>([])
|
||||
const latestVersionId = ref<string | null>(null)
|
||||
const latestVersion = ref<Version | null>(null)
|
||||
const modpackVersionId = ref<string | null>(null)
|
||||
const modpackVersion = ref<Version | null>(null)
|
||||
|
||||
const removedCount = computed(() => diffs.value.filter((d) => d.type === 'removed').length)
|
||||
const addedCount = computed(() => diffs.value.filter((d) => d.type === 'added').length)
|
||||
const updatedCount = computed(() => diffs.value.filter((d) => d.type === 'updated').length)
|
||||
const publishedDate = computed(() =>
|
||||
latestVersion.value?.date_published ? new Date(latestVersion.value.date_published) : null,
|
||||
const normalizedDiffs = computed<ContentDiffItem[]>(() =>
|
||||
diffs.value.map((diff) => ({
|
||||
type: diff.type,
|
||||
projectName: diff.project?.title,
|
||||
fileName: diff.fileName,
|
||||
currentVersionName: diff.currentVersion?.version_number,
|
||||
newVersionName: diff.newVersion?.version_number,
|
||||
})),
|
||||
)
|
||||
|
||||
function getFilename(version?: Version): string | undefined {
|
||||
return version?.files.find((f) => f.primary)?.filename
|
||||
}
|
||||
|
||||
async function computeDependencyDiffs(
|
||||
currentDeps: Dependency[],
|
||||
latestDeps: Dependency[],
|
||||
): Promise<DependencyDiff[]> {
|
||||
console.log('Computing dependency diffs', { currentDeps, latestDeps })
|
||||
|
||||
// Separate deps with project_id from file_name-only deps
|
||||
const currentWithProject = currentDeps.filter((d) => d.project_id)
|
||||
const latestWithProject = latestDeps.filter((d) => d.project_id)
|
||||
const currentFileOnly = currentDeps.filter((d) => !d.project_id && d.file_name)
|
||||
const latestFileOnly = latestDeps.filter((d) => !d.project_id && d.file_name)
|
||||
|
||||
const currentByProject = new Map<string, Dependency>(
|
||||
currentDeps.map((d) => [d.project_id || '', d]),
|
||||
currentWithProject.map((d) => [d.project_id!, d]),
|
||||
)
|
||||
const latestByProject = new Map<string, Dependency>(
|
||||
latestDeps.map((d) => [d.project_id || '', d]),
|
||||
latestWithProject.map((d) => [d.project_id!, d]),
|
||||
)
|
||||
const currentFilenames = new Set(currentFileOnly.map((d) => d.file_name!))
|
||||
const latestFilenames = new Set(latestFileOnly.map((d) => d.file_name!))
|
||||
|
||||
const diffs: DependencyDiff[] = []
|
||||
|
||||
// Find added and updated dependencies
|
||||
// Find added and updated dependencies (by project_id)
|
||||
latestByProject.forEach((latestDep, projectId) => {
|
||||
if (!projectId) return
|
||||
const currentDep = currentByProject.get(projectId)
|
||||
if (!currentDep && latestDep.version_id) {
|
||||
diffs.push({ type: 'added', project_id: projectId, newVersionId: latestDep.version_id })
|
||||
@@ -206,9 +135,8 @@ async function computeDependencyDiffs(
|
||||
}
|
||||
})
|
||||
|
||||
// Find removed dependencies
|
||||
// Find removed dependencies (by project_id)
|
||||
currentByProject.forEach((currentDep, projectId) => {
|
||||
if (!projectId) return
|
||||
if (!latestByProject.has(projectId)) {
|
||||
diffs.push({
|
||||
type: 'removed',
|
||||
@@ -218,6 +146,19 @@ async function computeDependencyDiffs(
|
||||
}
|
||||
})
|
||||
|
||||
// Find added/removed file_name-only dependencies
|
||||
// ideally in future, this should use the hash of the file instead of filename, but since version dependencies don't include file hashes, we'll use filename as a best effort approach
|
||||
for (const fileName of latestFilenames) {
|
||||
if (!currentFilenames.has(fileName)) {
|
||||
diffs.push({ type: 'added', project_id: '', newVersionId: '' as string, fileName })
|
||||
}
|
||||
}
|
||||
for (const fileName of currentFilenames) {
|
||||
if (!latestFilenames.has(fileName)) {
|
||||
diffs.push({ type: 'removed', project_id: '', fileName })
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch projects and versions of diffs
|
||||
const allProjectIds = [...new Set(diffs.map((d) => d.project_id).filter(Boolean))]
|
||||
const allVersionIds = [
|
||||
@@ -228,14 +169,14 @@ async function computeDependencyDiffs(
|
||||
),
|
||||
] as string[]
|
||||
const [projects, versions] = await Promise.all([
|
||||
get_project_many(allProjectIds, 'must_revalidate'),
|
||||
get_version_many(allVersionIds, 'must_revalidate'),
|
||||
get_project_many(allProjectIds, 'bypass'),
|
||||
get_version_many(allVersionIds, 'bypass'),
|
||||
])
|
||||
|
||||
const projectMap = new Map<string, ProjectInfo>(projects.map((p: ProjectInfo) => [p.id, p]))
|
||||
const versionMap = new Map<string, Version>(versions.map((v: Version) => [v.id, v]))
|
||||
|
||||
return diffs
|
||||
const mappedDiffs = diffs
|
||||
.map((diff) => {
|
||||
const project = projectMap.get(diff.project_id)
|
||||
return {
|
||||
@@ -248,7 +189,7 @@ async function computeDependencyDiffs(
|
||||
}
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const typeOrder = { removed: 0, added: 1, updated: 2 }
|
||||
const typeOrder = { added: 0, updated: 1, removed: 2 }
|
||||
const typeCompare = typeOrder[a.type] - typeOrder[b.type]
|
||||
if (typeCompare !== 0) return typeCompare
|
||||
|
||||
@@ -256,34 +197,26 @@ async function computeDependencyDiffs(
|
||||
const bDate = b.newVersion?.date_published || b.currentVersion?.date_published || ''
|
||||
return dayjs(bDate).valueOf() - dayjs(aDate).valueOf()
|
||||
})
|
||||
.filter((d) => d.project || d.fileName) // filter out any diffs that couldn't be matched to a project or file
|
||||
return mappedDiffs
|
||||
}
|
||||
|
||||
async function checkUpdateAvailable(instance: GameInstance): Promise<DependencyDiff[] | null> {
|
||||
if (!instance.linked_data) return null
|
||||
async function checkUpdateAvailable(inst: GameInstance): Promise<DependencyDiff[] | null> {
|
||||
if (!inst.linked_data) return null
|
||||
if (!modpackVersionId.value || !inst.linked_data.version_id) return null
|
||||
|
||||
try {
|
||||
const project = await get_project(instance.linked_data.project_id, 'must_revalidate')
|
||||
if (!project || !project.versions || project.versions.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const versions = await get_version_many(project.versions, 'must_revalidate')
|
||||
const sortedVersions = versions.sort(
|
||||
(a: { date_published: string }, b: { date_published: string }) =>
|
||||
dayjs(b.date_published).valueOf() - dayjs(a.date_published).valueOf(),
|
||||
)
|
||||
|
||||
latestVersion.value = sortedVersions[0]
|
||||
latestVersionId.value = latestVersion.value?.id || null
|
||||
|
||||
const currentVersionId = instance.linked_data.version_id
|
||||
const currentVersion = versions.find((v: { id: string }) => v.id === currentVersionId)
|
||||
// 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.
|
||||
modpackVersion.value = await get_version(modpackVersionId.value, 'bypass')
|
||||
const instanceModpackVersion = await get_version(inst.linked_data.version_id, 'bypass')
|
||||
|
||||
// Compute dependency diffs between current and latest version
|
||||
if (currentVersion && latestVersion.value) {
|
||||
if (instanceModpackVersion && modpackVersion.value) {
|
||||
return await computeDependencyDiffs(
|
||||
currentVersion.dependencies || [],
|
||||
latestVersion.value.dependencies || [],
|
||||
instanceModpackVersion.dependencies || [],
|
||||
modpackVersion.value.dependencies || [],
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -294,9 +227,10 @@ async function checkUpdateAvailable(instance: GameInstance): Promise<DependencyD
|
||||
}
|
||||
|
||||
watch(
|
||||
() => instance,
|
||||
async () => {
|
||||
const result = await checkUpdateAvailable(instance)
|
||||
() => instance.value,
|
||||
async (newInstance) => {
|
||||
if (!newInstance) return
|
||||
const result = await checkUpdateAvailable(newInstance)
|
||||
diffs.value = result || []
|
||||
},
|
||||
{ immediate: true, deep: true },
|
||||
@@ -304,18 +238,25 @@ watch(
|
||||
|
||||
async function handleUpdate() {
|
||||
hide()
|
||||
const serverProjectId = instance.value?.linked_data?.project_id
|
||||
if (serverProjectId) startInstallingServer(serverProjectId)
|
||||
try {
|
||||
if (latestVersionId.value) {
|
||||
await update_managed_modrinth_version(instance.path, latestVersionId.value)
|
||||
if (modpackVersionId.value && instance.value) {
|
||||
await update_managed_modrinth_version(instance.value.path, modpackVersionId.value)
|
||||
await onUpdateComplete.value()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating instance:', error)
|
||||
} finally {
|
||||
if (serverProjectId) stopInstallingServer(serverProjectId)
|
||||
}
|
||||
}
|
||||
|
||||
function handleReport() {
|
||||
if (instance.linked_data?.project_id) {
|
||||
openUrl(`https://modrinth.com/report?item=project&itemID=${instance.linked_data.project_id}`)
|
||||
if (instance.value?.linked_data?.project_id) {
|
||||
openUrl(
|
||||
`https://modrinth.com/report?item=project&itemID=${instance.value.linked_data.project_id}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,12 +264,20 @@ function handleDecline() {
|
||||
hide()
|
||||
}
|
||||
|
||||
function show(e?: MouseEvent) {
|
||||
modal.value?.show(e)
|
||||
function show(
|
||||
instanceVal: GameInstance,
|
||||
modpackVersionIdVal: string | null = null,
|
||||
callback: UpdateCompleteCallback = () => {},
|
||||
e?: MouseEvent,
|
||||
) {
|
||||
instance.value = instanceVal
|
||||
modpackVersionId.value = modpackVersionIdVal
|
||||
onUpdateComplete.value = callback
|
||||
diffModal.value?.show(e)
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value?.hide()
|
||||
diffModal.value?.hide()
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -345,38 +294,15 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'An update is required to play {name}. Please update to the latest version to launch the game.',
|
||||
},
|
||||
publishedDate: {
|
||||
id: 'app.modal.update-to-play.published-date',
|
||||
defaultMessage: '{date, date, long}',
|
||||
},
|
||||
removedCount: {
|
||||
id: 'app.modal.update-to-play.removed-count',
|
||||
defaultMessage: '{count} removed',
|
||||
},
|
||||
addedCount: {
|
||||
id: 'app.modal.update-to-play.added-count',
|
||||
defaultMessage: '{count} added',
|
||||
},
|
||||
updatedCount: {
|
||||
id: 'app.modal.update-to-play.updated-count',
|
||||
defaultMessage: '{count} updated',
|
||||
},
|
||||
})
|
||||
|
||||
const diffTypeMessages = defineMessages({
|
||||
added: {
|
||||
id: 'app.modal.update-to-play.diff-type.added',
|
||||
defaultMessage: 'Added',
|
||||
},
|
||||
removed: {
|
||||
id: 'app.modal.update-to-play.diff-type.removed',
|
||||
defaultMessage: 'Removed',
|
||||
},
|
||||
updated: {
|
||||
id: 'app.modal.update-to-play.diff-type.updated',
|
||||
defaultMessage: 'Updated',
|
||||
},
|
||||
const hasUpdate = computed(() => {
|
||||
if (!instance.value?.linked_data) return false
|
||||
return (
|
||||
modpackVersionId.value != null &&
|
||||
modpackVersionId.value !== instance.value.linked_data.version_id
|
||||
)
|
||||
})
|
||||
|
||||
defineExpose({ show, hide })
|
||||
defineExpose({ show, hide, hasUpdate })
|
||||
</script>
|
||||
|
||||
@@ -21,7 +21,7 @@ watch(
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Color theme</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Color theme</h2>
|
||||
<p class="m-0 mt-1">Select your preferred color theme for Modrinth App.</p>
|
||||
|
||||
<ThemeSelector
|
||||
@@ -36,9 +36,9 @@ watch(
|
||||
system-theme-color="system"
|
||||
/>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Advanced rendering</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Advanced rendering</h2>
|
||||
<p class="m-0 mt-1">
|
||||
Enables advanced rendering such as blur effects that may cause performance issues without
|
||||
hardware-accelerated rendering.
|
||||
@@ -57,48 +57,48 @@ watch(
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Hide nametag</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Hide nametag</h2>
|
||||
<p class="m-0 mt-1">Disables the nametag above your player on the skins page.</p>
|
||||
</div>
|
||||
<Toggle id="hide-nametag-skins-page" v-model="settings.hide_nametag_skins_page" />
|
||||
</div>
|
||||
|
||||
<div v-if="os !== 'MacOS'" class="mt-4 flex items-center justify-between gap-4">
|
||||
<div v-if="os !== 'MacOS'" class="mt-6 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Native decorations</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Native decorations</h2>
|
||||
<p class="m-0 mt-1">Use system window frame (app restart required).</p>
|
||||
</div>
|
||||
<Toggle id="native-decorations" v-model="settings.native_decorations" />
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Minimize launcher</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Minimize launcher</h2>
|
||||
<p class="m-0 mt-1">Minimize the launcher when a Minecraft process starts.</p>
|
||||
</div>
|
||||
<Toggle id="minimize-launcher" v-model="settings.hide_on_process_start" />
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Default landing page</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Default landing page</h2>
|
||||
<p class="m-0 mt-1">Change the page to which the launcher opens on.</p>
|
||||
</div>
|
||||
<Combobox
|
||||
id="opening-page"
|
||||
v-model="settings.default_page"
|
||||
name="Opening page dropdown"
|
||||
class="w-40"
|
||||
class="max-w-40"
|
||||
:options="['Home', 'Library'].map((v) => ({ value: v, label: v }))"
|
||||
:display-value="settings.default_page ?? 'Select an option'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Jump back into worlds</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Jump back into worlds</h2>
|
||||
<p class="m-0 mt-1">Includes recent worlds in the "Jump back in" section on the Home page.</p>
|
||||
</div>
|
||||
<Toggle
|
||||
@@ -113,9 +113,9 @@ watch(
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="mt-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Toggle sidebar</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Toggle sidebar</h2>
|
||||
<p class="m-0 mt-1">Enables the ability to toggle the sidebar.</p>
|
||||
</div>
|
||||
<Toggle
|
||||
|
||||
@@ -52,127 +52,135 @@ watch(
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Window size</h2>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="m-0 text-lg font-semibold text-contrast">Fullscreen</h3>
|
||||
<p class="m-0 leading-tight">
|
||||
Overwrites the options.txt file to start in full screen when launched.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Fullscreen</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
Overwrites the options.txt file to start in full screen when launched.
|
||||
</p>
|
||||
<Toggle id="fullscreen" v-model="settings.force_fullscreen" />
|
||||
</div>
|
||||
|
||||
<Toggle id="fullscreen" v-model="settings.force_fullscreen" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="m-0 text-lg font-semibold text-contrast">Width</h3>
|
||||
<p class="m-0 leading-tight">The width of the game window when launched.</p>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Width</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
The width of the game window when launched.
|
||||
</p>
|
||||
<StyledInput
|
||||
id="width"
|
||||
v-model="settings.game_resolution[0]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
placeholder="Enter width..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<StyledInput
|
||||
id="width"
|
||||
v-model="settings.game_resolution[0]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
placeholder="Enter width..."
|
||||
/>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h3 class="m-0 text-lg font-semibold text-contrast">Height</h3>
|
||||
<p class="m-0 leading-tight">The height of the game window when launched.</p>
|
||||
</div>
|
||||
|
||||
<StyledInput
|
||||
id="height"
|
||||
v-model="settings.game_resolution[1]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
placeholder="Enter height..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Height</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
The height of the game window when launched.
|
||||
</p>
|
||||
<hr class="my-6 bg-button-border border-none h-[1px]" />
|
||||
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Memory allocated</h2>
|
||||
<Slider
|
||||
id="max-memory"
|
||||
v-model="settings.memory.maximum"
|
||||
:min="512"
|
||||
:max="maxMemory"
|
||||
:step="64"
|
||||
:snap-points="snapPoints"
|
||||
:snap-range="512"
|
||||
unit="MB"
|
||||
/>
|
||||
<p class="m-0 mt-1 leading-tight">The memory allocated to each instance when it is ran.</p>
|
||||
</div>
|
||||
|
||||
<StyledInput
|
||||
id="height"
|
||||
v-model="settings.game_resolution[1]"
|
||||
:disabled="settings.force_fullscreen"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
placeholder="Enter height..."
|
||||
/>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Java arguments</h2>
|
||||
<StyledInput
|
||||
id="java-args"
|
||||
v-model="settings.launchArgs"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter java arguments..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Environmental variables</h2>
|
||||
<StyledInput
|
||||
id="env-vars"
|
||||
v-model="settings.envVars"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter environmental variables..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="mt-4 bg-button-border border-none h-[1px]" />
|
||||
<hr class="my-6 bg-button-border border-none h-[1px]" />
|
||||
|
||||
<h2 class="mt-4 m-0 text-lg font-extrabold text-contrast">Memory allocated</h2>
|
||||
<p class="m-0 mt-1 leading-tight">The memory allocated to each instance when it is ran.</p>
|
||||
<Slider
|
||||
id="max-memory"
|
||||
v-model="settings.memory.maximum"
|
||||
:min="512"
|
||||
:max="maxMemory"
|
||||
:step="64"
|
||||
:snap-points="snapPoints"
|
||||
:snap-range="512"
|
||||
unit="MB"
|
||||
/>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h3 class="m-0 text-lg font-semibold text-contrast">Pre launch hook</h3>
|
||||
<StyledInput
|
||||
id="pre-launch"
|
||||
v-model="settings.hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter pre-launch command..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<p class="m-0 leading-tight">Ran before the instance is launched.</p>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4 mb-2 text-lg font-extrabold text-contrast">Java arguments</h2>
|
||||
<StyledInput
|
||||
id="java-args"
|
||||
v-model="settings.launchArgs"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter java arguments..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h3 class="m-0 text-lg font-semibold text-contrast">Wrapper hook</h3>
|
||||
<StyledInput
|
||||
id="wrapper"
|
||||
v-model="settings.hooks.wrapper"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter wrapper command..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<p class="m-0 leading-tight">Wrapper command for launching Minecraft.</p>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4 mb-2 text-lg font-extrabold text-contrast">Environmental variables</h2>
|
||||
<StyledInput
|
||||
id="env-vars"
|
||||
v-model="settings.envVars"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter environmental variables..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<hr class="mt-4 bg-button-border border-none h-[1px]" />
|
||||
|
||||
<h2 class="mt-4 m-0 text-lg font-extrabold text-contrast">Hooks</h2>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Pre launch</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">Ran before the instance is launched.</p>
|
||||
<StyledInput
|
||||
id="pre-launch"
|
||||
v-model="settings.hooks.pre_launch"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter pre-launch command..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Wrapper</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
Wrapper command for launching Minecraft.
|
||||
</p>
|
||||
<StyledInput
|
||||
id="wrapper"
|
||||
v-model="settings.hooks.wrapper"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter wrapper command..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
|
||||
<h3 class="mt-2 m-0 text-base font-extrabold text-primary">Post exit</h3>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">Ran after the game closes.</p>
|
||||
<StyledInput
|
||||
id="post-exit"
|
||||
v-model="settings.hooks.post_exit"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter post-exit command..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h3 class="m-0 text-lg font-semibold text-contrast">Post exit hook</h3>
|
||||
<StyledInput
|
||||
id="post-exit"
|
||||
v-model="settings.hooks.post_exit"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
placeholder="Enter post-exit command..."
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<p class="m-0 leading-tight">Ran after the game closes.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { Toggle } from '@modrinth/ui'
|
||||
import { ButtonStyled, Toggle } from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
|
||||
import { get as getSettings, set as setSettings } from '@/helpers/settings.ts'
|
||||
@@ -25,17 +25,28 @@ watch(
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<div v-for="option in options" :key="option" class="mt-4 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast capitalize">
|
||||
{{ option.replaceAll('_', ' ') }}
|
||||
</h2>
|
||||
<div class="flex flex-col gap-2.5 min-w-[600px]">
|
||||
<div v-for="option in options" :key="option" class="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast capitalize">
|
||||
{{ option.replaceAll('_', ' ') }}
|
||||
</h2>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<ButtonStyled type="transparent">
|
||||
<button
|
||||
:disabled="themeStore.getFeatureFlag(option) === DEFAULT_FEATURE_FLAGS[option]"
|
||||
@click="setFeatureFlag(option, DEFAULT_FEATURE_FLAGS[option])"
|
||||
>
|
||||
Reset to default
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<Toggle
|
||||
id="advanced-rendering"
|
||||
:model-value="themeStore.getFeatureFlag(option)"
|
||||
@update:model-value="() => setFeatureFlag(option, !themeStore.getFeatureFlag(option))"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Toggle
|
||||
id="advanced-rendering"
|
||||
:model-value="themeStore.getFeatureFlag(option)"
|
||||
@update:model-value="() => setFeatureFlag(option, !themeStore.getFeatureFlag(option))"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -21,15 +21,21 @@ async function updateJavaVersion(version) {
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div v-for="(javaVersion, index) in [25, 21, 17, 8]" :key="`java-${javaVersion}`">
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast" :class="{ 'mt-4': index !== 0 }">
|
||||
Java {{ javaVersion }} location
|
||||
</h2>
|
||||
<JavaSelector
|
||||
:id="'java-selector-' + javaVersion"
|
||||
v-model="javaVersions[javaVersion]"
|
||||
:version="javaVersion"
|
||||
@update:model-value="updateJavaVersion"
|
||||
/>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div
|
||||
v-for="(javaVersion, index) in [25, 21, 17, 8]"
|
||||
:key="`java-${javaVersion}`"
|
||||
class="flex flex-col gap-2.5"
|
||||
>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast" :class="{ 'mt-4': index !== 0 }">
|
||||
Java {{ javaVersion }} location
|
||||
</h2>
|
||||
<JavaSelector
|
||||
:id="'java-selector-' + javaVersion"
|
||||
v-model="javaVersions[javaVersion]"
|
||||
:version="javaVersion"
|
||||
@update:model-value="updateJavaVersion"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,14 +8,14 @@ import {
|
||||
LOCALES,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref, watch } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
|
||||
import { get, set } from '@/helpers/settings.ts'
|
||||
import i18n from '@/i18n.config'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const platform = formatMessage(languageSelectorMessages.platformApp)
|
||||
const platform = computed(() => formatMessage(languageSelectorMessages.platformApp))
|
||||
|
||||
const settings = ref(await get())
|
||||
|
||||
@@ -43,7 +43,7 @@ async function onLocaleChange(newLocale: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Language</h2>
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Language</h2>
|
||||
|
||||
<Admonition type="warning" class="mt-2 mb-4">
|
||||
{{ formatMessage(languageSelectorMessages.languageWarning, { platform }) }}
|
||||
|
||||
@@ -25,8 +25,8 @@ watch(
|
||||
<template>
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Personalized ads</h2>
|
||||
<p class="m-0 text-sm">
|
||||
<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>
|
||||
@@ -36,8 +36,8 @@ watch(
|
||||
|
||||
<div class="mt-4 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Telemetry</h2>
|
||||
<p class="m-0 text-sm">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Telemetry</h2>
|
||||
<p class="m-0 mt-1 text-sm">
|
||||
Modrinth collects anonymized analytics and usage data to improve our user experience and
|
||||
customize your experience. By disabling this option, you opt out and your data will no
|
||||
longer be collected.
|
||||
@@ -48,8 +48,8 @@ watch(
|
||||
|
||||
<div class="mt-4 flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">Discord RPC</h2>
|
||||
<p class="m-0 text-sm">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">Discord RPC</h2>
|
||||
<p class="m-0 mt-1 text-sm">
|
||||
Manages the Discord Rich Presence integration. Disabling this will cause 'Modrinth' to no
|
||||
longer show up as a game or app you are using on your Discord profile.
|
||||
</p>
|
||||
|
||||
@@ -28,10 +28,12 @@ watch(
|
||||
async function purgeCache() {
|
||||
await purge_cache_types([
|
||||
'project',
|
||||
'project_v3',
|
||||
'version',
|
||||
'user',
|
||||
'team',
|
||||
'organization',
|
||||
'file',
|
||||
'loader_manifest',
|
||||
'minecraft_manifest',
|
||||
'categories',
|
||||
@@ -39,8 +41,10 @@ async function purgeCache() {
|
||||
'loaders',
|
||||
'game_versions',
|
||||
'donation_platforms',
|
||||
'file_hash',
|
||||
'file_update',
|
||||
'search_results',
|
||||
'search_results_v3',
|
||||
]).catch(handleError)
|
||||
}
|
||||
|
||||
@@ -58,67 +62,77 @@ async function findLauncherDir() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">App directory</h2>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
The directory where the launcher stores all of its files. Changes will be applied after
|
||||
restarting the launcher.
|
||||
</p>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast">App directory</h2>
|
||||
<StyledInput
|
||||
id="appDir"
|
||||
v-model="settings.custom_dir"
|
||||
:icon="BoxIcon"
|
||||
type="text"
|
||||
wrapper-class="w-full"
|
||||
>
|
||||
<template #right>
|
||||
<Button class="ml-1.5" @click="findLauncherDir">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
</template>
|
||||
</StyledInput>
|
||||
<p class="m-0 leading-tight text-secondary">
|
||||
The directory where the launcher stores all of its files. Changes will be applied after
|
||||
restarting the launcher.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="m-1 my-2">
|
||||
<StyledInput
|
||||
id="appDir"
|
||||
v-model="settings.custom_dir"
|
||||
:icon="BoxIcon"
|
||||
type="text"
|
||||
wrapper-class="w-full"
|
||||
>
|
||||
<template #right>
|
||||
<Button class="r-btn" @click="findLauncherDir">
|
||||
<FolderSearchIcon />
|
||||
</Button>
|
||||
</template>
|
||||
</StyledInput>
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<ConfirmModalWrapper
|
||||
ref="purgeCacheConfirmModal"
|
||||
title="Are you sure you want to purge the cache?"
|
||||
description="If you proceed, your entire cache will be purged. This may slow down the app temporarily."
|
||||
:has-to-type="false"
|
||||
proceed-label="Purge cache"
|
||||
:show-ad-on-close="false"
|
||||
@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()">
|
||||
<TrashIcon />
|
||||
Purge cache
|
||||
</button>
|
||||
<p class="m-0 leading-tight text-secondary">
|
||||
The Modrinth app stores a cache of data to speed up loading. This can be purged to force the
|
||||
app to reload data. This may slow down the app temporarily.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-2.5">
|
||||
<h2 class="m-0 text-lg font-semibold text-contrast mt-4">Maximum concurrent downloads</h2>
|
||||
<Slider
|
||||
id="max-downloads"
|
||||
v-model="settings.max_concurrent_downloads"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:step="1"
|
||||
/>
|
||||
<p class="m-0 leading-tight text-secondary">
|
||||
The maximum amount of files the launcher can download at the same time. Set this to a lower
|
||||
value if you have a poor internet connection. (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">Maximum concurrent writes</h2>
|
||||
<Slider
|
||||
id="max-writes"
|
||||
v-model="settings.max_concurrent_writes"
|
||||
:min="1"
|
||||
:max="50"
|
||||
:step="1"
|
||||
/>
|
||||
<p class="m-0 leading-tight text-secondary">
|
||||
The maximum amount of files the launcher can write to the disk at once. Set this to a lower
|
||||
value if you are frequently getting I/O errors. (app restart required to take effect)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ConfirmModalWrapper
|
||||
ref="purgeCacheConfirmModal"
|
||||
title="Are you sure you want to purge the cache?"
|
||||
description="If you proceed, your entire cache will be purged. This may slow down the app temporarily."
|
||||
:has-to-type="false"
|
||||
proceed-label="Purge cache"
|
||||
:show-ad-on-close="false"
|
||||
@proceed="purgeCache"
|
||||
/>
|
||||
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast">App cache</h2>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
The Modrinth app stores a cache of data to speed up loading. This can be purged to force the
|
||||
app to reload data. This may slow down the app temporarily.
|
||||
</p>
|
||||
</div>
|
||||
<button id="purge-cache" class="btn min-w-max" @click="$refs.purgeCacheConfirmModal.show()">
|
||||
<TrashIcon />
|
||||
Purge cache
|
||||
</button>
|
||||
|
||||
<h2 class="m-0 text-lg font-extrabold text-contrast mt-4">Maximum concurrent downloads</h2>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
The maximum amount of files the launcher can download at the same time. Set this to a lower
|
||||
value if you have a poor internet connection. (app restart required to take effect)
|
||||
</p>
|
||||
<Slider
|
||||
id="max-downloads"
|
||||
v-model="settings.max_concurrent_downloads"
|
||||
:min="1"
|
||||
:max="10"
|
||||
:step="1"
|
||||
/>
|
||||
|
||||
<h2 class="mt-4 m-0 text-lg font-extrabold text-contrast">Maximum concurrent writes</h2>
|
||||
<p class="m-0 mt-1 mb-2 leading-tight text-secondary">
|
||||
The maximum amount of files the launcher can write to the disk at once. Set this to a lower
|
||||
value if you are frequently getting I/O errors. (app restart required to take effect)
|
||||
</p>
|
||||
<Slider id="max-writes" v-model="settings.max_concurrent_writes" :min="1" :max="50" :step="1" />
|
||||
</template>
|
||||
|
||||
@@ -14,13 +14,13 @@ import {
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
SmartClickable,
|
||||
useFormatDateTime,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { capitalizeString } from '@modrinth/utils'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import type { Dayjs } from 'dayjs'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
@@ -36,6 +36,10 @@ import { handleSevereError } from '@/store/error'
|
||||
const { handleError } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatRelativeTime = useRelativeTime()
|
||||
const formatDateTime = useFormatDateTime({
|
||||
timeStyle: 'short',
|
||||
dateStyle: 'long',
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -80,7 +84,7 @@ const play = async (event: MouseEvent) => {
|
||||
await run(props.instance.path)
|
||||
.catch((err) => handleSevereError(err, { profilePath: props.instance.path }))
|
||||
.finally(() => {
|
||||
trackEvent('InstancePlay', {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: props.instance.loader,
|
||||
game_version: props.instance.game_version,
|
||||
source: 'InstanceItem',
|
||||
@@ -145,18 +149,14 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm text-secondary">
|
||||
<div
|
||||
v-tooltip="
|
||||
instance.last_played
|
||||
? dayjs(instance.last_played).format('MMMM D, YYYY [at] h:mm A')
|
||||
: null
|
||||
"
|
||||
v-tooltip="instance.last_played ? formatDateTime(instance.last_played) : null"
|
||||
class="w-fit shrink-0"
|
||||
:class="{ 'cursor-help smart-clickable:allow-pointer-events': last_played }"
|
||||
>
|
||||
<template v-if="last_played">
|
||||
{{
|
||||
formatMessage(commonMessages.playedLabel, {
|
||||
time: formatRelativeTime(last_played.toISOString?.()),
|
||||
ago: formatRelativeTime(last_played.toISOString?.()),
|
||||
})
|
||||
}}
|
||||
</template>
|
||||
|
||||
@@ -79,7 +79,7 @@ watch([() => props.recentInstances, () => showWorlds.value], async () => {
|
||||
})
|
||||
})
|
||||
|
||||
populateJumpBackIn()
|
||||
await populateJumpBackIn()
|
||||
.catch(() => {
|
||||
console.error('Failed to populate jump back in')
|
||||
})
|
||||
@@ -175,10 +175,17 @@ function refreshServer(address: string, instancePath: string) {
|
||||
refreshServerData(serverData.value[address], protocolVersions.value[instancePath], address)
|
||||
}
|
||||
|
||||
async function joinWorld(world: WorldWithProfile) {
|
||||
async function joinWorld(world: WorldWithProfile, instance?: GameInstance) {
|
||||
console.log(`Joining world ${getWorldIdentifier(world)}`)
|
||||
if (world.type === 'server') {
|
||||
await start_join_server(world.profile, world.address).catch(handleError)
|
||||
if (instance) {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: instance.loader,
|
||||
game_version: instance.game_version,
|
||||
source: 'WorldItem',
|
||||
})
|
||||
}
|
||||
} else if (world.type === 'singleplayer') {
|
||||
await start_join_singleplayer_world(world.profile, world.path).catch(handleError)
|
||||
}
|
||||
@@ -188,7 +195,7 @@ async function playInstance(instance: GameInstance) {
|
||||
await run(instance.path)
|
||||
.catch((err) => handleSevereError(err, { profilePath: instance.path }))
|
||||
.finally(() => {
|
||||
trackEvent('InstancePlay', {
|
||||
trackEvent('InstanceStart', {
|
||||
loader: instance.loader,
|
||||
game_version: instance.game_version,
|
||||
source: 'WorldItem',
|
||||
@@ -317,7 +324,7 @@ onUnmounted(() => {
|
||||
() => {
|
||||
currentProfile = item.instance.path
|
||||
currentWorld = getWorldIdentifier(item.world)
|
||||
joinWorld(item.world)
|
||||
joinWorld(item.world, item.instance)
|
||||
}
|
||||
"
|
||||
@play-instance="
|
||||
|
||||
@@ -25,10 +25,13 @@ import {
|
||||
defineMessages,
|
||||
OverflowMenu,
|
||||
SmartClickable,
|
||||
TagItem,
|
||||
useFormatDateTime,
|
||||
useFormatNumber,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatNumber, getPingLevel } from '@modrinth/utils'
|
||||
import { getPingLevel } from '@modrinth/utils'
|
||||
import { convertFileSrc } from '@tauri-apps/api/core'
|
||||
import dayjs from 'dayjs'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
@@ -46,8 +49,15 @@ import type {
|
||||
} from '@/helpers/worlds.ts'
|
||||
import { getWorldIdentifier, set_world_display_status } from '@/helpers/worlds.ts'
|
||||
|
||||
import { LockIcon } from '../../../../../../packages/assets/generated-icons'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatRelativeTime = useRelativeTime()
|
||||
const formatNumber = useFormatNumber()
|
||||
const formatDateTime = useFormatDateTime({
|
||||
timeStyle: 'short',
|
||||
dateStyle: 'long',
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
@@ -78,6 +88,8 @@ const props = withDefaults(
|
||||
message: MessageDescriptor
|
||||
}
|
||||
|
||||
managed?: boolean
|
||||
|
||||
// Instance
|
||||
instancePath?: string
|
||||
instanceName?: string
|
||||
@@ -96,6 +108,7 @@ const props = withDefaults(
|
||||
renderedMotd: undefined,
|
||||
|
||||
gameMode: undefined,
|
||||
managed: false,
|
||||
|
||||
instancePath: undefined,
|
||||
instanceName: undefined,
|
||||
@@ -117,6 +130,7 @@ const serverIncompatible = computed(
|
||||
)
|
||||
|
||||
const locked = computed(() => props.world.type === 'singleplayer' && props.world.locked)
|
||||
const managed = computed(() => props.managed)
|
||||
|
||||
const messages = defineMessages({
|
||||
hardcore: {
|
||||
@@ -171,6 +185,26 @@ const messages = defineMessages({
|
||||
id: 'instance.worlds.dont_show_on_home',
|
||||
defaultMessage: `Don't show on Home`,
|
||||
},
|
||||
linkedServer: {
|
||||
id: 'instance.worlds.linked_server',
|
||||
defaultMessage: 'Managed by server project',
|
||||
},
|
||||
incompatibleVersion: {
|
||||
id: 'app.world.world-item.incompatible-version',
|
||||
defaultMessage: 'Incompatible version {version}',
|
||||
},
|
||||
playersOnline: {
|
||||
id: 'app.world.world-item.players-online',
|
||||
defaultMessage: '{count} online',
|
||||
},
|
||||
offline: {
|
||||
id: 'app.world.world-item.offline',
|
||||
defaultMessage: 'Offline',
|
||||
},
|
||||
notPlayedYet: {
|
||||
id: 'app.world.world-item.not-played-yet',
|
||||
defaultMessage: 'Not played yet',
|
||||
},
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
@@ -200,6 +234,14 @@ const messages = defineMessages({
|
||||
<div class="text-lg text-contrast font-bold truncate smart-clickable:underline-on-hover">
|
||||
{{ world.name }}
|
||||
</div>
|
||||
<TagItem
|
||||
v-if="managed"
|
||||
v-tooltip="formatMessage(messages.linkedServer)"
|
||||
class="border !border-solid border-blue bg-highlight-blue text-xs"
|
||||
:style="`--_color: var(--color-blue)`"
|
||||
>
|
||||
<LockIcon aria-hidden="true" class="h-5 w-5" />
|
||||
</TagItem>
|
||||
<div
|
||||
v-if="world.type === 'singleplayer'"
|
||||
class="text-sm text-secondary flex items-center gap-1 font-semibold"
|
||||
@@ -217,13 +259,17 @@ const messages = defineMessages({
|
||||
>
|
||||
<template v-if="refreshing">
|
||||
<SpinnerIcon aria-hidden="true" class="animate-spin shrink-0" />
|
||||
Loading...
|
||||
{{ formatMessage(commonMessages.loadingLabel) }}
|
||||
</template>
|
||||
<template v-else-if="serverStatus">
|
||||
<template v-if="serverIncompatible">
|
||||
<IssuesIcon class="shrink-0 text-orange" aria-hidden="true" />
|
||||
<span class="text-orange">
|
||||
Incompatible version {{ serverStatus.version?.name }}
|
||||
{{
|
||||
formatMessage(messages.incompatibleVersion, {
|
||||
version: serverStatus.version?.name,
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -239,8 +285,11 @@ const messages = defineMessages({
|
||||
/>
|
||||
<Tooltip :disabled="!hasPlayersTooltip">
|
||||
<span :class="{ 'cursor-help': hasPlayersTooltip }">
|
||||
{{ formatNumber(serverStatus.players?.online, false) }}
|
||||
online
|
||||
{{
|
||||
formatMessage(messages.playersOnline, {
|
||||
count: formatNumber(serverStatus.players?.online ?? 0),
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<template #popper>
|
||||
<div class="flex flex-col gap-1">
|
||||
@@ -254,15 +303,13 @@ const messages = defineMessages({
|
||||
</template>
|
||||
<template v-else>
|
||||
<NoSignalIcon aria-hidden="true" stroke-width="3px" class="shrink-0" />
|
||||
Offline
|
||||
{{ formatMessage(messages.offline) }}
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 text-sm text-secondary">
|
||||
<div
|
||||
v-tooltip="
|
||||
world.last_played ? dayjs(world.last_played).format('MMMM D, YYYY [at] h:mm A') : null
|
||||
"
|
||||
v-tooltip="world.last_played ? formatDateTime(world.last_played) : null"
|
||||
class="w-fit shrink-0"
|
||||
:class="{
|
||||
'cursor-help smart-clickable:allow-pointer-events': world.last_played,
|
||||
@@ -271,11 +318,11 @@ const messages = defineMessages({
|
||||
<template v-if="world.last_played">
|
||||
{{
|
||||
formatMessage(commonMessages.playedLabel, {
|
||||
time: formatRelativeTime(dayjs(world.last_played).toISOString()),
|
||||
ago: formatRelativeTime(dayjs(world.last_played).toISOString()),
|
||||
})
|
||||
}}
|
||||
</template>
|
||||
<template v-else> Not played yet </template>
|
||||
<template v-else> {{ formatMessage(messages.notPlayedYet) }} </template>
|
||||
</div>
|
||||
<template v-if="instancePath">
|
||||
•
|
||||
@@ -396,8 +443,12 @@ const messages = defineMessages({
|
||||
id: 'edit',
|
||||
action: () => emit('edit'),
|
||||
shown: !instancePath,
|
||||
disabled: locked,
|
||||
tooltip: locked ? formatMessage(messages.worldInUse) : undefined,
|
||||
disabled: locked || managed,
|
||||
tooltip: locked
|
||||
? formatMessage(messages.worldInUse)
|
||||
: managed
|
||||
? formatMessage(messages.linkedServer)
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
id: 'open-folder',
|
||||
@@ -432,8 +483,12 @@ const messages = defineMessages({
|
||||
hoverFilled: true,
|
||||
action: () => emit('delete'),
|
||||
shown: !instancePath,
|
||||
disabled: locked,
|
||||
tooltip: locked ? formatMessage(messages.worldInUse) : undefined,
|
||||
disabled: locked || managed,
|
||||
tooltip: locked
|
||||
? formatMessage(messages.worldInUse)
|
||||
: managed
|
||||
? formatMessage(messages.linkedServer)
|
||||
: undefined,
|
||||
},
|
||||
]"
|
||||
>
|
||||
|
||||
@@ -5,12 +5,11 @@ import {
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import InstanceModalTitlePrefix from '@/components/ui/modal/InstanceModalTitlePrefix.vue'
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.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'
|
||||
@@ -26,10 +25,10 @@ const props = defineProps<{
|
||||
instance: GameInstance
|
||||
}>()
|
||||
|
||||
const modal = ref()
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
|
||||
const name = ref()
|
||||
const address = ref()
|
||||
const name = ref('')
|
||||
const address = ref('')
|
||||
const resourcePack = ref<ServerPackStatus>('enabled')
|
||||
|
||||
async function addServer(play: boolean) {
|
||||
@@ -60,11 +59,11 @@ function show() {
|
||||
name.value = ''
|
||||
address.value = ''
|
||||
resourcePack.value = 'enabled'
|
||||
modal.value.show()
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value.hide()
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -85,37 +84,33 @@ const messages = defineMessages({
|
||||
defineExpose({ show, hide })
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
<template #title>
|
||||
<span class="flex items-center gap-2 text-lg font-semibold text-primary">
|
||||
<InstanceModalTitlePrefix :instance="instance" />
|
||||
<span class="font-extrabold text-contrast">{{ formatMessage(messages.title) }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<NewModal ref="modal" :header="formatMessage(messages.title)" width="500px" max-width="500px">
|
||||
<ServerModalBody
|
||||
v-model:name="name"
|
||||
v-model:address="address"
|
||||
v-model:resource-pack="resourcePack"
|
||||
/>
|
||||
<div class="flex gap-2 mt-4">
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="!address" @click="addServer(true)">
|
||||
<PlayIcon />
|
||||
{{ formatMessage(messages.addAndPlay) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button :disabled="!address" @click="addServer(false)">
|
||||
<PlusIcon />
|
||||
{{ formatMessage(messages.addServer) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!border !border-surface-4" @click="hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button :disabled="!address" @click="addServer(false)">
|
||||
<PlusIcon />
|
||||
{{ formatMessage(messages.addServer) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="!address" @click="addServer(true)">
|
||||
<PlayIcon />
|
||||
{{ formatMessage(messages.addAndPlay) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
commonMessages,
|
||||
defineMessage,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
|
||||
import HideFromHomeOption from '@/components/ui/world/modal/HideFromHomeOption.vue'
|
||||
import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
|
||||
import type { GameInstance } from '@/helpers/types'
|
||||
@@ -32,7 +32,7 @@ const props = defineProps<{
|
||||
instance: GameInstance
|
||||
}>()
|
||||
|
||||
const modal = ref()
|
||||
const modal = ref<InstanceType<typeof NewModal>>()
|
||||
|
||||
const name = ref<string>('')
|
||||
const address = ref<string>('')
|
||||
@@ -81,11 +81,11 @@ function show(server: ServerWorld) {
|
||||
index.value = server.index
|
||||
displayStatus.value = server.display_status
|
||||
hideFromHome.value = server.display_status === 'hidden'
|
||||
modal.value.show()
|
||||
modal.value?.show()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
modal.value.hide()
|
||||
modal.value?.hide()
|
||||
}
|
||||
|
||||
defineExpose({ show })
|
||||
@@ -96,29 +96,28 @@ const titleMessage = defineMessage({
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ModalWrapper ref="modal">
|
||||
<template #title>
|
||||
<span class="font-extrabold text-lg text-contrast">{{ formatMessage(titleMessage) }}</span>
|
||||
</template>
|
||||
<NewModal ref="modal" :header="formatMessage(titleMessage)" width="500px" max-width="500px">
|
||||
<ServerModalBody
|
||||
v-model:name="name"
|
||||
v-model:address="address"
|
||||
v-model:resource-pack="resourcePack"
|
||||
/>
|
||||
<HideFromHomeOption v-model="hideFromHome" class="mt-3" />
|
||||
<div class="flex gap-2 mt-4">
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="!address" @click="saveServer">
|
||||
<SaveIcon />
|
||||
{{ formatMessage(commonMessages.saveChangesButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled>
|
||||
<button @click="hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</ModalWrapper>
|
||||
<template #actions>
|
||||
<div class="flex gap-2 justify-end">
|
||||
<ButtonStyled type="outlined">
|
||||
<button class="!border !border-surface-4" @click="hide()">
|
||||
<XIcon />
|
||||
{{ formatMessage(commonMessages.cancelButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
<ButtonStyled color="brand">
|
||||
<button :disabled="!address" @click="saveServer">
|
||||
<SaveIcon />
|
||||
{{ formatMessage(commonMessages.saveChangesButton) }}
|
||||
</button>
|
||||
</ButtonStyled>
|
||||
</div>
|
||||
</template>
|
||||
</NewModal>
|
||||
</template>
|
||||
|
||||
@@ -49,34 +49,40 @@ const messages = defineMessages({
|
||||
id: 'instance.server-modal.placeholder-name',
|
||||
defaultMessage: 'Minecraft Server',
|
||||
},
|
||||
placeholderAddress: {
|
||||
id: 'app.world.server-modal.placeholder-address',
|
||||
defaultMessage: 'example.modrinth.gg',
|
||||
},
|
||||
selectAnOption: {
|
||||
id: 'app.world.server-modal.select-an-option',
|
||||
defaultMessage: 'Select an option',
|
||||
},
|
||||
})
|
||||
|
||||
defineExpose({ resourcePackOptions })
|
||||
</script>
|
||||
<template>
|
||||
<div class="w-[450px]">
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-0 mb-1">
|
||||
{{ formatMessage(messages.name) }}
|
||||
</h2>
|
||||
<StyledInput
|
||||
v-model="name"
|
||||
:placeholder="formatMessage(messages.placeholderName)"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-3 mb-1">
|
||||
{{ formatMessage(messages.address) }}
|
||||
</h2>
|
||||
<StyledInput
|
||||
v-model="address"
|
||||
placeholder="example.modrinth.gg"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
<h2 class="text-lg font-extrabold text-contrast mt-3 mb-1">
|
||||
{{ formatMessage(messages.resourcePack) }}
|
||||
</h2>
|
||||
<div>
|
||||
<div class="space-y-4 w-full">
|
||||
<label class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">{{ formatMessage(messages.name) }}</span>
|
||||
<StyledInput
|
||||
v-model="name"
|
||||
:placeholder="formatMessage(messages.placeholderName)"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</label>
|
||||
<label class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">{{ formatMessage(messages.address) }}</span>
|
||||
<StyledInput
|
||||
v-model="address"
|
||||
:placeholder="formatMessage(messages.placeholderAddress)"
|
||||
autocomplete="off"
|
||||
wrapper-class="w-full"
|
||||
/>
|
||||
</label>
|
||||
<label class="flex flex-col gap-2">
|
||||
<span class="font-semibold text-contrast">{{ formatMessage(messages.resourcePack) }}</span>
|
||||
<Combobox
|
||||
v-model="resourcePack"
|
||||
:options="
|
||||
@@ -89,9 +95,9 @@ defineExpose({ resourcePackOptions })
|
||||
:display-value="
|
||||
resourcePack
|
||||
? formatMessage(resourcePackOptionMessages[resourcePack])
|
||||
: 'Select an option'
|
||||
: formatMessage(messages.selectAnOption)
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
import { createConsoleState } from '@modrinth/ui'
|
||||
|
||||
import { clear_log_buffer, get_live_log_buffer, get_logs } from '@/helpers/logs'
|
||||
|
||||
type ConsoleState = ReturnType<typeof createConsoleState>
|
||||
|
||||
interface LogEntry {
|
||||
filename: string
|
||||
name?: string
|
||||
log_type: string
|
||||
stdout?: string
|
||||
age?: number
|
||||
live?: boolean
|
||||
}
|
||||
|
||||
interface InstanceConsoleEntry {
|
||||
liveConsole: ConsoleState
|
||||
historicalConsole: ConsoleState
|
||||
historicalCache: Map<string, string>
|
||||
logList: LogEntry[] | null
|
||||
}
|
||||
|
||||
const instances = new Map<string, InstanceConsoleEntry>()
|
||||
|
||||
function getOrCreate(profilePathId: string): InstanceConsoleEntry {
|
||||
let entry = instances.get(profilePathId)
|
||||
if (entry) return entry
|
||||
|
||||
entry = {
|
||||
liveConsole: createConsoleState(),
|
||||
historicalConsole: createConsoleState(),
|
||||
historicalCache: new Map(),
|
||||
logList: null,
|
||||
}
|
||||
instances.set(profilePathId, entry)
|
||||
return entry
|
||||
}
|
||||
|
||||
async function hydrate(profilePathId: string): Promise<void> {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
if (entry.liveConsole.output.value.length > 0) return
|
||||
|
||||
const buffer = await get_live_log_buffer(profilePathId)
|
||||
if (buffer) {
|
||||
entry.liveConsole.addLegacyLog(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
async function getHistoricalLogs(profilePathId: string, instancePath: string): Promise<LogEntry[]> {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
if (entry.logList) return entry.logList
|
||||
|
||||
const logs: LogEntry[] = await get_logs(instancePath, false)
|
||||
entry.logList = logs
|
||||
|
||||
for (const log of logs) {
|
||||
if (log.stdout && log.stdout !== '') {
|
||||
entry.historicalCache.set(log.filename, log.stdout)
|
||||
}
|
||||
}
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
function getHistoricalContent(profilePathId: string, filename: string): string | undefined {
|
||||
return instances.get(profilePathId)?.historicalCache.get(filename)
|
||||
}
|
||||
|
||||
function invalidate(profilePathId: string): void {
|
||||
const entry = instances.get(profilePathId)
|
||||
if (!entry) return
|
||||
entry.historicalCache.clear()
|
||||
entry.logList = null
|
||||
}
|
||||
|
||||
async function clearLive(profilePathId: string): Promise<void> {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
entry.liveConsole.clear()
|
||||
await clear_log_buffer(profilePathId).catch(() => {})
|
||||
}
|
||||
|
||||
async function destroy(profilePathId: string): Promise<void> {
|
||||
instances.delete(profilePathId)
|
||||
await clear_log_buffer(profilePathId).catch(() => {})
|
||||
}
|
||||
|
||||
export function useInstanceConsole(profilePathId: string) {
|
||||
const entry = getOrCreate(profilePathId)
|
||||
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),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
const trimTrailingSlash = (url: string) => url.replace(/\/$/, '')
|
||||
|
||||
const siteUrl = trimTrailingSlash(import.meta.env.MODRINTH_URL || 'https://modrinth.com')
|
||||
const labrinthBaseUrl = trimTrailingSlash(
|
||||
import.meta.env.MODRINTH_API_BASE_URL || 'https://api.modrinth.com',
|
||||
)
|
||||
const archonBaseUrl = trimTrailingSlash(
|
||||
import.meta.env.MODRINTH_ARCHON_BASE_URL || 'https://archon.modrinth.com',
|
||||
)
|
||||
|
||||
export const config = {
|
||||
siteUrl,
|
||||
stripePublishableKey:
|
||||
import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY ||
|
||||
'pk_test_51JbFxJJygY5LJFfKV50mnXzz3YLvBVe2Gd1jn7ljWAkaBlRz3VQdxN9mXcPSrFbSqxwAb0svte9yhnsmm7qHfcWn00R611Ce7b',
|
||||
labrinthBaseUrl,
|
||||
archonBaseUrl,
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { OverlayScrollbars, type PartialOptions } from 'overlayscrollbars'
|
||||
import type { ObjectDirective } from 'vue'
|
||||
|
||||
const defaultOverlayScrollbarsOptions = Object.freeze<PartialOptions>({
|
||||
scrollbars: {
|
||||
theme: 'os-theme-dark',
|
||||
autoHide: 'leave',
|
||||
autoHideSuspend: true,
|
||||
},
|
||||
})
|
||||
|
||||
const mergeOptions = (options: PartialOptions = {}): PartialOptions => ({
|
||||
...defaultOverlayScrollbarsOptions,
|
||||
...options,
|
||||
scrollbars: {
|
||||
...defaultOverlayScrollbarsOptions.scrollbars,
|
||||
...(options.scrollbars ?? {}),
|
||||
},
|
||||
})
|
||||
|
||||
export const overlayScrollbarsDirective: ObjectDirective<HTMLElement, PartialOptions | undefined> =
|
||||
{
|
||||
mounted(el, binding) {
|
||||
OverlayScrollbars(el, mergeOptions(binding.value))
|
||||
},
|
||||
updated(el, binding) {
|
||||
if (binding.value === binding.oldValue) return
|
||||
const instance = OverlayScrollbars(el)
|
||||
instance?.options(mergeOptions(binding.value))
|
||||
},
|
||||
unmounted(el) {
|
||||
const instance = OverlayScrollbars(el)
|
||||
instance?.destroy()
|
||||
},
|
||||
}
|
||||
@@ -15,7 +15,7 @@ type AnalyticsEventMap = {
|
||||
PageView: { path: string; fromPath: string; failed: unknown }
|
||||
InstanceCreate: { source: string }
|
||||
InstanceCreateStart: { source: string }
|
||||
InstancePlay: InstanceProperties & { source: string }
|
||||
InstanceStart: InstanceProperties & { source: string }
|
||||
InstanceStop: Partial<InstanceProperties> & { source?: string }
|
||||
InstanceDuplicate: InstanceProperties
|
||||
InstanceRepair: InstanceProperties
|
||||
|
||||
@@ -8,6 +8,14 @@ export async function get_project_many(ids, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_project_many', { ids, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function get_project_v3(id, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_project_v3', { id, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function get_project_v3_many(ids, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_project_v3_many', { ids, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function get_version(id, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_version', { id, cacheBehaviour })
|
||||
}
|
||||
@@ -48,6 +56,28 @@ export async function get_search_results_many(ids, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_search_results_many', { ids, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function get_search_results_v3(id, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_search_results_v3', { id, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function get_search_results_v3_many(ids, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_search_results_v3_many', { ids, cacheBehaviour })
|
||||
}
|
||||
|
||||
export async function purge_cache_types(cacheTypes) {
|
||||
return await invoke('plugin:cache|purge_cache_types', { cacheTypes })
|
||||
}
|
||||
|
||||
/**
|
||||
* Get versions for a project (without changelogs for fast loading).
|
||||
* Uses the cache system - versions are cached for 30 minutes.
|
||||
* @param {string} projectId - The project ID
|
||||
* @param {string} [cacheBehaviour] - Cache behaviour ('must_revalidate', etc.)
|
||||
* @returns {Promise<Array|null>} Array of version objects (without changelogs) or null
|
||||
*/
|
||||
export async function get_project_versions(projectId, cacheBehaviour) {
|
||||
return await invoke('plugin:cache|get_project_versions', {
|
||||
projectId,
|
||||
cacheBehaviour,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -97,3 +97,23 @@ export async function warning_listener(callback) {
|
||||
export async function friend_listener(callback) {
|
||||
return await listen('friend', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
/// Payload for the 'log' event
|
||||
/*
|
||||
LogPayload {
|
||||
profile_path_id: string,
|
||||
type: "log4j" | "legacy",
|
||||
// log4j fields (when type === "log4j"):
|
||||
timestamp_millis?: number,
|
||||
logger_name?: string,
|
||||
level?: string,
|
||||
thread_name?: string,
|
||||
message?: string,
|
||||
throwable?: string,
|
||||
// legacy fields (when type === "legacy"):
|
||||
message?: string,
|
||||
}
|
||||
*/
|
||||
export async function log_listener(callback) {
|
||||
return await listen('log', (event) => callback(event.payload))
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { fetch } from '@tauri-apps/plugin-http'
|
||||
|
||||
export const useFetch = async (url, item, isSilent) => {
|
||||
try {
|
||||
const version = await getVersion()
|
||||
return await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: { 'User-Agent': `modrinth/theseus/${version} (support@modrinth.com)` },
|
||||
})
|
||||
} catch (err) {
|
||||
if (!isSilent) {
|
||||
throw err
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,3 +63,13 @@ export async function delete_logs(profilePath) {
|
||||
export async function get_latest_log_cursor(profilePath, cursor) {
|
||||
return await invoke('plugin:logs|logs_get_latest_log_cursor', { profilePath, 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 })
|
||||
}
|
||||
|
||||
/// 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 })
|
||||
}
|
||||
|
||||
@@ -1,65 +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 { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { create } from './profile'
|
||||
|
||||
// Installs pack from a version ID
|
||||
export async function create_profile_and_install(
|
||||
projectId,
|
||||
versionId,
|
||||
packTitle,
|
||||
iconUrl,
|
||||
createInstanceCallback = () => {},
|
||||
) {
|
||||
const location = {
|
||||
type: 'fromVersionId',
|
||||
project_id: projectId,
|
||||
version_id: versionId,
|
||||
title: packTitle,
|
||||
icon_url: iconUrl,
|
||||
}
|
||||
const profile_creator = await invoke('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, versionId, title, profilePath) {
|
||||
const location = {
|
||||
type: 'fromVersionId',
|
||||
project_id: projectId,
|
||||
version_id: versionId,
|
||||
title,
|
||||
}
|
||||
return await invoke('plugin:pack|pack_install', { location, profile: profilePath })
|
||||
}
|
||||
|
||||
// Installs pack from a path
|
||||
export async function create_profile_and_install_from_file(path) {
|
||||
const location = {
|
||||
type: 'fromFile',
|
||||
path: path,
|
||||
}
|
||||
const profile_creator = await invoke('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,
|
||||
)
|
||||
return await invoke('plugin:pack|pack_install', { location, profile })
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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
|
||||
}
|
||||
|
||||
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): Promise<void> {
|
||||
const location: PackLocationFile = {
|
||||
type: 'fromFile',
|
||||
path,
|
||||
}
|
||||
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,
|
||||
)
|
||||
return await invoke('plugin:pack|pack_install', { location, profile })
|
||||
}
|
||||
@@ -1,207 +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 { invoke } from '@tauri-apps/api/core'
|
||||
|
||||
import { install_to_existing_profile } from '@/helpers/pack.js'
|
||||
|
||||
/// 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, gameVersion, modloader, loaderVersion, icon, skipInstall) {
|
||||
//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,
|
||||
})
|
||||
}
|
||||
|
||||
// duplicate a profile
|
||||
export async function duplicate(path) {
|
||||
return await invoke('plugin:profile-create|profile_duplicate', { path })
|
||||
}
|
||||
|
||||
// Remove a profile
|
||||
export async function remove(path) {
|
||||
return await invoke('plugin:profile|profile_remove', { path })
|
||||
}
|
||||
|
||||
// Get a profile by path
|
||||
// Returns a Profile
|
||||
export async function get(path) {
|
||||
return await invoke('plugin:profile|profile_get', { path })
|
||||
}
|
||||
|
||||
export async function get_many(paths) {
|
||||
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, cacheBehaviour) {
|
||||
return await invoke('plugin:profile|profile_get_projects', { path, cacheBehaviour })
|
||||
}
|
||||
|
||||
// Get a profile's full fs path
|
||||
// Returns a path
|
||||
export async function get_full_path(path) {
|
||||
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, projectPath) {
|
||||
return await invoke('plugin:profile|profile_get_mod_full_path', { path, projectPath })
|
||||
}
|
||||
|
||||
// Get optimal java version from profile
|
||||
// Returns a java version
|
||||
export async function get_optimal_jre_key(path) {
|
||||
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() {
|
||||
return await invoke('plugin:profile|profile_list')
|
||||
}
|
||||
|
||||
export async function check_installed(path, projectId) {
|
||||
return await invoke('plugin:profile|profile_check_installed', { path, projectId })
|
||||
}
|
||||
|
||||
// Installs/Repairs a profile
|
||||
export async function install(path, force) {
|
||||
return await invoke('plugin:profile|profile_install', { path, force })
|
||||
}
|
||||
|
||||
// Updates all of a profile's projects
|
||||
export async function update_all(path) {
|
||||
return await invoke('plugin:profile|profile_update_all', { path })
|
||||
}
|
||||
|
||||
// Updates a specified project
|
||||
export async function update_project(path, projectPath) {
|
||||
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 async function add_project_from_version(path, versionId) {
|
||||
return await invoke('plugin:profile|profile_add_project_from_version', { path, versionId })
|
||||
}
|
||||
|
||||
// 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, projectPath, projectType) {
|
||||
return await invoke('plugin:profile|profile_add_project_from_path', {
|
||||
path,
|
||||
projectPath,
|
||||
projectType,
|
||||
})
|
||||
}
|
||||
|
||||
// Toggle disabling a project
|
||||
export async function toggle_disable_project(path, projectPath) {
|
||||
return await invoke('plugin:profile|profile_toggle_disable_project', { path, projectPath })
|
||||
}
|
||||
|
||||
// Remove a project
|
||||
export async function remove_project(path, projectPath) {
|
||||
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, versionId) {
|
||||
return await invoke('plugin:profile|profile_update_managed_modrinth_version', {
|
||||
path,
|
||||
versionId,
|
||||
})
|
||||
}
|
||||
|
||||
// Repair a managed Modrinth profile
|
||||
export async function update_repair_modrinth(path) {
|
||||
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,
|
||||
exportLocation,
|
||||
includedOverrides,
|
||||
versionId,
|
||||
description,
|
||||
name,
|
||||
) {
|
||||
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) {
|
||||
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) {
|
||||
return await invoke('plugin:profile|profile_run', { path })
|
||||
}
|
||||
|
||||
export async function kill(path) {
|
||||
return await invoke('plugin:profile|profile_kill', { path })
|
||||
}
|
||||
|
||||
// Edits a profile
|
||||
export async function edit(path, editProfile) {
|
||||
return await invoke('plugin:profile|profile_edit', { path, editProfile })
|
||||
}
|
||||
|
||||
// Edits a profile's icon
|
||||
export async function edit_icon(path, iconPath) {
|
||||
return await invoke('plugin:profile|profile_edit_icon', { path, iconPath })
|
||||
}
|
||||
|
||||
export async function finish_install(instance) {
|
||||
if (instance.install_stage !== 'pack_installed') {
|
||||
let linkedData = instance.linked_data
|
||||
await install_to_existing_profile(
|
||||
linkedData.project_id,
|
||||
linkedData.version_id,
|
||||
instance.name,
|
||||
instance.path,
|
||||
)
|
||||
} else {
|
||||
await install(instance.path, false)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
/**
|
||||
* 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 })
|
||||
}
|
||||
|
||||
// Get optimal java version from profile
|
||||
// Returns a java version
|
||||
export async function get_optimal_jre_key(path: string): Promise<string | 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 async function add_project_from_version(path: string, versionId: string): Promise<string> {
|
||||
return await invoke('plugin:profile|profile_add_project_from_version', { path, versionId })
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
+6
-18
@@ -1,6 +1,6 @@
|
||||
import type { ModrinthId } from '@modrinth/utils'
|
||||
|
||||
type GameInstance = {
|
||||
export type GameInstance = {
|
||||
path: string
|
||||
install_stage: InstallStage
|
||||
|
||||
@@ -46,20 +46,13 @@ type LinkedData = {
|
||||
locked: boolean
|
||||
}
|
||||
|
||||
type InstanceLoader = 'vanilla' | 'forge' | 'fabric' | 'quilt' | 'neoforge'
|
||||
export type InstanceLoader = 'vanilla' | 'forge' | 'fabric' | 'quilt' | 'neoforge'
|
||||
|
||||
type ContentFile = {
|
||||
hash: string
|
||||
file_name: string
|
||||
size: number
|
||||
metadata?: FileMetadata
|
||||
update_version_id?: string
|
||||
project_type: ContentFileProjectType
|
||||
}
|
||||
|
||||
type FileMetadata = {
|
||||
project_id: string
|
||||
version_id: string
|
||||
metadata?: {
|
||||
project_id: string
|
||||
version_id: string
|
||||
}
|
||||
}
|
||||
|
||||
type ContentFileProjectType = 'mod' | 'datapack' | 'resourcepack' | 'shaderpack'
|
||||
@@ -135,8 +128,3 @@ type AppSettings = {
|
||||
prev_custom_dir?: string
|
||||
migrated: boolean
|
||||
}
|
||||
|
||||
export type InstanceSettingsTabProps = {
|
||||
instance: GameInstance
|
||||
offline?: boolean
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ export type ServerWorld = BaseWorld & {
|
||||
index: number
|
||||
address: string
|
||||
pack_status: ServerPackStatus
|
||||
project_id?: string
|
||||
content_kind?: string
|
||||
}
|
||||
|
||||
export type World = SingleplayerWorld | ServerWorld
|
||||
@@ -140,8 +142,17 @@ export async function add_server_to_profile(
|
||||
name: string,
|
||||
address: string,
|
||||
packStatus: ServerPackStatus,
|
||||
projectId?: string,
|
||||
contentKind?: string,
|
||||
): Promise<number> {
|
||||
return await invoke('plugin:worlds|add_server_to_profile', { path, name, address, packStatus })
|
||||
return await invoke('plugin:worlds|add_server_to_profile', {
|
||||
path,
|
||||
name,
|
||||
address,
|
||||
packStatus,
|
||||
projectId,
|
||||
contentKind,
|
||||
})
|
||||
}
|
||||
|
||||
export async function edit_server_in_profile(
|
||||
@@ -212,6 +223,150 @@ export function isServerWorld(world: World): world is ServerWorld {
|
||||
return world.type === 'server'
|
||||
}
|
||||
|
||||
const DEFAULT_MINECRAFT_SERVER_PORT = 25565
|
||||
|
||||
function parseServerPort(port: string): number | null {
|
||||
const parsed = Number.parseInt(port, 10)
|
||||
return Number.isInteger(parsed) && parsed > 0 && parsed <= 65535 ? parsed : null
|
||||
}
|
||||
|
||||
function parseServerHost(address: string): string {
|
||||
const trimmedAddress = address.trim()
|
||||
if (!trimmedAddress) return ''
|
||||
|
||||
if (trimmedAddress.startsWith('[')) {
|
||||
const closingBracket = trimmedAddress.indexOf(']')
|
||||
if (closingBracket > 0) {
|
||||
return trimmedAddress.slice(1, closingBracket).trim().toLowerCase()
|
||||
}
|
||||
}
|
||||
|
||||
const firstColon = trimmedAddress.indexOf(':')
|
||||
const lastColon = trimmedAddress.lastIndexOf(':')
|
||||
|
||||
if (firstColon !== -1 && firstColon === lastColon) {
|
||||
return trimmedAddress.slice(0, firstColon).trim().toLowerCase()
|
||||
}
|
||||
|
||||
return trimmedAddress.toLowerCase()
|
||||
}
|
||||
|
||||
function isIPv4Host(host: string): boolean {
|
||||
const segments = host.split('.')
|
||||
if (segments.length !== 4) return false
|
||||
|
||||
return segments.every((segment) => {
|
||||
if (!/^\d+$/.test(segment)) return false
|
||||
const value = Number.parseInt(segment, 10)
|
||||
return value >= 0 && value <= 255
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalization converts addresses to a canonical form (lowercase-host:port, default port 25565)
|
||||
*/
|
||||
export function normalizeServerAddress(address: string): string {
|
||||
const trimmedAddress = address.trim()
|
||||
const host = parseServerHost(trimmedAddress)
|
||||
if (!host) return ''
|
||||
let port = DEFAULT_MINECRAFT_SERVER_PORT
|
||||
|
||||
// ipv6 address
|
||||
if (trimmedAddress.startsWith('[')) {
|
||||
const closingBracket = trimmedAddress.indexOf(']')
|
||||
if (closingBracket > 0) {
|
||||
const suffix = trimmedAddress.slice(closingBracket + 1)
|
||||
if (suffix.startsWith(':')) {
|
||||
const parsedPort = parseServerPort(suffix.slice(1))
|
||||
if (parsedPort != null) {
|
||||
port = parsedPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ipv4 address or hostname
|
||||
} else {
|
||||
const firstColon = trimmedAddress.indexOf(':')
|
||||
const lastColon = trimmedAddress.lastIndexOf(':')
|
||||
if (firstColon !== -1 && firstColon === lastColon) {
|
||||
const parsedPort = parseServerPort(trimmedAddress.slice(firstColon + 1))
|
||||
if (parsedPort != null) {
|
||||
port = parsedPort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `${host}:${port}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Domain key used for deduping server entries by removing a single leading subdomain.
|
||||
* Example: test.cobblemon.gg and cobblemon.gg map to cobblemon.gg
|
||||
*/
|
||||
export function getServerDomainKey(address: string): string {
|
||||
const normalizedAddress = normalizeServerAddress(address)
|
||||
if (!normalizedAddress) return ''
|
||||
|
||||
const separator = normalizedAddress.lastIndexOf(':')
|
||||
if (separator <= 0 || separator === normalizedAddress.length - 1) return normalizedAddress
|
||||
|
||||
const host = normalizedAddress.slice(0, separator).replace(/\.+$/, '')
|
||||
if (!host) return normalizedAddress
|
||||
if (host.includes(':') || isIPv4Host(host)) return normalizedAddress
|
||||
|
||||
const segments = host.split('.').filter(Boolean)
|
||||
if (segments.length <= 2) return host
|
||||
|
||||
return segments.slice(1).join('.')
|
||||
}
|
||||
|
||||
export function resolveManagedServerWorld(
|
||||
worlds: World[],
|
||||
managedName: string | null | undefined,
|
||||
managedAddress: string | null | undefined,
|
||||
): ServerWorld | null {
|
||||
if (!managedName || !managedAddress) return null
|
||||
|
||||
const normalizedManagedAddress = normalizeServerAddress(managedAddress)
|
||||
if (!normalizedManagedAddress) return null
|
||||
|
||||
const servers = worlds
|
||||
.filter(isServerWorld)
|
||||
.slice()
|
||||
.sort((a, b) => a.index - b.index)
|
||||
|
||||
const exactMatch = servers.find(
|
||||
(server) =>
|
||||
server.name === managedName &&
|
||||
normalizeServerAddress(server.address) === normalizedManagedAddress,
|
||||
)
|
||||
if (exactMatch) return exactMatch
|
||||
|
||||
return (
|
||||
servers.find((server) => normalizeServerAddress(server.address) === normalizedManagedAddress) ??
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
export async function getServerLatency(
|
||||
address: string,
|
||||
protocolVersion: ProtocolVersion | null = null,
|
||||
): Promise<number | undefined> {
|
||||
const pings: number[] = []
|
||||
for (let i = 0; i < 3; i++) {
|
||||
try {
|
||||
const status = await get_server_status(address, protocolVersion)
|
||||
if (status.ping != null) {
|
||||
pings.push(status.ping)
|
||||
}
|
||||
} catch {
|
||||
// Ignore individual ping failures
|
||||
}
|
||||
}
|
||||
if (pings.length === 0) return undefined
|
||||
return Math.round(pings.reduce((sum, p) => sum + p, 0) / pings.length)
|
||||
}
|
||||
|
||||
export async function refreshServerData(
|
||||
serverData: ServerData,
|
||||
protocolVersion: ProtocolVersion | null,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { buildLocaleMessages, createMessageCompiler, type CrowdinMessages } from '@modrinth/ui'
|
||||
import { uiLocaleModulesEager } from '@modrinth/ui/src/locales.eager.ts'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
const localeModules = import.meta.glob<{ default: CrowdinMessages }>('./locales/*/index.json', {
|
||||
@@ -12,7 +13,7 @@ const i18n = createI18n({
|
||||
messageCompiler: createMessageCompiler(),
|
||||
missingWarn: false,
|
||||
fallbackWarn: false,
|
||||
messages: buildLocaleMessages(localeModules),
|
||||
messages: buildLocaleMessages(localeModules, uiLocaleModulesEager),
|
||||
})
|
||||
|
||||
export default i18n
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "تعذر الوصول إلى خوادم المصادقة"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "أضف الخادم للنموذج"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "أضف الخوادم لنموذجك"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "أضف للنموذج"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "أضف للنموذج {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "مضاف"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "مضاف فعلا"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "استكشف محتوى"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "استكشف خوادم"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "إخفاء الخوادم المضافة"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "إخفاء المحتوى المضاف"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "تثبيت محتوى لنموذجك"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "أدخل وصف التعديل..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "تصدير"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "تصدير حزمة التعديل"
|
||||
},
|
||||
"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.instance.confirm-delete.admonition-body": {
|
||||
"message": "سيتم حذف جميع البيانات الخاصة لنموذجك نهائيًا، بما في ذلك عوالمك والتكوينات وكل المحتوى المثبت."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "لا يمكن التراجع عن هذا الإجراء"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "حذف النموذج"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "حذف النموذج"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "حُزْمَة التعديل هذه مثبته فعلًا في نموذج <bold>{instanceName}</bold>. هل انت متأكد بإرادة نسخه؟"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "إنشاء"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "حُزْمَة التعديل مثبتة بالفعل"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "النموذج"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "مشروع"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "تمت إضافة \"{name}\""
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "تمت إضافة {count} مشروع"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "تحقق من المشاريع التي أستخدمها في حزمة التعديل الخاص بي!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "مشاركة محتوى حزمة التعديل"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "تم الرفع بنجاح"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "أضف خادم"
|
||||
},
|
||||
"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": "معدّل"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "مفصول"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "يعمل"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "الأصلي"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "أضف خادما أو تصفح لكي تبدأ"
|
||||
},
|
||||
"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": "نزل للعب"
|
||||
},
|
||||
@@ -12,16 +159,22 @@
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": ""
|
||||
"message": "{count, plural, one {# تعديل} other {# تعديلات}}"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "تم إضافة"
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "حزمة التعديل مطلوبة"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "تم إزالة"
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "يتطلب هذا الخادم تعديلات للعب. انقر فوق \"تثبيت\" لإعداد الملفات المطلوبة من Modrinth، ثم قم بتشغيله مباشرة إلى الخادم."
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "تم تحديث"
|
||||
"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": "حدث للعب"
|
||||
@@ -29,6 +182,9 @@
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "يلزم التحديث"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "هناك تحديث مطلوب للعب بـ {name}. الرجاء التحديث إلى آخر اصدار لتشغيل اللعبة."
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "تم تفعيل وضع المطوّر."
|
||||
},
|
||||
@@ -41,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "خيارات النسخة الافتراضية"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "أعلام الميزات"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "تثبيتات جافا"
|
||||
},
|
||||
@@ -56,33 +209,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "إدارة الموارد"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "تطبيق Modrinth الإصدار {version} جاهز للتثبيت!\nأعد التحميل لتحديث التطبيق الآن، أو سيتم التحديث تلقائيًا عند إغلاق تطبيق Modrinth."
|
||||
"app.update-popup.body": {
|
||||
"message": "تطبيق Modrinth v{version} جاهز للتثبيت! أعد التحميل للتحديث الآن، أو تلقائيًا عند إغلاق تطبيق Modrinth."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "تطبيق Modrinth الإصدار {version} جاهز للتثبيت!\nأعد التحميل لتحديث التطبيق الآن، أو سيتم التحديث تلقائيًا عند إغلاق تطبيق Modrinth."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "انتهى تنزيل تطبيق Modrinth v{version}. أعد التحميل للتحديث الآن، أو تلقائيًا عند إغلاق تطبيق Modrinth."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "تطبيق Modrinth الإصدار {version} متاح الآن!\nنظرًا لأنك تستخدم شبكة محدودة البيانات، لم نقم بتنزيل التحديث تلقائيًا.\n"
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "تطبيق Modrinth v {version} متاح. استخدم مدير الحزم الخاص بك للتحديث للحصول على أحدث الميزات والإصلاحات!"
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "سجلّ التغييرات"
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "تطبيق Modrinth v{version} متاح الآن! وبما أنك متصل بشبكة مقيّدة، لم نقم بتنزيله تلقائيًا."
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "سجل التغيير"
|
||||
},
|
||||
"app.update-popup.download": {
|
||||
"message": "تنزيل ({size})"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "جار التنزيل..."
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "اكتمل التنزيل"
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "إعادة تحميل"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "تحديث متاح"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "اكتمل التنزيل"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "انقر هنا لعرض سجلّ التغييرات."
|
||||
},
|
||||
@@ -98,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "أعد التحميل لتثبيت التحديث"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "مثال.مودرنث.جج"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "حدد خيارا"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "إصدار غير مطابق ({version})"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "لم يتم اللعب به"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "مفصول"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} متصل حاليا"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "إضافة صديق"
|
||||
},
|
||||
@@ -197,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "تعديل العالم"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "المشاريع المعطَّلة"
|
||||
"instance.files.adding-files": {
|
||||
"message": "إضافة ملفات ({completed}\\{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "توجد تحديثات متاحة"
|
||||
"instance.files.save-as": {
|
||||
"message": "حفظ ك..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "العنوان"
|
||||
@@ -210,7 +381,7 @@
|
||||
"message": "الاسم"
|
||||
},
|
||||
"instance.server-modal.placeholder-name": {
|
||||
"message": "خادم ماينكرافت"
|
||||
"message": "خادم Minecraft"
|
||||
},
|
||||
"instance.server-modal.resource-pack": {
|
||||
"message": "حزمة الموارد"
|
||||
@@ -240,7 +411,7 @@
|
||||
"message": "نسخة النسخة"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "إنشاء."
|
||||
"message": "ينشئ نسخة من هذا النموذج شاملا عوالمه, تعديلاتها النصيه, إلخ..."
|
||||
},
|
||||
"instance.settings.tabs.general.edit-icon": {
|
||||
"message": "تعديل الأيقونة"
|
||||
@@ -311,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} لماينكرافت {game_version} مثبت بالفعل"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "فانيلا {game_version} مُثبّتة بالفعل"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "تغيير الإصدار"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "جاري التثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "جاري جلب إصدارات حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "جاري تثبيت الإصدار الجديد"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "المثبت حاليًا"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "معلومات التصحيح:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "جاري جلب تفاصيل حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "إصدار اللعبة"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "التثبيت قيد التنفيذ"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "إصدار {loader}"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "ماين كرافت {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "تعذّر جلب تفاصيل حزمة المودات المرتبطة. يرجى التحقق من اتصالك بالإنترنت."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} غير متاح لماين كرافت {version}. جرّب محمّل مودات آخر."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "هذه النسخة مرتبطة بحزمة مودات، لكن لم يتم العثور على الحزمة على مودرنث."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "منصّة"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "إعادة تثبيت حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "جاري إعادة تثبيت حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "إعادة التثبيت ستُعيد جميع الملفات المثبتة أو المعدلة إلى ما توفره حُزْمة المودات، مع إزالة أي مودات أو محتوى أضفته بعد التثبيت الأصلي. قد يساعد ذلك في حل السلوك غير المتوقع إذا تم تعديل النسخة، لكن إذا كانت عوالمك تعتمد على محتويات إضافية، فقد يتسبب ذلك في تعطلها."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "هل أنت متأكد أنك تريد إعادة تثبيت هذه النسخة؟"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "يعيد محتوى النسخة إلى حالته الأصلية، مع إزالة جميع المودات أو المحتوى الذي أُضيف فوق حزمة المودات الأصلية."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "إعادة تثبيت حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "إصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "جاري الإصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "الإصلاح يعيد تثبيت مكوّنات ماين كرافت ويتحقق من التلف. قد يساعد ذلك في حل المشكلات إذا كانت لعبتك لا تعمل بسبب أخطاء متعلقة ببرنامج التشغيل، لكنه لن يحل المشكلات أو الأعطال الناتجة عن المودات المثبّتة."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "إصلاح النسخة؟"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "الإصلاح قيد التنفيذ"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "إعادة التعيين إلى الحالة الحالية"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "عرض جميع الإصدارات"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "تغيير الإصدار"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "تثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "إعادة التثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "إصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "لا يمكن {action} أثناء التثبيت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "لا يمكن {action} أثناء عدم الاتصال بالإنترنت"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "لا يمكن {action} أثناء الإصلاح"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(إصدار غير معروف)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "إلغاء ربط النسخة"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "إذا تابعت، فلن تتمكّن من إعادة ربطها إلا بإنشاء نسخة جديدة بالكامل. لن تتلقى بعد ذلك تحديثات حزمة المودات، وستصبح نسخة عادية."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "هل أنت متأكد أنك تريد إلغاء ربط هذه النسخة؟"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "هذه النسخة مرتبطة بحزمة مودات، مما يعني أنه لا يمكن تحديث المودات أو تغيير محمّل المودات أو إصدار ماين كرافت. سيؤدي إلغاء الربط إلى فصل هذه النسخة نهائيًا عن حزمة المودات."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "إلغاء الربط من حزمة المودات"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "جافا والذاكرة"
|
||||
},
|
||||
@@ -506,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "عدم العرض في الصفحة الرئيسية"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "متاح"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "النسخة مفتوحة بالفعل"
|
||||
},
|
||||
@@ -518,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "الخادم غير متوافق"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "تدار بواسطة مشروع الخادم"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "تعذّر الاتصال بالخادم"
|
||||
},
|
||||
@@ -530,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "تشغيل النسخة"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "الخادم"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "لعب فردي"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "عرض النسخة"
|
||||
},
|
||||
@@ -553,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "مزامنة مع النسخة"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "يقدمها الخادم"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "يمكن إضافة التعديلات **المحليه** فقط إلى نموذج الخادم"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "يتم توفير نسخة اللعبة من قبل الخادم"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "يتم توفير المحمّل من قبل الخادم"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,147 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Připojení k autorizačním serverům se nezdařilo"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Přidat server do instance"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Přidat servery do instance"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Přidat do instance"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Přidat do {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Přidáno"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Už přidáno"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Prozkoumat obsah"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Prozkoumat servery"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Skrýt přidané servery"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Skrýt nainstalovaný obsah"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Nainstalovat obsah do instnce"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Přidej popis modpacku..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exportovat"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportovat modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Jméno Modpacku"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Jméno modpacku"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Vybrat soubory a složky co zahrnout do modpacku"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Číslo verze"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Všechna data z instance budou navždy smazána, včetně světů, nastavení a všeho ostatního."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Tato akce nemůže být vrácena"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Odstranit instanci"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Odstanit instanci"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Tento modpack je už nainstalovaný v instanci <bold>{instanceName}</bold>. Opravdu ho chceš duplikovat?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Vytvořit"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpack už je nainstalovaný"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" bylo přidáno"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} projektů bylo přidáno"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Podívejte se na projekty co používám ve svém modpacku!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Sdílení obsahu modpacku"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Úspěšně nahráno"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Přidat server"
|
||||
},
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Procházet servery"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "\"{name}\" bude **navždy smazáno** a nebude způsob, jak to obnovit."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Opravdu si jsi jistý, že chceš navždy smazat tenhle svět?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modováno"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Přidej nebo procházej servery"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Žádné servery nebo světy nebyly přidány"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "„{name}“ bude odstraněn z tvého seznamu, včetně hry, a nebude žádný způsob, jak ho obnovit."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Opravdu chceš odstranit {name}?"
|
||||
},
|
||||
"app.instance.worlds.search-worlds-placeholder": {
|
||||
"message": "Hledat ve světech {count}..."
|
||||
},
|
||||
"app.instance.worlds.this-server": {
|
||||
"message": "tento server"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Nainstaluj ke hraní"
|
||||
},
|
||||
@@ -14,48 +155,21 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural,one {#mód} other {#módy}}"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} dnes s vámi sdílel tuto instanci."
|
||||
},
|
||||
"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.update-to-play.added-count": {
|
||||
"message": "{count} přidáno"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Přidáno"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Odebráno"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Aktualizováno"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Updatuj ke hraní"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} odstraněno"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Je vyžadována aktualizace"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "Je nutná aktualizace ke hraní {name}. Prosím updatuj na nejnovější verzi k spuštění hry."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} aktualizováno"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Vývojářský režim povolen."
|
||||
},
|
||||
@@ -68,9 +182,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Výchozí možnosti instance"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Vlajky funkcí"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalace Javy"
|
||||
},
|
||||
@@ -83,38 +194,8 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Správa zdrojů"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Aplikace Modrinth v{version} je připravena k instalaci! Nainstalujte aktualizaci nyní nebo automaticky po zavření aplikace Modrinth."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Stahování aplikace Modrinth v{version} bylo dokončeno. Nainstalujte aktualizaci nyní nebo automaticky po zavření aplikace Modrinth."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} je k dispozici. Aktualizujte pomocí svého správce balíčků, abyste získali nejnovější funkce a opravy!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Aplikace Modrinth v{version} je nyní k dispozici! Protože jste v měřené síti, nebyla stažena automaticky."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Seznam změn"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"message": "Stahování ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Stáhnout"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Stahování..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Načíst znovu"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Aktualizace je k dispozici"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Stahování bylo dokončeno"
|
||||
"app.update-popup.download": {
|
||||
"message": "Stáhnout ({size})"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Kliknutím sem zobrazíte seznam změn."
|
||||
@@ -135,7 +216,7 @@
|
||||
"message": "Přidat přítele"
|
||||
},
|
||||
"friends.action.view-friend-requests": {
|
||||
"message": "{count} {count, plural, one {žádost} few {žádosti} other {žádostí}} o přátelství"
|
||||
"message": "{count} přátelé {count, plural, one {request} other {requests}}"
|
||||
},
|
||||
"friends.add-friend.submit": {
|
||||
"message": "Poslat žádost o přátelství"
|
||||
@@ -230,12 +311,6 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Upravit svět"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Vypnuté projekty"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "K dispozice jsou aktualizace"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresa"
|
||||
},
|
||||
@@ -344,141 +419,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instalace"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} pro Minecraft {game_version} již je nainstalována"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} již je nainstalována"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Změnit verzi"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Instalování"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Načítání verzí modpacku"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Instalace nové verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Aktuálně nainstalováno"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Debugové informace:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Načítání detailů modpacku"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Verze hry"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Probíhá instalace"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Nelze načíst podrobnosti o modpacku. Prosím, zkontrolujte své připojení k internetu."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} není dostupný pro Minecraft {version}. Zkuste jiný mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Tato instalace je připojená k modpacku, který ake nebyl najit na Modrinthu."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platforma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Přeinstalovat modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Přeinstalovávání modpacku"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Přeinstalace resetuje veškerý nainstalovaný nebo upravený obsah kromě toho, co poskytuje modpack, a odstraní všechny módy nebo obsah, které jste přidali do původní instalace. To může opravit neočekávané chyby, ale pokud vaše světy závisejí na doinstalovaném obsahu, možná budou poškozeny."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Opravdu si přejete přeinstalovat tuto instalaci?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Obnoví obsah instance do původního stavu a odstraní všechny mody nebo obsah, které jste přidali nad původní modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Přeinstalovat modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Opravit"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Opravováno"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Oprava přeinstaluje závislosti Minecraftu a zkontroluje poškození. To může vyřešit problémy, pokud se hra nespustí kvůli chybám souvisejícím s launcherem, ale nevyřeší to problémy nebo pády související s nainstalovanými mody."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Opravit instanci?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Probíhá oprava"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Resetovat na aktuální"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Ukázat všechny verze"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "změnit verzi"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Instalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "přeinstalovat"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "opravit"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Nelze {action} při instalaci"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Nelze {action} když offline"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Nelze {action} při opravě"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(neznámá verze)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Odpojit instanci"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Pokud budete pokračovat, nebudete ji moci znovu propojit bez vytvoření zcela nové instance. Již nebudete dostávat aktualizace modpacku a stane se z něj běžná instance."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Opravdu si přejete odpojit tuto instanci?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Tato instance je připojena k modpacku, což znamená, že módy nemohou být aktualizované a nelze změnit mod loader ani verze minecraftu. Odpojení permanentně rozváže tuto instanci od modpacku."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Odpojit od modpacku"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java a pamět"
|
||||
},
|
||||
@@ -539,9 +482,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nezobrazuje na domovské stránce"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Dostupné"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instance je již otevřená"
|
||||
},
|
||||
@@ -558,17 +498,11 @@
|
||||
"message": "Můžeš rovnou skočit na server pouze v Minecraftu Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Můžeš se rovnou připojit do světa jednoho hráče pouze v Minecraftu 1.20+"
|
||||
"message": "V Minecraftu 1.20+ se dá rovnou přeskočit pouze do singleplayerových světů"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Hrát instanci"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Hra pro jednoho hráče"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Zobrazit instanci"
|
||||
},
|
||||
@@ -582,9 +516,18 @@
|
||||
"message": "Verze hry je poskytnut instanci"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Spouštěč je poskytnut instanci"
|
||||
"message": "Spouštěč je poskytnut instancí"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchronizováno z instancí"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Jen klientské mody mohou být přidány na server"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Verzi hry poskytuje server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader zprostředkovává server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,90 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Kan ikke nå autentificeringsservere"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Tilføjet til {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Tilføjet"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Allerede tilføjet"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Opdag indhold"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Opdag servere"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Gem tilføjet servere"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Gem installeret indhold"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Indtast modpack beskrivelse..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Eksporter"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Eksporter modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpack Navn"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpack navn"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Vælg filer og mapper til at inkludere i pakken"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versionsnummer"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Denne handling kan ikke fortrydes"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Slet instance"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Slet instance"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Denne modpack er allerede installeret i <bold>{instanceName}</bold> instancen. Er du sikker på du vil duplikere den?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Opret"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" blev tilføjet"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} projekter blev tilføjet"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Tjek ud disse projekter jeg bruger i min modpack!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Deler modpack indhold"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Uploadet"
|
||||
},
|
||||
"app.modal.install-to-play.content-required": {
|
||||
"message": "Indhold krævet"
|
||||
},
|
||||
"app.modal.install-to-play.header": {
|
||||
"message": "Installer for at spille"
|
||||
},
|
||||
@@ -14,36 +98,30 @@
|
||||
"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. Klik installer for at sætte op filerne som er krævet fra Modrinth."
|
||||
"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.update-to-play.added-count": {
|
||||
"message": "{count} tilføjet"
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "Delt instance"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Tilføjet"
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Delt server instance"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Fjernet"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Opdateret"
|
||||
"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.removed-count": {
|
||||
"message": "{count} fjernet"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} opdateret"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Udvikler-tilstand aktiveret."
|
||||
},
|
||||
@@ -56,9 +134,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standardindstillinger for instans"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funktionsflags"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Javainstallationer"
|
||||
},
|
||||
@@ -71,39 +146,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressourcestyring"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} er allerede installeret! Genindlæs for at opdatere nu, eller automatisk når du lukker Modrinth App."
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App v{version} er klar til at blive installeret! Genindlæs for at opdatere nu, eller automatisk når du lukker Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} er færdig med at download. Genindlæs for at opdatere nu, eller automatisk når du lukker Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} er nu tilgængelig. Brug din pakke-manager til at opdatere for de nyeste features og fejlrettelser!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App v{version} er nu tilgængelig! Siden du er på et begrænset netværk, vi downloadede den ikke automatisk."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Ændringslog"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Download ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Download"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Download færdiggjort"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Downloader..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Geninlæs"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "Opdatering tilgængelig"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download færdiggjort"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klik her for at vise ændringslog."
|
||||
},
|
||||
@@ -218,12 +287,6 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Rediger verden"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Deaktiverede projekter"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Tilgængelige opdateringer"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
},
|
||||
@@ -332,141 +395,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} for Minecraft {game_version} er allerede installeret"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} er allerede installeret"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Skift version"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Får modpack versioner"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Installere ny version"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Lige nu installeret"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Debug information:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Får modpack detaljer"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spil version"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Installation igangværende"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Kan ikke få forbundet modpack detaljer. Venligst tjek din internet forbindelse."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} er ikke mulig at bruge for Minecraft {version}. Prøv en anden mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Denne instance er koblet til en modpack, men modpacken kunne ikke blive fundet på Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Geninstaller modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Geninstallere modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Geninstallering vil nulstille alt installeret eller modificeret indhold givet af modpacken, fjerne alle mods eller indhold du har tilføjet ovenpå den originale installation. Dette vil måske fikse uforventet adfærd hvis ændringer er blevet lavet til den instance, men hvis din verdener nu afhænger af ektra tilføjet indhold, dette vil måske ødelægge eksisterende verdener."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Er du sikker på du vil geninstallere denne instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Nulstiller instanceens indhold til dens oprindelige tilstand, fjerne alle mods eller indhold du har tilføjet ovenpå den oprindelige modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Geninstaller modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparere"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparering geninstaller Minecraft afhængigheder og tjekker for korruption. Dette vil måske fikse fejl hvis dit spil ikke køre på grund af launcher relateret fejl, men vil ikke fikse fejl eller crashes relateret til installerede mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Reparer instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparation i gang"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Nulstil til nuværende"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Vis alle versioner"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Ændre version"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "Geninstaller"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "Reparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Kan ikke {action} under installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Kan ikke {action} uden internet"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Kan ikke {action} under reparation"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(Ukendt version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Frakoble instance"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Hvis du forsætter, du vil ikke have mulighed for at koble sammen igen uden at lave en helt ny instance. Du vil ikke længere modtage modpack opdateringer og vil blive en normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Er du sikker på du vil frakoble denne instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Denne instance er forbundet til en modpack, hvilket betyder mods kan ikke blive opdateret og du kan ikke ændre mod loaderen eller Minecraft version. Frakobling vil permanent frakoble denne instance fra modpacken."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Frakoble fra modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java og hukommelse"
|
||||
},
|
||||
@@ -527,9 +458,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Vis ikke på forsiden"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Tilgængelig"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instance allerede åben"
|
||||
},
|
||||
@@ -539,6 +467,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Serveren er uforenelig"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Styret af server projektet"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Serveren kunne ikke blive kontaktet"
|
||||
},
|
||||
@@ -551,12 +482,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Spil instance"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Singleplayer"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Se instance"
|
||||
},
|
||||
@@ -574,5 +499,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkroniser med instance"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Givet af serveren"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Kun klient-sided mods kan blive tilføjet til denne server instance"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spille version er givet af serveren"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader er givet af serveren"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Authentifizierungsserver sind nicht erreichbar"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Server zu Instanz hinzufügen"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Server zu deiner Instanz hinzufügen"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Zu Instanz hinzufügen"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Zu {instanceName} hinzufügen"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Hinzugefügt"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Bereits hinzugefügt"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Inhalte entdecken"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Server entdecken"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Hinzugefügte Server ausblenden"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Installierte Inhalte ausblenden"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Inhalt in Instanz installieren"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Modpaketbeschreibung eingeben..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exportieren"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Modpack exportieren"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpaketname"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpaketname"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Wähle Dateien und Ordner zum hinzufügen im Paket aus"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versionsnummer"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle Daten deiner Instanz werden permanent gelöscht, inlusive deiner Welten, Konfigurationen und allen installierten Inhalten."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Diese Aktion kann nicht rückgängig gemacht werden"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Dieses Modpack ist bereits in der Instanz <bold>{instanceName}</bold> installiert. Möchtest du es wirklich duplizieren?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Erstellen"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpack bereits installiert"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instanz"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "Projekt"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" wurde hinzugefügt"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} Projekte wurden hinzugefügt"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Schau dir die Projekte, welche ich in meinem Modpaket nutze an!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Modpaketinhalte teilen"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Erfolgreich hochgeladen"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Server hinzufügen"
|
||||
},
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Server durchsuchen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "„{name}“ wird **endgültig gelöscht**, und es gibt keine Möglichkeit, sie wiederherzustellen."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Möchtest du diese Welt wirklich endgültig löschen?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modifiziert"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Füge einen Server hinzu oder durchsuche, um loszulegen"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Keine Server oder Welten hinzugefügt"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "„{name}“ wird aus deiner Liste entfernt, auch im Spiel, und es gibt keine Möglichkeit, ihn wiederherzustellen."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "„{name}“ ({address}) wird aus deiner Liste entfernt, inklusive im Spiel, und es gibt keine Möglichkeit, ihn wiederherzustellen."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Möchtest du {name} wirklich entfernen?"
|
||||
},
|
||||
"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.header": {
|
||||
"message": "Installieren zum Spielen"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# Mod} other {# Mods}}"
|
||||
},
|
||||
"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 einzurichten."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Benötigtes Modpack"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} hat diese Instanz heute mit dir geteilt."
|
||||
"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.shared-instance": {
|
||||
"message": "Geteilte Instanz"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Geteilte Server Instanz"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Aktualisiert"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Inhalte ansehen"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualisieren zum Spielen"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aktualisierung benötigt"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} aktualisiert"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Entwicklermodus aktiviert."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standard Instanz-Einstellungen"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funktionsflaggen"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java Installationen"
|
||||
},
|
||||
@@ -83,39 +209,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressourcenmanagement"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth App v{version} ist bereit zur Installation! Lade die App neu, oder schliesse sie, um zu aktualisieren."
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App v{version} ist bereit zur Installation! Lade die App neu um jetzt zu aktualisieren, oder automatisch nach dem schliessen der Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Lade die App neu, oder schliesse sie, um zu aktualisieren."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Lade die App neu um jetzt zu aktualisieren, oder automatisch nach dem schliessen der Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} ist verfügbar. Benutze deinen Paketmanager zum aktualisieren um die neusten Features und Bugfixes zu erhalten!"
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} ist verfügbar. Benutze deinen Paketmanager zum aktualisieren, um die neusten Features und Bugfixes zu erhalten!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App v{version} ist jetzt verfügbar! Da du in einem begrenzten Netzwerk bist, haben wir es nicht automatisch heruntergeladen."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Änderungen"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Herunterladen ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Herunterladen"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Download abgeschlossen"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Lade herunter..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Neu Laden"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "Aktualisierung verfügbar"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download abgeschlossen"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klicke Hier um die Änderungen zu sehen."
|
||||
},
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Lade neu um Aktualisierung zu installieren"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Wählen eine Option"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Inkompatible Version {version}"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Noch nicht gespielt"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} online"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Freund hinzufügen"
|
||||
},
|
||||
@@ -150,10 +288,10 @@
|
||||
"message": "Modrinth Nutzernamen eingeben..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "Was ist der Modrinth Nutzername deines Freundes?"
|
||||
"message": "Was ist der Modrinth-Nutzername deines Freundes?"
|
||||
},
|
||||
"friends.add-friends-to-share": {
|
||||
"message": "<link>Füge Freunde hinzu</link> um zu sehen, was sie spielen!"
|
||||
"message": "<link>Füge Freunde hinzu</link>, um zu sehen, was sie spielen!"
|
||||
},
|
||||
"friends.friend.cancel-request": {
|
||||
"message": "Anfrage abbrechen"
|
||||
@@ -192,7 +330,7 @@
|
||||
"message": "{title} - {count}"
|
||||
},
|
||||
"friends.sign-in-to-add-friends": {
|
||||
"message": "<link>Logge dich in ein Modrinth Konto ein</link> um Freunde hinzuzufügen und zu sehen, was sie spielen!"
|
||||
"message": "<link>Logge dich in ein Modrinth Konto ein</link>, um Freunde hinzuzufügen und zu sehen, was sie spielen!"
|
||||
},
|
||||
"instance.add-server.add-and-play": {
|
||||
"message": "Ersteue u starte"
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Welt bearbeiten"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Deaktivierte Projekte"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Dateien werden hinzugefügt ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Updates verfügbar"
|
||||
"instance.files.save-as": {
|
||||
"message": "Speichern unter..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
@@ -312,13 +450,13 @@
|
||||
"message": "Hooks ermöglichen es erfahrenen Benutzern, bestimmte Systembefehle vor und nach dem Start des Spiels auszuführen."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Nach dem Schliessen des Spiels"
|
||||
"message": "Nach dem Schließen des Spiels"
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.description": {
|
||||
"message": "Wird nach dem Beenden des Spiels ausgeführt."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit.enter": {
|
||||
"message": "Ausgeführter Befehl nach dem Beenden des Spiels eingeben..."
|
||||
"message": "Nach dem Beenden des Spiels auszuführenden Befehl eingeben..."
|
||||
},
|
||||
"instance.settings.tabs.hooks.pre-launch": {
|
||||
"message": "Vor Start des Spiels"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} für Minecraft {game_version} ist bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} ist bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Sammle Modpack-Versionen"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Neue Version wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Aktuell installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Informationen zur Fehlerbehebung:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Sammle Modpack-Details"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spielversion"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} Version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Kann Details für verknüpftes Modpack nicht abrufen. Bitte überprüfe deine Internerverbindung."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} ist nicht verfügbar für Minecraft {version}. Versuch einen anderen Modloader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft, aber das Modpack konnte nicht auf Modrinth gefunden werden."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Modpack wird neu installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Durch die Neuinstallation werden alle installierten oder geänderten Inhalte auf die vom Modpack bereitgestellten Inhalte zurückgesetzt, wobei alle Mods oder Inhalte entfernt werden, die zusätzlich zur ursprünglichen Installation hinzugefügt wurden. Dies kann unerwartetes Verhalten beheben, wenn Änderungen an der Instanz vorgenommen wurden. Wenn deine Welten jedoch von zusätzlich installierten Inhalten abhängig sind, kann dies zu Fehlern in bestehenden Welten führen."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Bist du sicher, dass du diese Instanz neu installieren willst?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Setzt den Inhalt der Instanz auf seinen ursprünglichen Zustand zurück und entfernt all Mods oder Inhalte, welche zusätzlich zum ursprünglichen Modpack hinzugefügt wurden."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Wird repariert"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Das reparieren installier Minecraft-Abhängigkeiten neu und überprüft für Beschädigungen. Dies kann Probleme beheben, sofern dein Spiel aufgrund von Launcher-relevanten Problemen nicht startet, aber es kann nicht Fehler und Abstpürze in Zusammenhang mit installierten Mods beheben."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Instanz reparieren?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Wird repariert"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Auf aktuellen Wert zurücksetzen"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Alle Versionen anzeigen"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "Neuinstallieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "{action} während der Installation nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "{action} nicht möglich ohne Internetverbindung"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "{action} während reparatur nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(unbekannte Version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Verlinking der Instanz trennen"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Wenn du fortfährst, kann die Instanz nicht erneut verknüpft werden, ohne eine komplett neue Instanz zu ersztellen. Du erhälst keine Modpack-Updates mehr und es wird zu einer normalen Instanz."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Bist du sicher, dass du die Verknüpfung dieser Instanz trennen willst?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft. Dies bedeutet, dass Mods nicht aktualisiert werden können, und dass du den Modloader oder die Minecraft Versionen nicht ändern kannst. Durch das trennen der Verknüpfung wird die Instanz permanent vom Modpack getrennt."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Verknüpfung vom Modpack trennen"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java und Arbeitsspeicher"
|
||||
},
|
||||
@@ -507,13 +513,13 @@
|
||||
"message": "Vollbild"
|
||||
},
|
||||
"instance.settings.tabs.window.fullscreen.description": {
|
||||
"message": "Startet das Spiel im Vollbildmodus (durch verwenden von options.txt)."
|
||||
"message": "Startet das Spiel im Vollbildmodus (mithilfe von options.txt)."
|
||||
},
|
||||
"instance.settings.tabs.window.height": {
|
||||
"message": "Höhe"
|
||||
},
|
||||
"instance.settings.tabs.window.height.description": {
|
||||
"message": "Die höhe des Spielfensters beim Start."
|
||||
"message": "Die Höhe des Spielfensters beim Start."
|
||||
},
|
||||
"instance.settings.tabs.window.height.enter": {
|
||||
"message": "Höhe eingeben..."
|
||||
@@ -528,7 +534,7 @@
|
||||
"message": "Breite eingeben..."
|
||||
},
|
||||
"instance.worlds.a_minecraft_server": {
|
||||
"message": "Ä Minecraft-Server"
|
||||
"message": "Ein Minecraft-Server"
|
||||
},
|
||||
"instance.worlds.cant_connect": {
|
||||
"message": "Verbindung mit Server nicht möglich"
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nicht auf Startseite anzeigen"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Verfügbar"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instanz ist bereits geöffnet"
|
||||
},
|
||||
@@ -549,42 +552,51 @@
|
||||
"message": "Hardcore-Modus"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Server ist inkompatibel"
|
||||
"message": "Server ist nicht kompatibel"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Von Serverprojekt verwaltet"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server konnte nicht erreicht werden"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Du kannst nur in Minecraft Alpha 1.0.5 und neuer direkt einem Server beitreten"
|
||||
"message": "Du kannst nur mit Minecraft Alpha 1.0.5 und neuer einem Server direkt beitreten"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Du kannst nur in Minecraft 1.20 und neuer einer Einzelspieler-Welt beitreten"
|
||||
"message": "Du kannst nur mit Minecraft 1.20 und neuer einer Einzelspieler-Welt direkt beitreten"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Instanz Spielen"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Einzelspieler"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Instanz anzeigen"
|
||||
},
|
||||
"instance.worlds.world_in_use": {
|
||||
"message": "Welt bereits in benutzung"
|
||||
"message": "Welt bereits in Benutzung"
|
||||
},
|
||||
"search.filter.locked.instance": {
|
||||
"message": "Von der Instanz bereitgestellt"
|
||||
"message": "Von der Instanz vorgegeben"
|
||||
},
|
||||
"search.filter.locked.instance-game-version.title": {
|
||||
"message": "Spielversion ist von der Instanz bereitgestellt"
|
||||
"message": "Spielversion ist von der Instanz vorgegeben"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "Loader ist von der Instanz bereitgestellt"
|
||||
"message": "Loader ist von der Instanz vorgegeben"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Mit Instanz synchronisieren"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Vom Server bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Nur Clientseitige Mods können der Serverinstanz hinzugefügt werden"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spielversion wird vom Server bereitgestellt"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader wird vom Server bereitgestellt"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Authentifizierungsserver sind nicht erreichbar"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Server zur Instanz hinzufügen"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Server zu deiner Instanz hinzufügen"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Zur Instanz hinzufügen"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Zu {instanceName} hinzufügen"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Hinzugefügt"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Bereits hinzugefügt"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Inhalte entdecken"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Server entdecken"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Hinzugefügte Server ausblenden"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Installierte Inhalte ausblenden"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Inhalt in Instanz installieren"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Beschreibung des Modpacks eingeben..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exportieren"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Modpack exportieren"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpackname"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpackname"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Wähle Dateien und Ordner aus, die in das Paket sollen"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versionsnummer"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Alle Daten deiner Instanz werden permanent gelöscht, einschließlich deiner Welten, Konfigurationen und allen installierten Inhalten."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Diese Aktion kann nicht rückgängig gemacht werden"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Instanz löschen"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Dieses Modpack ist bereits in der Instanz <bold>{instanceName}</bold> installiert. Möchtest du es wirklich duplizieren?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Erstellen"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpack bereits installiert"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instanz"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "Projekt"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" wurde hinzugefügt"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} Projekte wurden hinzugefügt"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Schau dir die Projekte an, die ich in meinem Modpack verwende!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Modpackinhalte teilen"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Erfolgreich hochgeladen"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Server hinzufügen"
|
||||
},
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Server durchsuchen"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "„{name}“ wird **endgültig gelöscht**, und es gibt keine Möglichkeit, sie wiederherzustellen."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Möchtest du diese Welt wirklich endgültig löschen?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modifiziert"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Füge einen Server hinzu oder durchsuche, um loszulegen"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Keine Server oder Welten hinzugefügt"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "„{name}“ wird aus deiner Liste entfernt, auch im Spiel, und es gibt keine Möglichkeit, ihn wiederherzustellen."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "„{name}“ ({address}) wird aus deiner Liste entfernt, inklusive im Spiel, und es gibt keine Möglichkeit, ihn wiederherzustellen."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Möchtest du {name} wirklich entfernen?"
|
||||
},
|
||||
"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.header": {
|
||||
"message": "Installieren zum Spielen"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# Mod} other {# Mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Dieser Server benötigt Mods zum Spielen. Klick auf „Installieren“ um die erforderlichen Dateien von Modrinth zu installieren."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Benötigtes Modpack"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} hat diese Instanz heute mit dir geteilt."
|
||||
"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.shared-instance": {
|
||||
"message": "Geteilte Instanz"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Geteilte Serverinstanz"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Hinzugefügt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Aktualisiert"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Inhalte ansehen"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Aktualisieren zum Spielen"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} entfernt"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Aktualisierung erforderlich"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} aktualisiert"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Entwicklermodus aktiviert."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Standard Instanz-Einstellungen"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funktionsflags"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java-Installationen"
|
||||
},
|
||||
@@ -83,38 +209,32 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Ressourcenmanagement"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App v{version} ist bereit zur Installation! Neu laden, um jetzt zu aktualisieren, oder automatisch, wenn du die Modrinth App schließt."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth App v{version} wurde heruntergeladen. Neu laden, um jetzt zu aktualisieren, oder automatisch, wenn du die Modrinth App schließt."
|
||||
"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."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} ist verfügbar. Verwende deinen Paketmanager, um die neuesten Funktionen und Fehlerbehebungen zu installieren!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App v{version} ist jetzt verfügbar! Da du ein getaktetes Netzwerk nutzt, haben wir den Download nicht automatisch gestartet."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Änderungsverlauf"
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Änderungen"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Herunterladen ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Herunterladen"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Download abgeschlossen"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Wird Heruntergeladen..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Neu laden"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Update verfügbar"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download abgeschlossen"
|
||||
"app.update-popup.title": {
|
||||
"message": "Aktualisierung verfügbar"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Hier klicken, um das Änderungsprotokoll anzuzeigen."
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Neu laden, um das Update zu installieren"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Wählen eine Option"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Inkompatible Version {version}"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Noch nicht gespielt"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} online"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Freund hinzufügen"
|
||||
},
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Welt bearbeiten"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Deaktivierte Projekte"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Dateien werden hinzugefügt ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Updates verfügbar"
|
||||
"instance.files.save-as": {
|
||||
"message": "Speichern unter..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} für Minecraft {game_version} bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} ist bereits installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Modpack-Versionen werden abgerufen"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Neue Version wird installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Derzeit installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Informationen für die Fehlerbehebung:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Modpack-Details werden abgerufen"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Spielversion"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Installation im Gange"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} Version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Die Details des verknüpften Modpacks können nicht abgerufen werden. Bitte überprüfe deine Internetverbindung."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} ist nicht für Minecraft {version} verfügbar. Versuche einen anderen Modloader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft, aber das Modpack konnte auf Modrinth nicht gefunden werden."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plattform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Modpack wird neu installiert"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Eine Neuinstallation setzt alle installierten oder geänderten Inhalte auf den Zustand zurück, der vom Modpack bereitgestellt wird, und entfernt alle Mods oder Inhalte, die du zusätzlich zur ursprünglichen Installation hinzugefügt hast.\nDies kann unerwartetes Verhalten beheben, falls Änderungen an der Instanz vorgenommen wurden. Wenn deine Welten jedoch von zusätzlich installierten Inhalten abhängen, kann dies bestehende Welten beschädigen."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Bist du dir sicher, dass du diese Instanz neu installieren willst?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Setzt den Inhalt der Instanz auf den ursprünglichen Zustand zurück und entfernt alle Mods oder Inhalte, die du zusätzlich zum ursprünglichen Modpack hinzugefügt hast."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Modpack neu installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Wird repariert"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Durch die Reparatur werden die Abhängigkeiten von Minecraft neu installiert und auf Beschädigungen überprüft. Dies kann Probleme beheben, wenn Minecraft aufgrund von Fehlern im Launcher nicht startet, löst jedoch keine Probleme oder Abstürze im Zusammenhang mit installierten Mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Instanz reparieren?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparatur im Gange"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Auf aktuellen Stand zurücksetzen"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Alle Versionen anzeigen"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "Version ändern"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "Installieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "Neuinstallieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "Reparieren"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "{action} während der Installation nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "{action} offline nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "{action} während der Reparation nicht möglich"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(unbekannte Version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Verknüpfung der Instanz trennen"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Wenn du fortfährst, kannst du sie nicht erneut verknüpfen, ohne eine völlig neue Instanz zu erstellen. Du wirst keine Modpack-Updates mehr erhalten, und sie wird zu einer normalen Instanz."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Möchtest du die Verknüpfungen dieser Instanz wirklich trennen?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Diese Instanz ist mit einem Modpack verknüpft. Das bedeutet, dass Mods nicht aktualisiert werden können und der Mod-Loader oder die Minecraft-Version nicht geändert werden können. Durch das Aufheben der Verknüpfung wird die Instanz dauerhaft vom Modpack getrennt."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Verknüpfung vom Modpack trennen"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java und Arbeitsspeicher"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Nicht auf der Startseite anzeigen"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Verfügbar"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instanz ist bereits geöffnet"
|
||||
},
|
||||
@@ -551,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Server ist nicht kompatibel"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Von Serverprojekt verwaltet"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server konnte nicht erreicht werden"
|
||||
},
|
||||
@@ -563,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Instanz spielen"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Einzelspieler"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Instanz anzeigen"
|
||||
},
|
||||
@@ -586,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Mit Instanz synchronisieren"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Vom Server vorgegeben"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Nur clientseitige Mods können der Serverinstanz hinzugefügt werden"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Spielversion vom Server vorgegeben"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader vom Server vorgegeben"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Cannot reach authentication servers"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Add server to instance"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Add servers to your instance"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Add to instance"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Add to {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Added"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Already added"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Discover content"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Discover servers"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Hide added servers"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Hide installed content"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Install content to instance"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Enter modpack description..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Export"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Export modpack"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "Modpack Name"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "Modpack name"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Select files and folders to include in pack"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Version number"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "All data for your instance will be permanently deleted, including your worlds, configs, and all installed content."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "This action cannot be undone"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Delete instance"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Delete instance"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "This modpack is already installed in the <bold>{instanceName}</bold> instance. Are you sure you want to duplicate it?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Create"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpack already installed"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "project"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" was added"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} projects were added"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Check out the projects I'm using in my modpack!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Sharing modpack content"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Successfully uploaded"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Add server"
|
||||
},
|
||||
"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-title": {
|
||||
"message": "Are you sure you want to permanently delete this world?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modded"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Add a server or browse to get started"
|
||||
},
|
||||
"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-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-title": {
|
||||
"message": "Are you sure you want to remove {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.header": {
|
||||
"message": "Install to play"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"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."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Required modpack"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} shared this instance with you today."
|
||||
"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.shared-instance": {
|
||||
"message": "Shared instance"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Shared server instance"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} added"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Added"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Removed"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Updated"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "View contents"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Update to play"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} removed"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Update required"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} updated"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Developer mode enabled."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Default instance options"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Feature flags"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java installations"
|
||||
},
|
||||
@@ -83,39 +209,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Resource management"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App v{version} is ready to install! Reload to update now, or automatically when you close Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"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."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} is available. Use your package manager to update for the latest features and fixes!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App v{version} is available now! Since you're on a metered network, we didn't automatically download it."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Changelog"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Download ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Download"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Download complete"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Downloading..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Reload"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "Update available"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Download complete"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Click here to view the changelog."
|
||||
},
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Reload to install update"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Select an option"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Incompatible version {version}"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Not played yet"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} online"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Add a friend"
|
||||
},
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Edit world"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Disabled projects"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Adding files ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Updates available"
|
||||
"instance.files.save-as": {
|
||||
"message": "Save as..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Address"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} for Minecraft {game_version} already installed"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} already installed"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Change version"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Install"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Installing"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Fetching modpack versions"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Installing new version"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Currently installed"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Debug information:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Fetching modpack details"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Game version"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Install"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Installation in progress"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} version"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Cannot fetch linked modpack details. Please check your internet connection."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} is not available for Minecraft {version}. Try another mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "This instance is linked to a modpack, but the modpack could not be found on Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Reinstall modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Reinstalling modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Reinstalling will reset all installed or modified content to what is provided by the modpack, removing any mods or content you have added on top of the original installation. This may fix unexpected behavior if changes have been made to the instance, but if your worlds now depend on additional installed content, it may break existing worlds."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Are you sure you want to reinstall this instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Resets the instance's content to its original state, removing any mods or content you have added on top of the original modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstall modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Repair"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Repairing"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Repairing reinstalls Minecraft dependencies and checks for corruption. This may resolve issues if your game is not launching due to launcher-related errors, but will not resolve issues or crashes related to installed mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Repair instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Repair in progress"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Reset to current"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Show all versions"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "change version"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "install"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "reinstall"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "repair"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Cannot {action} while installing"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Cannot {action} while offline"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Cannot {action} while repairing"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(unknown version)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Unlink instance"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "If you proceed, you will not be able to re-link it without creating an entirely new instance. You will no longer receive modpack updates and it will become a normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Are you sure you want to unlink this instance?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "This instance is linked to a modpack, which means mods can't be updated and you can't change the mod loader or Minecraft version. Unlinking will permanently disconnect this instance from the modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Unlink from modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java and memory"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Don't show on Home"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Available"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instance is already open"
|
||||
},
|
||||
@@ -551,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Server is incompatible"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Managed by server project"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Server couldn't be contacted"
|
||||
},
|
||||
@@ -563,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Play instance"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Singleplayer"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "View instance"
|
||||
},
|
||||
@@ -586,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sync with instance"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Provided by the server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Only client-side mods can be added to the server instance"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Game version is provided by the server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Loader is provided by the server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "No se puede acceder a los servidores de autenticación"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Añadir servidor a instancia"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Añade servidores a tu instancia"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Añadir a instancia"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Añadir a {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Añadido"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Ya se ha añadido"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Descubrir contenido"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descubrir servidores"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Ocultar servidores añadidos"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Ocultar contenido instalado"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Instalar contenido a la instancia"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Introduce la descripción del modpack..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exportar"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportar modpack"
|
||||
},
|
||||
"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": "Selecciona archivos y carpetas para incluirlos en el pack"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Número de la versión"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Esta acción no se puede deshacer"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "El modpack ya está instalado en la instancia <bold>{instanceName}</bold>. ¿Estás seguro de querer duplicarlo?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Crear"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Este modpack ya está instalado"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instancia"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "proyecto"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "Se añadió \"{name}\""
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "Se añadieron {count} proyectos"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "¡Mira a los proyectos que estoy usando en mi modpack!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Compartiendo contenido del modpack"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Cargado correctamente"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Añadir servidor"
|
||||
},
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Explorar servidores"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "\"{name}\" se **eliminará permanentemente** y no habrá forma de recuperarlo."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "¿Estás seguro de que quieres eliminar este mundo de forma permanente?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Con mods"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Sin conexión"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "En línea"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Añadir un servidor o explora para comenzar"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "No hay servidores ni mundos añadidos"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "\"{name}\" se eliminará de tu lista, también dentro del juego, y no podrás recuperarlo."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "\"{name}\" ({address}) se eliminará de tu lista, también dentro del juego, y no podrás recuperarlo."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "¿Estás seguro de que quieres eliminar {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.header": {
|
||||
"message": "Instala para jugar"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requiere mods para jugar. Haz clic en instalar para configurar los archivos necesarios desde Modrinth."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requerido"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} compartió esta instancia contigo hoy."
|
||||
"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.shared-instance": {
|
||||
"message": "Instancia compartida"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instancia de servidor compartida"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} agregados"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Se agregó"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Se eliminó"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Actualizado"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Ver contenidos"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Actualiza para jugar"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} eliminados"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Actualización requerida"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} actualizados"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Opciones predeterminadas de la instancia"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funciones experimentales"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalaciones de Java"
|
||||
},
|
||||
@@ -83,39 +209,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Gestión de recursos"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "¡Modrinth App v{version} lista para instalar! Actualiza ahora o automáticamente al cerrar la aplicación."
|
||||
"app.update-popup.body": {
|
||||
"message": "¡Modrinth App v{version} está lista para instalarse! Actualiza ahora o automáticamente al cerrar la Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "La descarga de la Modrinth App v{version} ha finalizado. Actualiza ahora o automáticamente al cerrar la aplicación Modrinth."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "La descarga de la Modrinth App v{version} ha finalizado. Actualiza ahora o automáticamente al cerrar la Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "La aplicación Modrinth v{version} ya está disponible. ¡Utiliza tu gestor de paquetes para actualizarla y disfrutar de las últimas funciones y correcciones!"
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "La Modrinth App v{version} está disponible. ¡Usa tu gestor de paquetes para actualizarla y tener las últimas funciones y corrección de errores!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "¡Modrinth App v{version} ya está disponible! Como estás en una red con límite de datos, no se descargó automáticamente."
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "¡La Modrinth App v{version} ya está disponible! Al estar usando una red de datos límitada, no la hemos descargado automáticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Registro de cambios"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Descargar ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Descargar"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Descarga completada"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Descargando..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Recargar"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "Actualización disponible"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Descarga completada"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Haz clic aquí para ver el registro de cambios."
|
||||
},
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Recarga para instalar la actualización"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "ejemplo.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Selecciona una opción"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Versión {version} incompatible"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Aún no se ha jugado"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Desconectado"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} en línea"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Añadir un amigo"
|
||||
},
|
||||
@@ -147,7 +285,7 @@
|
||||
"message": "¡Podría ser distinto a su nombre de usuario de Minecraft!"
|
||||
},
|
||||
"friends.add-friend.username.placeholder": {
|
||||
"message": "Ingresa tu nombre de usuario de Modrinth..."
|
||||
"message": "Introduce el nombre de usuario de Modrinth..."
|
||||
},
|
||||
"friends.add-friend.username.title": {
|
||||
"message": "¿Cuál es el nombre de usuario de Modrinth de tu amigo?"
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Editar mundo"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Proyectos desactivados"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Añadiendo archivos ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Actualizaciones disponibles"
|
||||
"instance.files.save-as": {
|
||||
"message": "Guardar como..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Dirección IP"
|
||||
@@ -297,7 +435,7 @@
|
||||
"message": "Los grupos de la librería te ayudan a organizar tus instancias en diferentes secciones en tu librería."
|
||||
},
|
||||
"instance.settings.tabs.general.library-groups.enter-name": {
|
||||
"message": "Ingresa el nombre del grupo"
|
||||
"message": "Escribe nombre del grupo"
|
||||
},
|
||||
"instance.settings.tabs.general.name": {
|
||||
"message": "Nombre"
|
||||
@@ -306,7 +444,7 @@
|
||||
"message": "Hooks de inicio"
|
||||
},
|
||||
"instance.settings.tabs.hooks.custom-hooks": {
|
||||
"message": "Hooks de inicio personalizados"
|
||||
"message": "Hooks personalizados"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Los hooks permiten que usuarios avanzados ejecuten comandos del sistema antes y despues de lanzar el juego."
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instalación"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} ya está instalado para Minecraft {game_version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Instalando"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Obteniendo versiones del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Instalando nueva versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Actualmente instalado"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Información de depuración:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Obteniendo detalles del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Versión del juego"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Instalación en progreso"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "Versión de {loader}"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "No se pueden obtener los detalles del modpack vinculado. Por favor, verifica tu conexión a internet."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} no está disponible para Minecraft {version}. Prueba con otro mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Esta instancia está vinculada a un modpack, pero no se pudo encontrar el modpack en Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plataforma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Reinstalando modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "La reinstalación restablecerá todo el contenido instalado o modificado a lo que proporciona el modpack, eliminando cualquier mod o contenido que hayas agregado sobre la instalación original. Esto puede solucionar comportamientos inesperados si se han hecho cambios en la instancia, pero si tus mundos dependen de contenido adicional instalado, podría romper los mundos existentes."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres reinstalar esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Restablece el contenido de la instancia a su estado original, eliminando cualquier mod o contenido que hayas agregado sobre el modpack original."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparar reinstala las dependencias de Minecraft y verifica la integridad de los archivos. Esto puede solucionar problemas si tu juego no se inicia por errores relacionados con el launcher, pero no resolverá problemas debidos a mods instalados."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "¿Reparar instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparación en proceso..."
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Restablecer al actual"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Mostrar todas las versiones"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "reinstalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "No se puede {action} mientras se está instalando"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "No se puede {action} mientras estés desconectado"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "No se puede {action} mientras se está reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(versión desconocida)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Desvincular instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Si continúas, no podrás volver a vincularla sin crear una nueva instancia. Ya no recibirás actualizaciones del modpack y pasará a ser una instancia normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres desvincular esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Esta instancia está vinculada a un modpack, lo que significa que los mods no pueden actualizarse y no puedes cambiar el mod loader ni la versión de Minecraft. Desvincularla la desconectará permanentemente del modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Desvincular del modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java y memoria"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "No mostrar en la página de inicio"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Disponible"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "La instancia ya está abierta"
|
||||
},
|
||||
@@ -551,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "El servidor es incompatible"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Gestionado por el proyecto del servidor"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "No se pudo conectar al servidor"
|
||||
},
|
||||
@@ -563,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Iniciar instancia"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Servidor"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Un jugador"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Ver instancia"
|
||||
},
|
||||
@@ -586,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar con la instancia"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Proporcionado por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Solo se puede añadir mods que sean del lado del cliente a la instancia del servidor"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "La versión del juego es proporcionada por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "El loader es proporcionado por el servidor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "No se puede conectar con los servidores de autenticación"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Añadir servidor a la instancia"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Añadir servidor a tu instancia"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Añadir a la instancia"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Añadir a {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Añadido"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Ya está añadido"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Descubrir contenido"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Descubrir servidores"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Ocultar servidores añadidos"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Ocultar contenido instalado"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Instalar contenido a una instancia"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Escribe la descripción del modpack..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exportar"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Exportar modpack"
|
||||
},
|
||||
"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": "Seleccione archivos y carpetas para incluir en el paquete"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Número de versión"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Todos los datos de su instancia se eliminarán permanentemente, incluidos sus mundos, configuraciones y todo el contenido instalado."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Esta acción no se puede deshacer"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Eliminar instancia"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Este modpack ya está instalado en la instancia <bold>{instanceName}</bold>. ¿Estás seguro qué quieres duplicarlo?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Crear"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpack ya está instalado"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instancia"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "proyecto"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "Se ha añadido \"{name}\""
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "Se han añadido {count} proyectos"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "¡Echa un vistazo a los proyectos que utilizo en mi modpack!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Compartir contenido del modpack"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Se ha subido correctamente"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Añadir servidor"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Sin conexión"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "En línea"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Añadir un servidor o explora para comenzar"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Este servidor requiere mods para jugar. Haz clic en instalar para configurar los archivos necesarios de Modrinth."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requerido"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} ha compartido contigo hoy esta instancia."
|
||||
"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"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instancia de servidor compartida"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} añadidos"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Añadido"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Eliminado"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Actualizado"
|
||||
"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.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} eliminados"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} actualizados"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Modo desarrollador activado."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Opciones predeterminadas de la instancia"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funciones experimentales"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Instalaciones de Java"
|
||||
},
|
||||
@@ -83,39 +209,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Gestión de recursos"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"app.update-popup.body": {
|
||||
"message": "¡La versión v{version} de Modrinth está lista para instalarse! Actualiza ahora o automáticamente al cerrar la aplicación."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "La descarga de la versión v{version} de Modrinth ha finalizado. Actualice ahora o automáticamente al cerrar la aplicación."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} se ha descargado. Actualiza la página ahora o espera a que se actualice automáticamente al cerrar Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrinth App v{version} está disponible. ¡Usa tu gestor de paquetes para actualizar a la última versión con nuevas funciones y correcciones!"
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Ya está disponible Modrinth App v{version}. ¡Utiliza tu gestor de paquetes para actualizarla y disfrutar de las últimas funciones y correcciones!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "¡La versión v{version} de Modrinth App ya está disponible! Como estás conectado a una red con límite de datos, no la hemos descargado automáticamente."
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "¡Modrinth App v{version} ya está disponible! Como estás conectado a una red con tarifa por datos, no la hemos descargado automáticamente."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Registro de cambios"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Descarga ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Descargar"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Descargando..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Recarga"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Actualización disponible"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Descarga completada"
|
||||
},
|
||||
"app.update-popup.reload": {
|
||||
"message": "Recargar"
|
||||
},
|
||||
"app.update-popup.title": {
|
||||
"message": "Actualización disponible"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Haga clic aquí para ver el registro de cambios."
|
||||
},
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Recarga para instalar la actualización"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "ejemplo.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Selecciona una opción"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Versión {version} incompatible"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "No se ha jugado aún"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Desconectado"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} en línea"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Agrega a un amigo"
|
||||
},
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Editar mundo"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Desactivar proyectos"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Añadiendo archivos ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Actualizaciones disponibles"
|
||||
"instance.files.save-as": {
|
||||
"message": "Guardar como..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Dirección IP"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} para Minecraft {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "La versión vanilla {game_version} ya está instalada"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Instalando"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Buscando versiones del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Instalando versión nueva"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Instalado actualmente"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Información de debug:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Buscando detalles del modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Versión del juego"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Instalación en progreso"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "No se puede buscar los detalles del modpack enlazado. Por favor revise su conexión a internet."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} no está disponible para Minecraft {version}. Prueba con otro cargador."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "La instancia está enlazada a un modpack, pero el modpack no se ha podido encontrar en Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plataforma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Reinstalando modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Reinstalar reiniciará todo el contenido instalado o modificado a lo que el modpack proporcione, quitando cualquier mod o contenido que hayas añadido por encima de la instalación original. Esto puede arreglar actividad inesperada, pero si los mundos dependen del contendio adicional instalado, puede romperlos. "
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres reinstalar esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Reinicia el contenido de la instancia a su estado original, quitando cualquier mod o contenido que hayas añadido por encima del modpack original."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Reinstalar modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Reparando reinstalaciones Minecraft dependencias y buscando corrupciones. Esto podría solucionar problemas si tu juego no se está abriendo debido a errores relacionados con el launcher, pero no solucionará problemas o crashes relacionados con mods instalados."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "¿Reparar instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Reparación en progreso"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Reiniciar a actual"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Mostrar todas las versiones"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "cambiar versión"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "instalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "reinstalar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "reparar"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "No se puede {action} mientras se está instalando."
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "No se puede {action} sin conexión"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "No se puede {action} reparando"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(versión desconocida)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Desvincular instancia"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Si procedes, no podrás re-vincular sin crear una nueva instancia. No recibirás actualizaciones del modpack y se convertira en uno normal."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "¿Estás seguro de que quieres desvincular esta instancia?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "La instancia está vinculada a un modpack, lo que significa que los mods no pueden ser actualizados y no puedes cambiar el mod loader o la versión de Minecraft. Desvincular desconectará permanentemente esta instancia del modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Desvincular del modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java y memoria"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "No mostrar en Inicio"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Disponible"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "La instancia ya está abierta"
|
||||
},
|
||||
@@ -551,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Servidor es incompatible"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Gestionado por el proyecto del servidor"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "No se pudo contactar con el servidor"
|
||||
},
|
||||
@@ -563,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Jugar instancia"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Servidor"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Un jugador"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Ver instancia"
|
||||
},
|
||||
@@ -586,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Sincronizar con la instancia"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Proporcionado por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Solo se pueden añadir a la instancia del servidor modificaciones del lado del cliente"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "La versión del juego es proporcionada por el servidor"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "El cargador lo proporciona el servidor"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,183 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Todennuspalvelimiin ei saada yhteyttä"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Lisää palvelin instanssiin"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Lisää palvelimia instanssiisi"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Lisää instanssiin"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Lisää instanssiin {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Lisätty"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "On jo asennettu"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Löydä sisältöä"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Löydä palvelimia"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Piilota lisätyt palvelimet"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Piilota asennettu sisältö"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Lataa sisältöä instanssiin"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Lisää modipaketin kuvaus..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Vie"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Vie modipaketti"
|
||||
},
|
||||
"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": "Valitse tiedostot ja kansiot pakettiin"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Versio numero"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Kaikki sinun instanssisi data poistetaan pysyvästi, sisältäen maailmasi, konfiguraatiosi ja asennetun sisällön."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Tätä toimintoa ei voi peruuttaa"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Poista instannsi"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Poista instanssi"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Tämä modipaketti on jo asennettu instanssiin <bold>{instanceName}</bold>. Oletko varma että haluat kopioida sen?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Luo"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modipaketti on jo asennettu"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instanssi"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekti"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" lisättiin"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} projektia lisättiin"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Tsekkaa projektit joita käytän minun modipaketissani!"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Onnistuneesti ladattu"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Lisää palvelin"
|
||||
},
|
||||
"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-title": {
|
||||
"message": "Oletko varma että haluat pysyvästi poistaa tämän maailman?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modattu"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline-tilassa"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online-tilassa"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Lisää palvelin tai selaa aloittaaksesi"
|
||||
},
|
||||
"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-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-title": {
|
||||
"message": "Oletko varma että haluat poistaa {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"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Asenna"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Kehittäjätila käytössä."
|
||||
},
|
||||
@@ -17,9 +194,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Oletusinstanssin asetukset"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Ominaisuuskytkimet"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Java asennukset"
|
||||
},
|
||||
@@ -32,36 +206,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Resurssien hallinta"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "Modrinth-sovellus v{version} on valmis asennettavaksi! Lataa sovellus uudelleen päivittääksesi sen nyt tai automaattisesti, kun suljet Modrinth-sovelluksen."
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App versio {version} on valmis asennettavaksi. Voit käynnistää sovelluksen uudelleen päivittääksesi heti tai antaa päivityksen asentua automaattisesti, kun suljet Modrinth Appin."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Modrinth-sovellus v{version} on ladattu. Lataa sovellus uudelleen päivittääksesi sen nyt tai automaattisesti, kun suljet Modrinth-sovelluksen."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App versio {version} on ladattu. Voit käynnistää sovelluksen uudelleen päivittääksesi heti tai antaa päivityksen asentua automaattisesti, kun suljet Modrinth Appin."
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth-sovellus v{version} on nyt saatavilla! Koska käytät käyttömaksullista verkkoa, emme ladanneet sitä automaattisesti."
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App versio {version} on saatavilla. Käytä paketinhallintasi ja päivitä käyttääksesi uusimpia ominaisuuksia ja korjauksia!"
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App versio {version} on nyt saatavilla! Koska käytät käytön mukaan laskutettavaa verkkoa, emme ladannut sitä automaattisesti."
|
||||
},
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Muutosloki"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Lataa ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Lataa"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Ladataan..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"message": "Uudelleen lataa"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Päivitys saatavilla"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Lataus valmis"
|
||||
},
|
||||
"app.update-popup.reload": {
|
||||
"message": "Lataa uudelleen"
|
||||
},
|
||||
"app.update-popup.title": {
|
||||
"message": "Päivitys saatavilla"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Klikkaa tästä nähdäksesi muutoslokin."
|
||||
},
|
||||
@@ -77,6 +248,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Lataa uudelleen asentaaksesi päivityksen"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Valitse vaihtoehto"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Yhteensopimaton versio {version}"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Ei pelattu vielä"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Offline-tilassa"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} paikalla"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Lisää ystävä"
|
||||
},
|
||||
@@ -176,11 +365,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Muokkaa maailmaa"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Käytöstä poistetut projektit"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Lisätään tiedostoja ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Päivityksia saatavilla"
|
||||
"instance.files.save-as": {
|
||||
"message": "Tallenna nimellä..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Osoite"
|
||||
@@ -216,7 +405,7 @@
|
||||
"message": "Ei pystytä monistamaan asennettaessa."
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance": {
|
||||
"message": "Monista instanssi"
|
||||
"message": "Monista asennus"
|
||||
},
|
||||
"instance.settings.tabs.general.duplicate-instance.description": {
|
||||
"message": "Luo kopion tästä instanssista sekä kaikista sen maailmoista, asetuksista, modeista yms."
|
||||
@@ -290,141 +479,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Asennus"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} Minecraft versiolle {game_version} on jo asennettu"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} on jo asennettu"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Vaihda versiota"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Asenna"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Asennetaan"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Noudetaan modipaketin versioita"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Asennetaan uutta versiota"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Asennettuna"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Virheenkorjaus informaatio:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Noudetaan modipaketin tietoja"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Peli versio"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Asenna"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Asennus käynnissä"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} versio"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Ei voida noutaa linkatun modipaketin tietoja. Tarkista internet yhteytesi."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} ei ole saatavilla Minecraft versiolle {version}. Kokeile toista modi lataajaa."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Tämä instanssi on linkitetty modipakettiin, mutta modipakettia ei löydetty Modrinthista."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Alusta"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Asenna modipaketti uudelleen"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Asennetaan modipakettia uudelleen"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Uudelleen asentaminen palauttaa kaiken asennetun tai muokatun sisällön siihen muotoon missä se on modipaketissa poistaen kaikki modit ja muun sisällön mitä olet lisännyt alkuperäisen asennuksen päälle. Tämä saattaa korjata odottamatonta käytöstä mikäli instanssia on muokattu mutta jos maailmasi ovat nyt riippuvaisia lisätystä sisällöstä se saattaa rikkoa olemassa olevia maailmoja."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Haluatko varmasti asentaa tämän instanssin uudelleen?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Palauttaa instanssin sisällön alkuperäiseen muotoonsa poistaen kaikki modit tai muun sisällön mitä olet lisännyt alkuperäisen modipaketin päälle."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Asenna modipaketti uudelleen"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Korjaa"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Korjataan"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Korjaaminen uudelleen asentaa Minecraftin riippuvuuksia ja tarkistaa korruptiota varten. Tämä saattaa ratkaista ongelmia jos pelisi ei käynnisty launcheriin liittyvien virheiden takia mutta ei ratkaise ongelmia tai kaatumisia liittyen ladattuihin modeihin."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Korjaa instanssi?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Korjaus käynnissä"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Palauta nykyiseen"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Näytä kaikki versiot"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "vaihda versiota"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "asenna"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "asenna uudelleen"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "korjaa"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Et voi {action} asentaessa"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Toimintoa {action} ei voida suorittaa offline tilassa"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Et voi {action} korjatessa"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(tuntematon versio)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Poista instanssin linkitys"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Jos jatkat et voi uudelleen linkata sitä ilman että luot täysin uuden instanssin. Et vastaanota enää modipaketti päivityksiä ja siitä tulee normaali."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Oletko varma että haluat poistaa tämän instanssin linkityksen?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Tämä instanssi on linkitetty modipakettin joka tarkoittaa että modeja ei voida päivittää etkä voi vaihtaa lataaja tai Minecraft versiota. Linkityksen poistaminen katkaisee pysyvästi yhteyden instanssin ja modipaketin välillä."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Poista linkitys modipakettiin"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java ja muisti"
|
||||
},
|
||||
@@ -485,9 +542,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Älä näytä koti näkymässä"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Saatavilla"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Instanssi on jo avattu"
|
||||
},
|
||||
@@ -497,6 +551,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Palvelin on yhteensopimaton"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Palvelimen projektin hallinnoima"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Palvelimeen ei saatu yhteyttä"
|
||||
},
|
||||
@@ -509,12 +566,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Pelaa instanssia"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Palvelin"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Yksinpeli"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Näytä instanssi"
|
||||
},
|
||||
@@ -531,6 +582,18 @@
|
||||
"message": "Lataajan antaa instanssi"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synkkaa instanssin kanssa"
|
||||
"message": "Synkronoi instanssin kanssa"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Palvelimen tarjoama"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Voit lisätä vain paikallisia modeja palvelin instanssiin"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Peliversio on palvelimen tarjoama"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Modialusta on palvelimen tarjoama"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,123 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Hindi maabot ang mga authentication server"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Idagdag ang server sa instansiya"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Idagdag ang mga server sa iyong instansiya"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Idagdag sa instansiya"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Idagdag sa {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Dinagdag"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Nadagdag na"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Tumuklas ng kontento"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Tumuklas ng mga server"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Taguin ang mga nadagdag na server"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Taguin ang mga na-install na kontento"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "I-install ang kontento sa instansiya"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Ilagay ang paglalarawan ng modpack..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Iluwas"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Iluwas ang modpack"
|
||||
},
|
||||
"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": "Pumili ng mga talaksan at folder na isasali sa pack"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Numero ng bersiyon"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-body": {
|
||||
"message": "Ang lahat ng data ng iyong instansiya ay tuluyang mawawala, kabilang na ang iyong mga mundo, kumpigurasyon, at lahat ng na-install na kontento."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Hindi mababawi ang aksiyong ito"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Tanggalin ang instansiya"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Tanggalin ang instansiya"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Ilikha"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instansiya"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "proyekto"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "Ang \"{name}\" ay nadagdag"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} proyekto ang nadagdag"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Binabahagi ang kontento ng modpack"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Matagumpay na na-upload"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Magdagdag ng server"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modded"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
@@ -14,11 +131,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# na mod}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Ang server na ito ay nangangailangan ng mga mod upang malaro. Pindutin ang install upang mahanda ang mga kinakailangang file galing sa Modrinth."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Kinailangan na modpack"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "Ibinahagi ngayong araw ni {name} ang instansiyang ito sa iyo."
|
||||
"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"
|
||||
@@ -26,38 +143,20 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Binahaging instansiyang pang-server"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} nadagdag"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Dinagdag"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Tinanggal"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Na-update"
|
||||
"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.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} tinanggal"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} na-update"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Nakabukas ang moda ng nagdidibelop."
|
||||
"message": "Binuksan ang moda ng nagdi-develop."
|
||||
},
|
||||
"app.settings.downloading": {
|
||||
"message": "Dina-download ang v{version}"
|
||||
@@ -68,9 +167,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Mga pagpipilian sa default na instansiya"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Mga hudyat ng tampok"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Mga instalasyon ng Java"
|
||||
},
|
||||
@@ -83,39 +179,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Pamamahala ng paglalaan"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"app.update-popup.body": {
|
||||
"message": "Ang Modrinth App v{version} ay handa nang ma-install. Mag-reload upang ma-update ngayon, o awtomatiko sa pagsara ng Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Tapos nang ma-download ang Modrinth App v{version}. Mag-reload upang ma-update ngayon, o awtomatiko sa pagsara ng Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Magagamit na ngayon ang Modrinth App v{version}. Gamitin ang iyong package manager upang i-update sa pinabagong tampok at pag-aayos!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Magagamit na ngayon ang Modrinth App v{version}! Hindi namin dinanload kaagad dahil naka-metro ang inyong network."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Changelog"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "I-download ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "I-download"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Nakumpleto ang pagdownload"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Nagda-download..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Mag-reload"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "May bagong update"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Nakumpleto ang pagdownload"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Dito pumindot upang matingnan ang changelog."
|
||||
},
|
||||
@@ -131,6 +221,18 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Handang ma-install ang update"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Pumili ng opsiyon"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Di-magkatugmang bersiyong {version}"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Magdagdag ng kaibigan"
|
||||
},
|
||||
@@ -201,10 +303,10 @@
|
||||
"message": "Idagdag ang server"
|
||||
},
|
||||
"instance.add-server.resource-pack.disabled": {
|
||||
"message": "Hindi pinahihintulotan"
|
||||
"message": "Tanggihan"
|
||||
},
|
||||
"instance.add-server.resource-pack.enabled": {
|
||||
"message": "Pinahihintulotan"
|
||||
"message": "Payagan"
|
||||
},
|
||||
"instance.add-server.resource-pack.prompt": {
|
||||
"message": "Magpahintulot"
|
||||
@@ -216,7 +318,7 @@
|
||||
"message": "Baguhin ang server"
|
||||
},
|
||||
"instance.edit-world.hide-from-home": {
|
||||
"message": "Huwag ipakita sa Home na pahina"
|
||||
"message": "Itago sa pahina ng Tahanan"
|
||||
},
|
||||
"instance.edit-world.name": {
|
||||
"message": "Pangalan"
|
||||
@@ -230,12 +332,6 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Baguhin ang mundo"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Mga hindi pinapagang proyekto"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "May bagong mga update"
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adres"
|
||||
},
|
||||
@@ -309,7 +405,7 @@
|
||||
"message": "Mga custom na launch hook"
|
||||
},
|
||||
"instance.settings.tabs.hooks.description": {
|
||||
"message": "Binibigyan-daan ng mga hook ang mga ekspertong tagagamit na makapagtakbo ng mga system command bago at pagkatapos ma-launch ang laro."
|
||||
"message": "Binibigyan-daan ng mga hook ang mga ekspertong tagagamit na makapagtakbo ng mga pansistemang utos o system command bago at pagkatapos ma-launch ang laro."
|
||||
},
|
||||
"instance.settings.tabs.hooks.post-exit": {
|
||||
"message": "Post-exist"
|
||||
@@ -344,141 +440,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Instalasyon"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "Naka-install naman ang {platform} {version} para sa Minecraft {game_version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Naka-install naman ang Vanilla {game_version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Palitan ang bersiyon"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "I-install"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Ini-install"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Nagfe-fetch ng mga bersiyon ng modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Ini-install ang bagong bersiyon"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Kasalukuyang naka-install"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Impormasyon sa pagdebug:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Nagfe-fetch ng mga detalye ng modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Bersiyon ng laro"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "I-install"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Nag-i-install ngayon"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "Bersiyon ng {loader}"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Hindi maka-fetch ng mga detalye ng linked modpack. Mangyaring tingnan ang iyong internet connection."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "Hindi magagamit ang {loader} sa Minecraft {version}. Sumubok ng ibang mod loader."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Naka-link itong instansiya sa isang modpack, pero ang modpack na ito ay hindi makikita sa Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plataporma"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "I-reinstall ang modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Ini-re-reinstall ang modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Ang pagrere-install ay maaaring ma-reset ang lahat ng na-install at binago na kontento sa kung anong hinahandog ng modpack, tatanggalin ang mga mods at kontentong idinagdag mo sa orihinal na modpack. Maaari nitong masiayos ang mga hindi inaasahang pag-uugali kung may pagbabagong naganap sa instansiya, ngunit kung dumedepende na ang iyong mundo sa karagdagang kontento, maaari nitong masira ang mga umiiral na mundo."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Sigurado ka bang gusto mong i-reinstall ang instansiyang ito?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Mare-reset ang mga kontento ng instansiya sa orihinal niyang estado, tatanggalin ang mga mods at kontentong idinagdag mo sa orihinal na modpack."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "I-reinstall ang modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Ayusin"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Inaayos"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "Sa pagre-repair, mare-reinstall ang mga dependency ng Minecraft at maghahanap ng mga kurapsiyon. Maaaring maresolbe nito ang mga isyu kung hindi malu-launch ang laro dahil sa mga launcher-related error, ngunit hindi nito mareresolbe ang mga isyu at pag-crash na dulot ng mga na-install na mod."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Ayusin ang instansiya?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Inaayos ngayon"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Sa kasalukuyan i-reset"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Ipakita ang lahat ng bersiyon"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "palitan ang bersiyon"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "i-install"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "i-reinstall"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "ayusin"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Hindi makaka-{action} habang nag-i-install"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Hindi makaka-{action} habang nasa offline"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Hindi makaka-{action} habang nag-aayos"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(hindi kilalang bersiyon)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "I-unlink sa instansiya"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Kapag ipagpatuloy mo, hindi mo na itong mai-link muli ng hindi gagawa ng bagong instansiya. Hindi ka makakatanggap ng mga update ng modpack at magiging normal na itong."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Sigurado ka bang gusto mong i-unlik ang instansiyang ito?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Ang instansiyang ito ay naka-link sa isang modpack, ibig sabihin ang mga mod ay hindi mai-update at hindi mo mapapalitan ang mod loader at ang bersiyon ng Minecraft. Permanenteng madi-diskonekta ang instansiyang ito sa modpack kung mag-unlink."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "I-unlink sa modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java at memorya"
|
||||
},
|
||||
@@ -537,10 +501,7 @@
|
||||
"message": "Kopyahin ang adres"
|
||||
},
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Huwag ipakita sa Home"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Magagamit"
|
||||
"message": "Huwag ipakita sa Tahanan"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "Bukas naman ang instansiya"
|
||||
@@ -551,6 +512,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Hindi magkatugma sa server"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Pinamamahala ng proyektong server"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Hindi makontak ang server"
|
||||
},
|
||||
@@ -563,12 +527,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Laruin ang instansiya"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Server"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Pang-isahang laro"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Tingnan ang instansiya"
|
||||
},
|
||||
@@ -586,5 +544,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Maki-sync sa instansiya"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Handog ng server"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Mga mod sa panig ng client lamang ang maidadaragdag sa instansiyang server"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Ang bersiyon ng laro ay handog ng server"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Ang loader ay handog na ng server"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Impossible de contacter les serveurs d'authentification"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Ajouter le serveur à l'instance"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Ajouter des serveurs à votre instance"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Ajouter à l'instance"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Ajouter à {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Ajouté"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Déjà ajouté"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Découvrir du contenu"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Découvrir des serveurs"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Masquer les serveurs ajoutés"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "Masquer le contenu installé"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Installer du contenu à l'instance"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Saisir la description du modpack..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exporter"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Exporter le modpack"
|
||||
},
|
||||
"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": "Sélectionnez des fichiers et des dossiers à inclure dans le pack"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Numéro de version"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"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é."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Cette action est irréversible"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Supprimer l'instance"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Supprimer l'instance"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Ce modpack est déjà installé sur l'instance <bold>{instanceName}</bold>. Êtes-vous sûr.e de vouloir le dupliquer ?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Créer"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "Modpack déjà installé"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Instance"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projet"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "« {name} » a été ajouté"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} projets ont été ajoutés"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Jette un coup d'œil aux projets que j'utilise dans mon modpack !"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Partage du contenu de votre modpack"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Mis en ligne avec succès"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Ajouter le serveur"
|
||||
},
|
||||
"app.instance.worlds.browse-servers": {
|
||||
"message": "Parcourir des serveurs"
|
||||
},
|
||||
"app.instance.worlds.delete-world-description": {
|
||||
"message": "« {name} » sera supprimé **pour toujours**, et il sera impossible de le récupérer."
|
||||
},
|
||||
"app.instance.worlds.delete-world-title": {
|
||||
"message": "Êtes-vous sûr.e de vouloir supprimer ce monde pour toujours ?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Moddé"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Hors ligne"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "En ligne"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Ajouter un serveur ou parcourir pour commencer"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-heading": {
|
||||
"message": "Aucun serveur ou monde ajoutés"
|
||||
},
|
||||
"app.instance.worlds.remove-server-description": {
|
||||
"message": "« {name} » sera retiré de votre liste, y compris en jeu, et il sera impossible de le récupérer."
|
||||
},
|
||||
"app.instance.worlds.remove-server-description-with-address": {
|
||||
"message": "« {name} » ({address}) sera retiré de votre liste, y compris en jeu, et il sera impossible de le récupérer."
|
||||
},
|
||||
"app.instance.worlds.remove-server-title": {
|
||||
"message": "Êtes-vous sûr.e de vouloir retirer {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.header": {
|
||||
"message": "Installer pour jouer"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {# mod} other {# mods}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "Ce serveur nécessite des mods pour pouvoir y jouer. Cliquez sur installer pour mettre les fichiers de Modrinth en place."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "Modpack requis"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} a partagé cette instance avec vous aujourd'hui."
|
||||
"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.shared-instance": {
|
||||
"message": "Instance partagée"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Instance serveur partagée"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} {count, plural, one {# ajouté} other {# ajoutés}}"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Ajouté"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Retiré"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Mis à jour"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Voir le contenu"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Mettre à jour pour jouer"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} {count, plural, one {# retiré} other {# retirés}}"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Mise à jour requise"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} mis à jour"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Mode développeur activé."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Options d’instance par défaut"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Menu de fonctionnalité"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Installations de Java"
|
||||
},
|
||||
@@ -83,39 +209,33 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Gestion des ressources"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App v{version} est prête à être installée ! Relancez l'application pour faire la mise à jour maintenant, ou automatiquement à la fermeture de Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "Le téléchargement de Modrinth App v{version} est terminé ! Relancez l'application pour mettre à jour maintenant, ou automatiquement à la fermeture de Modrinth App."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} a finie d'être téléchargée. Rechargez pour mettre à jour maintenant, ou automatiquement quand vous fermez Modrinth App."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "Modrith App v{version} est disponible. Utilisez votre gestionnaire de paquets pour obtenir les derniers changements et corrections de bugs !"
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} est disponible. Utilisez votre gestionnaire de paquets pour mettre à jour les dernières fonctionnalités et corrections de bogues !"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "Modrinth App v{version} est disponible dès maintenant ! Lorsque vous êtes sur un réseau limité ou en données mobiles, nous ne téléchargerons pas les mises à jour automatiquement."
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App v{version} est disponible maintenant ! Puisque vous êtes sur un réseau métré, nous ne l'avons pas téléchargé automatiquement."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Journal des modifications"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Télécharger ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Télécharger"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Téléchargement terminé"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Téléchargement..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Recharger"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"app.update-popup.title": {
|
||||
"message": "Mise à jour disponible"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Téléchargement terminé"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Cliquez ici pour voir les changements récents."
|
||||
},
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "Relancez l'application pour installer la mise à jour"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "exemple.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Sélectionner une option"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Version {version} incompatible"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Pas encore joué"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Hors ligne"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count, plural, =0 {Personne en ligne} one {# est en ligne} other {# sont en ligne}}"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Ajouter un ami"
|
||||
},
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Modifier le monde"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Projets désactivés"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Ajout de fichiers ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Mises à jour disponibles"
|
||||
"instance.files.save-as": {
|
||||
"message": "Sauvegarder en tant que..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Adresse"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} pour Minecraft {game_version} est déjà installé"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "Vanilla {game_version} est déjà installé"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Changer de version"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Récupération des versions de modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Installation d'une nouvelle version"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Actuellement installé"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Informations de débogage :"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Récupération des détails de modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Version du jeu"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Installation en cours"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "Version de {loader}"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Impossible de récupérer les détails du modpack lié. Veuillez vérifier votre connexion Internet."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} n'est pas disponible pour Minecraft {version}. Essayez avec un autre chargeur de mods."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "Cette instance est liée à un modpack, mais le modpack n'a pas pu être trouvé sur Modrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Plateforme"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Réinstaller le modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Réinstallation du modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "La réinstallation réinitialisera tout le contenu installé ou modifié à celui fourni par le modpack, supprimant ainsi tous les mods ou contenus ajoutés à l'installation d'origine. Cela peut corriger un comportement inattendu si des modifications ont été apportées à l'instance, mais si vos mondes dépendent désormais de contenu supplémentaire installé, cela peut endommager les mondes existants."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Êtes-vous sûr de vouloir réinstaller cette instance ?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Réinitialise le contenu de l'instance à son état d'origine, en supprimant tous les mods ou contenus que vous avez ajoutés au modpack d'origine."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Réinstaller le modpack"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Réparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Réparation"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "La réparation réinstalle les dépendances de Minecraft et vérifie la corruption. Cela peut résoudre les problèmes de lancement du jeu en raison d'erreurs liées au launcher, mais ne résoudra pas les problèmes ou plantages liés aux mods installés."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Réparer l'instance ?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Réparation en cours"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Restaurer à l’état actuel"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Voir toutes les versions"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "changer la version"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "installer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "réinstaller"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "réparer"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Impossible de {action} pendant l'installation"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Impossible de {action} hors ligne"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Impossible de {action} pendant la réparation"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(version inconnue)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Délier l'instance"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Si vous continuez, vous ne pourrez pas la relier de nouveau sans créer une toute nouvelle instance. Vous ne recevrez plus de mises à jour du modpack et elle deviendra une instance normale."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Êtes-vous sûr de vouloir délier cette instance ?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Cette instance est liée à un modpack, ce qui veut dire que les mods ne peuvent être mis à jour et vous ne pouvez pas changer le modloader ou la version de Minecraft. La délier va déconnecter l'instance du modpack de façon permanente."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Délier du modpack"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java et mémoire"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Ne pas montrer dans l'Accueil"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Disponible"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "L'instance est déjà ouverte"
|
||||
},
|
||||
@@ -551,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "Le serveur est incompatible"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Géré par le projet du serveur"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Le serveur n'a pas pu être contacté"
|
||||
},
|
||||
@@ -558,17 +564,11 @@
|
||||
"message": "Vous pouvez seulement entrer directement dans les serveurs sur Minecraft Alpha 1.0.5+"
|
||||
},
|
||||
"instance.worlds.no_singleplayer_quick_play": {
|
||||
"message": "Vous pouvez seulement entrer directement dans les mondes solo sur Minecraft Alpha 1.20+"
|
||||
"message": "Vous pouvez seulement entrer directement dans les mondes solo sur Minecraft 1.20+"
|
||||
},
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Jouer à l'instance"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Serveur"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Solo"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Voir l'instance"
|
||||
},
|
||||
@@ -586,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Synchroniser avec l'instance"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "Fournis par le serveur"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "Seuls les mods client peuvent être ajoutés à l'instance du serveur"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "Version du jeu est procurée par le serveur"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "Le loader est procuré par le serveur"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,153 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "לא ניתן לגשת לשרתי האימות"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "הוסף שרת להתקנה"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "הוסף שרתים להתקנה שלך"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "הוספה להתקנה"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "הוסף אל {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "נוסף"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "כבר נוסף"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "גלה תוכן"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "גלה שרתים"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "הסתר שרתים שנוספו"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "הסתר תוכן מותקן"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "הוספת התוכן להתקנה"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "הזן את תיאור חבילת המודים..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "יצוא"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "יצוא חבילת מודים"
|
||||
},
|
||||
"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.instance.confirm-delete.admonition-body": {
|
||||
"message": "כל הנתונים של ההתקנה שלך ימחקו לתמיד, זה כולל את העולמות שלך, ההגדרות וכל התוכן שהתקנת."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "הפעולה הזו לא ניתנת לביטול"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "מחק התקנה"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "מחיקת התקנה"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "חבילת המודים הזו כבר מותקנת בתוך ההתקנה <bold>{instanceName}</bold>. האם אתה בטוח שברצונך לשכפל אותה?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "צור"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "חבילת המודים הזאת כבר מותקנת"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "התקנה"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "פרויקט"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": "\"{name}\" נוסף"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} פרויקטים נוספו"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "בדוק את הפרויקטים שאני משתמש בהם בחבילת המודים שלי!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "משתף את התוכן של חבילת המודים"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "הועלה בהצלחה"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "הוסף שרת"
|
||||
},
|
||||
"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": "עם מודים"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "לא מקוון"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "מחובר"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "ונילה"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "הוספת שרת או עיון כדי להתחיל"
|
||||
},
|
||||
"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": "צריך להתקין כדי לשחק"
|
||||
},
|
||||
@@ -14,11 +161,11 @@
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "{count, plural, one {מוד אחד} other {# מודים}}"
|
||||
},
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "השרת דורש מודים כדי לשחק. התקנה מגדירה את הקבצים הדרושים מModrinth."
|
||||
"app.modal.install-to-play.required-modpack": {
|
||||
"message": "חבילת מודים נדרשת"
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} שיתף איתך את ההתקנה הזאת היום."
|
||||
"app.modal.install-to-play.server-requires-mods": {
|
||||
"message": "שרת זה דורש מודים כדי לשחק. לחץ על \"התקן\" כדי להגדיר את הקבצים הנדרשים מ-Modrinth, ולאחר מכן הפעל ישירות לשרת."
|
||||
},
|
||||
"app.modal.install-to-play.shared-instance": {
|
||||
"message": "התקנה משותפת"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "התקנת שרת משותפת"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} נוספו"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "נוסף"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "הוסר"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "עודכן"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "הצג תוכן"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "צריך לעדכן כדי לשחק"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} הוסרו"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "עדכון נדרש"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "עדכון נדרש כדי לשחק ב{name}. ניתן להתחיל את המשחק רק לאחר עדכון לגרסה החדשה."
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} עודכנו"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "מצב מפתח מופעל."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "אפשרויות ברירת מחדל של התקנה"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "הגדרות ניסיוניות"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "התקנות ג'אווה"
|
||||
},
|
||||
@@ -83,38 +209,32 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "ניהול משאבים"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"app.update-popup.body": {
|
||||
"message": "Modrinth App v{version} מוכנה להורדה!\nיש לרענן כדי לעדכן עכשיו, או באופן אוטומטי בעת סגירת האפליקציה."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "Modrinth App v{version} סיימה את תהליך ההורדה. יש לרענן כדי לעדכן עכשיו, או באופן אוטומטי בעת סגירת האפליקציה."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "Modrinth App v{version} זמין. יש להשתמש במנהל חבילות שלך כדי לעדכן בשביל התכונות החדשות ותיקונים!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "Modrinth App v{version} זמינה עכשיו! בגלל החיבור לפי שימוש, לא הורדנו אותה אוטומטית."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"app.update-popup.changelog": {
|
||||
"message": "יומן שינויים"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "הורדה ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "הורד"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "הורדה הושלמה"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "מוריד..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "רענן"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "עדכונים זמינים"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "הורדה הושלמה"
|
||||
"app.update-popup.title": {
|
||||
"message": "עדכון זמין"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "לחיצה כדי לראות את יומן השינויים."
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "צריך לרענן כדי להתקין את העדכון"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "example.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "בחר אופציה"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "גרסה לא תואמת: {version}"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "עדיין לא שוחק"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "לא מקוון"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} מחוברים"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "הוספת חבר"
|
||||
},
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "ערוך עולם"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "פרויקטים מושבתים"
|
||||
"instance.files.adding-files": {
|
||||
"message": "הוספת קבצים ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "עדכונים זמינים"
|
||||
"instance.files.save-as": {
|
||||
"message": "שמור כ..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "כתובת"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "התקנה"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} בשביל Minecraft {game_version} כבר מותקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "וונילה {game_version} כבר מותקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "שינוי גרסה"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "התקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "מתקין"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "מאחזר גרסאות חבילת מודים"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "מתקין גרסה חדשה"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "מותקן כעת"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "מידע ניפוי שגיאות:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "מאחזר פרטי חבילת מודים"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "גרסת משחק"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "התקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "ההתקנה בתהליך"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} גרסה"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "לא ניתן לאחזר את פרטי חבילת המודים המקושרת. יש לבדוק את חיבור האינטרנט שלך."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} אינו זמין עבור Minecraft {version}. אנא נסה טוען מודים אחר."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "התקנה זאת מקושרת לחבילת מודים, אך חבילת המודים לא נמצאה בModrinth."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "פלטפורמה"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "התקן מחדש את חבילת המודים"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "מתקין מחדש את חבילת המודים"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "התקנה מחדש תאפס את כל התוכן המותקן או ששונה, ותחזיר אותו למצב שסופק על ידי חבילת המודים, תוך הסרת כל מוד או תוכן שהוספתם מעבר להתקנה המקורית. פעולה זו עשויה לתקן תקלות שנגרמו משינויים בהתקנה, אך אם העולמות שלכם תלויים בתוכן נוסף שהותקן, היא עלולה לשבש אותם."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "האם אתה בטוח שברצונך להתקין מחדש instance זה?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "מאפס את התוכן שנמצא בהתקנה למצבו המקורי, תוך הסרת כל מוד או תוכן ששונה מעבר לחבילת המודים המקורית."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "התקן מחדש חבילת מודים"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "תיקון"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "מתקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "התיקון מתקין מחדש את התלויות של מיינקראפט ובודק דברים מקולקלים. פעולה זו עשויה לפתור בעיות שמונעות את הפעלת המשחק עקב שגיאות הקשורות למשגר, אך לא תפתור בעיות או קריסות הקשורות למודים המותקנים."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "לתקן את המכונה?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "תיקון בתהליך"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "אפס לגרסה הנוכחית"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "הצג את כל הגרסאות"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "שנה גרסה"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "התקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "התקן מחדש"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "תקן"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "לא ניתן לבצע {action} בזמן ההתקנה"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "לא ניתן לבצע {action} במצב לא מקוון"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "לא יכול {action} בזמן תיקון"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(גרסה לא ידועה)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "לבטל את הקישור של ההתקנה הזו"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "אם תמשיך, לא תוכל לקשר אותה מחדש מבלי ליצור התקנה חדשה לחלוטין. לא תקבל עוד עדכונים לחבילת המודים, והיא תהפוך להתקנה רגילה."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "האם אתה בטוח שברצונך לנתק את הקישור ל-instance הזה?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "התקנה זאת מקושרת לחבילת מודים, מה שאומר שלא ניתן לעדכן מודים ולא ניתן לשנות את טוען המודים או את גרסת המיינקראפט. הניתוק יבטל לצמיתות את הקישור של התקנה זאת לחבילת המודים."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "נתק קישור מחבילת מודים"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "ג'אווה וזיכרון"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "אל תציג בדף הבית"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "זמין"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "התקנה כבר פתוחה"
|
||||
},
|
||||
@@ -551,6 +554,9 @@
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "שרת לא מתאים"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "מנוהל על ידי פרויקט שרת"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "לא ניתן ליצור קשר עם השרת"
|
||||
},
|
||||
@@ -563,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "שחק בהתקנה"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "שרת"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "שחקן יחיד"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "הצג התקנה"
|
||||
},
|
||||
@@ -586,5 +586,17 @@
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "סנכרן עם התקנה"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "מסופק על ידי השרת"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"message": "ניתן להוסיף רק מודים בצד הלקוח לשרת"
|
||||
},
|
||||
"search.filter.locked.server-game-version.title": {
|
||||
"message": "גרסת המשחק מסופקת על ידי השרת"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "הטוען מסופק על ידי השרת"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,167 @@
|
||||
"app.auth-servers.unreachable.header": {
|
||||
"message": "Nem lehet elérni a hitelesítési kiszolgálókat"
|
||||
},
|
||||
"app.browse.add-server-to-instance": {
|
||||
"message": "Szerver hozzáadása a profilhoz"
|
||||
},
|
||||
"app.browse.add-servers-to-instance": {
|
||||
"message": "Szerverek hozzáadása a profilodhoz"
|
||||
},
|
||||
"app.browse.add-to-instance": {
|
||||
"message": "Hozzáadás a profilhoz"
|
||||
},
|
||||
"app.browse.add-to-instance-name": {
|
||||
"message": "Hozzáadás ehhez: {instanceName}"
|
||||
},
|
||||
"app.browse.added": {
|
||||
"message": "Hozzáadva"
|
||||
},
|
||||
"app.browse.already-added": {
|
||||
"message": "Már hozzá van adva"
|
||||
},
|
||||
"app.browse.discover-content": {
|
||||
"message": "Tartalom böngészése"
|
||||
},
|
||||
"app.browse.discover-servers": {
|
||||
"message": "Szerverek böngészése"
|
||||
},
|
||||
"app.browse.hide-added-servers": {
|
||||
"message": "Hozzáadott szerverek elrejtése"
|
||||
},
|
||||
"app.browse.hide-installed-content": {
|
||||
"message": "A telepített tartalmak elrejtése"
|
||||
},
|
||||
"app.browse.install-content-to-instance": {
|
||||
"message": "Tartalom letöltése a profilhoz"
|
||||
},
|
||||
"app.export-modal.description-placeholder": {
|
||||
"message": "Írd be a modcsomag leírását..."
|
||||
},
|
||||
"app.export-modal.export-button": {
|
||||
"message": "Exportálás"
|
||||
},
|
||||
"app.export-modal.header": {
|
||||
"message": "Modcsomag exportálása"
|
||||
},
|
||||
"app.export-modal.modpack-name-label": {
|
||||
"message": "A modcsomag neve"
|
||||
},
|
||||
"app.export-modal.modpack-name-placeholder": {
|
||||
"message": "A modcsomag neve"
|
||||
},
|
||||
"app.export-modal.select-files-label": {
|
||||
"message": "Válaszd ki a csomagba felveendő fájlokat és mappákat"
|
||||
},
|
||||
"app.export-modal.version-number-label": {
|
||||
"message": "Verziószám"
|
||||
},
|
||||
"app.export-modal.version-number-placeholder": {
|
||||
"message": "1.0.0"
|
||||
},
|
||||
"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."
|
||||
},
|
||||
"app.instance.confirm-delete.admonition-header": {
|
||||
"message": "Ezt a műveletet nem lehet visszavonni"
|
||||
},
|
||||
"app.instance.confirm-delete.delete-button": {
|
||||
"message": "Profil törlése"
|
||||
},
|
||||
"app.instance.confirm-delete.header": {
|
||||
"message": "Profil törlése"
|
||||
},
|
||||
"app.instance.modpack-already-installed.body": {
|
||||
"message": "Ez a modcsomag már telepítve van a(z) <bold>{instanceName}</bold> profilban. Biztosan duplikálni szeretnéd?"
|
||||
},
|
||||
"app.instance.modpack-already-installed.create": {
|
||||
"message": "Létrehozás"
|
||||
},
|
||||
"app.instance.modpack-already-installed.header": {
|
||||
"message": "A modcsomag már telepítve van"
|
||||
},
|
||||
"app.instance.modpack-already-installed.instance": {
|
||||
"message": "Profil"
|
||||
},
|
||||
"app.instance.mods.content-type-project": {
|
||||
"message": "projekt"
|
||||
},
|
||||
"app.instance.mods.project-was-added": {
|
||||
"message": " „{name}” hozzá lett adva"
|
||||
},
|
||||
"app.instance.mods.projects-were-added": {
|
||||
"message": "{count} projekt került hozzáadásra"
|
||||
},
|
||||
"app.instance.mods.share-text": {
|
||||
"message": "Nézd meg, milyen projekteket használok a modcsomagomban!"
|
||||
},
|
||||
"app.instance.mods.share-title": {
|
||||
"message": "Modcsomag-tartalmak megosztása"
|
||||
},
|
||||
"app.instance.mods.successfully-uploaded": {
|
||||
"message": "Sikeresen feltöltve"
|
||||
},
|
||||
"app.instance.worlds.add-server": {
|
||||
"message": "Szerver hozzáadása"
|
||||
},
|
||||
"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-title": {
|
||||
"message": "Biztosan véglegesen törölni szeretnéd ezt a világot?"
|
||||
},
|
||||
"app.instance.worlds.filter-modded": {
|
||||
"message": "Modolt"
|
||||
},
|
||||
"app.instance.worlds.filter-offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.instance.worlds.filter-online": {
|
||||
"message": "Online"
|
||||
},
|
||||
"app.instance.worlds.filter-vanilla": {
|
||||
"message": "Vanilla"
|
||||
},
|
||||
"app.instance.worlds.no-worlds-description": {
|
||||
"message": "Kezdéshez adj hozzá egy szervert, vagy böngéssz"
|
||||
},
|
||||
"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-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-title": {
|
||||
"message": "Biztosan el akarod távolítani ezt: {name}?"
|
||||
},
|
||||
"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.header": {
|
||||
"message": "Töltsd le a játékhoz"
|
||||
"message": "Telepítés a játékhoz"
|
||||
},
|
||||
"app.modal.install-to-play.install-button": {
|
||||
"message": "Telepítés"
|
||||
},
|
||||
"app.modal.install-to-play.mod-count": {
|
||||
"message": "# mod"
|
||||
"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 beállítsd a szükséges fájlokat a Modrinthból."
|
||||
},
|
||||
"app.modal.install-to-play.shared-by-today": {
|
||||
"message": "{name} ma megosztotta veled ezt a profilt."
|
||||
"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.shared-instance": {
|
||||
"message": "Megosztott profil"
|
||||
@@ -26,36 +173,18 @@
|
||||
"app.modal.install-to-play.shared-server-instance": {
|
||||
"message": "Megosztott szerverprofil"
|
||||
},
|
||||
"app.modal.update-to-play.added-count": {
|
||||
"message": "{count} hozzáadva"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.added": {
|
||||
"message": "Hozzáadva:"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.removed": {
|
||||
"message": "Eltávolítva:"
|
||||
},
|
||||
"app.modal.update-to-play.diff-type.updated": {
|
||||
"message": "Frissítve"
|
||||
"app.modal.install-to-play.view-contents": {
|
||||
"message": "Tartalom megtekintése"
|
||||
},
|
||||
"app.modal.update-to-play.header": {
|
||||
"message": "Frissítsd a játékhoz"
|
||||
},
|
||||
"app.modal.update-to-play.published-date": {
|
||||
"message": "{date, date, long}"
|
||||
},
|
||||
"app.modal.update-to-play.removed-count": {
|
||||
"message": "{count} eltávolítva"
|
||||
},
|
||||
"app.modal.update-to-play.update-required": {
|
||||
"message": "Frissítés szükséges"
|
||||
},
|
||||
"app.modal.update-to-play.update-required-description": {
|
||||
"message": "\nFrissítés szükséges ehhez: {name}. Kérjük, frissíts a legújabb verzióra a játék elindításához"
|
||||
},
|
||||
"app.modal.update-to-play.updated-count": {
|
||||
"message": "{count} frissítve"
|
||||
},
|
||||
"app.settings.developer-mode-enabled": {
|
||||
"message": "Fejlesztői mód bekapcsolva."
|
||||
},
|
||||
@@ -68,9 +197,6 @@
|
||||
"app.settings.tabs.default-instance-options": {
|
||||
"message": "Alapértelmezett profil beállítások"
|
||||
},
|
||||
"app.settings.tabs.feature-flags": {
|
||||
"message": "Funkciójelzők"
|
||||
},
|
||||
"app.settings.tabs.java-installations": {
|
||||
"message": "Telepített Java példányok"
|
||||
},
|
||||
@@ -83,38 +209,32 @@
|
||||
"app.settings.tabs.resource-management": {
|
||||
"message": "Erőforráskezelés"
|
||||
},
|
||||
"app.update-toast.body": {
|
||||
"message": "A Modrinth App v{version} telepítésre kész! Frissítéshez indítsa újra a programot, vagy zárja be a Modrinth App alkalmazást, és a frissítés automatikusan megtörténik."
|
||||
"app.update-popup.body": {
|
||||
"message": "A Modrinth App v{version} telepítésre kész! Frissítéshez Töltsd újra az oldalt, vagy a Modrinth App bezárásakor automatikusan frissül."
|
||||
},
|
||||
"app.update-toast.body.download-complete": {
|
||||
"message": "A Modrinth App v{version} letöltése befejeződött. Frissítéshez indítsa újra az alkalmazást, vagy zárja be a Modrinth App alkalmazást, és a frissítés automatikusan megtörténik."
|
||||
"app.update-popup.body.download-complete": {
|
||||
"message": "A Modrinth App v{version} letöltése befejeződött. Frissítéshez Töltsd újra az oldalt, vagy a Modrinth App bezárásakor automatikusan frissül."
|
||||
},
|
||||
"app.update-toast.body.linux": {
|
||||
"message": "A Modrinth alkalmazás v{version} elérhető. Használd a csomagkezelődet a legújabb funkciók és hibajavítások telepítéséhez!"
|
||||
"app.update-popup.body.linux": {
|
||||
"message": "A Modrinth App v{version} elérhető. Használd a csomagkezelőt a legújabb funkciók és javítások frissítéséhez!"
|
||||
},
|
||||
"app.update-toast.body.metered": {
|
||||
"message": "A Modrinth App v{version} már elérhető! Mivel díjköteles hálózaton vagy, így nem töltöttük le automatikusan."
|
||||
"app.update-popup.body.metered": {
|
||||
"message": "A Modrinth App v{version} már elérhető! Mivel mérhető hálózaton vagy, nem töltöttük le automatikusan."
|
||||
},
|
||||
"app.update-toast.changelog": {
|
||||
"message": "Változtatások"
|
||||
"app.update-popup.changelog": {
|
||||
"message": "Változásnapló"
|
||||
},
|
||||
"app.update-toast.download": {
|
||||
"app.update-popup.download": {
|
||||
"message": "Letöltés ({size})"
|
||||
},
|
||||
"app.update-toast.download-page": {
|
||||
"message": "Letöltés"
|
||||
"app.update-popup.download-complete": {
|
||||
"message": "Sikeres letöltés"
|
||||
},
|
||||
"app.update-toast.downloading": {
|
||||
"message": "Letöltés..."
|
||||
},
|
||||
"app.update-toast.reload": {
|
||||
"app.update-popup.reload": {
|
||||
"message": "Újratöltés"
|
||||
},
|
||||
"app.update-toast.title": {
|
||||
"message": "Frissítések elérhetőek"
|
||||
},
|
||||
"app.update-toast.title.download-complete": {
|
||||
"message": "Letöltés befejezve"
|
||||
"app.update-popup.title": {
|
||||
"message": "Frissítés elérhető"
|
||||
},
|
||||
"app.update.complete-toast.text": {
|
||||
"message": "Kattints ide a változások megtekintéséhez."
|
||||
@@ -131,6 +251,24 @@
|
||||
"app.update.reload-to-update": {
|
||||
"message": "A telepítéshez újraindítás szükséges"
|
||||
},
|
||||
"app.world.server-modal.placeholder-address": {
|
||||
"message": "pelda.modrinth.gg"
|
||||
},
|
||||
"app.world.server-modal.select-an-option": {
|
||||
"message": "Válassz egy lehetőséget"
|
||||
},
|
||||
"app.world.world-item.incompatible-version": {
|
||||
"message": "Inkompatibilis verzió: {version}"
|
||||
},
|
||||
"app.world.world-item.not-played-yet": {
|
||||
"message": "Még nem játszottál"
|
||||
},
|
||||
"app.world.world-item.offline": {
|
||||
"message": "Offline"
|
||||
},
|
||||
"app.world.world-item.players-online": {
|
||||
"message": "{count} online"
|
||||
},
|
||||
"friends.action.add-friend": {
|
||||
"message": "Barát hozzáadása"
|
||||
},
|
||||
@@ -230,11 +368,11 @@
|
||||
"instance.edit-world.title": {
|
||||
"message": "Világ szerkesztése"
|
||||
},
|
||||
"instance.filter.disabled": {
|
||||
"message": "Letiltott projektek"
|
||||
"instance.files.adding-files": {
|
||||
"message": "Fájlok hozzáadása ({completed}/{total})"
|
||||
},
|
||||
"instance.filter.updates-available": {
|
||||
"message": "Frissítések elérhetőek"
|
||||
"instance.files.save-as": {
|
||||
"message": "Mentés másként..."
|
||||
},
|
||||
"instance.server-modal.address": {
|
||||
"message": "Cím"
|
||||
@@ -344,141 +482,9 @@
|
||||
"instance.settings.tabs.installation": {
|
||||
"message": "Telepítés"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.modded": {
|
||||
"message": "{platform} {version} a Minecraft {game_version} verziójához már telepítve van"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.already-installed.vanilla": {
|
||||
"message": "A vanilla {game_version} már telepítve van"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button": {
|
||||
"message": "Verzióváltás"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.install": {
|
||||
"message": "Telepítés"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.button.installing": {
|
||||
"message": "Telepítés folyamatban"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.cannot-while-fetching": {
|
||||
"message": "Modpack verzióinak lekérése"
|
||||
},
|
||||
"instance.settings.tabs.installation.change-version.in-progress": {
|
||||
"message": "Új verzió telepítése"
|
||||
},
|
||||
"instance.settings.tabs.installation.currently-installed": {
|
||||
"message": "Jelenleg telepítve"
|
||||
},
|
||||
"instance.settings.tabs.installation.debug-information": {
|
||||
"message": "Debug információ:"
|
||||
},
|
||||
"instance.settings.tabs.installation.fetching-modpack-details": {
|
||||
"message": "Modpack részleteinek lekérése"
|
||||
},
|
||||
"instance.settings.tabs.installation.game-version": {
|
||||
"message": "Játék verziója"
|
||||
},
|
||||
"instance.settings.tabs.installation.install": {
|
||||
"message": "Telepítés"
|
||||
},
|
||||
"instance.settings.tabs.installation.install.in-progress": {
|
||||
"message": "Telepítés folyamatban"
|
||||
},
|
||||
"instance.settings.tabs.installation.loader-version": {
|
||||
"message": "{loader} verzió"
|
||||
},
|
||||
"instance.settings.tabs.installation.minecraft-version": {
|
||||
"message": "Minecraft {version}"
|
||||
},
|
||||
"instance.settings.tabs.installation.no-connection": {
|
||||
"message": "Nem lehetséges a csatolt modpack részleteit lekérdezni. Kérlek nézd meg az internetkapcsolatod."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-loader-versions": {
|
||||
"message": "{loader} nem elérhető a Minecraft {version} verziójához. Próbálj meg egy másik modbetöltőt."
|
||||
},
|
||||
"instance.settings.tabs.installation.no-modpack-found": {
|
||||
"message": "A profilod linkelve van egy Modrinth modcsomaghoz, de a modcsomag nem található Modrinth-on."
|
||||
},
|
||||
"instance.settings.tabs.installation.platform": {
|
||||
"message": "Platform"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button": {
|
||||
"message": "Modpack újratelepítése"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.button.reinstalling": {
|
||||
"message": "Modpack újratelepítése"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.description": {
|
||||
"message": "Az újratelepítés visszaállítja az összes telepített vagy módosított tartalmat a modcsomag által biztosított állapotra, eltávolítva az eredeti telepítéshez hozzáadott modokat vagy tartalmakat. Ez megoldhatja a váratlan hibákat, de fontos tudni hogyha használsz világokat amelyekben utólagosan hozzáadott tartalom van, azok a világok elromolhatnak."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.confirm.title": {
|
||||
"message": "Biztosan szeretnéd újratelepíteni ezt a profilt?"
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.description": {
|
||||
"message": "Visszaállítja a profilod tartalmát az eredeti állapotába, eltávolítva az eredeti modpackhez hozzáadott összes modot és tartalmat."
|
||||
},
|
||||
"instance.settings.tabs.installation.reinstall.title": {
|
||||
"message": "Modpack újratelepítése"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button": {
|
||||
"message": "Javítás"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.button.repairing": {
|
||||
"message": "Javítás folyamatban"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.description": {
|
||||
"message": "A javítás újratelepíti a Minecraft alapját és ellenőrzi, hogy nincs-e sérülés. Ez megoldhatja a problémákat, ha a játék nem az indítóval kapcsolatos hibák miatt nem indul el, de nem oldja meg a telepített modokkal kapcsolatos problémákat vagy összeomlásokat."
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.confirm.title": {
|
||||
"message": "Profil javítása?"
|
||||
},
|
||||
"instance.settings.tabs.installation.repair.in-progress": {
|
||||
"message": "Javítás folyamatban"
|
||||
},
|
||||
"instance.settings.tabs.installation.reset-selections": {
|
||||
"message": "Visszaállítás az aktuális állapotra"
|
||||
},
|
||||
"instance.settings.tabs.installation.show-all-versions": {
|
||||
"message": "Összes verzió mutatása"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.change-version": {
|
||||
"message": "verzió váltás"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.install": {
|
||||
"message": "telepítés"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.reinstall": {
|
||||
"message": "újratelepítés"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.action.repair": {
|
||||
"message": "javítás"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-installing": {
|
||||
"message": "Nem lehet {action}-t végrehajtani telepítés közben"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-offline": {
|
||||
"message": "Offline állapotban nem lehet {action}-t végrehajtani"
|
||||
},
|
||||
"instance.settings.tabs.installation.tooltip.cannot-while-repairing": {
|
||||
"message": "Nem lehet {action}-t végrehajtani javítás közben"
|
||||
},
|
||||
"instance.settings.tabs.installation.unknown-version": {
|
||||
"message": "(ismeretlen verzió)"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.button": {
|
||||
"message": "Profil leválasztása"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.description": {
|
||||
"message": "Ha folytatod, akkor nem tudod újra összekapcsolni anélkül, hogy egy teljesen új profilt hoznál létre. Többé nem fogja megkapni a modcsomag frissítéseit, és normál állapotba kerül."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.confirm.title": {
|
||||
"message": "Biztosan le szeretnéd választani ezt a profilt?"
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.description": {
|
||||
"message": "Ez az profil egy modcsomaghoz van kapcsolva, ami azt jelenti, hogy a modok nem frissíthetőek, és nem lehet megváltoztatni a modbetöltőt vagy a Minecraft verziót. A kapcsolódás megszüntetése véglegesen leválasztja ezt a profilt a modcsomagról."
|
||||
},
|
||||
"instance.settings.tabs.installation.unlink.title": {
|
||||
"message": "Modpack-ről való leválasztás"
|
||||
},
|
||||
"instance.settings.tabs.java": {
|
||||
"message": "Java és memória"
|
||||
},
|
||||
@@ -539,9 +545,6 @@
|
||||
"instance.worlds.dont_show_on_home": {
|
||||
"message": "Ne mutasd a kezdőlapon"
|
||||
},
|
||||
"instance.worlds.filter.available": {
|
||||
"message": "Elérhető"
|
||||
},
|
||||
"instance.worlds.game_already_open": {
|
||||
"message": "A profil már meg van nyitva"
|
||||
},
|
||||
@@ -549,10 +552,13 @@
|
||||
"message": "Hardcore mód"
|
||||
},
|
||||
"instance.worlds.incompatible_server": {
|
||||
"message": "A Szerver nem kompatibilis"
|
||||
"message": "A szerver nem kompatibilis"
|
||||
},
|
||||
"instance.worlds.linked_server": {
|
||||
"message": "Szerverprojekt által kezelt"
|
||||
},
|
||||
"instance.worlds.no_contact": {
|
||||
"message": "Nem lehet kapcsolatot létesíteni a szerverrel"
|
||||
"message": "A szerverrel nem lehet kapcsolatot létesíteni"
|
||||
},
|
||||
"instance.worlds.no_server_quick_play": {
|
||||
"message": "Csak Minecraft Alpha 1.0.5+-tól tudsz egyből szerverhez csatlakozni"
|
||||
@@ -563,12 +569,6 @@
|
||||
"instance.worlds.play_instance": {
|
||||
"message": "Játék a profillal"
|
||||
},
|
||||
"instance.worlds.type.server": {
|
||||
"message": "Szerver"
|
||||
},
|
||||
"instance.worlds.type.singleplayer": {
|
||||
"message": "Egyjátékosmód"
|
||||
},
|
||||
"instance.worlds.view_instance": {
|
||||
"message": "Profil megtekintése"
|
||||
},
|
||||
@@ -582,9 +582,21 @@
|
||||
"message": "A játékverzió a profil által van megadva"
|
||||
},
|
||||
"search.filter.locked.instance-loader.title": {
|
||||
"message": "A modbetöltő a profil által van megadva"
|
||||
"message": "A betöltő a profil által van megadva"
|
||||
},
|
||||
"search.filter.locked.instance.sync": {
|
||||
"message": "Profil szinkronizálása"
|
||||
},
|
||||
"search.filter.locked.server": {
|
||||
"message": "A szerver által van megadva"
|
||||
},
|
||||
"search.filter.locked.server-environment.title": {
|
||||
"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"
|
||||
},
|
||||
"search.filter.locked.server-loader.title": {
|
||||
"message": "A betöltőt a szerver biztosítja"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user