feat: make byte size units translatable (#5969)
Make byte size units translatable
This commit is contained in:
@@ -51,9 +51,10 @@ import {
|
||||
providePageContext,
|
||||
providePopupNotificationManager,
|
||||
useDebugLogger,
|
||||
useFormatBytes,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatBytes, renderString } from '@modrinth/utils'
|
||||
import { renderString } from '@modrinth/utils'
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { getVersion } from '@tauri-apps/api/app'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
@@ -262,6 +263,8 @@ onUnmounted(async () => {
|
||||
})
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
const messages = defineMessages({
|
||||
updateInstalledToastTitle: {
|
||||
id: 'app.update.complete-toast.title',
|
||||
|
||||
@@ -176,9 +176,10 @@ import {
|
||||
ButtonStyled,
|
||||
Card,
|
||||
CopyCode,
|
||||
useFormatBytes,
|
||||
useFormatDateTime,
|
||||
} from '@modrinth/ui'
|
||||
import { formatBytes, renderString } from '@modrinth/utils'
|
||||
import { renderString } from '@modrinth/utils'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
@@ -191,6 +192,7 @@ const formatDateTime = useFormatDateTime({
|
||||
timeStyle: 'short',
|
||||
dateStyle: 'long',
|
||||
})
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
const breadcrumbs = useBreadcrumbs()
|
||||
|
||||
|
||||
@@ -17,74 +17,60 @@
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fileIsValid } from '~/helpers/fileUtils.js'
|
||||
<script setup lang="ts">
|
||||
import { useFormatBytes } from '@modrinth/ui'
|
||||
import { fileIsValid } from '@modrinth/utils'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
prompt: {
|
||||
type: String,
|
||||
default: 'Select file',
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
accept: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
prompt?: string
|
||||
multiple?: boolean
|
||||
accept?: string
|
||||
/**
|
||||
* The max file size in bytes
|
||||
*/
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
showIcon: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
shouldAlwaysReset: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
longStyle: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
maxSize?: number | null
|
||||
showIcon?: boolean
|
||||
shouldAlwaysReset?: boolean
|
||||
longStyle?: boolean
|
||||
disabled?: boolean
|
||||
}>(),
|
||||
{
|
||||
prompt: 'Select file',
|
||||
multiple: false,
|
||||
showIcon: true,
|
||||
shouldAlwaysReset: false,
|
||||
longStyle: false,
|
||||
disabled: false,
|
||||
},
|
||||
emits: ['change'],
|
||||
data() {
|
||||
return {
|
||||
files: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addFiles(files, shouldNotReset) {
|
||||
if (!shouldNotReset || this.shouldAlwaysReset) {
|
||||
this.files = files
|
||||
}
|
||||
)
|
||||
|
||||
const validationOptions = { maxSize: this.maxSize, alertOnInvalid: true }
|
||||
this.files = [...this.files].filter((file) => fileIsValid(file, validationOptions))
|
||||
const emit = defineEmits<{ change: [files: File[]] }>()
|
||||
|
||||
if (this.files.length > 0) {
|
||||
this.$emit('change', this.files)
|
||||
}
|
||||
},
|
||||
handleDrop(e) {
|
||||
this.addFiles(e.dataTransfer.files)
|
||||
},
|
||||
handleChange(e) {
|
||||
this.addFiles(e.target.files)
|
||||
},
|
||||
},
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
const files = ref<File[]>([])
|
||||
|
||||
function addFiles(incoming: FileList, shouldNotReset = false) {
|
||||
if (!shouldNotReset || props.shouldAlwaysReset) {
|
||||
files.value = Array.from(incoming)
|
||||
}
|
||||
const validationOptions = { maxSize: props.maxSize, alertOnInvalid: true }
|
||||
files.value = files.value.filter((file) => fileIsValid(file, validationOptions, formatBytes))
|
||||
if (files.value.length > 0) {
|
||||
emit('change', files.value)
|
||||
}
|
||||
}
|
||||
|
||||
function handleDrop(e: DragEvent) {
|
||||
addFiles(e.dataTransfer!.files)
|
||||
}
|
||||
|
||||
function handleChange(e: Event) {
|
||||
const input = e.target as HTMLInputElement
|
||||
if (!input.files) return
|
||||
addFiles(input.files)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
type OverflowMenuOption,
|
||||
useFormatBytes,
|
||||
useFormatDateTime,
|
||||
} from '@modrinth/ui'
|
||||
import { NavTabs } from '@modrinth/ui'
|
||||
@@ -56,6 +57,7 @@ const formatDateTimeUtc = useFormatDateTime({
|
||||
timeZoneName: 'short',
|
||||
timeZone: 'UTC',
|
||||
})
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
type FlattenedFileReport = Labrinth.TechReview.Internal.FileReport & {
|
||||
id: string
|
||||
@@ -362,12 +364,6 @@ const formattedDate = computed(() => {
|
||||
return `${diffDays} days ago`
|
||||
})
|
||||
|
||||
function formatFileSize(bytes: number): string {
|
||||
if (bytes < 1024) return `${bytes} B`
|
||||
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KiB`
|
||||
return `${(bytes / (1024 * 1024)).toFixed(2)} MiB`
|
||||
}
|
||||
|
||||
function viewFileFlags(file: FlattenedFileReport) {
|
||||
selectedFileId.value = file.id
|
||||
currentTab.value = 'File'
|
||||
@@ -851,7 +847,7 @@ const reviewSummaryPreview = computed(() => {
|
||||
const fileVerdict = fileUnsafe > 0 ? 'Unsafe' : 'Safe'
|
||||
|
||||
markdown += `### ${fileData.fileName}\n`
|
||||
markdown += `> ${formatFileSize(fileData.fileSize)} • ${fileData.decisions.length} issues • Max severity: ${fileData.maxSeverity} • **Verdict:** ${fileVerdict}\n\n`
|
||||
markdown += `> ${formatBytes(fileData.fileSize)} • ${fileData.decisions.length} issues • Max severity: ${fileData.maxSeverity} • **Verdict:** ${fileVerdict}\n\n`
|
||||
markdown += `<details>\n<summary>Issues (${fileSafe} safe, ${fileUnsafe} unsafe)</summary>\n\n`
|
||||
markdown += `| Class | Issue Type | Severity | Decision |\n`
|
||||
markdown += `|-------|------------|----------|----------|\n`
|
||||
@@ -1150,7 +1146,7 @@ async function handleSubmitReview(verdict: 'safe' | 'unsafe') {
|
||||
</span>
|
||||
<div class="rounded-full border border-solid border-surface-5 bg-surface-3 px-2.5 py-1">
|
||||
<span class="text-sm font-medium text-secondary">{{
|
||||
formatFileSize(file.file_size)
|
||||
formatBytes(file.file_size)
|
||||
}}</span>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { formatBytes } from '@modrinth/utils'
|
||||
|
||||
export const fileIsValid = (file, validationOptions) => {
|
||||
const { maxSize, alertOnInvalid } = validationOptions
|
||||
if (maxSize !== null && maxSize !== undefined && file.size > maxSize) {
|
||||
if (alertOnInvalid) {
|
||||
alert(`File ${file.name} is too big! Must be less than ${formatBytes(maxSize)}`)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export const acceptFileFromProjectType = (projectType) => {
|
||||
switch (projectType) {
|
||||
case 'mod':
|
||||
return '.jar,.zip,.litemod,application/java-archive,application/x-java-archive,application/zip'
|
||||
case 'plugin':
|
||||
return '.jar,.zip,application/java-archive,application/x-java-archive,application/zip'
|
||||
case 'resourcepack':
|
||||
return '.zip,application/zip'
|
||||
case 'shader':
|
||||
return '.zip,application/zip'
|
||||
case 'datapack':
|
||||
return '.zip,application/zip'
|
||||
case 'modpack':
|
||||
return '.mrpack,application/x-modrinth-modpack+zip,application/zip'
|
||||
default:
|
||||
return '*'
|
||||
}
|
||||
}
|
||||
@@ -146,7 +146,11 @@
|
||||
const input = e.target
|
||||
if (input.files?.length) {
|
||||
if (
|
||||
fileIsValid(input.files[0], { maxSize: 524288000, alertOnInvalid: true })
|
||||
fileIsValid(
|
||||
input.files[0],
|
||||
{ maxSize: 524288000, alertOnInvalid: true },
|
||||
formatBytes,
|
||||
)
|
||||
)
|
||||
showBannerPreview(Array.from(input.files))
|
||||
}
|
||||
@@ -379,6 +383,7 @@ import {
|
||||
StyledInput,
|
||||
Toggle,
|
||||
UnsavedChangesPopup,
|
||||
useFormatBytes,
|
||||
usePageLeaveSafety,
|
||||
} from '@modrinth/ui'
|
||||
import { fileIsValid, formatProjectStatus, formatProjectType } from '@modrinth/utils'
|
||||
@@ -405,6 +410,8 @@ const flags = useFeatureFlags()
|
||||
const tags = useGeneratedState()
|
||||
const router = useNativeRouter()
|
||||
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
const name = ref(project.value.title)
|
||||
const slug = ref(project.value.slug)
|
||||
const summary = ref(project.value.description)
|
||||
|
||||
@@ -442,9 +442,10 @@ import {
|
||||
MultiSelect,
|
||||
PROJECT_DEP_MARKER_QUERY,
|
||||
StyledInput,
|
||||
useFormatBytes,
|
||||
useFormatDateTime,
|
||||
} from '@modrinth/ui'
|
||||
import { formatBytes, renderHighlightedString } from '@modrinth/utils'
|
||||
import { renderHighlightedString } from '@modrinth/utils'
|
||||
|
||||
import Breadcrumbs from '~/components/ui/Breadcrumbs.vue'
|
||||
import CreateProjectVersionModal from '~/components/ui/create-project-version/CreateProjectVersionModal.vue'
|
||||
@@ -473,6 +474,7 @@ const formatDateTime = useFormatDateTime({
|
||||
dateStyle: 'long',
|
||||
})
|
||||
const formatDate = useFormatDateTime({ dateStyle: 'medium' })
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
// Helper for accessing nuxt app $formatVersion
|
||||
const formatVersionDisplay = (versions: string[]) => (data as any).$formatVersion(versions)
|
||||
|
||||
@@ -81,11 +81,19 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FileIcon, SpinnerIcon, UploadIcon } from '@modrinth/assets'
|
||||
import { Admonition, Avatar, CopyCode, injectNotificationManager } from '@modrinth/ui'
|
||||
import { formatBytes, type Project, type Version } from '@modrinth/utils'
|
||||
import {
|
||||
Admonition,
|
||||
Avatar,
|
||||
CopyCode,
|
||||
injectNotificationManager,
|
||||
useFormatBytes,
|
||||
} from '@modrinth/ui'
|
||||
import type { Project, Version } from '@modrinth/utils'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
|
||||
const formatBytes = useFormatBytes()
|
||||
|
||||
const fileInput = ref<HTMLInputElement>()
|
||||
const selectedFile = ref<File | null>(null)
|
||||
const fileHashes = ref<{
|
||||
|
||||
Reference in New Issue
Block a user