forked from didirus/AstralRinth
devex: migrate to vue-i18n (#4966)
* sample languages refactor * feat: consistency + dedupe impl of i18n * fix: broken imports * fix: intl formatted component * fix: use relative imports * fix: imports * fix: comment out incomplete locales + fix imports * feat: cleanup * fix: ui imports * fix: lint * fix: admonition import * make footer a component, fix language reactivity * make copyright notice untranslatable --------- Co-authored-by: Calum H. <contact@cal.engineer>
This commit is contained in:
@@ -970,7 +970,9 @@ import {
|
||||
ButtonStyled,
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
NewModal,
|
||||
OverflowMenu,
|
||||
PopoutMenu,
|
||||
@@ -985,10 +987,10 @@ import {
|
||||
ServersPromo,
|
||||
TagItem,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import VersionSummary from '@modrinth/ui/src/components/version/VersionSummary.vue'
|
||||
import { formatCategory, formatPrice, formatProjectType, renderString } from '@modrinth/utils'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import { useLocalStorage } from '@vueuse/core'
|
||||
import dayjs from 'dayjs'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
|
||||
@@ -14,9 +14,9 @@ import {
|
||||
commonMessages,
|
||||
commonProjectSettingsMessages,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Project, ProjectV3Partial } from '@modrinth/utils'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
import { useLocalStorage, useScroll } from '@vueuse/core'
|
||||
import { computed } from 'vue'
|
||||
|
||||
|
||||
@@ -3,14 +3,15 @@ import { CheckIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
commonProjectSettingsMessages,
|
||||
defineMessages,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
ProjectSettingsEnvSelector,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
defineMessages,
|
||||
IconSelect,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
injectProjectPageContext,
|
||||
type MessageDescriptor,
|
||||
SettingsLabel,
|
||||
UnsavedChangesPopup,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
|
||||
@@ -326,11 +326,13 @@ import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
CopyCode,
|
||||
defineMessages,
|
||||
DropdownSelect,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
Toggle,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatCategory, formatPrice } from '@modrinth/utils'
|
||||
import { DEFAULT_CREDIT_EMAIL_MESSAGE } from '@modrinth/utils/utils.ts'
|
||||
|
||||
@@ -267,16 +267,17 @@ import {
|
||||
Combobox,
|
||||
commonMessages,
|
||||
CopyCode,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ServerNotice,
|
||||
TagItem,
|
||||
Toggle,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { NOTICE_LEVELS } from '@modrinth/ui/src/utils/notices.ts'
|
||||
import type { ServerNotice as ServerNoticeType } from '@modrinth/utils'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed } from 'vue'
|
||||
|
||||
|
||||
@@ -8,9 +8,15 @@ import {
|
||||
SendIcon,
|
||||
TrashIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Badge, Checkbox, commonMessages } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import {
|
||||
Avatar,
|
||||
Badge,
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import ATLauncher from '~/assets/images/external/atlauncher.svg?component'
|
||||
import CurseForge from '~/assets/images/external/curseforge.svg?component'
|
||||
|
||||
@@ -85,10 +85,12 @@ import {
|
||||
Avatar,
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
normalizeChildren,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
|
||||
import { useAuth } from '@/composables/auth.js'
|
||||
import { useScopes } from '@/composables/auth/scopes.ts'
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { KeyIcon, MailIcon, SendIcon } from '@modrinth/assets'
|
||||
import { commonMessages, injectNotificationManager } from '@modrinth/ui'
|
||||
import { commonMessages, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import HCaptcha from '@/components/ui/HCaptcha.vue'
|
||||
|
||||
|
||||
@@ -140,8 +140,13 @@ import {
|
||||
RightArrowIcon,
|
||||
SteamColorIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { commonMessages, injectNotificationManager } from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import {
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import HCaptcha from '@/components/ui/HCaptcha.vue'
|
||||
import { getAuthUrl, getLauncherRedirectUrl } from '@/composables/auth.js'
|
||||
|
||||
@@ -145,8 +145,14 @@ import {
|
||||
SteamColorIcon,
|
||||
UserIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Checkbox, commonMessages, injectNotificationManager } from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import {
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import HCaptcha from '@/components/ui/HCaptcha.vue'
|
||||
import { getAuthUrl } from '@/composables/auth.js'
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { RightArrowIcon, SettingsIcon } from '@modrinth/assets'
|
||||
import { ButtonStyled, injectNotificationManager } from '@modrinth/ui'
|
||||
import { ButtonStyled, defineMessages, injectNotificationManager, useVIntl } from '@modrinth/ui'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -49,8 +49,14 @@
|
||||
|
||||
<script setup>
|
||||
import { RightArrowIcon, WavingRinthbot } from '@modrinth/assets'
|
||||
import { Checkbox, commonMessages, normalizeChildren } from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import {
|
||||
Checkbox,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
normalizeChildren,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
|
||||
@@ -381,10 +381,13 @@ import {
|
||||
commonProjectTypeCategoryMessages,
|
||||
commonProjectTypeSentenceMessages,
|
||||
ConfirmModal,
|
||||
defineMessage,
|
||||
defineMessages,
|
||||
FileInput,
|
||||
HorizontalRule,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
NewModal,
|
||||
normalizeChildren,
|
||||
NormalPage,
|
||||
@@ -393,10 +396,9 @@ import {
|
||||
SidebarCard,
|
||||
useRelativeTime,
|
||||
useSavable,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { isAdmin } from '@modrinth/utils'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import AdPlaceholder from '~/components/ui/AdPlaceholder.vue'
|
||||
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
OrganizationIcon,
|
||||
ReportIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { commonMessages } from '@modrinth/ui'
|
||||
import { commonMessages, useVIntl } from '@modrinth/ui'
|
||||
import { type User, UserBadge } from '@modrinth/utils'
|
||||
|
||||
import NavStack from '~/components/ui/NavStack.vue'
|
||||
|
||||
@@ -71,10 +71,11 @@ import {
|
||||
Button,
|
||||
ButtonStyled,
|
||||
ConfirmModal,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { AffiliateLink } from '@modrinth/utils'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
|
||||
const createModal = useTemplateRef<typeof AffiliateLinkCreateModal>('createModal')
|
||||
const revokeModal = useTemplateRef<typeof ConfirmModal>('revokeModal')
|
||||
|
||||
@@ -106,7 +106,7 @@ import {
|
||||
SearchIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, Button, commonMessages } from '@modrinth/ui'
|
||||
import { Avatar, Button, commonMessages, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import CollectionCreateModal from '~/components/ui/create/CollectionCreateModal.vue'
|
||||
|
||||
|
||||
@@ -335,6 +335,7 @@ import {
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ProjectStatusBadge,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
@@ -260,8 +260,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ArrowUpRightIcon, InProgressIcon, UnknownIcon } from '@modrinth/assets'
|
||||
import { defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { formatMoney } from '@modrinth/utils'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import dayjs from 'dayjs'
|
||||
import { Tooltip } from 'floating-vue'
|
||||
|
||||
|
||||
@@ -90,9 +90,8 @@ import {
|
||||
GenericListIcon,
|
||||
SpinnerIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { ButtonStyled, Combobox } from '@modrinth/ui'
|
||||
import { ButtonStyled, Combobox, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import { formatMoney } from '@modrinth/utils'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
import RevenueTransaction from '~/components/ui/dashboard/RevenueTransaction.vue'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { commonProjectTypeCategoryMessages } from '@modrinth/ui'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
import { commonProjectTypeCategoryMessages, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import NavTabs from '~/components/ui/NavTabs.vue'
|
||||
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
const flags = useFeatureFlags()
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
SearchIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { defineMessages, useVIntl } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { useRelativeTime } from '@modrinth/ui'
|
||||
import { defineMessages, useRelativeTime, useVIntl } from '@modrinth/ui'
|
||||
|
||||
const vintl = useVIntl()
|
||||
const { formatMessage } = vintl
|
||||
|
||||
@@ -651,10 +651,10 @@ import {
|
||||
commonMessages,
|
||||
injectNotificationManager,
|
||||
ModrinthServersPurchaseModal,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { monthsInInterval } from '@modrinth/ui/src/utils/billing.ts'
|
||||
import { formatPrice } from '@modrinth/utils'
|
||||
import { useVIntl } from '@vintl/vintl'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { useBaseFetch } from '@/composables/fetch.js'
|
||||
|
||||
@@ -385,8 +385,10 @@ import {
|
||||
SettingsIcon,
|
||||
TransferIcon,
|
||||
} from '@modrinth/assets'
|
||||
import type { MessageDescriptor } from '@modrinth/ui'
|
||||
import {
|
||||
ButtonStyled,
|
||||
defineMessage,
|
||||
ErrorInformationCard,
|
||||
injectModrinthClient,
|
||||
injectNotificationManager,
|
||||
@@ -397,7 +399,6 @@ import {
|
||||
} from '@modrinth/ui'
|
||||
import type { PowerAction, Stats } from '@modrinth/utils'
|
||||
import { useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import type { MessageDescriptor } from '@vintl/vintl'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { computed, onMounted, onUnmounted, type Reactive, reactive, ref } from 'vue'
|
||||
|
||||
|
||||
@@ -439,9 +439,15 @@ import {
|
||||
ModrinthIcon,
|
||||
SearchIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled, commonMessages, useRelativeTime } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { ref } from 'vue'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { FolderIcon, ReportIcon, ShieldCheckIcon } from '@modrinth/assets'
|
||||
import { Chips } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { Chips, defineMessages, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import NavTabs from '@/components/ui/NavTabs.vue'
|
||||
|
||||
|
||||
@@ -105,8 +105,15 @@ import {
|
||||
SortDescIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Button, ButtonStyled, Combobox, type ComboboxOption, Pagination } from '@modrinth/ui'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import {
|
||||
Button,
|
||||
ButtonStyled,
|
||||
Combobox,
|
||||
type ComboboxOption,
|
||||
defineMessages,
|
||||
Pagination,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import Fuse from 'fuse.js'
|
||||
import ConfettiExplosion from 'vue-confetti-explosion'
|
||||
|
||||
|
||||
@@ -78,9 +78,15 @@
|
||||
<script setup lang="ts">
|
||||
import { ListFilterIcon, SearchIcon, SortAscIcon, SortDescIcon, XIcon } from '@modrinth/assets'
|
||||
import type { ExtendedReport } from '@modrinth/moderation'
|
||||
import { Button, Combobox, type ComboboxOption, Pagination } from '@modrinth/ui'
|
||||
import {
|
||||
Button,
|
||||
Combobox,
|
||||
type ComboboxOption,
|
||||
defineMessages,
|
||||
Pagination,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Report } from '@modrinth/utils'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import Fuse from 'fuse.js'
|
||||
|
||||
import ReportCard from '~/components/ui/moderation/ModerationReportCard.vue'
|
||||
|
||||
@@ -5,11 +5,12 @@ import {
|
||||
Button,
|
||||
Combobox,
|
||||
type ComboboxOption,
|
||||
defineMessages,
|
||||
injectModrinthClient,
|
||||
Pagination,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { useInfiniteQuery, useQueryClient } from '@tanstack/vue-query'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import Fuse from 'fuse.js'
|
||||
|
||||
import MaliciousSummaryModal, {
|
||||
|
||||
@@ -261,7 +261,14 @@ import {
|
||||
UsersIcon,
|
||||
XIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { Avatar, ButtonStyled, commonMessages, ContentPageHeader, OverflowMenu } from '@modrinth/ui'
|
||||
import {
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
commonMessages,
|
||||
ContentPageHeader,
|
||||
OverflowMenu,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Organization, ProjectStatus, ProjectType, ProjectV3 } from '@modrinth/utils'
|
||||
import { formatNumber } from '@modrinth/utils'
|
||||
|
||||
|
||||
@@ -334,6 +334,7 @@ import {
|
||||
injectNotificationManager,
|
||||
NewModal,
|
||||
ProjectStatusBadge,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
import { Multiselect } from 'vue-multiselect'
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { HeartIcon, ModrinthPlusIcon, SettingsIcon, SparklesIcon, StarIcon } from '@modrinth/assets'
|
||||
import { injectNotificationManager, PurchaseModal } from '@modrinth/ui'
|
||||
import { injectNotificationManager, PurchaseModal, useVIntl } from '@modrinth/ui'
|
||||
import { calculateSavings, formatPrice, getCurrency } from '@modrinth/utils'
|
||||
|
||||
import { useBaseFetch } from '@/composables/fetch.js'
|
||||
|
||||
@@ -281,18 +281,21 @@ import {
|
||||
VersionIcon,
|
||||
XCircleIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { defineMessage } from '@modrinth/ui'
|
||||
import {
|
||||
AutoLink,
|
||||
Avatar,
|
||||
ButtonStyled,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
MarkdownEditor,
|
||||
type MessageDescriptor,
|
||||
RadialHeader,
|
||||
RadioButtons,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import type { Project, Report, User, Version } from '@modrinth/utils'
|
||||
import { defineMessages, type MessageDescriptor, useVIntl } from '@vintl/vintl'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
|
||||
import { useImageUpload } from '~/composables/image-upload.ts'
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ import {
|
||||
ShieldIcon,
|
||||
UserIcon,
|
||||
} from '@modrinth/assets'
|
||||
import { commonMessages, commonSettingsMessages } from '@modrinth/ui'
|
||||
import { commonMessages, commonSettingsMessages, useVIntl } from '@modrinth/ui'
|
||||
|
||||
import NavStack from '~/components/ui/NavStack.vue'
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ import {
|
||||
CopyCode,
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import Modal from '~/components/ui/Modal.vue'
|
||||
|
||||
@@ -95,6 +95,7 @@ import {
|
||||
commonSettingsMessages,
|
||||
ConfirmModal,
|
||||
injectNotificationManager,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
import { useScopes } from '~/composables/auth/scopes.ts'
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Badge, Breadcrumbs } from '@modrinth/ui'
|
||||
import { Badge, Breadcrumbs, useVIntl } from '@modrinth/ui'
|
||||
import { formatPrice } from '@modrinth/utils'
|
||||
|
||||
import { products } from '~/generated/state.json'
|
||||
|
||||
@@ -617,11 +617,13 @@ import {
|
||||
commonMessages,
|
||||
ConfirmModal,
|
||||
CopyCode,
|
||||
defineMessages,
|
||||
getPaymentMethodIcon,
|
||||
injectNotificationManager,
|
||||
OverflowMenu,
|
||||
PurchaseModal,
|
||||
ServerListing,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { calculateSavings, formatPrice, getCurrency } from '@modrinth/utils'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
@@ -205,10 +205,16 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CodeIcon, RadioButtonCheckedIcon, RadioButtonIcon } from '@modrinth/assets'
|
||||
import { Button, injectNotificationManager, normalizeChildren, ThemeSelector } from '@modrinth/ui'
|
||||
import {
|
||||
Button,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
normalizeChildren,
|
||||
ThemeSelector,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { formatProjectType } from '@modrinth/utils'
|
||||
import { defineMessages, useVIntl } from '@vintl/vintl'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
|
||||
import MessageBanner from '~/components/ui/MessageBanner.vue'
|
||||
import type { DisplayLocation } from '~/plugins/cosmetics'
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { IssuesIcon, RadioButtonCheckedIcon, RadioButtonIcon } from '@modrinth/assets'
|
||||
import { Admonition, commonSettingsMessages } from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import { RadioButtonCheckedIcon, RadioButtonIcon } from '@modrinth/assets'
|
||||
import {
|
||||
Admonition,
|
||||
commonSettingsMessages,
|
||||
defineMessages,
|
||||
IntlFormatted,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import Fuse from 'fuse.js/dist/fuse.basic'
|
||||
|
||||
import { isModifierKeyDown } from '~/helpers/events.ts'
|
||||
|
||||
const vintl = useVIntl()
|
||||
const { formatMessage } = vintl
|
||||
const { formatMessage } = useVIntl()
|
||||
const { locale, setLocale, locales } = useI18n()
|
||||
|
||||
const messages = defineMessages({
|
||||
languagesDescription: {
|
||||
@@ -23,10 +28,6 @@ const messages = defineMessages({
|
||||
id: 'settings.language.languages.search.no-results',
|
||||
defaultMessage: 'No languages match your search.',
|
||||
},
|
||||
searchFieldDescription: {
|
||||
id: 'settings.language.languages.search-field.description',
|
||||
defaultMessage: 'Submit to focus the first search result',
|
||||
},
|
||||
searchFieldPlaceholder: {
|
||||
id: 'settings.language.languages.search-field.placeholder',
|
||||
defaultMessage: 'Search for a language...',
|
||||
@@ -36,18 +37,6 @@ const messages = defineMessages({
|
||||
defaultMessage:
|
||||
'{matches, plural, =0 {No languages match} one {# language matches} other {# languages match}} your search.',
|
||||
},
|
||||
loadFailed: {
|
||||
id: 'settings.language.languages.load-failed',
|
||||
defaultMessage: 'Cannot load this language. Try again in a bit.',
|
||||
},
|
||||
languageLabelApplying: {
|
||||
id: 'settings.language.languages.language-label-applying',
|
||||
defaultMessage: '{label}. Applying...',
|
||||
},
|
||||
languageLabelError: {
|
||||
id: 'settings.language.languages.language-label-error',
|
||||
defaultMessage: '{label}. Error',
|
||||
},
|
||||
languageWarning: {
|
||||
id: 'settings.language.warning',
|
||||
defaultMessage:
|
||||
@@ -56,22 +45,10 @@ const messages = defineMessages({
|
||||
})
|
||||
|
||||
const categoryNames = defineMessages({
|
||||
auto: {
|
||||
id: 'settings.language.categories.auto',
|
||||
defaultMessage: 'Automatic',
|
||||
},
|
||||
default: {
|
||||
id: 'settings.language.categories.default',
|
||||
defaultMessage: 'Standard languages',
|
||||
},
|
||||
fun: {
|
||||
id: 'settings.language.categories.fun',
|
||||
defaultMessage: 'Fun languages',
|
||||
},
|
||||
experimental: {
|
||||
id: 'settings.language.categories.experimental',
|
||||
defaultMessage: 'Experimental languages',
|
||||
},
|
||||
searchResult: {
|
||||
id: 'settings.language.categories.search-result',
|
||||
defaultMessage: 'Search results',
|
||||
@@ -80,97 +57,46 @@ const categoryNames = defineMessages({
|
||||
|
||||
type Category = keyof typeof categoryNames
|
||||
|
||||
const categoryOrder: Category[] = ['auto', 'default', 'fun', 'experimental']
|
||||
|
||||
function normalizeCategoryName(name?: string): keyof typeof categoryNames {
|
||||
switch (name) {
|
||||
case 'auto':
|
||||
case 'fun':
|
||||
case 'experimental':
|
||||
return name
|
||||
default:
|
||||
return 'default'
|
||||
}
|
||||
}
|
||||
|
||||
type LocaleBase = {
|
||||
type LocaleInfo = {
|
||||
category: Category
|
||||
tag: string
|
||||
displayName: string
|
||||
nativeName: string
|
||||
searchTerms?: string[]
|
||||
}
|
||||
|
||||
type AutomaticLocale = LocaleBase & {
|
||||
auto: true
|
||||
}
|
||||
|
||||
type CommonLocale = LocaleBase & {
|
||||
auto?: never
|
||||
displayName: string
|
||||
defaultName: string
|
||||
translatedName: string
|
||||
}
|
||||
|
||||
type Locale = AutomaticLocale | CommonLocale
|
||||
|
||||
const $defaultNames = useDisplayNames(() => vintl.defaultLocale)
|
||||
|
||||
const $translatedNames = useDisplayNames(() => vintl.locale)
|
||||
const displayNames = new Intl.DisplayNames(['en'], { type: 'language' })
|
||||
|
||||
const $locales = computed(() => {
|
||||
const locales: Locale[] = []
|
||||
const result: LocaleInfo[] = []
|
||||
|
||||
locales.push({
|
||||
auto: true,
|
||||
tag: 'auto',
|
||||
category: 'auto',
|
||||
searchTerms: [
|
||||
'automatic',
|
||||
'Sync with the system language',
|
||||
formatMessage(messages.automaticLocale),
|
||||
],
|
||||
})
|
||||
const localeList = Array.isArray(locales.value) ? locales.value : Object.keys(locales.value)
|
||||
|
||||
for (const locale of vintl.availableLocales) {
|
||||
let displayName = locale.meta?.displayName
|
||||
for (const loc of localeList) {
|
||||
const tag = typeof loc === 'string' ? loc : loc.code
|
||||
const name = typeof loc === 'object' && loc.name ? loc.name : (displayNames.of(tag) ?? tag)
|
||||
|
||||
if (displayName == null) {
|
||||
displayName = createDisplayNames(locale.tag).of(locale.tag) ?? locale.tag
|
||||
}
|
||||
const nativeDisplayNames = new Intl.DisplayNames([tag], { type: 'language' })
|
||||
const nativeName = nativeDisplayNames.of(tag) ?? tag
|
||||
|
||||
let defaultName = vintl.defaultResources['languages.json']?.[locale.tag]
|
||||
|
||||
if (defaultName == null) {
|
||||
defaultName = $defaultNames.value.of(locale.tag) ?? locale.tag
|
||||
}
|
||||
|
||||
let translatedName = vintl.resources['languages.json']?.[locale.tag]
|
||||
|
||||
if (translatedName == null) {
|
||||
translatedName = $translatedNames.value.of(locale.tag) ?? locale.tag
|
||||
}
|
||||
|
||||
let searchTerms = locale.meta?.searchTerms
|
||||
if (searchTerms === '-') searchTerms = undefined
|
||||
|
||||
locales.push({
|
||||
tag: locale.tag,
|
||||
category: normalizeCategoryName(locale.meta?.category),
|
||||
displayName,
|
||||
defaultName,
|
||||
translatedName,
|
||||
searchTerms: searchTerms?.split('\n'),
|
||||
result.push({
|
||||
tag,
|
||||
category: 'default',
|
||||
displayName: name,
|
||||
nativeName,
|
||||
searchTerms: [tag, name, nativeName],
|
||||
})
|
||||
}
|
||||
|
||||
return locales
|
||||
return result
|
||||
})
|
||||
|
||||
const $query = ref('')
|
||||
|
||||
const isQueryEmpty = () => $query.value.trim().length === 0
|
||||
|
||||
const fuse = new Fuse<Locale>([], {
|
||||
keys: ['tag', 'displayName', 'translatedName', 'englishName', 'searchTerms'],
|
||||
const fuse = new Fuse<LocaleInfo>([], {
|
||||
keys: ['tag', 'displayName', 'nativeName', 'searchTerms'],
|
||||
threshold: 0.4,
|
||||
distance: 100,
|
||||
})
|
||||
@@ -178,32 +104,13 @@ const fuse = new Fuse<Locale>([], {
|
||||
watchSyncEffect(() => fuse.setCollection($locales.value))
|
||||
|
||||
const $categories = computed(() => {
|
||||
const categories = new Map<Category, Locale[]>()
|
||||
|
||||
for (const category of categoryOrder) categories.set(category, [])
|
||||
|
||||
for (const locale of $locales.value) {
|
||||
let categoryLocales = categories.get(locale.category)
|
||||
|
||||
if (categoryLocales == null) {
|
||||
categoryLocales = []
|
||||
categories.set(locale.category, categoryLocales)
|
||||
}
|
||||
|
||||
categoryLocales.push(locale)
|
||||
}
|
||||
|
||||
for (const categoryKey of [...categories.keys()]) {
|
||||
if (categories.get(categoryKey)?.length === 0) {
|
||||
categories.delete(categoryKey)
|
||||
}
|
||||
}
|
||||
|
||||
const categories = new Map<Category, LocaleInfo[]>()
|
||||
categories.set('default', $locales.value)
|
||||
return categories
|
||||
})
|
||||
|
||||
const $searchResults = computed(() => {
|
||||
return new Map<Category, Locale[]>([
|
||||
return new Map<Category, LocaleInfo[]>([
|
||||
['searchResult', isQueryEmpty() ? [] : fuse.search($query.value).map(({ item }) => item)],
|
||||
])
|
||||
})
|
||||
@@ -216,11 +123,9 @@ const $changingTo = ref<string | undefined>()
|
||||
|
||||
const isChanging = () => $changingTo.value != null
|
||||
|
||||
const $failedLocale = ref<string>()
|
||||
|
||||
const $activeLocale = computed(() => {
|
||||
if ($changingTo.value != null) return $changingTo.value
|
||||
return vintl.automatic ? 'auto' : vintl.locale
|
||||
return locale.value
|
||||
})
|
||||
|
||||
async function changeLocale(value: string) {
|
||||
@@ -229,10 +134,7 @@ async function changeLocale(value: string) {
|
||||
$changingTo.value = value
|
||||
|
||||
try {
|
||||
await vintl.changeLocale(value)
|
||||
$failedLocale.value = undefined
|
||||
} catch {
|
||||
$failedLocale.value = value
|
||||
await setLocale(value)
|
||||
} finally {
|
||||
$changingTo.value = undefined
|
||||
}
|
||||
@@ -250,7 +152,7 @@ function onSearchKeydown(e: KeyboardEvent) {
|
||||
focusableTarget?.focus()
|
||||
}
|
||||
|
||||
function onItemKeydown(e: KeyboardEvent, locale: Locale) {
|
||||
function onItemKeydown(e: KeyboardEvent, loc: LocaleInfo) {
|
||||
switch (e.key) {
|
||||
case 'Enter':
|
||||
case ' ':
|
||||
@@ -261,29 +163,17 @@ function onItemKeydown(e: KeyboardEvent, locale: Locale) {
|
||||
|
||||
if (isModifierKeyDown(e) || isChanging()) return
|
||||
|
||||
changeLocale(locale.tag)
|
||||
changeLocale(loc.tag)
|
||||
}
|
||||
|
||||
function onItemClick(e: MouseEvent, locale: Locale) {
|
||||
function onItemClick(e: MouseEvent, loc: LocaleInfo) {
|
||||
if (isModifierKeyDown(e) || isChanging()) return
|
||||
|
||||
changeLocale(locale.tag)
|
||||
changeLocale(loc.tag)
|
||||
}
|
||||
|
||||
function getItemLabel(locale: Locale) {
|
||||
const label = locale.auto
|
||||
? formatMessage(messages.automaticLocale)
|
||||
: `${locale.translatedName}. ${locale.displayName}`
|
||||
|
||||
if ($changingTo.value === locale.tag) {
|
||||
return formatMessage(messages.languageLabelApplying, { label })
|
||||
}
|
||||
|
||||
if ($failedLocale.value === locale.tag) {
|
||||
return formatMessage(messages.languageLabelError, { label })
|
||||
}
|
||||
|
||||
return label
|
||||
function getItemLabel(loc: LocaleInfo) {
|
||||
return `${loc.nativeName}. ${loc.displayName}`
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -298,7 +188,7 @@ function getItemLabel(locale: Locale) {
|
||||
|
||||
<div class="card-description mt-4">
|
||||
<IntlFormatted :message-id="messages.languagesDescription">
|
||||
<template #crowdin-link="{ children }">
|
||||
<template #~crowdin-link="{ children }">
|
||||
<a href="https://translate.modrinth.com">
|
||||
<component :is="() => children" />
|
||||
</a>
|
||||
@@ -306,7 +196,7 @@ function getItemLabel(locale: Locale) {
|
||||
</IntlFormatted>
|
||||
</div>
|
||||
|
||||
<div class="search-container">
|
||||
<div v-if="$locales.length > 1" class="search-container">
|
||||
<input
|
||||
id="language-search"
|
||||
v-model="$query"
|
||||
@@ -314,15 +204,10 @@ function getItemLabel(locale: Locale) {
|
||||
type="search"
|
||||
:placeholder="formatMessage(messages.searchFieldPlaceholder)"
|
||||
class="language-search"
|
||||
aria-describedby="language-search-description"
|
||||
:disabled="isChanging()"
|
||||
@keydown="onSearchKeydown"
|
||||
/>
|
||||
|
||||
<div id="language-search-description" class="visually-hidden">
|
||||
{{ formatMessage(messages.searchFieldDescription) }}
|
||||
</div>
|
||||
|
||||
<div id="language-search-results-announcements" class="visually-hidden" aria-live="polite">
|
||||
{{
|
||||
isQueryEmpty()
|
||||
@@ -335,59 +220,46 @@ function getItemLabel(locale: Locale) {
|
||||
</div>
|
||||
|
||||
<div ref="$languagesList" class="languages-list">
|
||||
<template v-for="[category, locales] in $displayCategories" :key="category">
|
||||
<template v-for="[category, categoryLocales] in $displayCategories" :key="category">
|
||||
<strong class="category-name">
|
||||
{{ formatMessage(categoryNames[category]) }}
|
||||
</strong>
|
||||
|
||||
<div
|
||||
v-if="category === 'searchResult' && locales.length === 0"
|
||||
v-if="category === 'searchResult' && categoryLocales.length === 0"
|
||||
class="no-results"
|
||||
tabindex="0"
|
||||
>
|
||||
{{ formatMessage(messages.noResults) }}
|
||||
</div>
|
||||
|
||||
<template v-for="locale in locales" :key="locale.tag">
|
||||
<template v-for="loc in categoryLocales" :key="loc.tag">
|
||||
<div
|
||||
role="button"
|
||||
:aria-pressed="$activeLocale === locale.tag"
|
||||
:aria-pressed="$activeLocale === loc.tag"
|
||||
:class="{
|
||||
'language-item': true,
|
||||
pending: $changingTo == locale.tag,
|
||||
errored: $failedLocale == locale.tag,
|
||||
pending: $changingTo === loc.tag,
|
||||
}"
|
||||
:aria-describedby="
|
||||
$failedLocale == locale.tag ? `language__${locale.tag}__fail` : undefined
|
||||
"
|
||||
:aria-disabled="isChanging() && $changingTo !== locale.tag"
|
||||
:aria-disabled="isChanging() && $changingTo !== loc.tag"
|
||||
:tabindex="0"
|
||||
:aria-label="getItemLabel(locale)"
|
||||
@click="(e) => onItemClick(e, locale)"
|
||||
@keydown="(e) => onItemKeydown(e, locale)"
|
||||
:aria-label="getItemLabel(loc)"
|
||||
@click="(e) => onItemClick(e, loc)"
|
||||
@keydown="(e) => onItemKeydown(e, loc)"
|
||||
>
|
||||
<RadioButtonCheckedIcon v-if="$activeLocale === locale.tag" class="radio" />
|
||||
<RadioButtonCheckedIcon v-if="$activeLocale === loc.tag" class="radio" />
|
||||
<RadioButtonIcon v-else class="radio" />
|
||||
|
||||
<div class="language-names">
|
||||
<div class="language-name">
|
||||
{{ locale.auto ? formatMessage(messages.automaticLocale) : locale.displayName }}
|
||||
{{ loc.displayName }}
|
||||
</div>
|
||||
|
||||
<div v-if="!locale.auto" class="language-translated-name">
|
||||
{{ locale.translatedName }}
|
||||
<div class="language-translated-name">
|
||||
{{ loc.nativeName }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="$failedLocale === locale.tag"
|
||||
:id="`language__${locale.tag}__fail`"
|
||||
class="language-load-error"
|
||||
>
|
||||
<IssuesIcon />
|
||||
{{ formatMessage(messages.loadFailed) }}
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
@@ -423,14 +295,6 @@ function getItemLabel(locale: Locale) {
|
||||
outline: 2px solid var(--color-brand);
|
||||
}
|
||||
|
||||
&.errored {
|
||||
border-color: var(--color-red);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-red);
|
||||
}
|
||||
}
|
||||
|
||||
&.pending::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -482,15 +346,6 @@ function getItemLabel(locale: Locale) {
|
||||
}
|
||||
}
|
||||
|
||||
.language-load-error {
|
||||
color: var(--color-red);
|
||||
font-size: var(--font-size-sm);
|
||||
margin-left: 0.3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.radio {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
@@ -534,4 +389,9 @@ function getItemLabel(locale: Locale) {
|
||||
.category-name {
|
||||
margin-top: var(--spacing-card-md);
|
||||
}
|
||||
|
||||
.no-results {
|
||||
padding: var(--spacing-card-md);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -209,10 +209,12 @@ import {
|
||||
commonSettingsMessages,
|
||||
ConfirmModal,
|
||||
CopyCode,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
|
||||
import Modal from '~/components/ui/Modal.vue'
|
||||
import {
|
||||
|
||||
@@ -91,8 +91,16 @@
|
||||
|
||||
<script setup>
|
||||
import { SaveIcon, TrashIcon, UndoIcon, UploadIcon, UserIcon, XIcon } from '@modrinth/assets'
|
||||
import { Avatar, Button, commonMessages, FileInput, injectNotificationManager } from '@modrinth/ui'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
commonMessages,
|
||||
defineMessages,
|
||||
FileInput,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
const { addNotification } = injectNotificationManager()
|
||||
const { formatMessage } = useVIntl()
|
||||
|
||||
@@ -60,8 +60,10 @@ import { XIcon } from '@modrinth/assets'
|
||||
import {
|
||||
commonMessages,
|
||||
commonSettingsMessages,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
|
||||
definePageMeta({
|
||||
|
||||
@@ -482,14 +482,16 @@ import {
|
||||
Combobox,
|
||||
commonMessages,
|
||||
ContentPageHeader,
|
||||
defineMessages,
|
||||
injectNotificationManager,
|
||||
IntlFormatted,
|
||||
NewModal,
|
||||
OverflowMenu,
|
||||
TagItem,
|
||||
useRelativeTime,
|
||||
useVIntl,
|
||||
} from '@modrinth/ui'
|
||||
import { isAdmin, isStaff, UserBadge } from '@modrinth/utils'
|
||||
import { IntlFormatted } from '@vintl/vintl/components'
|
||||
|
||||
import TenMClubBadge from '~/assets/images/badges/10m-club.svg?component'
|
||||
import AlphaTesterBadge from '~/assets/images/badges/alpha-tester.svg?component'
|
||||
|
||||
Reference in New Issue
Block a user