Compare commits

...
Author SHA1 Message Date
aecsocket a7e990fac8 Fix buffer allocations in server pinging code 2026-04-04 16:39:00 +01:00
ProspectorandGitHub 3091021194 fix: no gap after navtabs on collections (#5740)
* fix: no gap after navtabs on collections

* fix collection sorting
2026-04-04 14:53:53 +00:00
Prospector dc96043adc app changelog 2026-04-03 16:38:43 -07:00
aecsocketandGitHub 92bf2e5c29 Install transitive dependencies of versions properly (#5745)
* install recursive deps properly

* fix up
2026-04-03 20:29:08 +00:00
Prospector a6d359e9c1 Revert "beenz"
This reverts commit 35033ccc03.
2026-04-02 13:18:20 -07:00
Calum H.andGitHub ddd1a36506 feat: allow changelog comment from 3rd party PRs (#5724) 2026-04-02 19:41:53 +00:00
Prospector 933fdba388 Revert "give beenz"
This reverts commit c52abece44.
2026-04-02 12:40:39 -07:00
Calum H.andGitHub fa4711ff7b feat: implement improved flow for server panel edit installation (#5711)
* feat: implement improved flow for server panel edit installation

* feat: installation form finalized

* feat: error state for InstallingBanner

* feat: action button refactor + save banner text fix

* fix: lint

* fix: content card alignment

* feat: better copy

* fix: lint

* fix: hide shift click + fix NeoForge chip

* fix: lint
2026-04-01 17:53:19 +00:00
Prospector c52abece44 give beenz 2026-04-01 03:03:26 -07:00
Prospector 35033ccc03 beenz 2026-04-01 01:42:18 -07:00
Prospector 97734a98f9 fix error 2026-04-01 01:42:01 -07:00
Calum H.andGitHub 3978e3dead fix: try fix virtual scrolling regression (#5723) 2026-03-31 20:40:04 +00:00
Calum H.andGitHub 5939d2a4e7 fix: mobile tooltip bug for files tab (#5722) 2026-03-31 20:33:02 +00:00
Truman GaoandGitHub 4224ef45b3 feat: add shared UI package auth DI (#5720)
* feat: add shared UI package auth DI

* use refs instead of reactive

* pnpm prepr

* move app auth provider setup to src/providers/setup
2026-03-31 17:15:35 +00:00
xinyihlandGitHub e2bfed177d fix: billing charges error 500 (#5718) 2026-03-31 07:06:26 +00:00
Truman GaoandGitHub 7f92706e5f improve app error modal (#5710) 2026-03-31 07:00:59 +00:00
François-Xavier TalbotandGitHub 90deb7310e Fix daedalus NeoForge (#5713)
* Support NeoForge version for year-based Minecraft versions

* Run on CI

* Fix

* Fix branch

* Undo branch switch
2026-03-30 17:53:29 +00:00
Truman GaoandGitHub 4cd6c1a72d fix modpacks no loader (#5707) 2026-03-30 09:21:20 +00:00
NitrrineandGitHub 3a8561cf35 fix: save banner is getting hidden by some parts of the ui (#5697) 2026-03-30 09:20:55 +00:00
Modrinth BotandGitHub a3f80dcb66 New translations from Crowdin (main) (#5708) 2026-03-30 09:20:30 +00:00
Calum H.andGitHub 0ee58867e8 feat: warning filter + remove client only filter as it's useless (#5690)
* feat: warning filter

* fix: remove client_only filter
2026-03-27 22:00:02 +00:00
Prospector d4c2fdb9ef Revert "revert release workflow changes"
This reverts commit fc87506745.
2026-03-27 15:01:52 -07:00
Calum H.andGitHub e6b061f38c fix: paper/purpur vers mismatch (#5687)
* fix: paper/purpur

* fix: use fill api

* fix: lint
2026-03-27 17:24:16 +00:00
Calum H.andGitHub 87122cf9bd feat: console component (#5685) 2026-03-27 15:44:08 +00:00
Prospector fc87506745 revert release workflow changes 2026-03-26 18:30:02 -07:00
Prospector 6ba41ba17f clean up changelog, remove unnecessary technical details 2026-03-26 18:21:12 -07:00
Prospector 628634772e changelog 2026-03-26 18:04:59 -07:00
François-Xavier TalbotandGitHub b68aeddedc hosting: Copy ID button for backups when developer mode is on (#5681)
* Copy ID button in backups tab

* Remove codex slop
2026-03-27 00:18:33 +00:00
Calum H.andGitHub c5a0c71424 feat: vite 8 app frontend (#5680) 2026-03-27 00:17:51 +00:00
Calum H.andGitHub 4394092928 feat: better tooltips for mods in content tab hosting panel (#5679)
* feat: better tooltips for mods in content tab hosting panel

* feat: qa
2026-03-26 22:55:08 +00:00
aecsocketandGitHub ef1ffa6577 Fix payout sync response schema (#5644) 2026-03-26 22:44:54 +00:00
Calum H.andGitHub b11b54cbc9 fix: various content fixes (#5676)
* fix: wrong lock field

* fix: install_stage locking up due to previous failure stored as stale snapshot

* fix: Error when updating instance
Fixes #5671

* fix: prepr
2026-03-26 22:30:17 +00:00
ProspectorandGitHub 36f62a3285 refactor: move flags into settings, change icon (#5678)
* refactor: move flags into settings, change icon

* fix: use ButtonStyled for app
2026-03-26 21:10:01 +00:00
Calum H.andGitHub 381ea51cce refactor: align files tab with content tab design (#5621)
* fix: files.vue bugs before styling changes

* feat: move files tab to shared layout structure

* fix: qa

* fix: qa

* fix: bugs

* fix: lint

* fix: admonition cleanup with progress + actions

* fix: cleanup

* fix: modals

* fix: admon title

* fix: i18n standard

* fix: lint + i18n pass

* fix: remove transition

* fix: type errors

* feat: files tab in app

* fix: qa

* fix: backup item minmax

* fix: use ContentPageHeader for server panel

* fix: lint

* fix: lint

* fix: lint

* feat: page leave safety

* fix: lint

* fix: cargo fmt fix

* fix: blank in prod

* fix: content card table stuff

* Revert "fix: blank in prod"

This reverts commit 74758fe185.

* fix: import

* feat: browse worlds/servers flow

* fix: worlds tab parity with content tab

* fix: perf bug + shader filter pill copy

* feat: singleplayer filter

* fix: ordering

* fix: breadcrumbs

* fix: lint

* fix: qa

* feat: store server proj id when adding to a non-linked instance

* fix: lint

* fix: i18n + qa

* fix: conflict

* qa: already installed modal + placeholders not server-specific

* fix: qa

* fix: add + edit server modals

* fix: qa

* fix: security

* fix: devin flags

* fix: lint

* chore: change file to break build cache

* fix: admon

* fix: import path stuff

* feat: qa

* fix: fmt fmt idiot

---------

Signed-off-by: Calum H. <calum@modrinth.com>
2026-03-26 18:55:15 +00:00
Truman GaoandGitHub 706eb800cb fix: website visual issues (#5675)
* fix no modpack loader showing as resource pack loader

* fix table overflow, add game version tags "+ {num}" overflow menu

* pnpm prepr
2026-03-26 18:40:44 +00:00
Calum H.andGitHub f1648298c4 fix: neoforge not existing for 26.1 breaking vers picker (#5674)
* fix: neoforge for 26.1 -> other vers being picked not existing causing version picker to break

* fix: lint
2026-03-26 17:53:27 +00:00
Prospector 3c3cde1908 changelog 2026-03-26 00:22:40 -07:00
ProspectorandGitHub 274325d97c fix: settings page error (#5668) 2026-03-26 00:21:19 -07:00
aecsocketandGitHub da48a12551 Only mark servers as offline if they fail pings 3+ times (#5664)
* wip: online status fix

* use INCR

* properly clear cache
2026-03-26 06:34:20 +00:00
François-Xavier TalbotandGitHub bf24ed8d12 Add feature flag to force Archon requests to be traced (#5666) 2026-03-26 06:34:04 +00:00
aecsocketandGitHub 0731654a1c maybe fix daedalus (#5665) 2026-03-26 06:33:58 +00:00
Calum H.andGitHub 81f19eeb8d fix: various content tab hosting bugs (#5662)
* fix: qa

* fix: lint
2026-03-25 17:58:13 +00:00
Calum H.andGitHub 4b4282cfbf fix: 500 on oauth authorize page (#5661) 2026-03-25 17:52:12 +00:00
François-Xavier TalbotandGitHub 7b3471944d hosting: "Reset to onboarding" support-only action (#5659)
* Reset to onboarding button

* Lint

* Intl
2026-03-25 14:50:31 +00:00
Prospector d2abeb434c changelog 2026-03-24 14:21:31 -07:00
François-Xavier TalbotandGitHub 0aecfa3140 hosting: support java 25 (#5654)
* Add Java 25, handle new version format

* Changelog

* Revert "Changelog"

This reverts commit 0c1c7e2fe8.
2026-03-24 20:39:04 +00:00
356 changed files with 27935 additions and 7741 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
name: Changelog Comment
on:
pull_request:
pull_request_target:
types: [opened, reopened]
workflow_dispatch:
inputs:
+1
View File
@@ -86,6 +86,7 @@ Each project may have its own `CLAUDE.md` with detailed instructions:
- 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.
## Edit Tool - Whitespace Handling (CLAUDE ONLY)
Generated
+2
View File
@@ -10241,6 +10241,7 @@ dependencies = [
name = "theseus_gui"
version = "1.0.0-local"
dependencies = [
"async_zip",
"chrono",
"daedalus",
"dashmap",
@@ -10258,6 +10259,7 @@ dependencies = [
"tauri-build",
"tauri-plugin-deep-link",
"tauri-plugin-dialog",
"tauri-plugin-fs",
"tauri-plugin-http",
"tauri-plugin-opener",
"tauri-plugin-os",
+1
View File
@@ -179,6 +179,7 @@ tauri = "2.8.5"
tauri-build = "2.4.1"
tauri-plugin-deep-link = "2.4.3"
tauri-plugin-dialog = "2.4.0"
tauri-plugin-fs = "2.4.5"
tauri-plugin-http = "2.5.7"
tauri-plugin-opener = "2.5.0"
tauri-plugin-os = "2.3.1"
+2 -1
View File
@@ -22,6 +22,7 @@
"@tanstack/vue-query": "^5.90.7",
"@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-dialog": "^2.2.1",
"@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",
@@ -58,7 +59,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"
},
+5
View File
@@ -106,6 +106,7 @@ import {
} from '@/providers/download-progress.ts'
import { createServerInstall, provideServerInstall } from '@/providers/server-install'
import { setupProviders } from '@/providers/setup'
import { setupAuthProvider } from '@/providers/setup/auth'
import { useError } from '@/store/error.js'
import { useLoading, useTheming } from '@/store/state'
@@ -454,6 +455,10 @@ const credentials = ref()
const modrinthLoginFlowWaitModal = ref()
setupAuthProvider(credentials, async (_redirectPath) => {
await signIn()
})
async function fetchCredentials() {
const creds = await getCreds().catch(handleError)
if (creds && creds.user_id) {
@@ -3,6 +3,7 @@
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"
@@ -128,6 +129,16 @@ watch(breadcrumbs, () => {
</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;
}
@@ -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>
@@ -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,185 +0,0 @@
<template>
<nav
v-if="filteredLinks.length > 1"
ref="scrollContainer"
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="[
'pointer-events-none absolute h-[calc(100%-0.5rem)] overflow-hidden rounded-full p-1',
subpageSelected ? 'bg-button-bg' : 'bg-button-bgSelected',
{ 'navtabs-transition': transitionsEnabled },
]"
:style="{
left: sliderLeftPx,
top: sliderTopPx,
right: sliderRightPx,
bottom: sliderBottomPx,
opacity: sliderReady && activeIndex !== -1 ? 1 : 0,
}"
aria-hidden="true"
></div>
</nav>
</template>
<script setup lang="ts">
import { computed, nextTick, 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 scrollContainer = ref<HTMLElement | null>(null)
const sliderLeft = ref(4)
const sliderTop = ref(4)
const sliderRight = ref(4)
const sliderBottom = ref(4)
const activeIndex = ref(-1)
const subpageSelected = ref(false)
const sliderReady = ref(false)
const transitionsEnabled = ref(false)
const sliderDelays = ref({ left: '0ms', top: '0ms', right: '0ms', bottom: '0ms' })
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`)
const leftDelay = computed(() => sliderDelays.value.left)
const rightDelay = computed(() => sliderDelays.value.right)
const topDelay = computed(() => sliderDelays.value.top)
const bottomDelay = computed(() => sliderDelays.value.bottom)
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 {
sliderLeft.value = 0
sliderRight.value = 0
}
}
function getTabElement(index: number): HTMLElement | null {
if (index === -1) return null
const container = scrollContainer.value
if (!container) return null
const tabs = container.querySelectorAll('.button-animation')
return (tabs[index] as HTMLElement) ?? null
}
function startAnimation() {
const el = getTabElement(activeIndex.value)
if (!el?.offsetParent) return
const parent = el.offsetParent as HTMLElement
const newValues = {
left: el.offsetLeft,
top: el.offsetTop,
right: parent.offsetWidth - el.offsetLeft - el.offsetWidth,
bottom: parent.offsetHeight - el.offsetTop - el.offsetHeight,
}
const isInitialPosition = sliderLeft.value === 4 && sliderRight.value === 4
if (isInitialPosition) {
sliderLeft.value = newValues.left
sliderRight.value = newValues.right
sliderTop.value = newValues.top
sliderBottom.value = newValues.bottom
sliderReady.value = true
requestAnimationFrame(() => {
transitionsEnabled.value = true
})
} else {
const STAGGER_DELAY = '200ms'
sliderDelays.value = {
left: newValues.left < sliderLeft.value ? '0ms' : STAGGER_DELAY,
right: newValues.left < sliderLeft.value ? STAGGER_DELAY : '0ms',
top: newValues.top < sliderTop.value ? '0ms' : STAGGER_DELAY,
bottom: newValues.top < sliderTop.value ? STAGGER_DELAY : '0ms',
}
sliderLeft.value = newValues.left
sliderRight.value = newValues.right
sliderTop.value = newValues.top
sliderBottom.value = newValues.bottom
}
}
onMounted(async () => {
window.addEventListener('resize', pickLink)
await nextTick()
pickLink()
})
onUnmounted(() => {
window.removeEventListener('resize', pickLink)
})
watch(
filteredLinks,
async () => {
await nextTick()
pickLink()
},
{ deep: true },
)
watch(route, async () => {
await nextTick()
pickLink()
})
</script>
<style scoped>
.navtabs-transition {
/* Delay on opacity is to hide any jankiness as the page loads */
transition:
left 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(leftDelay),
right 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(rightDelay),
top 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(topDelay),
bottom 150ms cubic-bezier(0.4, 0, 0.2, 1) v-bind(bottomDelay),
opacity 250ms cubic-bezier(0.5, 0, 0.2, 1) 50ms;
}
</style>
@@ -30,19 +30,19 @@ const deleteConfirmModal = ref()
const { instance } = injectInstanceSettings()
const title = ref(instance.name)
const icon: Ref<string | undefined> = ref(instance.icon_path)
const groups = ref(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(() => instance.install_stage !== 'installed')
const installing = computed(() => instance.value.install_stage !== 'installed')
async function duplicateProfile() {
await duplicate(instance.path).catch(handleError)
await duplicate(instance.value.path).catch(handleError)
trackEvent('InstanceDuplicate', {
loader: instance.loader,
game_version: instance.game_version,
loader: instance.value.loader,
game_version: instance.value.game_version,
})
}
@@ -53,7 +53,7 @@ const availableGroups = computed(() => [
async function resetIcon() {
icon.value = undefined
await edit_icon(instance.path, null).catch(handleError)
await edit_icon(instance.value.path, null).catch(handleError)
trackEvent('InstanceRemoveIcon')
}
@@ -71,7 +71,7 @@ async function setIcon() {
if (!value) return
icon.value = value
await edit_icon(instance.path, icon.value).catch(handleError)
await edit_icon(instance.value.path, icon.value).catch(handleError)
trackEvent('InstanceSetIcon')
}
@@ -102,7 +102,7 @@ watch(
[title, groups, groups],
async () => {
if (removing.value) return
await edit(instance.path, editProfileObject.value).catch(handleError)
await edit(instance.value.path, editProfileObject.value).catch(handleError)
},
{ deep: true },
)
@@ -110,11 +110,11 @@ watch(
const removing = ref(false)
async function removeProfile() {
removing.value = true
const path = instance.path
const path = instance.value.path
trackEvent('InstanceRemove', {
loader: instance.loader,
game_version: instance.game_version,
loader: instance.value.loader,
game_version: instance.value.game_version,
})
await router.push({ path: '/' })
@@ -22,9 +22,11 @@ const { instance } = injectInstanceSettings()
const globalSettings = (await get().catch(handleError)) as AppSettings
const overrideHooks = ref(
!!instance.hooks.pre_launch || !!instance.hooks.wrapper || !!instance.hooks.post_exit,
!!instance.value.hooks.pre_launch ||
!!instance.value.hooks.wrapper ||
!!instance.value.hooks.post_exit,
)
const hooks = ref(instance.hooks ?? globalSettings.hooks)
const hooks = ref(instance.value.hooks ?? globalSettings.hooks)
const editProfileObject = computed(() => {
const editProfile: {
@@ -40,7 +42,7 @@ const editProfileObject = computed(() => {
watch(
[overrideHooks, hooks],
async () => {
await edit(instance.path, editProfileObject.value)
await edit(instance.value.path, editProfileObject.value)
},
{ deep: true },
)
@@ -73,9 +73,9 @@ const [
])
const { data: modpackInfo } = useQuery({
queryKey: computed(() => ['linkedModpackInfo', instance.path]),
queryFn: () => get_linked_modpack_info(instance.path, 'must_revalidate'),
enabled: computed(() => !!instance.linked_data?.project_id && !offline),
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 repairing = ref(false)
@@ -101,13 +101,13 @@ function getManifest(loader: string) {
provideAppBackup({
async createBackup() {
const allProfiles = await list()
const prefix = `${instance.name} - Backup #`
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.path)
const newPath = await duplicate(instance.value.path)
await edit(newPath, { name: `${prefix}${nextNum}` })
},
})
@@ -118,27 +118,30 @@ provideInstallationSettings({
const rows = [
{
label: formatMessage(commonMessages.platformLabel),
value: formatLoaderLabel(instance.loader),
value: formatLoaderLabel(instance.value.loader),
},
{
label: formatMessage(commonMessages.gameVersionLabel),
value: instance.game_version,
value: instance.value.game_version,
},
]
if (instance.loader !== 'vanilla' && instance.loader_version) {
if (instance.value.loader !== 'vanilla' && instance.value.loader_version) {
rows.push({
label: formatMessage(messages.loaderVersion, {
loader: formatLoaderLabel(instance.loader),
loader: formatLoaderLabel(instance.value.loader),
}),
value: instance.loader_version,
value: instance.value.loader_version,
})
}
return rows
}),
isLinked: computed(() => !!instance.linked_data?.locked),
isLinked: computed(() => !!instance.value.linked_data?.locked),
isBusy: computed(
() =>
instance.install_stage !== 'installed' || repairing.value || reinstalling.value || !!offline,
instance.value.install_stage !== 'installed' ||
repairing.value ||
reinstalling.value ||
!!offline,
),
modpack: computed(() => {
if (!modpackInfo.value) return null
@@ -149,9 +152,9 @@ provideInstallationSettings({
versionNumber: modpackInfo.value.version?.version_number,
}
}),
currentPlatform: computed(() => instance.loader),
currentGameVersion: computed(() => instance.game_version),
currentLoaderVersion: computed(() => instance.loader_version ?? ''),
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) {
@@ -194,50 +197,50 @@ provideInstallationSettings({
if (platform !== 'vanilla' && loaderVersionId) {
editProfile.loader_version = loaderVersionId
}
await edit(instance.path, editProfile).catch(handleError)
await edit(instance.value.path, editProfile).catch(handleError)
},
afterSave: async () => {
await install(instance.path, false).catch(handleError)
await install(instance.value.path, false).catch(handleError)
trackEvent('InstanceRepair', {
loader: instance.loader,
game_version: instance.game_version,
loader: instance.value.loader,
game_version: instance.value.game_version,
})
},
async repair() {
repairing.value = true
await install(instance.path, true).catch(handleError)
await install(instance.value.path, true).catch(handleError)
repairing.value = false
trackEvent('InstanceRepair', {
loader: instance.loader,
game_version: instance.game_version,
loader: instance.value.loader,
game_version: instance.value.game_version,
})
},
async reinstallModpack() {
reinstalling.value = true
await update_repair_modrinth(instance.path).catch(handleError)
await update_repair_modrinth(instance.value.path).catch(handleError)
reinstalling.value = false
trackEvent('InstanceRepair', {
loader: instance.loader,
game_version: instance.game_version,
loader: instance.value.loader,
game_version: instance.value.game_version,
})
},
async unlinkModpack() {
await edit(instance.path, {
await edit(instance.value.path, {
linked_data: null as unknown as undefined,
})
await queryClient.invalidateQueries({
queryKey: ['linkedModpackInfo', instance.path],
queryKey: ['linkedModpackInfo', instance.value.path],
})
onUnlinked()
},
getCachedModpackVersions: () => null,
async fetchModpackVersions() {
const versions = await get_project_versions(instance.linked_data!.project_id!).catch(
const versions = await get_project_versions(instance.value.linked_data!.project_id!).catch(
handleError,
)
return (versions ?? []) as Labrinth.Versions.v2.Version[]
@@ -250,20 +253,20 @@ provideInstallationSettings({
},
async onModpackVersionConfirm(version) {
await update_managed_modrinth_version(instance.path, version.id)
await update_managed_modrinth_version(instance.value.path, version.id)
await queryClient.invalidateQueries({
queryKey: ['linkedModpackInfo', instance.path],
queryKey: ['linkedModpackInfo', instance.value.path],
})
},
updaterModalProps: computed(() => ({
isApp: true,
currentVersionId:
modpackInfo.value?.update_version_id ?? instance.linked_data?.version_id ?? '',
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.game_version,
currentLoader: instance.loader,
currentGameVersion: instance.value.game_version,
currentLoader: instance.value.loader,
})),
isServer: false,
@@ -25,20 +25,24 @@ const { instance } = injectInstanceSettings()
const globalSettings = (await get().catch(handleError)) as unknown as AppSettings
const overrideJavaInstall = ref(!!instance.java_path)
const optimalJava = readonly(await get_optimal_jre_key(instance.path).catch(handleError))
const javaInstall = ref({ path: optimalJava.path ?? 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((instance.extra_launch_args?.length ?? 0) > 0)
const javaArgs = ref((instance.extra_launch_args ?? globalSettings.extra_launch_args).join(' '))
const overrideEnvVars = ref((instance.custom_env_vars?.length ?? 0) > 0)
const envVars = ref(
(instance.custom_env_vars ?? globalSettings.custom_env_vars).map((x) => x.join('=')).join(' '),
const overrideJavaArgs = ref((instance.value.extra_launch_args?.length ?? 0) > 0)
const javaArgs = ref(
(instance.value.extra_launch_args ?? globalSettings.extra_launch_args).join(' '),
)
const overrideMemorySettings = ref(!!instance.memory)
const memory = ref(instance.memory ?? globalSettings.memory)
const overrideEnvVars = ref((instance.value.custom_env_vars?.length ?? 0) > 0)
const envVars = ref(
(instance.value.custom_env_vars ?? globalSettings.custom_env_vars)
.map((x) => x.join('='))
.join(' '),
)
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[]
@@ -76,7 +80,7 @@ watch(
memory,
],
async () => {
await edit(instance.path, editProfileObject.value)
await edit(instance.value.path, editProfileObject.value)
},
{ deep: true },
)
@@ -22,12 +22,14 @@ const { instance } = injectInstanceSettings()
const globalSettings = (await get().catch(handleError)) as AppSettings
const overrideWindowSettings = ref(!!instance.game_resolution || !!instance.force_fullscreen)
const overrideWindowSettings = ref(
!!instance.value.game_resolution || !!instance.value.force_fullscreen,
)
const resolution: Ref<[number, number]> = ref(
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(
instance.force_fullscreen ?? globalSettings.force_fullscreen,
instance.value.force_fullscreen ?? globalSettings.force_fullscreen,
)
const editProfileObject = computed(() => {
@@ -46,7 +48,7 @@ const editProfileObject = computed(() => {
watch(
[overrideWindowSettings, resolution, fullscreenSetting],
async () => {
await edit(instance.path, editProfileObject.value)
await edit(instance.value.path, editProfileObject.value)
},
{ deep: true },
)
@@ -6,12 +6,13 @@ import {
LanguagesIcon,
ModrinthIcon,
PaintbrushIcon,
ReportIcon,
SettingsIcon,
ShieldIcon,
ToggleRightIcon,
} from '@modrinth/assets'
import {
commonMessages,
commonSettingsMessages,
defineMessage,
defineMessages,
ProgressBar,
@@ -95,11 +96,8 @@ 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,
},
@@ -44,8 +44,10 @@ const emit = defineEmits<{
const isMinecraftServer = ref(false)
const handleUnlinked = () => emit('unlinked')
const instanceRef = computed(() => props.instance)
provideInstanceSettings({
instance: props.instance,
instance: instanceRef,
offline: props.offline,
isMinecraftServer,
onUnlinked: handleUnlinked,
@@ -1,21 +1,31 @@
<template>
<NewModal ref="modal" :header="formatMessage(messages.header)" fade="warning" max-width="500px">
<Admonition type="warning" :header="formatMessage(messages.admonitionHeader)">
{{ formatMessage(messages.admonitionBody, { instanceName }) }}
</Admonition>
<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="handleGoToInstance">
<ExternalIcon />
{{ formatMessage(messages.goToInstance) }}
<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.createAnyway) }}
{{ formatMessage(messages.create) }}
</button>
</ButtonStyled>
</div>
@@ -24,8 +34,15 @@
</template>
<script setup lang="ts">
import { ExternalIcon, PlusIcon } from '@modrinth/assets'
import { Admonition, ButtonStyled, defineMessages, NewModal, useVIntl } from '@modrinth/ui'
import { PlusIcon, RightArrowIcon, XIcon } from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
defineMessages,
IntlFormatted,
NewModal,
useVIntl,
} from '@modrinth/ui'
import { ref } from 'vue'
const { formatMessage } = useVIntl()
@@ -35,21 +52,18 @@ const messages = defineMessages({
id: 'app.instance.modpack-already-installed.header',
defaultMessage: 'Modpack already installed',
},
admonitionHeader: {
id: 'app.instance.modpack-already-installed.admonition-header',
defaultMessage: 'Duplicate modpack',
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?',
},
admonitionBody: {
id: 'app.instance.modpack-already-installed.admonition-body',
defaultMessage: 'This modpack is already installed in the "{instanceName}" instance.',
instance: {
id: 'app.instance.modpack-already-installed.instance',
defaultMessage: 'Instance',
},
goToInstance: {
id: 'app.instance.modpack-already-installed.go-to-instance',
defaultMessage: 'Go to instance',
},
createAnyway: {
id: 'app.instance.modpack-already-installed.create-anyway',
defaultMessage: 'Create anyway',
create: {
id: 'app.instance.modpack-already-installed.create',
defaultMessage: 'Create',
},
})
@@ -68,6 +82,10 @@ function show(name: string, path: string) {
modal.value?.show()
}
function handleCancel() {
modal.value?.hide()
}
function handleGoToInstance() {
modal.value?.hide()
emit('go-to-instance', instancePath.value)
@@ -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'
@@ -31,11 +31,20 @@ watch(
{{ option.replaceAll('_', ' ') }}
</h2>
</div>
<Toggle
id="advanced-rendering"
:model-value="themeStore.getFeatureFlag(option)"
@update:model-value="() => setFeatureFlag(option, !themeStore.getFeatureFlag(option))"
/>
<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>
</template>
@@ -189,6 +189,22 @@ const messages = defineMessages({
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>
@@ -243,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>
@@ -265,8 +285,11 @@ const messages = defineMessages({
/>
<Tooltip :disabled="!hasPlayersTooltip">
<span :class="{ 'cursor-help': hasPlayersTooltip }">
{{ formatNumber(serverStatus.players?.online) }}
online
{{
formatMessage(messages.playersOnline, {
count: formatNumber(serverStatus.players?.online ?? 0),
})
}}
</span>
<template #popper>
<div class="flex flex-col gap-1">
@@ -280,7 +303,7 @@ const messages = defineMessages({
</template>
<template v-else>
<NoSignalIcon aria-hidden="true" stroke-width="3px" class="shrink-0" />
Offline
{{ formatMessage(messages.offline) }}
</template>
</div>
</div>
@@ -299,7 +322,7 @@ const messages = defineMessages({
})
}}
</template>
<template v-else> Not played yet </template>
<template v-else> {{ formatMessage(messages.notPlayedYet) }} </template>
</div>
<template v-if="instancePath">
@@ -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>
+6
View File
@@ -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,12 +142,16 @@ 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,
projectId,
contentKind,
})
}
+5 -47
View File
@@ -6,7 +6,7 @@
"message": "تعذر الوصول إلى خوادم المصادقة"
},
"app.export-modal.description-placeholder": {
"message": "ادخل وصف التعديل..."
"message": "أدخل وصف التعديل..."
},
"app.export-modal.export-button": {
"message": "تصدير"
@@ -41,35 +41,14 @@
"app.instance.confirm-delete.header": {
"message": "حذف المثيل"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "تم تثبيت حزمة التعديل هذه بالفعل في مثيل \"{instanceName}\"."
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "حزمة تعديل مكررة"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "إنشاء على أي حال"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "انتقل إلى المثال"
},
"app.instance.modpack-already-installed.header": {
"message": "تم تثبيت حزمة التعديل بالفعل"
},
"app.instance.mods.content-type-project": {
"message": "مشروع"
},
"app.instance.mods.copy-link": {
"message": "نسخ الرابط"
},
"app.instance.mods.installing": {
"message": "جاري التثبيت..."
},
"app.instance.mods.modpack-fallback": {
"message": "حزمة التعديل"
},
"app.instance.mods.project-was-added": {
"message": "تمت إضافة \"{name}\"."
"message": "تمت إضافة \"{name}\""
},
"app.instance.mods.projects-were-added": {
"message": "تمت إضافة {count} من المشاريع"
@@ -80,18 +59,9 @@
"app.instance.mods.share-title": {
"message": "مشاركة محتوى حزمة التعديل"
},
"app.instance.mods.show-file": {
"message": "عرض الملف"
},
"app.instance.mods.successfully-uploaded": {
"message": "تم الرفع بنجاح"
},
"app.instance.mods.unknown-version": {
"message": "غير معروف"
},
"app.instance.mods.updating": {
"message": "جارٍ التحديث..."
},
"app.modal.install-to-play.content-required": {
"message": "المحتوى مطلوب"
},
@@ -102,7 +72,7 @@
"message": "تثبيت"
},
"app.modal.install-to-play.mod-count": {
"message": ""
"message": "{count, plural, one {# تعديل} other {# تعديلات}}"
},
"app.modal.install-to-play.required-modpack": {
"message": "حزمة التعديل مطلوبة"
@@ -111,10 +81,10 @@
"message": "يتطلب هذا الخادم تعديلات للعب. انقر فوق \"تثبيت\" لإعداد الملفات المطلوبة من Modrinth، ثم قم بتشغيله مباشرة إلى الخادم."
},
"app.modal.install-to-play.shared-instance": {
"message": ُزْمَة مشاركة"
"message": زمة مشتركة"
},
"app.modal.install-to-play.shared-server-instance": {
"message": ُزْمَة خادم مشاركة"
"message": زمة خادم مشتركة"
},
"app.modal.install-to-play.view-contents": {
"message": "عرض المحتويات"
@@ -140,9 +110,6 @@
"app.settings.tabs.default-instance-options": {
"message": "خيارات النسخة الافتراضية"
},
"app.settings.tabs.feature-flags": {
"message": "أعلام الميزات"
},
"app.settings.tabs.java-installations": {
"message": "تثبيتات جافا"
},
@@ -467,9 +434,6 @@
"instance.worlds.dont_show_on_home": {
"message": "عدم العرض في الصفحة الرئيسية"
},
"instance.worlds.filter.available": {
"message": "متاح"
},
"instance.worlds.game_already_open": {
"message": "النسخة مفتوحة بالفعل"
},
@@ -494,12 +458,6 @@
"instance.worlds.play_instance": {
"message": "تشغيل النسخة"
},
"instance.worlds.type.server": {
"message": "الخادم"
},
"instance.worlds.type.singleplayer": {
"message": "لعب فردي"
},
"instance.worlds.view_instance": {
"message": "عرض النسخة"
},
@@ -47,9 +47,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"
},
@@ -350,9 +347,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á"
},
@@ -374,12 +368,6 @@
"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"
},
@@ -44,15 +44,6 @@
"app.instance.mods.content-type-project": {
"message": "projekt"
},
"app.instance.mods.copy-link": {
"message": "Kopier link"
},
"app.instance.mods.installing": {
"message": "Installer..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" blev tilføjet"
},
@@ -65,18 +56,9 @@
"app.instance.mods.share-title": {
"message": "Deler modpack indhold"
},
"app.instance.mods.show-file": {
"message": "Vis filer"
},
"app.instance.mods.successfully-uploaded": {
"message": "Uploadet"
},
"app.instance.mods.unknown-version": {
"message": "Ukendt"
},
"app.instance.mods.updating": {
"message": "Opdatere..."
},
"app.modal.install-to-play.content-required": {
"message": "Indhold krævet"
},
@@ -125,9 +107,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"
},
@@ -452,9 +431,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"
},
@@ -479,12 +455,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"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"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..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Instanz löschen"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Dieses Modpack ist bereits in der Instanz {instanceName} installiert."
"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.admonition-header": {
"message": "Modpack duplizieren"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Trotzdem erstellen"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Gehe zu Instanz"
"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.copy-link": {
"message": "Link kopieren"
},
"app.instance.mods.installing": {
"message": "Wird installiert..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpaket"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" wurde hinzugefügt"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Modpaketinhalte teilen"
},
"app.instance.mods.show-file": {
"message": "Datei anzeigen"
},
"app.instance.mods.successfully-uploaded": {
"message": "Erfolgreich hochgeladen"
},
"app.instance.mods.unknown-version": {
"message": "Unbekannt"
"app.instance.worlds.add-server": {
"message": "Server hinzufügen"
},
"app.instance.mods.updating": {
"message": "Wird aktualisiert..."
"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"
@@ -140,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"
},
@@ -197,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"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Welt bearbeiten"
},
"instance.files.adding-files": {
"message": "Dateien werden hinzugefügt ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Speichern unter..."
},
"instance.server-modal.address": {
"message": "Adresse"
},
@@ -467,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"
},
@@ -494,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"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"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": "Beschreibung des Modpacks eingeben..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Instanz löschen"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Dieses Modpack ist bereits in der Instanz {instanceName} installiert."
"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.admonition-header": {
"message": "Modpack duplizieren"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Trotzdem erstellen"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Gehe zu Instanz"
"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.copy-link": {
"message": "Link kopieren"
},
"app.instance.mods.installing": {
"message": "Wird installiert..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" wurde hinzugefügt"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Modpackinhalte teilen"
},
"app.instance.mods.show-file": {
"message": "Datei anzeigen"
},
"app.instance.mods.successfully-uploaded": {
"message": "Erfolgreich hochgeladen"
},
"app.instance.mods.unknown-version": {
"message": "Unbekannt"
"app.instance.worlds.add-server": {
"message": "Server hinzufügen"
},
"app.instance.mods.updating": {
"message": "Wird aktualisiert..."
"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"
@@ -140,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"
},
@@ -197,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"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Welt bearbeiten"
},
"instance.files.adding-files": {
"message": "Dateien werden hinzugefügt ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Speichern unter..."
},
"instance.server-modal.address": {
"message": "Adresse"
},
@@ -467,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"
},
@@ -494,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"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"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..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Delete instance"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "This modpack is already installed in the \"{instanceName}\" 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.admonition-header": {
"message": "Duplicate modpack"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Create anyway"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Go to instance"
"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.copy-link": {
"message": "Copy link"
},
"app.instance.mods.installing": {
"message": "Installing..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" was added"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Sharing modpack content"
},
"app.instance.mods.show-file": {
"message": "Show file"
},
"app.instance.mods.successfully-uploaded": {
"message": "Successfully uploaded"
},
"app.instance.mods.unknown-version": {
"message": "Unknown"
"app.instance.worlds.add-server": {
"message": "Add server"
},
"app.instance.mods.updating": {
"message": "Updating..."
"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"
@@ -140,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"
},
@@ -197,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"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Edit world"
},
"instance.files.adding-files": {
"message": "Adding files ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Save as..."
},
"instance.server-modal.address": {
"message": "Address"
},
@@ -467,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"
},
@@ -494,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"
},
+117 -48
View File
@@ -5,8 +5,41 @@
"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 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..."
"message": "Colocá la descripción del modpack..."
},
"app.export-modal.export-button": {
"message": "Exportar"
@@ -21,16 +54,16 @@
"message": "Nombre del modpack"
},
"app.export-modal.select-files-label": {
"message": "Seleccione archivos y carpetas para incluir en el paquete"
"message": "Selelecciona archivos y carpetas para incluir en el pack"
},
"app.export-modal.version-number-label": {
"message": "Número de versión"
"message": "Nombre 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 su instancia se eliminarán permanentemente, incluidos sus mundos, configuraciones y todo el contenido instalado."
"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"
@@ -41,56 +74,80 @@
"app.instance.confirm-delete.header": {
"message": "Eliminar instancia"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Este modpack ya está instalado en la instancia \"{instanceName}\"."
"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.admonition-header": {
"message": "Modpack duplicado"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Crea de todos modos"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Ir a la instancia"
"app.instance.modpack-already-installed.create": {
"message": "Crear"
},
"app.instance.modpack-already-installed.header": {
"message": "Modpack ya está instalado"
"message": "Este modpack ya esta instalado"
},
"app.instance.modpack-already-installed.instance": {
"message": "Instancia"
},
"app.instance.mods.content-type-project": {
"message": "proyecto"
},
"app.instance.mods.copy-link": {
"message": "Copiar enlace"
},
"app.instance.mods.installing": {
"message": "Instalando..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "Se ha añadido \"{name}\""
"message": "\"{name}\" fue añadido"
},
"app.instance.mods.projects-were-added": {
"message": "Se han añadido {count} proyectos"
"message": "Se agregaron {count} proyectos"
},
"app.instance.mods.share-text": {
"message": "¡Echa un vistazo a los proyectos que utilizo en mi modpack!"
"message": "¡Echa un vistazo a los proyectos que estoy usando en mi paquete de mods!"
},
"app.instance.mods.share-title": {
"message": "Compartir contenido del modpack"
},
"app.instance.mods.show-file": {
"message": "Mostrar archivo"
"message": "Compartiendo contenido del modpack"
},
"app.instance.mods.successfully-uploaded": {
"message": "Se ha subido correctamente"
"message": "Subido correctamente"
},
"app.instance.mods.unknown-version": {
"message": "Desconocido"
"app.instance.worlds.add-server": {
"message": "Añadir servidor"
},
"app.instance.mods.updating": {
"message": "Actualizando..."
"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 requerido"
@@ -140,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"
},
@@ -197,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": "Añadir un amigo"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Editar mundo"
},
"instance.files.adding-files": {
"message": "Añadiendo archivos ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Guardar como..."
},
"instance.server-modal.address": {
"message": "Dirección IP"
},
@@ -467,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"
},
@@ -494,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"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"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..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Eliminar instancia"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Este modpack ya está instalado en la instancia \"{instanceName}\"."
"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.admonition-header": {
"message": "Modpack duplicado"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Crea de todos modos"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Ir a la instancia"
"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.copy-link": {
"message": "Copiar enlace"
},
"app.instance.mods.installing": {
"message": "Instalando..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "Se ha añadido \"{name}\""
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Compartir contenido del modpack"
},
"app.instance.mods.show-file": {
"message": "Mostrar archivo"
},
"app.instance.mods.successfully-uploaded": {
"message": "Se ha subido correctamente"
},
"app.instance.mods.unknown-version": {
"message": "Desconocido"
"app.instance.worlds.add-server": {
"message": "Añadir servidor"
},
"app.instance.mods.updating": {
"message": "Actualizando..."
"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"
@@ -140,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"
},
@@ -197,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"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Editar mundo"
},
"instance.files.adding-files": {
"message": "Añadiendo archivos ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Guardar como..."
},
"instance.server-modal.address": {
"message": "Dirección IP"
},
@@ -467,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"
},
@@ -494,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"
},
@@ -71,9 +71,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"
},
@@ -398,9 +395,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"
},
@@ -425,12 +419,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"
},
@@ -26,18 +26,9 @@
"app.instance.mods.content-type-project": {
"message": "proyekto"
},
"app.instance.mods.copy-link": {
"message": "Kopyahin ang link"
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "Ang \"{name}\" ay nadagdag"
},
"app.instance.mods.unknown-version": {
"message": "Hindi kilala"
},
"app.modal.install-to-play.content-required": {
"message": "Nangangailangan ng kontento"
},
@@ -86,9 +77,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"
},
@@ -413,9 +401,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Huwag ipakita sa Home"
},
"instance.worlds.filter.available": {
"message": "Magagamit"
},
"instance.worlds.game_already_open": {
"message": "Bukas naman ang instansiya"
},
@@ -440,12 +425,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"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Impossible de contacter les serveurs d'authentification"
},
"app.browse.add-server-to-instance": {
"message": "Ajouter le serveur a l'instance"
},
"app.browse.add-servers-to-instance": {
"message": "Ajouter des serveurs a 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..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Supprimer l'instance"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Ce modpack est déjà installé dans linstance « {instanceName} »."
"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.admonition-header": {
"message": "Dupliquer le modpack"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Créer quand même"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Aller à linstance"
"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.copy-link": {
"message": "Copier le lien"
},
"app.instance.mods.installing": {
"message": "Installation..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "« {name} » a été ajouté"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Partagez le contenu de votre modpack"
},
"app.instance.mods.show-file": {
"message": "Montrer le fichier"
},
"app.instance.mods.successfully-uploaded": {
"message": "Mis en ligne avec succès"
},
"app.instance.mods.unknown-version": {
"message": "Inconnu"
"app.instance.worlds.add-server": {
"message": "Ajouter le serveur"
},
"app.instance.mods.updating": {
"message": "Mise à jour..."
"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"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Options dinstance par défaut"
},
"app.settings.tabs.feature-flags": {
"message": "Menu de fonctionnalité"
},
"app.settings.tabs.java-installations": {
"message": "Installations de Java"
},
@@ -197,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"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Modifier le monde"
},
"instance.files.adding-files": {
"message": "Ajout de fichiers ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Sauvegarder en tant que..."
},
"instance.server-modal.address": {
"message": "Adresse"
},
@@ -467,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"
},
@@ -494,12 +569,6 @@
"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"
},
+16 -28
View File
@@ -5,6 +5,9 @@
"app.auth-servers.unreachable.header": {
"message": "לא ניתן לגשת לשרתי האימות"
},
"app.browse.hide-installed-content": {
"message": "הסתר תוכן מותקן"
},
"app.export-modal.description-placeholder": {
"message": "הזן את תיאור חבילת המודים..."
},
@@ -41,18 +44,12 @@
"app.instance.confirm-delete.header": {
"message": "מחיקת התקנה"
},
"app.instance.modpack-already-installed.create": {
"message": "צור"
},
"app.instance.mods.content-type-project": {
"message": "פרויקט"
},
"app.instance.mods.copy-link": {
"message": "העתק קישור"
},
"app.instance.mods.installing": {
"message": "מתקין..."
},
"app.instance.mods.modpack-fallback": {
"message": "חבילת מודים"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" נוסף"
},
@@ -65,17 +62,17 @@
"app.instance.mods.share-title": {
"message": "משתף את התוכן של חבילת המודים"
},
"app.instance.mods.show-file": {
"message": "מצא קובץ"
},
"app.instance.mods.successfully-uploaded": {
"message": "הועלה בהצלחה"
},
"app.instance.mods.unknown-version": {
"message": "לא ידוע"
"app.instance.worlds.add-server": {
"message": "הוסף שרת"
},
"app.instance.mods.updating": {
"message": "מעדכן..."
"app.instance.worlds.delete-world-title": {
"message": "האם אתה בטוח שברצונך למחוק לצמיתות את העולם הזה?"
},
"app.instance.worlds.no-worlds-heading": {
"message": "אין שרתים אן עולמות שנוספו"
},
"app.modal.install-to-play.content-required": {
"message": "תוכן נדרש"
@@ -125,9 +122,6 @@
"app.settings.tabs.default-instance-options": {
"message": "אפשרויות ברירת מחדל של התקנה"
},
"app.settings.tabs.feature-flags": {
"message": "הגדרות ניסיוניות"
},
"app.settings.tabs.java-installations": {
"message": "התקנות ג'אווה"
},
@@ -281,6 +275,9 @@
"instance.edit-world.title": {
"message": "ערוך עולם"
},
"instance.files.save-as": {
"message": "שמור כ..."
},
"instance.server-modal.address": {
"message": "כתובת"
},
@@ -452,9 +449,6 @@
"instance.worlds.dont_show_on_home": {
"message": "אל תציג בדף הבית"
},
"instance.worlds.filter.available": {
"message": "זמין"
},
"instance.worlds.game_already_open": {
"message": "התקנה כבר פתוחה"
},
@@ -479,12 +473,6 @@
"instance.worlds.play_instance": {
"message": "שחק בהתקנה"
},
"instance.worlds.type.server": {
"message": "שרת"
},
"instance.worlds.type.singleplayer": {
"message": "שחקן יחיד"
},
"instance.worlds.view_instance": {
"message": "הצג התקנה"
},
+105 -42
View File
@@ -5,6 +5,39 @@
"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..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Profil törlése"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Ez a modcsomag már telepítve van a{instanceName} profilban."
"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.admonition-header": {
"message": "Modcsomag duplikálása"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Létrehozás mindenképpen"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Profil megnyitása"
"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.copy-link": {
"message": "Link másolása"
},
"app.instance.mods.installing": {
"message": "Telepítés..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modcsomag"
},
"app.instance.mods.project-was-added": {
"message": " „{name}” hozzá lett adva"
},
@@ -80,17 +101,47 @@
"app.instance.mods.share-title": {
"message": "Modcsomag-tartalmak megosztása"
},
"app.instance.mods.show-file": {
"message": "Fájl megjelenítése"
},
"app.instance.mods.successfully-uploaded": {
"message": "Sikeresen feltöltve"
},
"app.instance.mods.unknown-version": {
"message": "Ismeretlen"
"app.instance.worlds.add-server": {
"message": "Szerver hozzáadása"
},
"app.instance.mods.updating": {
"message": "Frissítés..."
"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-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"
@@ -102,7 +153,7 @@
"message": "Telepítés"
},
"app.modal.install-to-play.mod-count": {
"message": "{count, plural,one {# mod}other {# modok}}"
"message": "{count} mod"
},
"app.modal.install-to-play.required-modpack": {
"message": "Szükséges modcsomag"
@@ -140,9 +191,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"
},
@@ -197,6 +245,24 @@
"app.update.reload-to-update": {
"message": "A telepítéshez újraindítás szükséges"
},
"app.world.server-modal.placeholder-address": {
"message": "example.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"
},
@@ -296,6 +362,12 @@
"instance.edit-world.title": {
"message": "Világ szerkesztése"
},
"instance.files.adding-files": {
"message": "Fájlok hozzáadása ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Mentés másként..."
},
"instance.server-modal.address": {
"message": "Cím"
},
@@ -467,9 +539,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"
},
@@ -494,12 +563,6 @@
"instance.worlds.play_instance": {
"message": "Játék a profillal"
},
"instance.worlds.type.server": {
"message": "Szerver"
},
"instance.worlds.type.singleplayer": {
"message": "Egyjátékos"
},
"instance.worlds.view_instance": {
"message": "Profil megtekintése"
},
@@ -513,13 +576,13 @@
"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 biztosítja"
"message": "A szerver által van megadva"
},
"search.filter.locked.server-environment.title": {
"message": "Csak kliensoldali modok adhatók hozzá a szerverprofilhoz"
@@ -528,6 +591,6 @@
"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"
"message": "A betöltő a szerver által van megadva"
}
}
@@ -41,33 +41,12 @@
"app.instance.confirm-delete.header": {
"message": "Hapus instans"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Paket mod ini telah terpasang pada instans \"{instanceName}\"."
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Gandakan paket mod"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Tetap buat"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Pergi ke instans"
},
"app.instance.modpack-already-installed.header": {
"message": "Paket mod telah terpasang"
},
"app.instance.mods.content-type-project": {
"message": "proyek"
},
"app.instance.mods.copy-link": {
"message": "Salin tautan"
},
"app.instance.mods.installing": {
"message": "Memasang..."
},
"app.instance.mods.modpack-fallback": {
"message": "Paket Mod"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" telah ditambahkan"
},
@@ -80,18 +59,9 @@
"app.instance.mods.share-title": {
"message": "Membagi konten paket mod"
},
"app.instance.mods.show-file": {
"message": "Tampilkan berkas"
},
"app.instance.mods.successfully-uploaded": {
"message": "Berhasil diunggah"
},
"app.instance.mods.unknown-version": {
"message": "Tidak diketahui"
},
"app.instance.mods.updating": {
"message": "Memperbarui..."
},
"app.modal.install-to-play.content-required": {
"message": "Konten diperlukan"
},
@@ -140,9 +110,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Pilihan instans bawaan"
},
"app.settings.tabs.feature-flags": {
"message": "Bendera fitur"
},
"app.settings.tabs.java-installations": {
"message": "Pemasangan Java"
},
@@ -467,9 +434,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Jangan tampilkan di Beranda"
},
"instance.worlds.filter.available": {
"message": "Tersedia"
},
"instance.worlds.game_already_open": {
"message": "Instans telah dibuka"
},
@@ -494,12 +458,6 @@
"instance.worlds.play_instance": {
"message": "Mainkan instans"
},
"instance.worlds.type.server": {
"message": "Server"
},
"instance.worlds.type.singleplayer": {
"message": "Bermain sendiri"
},
"instance.worlds.view_instance": {
"message": "Lihat instans"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Impossibile raggiungere i server di autenticazione"
},
"app.browse.add-server-to-instance": {
"message": "Aggiungi server all'istanza"
},
"app.browse.add-servers-to-instance": {
"message": "Aggiungi server alla tua istanza"
},
"app.browse.add-to-instance": {
"message": "Aggiungi all'istanza"
},
"app.browse.add-to-instance-name": {
"message": "Aggiungi a {instanceName}"
},
"app.browse.added": {
"message": "Aggiunto"
},
"app.browse.already-added": {
"message": "Già aggiunto"
},
"app.browse.discover-content": {
"message": "Esplora contenuti"
},
"app.browse.discover-servers": {
"message": "Esplora i server"
},
"app.browse.hide-added-servers": {
"message": "Nascondi server aggiunti"
},
"app.browse.hide-installed-content": {
"message": "Nascondi contenuti installati"
},
"app.browse.install-content-to-instance": {
"message": "Installa nella istanza"
},
"app.export-modal.description-placeholder": {
"message": "Inserisci descrizione del pacchetto..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Elimina istanza"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Questo pacchetto è già stato installato nell'istanza \"{instanceName}\"."
"app.instance.modpack-already-installed.body": {
"message": "Questo pacchetto di mod è già installato nell'istanza <bold>{instanceName}</bold>. Vuoi davvero duplicarlo?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Pacchetto duplicato"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Crea comunque"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Vai all'istanza"
"app.instance.modpack-already-installed.create": {
"message": "Crea"
},
"app.instance.modpack-already-installed.header": {
"message": "Pacchetto già installato"
},
"app.instance.modpack-already-installed.instance": {
"message": "Istanza"
},
"app.instance.mods.content-type-project": {
"message": "progetto"
},
"app.instance.mods.copy-link": {
"message": "Copia link"
},
"app.instance.mods.installing": {
"message": "Installando..."
},
"app.instance.mods.modpack-fallback": {
"message": "Pacchetto di mod"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" è stato aggiunto"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Condivisione del pacchetto"
},
"app.instance.mods.show-file": {
"message": "Mostra file"
},
"app.instance.mods.successfully-uploaded": {
"message": "Caricato con successo"
},
"app.instance.mods.unknown-version": {
"message": "Sconosciuta"
"app.instance.worlds.add-server": {
"message": "Aggiungi server"
},
"app.instance.mods.updating": {
"message": "Aggiornando..."
"app.instance.worlds.browse-servers": {
"message": "Esplora i server"
},
"app.instance.worlds.delete-world-description": {
"message": "\"{name}\" verrà eliminato permanentemente e non ci sarà modo di recuperarlo."
},
"app.instance.worlds.delete-world-title": {
"message": "Vuoi davvero eliminare permanentemente questo mondo?"
},
"app.instance.worlds.filter-modded": {
"message": "Moddato"
},
"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": "Inizia esplorando o aggiungendo un server"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Nessun server o mondi aggiunti"
},
"app.instance.worlds.remove-server-description": {
"message": "\"{name}\" sarà rimosso dalla tua lista, inclusa quella in-gioco, e non ci sarà modo di recuperarlo."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "\"{name}\" ({address}) sarà rimosso dalla tua lista, inclusa quella in-gioco, e non ci sarà modo di recuperarlo."
},
"app.instance.worlds.remove-server-title": {
"message": "Vuoi davvero rimuovere {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Cerca tra {count} mondi..."
},
"app.instance.worlds.this-server": {
"message": "questo server"
},
"app.modal.install-to-play.content-required": {
"message": "Contenuto richiesto"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Opzioni d'istanza predefinite"
},
"app.settings.tabs.feature-flags": {
"message": "Flag di funzionalità"
},
"app.settings.tabs.java-installations": {
"message": "Installazioni Java"
},
@@ -197,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Ricarica per installare l'aggiornamento"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Seleziona un'opzione"
},
"app.world.world-item.incompatible-version": {
"message": "Versione {version} incompatibile"
},
"app.world.world-item.not-played-yet": {
"message": "Mai avviato"
},
"app.world.world-item.offline": {
"message": "Offline"
},
"app.world.world-item.players-online": {
"message": "{count} online"
},
"friends.action.add-friend": {
"message": "Stringi un'amicizia"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Modifica mondo"
},
"instance.files.adding-files": {
"message": "Aggiungendo i file ({completed}/{total})..."
},
"instance.files.save-as": {
"message": "Salva come..."
},
"instance.server-modal.address": {
"message": "Indirizzo"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Non mostrare nella home"
},
"instance.worlds.filter.available": {
"message": "Disponibile"
},
"instance.worlds.game_already_open": {
"message": "Istanza già aperta"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Avvia istanza"
},
"instance.worlds.type.server": {
"message": "Server"
},
"instance.worlds.type.singleplayer": {
"message": "Giocatore singolo"
},
"instance.worlds.view_instance": {
"message": "Mostra istanza"
},
+109 -40
View File
@@ -5,6 +5,39 @@
"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": "Modパックの説明を入力…"
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "インスタンスを削除"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "このModパックは「{instanceName}インスタンスにすでにインストールされています。"
"app.instance.modpack-already-installed.body": {
"message": "このModpackは既に <bold>{instanceName}</bold> インスタンスにインストール済みです。本当に複製しますか?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "重複したModパック"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "とにかく作成する"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "インスタンスに移動"
"app.instance.modpack-already-installed.create": {
"message": "新規作成"
},
"app.instance.modpack-already-installed.header": {
"message": "Modパックはすでにインストール済み"
},
"app.instance.modpack-already-installed.instance": {
"message": "インスタンス"
},
"app.instance.mods.content-type-project": {
"message": "プロジェクト"
},
"app.instance.mods.copy-link": {
"message": "リンクをコピー"
},
"app.instance.mods.installing": {
"message": "インストール中…"
},
"app.instance.mods.modpack-fallback": {
"message": "Modパック"
},
"app.instance.mods.project-was-added": {
"message": "「{name}」が追加されました"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Modパックのコンテンツを共有"
},
"app.instance.mods.show-file": {
"message": "ファイルを表示"
},
"app.instance.mods.successfully-uploaded": {
"message": "アップロードに成功しました"
},
"app.instance.mods.unknown-version": {
"message": "不明"
"app.instance.worlds.add-server": {
"message": "サーバーを追加"
},
"app.instance.mods.updating": {
"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": "Mod導入済み"
},
"app.instance.worlds.filter-offline": {
"message": "オフライン"
},
"app.instance.worlds.filter-online": {
"message": "オンライン"
},
"app.instance.worlds.filter-vanilla": {
"message": "バニラ(Mod非導入)"
},
"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": "必須コンテンツ"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "インスタンスの基本設定"
},
"app.settings.tabs.feature-flags": {
"message": "機能設定"
},
"app.settings.tabs.java-installations": {
"message": "Javaのインストール設定"
},
@@ -197,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": "フレンドを追加"
},
@@ -210,10 +282,10 @@
"message": "フレンドを追加中"
},
"friends.add-friend.username.description": {
"message": "これはMinecraftユーザーネームと違う可能性があります!"
"message": "これはMinecraftユーザー名とは異なる可能性があります!"
},
"friends.add-friend.username.placeholder": {
"message": "Modrinthユーザーネームを入力..."
"message": "Modrinthユーザー名を入力…"
},
"friends.add-friend.username.title": {
"message": "あなたのフレンドのModrinthユーザー名は何ですか?"
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "ワールドを編集"
},
"instance.files.adding-files": {
"message": "ファイルを追加中 ({completed}/{total})"
},
"instance.files.save-as": {
"message": "名前をつけて保存..."
},
"instance.server-modal.address": {
"message": "アドレス"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "ホームに表示しない"
},
"instance.worlds.filter.available": {
"message": "利用可能"
},
"instance.worlds.game_already_open": {
"message": "インスタンスは既に開いています"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "インスタンスを起動"
},
"instance.worlds.type.server": {
"message": "サーバー"
},
"instance.worlds.type.singleplayer": {
"message": "シングルプレイ"
},
"instance.worlds.view_instance": {
"message": "インスタンスを表示する"
},
+171 -18
View File
@@ -5,8 +5,149 @@
"app.auth-servers.unreachable.header": {
"message": "인증 서버에 연결할 수 없습니다"
},
"app.instance.mods.updating": {
"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": "콘텐츠 설치 필요"
@@ -56,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "기본 인스턴스 옵션"
},
"app.settings.tabs.feature-flags": {
"message": "기능 플래그"
},
"app.settings.tabs.java-installations": {
"message": "Java 설치"
},
@@ -78,7 +216,7 @@
"message": "Modrinth App v{version} 다운로드가 완료되었습니다. 새로고침하거나 Modrinth App을 종료하면 자동으로 업데이트됩니다."
},
"app.update-popup.body.linux": {
"message": "Modrinth App v{version} 버전을 사용할 수 있습니다. 최신 기능과 오류 수정을 적용하려면 패키지 관리자를 통해 업데이트하세요!"
"message": "Modrinth App v{version}을 사용할 수 있습니다. 최신 기능과 오류 수정을 적용하려면 패키지 관리자를 통해 업데이트하세요!"
},
"app.update-popup.body.metered": {
"message": "Modrinth App v{version}을 지금 사용할 수 있습니다! 데이터 통신 연결을 사용 중이므로, 자동으로 다운로드하지 않았습니다."
@@ -87,7 +225,7 @@
"message": "변경 내역"
},
"app.update-popup.download": {
"message": "({size}) 다운로드"
"message": "다운로드 ({size})"
},
"app.update-popup.download-complete": {
"message": "다운로드 완료"
@@ -113,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": "친구 추가"
},
@@ -165,7 +321,7 @@
"message": "대기 중"
},
"friends.no-friends-match": {
"message": "\"{query}\" 이름과 일치하는 친구 없음"
"message": "\"{query}\"과(와) 일치하는 친구 없음"
},
"friends.search-friends-placeholder": {
"message": "친구 검색 중..."
@@ -212,6 +368,12 @@
"instance.edit-world.title": {
"message": "세계 편집"
},
"instance.files.adding-files": {
"message": "파일 추가 중 ({completed}/{total})"
},
"instance.files.save-as": {
"message": "다른 이름으로 저장..."
},
"instance.server-modal.address": {
"message": "주소"
},
@@ -258,7 +420,7 @@
"message": "아이콘 제거"
},
"instance.settings.tabs.general.edit-icon.replace": {
"message": "아이콘 체"
"message": "아이콘 체"
},
"instance.settings.tabs.general.edit-icon.select": {
"message": "아이콘 선택"
@@ -383,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "홈에서 숨기기"
},
"instance.worlds.filter.available": {
"message": "이용 가능"
},
"instance.worlds.game_already_open": {
"message": "이미 실행된 인스턴스"
},
@@ -410,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "인스턴스 플레이"
},
"instance.worlds.type.server": {
"message": "서버"
},
"instance.worlds.type.singleplayer": {
"message": "싱글 플레이"
},
"instance.worlds.view_instance": {
"message": "인스턴스 보기"
},
+107 -32
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Tidak dapat mencapai pelayan pengesahan"
},
"app.browse.add-server-to-instance": {
"message": "Tambahkan pelayan ke dalam pemasangan"
},
"app.browse.add-servers-to-instance": {
"message": "Tambahkan pelayan ke dalam pemasangan anda"
},
"app.browse.add-to-instance": {
"message": "Tambahkan ke dalam pemasangan"
},
"app.browse.add-to-instance-name": {
"message": "Tambahkan ke {instanceName}"
},
"app.browse.added": {
"message": "Ditambah"
},
"app.browse.already-added": {
"message": "Sudah ditambah"
},
"app.browse.discover-content": {
"message": "Temui kandungan"
},
"app.browse.discover-servers": {
"message": "Temui pelayan"
},
"app.browse.hide-added-servers": {
"message": "Sembunyikan pelayan yang ditambah"
},
"app.browse.hide-installed-content": {
"message": "Sembunyikan kandungan yang dipasang"
},
"app.browse.install-content-to-instance": {
"message": "Pasang kandungan ke dalam pemasangan"
},
"app.export-modal.description-placeholder": {
"message": "Masukkan keterangan pek mod..."
},
@@ -41,27 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Padam pemasangan"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Pek mod ini sudah pun dipasang di dalam pemasangan \"{instanceName}\"."
"app.instance.modpack-already-installed.body": {
"message": "Pek mod ini telah dipasang dalam pemasangan <bold>{instanceName}</bold>. Adakah anda pasti mahu menduakannya?"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Pergi ke pemasangan"
"app.instance.modpack-already-installed.create": {
"message": "Cipta"
},
"app.instance.modpack-already-installed.header": {
"message": "Pek mod sudah dipasang"
},
"app.instance.modpack-already-installed.instance": {
"message": "Pemasangan"
},
"app.instance.mods.content-type-project": {
"message": "projek"
},
"app.instance.mods.copy-link": {
"message": "Salin pautan"
},
"app.instance.mods.installing": {
"message": "Sedang memasang..."
},
"app.instance.mods.modpack-fallback": {
"message": "Pek Mod"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" telah ditambahkan"
},
@@ -74,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Berkongsi kandungan pek mod"
},
"app.instance.mods.show-file": {
"message": "Tunjukkan fail"
},
"app.instance.mods.successfully-uploaded": {
"message": "Berjaya dimuat naik"
},
"app.instance.mods.unknown-version": {
"message": "Tidak Diketahui"
"app.instance.worlds.add-server": {
"message": "Tambah pelayan"
},
"app.instance.mods.updating": {
"message": "Sedang mengemas kini..."
"app.instance.worlds.browse-servers": {
"message": "Layari pelayan"
},
"app.instance.worlds.delete-world-description": {
"message": "'{name}' akan **dipadamkan secara kekal**, dan tiada cara untuk memulihkannya."
},
"app.instance.worlds.delete-world-title": {
"message": "Adakah anda pasti mahu memadamkan dunia ini secara kekal?"
},
"app.instance.worlds.filter-modded": {
"message": "Diubah Suai"
},
"app.instance.worlds.filter-offline": {
"message": "Luar Talian"
},
"app.instance.worlds.filter-online": {
"message": "Dalam Talian"
},
"app.instance.worlds.filter-vanilla": {
"message": "Vanila"
},
"app.instance.worlds.no-worlds-description": {
"message": "Tambah sebuah pelayan atau layari untuk bermula"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Tiada pelayan atau dunia ditambah"
},
"app.instance.worlds.remove-server-description": {
"message": "'{name}' akan dialih keluar daripada senarai anda, termasuk dalam permainan, dan tiada cara untuk memulihkannya."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "'{name}' ({address}) akan dialih keluar daripada senarai anda, termasuk dalam permainan, dan tiada cara untuk memulihkannya."
},
"app.instance.worlds.remove-server-title": {
"message": "Adakah anda pasti mahu mengalih keluar {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Cari {count} dunia..."
},
"app.instance.worlds.this-server": {
"message": "pelayan ini"
},
"app.modal.install-to-play.content-required": {
"message": "Kandungan yang diperlukan"
@@ -134,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Tetapan lalai pemasangan"
},
"app.settings.tabs.feature-flags": {
"message": "Penetapan ciri"
},
"app.settings.tabs.java-installations": {
"message": "Pemasangan Java"
},
@@ -191,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Muat semula untuk memasang kemas kini"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Pilih pilihan anda"
},
"app.world.world-item.incompatible-version": {
"message": "Versi tidak serasi: {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Belum dimainkan"
},
"app.world.world-item.offline": {
"message": "Luar Talian"
},
"app.world.world-item.players-online": {
"message": "{count} dalam talian"
},
"friends.action.add-friend": {
"message": "Tambah rakan"
},
@@ -290,6 +368,12 @@
"instance.edit-world.title": {
"message": "Sunting dunia"
},
"instance.files.adding-files": {
"message": "Sedang menambah fail ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Simpan sebagai..."
},
"instance.server-modal.address": {
"message": "Alamat"
},
@@ -461,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Jangan tunjukkan pada Laman Utama"
},
"instance.worlds.filter.available": {
"message": "Tersedia"
},
"instance.worlds.game_already_open": {
"message": "Pemasangan sudah pun dibuka"
},
@@ -488,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Mainkan pemasangan"
},
"instance.worlds.type.server": {
"message": "Pelayan"
},
"instance.worlds.type.singleplayer": {
"message": "Ekapemain"
},
"instance.worlds.view_instance": {
"message": "Lihat pemasangan"
},
@@ -41,33 +41,12 @@
"app.instance.confirm-delete.header": {
"message": "Verwijder instantie"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Deze modpack is al geïnstalleerd in de \"{instanceName}\" instantie."
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Dupliceer modpack"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Maak toch"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Ga naar instantie"
},
"app.instance.modpack-already-installed.header": {
"message": "Modpack is al geïnstalleerd"
},
"app.instance.mods.content-type-project": {
"message": "project"
},
"app.instance.mods.copy-link": {
"message": "Kopieer link"
},
"app.instance.mods.installing": {
"message": "Aan het installeren..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" was toegevoegd"
},
@@ -80,18 +59,9 @@
"app.instance.mods.share-title": {
"message": "Modpack-inhoud delen"
},
"app.instance.mods.show-file": {
"message": "Bestand weergeven"
},
"app.instance.mods.successfully-uploaded": {
"message": "Succesvol geüpload"
},
"app.instance.mods.unknown-version": {
"message": "Onbekend"
},
"app.instance.mods.updating": {
"message": "Aan het updaten..."
},
"app.modal.install-to-play.content-required": {
"message": "Content vereist"
},
@@ -140,9 +110,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Standaardopties voor instantie"
},
"app.settings.tabs.feature-flags": {
"message": "Feature flags"
},
"app.settings.tabs.java-installations": {
"message": "Java installaties"
},
@@ -467,9 +434,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Niet tonen op de startpagina"
},
"instance.worlds.filter.available": {
"message": "Beschikbaar"
},
"instance.worlds.game_already_open": {
"message": "Instantie is al open"
},
@@ -494,12 +458,6 @@
"instance.worlds.play_instance": {
"message": "Speel instantie"
},
"instance.worlds.type.server": {
"message": "Server"
},
"instance.worlds.type.singleplayer": {
"message": "Alleen spelen"
},
"instance.worlds.view_instance": {
"message": "Bekijk instantie"
},
@@ -41,9 +41,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Standard instansinstillinger"
},
"app.settings.tabs.feature-flags": {
"message": "Funksjonsflagg"
},
"app.settings.tabs.java-installations": {
"message": "Java installasjoner"
},
@@ -341,9 +338,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Ikke vis på Hjem"
},
"instance.worlds.filter.available": {
"message": "Tilgjengelig"
},
"instance.worlds.game_already_open": {
"message": "Instansen er allerede open"
},
@@ -365,12 +359,6 @@
"instance.worlds.play_instance": {
"message": "Spill instans"
},
"instance.worlds.type.server": {
"message": "Server"
},
"instance.worlds.type.singleplayer": {
"message": "Enkeltspillermodus"
},
"instance.worlds.view_instance": {
"message": "Vis instans"
},
+117 -33
View File
@@ -5,6 +5,42 @@
"app.auth-servers.unreachable.header": {
"message": "Nie udało się połączyć się z serwerami uwierzytelniania"
},
"app.browse.add-server-to-instance": {
"message": "Dodaj serwer do instancji"
},
"app.browse.add-servers-to-instance": {
"message": "Dodaj serwery do swojej instancji"
},
"app.browse.add-to-instance": {
"message": "Dodaj do instancji"
},
"app.browse.add-to-instance-name": {
"message": "Dodaj do {instanceName}"
},
"app.browse.added": {
"message": "Dodano"
},
"app.browse.already-added": {
"message": "Już dodano"
},
"app.browse.discover-content": {
"message": "Odkrywaj zawartość"
},
"app.browse.discover-servers": {
"message": "Odkryj serwery"
},
"app.browse.hide-added-servers": {
"message": "Ukryj dodane serwery"
},
"app.browse.hide-installed-content": {
"message": "Ukryj zainstalowane zasoby"
},
"app.browse.install-content-to-instance": {
"message": "Zainstaluj zasoby do instancji"
},
"app.export-modal.description-placeholder": {
"message": "Wprowadź opis paczki modów..."
},
"app.export-modal.export-button": {
"message": "Eksportuj"
},
@@ -38,45 +74,81 @@
"app.instance.confirm-delete.header": {
"message": "Usuń instancję"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Ta paczka modów jest już zainstalowana w instancji \"{instanceName}\"."
"app.instance.modpack-already-installed.body": {
"message": "Ta paczka modów jest już zainstalowana w instancji <bold>{instanceName}</bold>. Czy na pewno chcesz utworzyć duplikat?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Duplikat paczki modów"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Utwórz mimo to"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Przejdź do instancji"
"app.instance.modpack-already-installed.create": {
"message": "Utwórz"
},
"app.instance.modpack-already-installed.header": {
"message": "Paczka modów jest już zainstalowana"
},
"app.instance.modpack-already-installed.instance": {
"message": "Instalacja"
},
"app.instance.mods.content-type-project": {
"message": "projekt"
},
"app.instance.mods.copy-link": {
"message": "Kopiuj łącze"
},
"app.instance.mods.installing": {
"message": "Instalowanie..."
},
"app.instance.mods.modpack-fallback": {
"message": "Paczka modów"
},
"app.instance.mods.project-was-added": {
"message": "Dodano \"{name}\""
},
"app.instance.mods.projects-were-added": {
"message": "Dodano {count} {count, plural, one {projekt} few {projekty} other {projektów}}"
},
"app.instance.mods.show-file": {
"message": "Pokaż plik"
"app.instance.mods.share-text": {
"message": "Sprawdź projekty, które używam w mojej paczce modów!"
},
"app.instance.mods.share-title": {
"message": "Udostępnianie zawartości paczki modów"
},
"app.instance.mods.successfully-uploaded": {
"message": "Przesyłanie powiodło się"
},
"app.instance.worlds.add-server": {
"message": "Dodaj serwer"
},
"app.instance.worlds.browse-servers": {
"message": "Szukaj serwerów"
},
"app.instance.worlds.delete-world-description": {
"message": "'{name}' zostanie **permanentnie usunięty**, i nie ma możliwości go odzyskać."
},
"app.instance.worlds.delete-world-title": {
"message": "Czy na pewno chcesz trwale usunąć ten świat?"
},
"app.instance.worlds.filter-modded": {
"message": "Zmodowany"
},
"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": "Dodaj serwer lub szukaj, aby rozpocząć"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Nie dodano żadnych światów ani serwerów"
},
"app.instance.worlds.remove-server-description": {
"message": "'{name}' zostanie usunięty z twojej listy, również z gry, i nie będzie możliwości go odzyskać."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "'{name}' ({address}) zostanie usunięty z twojej listy, również z gry, i nie będzie możliwości go odzyskać."
},
"app.instance.worlds.remove-server-title": {
"message": "Czy jesteś pewny, że chcesz usunąć {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Szukaj wśród {count} światów..."
},
"app.instance.worlds.this-server": {
"message": "ten serwer"
},
"app.modal.install-to-play.content-required": {
"message": "Wymagane treści"
},
@@ -125,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Domyślne opcje instancji"
},
"app.settings.tabs.feature-flags": {
"message": "Flagi funkcji"
},
"app.settings.tabs.java-installations": {
"message": "Instalacje Java"
},
@@ -182,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Załaduj ponownie, aby zainstalować aktualizację"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Wybierz opcję"
},
"app.world.world-item.incompatible-version": {
"message": "Niekompatybilna wersja {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Jeszcze nie grano"
},
"app.world.world-item.offline": {
"message": "Offline"
},
"app.world.world-item.players-online": {
"message": "{count} online"
},
"friends.action.add-friend": {
"message": "Dodaj znajomego"
},
@@ -281,6 +368,12 @@
"instance.edit-world.title": {
"message": "Edytuj świat"
},
"instance.files.adding-files": {
"message": "Dodawanie plików ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Zapisz jako..."
},
"instance.server-modal.address": {
"message": "Adres"
},
@@ -452,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Nie pokazuj na stronie głównej"
},
"instance.worlds.filter.available": {
"message": "Dostępny"
},
"instance.worlds.game_already_open": {
"message": "Instancja jest już otwarta"
},
@@ -479,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Zagraj"
},
"instance.worlds.type.server": {
"message": "Serwer"
},
"instance.worlds.type.singleplayer": {
"message": "Tryb jednoosobowy"
},
"instance.worlds.view_instance": {
"message": "Zobacz instancję"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Não foi possível acessar os servidores de autenticação"
},
"app.browse.add-server-to-instance": {
"message": "Adicionar servidor à instância"
},
"app.browse.add-servers-to-instance": {
"message": "Adicionar servidores à sua instância"
},
"app.browse.add-to-instance": {
"message": "Adicionar à instância"
},
"app.browse.add-to-instance-name": {
"message": "Adicionar a {instanceName}"
},
"app.browse.added": {
"message": "Adicionado"
},
"app.browse.already-added": {
"message": "Já adicionado"
},
"app.browse.discover-content": {
"message": "Descubra conteúdo"
},
"app.browse.discover-servers": {
"message": "Descubra servidores"
},
"app.browse.hide-added-servers": {
"message": "Ocultar servidores adicionados"
},
"app.browse.hide-installed-content": {
"message": "Ocultar conteúdo instalado"
},
"app.browse.install-content-to-instance": {
"message": "Instalar conteúdo na instância"
},
"app.export-modal.description-placeholder": {
"message": "Insira a descrição do pacote de mods..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Excluir instância"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Este pacote de mods já está instalado na instância \"{instanceName}\"."
"app.instance.modpack-already-installed.body": {
"message": "Este pacote de mods já está instalado na instância <bold>{instanceName}</bold>. Tem certeza de que deseja duplicá-lo?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Pacote de mods duplicado"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Criar mesmo assim"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Ir para a instância"
"app.instance.modpack-already-installed.create": {
"message": "Criar"
},
"app.instance.modpack-already-installed.header": {
"message": "O pacote de mods já está instalado"
},
"app.instance.modpack-already-installed.instance": {
"message": "Instância"
},
"app.instance.mods.content-type-project": {
"message": "projeto"
},
"app.instance.mods.copy-link": {
"message": "Copiar link"
},
"app.instance.mods.installing": {
"message": "Instalando..."
},
"app.instance.mods.modpack-fallback": {
"message": "Pacote de mods"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" foi adicionado"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Compartilhando conteúdo do pacote de mods\n\n\n \t\t\t\t\t\t\n \t\t\t\t\t\t\t\n \t\t\t\t\t\t\n \t\t\t\t\t\t"
},
"app.instance.mods.show-file": {
"message": "Mostrar arquivo"
},
"app.instance.mods.successfully-uploaded": {
"message": "Enviado com sucesso"
},
"app.instance.mods.unknown-version": {
"message": "Desconhecido"
"app.instance.worlds.add-server": {
"message": "Adicionar servidor"
},
"app.instance.mods.updating": {
"message": "Atualizando..."
"app.instance.worlds.browse-servers": {
"message": "Explorar servidores"
},
"app.instance.worlds.delete-world-description": {
"message": "'{name}' será excluído permanentemente, e não haverá como recuperá-lo."
},
"app.instance.worlds.delete-world-title": {
"message": "Tem certeza de que deseja excluir este mundo permanentemente?"
},
"app.instance.worlds.filter-modded": {
"message": "Modificado"
},
"app.instance.worlds.filter-offline": {
"message": "Offline"
},
"app.instance.worlds.filter-online": {
"message": "Online"
},
"app.instance.worlds.filter-vanilla": {
"message": "Jogo padrão"
},
"app.instance.worlds.no-worlds-description": {
"message": "Adicione um servidor ou explore para começar"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Nenhum servidor ou mundo adicionado"
},
"app.instance.worlds.remove-server-description": {
"message": "'{name}' será removido da sua lista, inclusive no jogo, e não haverá como recuperá-lo."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "'{name}' ({address}) será removido da sua lista, inclusive no jogo, e não haverá como recuperá-lo."
},
"app.instance.worlds.remove-server-title": {
"message": "Tem certeza de que deseja remover {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Buscar {count} mundos..."
},
"app.instance.worlds.this-server": {
"message": "este servidor"
},
"app.modal.install-to-play.content-required": {
"message": "Conteúdo necessário"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Opções da instância"
},
"app.settings.tabs.feature-flags": {
"message": "Sinalização de recursos"
},
"app.settings.tabs.java-installations": {
"message": "Instalações do Java"
},
@@ -197,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Recarregue para instalar a atualização"
},
"app.world.server-modal.placeholder-address": {
"message": "exemplo.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Selecione uma opção"
},
"app.world.world-item.incompatible-version": {
"message": "Versão incompatível {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Ainda não jogado"
},
"app.world.world-item.offline": {
"message": "Offline"
},
"app.world.world-item.players-online": {
"message": "{count} online"
},
"friends.action.add-friend": {
"message": "Adicionar um amigo"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Editar mundo"
},
"instance.files.adding-files": {
"message": "Adicionando arquivos ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Salvar como..."
},
"instance.server-modal.address": {
"message": "Endereço"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Não mostrar na tela inicial"
},
"instance.worlds.filter.available": {
"message": "Disponível"
},
"instance.worlds.game_already_open": {
"message": "A instância já está aberta"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Jogar na instância"
},
"instance.worlds.type.server": {
"message": "Servidor"
},
"instance.worlds.type.singleplayer": {
"message": "Um jogador"
},
"instance.worlds.view_instance": {
"message": "Ver instância"
},
+222 -12
View File
@@ -5,6 +5,153 @@
"app.auth-servers.unreachable.header": {
"message": "Não foi possível alcançar os servidores de autenticação"
},
"app.browse.add-server-to-instance": {
"message": "Adicionar servidor à instância"
},
"app.browse.add-servers-to-instance": {
"message": "Adicionar servidores à tua instância"
},
"app.browse.add-to-instance": {
"message": "Adicionar à instância"
},
"app.browse.add-to-instance-name": {
"message": "Adicionar a {instanceName}"
},
"app.browse.added": {
"message": "Adicionado"
},
"app.browse.already-added": {
"message": "Já adicionado"
},
"app.browse.discover-content": {
"message": "Descobrir conteúdo"
},
"app.browse.discover-servers": {
"message": "Descobrir servidores"
},
"app.browse.hide-added-servers": {
"message": "Esconder servidores adicionados"
},
"app.browse.hide-installed-content": {
"message": "Esconder conteúdo instalado"
},
"app.browse.install-content-to-instance": {
"message": "Instalar conteúdo à instância"
},
"app.export-modal.description-placeholder": {
"message": "Insere a descrição do modpack..."
},
"app.export-modal.export-button": {
"message": "Exportar"
},
"app.export-modal.header": {
"message": "Exportar modpack"
},
"app.export-modal.modpack-name-label": {
"message": "Nome do Modpack"
},
"app.export-modal.modpack-name-placeholder": {
"message": "Nome do Modpack"
},
"app.export-modal.select-files-label": {
"message": "Seleciona as pastas e ficheiros a incluir no pack"
},
"app.export-modal.version-number-label": {
"message": "Número da versão"
},
"app.export-modal.version-number-placeholder": {
"message": "1.0.0"
},
"app.instance.confirm-delete.admonition-body": {
"message": "Todos os dados da tua instância vão ser permanentemente apagados, incluídos os teus mundos, definições, e todos os conteúdos instalados."
},
"app.instance.confirm-delete.admonition-header": {
"message": "Esta ação não pode ser desfeita"
},
"app.instance.confirm-delete.delete-button": {
"message": "Apagar instância"
},
"app.instance.confirm-delete.header": {
"message": "Apagar instância"
},
"app.instance.modpack-already-installed.body": {
"message": "Este modpack já está instalado na instância <bold>{instanceName}</bold>. Tens a certeza que o queres duplicar?"
},
"app.instance.modpack-already-installed.create": {
"message": "Criar"
},
"app.instance.modpack-already-installed.header": {
"message": "Modpack já instalado"
},
"app.instance.modpack-already-installed.instance": {
"message": "Instância"
},
"app.instance.mods.content-type-project": {
"message": "projeto"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" foi adicionado"
},
"app.instance.mods.projects-were-added": {
"message": "{count} projetos foram adicionados"
},
"app.instance.mods.share-text": {
"message": "Vê os projetos que estou a usar no meu modpack!"
},
"app.instance.mods.share-title": {
"message": "Partilhar conteúdo do modpack"
},
"app.instance.mods.successfully-uploaded": {
"message": "Carregado com sucesso"
},
"app.instance.worlds.add-server": {
"message": "Adicionar servidor"
},
"app.instance.worlds.browse-servers": {
"message": "Procurar servidores"
},
"app.instance.worlds.delete-world-description": {
"message": "\"{name}\" vai ser **apagado permanentemente**, e não haverá maneira de o recuperar."
},
"app.instance.worlds.delete-world-title": {
"message": "Tens a certeza que queres apagar permanentemente este mundo?"
},
"app.instance.worlds.filter-modded": {
"message": "Com Mods"
},
"app.instance.worlds.filter-offline": {
"message": "Offline"
},
"app.instance.worlds.filter-online": {
"message": "Online"
},
"app.instance.worlds.filter-vanilla": {
"message": "Sem mods"
},
"app.instance.worlds.no-worlds-description": {
"message": "Adiciona um servidor ou procura um para começar"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Sem servidores ou mundos adicionados"
},
"app.instance.worlds.remove-server-description": {
"message": "\"{name}\" vai ser removido da tua lista, incluindo dentro do jogo, e não haverá maneira de o recuperar."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "\"{name}\" ({address}) vai ser removido da tua lista, incluindo dentro do jogo, e não haverá maneira de o recuperar."
},
"app.instance.worlds.remove-server-title": {
"message": "Tens a certeza que queres remover {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Pesquisar {count} mundos..."
},
"app.instance.worlds.this-server": {
"message": "este servidor"
},
"app.modal.install-to-play.content-required": {
"message": "Conteúdo necessário"
},
"app.modal.install-to-play.header": {
"message": "Instala para jogar"
},
@@ -14,12 +161,21 @@
"app.modal.install-to-play.mod-count": {
"message": "{count, plural, one {mod} other {mods}}"
},
"app.modal.install-to-play.required-modpack": {
"message": "Modpack requerido"
},
"app.modal.install-to-play.server-requires-mods": {
"message": "Este servidor requer mods para jogares. Clica Instalar para transferir os ficheiros necessários do Modrinth, e então entrar diretamente no servidor."
},
"app.modal.install-to-play.shared-instance": {
"message": "Instância partilhada"
},
"app.modal.install-to-play.shared-server-instance": {
"message": "Instância de servidor partilhada"
},
"app.modal.install-to-play.view-contents": {
"message": "Ver conteúdo"
},
"app.modal.update-to-play.header": {
"message": "Atualiza para jogar"
},
@@ -41,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Opções padrão de instância"
},
"app.settings.tabs.feature-flags": {
"message": "Flags de funcionalidades"
},
"app.settings.tabs.java-installations": {
"message": "Instalações Java"
},
@@ -56,6 +209,33 @@
"app.settings.tabs.resource-management": {
"message": "Gestão de recursos"
},
"app.update-popup.body": {
"message": "Modrinth App v{version} está pronta para ser instalada! Recarrega para atualizar agora, ou automaticamente quando fechares a Modrinth App."
},
"app.update-popup.body.download-complete": {
"message": "Modrinth App v{version} acabou de ser transferida. Recarrega para atualizar agora, ou automaticamente quando fechares a Modrinth App."
},
"app.update-popup.body.linux": {
"message": "Modrinth App v{version} está disponível. Usa o teu gestor de pacotes para atualizar e receber as correções e recursos mais recentes!"
},
"app.update-popup.body.metered": {
"message": "Modrinth App v{version} está disponível! Como estás numa rede com tráfego limitado, não a transferimos automaticamente."
},
"app.update-popup.changelog": {
"message": "Lista de alterações"
},
"app.update-popup.download": {
"message": "Transferir ({size})"
},
"app.update-popup.download-complete": {
"message": "Transferência concluída"
},
"app.update-popup.reload": {
"message": "Recarregar"
},
"app.update-popup.title": {
"message": "Atualização disponível"
},
"app.update.complete-toast.text": {
"message": "Clica aqui para ver a lista de alterações."
},
@@ -71,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Recarrega para instalar a atualização"
},
"app.world.server-modal.placeholder-address": {
"message": "exemplo.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Seleciona uma opção"
},
"app.world.world-item.incompatible-version": {
"message": "Versão incompatível {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Ainda não jogado"
},
"app.world.world-item.offline": {
"message": "Offline"
},
"app.world.world-item.players-online": {
"message": "{count} online"
},
"friends.action.add-friend": {
"message": "Adicionar um amigo"
},
@@ -170,6 +368,12 @@
"instance.edit-world.title": {
"message": "Editar mundo"
},
"instance.files.adding-files": {
"message": "Adicionando ficheiros ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Guardar como..."
},
"instance.server-modal.address": {
"message": "Endereço"
},
@@ -341,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Não mostrar na página Inicial"
},
"instance.worlds.filter.available": {
"message": "Disponível"
},
"instance.worlds.game_already_open": {
"message": "Instância já está aberta"
},
@@ -353,6 +554,9 @@
"instance.worlds.incompatible_server": {
"message": "Servidor é incompatível"
},
"instance.worlds.linked_server": {
"message": "Gerido pelo projeto do servidor"
},
"instance.worlds.no_contact": {
"message": "Servidor não conseguiu ser contactado"
},
@@ -365,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Jogar instância"
},
"instance.worlds.type.server": {
"message": "Servidor"
},
"instance.worlds.type.singleplayer": {
"message": "Um jogador"
},
"instance.worlds.view_instance": {
"message": "Ver instância"
},
@@ -388,5 +586,17 @@
},
"search.filter.locked.instance.sync": {
"message": "Sincronizar com a instância"
},
"search.filter.locked.server": {
"message": "Fornecido pelo servidor"
},
"search.filter.locked.server-environment.title": {
"message": "Apenas mods no cliente podem ser adicionados à instância de servidor"
},
"search.filter.locked.server-game-version.title": {
"message": "Versão do jogo é fornecida pelo servidor"
},
"search.filter.locked.server-loader.title": {
"message": "Carregador é fornecido pelo servidor"
}
}
@@ -5,9 +5,6 @@
"app.auth-servers.unreachable.header": {
"message": "Nu se pot accesa serverele de autentificare"
},
"app.instance.mods.copy-link": {
"message": "Copiază linkul"
},
"app.modal.install-to-play.content-required": {
"message": "Conținut necesar"
},
@@ -56,9 +53,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Opțiuni implicite instanță"
},
"app.settings.tabs.feature-flags": {
"message": "Controale funcționalitate"
},
"app.settings.tabs.java-installations": {
"message": "Instalări Java"
},
@@ -383,9 +377,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Nu afișa în pagina principală"
},
"instance.worlds.filter.available": {
"message": "Disponibil"
},
"instance.worlds.game_already_open": {
"message": "Instanța este deja deschisă"
},
@@ -410,12 +401,6 @@
"instance.worlds.play_instance": {
"message": "Joacă pe instanța"
},
"instance.worlds.type.server": {
"message": "Server"
},
"instance.worlds.type.singleplayer": {
"message": "Un singur jucător"
},
"instance.worlds.view_instance": {
"message": "Afișează instanța"
},
+112 -43
View File
@@ -5,6 +5,39 @@
"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": "Введите описание сборки..."
},
@@ -12,7 +45,7 @@
"message": "Экспортировать"
},
"app.export-modal.header": {
"message": "Экспорт модпака"
"message": "Экспорт сборки модов"
},
"app.export-modal.modpack-name-label": {
"message": "Название сборки"
@@ -21,7 +54,7 @@
"message": "Название сборки"
},
"app.export-modal.select-files-label": {
"message": "Выберите элементы экспорта в модпак"
"message": "Выберите файлы или папки для включения в сборку"
},
"app.export-modal.version-number-label": {
"message": "Номер версии"
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Удаление сборки"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Этот модпак уже установлен в инстанции \"{instanceName}\"."
"app.instance.modpack-already-installed.body": {
"message": "Эта сборка модов уже установлена в сборку <bold>{instanceName}</bold>. Вы уверены, что хотите дублировать её?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Дублировать модпак"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Всё равно создать"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "К инстанции"
"app.instance.modpack-already-installed.create": {
"message": "Создать"
},
"app.instance.modpack-already-installed.header": {
"message": "Модпак уже установлен"
"message": "Сборка модов уже установлена"
},
"app.instance.modpack-already-installed.instance": {
"message": "Сборка"
},
"app.instance.mods.content-type-project": {
"message": "проект"
},
"app.instance.mods.copy-link": {
"message": "Копировать ссылку"
},
"app.instance.mods.installing": {
"message": "Установка..."
},
"app.instance.mods.modpack-fallback": {
"message": "Сборка"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" был добавлен"
},
@@ -75,22 +96,58 @@
"message": "Проектов добавлено: {count}"
},
"app.instance.mods.share-text": {
"message": "Посмотрите проекты, в моём модпаке!"
"message": "Посмотрите проекты, которые я использую в своей сборке модов!"
},
"app.instance.mods.share-title": {
"message": "Содержимое сборки"
},
"app.instance.mods.show-file": {
"message": "Показать в папке"
},
"app.instance.mods.successfully-uploaded": {
"message": "Успешно загружено"
},
"app.instance.mods.unknown-version": {
"message": "Неизвестно"
"app.instance.worlds.add-server": {
"message": "Добавить сервер"
},
"app.instance.mods.updating": {
"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, plural, one {# миру} other {# мирам}}..."
},
"app.instance.worlds.this-server": {
"message": "Этот сервер"
},
"app.modal.install-to-play.content-required": {
"message": "Требуется дополнительный контент"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Предустановки"
},
"app.settings.tabs.feature-flags": {
"message": "Флаги функций"
},
"app.settings.tabs.java-installations": {
"message": "Установки Java"
},
@@ -197,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": "Добавить в друзья"
},
@@ -258,7 +330,7 @@
"message": "{title} — {count}"
},
"friends.sign-in-to-add-friends": {
"message": "<link>Войдите в аккаунт Modrinth</link>, вы сможете добавлять друзей и видеть их статус!"
"message": "<link>Войдите в аккаунт Modrinth</link>, чтобы добавлять друзей и видеть, во что они играют!"
},
"instance.add-server.add-and-play": {
"message": "Добавить и играть"
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Настройка мира"
},
"instance.files.adding-files": {
"message": "Добавление файлов ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Сохранить как..."
},
"instance.server-modal.address": {
"message": "Адрес"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Не показывать на главной"
},
"instance.worlds.filter.available": {
"message": "Доступно"
},
"instance.worlds.game_already_open": {
"message": "Сборка уже запущена"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Запустить сборку"
},
"instance.worlds.type.server": {
"message": "Сервер"
},
"instance.worlds.type.singleplayer": {
"message": "Одиночная игра"
},
"instance.worlds.view_instance": {
"message": "Посмотреть сборку"
},
@@ -8,24 +8,9 @@
"app.export-modal.version-number-placeholder": {
"message": "1.0.0"
},
"app.instance.mods.copy-link": {
"message": "Kopiraj link"
},
"app.instance.mods.installing": {
"message": "Instaliranje..."
},
"app.instance.mods.show-file": {
"message": "Prikaži datoteku"
},
"app.instance.mods.successfully-uploaded": {
"message": "Uspešno otpremljeno"
},
"app.instance.mods.unknown-version": {
"message": "Nepoznato"
},
"app.instance.mods.updating": {
"message": "Ažuriranje..."
},
"app.settings.tabs.appearance": {
"message": "Izgled"
},
+111 -30
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Kan ej nå autentiseringsservrarna"
},
"app.browse.add-server-to-instance": {
"message": "Lägg till server till instans"
},
"app.browse.add-servers-to-instance": {
"message": "Lägg till servrar till din instans"
},
"app.browse.add-to-instance": {
"message": "Lägg till i instans"
},
"app.browse.add-to-instance-name": {
"message": "Lägg till i {instanceName}"
},
"app.browse.added": {
"message": "Tillagd"
},
"app.browse.already-added": {
"message": "Redan tillagd"
},
"app.browse.discover-content": {
"message": "Upptäck innehåll"
},
"app.browse.discover-servers": {
"message": "Upptäck servrar"
},
"app.browse.hide-added-servers": {
"message": "Dölj tillagda servrar"
},
"app.browse.hide-installed-content": {
"message": "Dölj installerat innehåll"
},
"app.browse.install-content-to-instance": {
"message": "Installera innehåll till instans"
},
"app.export-modal.description-placeholder": {
"message": "Ange modpaketets beskrivning..."
},
@@ -41,21 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Radera instans"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Skapa ändå"
"app.instance.modpack-already-installed.body": {
"message": "Detta modpaket är redan installerat i instansen <bold>{instanceName}</bold>. Är du säker på att du vill duplicera det?"
},
"app.instance.modpack-already-installed.create": {
"message": "Skapa"
},
"app.instance.modpack-already-installed.header": {
"message": "Modpaket redan installerat"
},
"app.instance.modpack-already-installed.instance": {
"message": "Instans"
},
"app.instance.mods.content-type-project": {
"message": "projekt"
},
"app.instance.mods.copy-link": {
"message": "Kopiera länk"
},
"app.instance.mods.installing": {
"message": "Installerar..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpaket"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" lades till"
},
@@ -68,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Delar innehåll från modpaket"
},
"app.instance.mods.show-file": {
"message": "Visa fil"
},
"app.instance.mods.successfully-uploaded": {
"message": "Uppladdning lyckades"
},
"app.instance.mods.unknown-version": {
"message": "Okänt"
"app.instance.worlds.add-server": {
"message": "Lägg till server"
},
"app.instance.mods.updating": {
"message": "Uppdaterar..."
"app.instance.worlds.browse-servers": {
"message": "Utforska servrar"
},
"app.instance.worlds.delete-world-description": {
"message": "'{name}' kommer bli **permanent borttagen**, och det kommer inte finnas något sätt att återskapa den."
},
"app.instance.worlds.delete-world-title": {
"message": "Är du säker på att du vill permanent radera denna värld?"
},
"app.instance.worlds.filter-modded": {
"message": "Moddade"
},
"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": "Lägg till en server eller utforska för att komma igång"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Inga servrar eller världar tillagda"
},
"app.instance.worlds.remove-server-description": {
"message": "'{name}' kommer bli borttagen från din lista, inklusive i spelet, och det kommer inte finnas något sätt att återskapa den."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "'{name}' ({address}) kommer bli borttagen från din lista, inklusive i spelet, och det kommer inte finnas något sätt att återskapa den."
},
"app.instance.worlds.remove-server-title": {
"message": "Är du säker på att du vill radera {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Sök {count} världar..."
},
"app.instance.worlds.this-server": {
"message": "denna server"
},
"app.modal.install-to-play.content-required": {
"message": "Innehåll krävs"
@@ -128,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Standardinställningar för instanser"
},
"app.settings.tabs.feature-flags": {
"message": "Funktionsflaggor"
},
"app.settings.tabs.java-installations": {
"message": "Java-installationer"
},
@@ -185,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Ladda om för att installera uppdatering"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Välj ett alternativ"
},
"app.world.world-item.incompatible-version": {
"message": "Inkompatibel version {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Inte spelad än"
},
"app.world.world-item.offline": {
"message": "Offline"
},
"app.world.world-item.players-online": {
"message": "{count} online"
},
"friends.action.add-friend": {
"message": "Lägg till en vän"
},
@@ -284,6 +368,12 @@
"instance.edit-world.title": {
"message": "Redigera värld"
},
"instance.files.adding-files": {
"message": "Lägger till filer ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Spara som..."
},
"instance.server-modal.address": {
"message": "Adress"
},
@@ -455,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Visa inte på Startsidan"
},
"instance.worlds.filter.available": {
"message": "Tillgängliga"
},
"instance.worlds.game_already_open": {
"message": "Instans är redan öppen"
},
@@ -482,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Spela instans"
},
"instance.worlds.type.server": {
"message": "Server"
},
"instance.worlds.type.singleplayer": {
"message": "Enspelarläge"
},
"instance.worlds.view_instance": {
"message": "Visa instans"
},
+262 -7
View File
@@ -1,34 +1,142 @@
{
"app.auth-servers.unreachable.body": {
"message": "เซิร์ฟเวอร์ตรวจสอบสิทธิ์ของ Minecraft อาจใช้งานไม่ได้ในขณะนี้ โปรดตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณและลองใหม่อีกครั้งในภายหลัง"
},
"app.browse.add-server-to-instance": {
"message": "เพิ่มเซิร์ฟเวอร์ลงในอินสแตนซ์"
},
"app.browse.added": {
"message": "เพิ่ม"
},
"app.export-modal.description-placeholder": {
"message": "กรอกคำอธิบายมอดแพ็ก.."
},
"app.export-modal.modpack-name-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.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.successfully-uploaded": {
"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": "ติดตั้งเพื่อเล่น"
},
"app.modal.install-to-play.install-button": {
"message": "ติดตั้ง"
},
"app.modal.install-to-play.required-modpack": {
"message": "มอดแพ็กที่จำเป็น"
},
"app.modal.install-to-play.server-requires-mods": {
"message": "เซิร์ฟเวอร์นี้จำเป็นต้องใช้มอดเพื่อเข้าเล่น คลิกติดตั้ง เพื่อตั้งค่าไฟล์ที่จำเป็นจาก Modrinth จากนั้นจึงจะเข้าสู่เซิร์ฟเวอร์โดยตรงได้"
},
"app.modal.install-to-play.shared-instance": {
"message": "อินสแตนซ์ที่ใช้ร่วมกัน"
},
"app.modal.install-to-play.shared-server-instance": {
"message": "อินสแตนซ์เซิร์ฟเวอร์ที่ใช้ร่วมกัน"
},
"app.modal.update-to-play.header": {
"message": "อัปเดตเพื่อเล่น"
},
"app.modal.update-to-play.update-required": {
"message": "ต้องมีการอัปเดต"
"message": "จำเป็นต้องอัปเดต"
},
"app.modal.update-to-play.update-required-description": {
"message": "ต้องอัปเดตอย่างหนึ่งเพื่อเล่น {name}. โปรดอัปเดตให้เป็นเวอร์ชันล่าสุดเพื่อเปิดเกม"
"message": "จำเป็นต้องอัปเดตเพื่อเล่น {name} กรุณาอัปเดตเป็นเวอร์ชันล่าสุดเพื่อเปิดเกม"
},
"app.settings.developer-mode-enabled": {
"message": "กำลังอยู่ในโหมดผู้พัฒนา"
"message": "โหมดนักพัฒนาเปิดอยู่"
},
"app.settings.downloading": {
"message": "ดาวน์โหลด เวอร์ชั่น{version}"
},
"app.settings.tabs.appearance": {
"message": "รูปลักษณ์"
"message": "หน้าตา"
},
"app.settings.tabs.default-instance-options": {
"message": "ตัวเลือกอินสแตนซ์เริ่มต้น"
},
"app.settings.tabs.feature-flags": {
"message": "ระบบควบคุมการเปิดใช้งานฟีเจอร์"
},
"app.settings.tabs.java-installations": {
"message": "การจัดการ Java ที่ติดตั้ง"
},
@@ -41,6 +149,15 @@
"app.settings.tabs.resource-management": {
"message": "การจัดการทรัพยากร"
},
"app.update-popup.body.linux": {
"message": "Modrinth App v{version} พร้อมให้อัปเดตแล้ว โปรดใช้ตัวจัดการแพ็กเกจ ของคุณเพื่ออัปเดตฟีเจอร์ใหม่และตัวแก้ไขล่าสุด!"
},
"app.update-popup.download-complete": {
"message": "ดาวน์โหลดเสร็จสมบูรณ์"
},
"app.update-popup.title": {
"message": "มีการอัปเดตใหม่"
},
"app.update.complete-toast.text": {
"message": "คลิกที่นี่เพื่อดูบันทึกการเปลี่ยนแปลง"
},
@@ -56,6 +173,18 @@
"app.update.reload-to-update": {
"message": "รีโหลดเพื่อติดตั้งอัพเดต"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.world-item.incompatible-version": {
"message": "เวอร์ชัน {version} ไม่รองรับ"
},
"app.world.world-item.offline": {
"message": "ออฟไลน์"
},
"app.world.world-item.players-online": {
"message": "{count} ออนไลน์"
},
"friends.action.add-friend": {
"message": "เพิ่มเพื่อน"
},
@@ -101,6 +230,9 @@
"friends.heading.online": {
"message": "ออฟไลน์"
},
"friends.heading.pending": {
"message": "กําลังดำเนินการ"
},
"friends.no-friends-match": {
"message": "ไม่มีเพื่อนชื่อว่า \"{query}\""
},
@@ -149,6 +281,12 @@
"instance.edit-world.title": {
"message": "แก้ไขโลก"
},
"instance.files.adding-files": {
"message": "กำลังเพิ่มไฟล์ ({completed}/{total})"
},
"instance.files.save-as": {
"message": "บันทึกเป็น..."
},
"instance.server-modal.address": {
"message": "ที่อยู่เซิร์ฟเวอร์"
},
@@ -215,13 +353,130 @@
"instance.settings.tabs.general.name": {
"message": "ชื่อ"
},
"instance.settings.tabs.hooks": {
"message": "ตัวดักการปล่อย"
},
"instance.settings.tabs.hooks.custom-hooks": {
"message": "กำหนดเอง"
},
"instance.settings.tabs.hooks.description": {
"message": "ตัวดักจับช่วยให้ผู้ใช้ระดับสูงสามารถรันคำสั่งระบบบางอย่างได้ ทั้งก่อนและหลังการเปิดเกม"
},
"instance.settings.tabs.hooks.post-exit.enter": {
"message": "ป้อนคำสั่งหลังจบการทำงาน..."
},
"instance.settings.tabs.hooks.pre-launch": {
"message": "ก่อนรัน"
},
"instance.settings.tabs.hooks.title": {
"message": "ฮุกการเปิดเกม"
},
"instance.settings.tabs.hooks.wrapper": {
"message": "ตัวห่อหุ้ม"
},
"instance.settings.tabs.hooks.wrapper.description": {
"message": "คำสั่งตัวห่อหุ้มสำหรับเปิด ไมน์คราฟต์"
},
"instance.settings.tabs.hooks.wrapper.enter": {
"message": "ป้อนตัวห่อหุ้มคำสั่ง..."
},
"instance.settings.tabs.installation": {
"message": "การติดตั้ง"
},
"instance.settings.tabs.installation.loader-version": {
"message": "เวอร์ชั่น {loader}"
},
"instance.settings.tabs.java": {
"message": "Java และ หน่วยความจำ"
},
"instance.settings.tabs.java.hooks": {
"message": "ฮุก"
},
"instance.settings.tabs.java.java-arguments": {
"message": "อาร์กิวเมนต์ Java"
},
"instance.settings.tabs.java.java-installation": {
"message": "การติดตั้ง Java"
},
"instance.settings.tabs.java.java-memory": {
"message": "หน่วยความจำที่จัดสรร"
},
"instance.settings.tabs.window": {
"message": "หน้าต่าง"
},
"instance.settings.tabs.window.fullscreen": {
"message": "เต็มหน้าจอ"
},
"instance.settings.tabs.window.fullscreen.description": {
"message": "ทำให้เกมเปิดในโหมดเต็มหน้าจอเมื่อเริ่มเกม (โดยใช้ไฟล์ options.txt)"
},
"instance.settings.tabs.window.height": {
"message": "ความสูง"
},
"instance.settings.tabs.window.height.description": {
"message": "ความสูงของหน้าต่างเมื่อรันเกม"
},
"instance.settings.tabs.window.height.enter": {
"message": "ป้อนความสูง..."
},
"instance.settings.tabs.window.width": {
"message": "ความกว้าง"
},
"instance.settings.tabs.window.width.description": {
"message": "ความกว้างของหน้าต่างเมื่อรันเกม"
},
"instance.settings.tabs.window.width.enter": {
"message": "ป้อนความกว้าง..."
},
"instance.worlds.a_minecraft_server": {
"message": "เซิร์ฟเวอร์ ไมน์คราฟต์"
},
"instance.worlds.cant_connect": {
"message": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้"
},
"instance.worlds.copy_address": {
"message": "คัดลอกที่อยู่"
},
"instance.worlds.dont_show_on_home": {
"message": "ไม่ต้องแสดงในหน้าแรก"
},
"instance.worlds.game_already_open": {
"message": "อินสแตนซ์ถูกเปิดอยู่แล้ว"
},
"instance.worlds.hardcore": {
"message": "โหมดฮาร์ดคอร์"
},
"instance.worlds.incompatible_server": {
"message": "เซิร์ฟเวอร์ไม่รองรับ"
},
"instance.worlds.linked_server": {
"message": "จัดการโดยโปรเจกต์เซิร์ฟเวอร์"
},
"instance.worlds.no_contact": {
"message": "ไม่สามารถติดต่อเซิร์ฟเวอร์ได้"
},
"instance.worlds.no_server_quick_play": {
"message": "คุณสามารถเข้าสู่เซิร์ฟเวอร์ได้โดยตรงบน Minecraft Alpha 1.0.5 ขึ้นไปเท่านั้น"
},
"instance.worlds.no_singleplayer_quick_play": {
"message": "คุณสามารถเข้าสู่โลกผู้เล่นคนเดียวได้โดยตรงบน Minecraft 1.20 ขึ้นไปเท่านั้น"
},
"instance.worlds.play_instance": {
"message": "เริ่มเล่นอินสแตนซ์"
},
"instance.worlds.view_instance": {
"message": "ดูอินสแตนซ์"
},
"instance.worlds.world_in_use": {
"message": "โลกนี้กำลังถูกใช้งานอยู่"
},
"search.filter.locked.instance": {
"message": "อินสแตนซ์เป็นผู้จัดเตรียม"
},
"search.filter.locked.server": {
"message": "เซิร์ฟเวอร์เป็นผู้จัดเตรียม"
},
"search.filter.locked.server-game-version.title": {
"message": "เซิร์ฟเวอร์เป็นผู้จัดเตรียมเวอร์ชันเกม"
}
}
+122 -29
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Doğrulama sunucularına erişilemedi"
},
"app.browse.add-server-to-instance": {
"message": "Sunucuya içerik ekle"
},
"app.browse.add-servers-to-instance": {
"message": "İçeriğe sunucu ekle"
},
"app.browse.add-to-instance": {
"message": "İçerik ekle"
},
"app.browse.add-to-instance-name": {
"message": "{instanceName} içeriğine ekle"
},
"app.browse.added": {
"message": "Eklendi"
},
"app.browse.already-added": {
"message": "Zaten eklendi"
},
"app.browse.discover-content": {
"message": "İçerikleri keşfet"
},
"app.browse.discover-servers": {
"message": "Sunucuları keşfet"
},
"app.browse.hide-added-servers": {
"message": "Eklenen sunucuları gizle\n"
},
"app.browse.hide-installed-content": {
"message": "Yüklü İçerikleri Gizle"
},
"app.browse.install-content-to-instance": {
"message": "İçeriği profile yükle"
},
"app.export-modal.description-placeholder": {
"message": "Mod paketi açıklaması yazın..."
},
@@ -20,33 +53,42 @@
"app.export-modal.modpack-name-placeholder": {
"message": "Modpaketi adı"
},
"app.export-modal.select-files-label": {
"message": "Pakete dahil edilecek dosya ve klasörleri seçin"
},
"app.export-modal.version-number-label": {
"message": "Sürüm numarası"
},
"app.export-modal.version-number-placeholder": {
"message": "1.0.0"
},
"app.instance.confirm-delete.admonition-body": {
"message": "Dünyalarınız, yapılandırmalarınız ve yüklü tüm içerikler ve tüm veriler kalıcı olarak silinecek."
},
"app.instance.confirm-delete.admonition-header": {
"message": "Bu eylem geri alınamaz"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Yinede oluştur"
"app.instance.confirm-delete.delete-button": {
"message": "İçeriği Sil"
},
"app.instance.confirm-delete.header": {
"message": "İçeriği Sil"
},
"app.instance.modpack-already-installed.body": {
"message": "Bu mod paketi zaten <bold>{instanceName}</bold> örneğinde yüklü. Kopyalamak istediğinizden emin misiniz?"
},
"app.instance.modpack-already-installed.create": {
"message": "Oluştur"
},
"app.instance.modpack-already-installed.header": {
"message": "Modpaketi zaten kurulu"
},
"app.instance.modpack-already-installed.instance": {
"message": "İçerik"
},
"app.instance.mods.content-type-project": {
"message": "proje"
},
"app.instance.mods.copy-link": {
"message": "Bağlantıyı kopyala"
},
"app.instance.mods.installing": {
"message": "Kuruluyor..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpaketi"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" eklendi"
},
@@ -56,17 +98,56 @@
"app.instance.mods.share-text": {
"message": "Modpaketimde kullandığım projelere göz at!"
},
"app.instance.mods.show-file": {
"message": "Dosya göster"
"app.instance.mods.share-title": {
"message": "Mod paketi içeriğini paylaşıyorsunuz"
},
"app.instance.mods.successfully-uploaded": {
"message": "Başarı ile yüklendi"
},
"app.instance.mods.unknown-version": {
"message": "Bilinmeyen"
"app.instance.worlds.add-server": {
"message": "Sunucu Ekle"
},
"app.instance.mods.updating": {
"message": "Güncelleniyor..."
"app.instance.worlds.browse-servers": {
"message": "Sunucuya göz at"
},
"app.instance.worlds.delete-world-description": {
"message": "'{name}' kalıcı olarak silinecek ve geri getirilmesi mümkün olmayacaktır."
},
"app.instance.worlds.delete-world-title": {
"message": "Bu dünyayı kalıcı olarak silmek istediğinizden emin misiniz?"
},
"app.instance.worlds.filter-modded": {
"message": "Modlu"
},
"app.instance.worlds.filter-offline": {
"message": "Çevrimdışı"
},
"app.instance.worlds.filter-online": {
"message": "Çevrimiçi"
},
"app.instance.worlds.filter-vanilla": {
"message": "Vanilla"
},
"app.instance.worlds.no-worlds-description": {
"message": "Başlamak için bir sunucu ekleyin veya göz atın"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Eklenmiş sunucu veya dünya yok"
},
"app.instance.worlds.remove-server-description": {
"message": "'{name}' oyun içi dahil olmak üzere listenizden kaldırılacak ve geri getirilmesi mümkün olmayacaktır."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "'{name}' ({address}) oyun içi dahil olmak üzere listenizden kaldırılacak ve geri getirilmesi mümkün olmayacaktır."
},
"app.instance.worlds.remove-server-title": {
"message": "{name} öğesini kaldırmak istediğinizden emin misiniz?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "{count} dünya ara..."
},
"app.instance.worlds.this-server": {
"message": "bu sunucu"
},
"app.modal.install-to-play.content-required": {
"message": "İçerik gerekli"
@@ -116,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Varsayılan profil seçenekleri"
},
"app.settings.tabs.feature-flags": {
"message": "Özellik bayrakları"
},
"app.settings.tabs.java-installations": {
"message": "Java kurulumları"
},
@@ -173,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Güncellemeyi kurmak için yeniden yükleyin"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Bir seçenek seçin"
},
"app.world.world-item.incompatible-version": {
"message": "Uyumsuz sürüm {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Henüz oynanmadı"
},
"app.world.world-item.offline": {
"message": "Çevrimdışı"
},
"app.world.world-item.players-online": {
"message": "{count} çevrimiçi"
},
"friends.action.add-friend": {
"message": "Bir arkadaş ekle"
},
@@ -272,6 +368,12 @@
"instance.edit-world.title": {
"message": "Dünyayı düzenle"
},
"instance.files.adding-files": {
"message": "Dosyalar ekleniyor ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Farklı kaydet..."
},
"instance.server-modal.address": {
"message": "Adres"
},
@@ -443,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Ana sayfada gösterme"
},
"instance.worlds.filter.available": {
"message": "Kullanılabilir"
},
"instance.worlds.game_already_open": {
"message": "Bu kurulum zaten açık"
},
@@ -470,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Kurulumu oyna"
},
"instance.worlds.type.server": {
"message": "Sunucu"
},
"instance.worlds.type.singleplayer": {
"message": "Tek Oyunculu"
},
"instance.worlds.view_instance": {
"message": "Kurulumu gör"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"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": "Уведіть опис збірки…"
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Видалити профіль"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": ю збірку вже встановлено в профілі «{instanceName}»."
"app.instance.modpack-already-installed.body": {
"message": я збірка вже встановлена в профілі <bold>«{instanceName}»</bold>. Ви впевнені, що хочете її скопіювати?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Дублікат збірки"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Все одно створити"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Перейти до профілю"
"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.copy-link": {
"message": "Копіювати посилання"
},
"app.instance.mods.installing": {
"message": "Установлення…"
},
"app.instance.mods.modpack-fallback": {
"message": "Збірка"
},
"app.instance.mods.project-was-added": {
"message": "«{name}» було додано"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Поширення вмісту збірки"
},
"app.instance.mods.show-file": {
"message": "Показати файл"
},
"app.instance.mods.successfully-uploaded": {
"message": "Успішно вивантажено"
},
"app.instance.mods.unknown-version": {
"message": "Невідомо"
"app.instance.worlds.add-server": {
"message": "Додати сервер"
},
"app.instance.mods.updating": {
"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": "Потрібний уміст"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Усталені налашт. профілю"
},
"app.settings.tabs.feature-flags": {
"message": "Спеціальні функції"
},
"app.settings.tabs.java-installations": {
"message": "Інсталяції Java"
},
@@ -197,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": "Додати друга"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Редагувати світ"
},
"instance.files.adding-files": {
"message": "Додавання файлів ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Зберегти як…"
},
"instance.server-modal.address": {
"message": "Адреса"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Не показувати на головній"
},
"instance.worlds.filter.available": {
"message": "Доступно"
},
"instance.worlds.game_already_open": {
"message": "Профіль вже запущений"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Грати у профіль"
},
"instance.worlds.type.server": {
"message": "Сервер"
},
"instance.worlds.type.singleplayer": {
"message": "Гра наодинці"
},
"instance.worlds.view_instance": {
"message": "Переглянути профіль"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"app.auth-servers.unreachable.header": {
"message": "Không thể kết nối đến máy chủ xác thực"
},
"app.browse.add-server-to-instance": {
"message": "Thêm máy chủ vào hồ sơ"
},
"app.browse.add-servers-to-instance": {
"message": "Thêm máy chủ vào hồ sơ của bạn"
},
"app.browse.add-to-instance": {
"message": "Thêm vào hồ sơ"
},
"app.browse.add-to-instance-name": {
"message": "Thêm vào {instanceName}"
},
"app.browse.added": {
"message": "Đã thêm"
},
"app.browse.already-added": {
"message": "Đã được thêm"
},
"app.browse.discover-content": {
"message": "Khám phá nội dung"
},
"app.browse.discover-servers": {
"message": "Khám phá máy chủ"
},
"app.browse.hide-added-servers": {
"message": "Ẩn các máy chủ đã thêm"
},
"app.browse.hide-installed-content": {
"message": "Ẩn các nội dung đã được tải xuống"
},
"app.browse.install-content-to-instance": {
"message": "Tải nội dung này vào hồ sơ"
},
"app.export-modal.description-placeholder": {
"message": "Thêm miêu tả cho gói modpack..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "Xoá hồ sơ"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "Modpack này đã được cài đặt trong phiên chơi \"{instanceName}\"."
"app.instance.modpack-already-installed.body": {
"message": "Gói modpack này đã được cài đặt trong hồ sơ <bold>{instanceName}</bold> rồi. Bạn có chắc chắn muốn sao chép nó không?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "Nhân bản modpack"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "Vẫn tiếp tục tạo"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "Đi đến phiên chơi"
"app.instance.modpack-already-installed.create": {
"message": "Khởi tạo"
},
"app.instance.modpack-already-installed.header": {
"message": "Modpack đã được cài đặt"
},
"app.instance.modpack-already-installed.instance": {
"message": "Hồ sơ"
},
"app.instance.mods.content-type-project": {
"message": "Dự án"
},
"app.instance.mods.copy-link": {
"message": "Sao chép liên kết"
},
"app.instance.mods.installing": {
"message": "Đang tải xuống..."
},
"app.instance.mods.modpack-fallback": {
"message": "Modpack"
},
"app.instance.mods.project-was-added": {
"message": "\"{name}\" đã được thêm"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "Chia sẻ hồ sơ modpack"
},
"app.instance.mods.show-file": {
"message": "Hiện tệp"
},
"app.instance.mods.successfully-uploaded": {
"message": "Tải lên thành công"
},
"app.instance.mods.unknown-version": {
"message": "Không rõ"
"app.instance.worlds.add-server": {
"message": "Thêm máy chủ"
},
"app.instance.mods.updating": {
"message": "Đang cập nhật..."
"app.instance.worlds.browse-servers": {
"message": "Tìm kiếm máy chủ"
},
"app.instance.worlds.delete-world-description": {
"message": "'{name}' sẽ bị **xóa vĩnh viễn** và không có cách nào khôi phục lại."
},
"app.instance.worlds.delete-world-title": {
"message": "Bạn có chắc cắn rằng bạn muốn xoá vĩnh viễn thế giới này không?"
},
"app.instance.worlds.filter-modded": {
"message": "Modded"
},
"app.instance.worlds.filter-offline": {
"message": "Ngoại tuyến"
},
"app.instance.worlds.filter-online": {
"message": "Trực tuyến"
},
"app.instance.worlds.filter-vanilla": {
"message": "Vanilla"
},
"app.instance.worlds.no-worlds-description": {
"message": "Thêm một máy chủ hoặc tìm kiếm để bắt đầu"
},
"app.instance.worlds.no-worlds-heading": {
"message": "Không có máy chủ hay thế giới nào đã được thêm"
},
"app.instance.worlds.remove-server-description": {
"message": "'{name}' sẽ bị xóa khỏi danh sách của bạn, kể cả trong game, và bạn sẽ không có cách nào để khôi phục lại."
},
"app.instance.worlds.remove-server-description-with-address": {
"message": "'{name}' ({address}) sẽ bị xóa khỏi danh sách của bạn, kể cả trong game, và bạn sẽ không có cách nào để khôi phục lại."
},
"app.instance.worlds.remove-server-title": {
"message": "Bạn có chắc chắn rằng bạn muốn xoá {name}?"
},
"app.instance.worlds.search-worlds-placeholder": {
"message": "Tìm kiếm {count} world..."
},
"app.instance.worlds.this-server": {
"message": "Máy chủ này"
},
"app.modal.install-to-play.content-required": {
"message": "Nội dung bắt buộc"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "Tuỳ chọn hồ sơ khởi chạy mặc định"
},
"app.settings.tabs.feature-flags": {
"message": "Các cờ tính năng"
},
"app.settings.tabs.java-installations": {
"message": "Các bản cài Java"
},
@@ -197,6 +251,24 @@
"app.update.reload-to-update": {
"message": "Hãy khởi động lại để cài đặt bản cập nhật"
},
"app.world.server-modal.placeholder-address": {
"message": "example.modrinth.gg"
},
"app.world.server-modal.select-an-option": {
"message": "Chọn một tuỳ chọn"
},
"app.world.world-item.incompatible-version": {
"message": "Không phù hợp với phiên bản {version}"
},
"app.world.world-item.not-played-yet": {
"message": "Chưa từng được chơi"
},
"app.world.world-item.offline": {
"message": "Ngoại tuyến"
},
"app.world.world-item.players-online": {
"message": "{count} đang trực tuyến"
},
"friends.action.add-friend": {
"message": "Thêm một người bạn"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "Chỉnh sửa thế giới"
},
"instance.files.adding-files": {
"message": "Đang thêm dữ liệu ({completed}/{total})"
},
"instance.files.save-as": {
"message": "Lưu như..."
},
"instance.server-modal.address": {
"message": "Địa chỉ"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "Không hiện ở Trang chủ"
},
"instance.worlds.filter.available": {
"message": "Có sẵn"
},
"instance.worlds.game_already_open": {
"message": "Bản này đã mở sẵn"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "Chơi phiên bản này"
},
"instance.worlds.type.server": {
"message": "Máy chủ"
},
"instance.worlds.type.singleplayer": {
"message": "Chế độ một người chơi"
},
"instance.worlds.view_instance": {
"message": "Xem phiên bản"
},
+108 -39
View File
@@ -5,6 +5,39 @@
"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": "输入整合包描述……"
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "删除实例"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "这个整合包已经安装在\"{instanceName}\"实例中了。"
"app.instance.modpack-already-installed.body": {
"message": "整合包已经安装到实例<bold>{instanceName}</bold>中了。你确定要重复安装吗?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "重复的整合包"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "在任何地方创建"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "前往实例"
"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.copy-link": {
"message": "复制链接"
},
"app.instance.mods.installing": {
"message": "正在安装……"
},
"app.instance.mods.modpack-fallback": {
"message": "整合包"
},
"app.instance.mods.project-was-added": {
"message": "已添加“{name}”"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "分享整合包内容"
},
"app.instance.mods.show-file": {
"message": "显示文件"
},
"app.instance.mods.successfully-uploaded": {
"message": "上传成功"
},
"app.instance.mods.unknown-version": {
"message": "未知"
"app.instance.worlds.add-server": {
"message": "添加服务器"
},
"app.instance.mods.updating": {
"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": "内容需求"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "默认实例选项"
},
"app.settings.tabs.feature-flags": {
"message": "功能开关"
},
"app.settings.tabs.java-installations": {
"message": "Java 管理"
},
@@ -197,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": "添加好友"
},
@@ -213,7 +285,7 @@
"message": "这可能与对方的 Minecraft 用户名不同!"
},
"friends.add-friend.username.placeholder": {
"message": "输入 Modrinth 用户名…"
"message": "输入 Modrinth 用户名…"
},
"friends.add-friend.username.title": {
"message": "你好友的 Modrinth 用户名是什么?"
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "编辑存档"
},
"instance.files.adding-files": {
"message": "正在添加文件({completed}/{total}"
},
"instance.files.save-as": {
"message": "保存为……"
},
"instance.server-modal.address": {
"message": "地址"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "在主界面隐藏"
},
"instance.worlds.filter.available": {
"message": "可用"
},
"instance.worlds.game_already_open": {
"message": "实例已启动"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "游玩实例"
},
"instance.worlds.type.server": {
"message": "服务器"
},
"instance.worlds.type.singleplayer": {
"message": "单人游戏"
},
"instance.worlds.view_instance": {
"message": "查看实例"
},
+107 -38
View File
@@ -5,6 +5,39 @@
"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": "輸入模組包描述..."
},
@@ -41,33 +74,21 @@
"app.instance.confirm-delete.header": {
"message": "刪除實例"
},
"app.instance.modpack-already-installed.admonition-body": {
"message": "這個模組包已經安裝在{instanceName}」實例中了。"
"app.instance.modpack-already-installed.body": {
"message": "模組包已經安裝在<bold>{instanceName}</bold> 實例中了,您確定要再次安裝嗎?"
},
"app.instance.modpack-already-installed.admonition-header": {
"message": "複製模組包"
},
"app.instance.modpack-already-installed.create-anyway": {
"message": "仍要建立"
},
"app.instance.modpack-already-installed.go-to-instance": {
"message": "前往實例"
"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.copy-link": {
"message": "複製連結"
},
"app.instance.mods.installing": {
"message": "安裝中..."
},
"app.instance.mods.modpack-fallback": {
"message": "模組包"
},
"app.instance.mods.project-was-added": {
"message": "新增了「{name}」"
},
@@ -80,17 +101,53 @@
"app.instance.mods.share-title": {
"message": "分享模組包內容"
},
"app.instance.mods.show-file": {
"message": "顯示檔案"
},
"app.instance.mods.successfully-uploaded": {
"message": "上傳成功"
},
"app.instance.mods.unknown-version": {
"message": "未知"
"app.instance.worlds.add-server": {
"message": "新增伺服器"
},
"app.instance.mods.updating": {
"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": "所需內容"
@@ -140,9 +197,6 @@
"app.settings.tabs.default-instance-options": {
"message": "預設實例選項"
},
"app.settings.tabs.feature-flags": {
"message": "功能開關"
},
"app.settings.tabs.java-installations": {
"message": "Java 安裝"
},
@@ -197,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": "新增好友"
},
@@ -296,6 +368,12 @@
"instance.edit-world.title": {
"message": "編輯世界"
},
"instance.files.adding-files": {
"message": "正在新增檔案 ({completed}/{total})"
},
"instance.files.save-as": {
"message": "另存新檔..."
},
"instance.server-modal.address": {
"message": "位址"
},
@@ -467,9 +545,6 @@
"instance.worlds.dont_show_on_home": {
"message": "不要在首頁顯示"
},
"instance.worlds.filter.available": {
"message": "可用"
},
"instance.worlds.game_already_open": {
"message": "實例已經開啟"
},
@@ -494,12 +569,6 @@
"instance.worlds.play_instance": {
"message": "遊戲實例"
},
"instance.worlds.type.server": {
"message": "伺服器"
},
"instance.worlds.type.singleplayer": {
"message": "單人遊戲"
},
"instance.worlds.view_instance": {
"message": "檢視實例"
},
+272 -110
View File
@@ -1,6 +1,7 @@
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import {
CheckIcon,
ClipboardCopyIcon,
ExternalIcon,
GlobeIcon,
@@ -14,10 +15,12 @@ import {
Admonition,
ButtonStyled,
Checkbox,
commonMessages,
defineMessages,
DropdownSelect,
injectNotificationManager,
LoadingIndicator,
NavTabs,
Pagination,
ProjectCard,
ProjectCardList,
@@ -33,12 +36,11 @@ import { openUrl } from '@tauri-apps/plugin-opener'
import type { Ref } from 'vue'
import { computed, nextTick, onUnmounted, ref, shallowRef, toRaw, watch } from 'vue'
import type { LocationQuery } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import type Instance from '@/components/ui/Instance.vue'
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
import NavTabs from '@/components/ui/NavTabs.vue'
import SearchCard from '@/components/ui/SearchCard.vue'
import { get_project_v3, get_search_results_v3 } from '@/helpers/cache.js'
import { process_listener } from '@/helpers/events'
@@ -51,7 +53,7 @@ import {
} from '@/helpers/profile.js'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import type { GameInstance } from '@/helpers/types'
import { getServerLatency } from '@/helpers/worlds'
import { add_server_to_profile, get_profile_worlds, getServerLatency } from '@/helpers/worlds'
import { injectServerInstall } from '@/providers/server-install'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { getServerAddress } from '@/store/install.js'
@@ -108,19 +110,27 @@ const installedProjectIds: Ref<string[] | null> = ref(null)
const instanceHideInstalled = ref(false)
const newlyInstalled = ref<string[]>([])
const isServerInstance = ref(false)
const isFromWorlds = computed(() => route.query.from === 'worlds')
if (isFromWorlds.value && route.params.projectType !== 'server') {
router.replace({
path: '/browse/server',
query: route.query,
})
}
const allInstalledIds = computed(
() => new Set([...newlyInstalled.value, ...(installedProjectIds.value ?? [])]),
)
const PERSISTENT_QUERY_PARAMS = ['i', 'ai']
const PERSISTENT_QUERY_PARAMS = ['i', 'ai', 'from']
await initInstanceContext()
async function initInstanceContext() {
debugLog('initInstanceContext', { queryI: route.query.i, queryAi: route.query.ai })
if (route.query.i) {
instance.value = await getInstance(route.query.i).catch(handleError)
instance.value = (await getInstance(route.query.i as string).catch(handleError)) ?? null
debugLog('instance loaded', {
name: instance.value?.name,
loader: instance.value?.loader,
@@ -130,12 +140,24 @@ async function initInstanceContext() {
// Load installed project IDs in background — the page and initial search render immediately.
// When this resolves, instanceFilters recomputes and triggers a search refresh
// that applies the "hide installed" negative filters and marks installed badges.
getInstalledProjectIds(route.query.i)
.then((ids) => {
debugLog('installedProjectIds loaded', { count: ids?.length })
installedProjectIds.value = ids
})
.catch(handleError)
if (route.query.from === 'worlds') {
get_profile_worlds(route.query.i as string)
.then((worlds) => {
const serverProjectIds = worlds
.filter((w) => w.type === 'server' && 'project_id' in w && w.project_id)
.map((w) => (w as { project_id: string }).project_id)
debugLog('installedServerProjectIds loaded', { count: serverProjectIds.length })
installedProjectIds.value = serverProjectIds
})
.catch(handleError)
} else {
getInstalledProjectIds(route.query.i as string)
.then((ids) => {
debugLog('installedProjectIds loaded', { count: ids?.length })
installedProjectIds.value = ids
})
.catch(handleError)
}
if (instance.value?.linked_data?.project_id) {
debugLog('checking linked project for server status', instance.value.linked_data.project_id)
@@ -246,6 +268,10 @@ const activeGameVersion = computed(() => {
})
const serverHits = shallowRef<Labrinth.Search.v3.ResultSearchProject[]>([])
const filteredServerHits = computed(() => {
if (!instanceHideInstalled.value || allInstalledIds.value.size === 0) return serverHits.value
return serverHits.value.filter((hit) => !allInstalledIds.value.has(hit.project_id))
})
const serverPings = shallowRef<Record<string, number | undefined>>({})
const runningServerProjects = ref<Record<string, string>>({})
@@ -281,11 +307,28 @@ async function handlePlayServerProject(projectId: string) {
checkServerRunningStates(serverHits.value)
}
function handleAddServerToInstance(project: Labrinth.Search.v3.ResultSearchProject) {
async function handleAddServerToInstance(project: Labrinth.Search.v3.ResultSearchProject) {
debugLog('handleAddServerToInstance', { projectId: project.project_id, name: project.name })
const address = getServerAddress(project.minecraft_java_server)
if (!address) return
showAddServerToInstanceModal(project.name, address)
if (instance.value) {
try {
await add_server_to_profile(
instance.value.path,
project.name,
address,
'prompt',
project.project_id,
project.minecraft_java_server?.content?.kind,
)
newlyInstalled.value.push(project.project_id)
} catch (err) {
handleError(err as Error)
}
} else {
showAddServerToInstanceModal(project.name, address)
}
}
const unlistenProcesses = await process_listener(
@@ -317,6 +360,16 @@ const {
createServerPageParams,
} = useServerSearch({ tags, query, maxResults, currentPage })
if (instance.value?.game_version) {
const gv = instance.value.game_version
const alreadyHasGv = serverCurrentFilters.value.some(
(f) => f.type === 'server_game_version' && f.option === gv,
)
if (!alreadyHasGv) {
serverCurrentFilters.value.push({ type: 'server_game_version', option: gv })
}
}
async function pingServerHits(hits: Labrinth.Search.v3.ResultSearchProject[]) {
debugLog('pingServerHits', { hitCount: hits.length })
const pingsToFetch = hits.filter((hit) => hit.minecraft_java_server?.address)
@@ -346,8 +399,107 @@ window.addEventListener('online', () => {
offline.value = false
})
const messages = defineMessages({
addServerToInstance: {
id: 'app.browse.add-server-to-instance',
defaultMessage: 'Add server to instance',
},
addServersToInstance: {
id: 'app.browse.add-servers-to-instance',
defaultMessage: 'Add servers to your instance',
},
addToInstance: {
id: 'app.browse.add-to-instance',
defaultMessage: 'Add to instance',
},
addToInstanceName: {
id: 'app.browse.add-to-instance-name',
defaultMessage: 'Add to {instanceName}',
},
added: {
id: 'app.browse.added',
defaultMessage: 'Added',
},
alreadyAdded: {
id: 'app.browse.already-added',
defaultMessage: 'Already added',
},
discoverContent: {
id: 'app.browse.discover-content',
defaultMessage: 'Discover content',
},
discoverServers: {
id: 'app.browse.discover-servers',
defaultMessage: 'Discover servers',
},
environmentProvidedByServer: {
id: 'search.filter.locked.server-environment.title',
defaultMessage: 'Only client-side mods can be added to the server instance',
},
gameVersionProvidedByInstance: {
id: 'search.filter.locked.instance-game-version.title',
defaultMessage: 'Game version is provided by the instance',
},
gameVersionProvidedByServer: {
id: 'search.filter.locked.server-game-version.title',
defaultMessage: 'Game version is provided by the server',
},
hideAddedServers: {
id: 'app.browse.hide-added-servers',
defaultMessage: 'Hide added servers',
},
hideInstalledContent: {
id: 'app.browse.hide-installed-content',
defaultMessage: 'Hide installed content',
},
installContentToInstance: {
id: 'app.browse.install-content-to-instance',
defaultMessage: 'Install content to instance',
},
modLoaderProvidedByInstance: {
id: 'search.filter.locked.instance-loader.title',
defaultMessage: 'Loader is provided by the instance',
},
modLoaderProvidedByServer: {
id: 'search.filter.locked.server-loader.title',
defaultMessage: 'Loader is provided by the server',
},
providedByInstance: {
id: 'search.filter.locked.instance',
defaultMessage: 'Provided by the instance',
},
providedByServer: {
id: 'search.filter.locked.server',
defaultMessage: 'Provided by the server',
},
syncFilterButton: {
id: 'search.filter.locked.instance.sync',
defaultMessage: 'Sync with instance',
},
})
const breadcrumbs = useBreadcrumbs()
breadcrumbs.setContext({ name: 'Discover content', link: route.path, query: route.query })
const browseTitle = computed(() =>
formatMessage(isFromWorlds.value ? messages.discoverServers : messages.discoverContent),
)
breadcrumbs.setName('BrowseTitle', browseTitle.value)
if (instance.value) {
const instanceLink = `/instance/${encodeURIComponent(instance.value.path)}`
breadcrumbs.setContext({
name: instance.value.name,
link: isFromWorlds.value ? `${instanceLink}/worlds` : instanceLink,
})
} else {
breadcrumbs.setContext(null)
}
onBeforeRouteLeave(() => {
breadcrumbs.setContext({
name: browseTitle.value,
link: `/browse/${projectType.value}`,
query: route.query,
})
})
const loading = ref(true)
@@ -484,11 +636,6 @@ async function refreshSearch() {
...(isServer ? createServerPageParams() : createPageParams()),
}
breadcrumbs.setContext({
name: 'Discover content',
link: `/browse/${projectType.value}`,
query: params,
})
debugLog('updating URL', params)
router.replace({ path: route.path, query: params })
@@ -532,6 +679,18 @@ watch(
debugLog('projectType route param changed', { from: projectType.value, to: newType })
projectType.value = newType
// If instance context was removed (e.g. sidebar browse navigation), reset state
if (!route.query.i && instance.value) {
debugLog('instance context removed, resetting')
instance.value = null
installedProjectIds.value = null
instanceHideInstalled.value = false
newlyInstalled.value = []
isServerInstance.value = false
breadcrumbs.setName('BrowseTitle', formatMessage(messages.discoverContent))
breadcrumbs.setContext(null)
}
currentSortType.value = { display: 'Relevance', name: 'relevance' }
query.value = ''
},
@@ -569,64 +728,25 @@ const selectableProjectTypes = computed(() => {
if (route.query.ai) {
params.ai = route.query.ai
}
const links = [
{ label: 'Modpacks', href: `/browse/modpack`, shown: modpacks },
{ label: 'Mods', href: `/browse/mod`, shown: mods },
{ label: 'Resource Packs', href: `/browse/resourcepack` },
{ label: 'Data Packs', href: `/browse/datapack`, shown: dataPacks },
{ label: 'Shaders', href: `/browse/shader` },
{ label: 'Servers', href: `/browse/server`, shown: !instance.value },
]
if (params) {
return links.map((link) => {
return {
...link,
href: {
path: link.href,
query: params,
},
}
})
if (route.query.from) {
params.from = route.query.from
}
return links
})
const queryString = new URLSearchParams(params as Record<string, string>).toString()
const suffix = queryString ? `?${queryString}` : ''
const messages = defineMessages({
gameVersionProvidedByInstance: {
id: 'search.filter.locked.instance-game-version.title',
defaultMessage: 'Game version is provided by the instance',
},
gameVersionProvidedByServer: {
id: 'search.filter.locked.server-game-version.title',
defaultMessage: 'Game version is provided by the server',
},
modLoaderProvidedByInstance: {
id: 'search.filter.locked.instance-loader.title',
defaultMessage: 'Loader is provided by the instance',
},
modLoaderProvidedByServer: {
id: 'search.filter.locked.server-loader.title',
defaultMessage: 'Loader is provided by the server',
},
environmentProvidedByServer: {
id: 'search.filter.locked.server-environment.title',
defaultMessage: 'Only client-side mods can be added to the server instance',
},
providedByInstance: {
id: 'search.filter.locked.instance',
defaultMessage: 'Provided by the instance',
},
providedByServer: {
id: 'search.filter.locked.server',
defaultMessage: 'Provided by the server',
},
syncFilterButton: {
id: 'search.filter.locked.instance.sync',
defaultMessage: 'Sync with instance',
},
if (isFromWorlds.value) {
return [{ label: 'Servers', href: `/browse/server${suffix}` }]
}
return [
{ label: 'Modpacks', href: `/browse/modpack${suffix}`, shown: modpacks },
{ label: 'Mods', href: `/browse/mod${suffix}`, shown: mods },
{ label: 'Resource Packs', href: `/browse/resourcepack${suffix}` },
{ label: 'Data Packs', href: `/browse/datapack${suffix}`, shown: dataPacks },
{ label: 'Shaders', href: `/browse/shader${suffix}` },
{ label: 'Servers', href: `/browse/server${suffix}`, shown: !instance.value },
]
})
const getServerModpackContent = (project: Labrinth.Search.v3.ResultSearchProject) => {
@@ -697,7 +817,9 @@ previousFilterState.value = JSON.stringify({
>
<Checkbox
v-model="instanceHideInstalled"
label="Hide installed content"
:label="
formatMessage(isFromWorlds ? messages.hideAddedServers : messages.hideInstalledContent)
"
class="filter-checkbox"
@update:model-value="onSearchChangeToTop()"
@click.prevent.stop
@@ -776,9 +898,15 @@ previousFilterState.value = JSON.stringify({
</Teleport>
<div ref="searchWrapper" class="flex flex-col gap-3 p-6">
<template v-if="instance">
<InstanceIndicator :instance="instance" />
<h1 class="m-0 mb-1 text-xl">Install content to instance</h1>
<Admonition v-if="isServerInstance" type="warning" class="mb-1">
<InstanceIndicator :instance="instance" :back-tab="isFromWorlds ? 'worlds' : undefined" />
<h1 class="m-0 mb-1 text-xl">
{{
formatMessage(
isFromWorlds ? messages.addServersToInstance : messages.installContentToInstance,
)
}}
</h1>
<Admonition v-if="isServerInstance && !isFromWorlds" type="warning" class="mb-1">
Adding content can break compatibility when joining the server. Any added content will also
be lost when you update the server instance content.
</Admonition>
@@ -850,7 +978,7 @@ previousFilterState.value = JSON.stringify({
<section
v-else-if="
projectType === 'server'
? serverHits.length === 0
? filteredServerHits.length === 0
: results && results.hits && results.hits.length === 0
"
class="offline"
@@ -861,7 +989,7 @@ previousFilterState.value = JSON.stringify({
<ProjectCardList v-else :layout="'list'">
<template v-if="projectType === 'server'">
<ProjectCard
v-for="project in serverHits"
v-for="project in filteredServerHits"
:key="`server-card-${project.project_id}`"
:title="project.name"
:icon-url="project.icon_url || undefined"
@@ -887,37 +1015,71 @@ previousFilterState.value = JSON.stringify({
>
<template #actions>
<div class="flex gap-2">
<ButtonStyled circular>
<button
v-tooltip="'Add server to instance'"
@click.stop="() => handleAddServerToInstance(project)"
<template v-if="isFromWorlds && instance">
<ButtonStyled color="brand" type="outlined">
<button
:disabled="allInstalledIds.has(project.project_id)"
@click.stop="() => handleAddServerToInstance(project)"
>
<CheckIcon v-if="allInstalledIds.has(project.project_id)" />
<PlusIcon v-else />
{{
formatMessage(
allInstalledIds.has(project.project_id)
? messages.added
: messages.addToInstance,
)
}}
</button>
</ButtonStyled>
</template>
<template v-else>
<ButtonStyled circular>
<button
v-tooltip="
allInstalledIds.has(project.project_id)
? formatMessage(messages.alreadyAdded)
: instance
? formatMessage(messages.addToInstanceName, {
instanceName: instance.name,
})
: formatMessage(messages.addServerToInstance)
"
:disabled="allInstalledIds.has(project.project_id)"
@click.stop="() => handleAddServerToInstance(project)"
>
<CheckIcon v-if="allInstalledIds.has(project.project_id)" />
<PlusIcon v-else />
</button>
</ButtonStyled>
<ButtonStyled
v-if="runningServerProjects[project.project_id]"
color="red"
type="outlined"
>
<PlusIcon />
</button>
</ButtonStyled>
<ButtonStyled
v-if="runningServerProjects[project.project_id]"
color="red"
type="outlined"
>
<button @click="() => handleStopServerProject(project.project_id)">
<StopCircleIcon />
Stop
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand" type="outlined">
<button
:disabled="(installingServerProjects as string[]).includes(project.project_id)"
@click="() => handlePlayServerProject(project.project_id)"
>
<PlayIcon />
{{
(installingServerProjects as string[]).includes(project.project_id)
? 'Installing...'
: 'Play'
}}
</button>
</ButtonStyled>
<button @click="() => handleStopServerProject(project.project_id)">
<StopCircleIcon />
{{ formatMessage(commonMessages.stopButton) }}
</button>
</ButtonStyled>
<ButtonStyled v-else color="brand" type="outlined">
<button
:disabled="
(installingServerProjects as string[]).includes(project.project_id)
"
@click="() => handlePlayServerProject(project.project_id)"
>
<PlayIcon />
{{
formatMessage(
(installingServerProjects as string[]).includes(project.project_id)
? commonMessages.installingLabel
: commonMessages.playButton,
)
}}
</button>
</ButtonStyled>
</template>
</div>
</template>
</ProjectCard>
@@ -0,0 +1,345 @@
<script setup lang="ts">
import type { EditingFile, FileItem, UploadState } from '@modrinth/ui'
import {
commonMessages,
defineMessages,
FilePageLayout,
injectNotificationManager,
provideFileManager,
useDebugLogger,
useVIntl,
} from '@modrinth/ui'
import { invoke } from '@tauri-apps/api/core'
import {
mkdir,
readDir,
readFile as readFileBytes,
readTextFile,
remove,
rename,
stat,
writeFile as writeFileBytes,
writeTextFile,
} from '@tauri-apps/plugin-fs'
import { onUnmounted, ref, watch } from 'vue'
import { profile_listener } from '@/helpers/events'
import { get_full_path } from '@/helpers/profile'
import type { GameInstance } from '@/helpers/types'
import { highlightInFolder } from '@/helpers/utils'
const props = defineProps<{
instance: GameInstance
options: unknown
offline: boolean
playing: boolean
installed: boolean
isServerInstance: boolean
}>()
const { formatMessage } = useVIntl()
const { addNotification } = injectNotificationManager()
const debug = useDebugLogger('Files')
const messages = defineMessages({
saveAs: {
id: 'instance.files.save-as',
defaultMessage: 'Save as...',
},
addingFiles: {
id: 'instance.files.adding-files',
defaultMessage: 'Adding files ({completed}/{total})',
},
})
const instanceRoot = ref('')
const items = ref<FileItem[]>([])
const loading = ref(true)
const error = ref<Error | null>(null)
const currentPath = ref('')
const editingFile = ref<EditingFile | null>(null)
debug('setup: start, instance.path =', props.instance.path)
instanceRoot.value = await get_full_path(props.instance.path)
debug('setup: instanceRoot =', instanceRoot.value)
await refresh()
debug('setup: refresh complete, items =', items.value.length, 'error =', error.value)
function resolvePath(relativePath: string): string {
return relativePath ? `${instanceRoot.value}/${relativePath}` : instanceRoot.value
}
async function listDirectory(dirPath: string): Promise<FileItem[]> {
const absPath = resolvePath(dirPath)
debug('listDirectory: dirPath =', dirPath, 'absPath =', absPath)
const entries = await readDir(absPath)
debug('listDirectory: got', entries.length, 'entries')
const results = await Promise.all(
entries.map(async (entry) => {
const entryAbsPath = `${absPath}/${entry.name}`
let metadata
try {
metadata = await stat(entryAbsPath)
} catch {
debug('listDirectory: stat failed for', entry.name, '- skipping')
return null
}
const item: FileItem = {
name: entry.name,
type: entry.isDirectory ? 'directory' : 'file',
path: dirPath ? `${dirPath}/${entry.name}` : entry.name,
modified: metadata.mtime ? Math.floor(metadata.mtime.getTime() / 1000) : 0,
created: metadata.birthtime ? Math.floor(metadata.birthtime.getTime() / 1000) : 0,
}
if (!entry.isDirectory) {
item.size = metadata.size
}
if (entry.isDirectory) {
try {
const children = await readDir(entryAbsPath)
item.count = children.length
} catch {
item.count = 0
}
}
return item
}),
)
return results.filter((item): item is FileItem => item !== null)
}
async function refresh() {
debug('refresh: called, currentPath =', currentPath.value, 'instanceRoot =', instanceRoot.value)
loading.value = true
error.value = null
try {
items.value = await listDirectory(currentPath.value)
debug('refresh: success, items =', items.value.length)
} catch (e) {
debug('refresh: error =', e)
error.value = e instanceof Error ? e : new Error(String(e))
items.value = []
} finally {
loading.value = false
}
}
function navigateTo(path: string) {
debug('navigateTo:', path)
currentPath.value = path.startsWith('/') ? path.slice(1) : path
refresh()
}
function startEditing(file: EditingFile) {
editingFile.value = file
}
function stopEditing() {
editingFile.value = null
}
async function handleCreateItem(name: string, type: 'file' | 'directory') {
const targetPath = currentPath.value ? `${currentPath.value}/${name}` : name
const absPath = resolvePath(targetPath)
try {
if (type === 'directory') {
await mkdir(absPath)
} else {
await writeTextFile(absPath, '')
}
await refresh()
} catch (e) {
addNotification({
title: formatMessage(commonMessages.createFailedLabel),
text: e instanceof Error ? e.message : '',
type: 'error',
})
}
}
async function handleRenameItem(path: string, newName: string) {
const oldAbs = resolvePath(path)
const parentDir = path.includes('/') ? path.substring(0, path.lastIndexOf('/')) : ''
const newPath = parentDir ? `${parentDir}/${newName}` : newName
const newAbs = resolvePath(newPath)
try {
await rename(oldAbs, newAbs)
await refresh()
} catch (e) {
addNotification({
title: formatMessage(commonMessages.renameFailedLabel),
text: e instanceof Error ? e.message : '',
type: 'error',
})
}
}
async function handleMoveItem(source: string, destination: string) {
try {
await rename(resolvePath(source), resolvePath(destination))
await refresh()
} catch (e) {
addNotification({
title: formatMessage(commonMessages.moveFailedLabel),
text: e instanceof Error ? e.message : '',
type: 'error',
})
}
}
async function handleDeleteItem(path: string, recursive: boolean) {
try {
await remove(resolvePath(path), { recursive })
await refresh()
} catch (e) {
addNotification({
title: formatMessage(commonMessages.deleteFailedLabel),
text: e instanceof Error ? e.message : '',
type: 'error',
})
}
}
async function handleReadFile(path: string): Promise<string> {
return await readTextFile(resolvePath(path))
}
async function handleReadFileAsBlob(path: string): Promise<Blob> {
const bytes = await readFileBytes(resolvePath(path))
return new Blob([bytes])
}
async function handleWriteFile(path: string, content: string) {
await writeTextFile(resolvePath(path), content)
}
async function handleDownloadFile(path: string, _fileName: string) {
await invoke('plugin:files|file_save_as', {
instancePath: props.instance.path,
filePath: path,
})
}
const uploadState = ref<UploadState>({
isUploading: false,
currentFileName: null,
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes: 0,
completedFiles: 0,
totalFiles: 0,
})
async function handleUploadFiles(files: File[]) {
if (files.length === 0) return
uploadState.value = {
isUploading: true,
currentFileName: '',
currentFileProgress: 0,
uploadedBytes: 0,
totalBytes: files.reduce((sum, f) => sum + f.size, 0),
completedFiles: 0,
totalFiles: files.length,
}
try {
for (const file of files) {
uploadState.value.currentFileName = file.name
const buffer = await file.arrayBuffer()
const targetPath = resolvePath(
currentPath.value ? `${currentPath.value}/${file.name}` : file.name,
)
await writeFileBytes(targetPath, new Uint8Array(buffer))
uploadState.value.completedFiles++
uploadState.value.uploadedBytes += file.size
uploadState.value.currentFileProgress = 1
}
} catch (e) {
addNotification({
title: formatMessage(commonMessages.uploadFailedLabel),
text: e instanceof Error ? e.message : '',
type: 'error',
})
} finally {
uploadState.value.isUploading = false
await refresh()
}
}
async function handleExtractFile(path: string, override: boolean, dry: boolean) {
try {
return await invoke('plugin:files|file_extract_zip', {
instancePath: props.instance.path,
filePath: path,
overrideConflicts: override,
dryRun: dry,
})
} catch (e) {
addNotification({
title: formatMessage(commonMessages.extractFailedLabel),
text: e instanceof Error ? e.message : '',
type: 'error',
})
}
}
debug('setup: registering profile_listener')
const unlistenProfiles = await profile_listener(
async (event: { event: string; profile_path_id: string }) => {
debug('profile_listener: event =', event.event, 'path =', event.profile_path_id)
if (event.profile_path_id === props.instance.path && event.event === 'synced') {
debug('profile_listener: synced event matched, calling refresh')
await refresh()
}
},
)
debug('setup: profile_listener registered')
onUnmounted(() => {
unlistenProfiles()
})
watch(
() => props.instance.path,
async () => {
debug('watch instance.path: changed to', props.instance.path)
instanceRoot.value = await get_full_path(props.instance.path)
currentPath.value = ''
await refresh()
},
)
provideFileManager({
items,
loading,
error,
currentPath,
navigateTo,
editingFile,
startEditing,
stopEditing,
createItem: handleCreateItem,
renameItem: handleRenameItem,
moveItem: handleMoveItem,
deleteItem: handleDeleteItem,
readFile: handleReadFile,
readFileAsBlob: handleReadFileAsBlob,
writeFile: handleWriteFile,
downloadFile: handleDownloadFile,
uploadFiles: handleUploadFiles,
uploadState,
extractFile: handleExtractFile,
refresh,
basePath: instanceRoot,
openInFolder: (path: string) => highlightInFolder(path),
downloadButtonLabel: formatMessage(messages.saveAs),
uploadingLabel: (completed: number, total: number) =>
formatMessage(messages.addingFiles, { completed, total }),
})
</script>
<template>
<FilePageLayout :show-refresh-button="true" />
</template>
+12 -22
View File
@@ -3,6 +3,7 @@
<div class="p-6 pr-2 pb-4" @contextmenu.prevent.stop="(event) => handleRightClick(event)">
<ExportModal ref="exportModal" :instance="instance" />
<InstanceSettingsModal
:key="instance.path"
ref="settingsModal"
:instance="instance"
:offline="offline"
@@ -36,27 +37,6 @@
</template>
<template v-else> Never played </template>
</div>
<div v-if="linkedProjectV3" class="w-1.5 h-1.5 rounded-full bg-surface-5"></div>
<div
v-if="linkedProjectV3"
class="flex gap-1.5 items-center font-medium text-primary"
>
Linked to
<Avatar
:src="linkedProjectV3.icon_url"
:alt="linkedProjectV3.name"
:tint-by="instance.path"
size="24px"
/>
<router-link
:to="`/project/${linkedProjectV3.slug ?? linkedProjectV3.id}`"
class="hover:underline text-primary truncate"
>
{{ linkedProjectV3.name }}
</router-link>
</div>
</template>
<template v-else>
@@ -285,6 +265,7 @@
<script setup lang="ts">
import type { Labrinth } from '@modrinth/api-client'
import {
BoxesIcon,
CheckCircleIcon,
ClipboardCopyIcon,
DownloadIcon,
@@ -302,6 +283,7 @@ import {
ServerIcon,
SettingsIcon,
StopCircleIcon,
TerminalSquareIcon,
UpdatedIcon,
UserPlusIcon,
XIcon,
@@ -312,6 +294,7 @@ import {
ContentPageHeader,
injectNotificationManager,
LoadingIndicator,
NavTabs,
OverflowMenu,
ServerOnlinePlayers,
ServerPing,
@@ -329,7 +312,6 @@ import ContextMenu from '@/components/ui/ContextMenu.vue'
import ExportModal from '@/components/ui/ExportModal.vue'
import InstanceSettingsModal from '@/components/ui/modal/InstanceSettingsModal.vue'
import UpdateToPlayModal from '@/components/ui/modal/UpdateToPlayModal.vue'
import NavTabs from '@/components/ui/NavTabs.vue'
import { trackEvent } from '@/helpers/analytics'
import { get_project_v3 } from '@/helpers/cache.js'
import { process_listener, profile_listener } from '@/helpers/events'
@@ -451,14 +433,22 @@ const tabs = computed(() => [
{
label: 'Content',
href: `${basePath.value}`,
icon: BoxesIcon,
},
{
label: 'Files',
href: `${basePath.value}/files`,
icon: FolderOpenIcon,
},
{
label: 'Worlds',
href: `${basePath.value}/worlds`,
icon: GlobeIcon,
},
{
label: 'Logs',
href: `${basePath.value}/logs`,
icon: TerminalSquareIcon,
},
])
+44 -67
View File
@@ -13,6 +13,7 @@
:modpack-icon-url="linkedModpackProject?.icon_url ?? undefined"
:enable-toggle="!props.isServerInstance"
:get-overflow-options="getOverflowOptions"
:switch-version="handleSwitchVersion"
@update:enabled="handleModpackContentToggle"
@bulk:enable="handleModpackContentBulkToggle"
@bulk:disable="handleModpackContentBulkToggle"
@@ -47,7 +48,7 @@
"
:project-name="
updatingModpack
? (linkedModpackProject?.title ?? formatMessage(messages.modpackFallback))
? (linkedModpackProject?.title ?? formatMessage(commonMessages.modpackLabel))
: (updatingProject?.project?.title ?? updatingProject?.file_name)
"
:loading="loadingVersions"
@@ -65,7 +66,9 @@
import type { Labrinth } from '@modrinth/api-client'
import { ClipboardCopyIcon, FolderOpenIcon } from '@modrinth/assets'
import {
commonMessages,
ConfirmModpackUpdateModal,
ContentCardLayout as ContentPageLayout,
type ContentItem,
type ContentModpackCardCategory,
type ContentModpackCardProject,
@@ -82,7 +85,6 @@ import {
useDebugLogger,
useVIntl,
} from '@modrinth/ui'
import { ContentCardLayout as ContentPageLayout } from '@modrinth/ui'
import { getCurrentWebview } from '@tauri-apps/api/webview'
import { open } from '@tauri-apps/plugin-dialog'
import { openUrl } from '@tauri-apps/plugin-opener'
@@ -125,10 +127,6 @@ const messages = defineMessages({
id: 'app.instance.mods.share-text',
defaultMessage: "Check out the projects I'm using in my modpack!",
},
modpackFallback: {
id: 'app.instance.mods.modpack-fallback',
defaultMessage: 'Modpack',
},
successfullyUploaded: {
id: 'app.instance.mods.successfully-uploaded',
defaultMessage: 'Successfully uploaded',
@@ -141,30 +139,10 @@ const messages = defineMessages({
id: 'app.instance.mods.projects-were-added',
defaultMessage: '{count} projects were added',
},
updating: {
id: 'app.instance.mods.updating',
defaultMessage: 'Updating...',
},
installing: {
id: 'app.instance.mods.installing',
defaultMessage: 'Installing...',
},
contentTypeProject: {
id: 'app.instance.mods.content-type-project',
defaultMessage: 'project',
},
unknownVersion: {
id: 'app.instance.mods.unknown-version',
defaultMessage: 'Unknown',
},
showFile: {
id: 'app.instance.mods.show-file',
defaultMessage: 'Show file',
},
copyLink: {
id: 'app.instance.mods.copy-link',
defaultMessage: 'Copy link',
},
})
let savedModalState: ModpackContentModalState | null = null
@@ -283,7 +261,7 @@ async function handleUploadFiles() {
}
}
async function _toggleDisableMod(mod: ContentItem) {
async function toggleDisableMod(mod: ContentItem) {
try {
mod.file_path = await toggle_disable_project(props.instance.path, mod.file_path!)
mod.enabled = !mod.enabled
@@ -301,7 +279,7 @@ async function _toggleDisableMod(mod: ContentItem) {
}
}
const toggleDisableMod = useDebounceFn(_toggleDisableMod, 20)
const toggleDisableDebounced = useDebounceFn(toggleDisableMod, 20)
async function removeMod(mod: ContentItem) {
await remove_project(props.instance.path, mod.file_path!).catch(handleError)
@@ -354,6 +332,12 @@ async function updateProject(mod: ContentItem) {
}
async function switchProjectVersion(mod: ContentItem, version: Labrinth.Versions.v2.Version) {
isBulkOperating.value = true
mod.installing = true
if (mod.version) {
mod.version.id = version.id
mod.version.version_number = version.version_number
}
try {
await remove_project(props.instance.path, mod.file_path!)
const newPath = await add_project_from_version(props.instance.path, version.id)
@@ -364,20 +348,12 @@ async function switchProjectVersion(mod: ContentItem, version: Labrinth.Versions
}
mod.file_path = newPath
if (mod.version) {
mod.version.id = version.id
mod.version.version_number = version.version_number
}
trackEvent('InstanceProjectSwitchVersion', {
loader: props.instance.loader,
game_version: props.instance.game_version,
id: mod.project?.id,
name: mod.project?.title ?? mod.file_name,
project_type: mod.project_type,
})
} catch (err) {
handleError(err as Error)
} finally {
mod.installing = false
isBulkOperating.value = false
await initProjects()
}
}
@@ -468,11 +444,11 @@ async function handleSwitchVersion(item: ContentItem) {
}
async function handleModpackContentToggle(item: ContentItem) {
await toggleDisableMod(item)
await toggleDisableDebounced(item)
}
async function handleModpackContentBulkToggle(items: ContentItem[]) {
await Promise.all(items.map((item) => _toggleDisableMod(item)))
await Promise.all(items.map((item) => toggleDisableMod(item)))
}
async function handleModpackContent() {
@@ -539,7 +515,7 @@ async function fetchAndSpliceVersion(
async function handleVersionSelect(version: Labrinth.Versions.v2.Version) {
if (version.changelog != null) return
loadingChangelog.value = true
await fetchAndSpliceVersion(version.id, 'must_revalidate', handleError)
await fetchAndSpliceVersion(version.id, 'must_revalidate', handleError as (err: unknown) => void)
loadingChangelog.value = false
}
@@ -660,14 +636,14 @@ function getOverflowOptions(item: ContentItem): OverflowMenuOption[] {
const options: OverflowMenuOption[] = []
options.push({
id: formatMessage(messages.showFile),
id: formatMessage(commonMessages.showFileButton),
icon: FolderOpenIcon,
action: () => highlightModInProfile(props.instance.path, item.file_path),
})
if (item.project?.slug) {
options.push({
id: formatMessage(messages.copyLink),
id: formatMessage(commonMessages.copyLinkButton),
icon: ClipboardCopyIcon,
action: async () => {
await navigator.clipboard.writeText(
@@ -718,18 +694,13 @@ async function initProjects(cacheBehaviour?: CacheBehaviour) {
if (allCategories && modpackInfo.project.categories) {
const seen = new Set<string>()
linkedModpackCategories.value = allCategories
.filter((cat: { name: string }) => {
if (modpackInfo.project.categories.includes(cat.name) && !seen.has(cat.name)) {
seen.add(cat.name)
return true
}
return false
})
.map((cat: { name: string }) => ({
...cat,
name: cat.name.charAt(0).toUpperCase() + cat.name.slice(1),
}))
linkedModpackCategories.value = allCategories.filter((cat: { name: string }) => {
if (modpackInfo.project.categories.includes(cat.name) && !seen.has(cat.name)) {
seen.add(cat.name)
return true
}
return false
})
} else {
linkedModpackCategories.value = []
}
@@ -799,8 +770,8 @@ provideContentManager({
hasUpdate: linkedModpackHasUpdate.value,
disabled: isModpackUpdating.value,
disabledText: isModpackUpdating.value
? formatMessage(messages.updating)
: formatMessage(messages.installing),
? formatMessage(commonMessages.updatingLabel)
: formatMessage(commonMessages.installingLabel),
}
: null,
),
@@ -808,13 +779,18 @@ provideContentManager({
isBusy: isInstanceBusy,
isBulkOperating,
contentTypeLabel: ref(formatMessage(messages.contentTypeProject)),
toggleEnabled: toggleDisableMod,
bulkEnableItems: (items) =>
Promise.all(items.map((item) => _toggleDisableMod(item))).then(() => {}),
bulkDisableItems: (items) =>
Promise.all(items.map((item) => _toggleDisableMod(item))).then(() => {}),
toggleEnabled: toggleDisableDebounced,
bulkEnableItems: (items: ContentItem[]) =>
Promise.all(items.filter((item) => !item.enabled).map((item) => toggleDisableMod(item))).then(
() => {},
),
bulkDisableItems: (items: ContentItem[]) =>
Promise.all(items.filter((item) => item.enabled).map((item) => toggleDisableMod(item))).then(
() => {},
),
deleteItem: removeMod,
bulkDeleteItems: (items) => Promise.all(items.map((item) => removeMod(item))).then(() => {}),
bulkDeleteItems: (items: ContentItem[]) =>
Promise.all(items.map((item) => removeMod(item))).then(() => {}),
refresh: () => initProjects('must_revalidate'),
browse: handleBrowseContent,
uploadFiles: handleUploadFiles,
@@ -830,7 +806,7 @@ provideContentManager({
showContentHint,
dismissContentHint,
shareItems: handleShareItems,
mapToTableItem: (item) => ({
mapToTableItem: (item: ContentItem) => ({
id: item.id,
project: item.project ?? {
id: item.file_name,
@@ -843,7 +819,7 @@ provideContentManager({
: undefined,
version: item.version ?? {
id: item.file_name,
version_number: formatMessage(messages.unknownVersion),
version_number: formatMessage(commonMessages.unknownLabel),
file_name: item.file_name,
},
versionLink:
@@ -860,6 +836,7 @@ provideContentManager({
}
: undefined,
enabled: item.enabled,
installing: item.installing,
}),
filterPersistKey: props.instance.path,
})
+253 -107
View File
@@ -15,48 +15,88 @@
<EditWorldModal ref="editWorldModal" :instance="instance" @submit="editWorld" />
<ConfirmModalWrapper
ref="removeServerModal"
:title="`Are you sure you want to remove ${serverToRemove?.name ?? 'this server'}?`"
:description="`'${serverToRemove?.name}'${serverToRemove?.address === serverToRemove?.name ? ' ' : ` (${serverToRemove?.address})`} will be removed from your list, including in-game, and there will be no way to recover it.`"
:title="
formatMessage(messages.removeServerTitle, {
name: serverToRemove?.name ?? formatMessage(messages.thisServer),
})
"
:description="
serverToRemove?.address === serverToRemove?.name
? formatMessage(messages.removeServerDescription, { name: serverToRemove?.name })
: formatMessage(messages.removeServerDescriptionWithAddress, {
name: serverToRemove?.name,
address: serverToRemove?.address,
})
"
:markdown="false"
@proceed="proceedRemoveServer"
/>
<ConfirmModalWrapper
ref="deleteWorldModal"
:title="`Are you sure you want to permanently delete this world?`"
:description="`'${worldToDelete?.name}' will be **permanently deleted**, and there will be no way to recover it.`"
:title="formatMessage(messages.deleteWorldTitle)"
:description="formatMessage(messages.deleteWorldDescription, { name: worldToDelete?.name })"
@proceed="proceedDeleteWorld"
/>
<div v-if="dedupedWorlds.length > 0" class="flex flex-col gap-4">
<div class="flex flex-wrap gap-2 items-center">
<div class="flex flex-wrap items-center gap-2">
<StyledInput
v-model="searchFilter"
:icon="SearchIcon"
type="text"
placeholder="Search worlds..."
autocomplete="off"
:spellcheck="false"
input-class="!h-10"
wrapper-class="flex-1 min-w-0"
clearable
wrapper-class="flex-grow"
:placeholder="
formatMessage(messages.searchWorldsPlaceholder, { count: dedupedWorlds.length })
"
/>
<ButtonStyled>
<button :disabled="refreshingAll" @click="refreshAllWorlds">
<template v-if="refreshingAll">
<SpinnerIcon class="animate-spin" />
Refreshing...
</template>
<template v-else>
<UpdatedIcon />
Refresh
</template>
<div class="flex gap-2">
<ButtonStyled type="outlined">
<button class="!h-10 !border-button-bg !border-[1px]" @click="addServerModal?.show()">
<PlusIcon class="size-5" />
{{ formatMessage(messages.addServer) }}
</button>
</ButtonStyled>
<ButtonStyled color="brand">
<button
class="!h-10 flex items-center gap-2"
@click="
router.push({ path: '/browse/server', query: { i: instance.path, from: 'worlds' } })
"
>
<CompassIcon class="size-5" />
<span>{{ formatMessage(messages.browseServers) }}</span>
</button>
</ButtonStyled>
</div>
</div>
<div class="flex flex-wrap items-center justify-between gap-2">
<div class="flex flex-wrap items-center gap-1.5">
<FilterIcon class="size-5 text-secondary" />
<button
:class="filterPillClass(selectedFilters.length === 0)"
@click="selectedFilters = []"
>
{{ formatMessage(commonMessages.allProjectType) }}
</button>
</ButtonStyled>
<ButtonStyled>
<button @click="addServerModal?.show()">
<PlusIcon />
Add a server
<button
v-for="option in filterOptions"
:key="option.id"
:class="filterPillClass(selectedFilters.includes(option.id))"
@click="toggleFilter(option.id)"
>
{{ option.label }}
</button>
</div>
<ButtonStyled type="transparent" hover-color-fill="none">
<button :disabled="refreshingAll" @click="refreshAllWorlds">
<RefreshCwIcon :class="refreshingAll ? 'animate-spin' : ''" />
{{ formatMessage(commonMessages.refreshButton) }}
</button>
</ButtonStyled>
</div>
<FilterBar v-model="filters" :options="filterOptions" show-all-options />
<div class="flex flex-col w-full gap-2">
<WorldItem
v-for="world in filteredWorlds"
@@ -92,51 +132,49 @@
/>
</div>
</div>
<div v-else class="w-full max-w-[48rem] mx-auto flex flex-col mt-6">
<RadialHeader class="">
<div class="flex items-center gap-6 w-[32rem] mx-auto">
<img src="@/assets/sad-modrinth-bot.webp" alt="" aria-hidden="true" class="h-24" />
<span class="text-contrast font-bold text-xl"> You don't have any worlds yet. </span>
</div>
</RadialHeader>
<div class="flex gap-2 mt-4 mx-auto">
<ButtonStyled>
<button @click="addServerModal?.show()">
<PlusIcon aria-hidden="true" />
Add a server
<EmptyState
v-else
type="empty-inbox"
:heading="formatMessage(messages.noWorldsHeading)"
:description="formatMessage(messages.noWorldsDescription)"
>
<template #actions>
<ButtonStyled type="outlined">
<button class="!h-10 !border-button-bg !border-[1px]" @click="addServerModal?.show()">
<PlusIcon class="size-5" />
{{ formatMessage(messages.addServer) }}
</button>
</ButtonStyled>
<ButtonStyled>
<button :disabled="refreshingAll" @click="refreshAllWorlds">
<template v-if="refreshingAll">
<SpinnerIcon aria-hidden="true" class="animate-spin" />
Refreshing...
</template>
<template v-else>
<UpdatedIcon aria-hidden="true" />
Refresh
</template>
<ButtonStyled color="brand">
<button
class="!h-10 flex items-center gap-2"
@click="
router.push({ path: '/browse/server', query: { i: instance.path, from: 'worlds' } })
"
>
<CompassIcon class="size-5" />
<span>{{ formatMessage(messages.browseServers) }}</span>
</button>
</ButtonStyled>
</div>
</div>
</template>
</EmptyState>
</template>
<script setup lang="ts">
import { PlusIcon, SearchIcon, SpinnerIcon, UpdatedIcon } from '@modrinth/assets'
import { CompassIcon, FilterIcon, PlusIcon, RefreshCwIcon, SearchIcon } from '@modrinth/assets'
import {
ButtonStyled,
commonMessages,
defineMessages,
FilterBar,
type FilterBarOption,
EmptyState,
GAME_MODES,
type GameVersion,
injectNotificationManager,
RadialHeader,
StyledInput,
useVIntl,
} from '@modrinth/ui'
import { platform } from '@tauri-apps/plugin-os'
import { computed, onUnmounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { useRoute, useRouter } from 'vue-router'
import type ContextMenu from '@/components/ui/ContextMenu.vue'
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
@@ -176,11 +214,80 @@ import {
type World,
} from '@/helpers/worlds.ts'
import { injectServerInstall } from '@/providers/server-install'
import { handleSevereError } from '@/store/error.js'
import { ensureManagedServerWorldExists, getServerAddress } from '@/store/install'
const messages = defineMessages({
removeServerTitle: {
id: 'app.instance.worlds.remove-server-title',
defaultMessage: 'Are you sure you want to remove {name}?',
},
removeServerDescription: {
id: 'app.instance.worlds.remove-server-description',
defaultMessage:
"'{name}' will be removed from your list, including in-game, and there will be no way to recover it.",
},
removeServerDescriptionWithAddress: {
id: 'app.instance.worlds.remove-server-description-with-address',
defaultMessage:
"'{name}' ({address}) will be removed from your list, including in-game, and there will be no way to recover it.",
},
deleteWorldTitle: {
id: 'app.instance.worlds.delete-world-title',
defaultMessage: 'Are you sure you want to permanently delete this world?',
},
deleteWorldDescription: {
id: 'app.instance.worlds.delete-world-description',
defaultMessage:
"'{name}' will be **permanently deleted**, and there will be no way to recover it.",
},
searchWorldsPlaceholder: {
id: 'app.instance.worlds.search-worlds-placeholder',
defaultMessage: 'Search {count} worlds...',
},
addServer: {
id: 'app.instance.worlds.add-server',
defaultMessage: 'Add server',
},
browseServers: {
id: 'app.instance.worlds.browse-servers',
defaultMessage: 'Browse servers',
},
noWorldsHeading: {
id: 'app.instance.worlds.no-worlds-heading',
defaultMessage: 'No servers or worlds added',
},
noWorldsDescription: {
id: 'app.instance.worlds.no-worlds-description',
defaultMessage: 'Add a server or browse to get started',
},
thisServer: {
id: 'app.instance.worlds.this-server',
defaultMessage: 'this server',
},
vanillaFilter: {
id: 'app.instance.worlds.filter-vanilla',
defaultMessage: 'Vanilla',
},
moddedFilter: {
id: 'app.instance.worlds.filter-modded',
defaultMessage: 'Modded',
},
onlineFilter: {
id: 'app.instance.worlds.filter-online',
defaultMessage: 'Online',
},
offlineFilter: {
id: 'app.instance.worlds.filter-offline',
defaultMessage: 'Offline',
},
})
const { formatMessage } = useVIntl()
const { handleError } = injectNotificationManager()
const { playServerProject } = injectServerInstall()
const route = useRoute()
const router = useRouter()
const addServerModal = ref<InstanceType<typeof AddServerModal>>()
const editServerModal = ref<InstanceType<typeof EditServerModal>>()
@@ -211,9 +318,32 @@ function play(world: World) {
emit('play', world)
}
const filters = ref<string[]>([])
const selectedFilters = ref<string[]>([])
const searchFilter = ref('')
function filterPillClass(isActive: boolean) {
return [
'cursor-pointer rounded-full border border-solid px-3 py-1.5 text-base font-semibold leading-5 transition-all duration-100 active:scale-[0.97]',
isActive
? 'border-green bg-brand-highlight text-brand'
: 'border-surface-5 bg-surface-4 text-primary hover:bg-surface-5',
]
}
function toggleFilter(id: string) {
const idx = selectedFilters.value.indexOf(id)
if (idx >= 0) {
selectedFilters.value.splice(idx, 1)
} else {
selectedFilters.value.push(id)
if (id === 'singleplayer') {
selectedFilters.value = selectedFilters.value.filter((f) => f !== 'online' && f !== 'offline')
} else if (id === 'online' || id === 'offline') {
selectedFilters.value = selectedFilters.value.filter((f) => f !== 'singleplayer')
}
}
}
const refreshingAll = ref(false)
const hadNoWorlds = ref(true)
const startingInstance = ref(false)
@@ -371,6 +501,12 @@ async function editServer(server: ServerWorld) {
async function removeServer(server: ServerWorld) {
await remove_server_from_profile(instance.value.path, server.index).catch(handleError)
worlds.value = worlds.value.filter((w) => w.type !== 'server' || w.index !== server.index)
let serverIdx = 0
for (const w of worlds.value) {
if (w.type === 'server') {
w.index = serverIdx++
}
}
}
async function editWorld(path: string, name: string, removeIcon: boolean) {
@@ -393,7 +529,7 @@ async function deleteWorld(world: SingleplayerWorld) {
}
function handleJoinError(err: Error) {
handleError(err)
handleSevereError(err, { profilePath: instance.value.path })
startingInstance.value = false
worldPlaying.value = undefined
}
@@ -498,58 +634,83 @@ const dedupedWorlds = computed(() => {
})
const filterOptions = computed(() => {
const options: FilterBarOption[] = []
const options: { id: string; label: string }[] = []
const hasSingleplayer = dedupedWorlds.value.some((x) => x.type === 'singleplayer')
const hasServer = dedupedWorlds.value.some((x) => x.type === 'server')
if (dedupedWorlds.value.some((x) => x.type === 'singleplayer') && hasServer) {
options.push({
id: 'singleplayer',
message: messages.singleplayer,
})
options.push({
id: 'server',
message: messages.server,
})
const hasStatusFilter =
selectedFilters.value.includes('online') || selectedFilters.value.includes('offline')
if (hasSingleplayer && hasServer && !hasStatusFilter) {
options.push({ id: 'singleplayer', label: formatMessage(commonMessages.singleplayerLabel) })
}
if (hasServer) {
// add available filter if there's any offline ("unavailable") servers AND there's any singleplayer worlds or available servers
if (
dedupedWorlds.value.some(
(x) =>
x.type === 'server' &&
!serverData.value[x.address]?.status &&
!serverData.value[x.address]?.refreshing,
) &&
dedupedWorlds.value.some(
(x) =>
x.type === 'singleplayer' ||
(x.type === 'server' &&
serverData.value[x.address]?.status &&
!serverData.value[x.address]?.refreshing),
)
) {
options.push({
id: 'available',
message: messages.available,
})
const servers = dedupedWorlds.value.filter((x) => x.type === 'server')
const hasVanilla = servers.some((x) => x.content_kind !== 'modpack')
const hasModded = servers.some((x) => x.content_kind === 'modpack')
if (hasVanilla && hasModded) {
options.push({ id: 'vanilla', label: formatMessage(messages.vanillaFilter) })
options.push({ id: 'modded', label: formatMessage(messages.moddedFilter) })
}
if (!selectedFilters.value.includes('singleplayer')) {
const hasOnline = servers.some((x) => !!serverData.value[x.address]?.status)
const hasOffline = servers.some((x) => !serverData.value[x.address]?.status)
if (hasOnline && hasOffline) {
options.push({ id: 'online', label: formatMessage(messages.onlineFilter) })
options.push({ id: 'offline', label: formatMessage(messages.offlineFilter) })
}
}
}
return options
})
watch(filterOptions, (options) => {
const validIds = new Set(options.map((opt) => opt.id))
const cleaned = selectedFilters.value.filter((f) => validIds.has(f))
if (cleaned.length !== selectedFilters.value.length) {
selectedFilters.value = cleaned
}
})
const filteredWorlds = computed(() =>
dedupedWorlds.value.filter((x) => {
const availableFilter = filters.value.includes('available')
const typeFilter = filters.value.includes('server') || filters.value.includes('singleplayer')
if (searchFilter.value && !x.name.toLowerCase().includes(searchFilter.value.toLowerCase())) {
return false
}
return (
(!typeFilter || filters.value.includes(x.type)) &&
(!availableFilter || x.type !== 'server' || serverData.value[x.address]?.status) &&
(!searchFilter.value || x.name.toLowerCase().includes(searchFilter.value.toLowerCase()))
)
if (selectedFilters.value.length === 0) return true
const hasSingleplayerFilter = selectedFilters.value.includes('singleplayer')
const typeFilters = selectedFilters.value.filter((f) => f === 'vanilla' || f === 'modded')
const statusFilters = selectedFilters.value.filter((f) => f === 'online' || f === 'offline')
if (x.type === 'singleplayer') {
return hasSingleplayerFilter || (typeFilters.length === 0 && statusFilters.length === 0)
}
if (hasSingleplayerFilter && typeFilters.length === 0 && statusFilters.length === 0) {
return false
}
let passesType = true
if (typeFilters.length > 0) {
const isModded = x.content_kind === 'modpack'
passesType =
(typeFilters.includes('modded') && isModded) ||
(typeFilters.includes('vanilla') && !isModded)
}
let passesStatus = true
if (statusFilters.length > 0) {
const isOnline = !!serverData.value[x.address]?.status
passesStatus =
(statusFilters.includes('online') && isOnline) ||
(statusFilters.includes('offline') && !isOnline)
}
return passesType && passesStatus
}),
)
@@ -588,19 +749,4 @@ async function proceedDeleteWorld() {
onUnmounted(() => {
unlistenProfile()
})
const messages = defineMessages({
singleplayer: {
id: 'instance.worlds.type.singleplayer',
defaultMessage: 'Singleplayer',
},
server: {
id: 'instance.worlds.type.server',
defaultMessage: 'Server',
},
available: {
id: 'instance.worlds.filter.available',
defaultMessage: 'Available',
},
})
</script>
@@ -1,7 +1,8 @@
import Files from './Files.vue'
import Index from './Index.vue'
import Logs from './Logs.vue'
import Mods from './Mods.vue'
import Overview from './Overview.vue'
import Worlds from './Worlds.vue'
export { Index, Logs, Mods, Overview, Worlds }
export { Files, Index, Logs, Mods, Overview, Worlds }
@@ -1,11 +1,10 @@
<script setup lang="ts">
import { PlusIcon } from '@modrinth/assets'
import { Button, injectNotificationManager } from '@modrinth/ui'
import { Button, injectNotificationManager, NavTabs } from '@modrinth/ui'
import { inject, onUnmounted, ref, shallowRef } from 'vue'
import { useRoute } from 'vue-router'
import { NewInstanceImage } from '@/assets/icons'
import NavTabs from '@/components/ui/NavTabs.vue'
import { profile_listener } from '@/helpers/events.js'
import { list } from '@/helpers/profile.js'
import { useBreadcrumbs } from '@/store/breadcrumbs.js'
+18 -6
View File
@@ -5,7 +5,7 @@
v-if="!isServerProject"
:project="data"
:tags="{ loaders: allLoaders, gameVersions: allGameVersions }"
:v3-metadata="projectV3"
:project-v3="projectV3"
class="project-sidebar-section"
/>
<ProjectSidebarServerInfo
@@ -170,10 +170,7 @@
},
{
label: 'Versions',
href: {
path: `/project/${$route.params.id}/versions`,
query: instanceFilters,
},
href: versionsHref,
subpages: ['version'],
shown: projectV3?.minecraft_server == null,
},
@@ -224,6 +221,7 @@ import {
import {
ButtonStyled,
injectNotificationManager,
NavTabs,
OverflowMenu,
ProjectBackgroundGradient,
ProjectHeader,
@@ -242,7 +240,6 @@ import { useRoute, useRouter } from 'vue-router'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
import NavTabs from '@/components/ui/NavTabs.vue'
import {
get_organization,
get_project,
@@ -318,6 +315,21 @@ const instanceFilters = computed(() => {
return { l: loaders, g: instance.value.game_version }
})
const versionsHref = computed(() => {
const base = `/project/${route.params.id}/versions`
const filters = instanceFilters.value
const params = new URLSearchParams()
for (const [key, val] of Object.entries(filters)) {
if (Array.isArray(val)) {
for (const v of val) params.append(key, v)
} else if (val) {
params.append(key, String(val))
}
}
const qs = params.toString()
return qs ? `${base}?${qs}` : base
})
const [allLoaders, allGameVersions] = await Promise.all([
get_loaders().catch(handleError).then(ref),
get_game_versions().catch(handleError).then(ref),
@@ -133,6 +133,8 @@ export function createContentInstall(opts: {
title: string
icon_url?: string | null
project_type?: string
organization?: string | null
team?: string
},
version?: Labrinth.Versions.v2.Version,
) {
@@ -164,6 +166,60 @@ export function createContentInstall(opts: {
if (items.some((i) => i.file_name === placeholder.file_name)) return
next.set(instancePath, [...items, placeholder])
installingItems.value = next
if (project.organization) {
get_organization(project.organization)
.then((org: { id: string; slug: string; name: string; icon_url?: string }) => {
updateInstallingItem(instancePath, placeholder.file_name, {
owner: {
id: org.id,
name: org.name,
avatar_url: org.icon_url,
type: 'organization',
},
})
})
.catch(() => {})
} else if (project.team) {
get_team(project.team)
.then(
(
members: {
user: { id: string; username: string; avatar_url?: string }
is_owner: boolean
}[],
) => {
const owner = members.find((m) => m.is_owner)
if (owner) {
updateInstallingItem(instancePath, placeholder.file_name, {
owner: {
id: owner.user.id,
name: owner.user.username,
avatar_url: owner.user.avatar_url,
type: 'user',
},
})
}
},
)
.catch(() => {})
}
}
function updateInstallingItem(
instancePath: string,
fileName: string,
updates: Partial<ContentItem>,
) {
const next = new Map(installingItems.value)
const items = next.get(instancePath)
if (!items) return
const index = items.findIndex((i) => i.file_name === fileName)
if (index === -1) return
const updated = [...items]
updated[index] = { ...updated[index], ...updates }
next.set(instancePath, updated)
installingItems.value = next
}
function removeInstallingItems(instancePath: string, projectIds: string[]) {
@@ -1,10 +1,10 @@
import { createContext } from '@modrinth/ui'
import type { Ref } from 'vue'
import type { ComputedRef, Ref } from 'vue'
import type { GameInstance } from '@/helpers/types'
export interface InstanceSettingsContext {
instance: GameInstance
instance: ComputedRef<GameInstance>
offline?: boolean
isMinecraftServer: Ref<boolean>
onUnlinked: () => void
@@ -0,0 +1,29 @@
import type { Labrinth } from '@modrinth/api-client'
import { type AuthProvider, provideAuth } from '@modrinth/ui'
import { type Ref, ref, watchEffect } from 'vue'
type AppCredentials = {
session?: string | null
user?: Labrinth.Users.v2.User | null
}
export function setupAuthProvider(
credentials: Ref<AppCredentials | null | undefined>,
requestSignIn: (redirectPath: string) => void | Promise<void>,
) {
const sessionToken = ref<string | null>(null)
const user = ref<Labrinth.Users.v2.User | null>(null)
const authProvider: AuthProvider = {
session_token: sessionToken,
user,
requestSignIn,
}
watchEffect(() => {
sessionToken.value = credentials.value?.session ?? null
user.value = credentials.value?.user ?? null
})
provideAuth(authProvider)
}
+11 -1
View File
@@ -41,7 +41,8 @@ export default new createRouter({
name: 'Discover content',
component: Pages.Browse,
meta: {
breadcrumb: [{ name: 'Discover content' }],
useContext: true,
breadcrumb: [{ name: '?BrowseTitle' }],
},
},
{
@@ -178,6 +179,15 @@ export default new createRouter({
breadcrumb: [{ name: '?Instance', link: '/instance/{id}/' }, { name: 'Content' }],
},
},
{
path: 'files',
name: 'Files',
component: Instance.Files,
meta: {
useRootContext: true,
breadcrumb: [{ name: '?Instance', link: '/instance/{id}/' }, { name: 'Files' }],
},
},
{
path: 'logs',
name: 'Logs',
+129 -24
View File
@@ -2,7 +2,7 @@
import dayjs from 'dayjs'
import { get_project, get_version_many } from '@/helpers/cache.js'
import { get_project, get_version, get_version_many } from '@/helpers/cache.js'
import { add_project_from_version, check_installed } from '@/helpers/profile.js'
import {
add_server_to_profile,
@@ -49,32 +49,137 @@ export const isVersionCompatible = (version, project, instance) => {
}
export const installVersionDependencies = async (profile, version, onDepInstalling) => {
for (const dep of version.dependencies) {
if (dep.dependency_type !== 'required') continue
// disallow fabric api install on quilt
if (dep.project_id === 'P7dR8mSH' && profile.loader === 'quilt') continue
if (dep.version_id) {
if (dep.project_id && (await check_installed(profile.path, dep.project_id))) continue
if (dep.project_id && onDepInstalling) {
const depProject = await get_project(dep.project_id, 'bypass').catch(() => null)
if (depProject) onDepInstalling(depProject)
}
await add_project_from_version(profile.path, dep.version_id)
} else {
if (dep.project_id && (await check_installed(profile.path, dep.project_id))) continue
const projectNames = new Map()
const storeProjectName = (p) => {
if (p?.id && p.title) projectNames.set(p.id, p.title)
}
const depProject = await get_project(dep.project_id, 'bypass')
if (onDepInstalling) onDepInstalling(depProject)
const visitedVersions = new Set()
const announcedProjects = new Set()
const queuedVersionIds = new Set()
const queuedProjectVersions = new Map()
const queuedInstalls = []
const installedProjectCache = new Map()
const depVersions = (await get_version_many(depProject.versions, 'bypass')).sort(
(a, b) => dayjs(b.date_published) - dayjs(a.date_published),
)
const latest = findPreferredVersion(depVersions, dep, profile)
if (latest) {
await add_project_from_version(profile.path, latest.id)
}
const isProjectInstalled = async (projectId) => {
if (!projectId) return false
if (installedProjectCache.has(projectId)) {
return installedProjectCache.get(projectId)
}
const installed = await check_installed(profile.path, projectId)
installedProjectCache.set(projectId, installed)
return installed
}
const queueInstall = async (projectId, resolvedVersion) => {
if (!resolvedVersion?.id) return false
const versionId = resolvedVersion.id
const resolvedProjectId = projectId ?? resolvedVersion.project_id ?? null
if (resolvedProjectId) {
if (await isProjectInstalled(resolvedProjectId)) return false
const existingVersionId = queuedProjectVersions.get(resolvedProjectId)
if (existingVersionId && existingVersionId !== versionId) return false
if (existingVersionId === versionId) return false
}
if (queuedVersionIds.has(versionId)) return false
queuedVersionIds.add(versionId)
if (resolvedProjectId) {
queuedProjectVersions.set(resolvedProjectId, versionId)
}
queuedInstalls.push({ versionId, projectId: resolvedProjectId })
return true
}
const announceDependency = async (projectId, resolvedVersion) => {
if (!onDepInstalling || !projectId) return
if (announcedProjects.has(projectId)) return
const depProject = await get_project(projectId, 'bypass').catch(() => null)
if (!depProject) return
storeProjectName(depProject)
onDepInstalling(depProject, resolvedVersion ?? undefined)
announcedProjects.add(projectId)
}
const resolveDependency = async (dep) => {
let depVersion = null
let depProjectId = dep.project_id ?? null
if (dep.version_id) {
depVersion = await get_version(dep.version_id, 'bypass').catch(() => null)
if (!depVersion) return null
depProjectId = depProjectId ?? depVersion.project_id ?? null
if (depProjectId && !projectNames.has(depProjectId)) {
const p = await get_project(depProjectId, 'bypass').catch(() => null)
storeProjectName(p)
}
} else if (dep.project_id) {
const depProject = await get_project(dep.project_id, 'bypass').catch(() => null)
if (!depProject) return null
storeProjectName(depProject)
const depVersions = await get_version_many(depProject.versions, 'bypass').catch(() => [])
depVersion = findPreferredVersion(
depVersions.sort((a, b) => dayjs(b.date_published) - dayjs(a.date_published)),
dep,
profile,
)
if (!depVersion) return null
depProjectId = dep.project_id
} else {
return null
}
return { depVersion, depProjectId }
}
const collectDependenciesForVersion = async (inputVersion) => {
if (!inputVersion?.id || visitedVersions.has(inputVersion.id)) return
visitedVersions.add(inputVersion.id)
if (inputVersion.project_id && !projectNames.has(inputVersion.project_id)) {
const p = await get_project(inputVersion.project_id, 'bypass').catch(() => null)
storeProjectName(p)
}
for (const dep of inputVersion.dependencies ?? []) {
if (dep.dependency_type !== 'required') continue
if (dep.project_id === 'P7dR8mSH' && profile.loader === 'quilt') continue
const resolved = await resolveDependency(dep, inputVersion)
if (!resolved) continue
const { depVersion, depProjectId } = resolved
const queued = await queueInstall(depProjectId, depVersion)
if (queued && depProjectId) {
await announceDependency(depProjectId, depVersion)
}
await collectDependenciesForVersion(depVersion)
}
}
await collectDependenciesForVersion(version)
if (queuedInstalls.length === 0) return
const batchSize = 8
for (let i = 0; i < queuedInstalls.length; i += batchSize) {
const batch = queuedInstalls.slice(i, i + batchSize)
await Promise.all(
batch.map(async ({ versionId }) => {
await add_project_from_version(profile.path, versionId)
}),
)
}
}
+7 -4
View File
@@ -70,14 +70,17 @@ export default defineConfig({
// https://v2.tauri.app/reference/environment-variables/#tauri-cli-hook-commands
envPrefix: ['VITE_', 'TAURI_'],
build: {
rolldownOptions: {
onwarn(warning, defaultHandler) {
if (warning.code === 'INEFFECTIVE_DYNAMIC_IMPORT') return
defaultHandler(warning)
},
},
// Tauri supports es2021
target: process.env.TAURI_ENV_PLATFORM == 'windows' ? 'chrome105' : 'safari13', // eslint-disable-line turbo/no-undeclared-env-vars
// don't minify for debug builds
minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false, // eslint-disable-line turbo/no-undeclared-env-vars
minify: !process.env.TAURI_ENV_DEBUG, // eslint-disable-line turbo/no-undeclared-env-vars
// produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_ENV_DEBUG, // eslint-disable-line turbo/no-undeclared-env-vars
commonjsOptions: {
esmExternals: true,
},
},
})
+2
View File
@@ -8,6 +8,7 @@ repository = "https://github.com/modrinth/code/apps/app/"
license = "GPL-3.0-only"
[dependencies]
async_zip = { workspace = true, features = ["deflate", "tokio-fs"] }
chrono = { workspace = true }
daedalus = { workspace = true }
dashmap = { workspace = true }
@@ -28,6 +29,7 @@ tauri = { workspace = true, features = [
] }
tauri-plugin-deep-link = { workspace = true }
tauri-plugin-dialog = { workspace = true }
tauri-plugin-fs = { workspace = true }
tauri-plugin-http = { workspace = true }
tauri-plugin-opener = { workspace = true }
tauri-plugin-os = { workspace = true }
+8
View File
@@ -263,6 +263,14 @@ fn main() {
DefaultPermissionRule::AllowAllCommands,
),
)
.plugin(
"files",
InlinedPlugin::new()
.commands(&["file_extract_zip", "file_save_as"])
.default_permission(
DefaultPermissionRule::AllowAllCommands,
),
)
.plugin(
"friends",
InlinedPlugin::new()
+27
View File
@@ -25,6 +25,32 @@
"allow": [{ "url": "https://modrinth.com/*" }, { "url": "https://*.modrinth.com/*" }]
},
"dialog:allow-save",
"fs:allow-read-dir",
"fs:allow-read-file",
"fs:allow-read-text-file",
"fs:allow-write-file",
"fs:allow-write-text-file",
"fs:allow-create",
"fs:allow-remove",
"fs:allow-rename",
"fs:allow-copy-file",
"fs:allow-stat",
"fs:allow-exists",
"fs:allow-mkdir",
{
"identifier": "fs:scope",
"allow": [
{ "path": "$APPDATA/profiles" },
{ "path": "$APPDATA/profiles/**" },
{ "path": "$APPCONFIG/profiles" },
{ "path": "$APPCONFIG/profiles/**" },
{ "path": "$CONFIG/profiles" },
{ "path": "$CONFIG/profiles/**" }
]
},
"auth:default",
"import:default",
"jre:default",
@@ -37,6 +63,7 @@
"process:default",
"profile:default",
"cache:default",
"files:default",
"settings:default",
"tags:default",
"utils:default",
+164
View File
@@ -0,0 +1,164 @@
use crate::api::Result;
use async_zip::base::read::seek::ZipFileReader;
use serde::Serialize;
use std::io::Cursor;
use tauri::Runtime;
use tauri_plugin_dialog::DialogExt;
use theseus::profile::get_full_path;
pub fn init<R: Runtime>() -> tauri::plugin::TauriPlugin<R> {
tauri::plugin::Builder::new("files")
.invoke_handler(tauri::generate_handler![
file_extract_zip,
file_save_as,
])
.build()
}
#[derive(Serialize)]
pub struct ExtractDryRunResult {
modpack_name: Option<String>,
conflicting_files: Vec<String>,
}
#[tauri::command]
pub async fn file_extract_zip(
instance_path: &str,
file_path: &str,
override_conflicts: bool,
dry_run: bool,
) -> Result<Option<ExtractDryRunResult>> {
let base = get_full_path(instance_path).await?;
let zip_path = base.join(file_path);
let canonical_zip = tokio::fs::canonicalize(&zip_path).await?;
let canonical_base = tokio::fs::canonicalize(&base).await?;
if !canonical_zip.starts_with(&canonical_base) {
return Err(theseus::Error::from(theseus::ErrorKind::OtherError(
"file_path escapes the instance directory".to_string(),
))
.into());
}
let extract_dir = zip_path
.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| base.clone());
let file_bytes = tokio::fs::read(&zip_path).await?;
let reader = Cursor::new(file_bytes);
let zip_reader = ZipFileReader::with_tokio(reader).await.map_err(|e| {
theseus::Error::from(theseus::ErrorKind::OtherError(format!(
"Failed to read zip file: {e}"
)))
})?;
let entries: Vec<(usize, String)> = zip_reader
.file()
.entries()
.iter()
.enumerate()
.filter_map(|(i, entry)| {
let name = entry.filename().as_str().ok()?.to_string();
if name.ends_with('/') {
None
} else {
Some((i, name))
}
})
.collect();
if dry_run {
let mut conflicting_files = Vec::new();
let canonical_extract = tokio::fs::canonicalize(&extract_dir).await?;
for (_, name) in &entries {
let target = extract_dir.join(name);
if let Some(parent) = target.parent() {
let normalized = parent
.canonicalize()
.unwrap_or_else(|_| extract_dir.join(parent));
if !normalized.starts_with(&canonical_extract) {
continue;
}
}
if target.exists() {
conflicting_files.push(name.clone());
}
}
return Ok(Some(ExtractDryRunResult {
modpack_name: None,
conflicting_files,
}));
}
let canonical_extract_dir = tokio::fs::canonicalize(&extract_dir).await?;
let mut zip_reader = zip_reader;
for (index, name) in &entries {
let target = extract_dir.join(name);
if !override_conflicts && target.exists() {
continue;
}
if let Some(parent) = target.parent() {
tokio::fs::create_dir_all(parent).await?;
let canonical_parent = tokio::fs::canonicalize(parent).await?;
if !canonical_parent.starts_with(&canonical_extract_dir) {
continue;
}
}
let mut file_bytes = Vec::new();
let mut entry_reader =
zip_reader.reader_with_entry(*index).await.map_err(|e| {
theseus::Error::from(theseus::ErrorKind::OtherError(format!(
"Failed to read zip entry: {e}"
)))
})?;
entry_reader
.read_to_end_checked(&mut file_bytes)
.await
.map_err(|e| {
theseus::Error::from(theseus::ErrorKind::OtherError(format!(
"Failed to extract zip entry: {e}"
)))
})?;
tokio::fs::write(&target, &file_bytes).await?;
}
Ok(None)
}
#[tauri::command]
pub async fn file_save_as<R: Runtime>(
app: tauri::AppHandle<R>,
instance_path: &str,
file_path: &str,
) -> Result<()> {
let base = get_full_path(instance_path).await?;
let source = base.join(file_path);
let file_name = source
.file_name()
.unwrap_or_default()
.to_string_lossy()
.to_string();
let (tx, rx) = tokio::sync::oneshot::channel();
app.dialog()
.file()
.set_file_name(&file_name)
.save_file(|path| {
let _ = tx.send(path);
});
if let Some(dest) = rx.await.unwrap_or(None) {
let dest_path = std::path::PathBuf::try_from(dest).map_err(|e| {
theseus::Error::from(theseus::ErrorKind::OtherError(format!(
"Invalid save path: {e}"
)))
})?;
tokio::fs::copy(&source, &dest_path).await?;
}
Ok(())
}
+1
View File
@@ -19,6 +19,7 @@ pub mod utils;
pub mod ads;
pub mod cache;
pub mod files;
pub mod friends;
pub mod worlds;
+12 -4
View File
@@ -151,12 +151,20 @@ pub async fn add_server_to_profile(
name: String,
address: String,
pack_status: ServerPackStatus,
project_id: Option<String>,
content_kind: Option<String>,
) -> Result<usize> {
let path = get_full_path(path).await?;
Ok(
worlds::add_server_to_profile(&path, name, address, pack_status)
.await?,
let full_path = get_full_path(path).await?;
Ok(worlds::add_server_to_profile(
&full_path,
path,
name,
address,
pack_status,
project_id,
content_kind,
)
.await?)
}
#[tauri::command]
+2
View File
@@ -152,6 +152,7 @@ fn main() {
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_deep_link::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_opener::init())
.plugin(
tauri_plugin_window_state::Builder::default()
@@ -229,6 +230,7 @@ fn main() {
.plugin(api::tags::init())
.plugin(api::utils::init())
.plugin(api::cache::init())
.plugin(api::files::init())
.plugin(api::ads::init())
.plugin(api::friends::init())
.plugin(api::worlds::init())
+2
View File
@@ -33,6 +33,8 @@ pub enum ErrorKind {
Tracing(#[from] tracing::subscriber::SetGlobalDefaultError),
#[error("Zip error: {0}")]
Zip(#[from] async_zip::error::ZipError),
#[error("Failed to parse an integer: {0}")]
ParseIntError(#[from] std::num::ParseIntError),
}
#[derive(Debug)]
+32 -12
View File
@@ -114,12 +114,12 @@ pub async fn fetch_neo(
}
let forge_versions = fetch_xml::<Metadata>(
"https://maven.neoforged.net/net/neoforged/forge/maven-metadata.xml",
"https://maven.neoforged.net/releases/net/neoforged/forge/maven-metadata.xml",
&semaphore,
)
.await?;
let neo_versions = fetch_xml::<Metadata>(
"https://maven.neoforged.net/net/neoforged/neoforge/maven-metadata.xml",
"https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml",
&semaphore,
)
.await?;
@@ -133,7 +133,7 @@ pub async fn fetch_neo(
Ok(ForgeVersion {
format_version: 2,
installer_url: format!("https://maven.neoforged.net/net/neoforged/forge/{loader_version}/forge-{loader_version}-installer.jar"),
installer_url: format!("https://maven.neoforged.net/releases/net/neoforged/forge/{loader_version}/forge-{loader_version}-installer.jar"),
raw: loader_version,
loader_version: version_split,
game_version: "1.20.1".to_string(), // All NeoForge Forge versions are for 1.20.1
@@ -141,9 +141,16 @@ pub async fn fetch_neo(
}).chain(neo_versions.versioning.versions.version.into_iter().map(|loader_version| {
let mut parts = loader_version.split('.');
// NeoForge Forge versions are in this format: 20.2.29-beta, 20.6.119
// Where the first number is the major MC version, the second is the minor MC version, and the third is the NeoForge version
let major = parts.next().ok_or_else(
// NeoForge Forge versions are in either of these formats:
// - 20.2.29-beta, 20.6.119
// - 26.1.0.10-beta, 26.1.0.16
//
// The first format is the "modern" format for Minecraft versions starting with 1, where the first number is the major MC version,
// the second is the minor MC version, and the third is the NeoForge version.
//
// The second format is the "new-modern" format for Minecraft versions in year-based format, where the first three numbers
// are the Minecraft version (year.release.hotfix), and the fourth, the NeoForge release version, with an optional "beta" suffix.
let major_or_year = parts.next().ok_or_else(
|| crate::ErrorKind::InvalidInput(format!("Unable to find major game version for NeoForge {loader_version}"))
)?;
@@ -151,15 +158,28 @@ pub async fn fetch_neo(
|| crate::ErrorKind::InvalidInput(format!("Unable to find minor game version for NeoForge {loader_version}"))
)?;
let game_version = if minor == "0" {
format!("1.{major}")
} else {
format!("1.{major}.{minor}")
};
let major_or_year = major_or_year.parse::<u32>()?;
// Year-based MC versions started in 2026
let game_version = match major_or_year {
26.. => {
let hotfix = parts.next().ok_or_else(
|| crate::ErrorKind::InvalidInput(format!("Unable to find hotfix version for NeoForge {loader_version}"))
)?;
if hotfix == "0" {
format!("{major_or_year}.{minor}")
} else {
format!("{major_or_year}.{minor}.{hotfix}")
}
}
..26 if minor == "0" => format!("1.{major_or_year}"),
..26 => format!("1.{major_or_year}.{minor}"),
};
Ok(ForgeVersion {
format_version: 2,
installer_url: format!("https://maven.neoforged.net/net/neoforged/neoforge/{loader_version}/neoforge-{loader_version}-installer.jar"),
installer_url: format!("https://maven.neoforged.net/releases/net/neoforged/neoforge/{loader_version}/neoforge-{loader_version}-installer.jar"),
loader_version: loader_version.clone(),
raw: loader_version,
game_version,
@@ -446,13 +446,6 @@ textarea {
}
}
button,
input[type='button'] {
cursor: pointer;
border: none;
outline: 2px solid transparent;
}
kbd {
background-color: var(--color-code-bg);
color: var(--color-code-text);
@@ -30,6 +30,7 @@ import {
type OverflowMenuOption,
useFormatDateTime,
} from '@modrinth/ui'
import { NavTabs } from '@modrinth/ui'
import {
capitalizeString,
formatProjectType,
@@ -41,7 +42,6 @@ import dayjs from 'dayjs'
import { computed, reactive, ref, watch } from 'vue'
import type { UnsafeFile } from '~/components/ui/moderation/MaliciousSummaryModal.vue'
import NavTabs from '~/components/ui/NavTabs.vue'
import ThreadView from '~/components/ui/thread/ThreadView.vue'
const auth = await useAuth()
@@ -4,19 +4,19 @@
<div class="flex flex-col gap-4 md:w-[400px]">
<p class="m-0">
Are you sure you want to
<span class="lowercase">{{ confirmActionText }}</span> the server?
<span class="lowercase">{{ pendingAction }}</span> the server?
</p>
<Checkbox
v-model="dontAskAgain"
label="Don't ask me again"
class="text-sm"
:disabled="!powerAction"
:disabled="!pendingAction"
/>
<div class="flex flex-row gap-4">
<ButtonStyled type="standard" color="brand" @click="executePowerAction">
<button>
<CheckIcon class="h-5 w-5" />
{{ confirmActionText }} server
{{ pendingAction }} server
</button>
</ButtonStyled>
<ButtonStyled @click="resetPowerAction">
@@ -31,11 +31,11 @@
<NewModal
ref="detailsModal"
:header="`All of ${serverName || 'Server'} info`"
@close="closeDetailsModal"
:header="`All of ${server.name || 'Server'} info`"
@close="detailsModal?.hide()"
>
<ServerInfoLabels
:server-data="serverData"
:server-data="server"
:show-game-label="true"
:show-loader-label="true"
:uptime-seconds="uptimeSeconds"
@@ -43,33 +43,33 @@
class="mb-6 flex flex-col gap-2"
/>
<div v-if="flags.advancedDebugInfo" class="markdown-body">
<pre>{{ serverData }}</pre>
<pre>{{ server }}</pre>
</div>
<ButtonStyled type="standard" color="brand" @click="closeDetailsModal">
<ButtonStyled type="standard" color="brand" @click="detailsModal?.hide()">
<button class="w-full">Close</button>
</ButtonStyled>
</NewModal>
<div class="flex flex-row items-center gap-2 rounded-lg">
<ButtonStyled v-if="isInstalling" type="standard" color="brand">
<ButtonStyled v-if="isInstalling" type="standard" color="brand" size="large">
<button disabled class="flex-shrink-0">
<PanelSpinner class="size-5" /> Installing...
</button>
</ButtonStyled>
<template v-else>
<ButtonStyled v-if="showStopButton" type="transparent">
<ButtonStyled v-if="showStopButton" type="transparent" size="large">
<button :disabled="!canTakeAction" @click="initiateAction('Stop')">
<div class="flex gap-1">
<StopCircleIcon class="h-5 w-5" />
<span>{{ isStoppingState ? 'Stopping...' : 'Stop' }}</span>
<span>{{ isStopping ? 'Stopping...' : 'Stop' }}</span>
</div>
</button>
</ButtonStyled>
<ButtonStyled type="standard" color="brand">
<button v-tooltip="busyReason" :disabled="!canTakeAction" @click="handlePrimaryAction">
<div v-if="isTransitionState" class="grid place-content-center">
<ButtonStyled type="standard" color="brand" size="large">
<button v-tooltip="busyTooltip" :disabled="!canTakeAction" @click="handlePrimaryAction">
<div v-if="isTransitioning" class="grid place-content-center">
<LoadingIcon />
</div>
<component :is="isRunning ? UpdatedIcon : PlayIcon" v-else />
@@ -77,7 +77,7 @@
</button>
</ButtonStyled>
<ButtonStyled circular type="transparent">
<ButtonStyled circular type="transparent" size="large">
<TeleportOverflowMenu :options="[...menuOptions]">
<MoreVerticalIcon aria-hidden="true" />
<template #kill>
@@ -116,8 +116,16 @@ import {
UpdatedIcon,
XIcon,
} from '@modrinth/assets'
import { ButtonStyled, Checkbox, NewModal, ServerInfoLabels } from '@modrinth/ui'
import type { PowerAction as ServerPowerAction, ServerState } from '@modrinth/utils'
import {
ButtonStyled,
Checkbox,
injectModrinthClient,
injectModrinthServerContext,
injectNotificationManager,
NewModal,
ServerInfoLabels,
useVIntl,
} from '@modrinth/ui'
import { useStorage } from '@vueuse/core'
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
@@ -126,70 +134,60 @@ import LoadingIcon from './icons/LoadingIcon.vue'
import PanelSpinner from './PanelSpinner.vue'
import TeleportOverflowMenu from './TeleportOverflowMenu.vue'
const flags = useFeatureFlags()
interface PowerAction {
action: ServerPowerAction
nextState: ServerState
}
type PowerAction = 'Start' | 'Stop' | 'Restart' | 'Kill'
const props = defineProps<{
isOnline: boolean
isActioning: boolean
isInstalling: boolean
disabled: boolean
serverName?: string
serverData: object
disabled?: boolean
uptimeSeconds: number
busyReason?: string
}>()
const emit = defineEmits<{
(e: 'action', action: ServerPowerAction): void
}>()
const { formatMessage } = useVIntl()
const flags = useFeatureFlags()
const router = useRouter()
const serverId = router.currentRoute.value.params.id
const client = injectModrinthClient()
const { serverId, server, powerState, busyReasons } = injectModrinthServerContext()
const { addNotification } = injectNotificationManager()
const confirmActionModal = ref<InstanceType<typeof NewModal> | null>(null)
const detailsModal = ref<InstanceType<typeof NewModal> | null>(null)
const pendingAction = ref<PowerAction | null>(null)
const dontAskAgain = ref(false)
const userPreferences = useStorage(`pyro-server-${serverId}-preferences`, {
powerDontAskAgain: false,
})
const serverState = ref<ServerState>(props.isOnline ? 'running' : 'stopped')
const powerAction = ref<PowerAction | null>(null)
const dontAskAgain = ref(false)
const startingDelay = ref(false)
const isInstalling = computed(() => server.value.status === 'installing')
const isRunning = computed(() => powerState.value === 'running')
const isStopping = computed(() => powerState.value === 'stopping')
const isTransitioning = computed(
() => powerState.value === 'starting' || powerState.value === 'stopping',
)
const showStopButton = computed(() => isRunning.value || isStopping.value)
const busyTooltip = computed(() =>
busyReasons.value.length > 0 ? formatMessage(busyReasons.value[0].reason) : undefined,
)
const canTakeAction = computed(
() => !props.isActioning && !startingDelay.value && !isTransitionState.value && !props.busyReason,
() => !isTransitioning.value && !props.disabled && busyReasons.value.length === 0,
)
const isRunning = computed(() => serverState.value === 'running')
const isTransitionState = computed(() =>
['starting', 'stopping', 'restarting'].includes(serverState.value),
)
const isStoppingState = computed(() => serverState.value === 'stopping')
const showStopButton = computed(() => isRunning.value || isStoppingState.value)
const primaryActionText = computed(() => {
const states: Partial<Record<ServerState, string>> = {
starting: 'Starting...',
restarting: 'Restarting...',
running: 'Restart',
stopping: 'Stopping...',
stopped: 'Start',
switch (powerState.value) {
case 'starting':
return 'Starting...'
case 'stopping':
return 'Stopping...'
case 'running':
return 'Restart'
default:
return 'Start'
}
return states[serverState.value]
})
const confirmActionText = computed(() => {
if (!powerAction.value) return ''
return powerAction.value.action.charAt(0).toUpperCase() + powerAction.value.action.slice(1)
})
const menuOptions = computed(() => [
...(props.isInstalling
...(isInstalling.value
? []
: [
{
@@ -221,28 +219,31 @@ const menuOptions = computed(() => [
])
async function copyId() {
await navigator.clipboard.writeText(serverId as string)
await navigator.clipboard.writeText(serverId)
}
function initiateAction(action: ServerPowerAction) {
async function sendPowerAction(action: PowerAction) {
try {
await client.archon.servers_v0.power(serverId, action)
} catch (error) {
console.error(`Error performing ${action} on server:`, error)
addNotification({
type: 'error',
title: `Failed to ${action.toLowerCase()} server`,
text: 'An error occurred while performing this action.',
})
}
}
function initiateAction(action: PowerAction) {
if (!canTakeAction.value) return
const stateMap: Record<ServerPowerAction, ServerState> = {
Start: 'starting',
Stop: 'stopping',
Restart: 'restarting',
Kill: 'stopping',
}
if (action === 'Start') {
emit('action', action)
serverState.value = stateMap[action]
startingDelay.value = true
setTimeout(() => (startingDelay.value = false), 5000)
sendPowerAction(action)
return
}
powerAction.value = { action, nextState: stateMap[action] }
pendingAction.value = action
if (userPreferences.value.powerDontAskAgain) {
executePowerAction()
@@ -256,41 +257,20 @@ function handlePrimaryAction() {
}
function executePowerAction() {
if (!powerAction.value) return
if (!pendingAction.value) return
const { action, nextState } = powerAction.value
emit('action', action)
serverState.value = nextState
sendPowerAction(pendingAction.value)
if (dontAskAgain.value) {
userPreferences.value.powerDontAskAgain = true
}
if (action === 'Start') {
startingDelay.value = true
setTimeout(() => (startingDelay.value = false), 5000)
}
resetPowerAction()
}
function resetPowerAction() {
confirmActionModal.value?.hide()
powerAction.value = null
pendingAction.value = null
dontAskAgain.value = false
}
function closeDetailsModal() {
detailsModal.value?.hide()
}
watch(
() => props.isOnline,
(online) => (serverState.value = online ? 'running' : 'stopped'),
)
watch(
() => router.currentRoute.value.fullPath,
() => closeDetailsModal(),
)
</script>
@@ -3,7 +3,7 @@
<div
v-if="props.isVisible"
data-pyro-save-banner
class="fixed bottom-16 left-0 right-0 z-[6] mx-auto h-fit w-full max-w-4xl transition-all duration-300 sm:bottom-8"
class="fixed bottom-16 left-0 right-0 z-[10] mx-auto h-fit w-full max-w-4xl transition-all duration-300 sm:bottom-8"
>
<div class="mx-2 rounded-2xl border-2 border-solid border-button-border bg-bg-raised p-4">
<div class="flex flex-col items-center justify-between gap-2 md:flex-row">
@@ -18,8 +18,8 @@
</button>
</ButtonStyled>
<ButtonStyled v-if="props.restart" type="standard" color="brand">
<button :disabled="props.isUpdating" @click="saveAndRestart">
{{ props.isUpdating ? 'Saving...' : 'Save & restart' }}
<button :disabled="props.isUpdating || isTransitioning" @click="saveAndPower">
{{ powerButtonLabel }}
</button>
</ButtonStyled>
</div>
@@ -30,7 +30,8 @@
</template>
<script setup lang="ts">
import { ButtonStyled, injectModrinthClient } from '@modrinth/ui'
import { ButtonStyled, injectModrinthClient, injectModrinthServerContext } from '@modrinth/ui'
import { computed } from 'vue'
const props = defineProps<{
isUpdating: boolean
@@ -42,10 +43,23 @@ const props = defineProps<{
}>()
const client = injectModrinthClient()
const { powerState } = injectModrinthServerContext()
const saveAndRestart = async () => {
const isStopped = computed(() => powerState.value === 'stopped' || powerState.value === 'crashed')
const isTransitioning = computed(
() => powerState.value === 'starting' || powerState.value === 'stopping',
)
const powerButtonLabel = computed(() => {
if (props.isUpdating) return 'Saving...'
if (isTransitioning.value) return isStopped.value ? 'Save & start' : 'Save & restart'
return isStopped.value ? 'Save & start' : 'Save & restart'
})
const saveAndPower = async () => {
props.save()
await client.archon.servers_v0.power(props.serverId, 'Restart')
await client.archon.servers_v0.power(props.serverId, isStopped.value ? 'Start' : 'Restart')
}
</script>
@@ -38,6 +38,7 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
showProjectPageQuickServerButton: false,
newProjectGeneralSettings: false,
newProjectEnvironmentSettings: true,
archonSentryCapture: false,
hideRussiaCensorshipBanner: false,
disablePrettyProjectUrlRedirects: false,
hidePreviewBanner: false,
+4
View File
@@ -13,6 +13,8 @@ import {
} from '@modrinth/api-client'
import type { Ref } from 'vue'
import { useFeatureFlags } from '~/composables/featureFlags.ts'
async function getRateLimitKeyFromSecretsStore(): Promise<string | undefined> {
try {
const mod = 'cloudflare:workers'
@@ -28,6 +30,7 @@ export function createModrinthClient(
auth: Ref<{ token: string | undefined }>,
config: { apiBaseUrl: string; archonBaseUrl: string; rateLimitKey?: string },
): NuxtModrinthClient {
const flags = useFeatureFlags()
const optionalFeatures = [
import.meta.dev ? (new VerboseLoggingFeature() as AbstractFeature) : undefined,
].filter(Boolean) as AbstractFeature[]
@@ -35,6 +38,7 @@ export function createModrinthClient(
const clientConfig: NuxtClientConfig = {
labrinthBaseUrl: config.apiBaseUrl,
archonBaseUrl: config.archonBaseUrl,
archonSentryCapture: () => flags.value.archonSentryCapture,
rateLimitKey: config.rateLimitKey || getRateLimitKeyFromSecretsStore,
features: [
// for modrinth hosting
+8 -9
View File
@@ -473,7 +473,8 @@
<SettingsIcon aria-hidden="true" /> {{ formatMessage(commonMessages.settingsLabel) }}
</template>
<template #flags>
<ReportIcon aria-hidden="true" /> {{ formatMessage(messages.featureFlags) }}
<ToggleRightIcon aria-hidden="true" />
{{ formatMessage(commonSettingsMessages.featureFlags) }}
</template>
<template #projects>
<BoxIcon aria-hidden="true" /> {{ formatMessage(messages.projects) }}
@@ -585,9 +586,9 @@
<ScaleIcon aria-hidden="true" />
{{ formatMessage(commonMessages.moderationLabel) }}
</NuxtLink>
<NuxtLink v-if="flags.developerMode" class="iconified-button" to="/flags">
<ReportIcon aria-hidden="true" />
{{ formatMessage(messages.featureFlags) }}
<NuxtLink v-if="flags.developerMode" class="iconified-button" to="/settings/flags">
<ToggleRightIcon aria-hidden="true" />
{{ formatMessage(commonSettingsMessages.featureFlags) }}
</NuxtLink>
</template>
<NuxtLink class="iconified-button" to="/settings">
@@ -724,6 +725,7 @@ import {
SettingsIcon,
ShieldAlertIcon,
SunIcon,
ToggleRightIcon,
TransferIcon,
UserIcon,
UserSearchIcon,
@@ -734,6 +736,7 @@ import {
ButtonStyled,
commonMessages,
commonProjectTypeCategoryMessages,
commonSettingsMessages,
defineMessages,
injectModrinthClient,
OverflowMenu,
@@ -918,10 +921,6 @@ const messages = defineMessages({
id: 'layout.nav.upgrade-to-modrinth-plus',
defaultMessage: 'Upgrade to Modrinth+',
},
featureFlags: {
id: 'layout.nav.feature-flags',
defaultMessage: 'Feature flags',
},
projects: {
id: 'layout.nav.projects',
defaultMessage: 'Projects',
@@ -1045,7 +1044,7 @@ const userMenuOptions = computed(() => {
},
{
id: 'flags',
link: '/flags',
link: '/settings/flags',
shown: flags.value.developerMode,
},
{
@@ -38,6 +38,9 @@
"app-marketing.download.options-title": {
"message": "خيارات التنزيل"
},
"app-marketing.download.terms": {
"message": "بتنزيلك Modrinth App فإنك توافق على <terms-link>الشروط</terms-link> و <privacy-link>سياسة الخصوصية</privacy-link>."
},
"app-marketing.download.title": {
"message": "تنزيل Modrinth App (النسخة التجريبية)"
},
@@ -104,6 +107,9 @@
"app-marketing.features.performance.cpu-percent": {
"message": "% CPU"
},
"app-marketing.features.performance.description": {
"message": "يعمل Modrinth App بكفاءة أفضل من العديد من مديري المودات الرائدين، باستخدام 150 ميغابايت فقط من الذاكرة العشوائية!"
},
"app-marketing.features.performance.discord": {
"message": "ديسكورد"
},
@@ -386,6 +392,9 @@
"collection.label.no-projects": {
"message": "لا توجد مشروعات في هذه المجموعة حتي الآن"
},
"collection.label.projects-count": {
"message": "{count, plural, =0 {لا مشاريع حتى الاۤن} other {<stat>{count}</stat> {type}}}"
},
"collection.label.updated-at": {
"message": "تم التحديث منذ {ago}"
},
@@ -488,12 +497,24 @@
"create.project.create-project": {
"message": "إنشاء مشروع"
},
"create.project.missing-fields-tooltip": {
"message": "حقل مفقود: {fields}"
},
"create.project.name-label": {
"message": "الإسم"
},
"create.project.name-placeholder": {
"message": "أدخل اسم المشروع..."
},
"create.project.owner-description": {
"message": "عين مالك المشروع كنفسك أو كمنظمة أنت عضو منها."
},
"create.project.owner-label": {
"message": "المالك"
},
"create.project.server-project-title": {
"message": "إنشاء مشروع الخادم"
},
"create.project.summary-description": {
"message": "جملة أو جملتان تصف مجموعتك."
},
@@ -506,6 +527,15 @@
"create.project.title": {
"message": "إنشاء مشروع"
},
"create.project.type-label": {
"message": "نوع"
},
"create.project.type-project": {
"message": "مشروع"
},
"create.project.type-server": {
"message": "خادم"
},
"create.project.url-label": {
"message": "عنوان URL"
},
@@ -545,6 +575,21 @@
"dashboard.collections.button.create-new": {
"message": "إنشاء جديد"
},
"dashboard.collections.empty.get-started-hint": {
"message": "أنشئ مجموعتك الأولى للبدء!"
},
"dashboard.collections.empty.no-collections": {
"message": "ليس لديك مجموعات بعد"
},
"dashboard.collections.empty.no-match": {
"message": "لا توجد مجموعات تطابق بحثك"
},
"dashboard.collections.empty.no-match-hint": {
"message": "جرب تعديل فلاترك أو شروط البحث."
},
"dashboard.collections.label.projects-count": {
"message": "{count} {countPlural, plural, one {مشروع} other {مشروع}}"
},
"dashboard.collections.label.search-input": {
"message": "ابحث في مجموعاتك"
},
@@ -620,6 +665,9 @@
"dashboard.creator-withdraw-modal.kyc.entity-description": {
"message": "تشير الكيان التجاري إلى منظمة مسجلة مثل شركة مساهمة أو شراكة أو شركة ذات مسؤولية محدودة."
},
"dashboard.creator-withdraw-modal.kyc.entity-question": {
"message": "هل تسحب كفرد أم كشركة؟"
},
"dashboard.creator-withdraw-modal.kyc.private-individual": {
"message": "فرد خاص"
},
@@ -1046,15 +1094,57 @@
"frog": {
"message": "لقد تم ضفدعتك! 🐸"
},
"frog.altText": {
"message": "لوحة فنية واقعية فوتوغرافية لمتاهة ضفادع"
},
"frog.title": {
"message": "ضفدع"
},
"hosting-marketing.available-locations": {
"message": "متاح في أمريكا الشمالية، أوروبا، و جنوب شرق اۤسيا لتغطية أوسع."
},
"hosting-marketing.billing.monthly": {
"message": "ادفع شهريا"
},
"hosting-marketing.billing.quarterly": {
"message": "ادفع أرباعا سنوية"
},
"hosting-marketing.billing.save-with-quarterly": {
"message": "وفر 16% مع الدفع ربع السنوي!"
},
"hosting-marketing.billing.starting-at": {
"message": "يبدأ من {price} / للشهر"
},
"hosting-marketing.billing.yearly": {
"message": "ادفع سنويا"
},
"hosting-marketing.faq.burst-threads": {
"message": "كيف تعمل مسارات المعالجة في وحدة المعالجة المركزية؟"
},
"hosting-marketing.faq.cpu-kind.answer": {
"message": "تعمل استضافة خوادم مودرينث على AMD Ryzen 7900 و 7950X3D و وحدات معالجة مركزية مماثلة بسرعة 5+ غيغاهيرتز مقترنة بذاكرة وصول عشوائي من نوع DDR5"
},
"hosting-marketing.faq.location": {
"message": "أين تقع استضافة خوادم Modrinth؟ هل يمكنني اختيار منطقة؟"
},
"hosting-marketing.get-started": {
"message": "ابدأ"
},
"hosting-marketing.hero.button.manage-your-servers": {
"message": "ٳدارة خوادمك"
},
"hosting-marketing.hero.button.start-a-new-server": {
"message": "أنشئ خادما جديدا"
},
"hosting-marketing.hero.button.start-your-server": {
"message": "أنشئ خادمك"
},
"hosting-marketing.hero.host-with-modrinth": {
"message": "أدر خادمك التالي مع Modrinth Hosting"
},
"hosting-marketing.included.backups-included": {
"message": "النسخ الاحتياطية مضمنة"
},
"hosting-marketing.included.description": {
"message": "."
},
@@ -536,6 +536,9 @@
"dashboard.affiliate-links.revoke-confirm.button": {
"message": "Odvolat"
},
"dashboard.affiliate-links.revoke-confirm.title": {
"message": "Jste si jistý, že chcete zrušit svůj affiliate odkaz „{title}“?"
},
"dashboard.collections.button.create-new": {
"message": "Vytvořit novou"
},
@@ -1460,9 +1460,6 @@
"layout.nav.discover-content": {
"message": "Opdag indhold"
},
"layout.nav.feature-flags": {
"message": "Funktionsflags"
},
"layout.nav.get-modrinth-app": {
"message": "Hent Modrinth-app"
},
+21 -3
View File
@@ -1313,6 +1313,9 @@
"hosting.loader.failed-to-repair": {
"message": "Reparatur des Servers fehlgeschlagen"
},
"hosting.loader.failed-to-reset-to-onboarding": {
"message": "Server konnte nicht in den Onboarding-Zustand zurückgesetzt werden"
},
"hosting.loader.failed-to-save-settings": {
"message": "Speichern der Installationseinstellungen fehlgeschlagen"
},
@@ -1334,6 +1337,24 @@
"hosting.loader.reset-server-description": {
"message": "Entfernt sämtliche daten von deinem Server, inklusive deiner Welten, Mods und Konfigurationsdateien. Sicherung bleiben und können wiederhergestellt werden."
},
"hosting.loader.reset-to-onboarding-button": {
"message": "Auf Onboarding zurücksetzen"
},
"hosting.loader.reset-to-onboarding-modal-description": {
"message": "Dadurch wird der Server in den Onboarding-Zustand zurückgesetzt, sodass die Einrichtung erneut abgeschlossen werden kann. Möchtest du wirklich fortfahren?"
},
"hosting.loader.reset-to-onboarding-modal-title": {
"message": "Auf Onboarding zurücksetzen"
},
"hosting.loader.reset-to-onboarding-success-description": {
"message": "Der Server wurde in den Onboarding-Ablauf zurückgesetzt."
},
"hosting.loader.reset-to-onboarding-success-title": {
"message": "Server auf Onboarding zurückgesetzt"
},
"hosting.loader.support-options-title": {
"message": "Supportoptionen"
},
"hosting.plan.out-of-stock": {
"message": "Nicht verfügbar"
},
@@ -1688,9 +1709,6 @@
"layout.nav.discover-content": {
"message": "Inhalte entdecken"
},
"layout.nav.feature-flags": {
"message": "Funktionsflags"
},
"layout.nav.get-modrinth-app": {
"message": "Modrinth App herunterladen"
},
+21 -3
View File
@@ -1313,6 +1313,9 @@
"hosting.loader.failed-to-repair": {
"message": "Reparatur des Servers fehlgeschlagen"
},
"hosting.loader.failed-to-reset-to-onboarding": {
"message": "Server konnte nicht in den Onboarding-Zustand zurückgesetzt werden"
},
"hosting.loader.failed-to-save-settings": {
"message": "Speichern der Installationseinstellungen ist fehlgeschlagen"
},
@@ -1334,6 +1337,24 @@
"hosting.loader.reset-server-description": {
"message": "Entfernt alle Daten auf deinem Server, einschließlich deiner Welten, Mods und Konfigurationsdateien. Die Sicherungen bleiben erhalten und können wiederhergestellt werden."
},
"hosting.loader.reset-to-onboarding-button": {
"message": "Auf Onboarding zurücksetzen"
},
"hosting.loader.reset-to-onboarding-modal-description": {
"message": "Dadurch wird der Server in den Onboarding-Zustand zurückgesetzt, sodass die Einrichtung erneut abgeschlossen werden kann. Möchtest du wirklich fortfahren?"
},
"hosting.loader.reset-to-onboarding-modal-title": {
"message": "Auf Onboarding zurücksetzen"
},
"hosting.loader.reset-to-onboarding-success-description": {
"message": "Der Server wurde in den Onboarding-Ablauf zurückgesetzt."
},
"hosting.loader.reset-to-onboarding-success-title": {
"message": "Server auf Onboarding zurückgesetzt"
},
"hosting.loader.support-options-title": {
"message": "Supportoptionen"
},
"hosting.plan.out-of-stock": {
"message": "Nicht verfügbar"
},
@@ -1688,9 +1709,6 @@
"layout.nav.discover-content": {
"message": "Inhalte entdecken"
},
"layout.nav.feature-flags": {
"message": "Funktionsflags"
},
"layout.nav.get-modrinth-app": {
"message": "Modrinth App herunterladen"
},
+24 -3
View File
@@ -1313,6 +1313,9 @@
"hosting.loader.failed-to-repair": {
"message": "Failed to repair server"
},
"hosting.loader.failed-to-reset-to-onboarding": {
"message": "Failed to reset server to onboarding"
},
"hosting.loader.failed-to-save-settings": {
"message": "Failed to save installation settings"
},
@@ -1334,6 +1337,24 @@
"hosting.loader.reset-server-description": {
"message": "Removes all data on your server, including your worlds, mods, and configuration files. Backups will remain and can be restored."
},
"hosting.loader.reset-to-onboarding-button": {
"message": "Reset to onboarding"
},
"hosting.loader.reset-to-onboarding-modal-description": {
"message": "This will send the server back into onboarding so setup can be completed again. Are you sure you want to continue?"
},
"hosting.loader.reset-to-onboarding-modal-title": {
"message": "Reset to onboarding"
},
"hosting.loader.reset-to-onboarding-success-description": {
"message": "The server has been returned to the onboarding flow."
},
"hosting.loader.reset-to-onboarding-success-title": {
"message": "Server reset to onboarding"
},
"hosting.loader.support-options-title": {
"message": "Support options"
},
"hosting.plan.out-of-stock": {
"message": "Out of stock"
},
@@ -1688,9 +1709,6 @@
"layout.nav.discover-content": {
"message": "Discover content"
},
"layout.nav.feature-flags": {
"message": "Feature flags"
},
"layout.nav.get-modrinth-app": {
"message": "Get Modrinth App"
},
@@ -3191,6 +3209,9 @@
"settings.billing.charges.product.pyro": {
"message": "Modrinth Hosting"
},
"settings.billing.charges.title": {
"message": "Past charges"
},
"settings.billing.expires": {
"message": "Expires {date}"
},
+15 -18
View File
@@ -39,7 +39,7 @@
"message": "Opciones de descarga"
},
"app-marketing.download.terms": {
"message": "Al descargar Modrinth App, tú aceptas nuestros <terms-link>Términos</terms-link> y <privacy-link>Política de privacidad</privacy-link>."
"message": "Al descargar la aplicación Modrinth, acepta nuestros <terms-link>Términos</terms-link> y <privacy-link>Política de privacidad</privacy-link>."
},
"app-marketing.download.title": {
"message": "Descargar la Modrinth App (Beta)"
@@ -108,7 +108,7 @@
"message": "% CPU"
},
"app-marketing.features.performance.description": {
"message": "La aplicación Modrinth funciona mejor que muchos de los principales gestores de mods, ¡usando solo 150 MB de RAM!"
"message": "Modrinth App performs better than many of the leading mod managers, using just 150 MB of RAM!"
},
"app-marketing.features.performance.discord": {
"message": "Discord"
@@ -393,7 +393,7 @@
"message": "Aún no hay proyectos en la colección"
},
"collection.label.projects-count": {
"message": "{count, plural, =0 {Aún no hay proyectos} other {<stat>{count}</stat> {type}}}"
"message": "{count, plural, =0 {No hay proyectos todavía} otros {<stat>{count}</stat> {type}}}"
},
"collection.label.updated-at": {
"message": "Actualizado {ago}"
@@ -576,7 +576,7 @@
"message": "Crear nuevo"
},
"dashboard.collections.empty.get-started-hint": {
"message": "¡Crea tu primera colección para comenzar!"
"message": "Crea tu primera colección para comenzar!"
},
"dashboard.collections.empty.no-collections": {
"message": "Aún no tienes ninguna colección"
@@ -585,10 +585,10 @@
"message": "Ninguna colección coincide con tu búsqueda"
},
"dashboard.collections.empty.no-match-hint": {
"message": "Intente ajustar sus filtros o términos de búsqueda."
"message": "Prueba a ajustar tus filtros o términos de búsqueda."
},
"dashboard.collections.label.projects-count": {
"message": "{count} {countPlural, plural, one {proyecto} other {proyectos}}"
"message": "{count} {countPlural, plural, one {project} other {projects}}"
},
"dashboard.collections.label.search-input": {
"message": "Busca en tus colecciones"
@@ -666,7 +666,7 @@
"message": "Una entidad comercial se refiere a una organización registrada, como una sociedad anónima, una sociedad colectiva o una sociedad de responsabilidad limitada."
},
"dashboard.creator-withdraw-modal.kyc.entity-question": {
"message": "¿Vas a realizar la retirada como particular o como empresa?"
"message": "¿Te vas a retirar como individuo o como empresa?"
},
"dashboard.creator-withdraw-modal.kyc.private-individual": {
"message": "Particular"
@@ -1248,7 +1248,7 @@
"message": "¿Sabes exactamente lo que necesitas?"
},
"hosting-marketing.medal.info": {
"message": "Pruebe un <orange>servidor de 3 GB</orange> gratuito durante 5 días con <orange>Medal</orange>"
"message": "Pruebe un <orange>servidor de 3 GB</orange> gratis durante 5 días con la tecnología <orange>Medal</orange>"
},
"hosting-marketing.medal.learn-more": {
"message": "Aprender más"
@@ -1305,7 +1305,7 @@
"message": "No se pudo cambiar la versión del modpack"
},
"hosting.loader.failed-to-load-versions": {
"message": "No se pudieron cargar las versiones"
"message": "No se pudo cargar las versiones"
},
"hosting.loader.failed-to-reinstall": {
"message": "No se pudo reinstalar el modpack"
@@ -1314,25 +1314,25 @@
"message": "No se pudo reparar el servidor"
},
"hosting.loader.failed-to-save-settings": {
"message": "No se pudo guardar la configuración de instalación"
"message": "No se pudo guardar la configuración de la instalación"
},
"hosting.loader.failed-to-unlink": {
"message": "No se pudo desvincular el modpack"
},
"hosting.loader.loader-version": {
"message": "{loader, select, null {Cargador} other {{loader}}} versión"
"message": "{loader, select, null {Loader} otra versión {{loader}}}"
},
"hosting.loader.repair-started-text": {
"message": "La instalación de su servidor ha sido reparada."
"message": "La instalación de tu servidor ha sido reparada."
},
"hosting.loader.repair-started-title": {
"message": "Reparación completada"
},
"hosting.loader.reset-server": {
"message": "Reiniciar servidor"
"message": "Resetear server"
},
"hosting.loader.reset-server-description": {
"message": "Elimina todos los datos de su servidor, incluidos sus mundos, mods y archivos de configuración. Las copias de seguridad permanecerán y podrán restaurarse."
"message": "Elimina todos los datos de tu servidor, incluidos tus mundos, mods y archivos de configuración. Los backups se mantendrán y podrán restaurarse."
},
"hosting.plan.out-of-stock": {
"message": "Agotado"
@@ -1467,7 +1467,7 @@
"message": "Para jugadores"
},
"landing.section.for-players.tagline": {
"message": "Descubra más de {count, number} creaciones"
"message": "Descubre sobre las creaciones de {count, number}"
},
"landing.subheading": {
"message": "Descubre, juega y comparte contenido de Minecraft a través de nuestra plataforma de código abierto creada para la comunidad."
@@ -1688,9 +1688,6 @@
"layout.nav.discover-content": {
"message": "Descubrir contenido"
},
"layout.nav.feature-flags": {
"message": "Funciones experimentales"
},
"layout.nav.get-modrinth-app": {
"message": "Obtener la Modrinth App"
},
@@ -1688,9 +1688,6 @@
"layout.nav.discover-content": {
"message": "Descubra el contenido"
},
"layout.nav.feature-flags": {
"message": "Banderas de características"
},
"layout.nav.get-modrinth-app": {
"message": "Descargar la aplicación Modrinth"
},
@@ -143,6 +143,9 @@
"app-marketing.features.performance.title": {
"message": "Suorituskykyinen"
},
"app-marketing.features.play.description": {
"message": "Käytä Modrinth sovellusta asentaaksesi ja pelataksesi sinun suosikki modeliila ja modpackeilla."
},
"app-marketing.features.play.title": {
"message": "Pelaa lempi modeillasi"
},
@@ -332,6 +335,9 @@
"collection.label.created-at": {
"message": "Luotu {ago}"
},
"collection.label.projects-count": {
"message": "{count, plural, =0 {No projects yet} other {<stat>{count}</stat> {type}}}"
},
"collection.label.updated-at": {
"message": "Päivitetty {ago}"
},
@@ -1658,9 +1658,6 @@
"layout.nav.discover-content": {
"message": "Tumuklas ng kontento"
},
"layout.nav.feature-flags": {
"message": "Mga hudyat ng tampok"
},
"layout.nav.get-modrinth-app": {
"message": "Kunin ang Modrinth App"
},
+21 -3
View File
@@ -1313,6 +1313,9 @@
"hosting.loader.failed-to-repair": {
"message": "Impossible de réparer le serveur"
},
"hosting.loader.failed-to-reset-to-onboarding": {
"message": "Impossible de réinitialiser le serveur à l'intégration"
},
"hosting.loader.failed-to-save-settings": {
"message": "Impossible de sauvegarder les paramètres d'installation"
},
@@ -1334,6 +1337,24 @@
"hosting.loader.reset-server-description": {
"message": "Supprime définitivement toutes les données de votre serveur, y compris vos mondes, vos mods, et vos fichiers paramètres. Les sauvegardes resteront et pourront être restaurées."
},
"hosting.loader.reset-to-onboarding-button": {
"message": "Réinitialiser à l'intégration"
},
"hosting.loader.reset-to-onboarding-modal-description": {
"message": "Cela enverra le serveur à l'intégration afin que la configuration puisse être terminée à nouveau. Êtes-vous sûr de vouloir continuer ?"
},
"hosting.loader.reset-to-onboarding-modal-title": {
"message": "Réinitialiser à l'intégration"
},
"hosting.loader.reset-to-onboarding-success-description": {
"message": "Le serveur a été renvoyé au flux d'intégration."
},
"hosting.loader.reset-to-onboarding-success-title": {
"message": "Serveur réinitialisé à l'intégration"
},
"hosting.loader.support-options-title": {
"message": "Options de prise en charge"
},
"hosting.plan.out-of-stock": {
"message": "En rupture de stock"
},
@@ -1688,9 +1709,6 @@
"layout.nav.discover-content": {
"message": "Découvrir du contenu"
},
"layout.nav.feature-flags": {
"message": "Fonctionnalités expérimentales"
},
"layout.nav.get-modrinth-app": {
"message": "Obtenir Modrinth App"
},
@@ -1010,9 +1010,6 @@
"layout.nav.discover-content": {
"message": "גלה תוכן"
},
"layout.nav.feature-flags": {
"message": "הגדרות ניסיוניות"
},
"layout.nav.get-modrinth-app": {
"message": "להוריד אפליקציאת Modrinth"
},
+241 -55
View File
@@ -66,7 +66,7 @@
"message": "Profil importálás"
},
"app-marketing.features.mod-management.actions": {
"message": "Akciók"
"message": "Műveletek"
},
"app-marketing.features.mod-management.byAuthor": {
"message": "{author} által"
@@ -309,10 +309,10 @@
"message": "Az email már hítelesítve van!"
},
"auth.verify-email.already-verified.title": {
"message": "Email már hítelesítve van"
"message": "Az e-mail cím már hítelesítve van"
},
"auth.verify-email.failed-verification.action": {
"message": "Hítelesítő email újraküldése"
"message": "Hitelesítő e-mail újraküldése"
},
"auth.verify-email.failed-verification.description": {
"message": "Nem tudtuk ellenőrizni az e-mail címét. Próbálja meg újra elküldeni az ellenőrző e-mailt a bejelentkezés után a vezérlőpulton keresztül."
@@ -321,16 +321,16 @@
"message": "Nem tudtuk ellenőrizni az e-mail címét. Kérjük, próbálja meg újra elküldeni az ellenőrző e-mailt az alábbi gombra kattintva."
},
"auth.verify-email.failed-verification.title": {
"message": "Email hítelesítés sikertelen"
"message": "Az e-mail cím hitelesítés sikertelen"
},
"auth.verify-email.post-verification.description": {
"message": "E-mail cím sikeresen megerősítve!"
"message": "Az e-mail cím sikeresen megerősítve!"
},
"auth.verify-email.post-verification.title": {
"message": "Email megerősítés"
"message": "E-mail cím hitelesítése"
},
"auth.verify-email.title": {
"message": "Email-cím megerősítése"
"message": "Email-cím hitelesítése"
},
"auth.welcome.checkbox.subscribe": {
"message": "Iratkozzon fel a Modrinth frissítéseiről szóló értesítésekre"
@@ -387,7 +387,7 @@
"message": "Létrehozva {ago}"
},
"collection.label.curated-by": {
"message": "Kurátor"
"message": "Készítő"
},
"collection.label.no-projects": {
"message": "Még nincsenek projektek ebben a gyűjteményben"
@@ -411,7 +411,7 @@
"message": "A kiegészítő fájlok olyan kiegészítő forrásokhoz tartoznak, mint például a forráskód, nem pedig alternatív verziókhoz vagy változatokhoz."
},
"create.collection.collection-info": {
"message": "Az új gyűjteményed nyilvános gyűjteményként jön létre, {count, plural, =0 {nincs projekt} one {# projekt} other {# projekt}}."
"message": "Az új gyűjteményed nyilvános gyűjteményként jön létre {count, plural, =0 {projektek nélkül} other {# projekttel}}."
},
"create.collection.create-collection": {
"message": "Gyűjtemény létrehozása"
@@ -588,7 +588,7 @@
"message": "Próbáld meg módosítani a szűrőket vagy a keresési kifejezéseket."
},
"dashboard.collections.label.projects-count": {
"message": "{count} {countPlural, plural, one {projekt} other {projektek}}"
"message": "{count} projekt"
},
"dashboard.collections.label.search-input": {
"message": "Keresd meg a gyűjteményeidet"
@@ -603,7 +603,7 @@
"message": "A(z) {formType} adóbevallásodat sikeresen elküldtük!"
},
"dashboard.creator-tax-form-modal.confirmation.support-text": {
"message": "Mostantól szabadon kivehetsz a fiókodról. Amennyiben kérdésed van, vagy frissítenéd az adataidat <support-link>vedd fel velünk a kapcsolatot</support-link>."
"message": "Mostantól szabadon felvehetsz a fiókodról. Amennyiben kérdésed van, vagy frissítenéd az adataidat <support-link>vedd fel velünk a kapcsolatot</support-link>."
},
"dashboard.creator-tax-form-modal.confirmation.title": {
"message": "Készen állsz! 🎉"
@@ -624,7 +624,7 @@
"message": "Adóűrlap"
},
"dashboard.creator-tax-form-modal.security.description": {
"message": "A Modrinth a Track1099 nevű harmadik fél szolgáltatót használja az adóűrlapjaid biztonságos begyűjtésére és tárolására. <security-link>További információk itt.</security-link>"
"message": "A Modrinth a Track1099 nevű harmadik fél szolgáltatót használja az adóűrlapjaid biztonságos begyűjtésére és tárolására. <security-link>További információ.</security-link>"
},
"dashboard.creator-tax-form-modal.security.header": {
"message": "Biztonsági gyakorlatok"
@@ -699,7 +699,7 @@
"message": "Fiók tulajdonosa"
},
"dashboard.creator-withdraw-modal.muralpay-details.bank-account-owner": {
"message": "Bankszámla tulajdonos"
"message": "Bankszámla tulajdonosa"
},
"dashboard.creator-withdraw-modal.muralpay-details.bank-account-owner-description": {
"message": "Adja meg annak a személynek a nevét, aki a vállalkozás nevében jogosult a bankszámla kezelésére."
@@ -819,10 +819,10 @@
"message": "Összeg keresése"
},
"dashboard.creator-withdraw-modal.tremendous-details.unverified-email-header": {
"message": "Megerősítettlen E-mail"
"message": "Hitelesítetlen e-mail"
},
"dashboard.creator-withdraw-modal.tremendous-details.unverified-email-message": {
"message": "A kiszállítási e-mail, amit megadtál nincs hozzákapcsolva a Modrinth fiókodhoz. A Modrinth nem tudja visszaállítani a jutalmakat, amik rossz e-mail címre lettek küldve."
"message": "A kiszállítási e-mail cím, amit megadtál nincs hozzákapcsolva a Modrinth fiókodhoz. A Modrinth nem tudja visszaállítani a jutalmakat, amik rossz e-mail címre lettek küldve."
},
"dashboard.creator-withdraw-modal.tremendous-details.usd-paypal-warning-header": {
"message": "Alacsonyabb díjak elérhetőek"
@@ -1064,11 +1064,17 @@
"hosting-marketing.billing.yearly": {
"message": "Éves fizetés"
},
"hosting-marketing.faq.burst-threads": {
"message": "Hogyan működnek a CPU-burst szálak?"
},
"hosting-marketing.faq.burst-threads.answer": {
"message": "Amikor a szervered nagy terhelés alatt áll, ideiglenesen további processzorszálakat biztosítunk számára, hogy csökkentsük a lagtüskéket és az instabilitást. Ez segít megakadályozni, hogy a TPS 20 alá essen, így a játékélmény a lehető legsimább marad.\nMivel ezek az extra processzorszálak csak rövid ideig, nagy terhelés esetén érhetők el, előfordulhat, hogy nem jelennek meg a Spark jelentésekben vagy más teljesítményelemző eszközökben."
},
"hosting-marketing.faq.cpu-kind": {
"message": "Milyen típusú CPU-k futnak a Modrinth Hosting szerverein?"
},
"hosting-marketing.faq.cpu-kind.answer": {
"message": "A Modrinth Hosting szerverei AMD Ryzen 7900 és 7950X3D egyenértékű, 5+ GHz-s CPU-kkal és DDR5 memóriával vannak felszerelve."
"message": "A Modrinth Hosting szerverei AMD Ryzen 7900 és 7950X3D egyenértékű, 5+ GHz-s processzorokkal és DDR5 memóriával vannak felszerelve."
},
"hosting-marketing.faq.currency": {
"message": "Milyen pénznemben vannak megadva az árak?"
@@ -1079,6 +1085,9 @@
"hosting-marketing.faq.ddos-protection": {
"message": "A Modrinth Hosting szerverei rendelkeznek DDoS védelemmel?"
},
"hosting-marketing.faq.ddos-protection.answer": {
"message": "Igen. A Modrinth Hosting összes szerverén DDoS-védelem működik, egyes helyszíneken akár 17 Tbps kapacitással."
},
"hosting-marketing.faq.heading": {
"message": "Gyakori kérdések"
},
@@ -1134,7 +1143,7 @@
"message": "Fejlett hálózatkezelés"
},
"hosting-marketing.included.advanced-networking.description": {
"message": "."
"message": "Add hozzá saját domainedet a szerveredhez, foglalj le akár 15 portot azokhoz a modokhoz, amelyeknek szükségük van rá, és még sok más."
},
"hosting-marketing.included.backups-included": {
"message": "Tartalmaz biztonsági másolatokat"
@@ -1175,12 +1184,18 @@
"hosting-marketing.included.sftp-access": {
"message": "SFTP hozzáférés"
},
"hosting-marketing.included.sftp-access.description": {
"message": "A Modrinth Hosting szolgáltatásba beépített SFTP segítségével közvetlenül elérheti a szerver fájljait."
},
"hosting-marketing.included.with-your-server": {
"message": "A szerverhez tartozik"
},
"hosting-marketing.know-what-you-need": {
"message": "Pontosan tudod, mire van szükséged?"
},
"hosting-marketing.medal.info": {
"message": "Próbálja ki 5 napig ingyen a <orange>3 GB-os szervert</orange>, amelyet a <orange>Medal</orange> biztosít"
},
"hosting-marketing.medal.learn-more": {
"message": "További információk"
},
@@ -1211,8 +1226,11 @@
"hosting-marketing.why.heading": {
"message": "Keress egy modcsomagot. Most már ez egy szerver."
},
"hosting-marketing.why.modern-reliable-hosting": {
"message": "Élvezd a modern, megbízható szerverüzemeltetést"
},
"hosting-marketing.why.modern-reliable-hosting.description": {
"message": "A Modrinth Hosting szerverei <contrast>nagy teljesítményű AMD CPU-kon és DDR5 RAM-on</contrast> futnak, egyedi fejlesztésű szoftverrel, hogy a szerver zökkenőmentesen működjön."
"message": "A Modrinth Hosting <contrast>nagy teljesítményű AMD processzorokat és DDR5 memóriát</contrast> használ, valamint egyedi szoftverrel gondoskodik a stabil, zökkenőmentes működésről."
},
"hosting-marketing.why.where-mods-are": {
"message": "Játssz ott, ahol a modjaid vannak"
@@ -1232,6 +1250,12 @@
"hosting.loader.loader-version": {
"message": "{loader, select,null {Betöltő} other {{loader}}} Verzió"
},
"hosting.loader.reset-server": {
"message": "Szerver visszaállítása"
},
"hosting.loader.reset-server-description": {
"message": "Minden adatot eltávolít a szerverről, beleértve a világokat, a modokat és a konfigurációs fájlokat is. A biztonsági másolatok megmaradnak, és visszaállíthatók."
},
"hosting.plan.select-plan": {
"message": "Csomag kiválasztása"
},
@@ -1245,7 +1269,7 @@
"message": "Kapd meg a legjobb modolási élményt folyamatos frissítésekkel a Modrinth csapattól"
},
"landing.creator.feature.constantly-evolving.title": {
"message": "Folyamatos Változás"
"message": "Folyamatos változás"
},
"landing.creator.feature.data-statistics.description": {
"message": "Részletes jelentéseket kaphatsz a megtekintésekről, a letöltések számáról és a bevételekről."
@@ -1341,7 +1365,7 @@
"message": "Értesítések"
},
"landing.notifications.received-time": {
"message": "Kaptad {time} óta"
"message": "{time} kaptad"
},
"landing.notifications.version-released": {
"message": "Egy új verzió {version} kijött erre: {gameVersion}"
@@ -1377,7 +1401,7 @@
"message": "Fájl keresés"
},
"layout.action.lookup-by-email": {
"message": "Email alapján keresés"
"message": "Keresés e-mail cím alapján"
},
"layout.action.manage-server-notices": {
"message": "Szerver megjegyzések kezelése"
@@ -1544,9 +1568,6 @@
"layout.nav.discover-content": {
"message": "Tartalom felfedezése"
},
"layout.nav.feature-flags": {
"message": "Funkciójelzők"
},
"layout.nav.get-modrinth-app": {
"message": "Szerezd meg a Modrinth Appot"
},
@@ -1845,7 +1866,7 @@
"message": "Nézd át jól a pénztárca címedet. Az egyenleg rossz címre lesz küldve az nem szerezhető vissza."
},
"profile.bio.fallback.creator": {
"message": "Egy Modrinth alkotó."
"message": "Egy Modrinth fejlesztő."
},
"profile.bio.fallback.user": {
"message": "Egy Modrinth felhasználó."
@@ -1872,7 +1893,7 @@
"message": "Auth szolgáltatók"
},
"profile.details.label.email": {
"message": "Email"
"message": "E-mail"
},
"profile.details.label.email-verified": {
"message": "E-mail cím ellenőrizve"
@@ -1890,7 +1911,7 @@
"message": "Nem hitelesített email"
},
"profile.details.tooltip.email-verified": {
"message": "Hitelesített email"
"message": "E-mail cím hitelesítve"
},
"profile.error.not-found": {
"message": "Felhasználó nem található"
@@ -1905,7 +1926,7 @@
"message": "Gyűjtemény"
},
"profile.label.downloads": {
"message": "{count} {countPlural, plural,one {letöltés} other {letöltések}}"
"message": "{count} letöltés"
},
"profile.label.joined": {
"message": "Csatlakozott"
@@ -1926,7 +1947,7 @@
"message": "Szervezetek"
},
"profile.label.projects": {
"message": "{count} {countPlural, plural,one {projekt} other {projektek}}"
"message": "{count} projekt"
},
"profile.label.saving": {
"message": "Mentés..."
@@ -1998,61 +2019,61 @@
"message": "Figyelmeztetés"
},
"project-type.collection.plural": {
"message": "Gyűjtemény"
"message": "Gyűjtemények"
},
"project-type.collection.singular": {
"message": "Gyűjtemény"
},
"project-type.datapack.plural": {
"message": "Adatcsomag"
"message": "Adatcsomagok"
},
"project-type.datapack.singular": {
"message": "Adatcsomag"
},
"project-type.minecraft_java_server.plural": {
"message": "Szerver"
"message": "Szerverek"
},
"project-type.minecraft_java_server.singular": {
"message": "Szerver"
},
"project-type.mod.plural": {
"message": "Mod"
"message": "Modok"
},
"project-type.mod.singular": {
"message": "Mod"
},
"project-type.modpack.plural": {
"message": "Modcsomag"
"message": "Modcsomagok"
},
"project-type.modpack.singular": {
"message": "Modpack"
"message": "Modcsomag"
},
"project-type.plugin.plural": {
"message": "Bővítmény"
"message": "Bővítmények"
},
"project-type.plugin.singular": {
"message": "Bővítmény"
},
"project-type.project.plural": {
"message": "Projekt"
"message": "Projektek"
},
"project-type.project.singular": {
"message": "Projekt"
},
"project-type.resourcepack.plural": {
"message": "Forráscsomag"
"message": "Forráscsomagok"
},
"project-type.resourcepack.singular": {
"message": "Forráscsomag"
},
"project-type.server.plural": {
"message": "Szerver"
"message": "Szerverek"
},
"project-type.server.singular": {
"message": "Szerver"
},
"project-type.shader.plural": {
"message": "Shader"
"message": "Shaderek"
},
"project-type.shader.singular": {
"message": "Shader"
@@ -2169,7 +2190,7 @@
"message": "Projekt nem található"
},
"project.gallery.title": {
"message": "Galéria"
"message": "Képek"
},
"project.license.error": {
"message": "A licensz szövege nem tölthető le."
@@ -2319,13 +2340,13 @@
"message": "Jelentés benyújtása"
},
"scopes.analytics.description": {
"message": "Analitikai adataid elérése"
"message": "Statisztikai adataid elérése"
},
"scopes.analytics.label": {
"message": "Analitikák olvasása"
"message": "Statisztikák olvasása"
},
"scopes.category.analytics": {
"message": "Elemzések"
"message": "Statisztikák"
},
"scopes.category.collections": {
"message": "Kollekciók"
@@ -2445,10 +2466,10 @@
"message": "PAT-ek írása"
},
"scopes.performAnalytics.description": {
"message": "Analitikai tevékenységek végrehajtása"
"message": "Statisztikai műveletek végrehajtása"
},
"scopes.performAnalytics.label": {
"message": "Analitikák végrehajtása"
"message": "Statisztikák végrehajtása"
},
"scopes.projectCreate.description": {
"message": "Új projektek létrehozása"
@@ -2519,6 +2540,15 @@
"scopes.threadWrite.label": {
"message": "Szálakban írás"
},
"search.filter.locked.server": {
"message": "A szerver által van megadva"
},
"search.filter.locked.server-game-version.title": {
"message": "A játékverzió a szerver által van megadva"
},
"search.filter.locked.server-loader.title": {
"message": "A betöltő a szerver által van megadva"
},
"search.filter.locked.server.sync": {
"message": "Szinkronizálás a szerverrel"
},
@@ -2555,6 +2585,27 @@
"servers.plan.small.description": {
"message": "Tökéletes 15 barát számára, néhány kisebb moddal."
},
"settings.account.button.complete-setup": {
"message": "Beállítás befejezése"
},
"settings.account.data-export.action.download": {
"message": "Exportálás letöltése"
},
"settings.account.data-export.action.generate": {
"message": "Exportálás"
},
"settings.account.data-export.action.generating": {
"message": "Exportálás..."
},
"settings.account.data-export.description": {
"message": "Másolatot kér az összes személyes adatról, amelyet a Modrinthra feltöltött. A feldolgozás néhány percig is eltarthat."
},
"settings.account.data-export.title": {
"message": "Adatok exportálása"
},
"settings.account.delete.confirm.description": {
"message": "Ez **azonnal törli az összes felhasználói adatodat és követőidet**. A projektjeid nem kerülnek törlésre. A fiók törlése visszafordíthatatlan.<br><br>Ha segítségre van szükséged a fiókoddal kapcsolatban, kérj támogatást a [Modrinth Discord](https://discord.modrinth.com)on."
},
"settings.account.delete.confirm.proceed": {
"message": "Fiók törlése"
},
@@ -2564,6 +2615,9 @@
"settings.account.delete.section.action": {
"message": "Fiók törlése"
},
"settings.account.delete.section.description": {
"message": "A fiók törlése után nincs visszaút. A fiók törlésével a projektek kivételével minden kapcsolódó adat eltávolításra kerül a szervereinkről."
},
"settings.account.delete.section.title": {
"message": "Fiók törlése"
},
@@ -2571,16 +2625,22 @@
"message": "E-mail mentése"
},
"settings.account.email.field.label": {
"message": "E-mail-cím"
"message": "E-mail cím"
},
"settings.account.email.field.placeholder": {
"message": "Írd ide az e-mail címedet..."
},
"settings.account.email.modal.header.add": {
"message": "E-mail hozzáadása"
"message": "E-mail cím hozzáadása"
},
"settings.account.email.modal.header.change": {
"message": "E-mail megváltoztatása"
"message": "E-mail cím megváltoztatása"
},
"settings.account.email.modal.notice": {
"message": "A fiókadataid nem jelennek meg nyilvánosan."
},
"settings.account.password.action.remove": {
"message": "Jelszó törlése"
},
"settings.account.password.action.save": {
"message": "Jelszó mentése"
@@ -2621,27 +2681,105 @@
"settings.account.password.modal.header.change": {
"message": "Jelszó módosítása"
},
"settings.account.password.modal.header.remove": {
"message": "Jelszó törlése"
},
"settings.account.providers.action.add": {
"message": "Hozzáadás"
},
"settings.account.providers.modal.header": {
"message": "Hitelesítési szolgáltatók"
},
"settings.account.providers.table.actions": {
"message": "Műveletek"
},
"settings.account.providers.table.provider": {
"message": "Szolgáltató"
},
"settings.account.security.email.action.add": {
"message": "E-mail cím hozzáadása"
},
"settings.account.security.email.action.change": {
"message": "E-mail cím módosítása"
},
"settings.account.security.email.description": {
"message": "Módosítja a fiókodhoz tartozó e-mail címet."
},
"settings.account.security.email.title": {
"message": "E-mail"
"message": "E-mail cím"
},
"settings.account.security.password.action.add": {
"message": "Jelszó hozzáadása"
},
"settings.account.security.password.action.change": {
"message": "Jelszó módosítása"
},
"settings.account.security.password.description.change": {
"message": "Módosítsd a fiókodba való bejelentkezéshez használt jelszót."
},
"settings.account.security.password.description.change-or-remove": {
"message": "Módosítsd vagy töröld a fiókodba való bejelentkezéshez használt jelszót."
},
"settings.account.security.password.description.set": {
"message": "Állíts be egy állandó jelszót a fiókodba való bejelentkezéshez."
},
"settings.account.security.password.title": {
"message": "Jelszó"
},
"settings.account.security.providers.action.manage": {
"message": "Szolgáltatók kezelése"
},
"settings.account.security.providers.description": {
"message": "Hozzáadhatod vagy eltávolíthatod a fiókodhoz a bejelentkezési módszereket, beleértve a GitHubot, a GitLabot, a Microsoftot, a Discordot, a Steamet és a Google-t."
},
"settings.account.security.providers.title": {
"message": "Hitelesítési szolgáltatók kezelése"
},
"settings.account.security.title": {
"message": "Fiókbiztonság"
},
"settings.account.security.two-factor.action.remove": {
"message": "A kétlépcsős hitelesítés kikapcsolása "
"message": "A kétlépcsős hitelesítés kikapcsolása"
},
"settings.account.security.two-factor.action.setup": {
"message": "A kétlépcsős hitelesítés beállítása"
},
"settings.account.security.two-factor.description": {
"message": "Biztosíts további védelmet a fiókodnak."
},
"settings.account.security.two-factor.title": {
"message": "Kétlépcsős hitelesítés"
},
"settings.account.two-factor.backup.intro": {
"message": "Töltse le ezeket a biztonsági kódokat, és őrizze meg őket biztonságos helyen. Ha valaha is elveszítené a hozzáférését az eszközéhez, ezeket a kódokat használhatja a kétlépcsős hitelesítés kódja helyett! Ezeket a kódokat ugyanúgy óvnia kell, mint a jelszavát."
},
"settings.account.two-factor.backup.single-use": {
"message": "A biztonsági kódok csak egyszer használhatók fel."
},
"settings.account.two-factor.error.incorrect-code": {
"message": "A megadott kód helytelen!"
},
"settings.account.two-factor.field.code.description": {
"message": "Kérjük, írja be a kétlépcsős hitelesítés kódját a folytatáshoz."
},
"settings.account.two-factor.field.code.label": {
"message": "Írd be a kétlépcsős hitelesítés kódját"
},
"settings.account.two-factor.field.code.placeholder": {
"message": "Írd ide a kódot..."
},
"settings.account.two-factor.setup.intro": {
"message": "A kétlépcsős hitelesítés biztosítja fiókod biztonságát azzal, hogy a bejelentkezéshez egy második eszköz használatát is megköveteli."
},
"settings.account.two-factor.setup.scan": {
"message": "Olvassa be a QR-kódot az <authy-link>Authy</authy-link>, a <microsoft-authenticator-link>Microsoft Authenticator</microsoft-authenticator-link> vagy bármely más kétlépcsős hitelesítési alkalmazás segítségével a folyamat megkezdéséhez."
},
"settings.account.two-factor.verify.description": {
"message": "Írja be az hitelesítőalkalmazásból kapott egyszeri kódot a hozzáférés igazolásához."
},
"settings.account.two-factor.verify.label": {
"message": "Kód ellenőrzése"
},
"settings.applications.about": {
"message": "Rólunk"
},
@@ -2673,7 +2811,7 @@
"message": "Ikon feltöltése"
},
"settings.applications.client-id": {
"message": "Kliens ID"
"message": "Kliensazonosító"
},
"settings.applications.client-secret": {
"message": "Kliens secret"
@@ -2717,6 +2855,9 @@
"settings.applications.field.url.placeholder": {
"message": "https://example.com"
},
"settings.applications.head-title": {
"message": "Alkalmazások"
},
"settings.applications.modal.header": {
"message": "Alkamazás információ"
},
@@ -2729,6 +2870,15 @@
"settings.applications.secret.disclaimer": {
"message": "A secreteted most mentesd el, el lesz tüntetve mituán elhagyod ezt az oldalt!"
},
"settings.authorizations.by": {
"message": "által"
},
"settings.billing.interval.month": {
"message": "hónap"
},
"settings.billing.midas.benefits.ad-free": {
"message": "Reklámmentes böngészés a modrinth.com-on és a Modrinth App-ban"
},
"settings.billing.modal.cancel.action": {
"message": "Előfizetés lemondása"
},
@@ -2765,15 +2915,27 @@
"settings.billing.subscription.title": {
"message": "Előfizetések"
},
"settings.billing.switch.tooltip.monthly-additional-per-year": {
"message": "A havi számlázás évente további {amount} költséggel jár"
},
"settings.display.banner.developer-mode.button": {
"message": "Fejlesztői mód deaktiválása"
"message": "A fejlesztői mód letiltása"
},
"settings.display.banner.developer-mode.description": {
"message": "A <strong>fejlesztői mód</strong> aktív. Ez lehetővé teszi, hogy megtekintsd a Modrinth különböző elemeinek belső azonosítóit, ami hasznos lehet, ha a Modrinth API-t használó fejlesztő vagy. Kattints ötször a lap alján található Modrinth logóra a fejlesztői mód bekapcsolásához."
},
"settings.display.flags.description": {
"message": "Bizonyos funkciók engedélyezése vagy letiltása ezen az eszközön."
},
"settings.display.flags.title": {
"message": "Funkciók be-/kikapcsolása"
},
"settings.display.notification.developer-mode-deactivated.text": {
"message": "A fejlesztői mód le lett tiltva"
},
"settings.display.notification.developer-mode-deactivated.title": {
"message": "Fejlesztői mód letiltva"
},
"settings.display.project-list-layouts.datapack": {
"message": "Adatcsomagok oldal"
},
@@ -2783,6 +2945,15 @@
"settings.display.project-list-layouts.mod": {
"message": "Modok oldal"
},
"settings.display.project-list-layouts.mode.gallery": {
"message": "Képek"
},
"settings.display.project-list-layouts.mode.grid": {
"message": "Rács"
},
"settings.display.project-list-layouts.mode.rows": {
"message": "Lista"
},
"settings.display.project-list-layouts.modpack": {
"message": "Modcsomagok oldal"
},
@@ -2796,13 +2967,13 @@
"message": "Szerverek oldal"
},
"settings.display.project-list-layouts.shader": {
"message": "Shaferek oldal"
"message": "Shaderek oldal"
},
"settings.display.project-list-layouts.title": {
"message": "Projektlista elrendezések"
},
"settings.display.project-list-layouts.user": {
"message": "Felhasználói profil oldalai"
"message": "Profil oldalak"
},
"settings.display.project-list.layouts.collection": {
"message": "Gyűjtemény"
@@ -2831,6 +3002,9 @@
"settings.display.theme.title": {
"message": "Téma"
},
"settings.head-title": {
"message": "Megjelenési beállítások"
},
"settings.pats.action.create": {
"message": "PAT létrehozása"
},
@@ -2888,6 +3062,9 @@
"settings.profile.description": {
"message": "A rofiladataid nyilvánosan megtekinthetők a Modrinth oldalon és a <docs-link>Modrinth API</docs-link>-n keresztül."
},
"settings.profile.head-title": {
"message": "Profilbeállítások"
},
"settings.profile.profile-info": {
"message": "Profilinformációk"
},
@@ -2918,6 +3095,15 @@
"settings.sessions.unknown-platform": {
"message": "Ismeretlen platform"
},
"settings.sidebar.label.account": {
"message": "Fiók"
},
"settings.sidebar.label.developer": {
"message": "Fejlesztő"
},
"settings.sidebar.label.display": {
"message": "Megjelenés"
},
"ui.latest-news-row.latest-news": {
"message": "A legújabb hírek a Modrinthról"
},

Some files were not shown because too many files have changed in this diff Show More