From 1bbb01bd420b8a48df00f7589ca23851a9ada347 Mon Sep 17 00:00:00 2001 From: Prospector <6166773+Prospector@users.noreply.github.com> Date: Sat, 27 Dec 2025 13:37:37 -0800 Subject: [PATCH] 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. --- apps/app-frontend/package.json | 3 +- apps/app-frontend/src/App.vue | 3 +- .../src/components/ui/UpdateToast.vue | 3 +- .../src/components/ui/friends/FriendsList.vue | 5 +- .../components/ui/friends/FriendsSection.vue | 10 +- .../ui/instance_settings/GeneralSettings.vue | 3 +- .../ui/instance_settings/HooksSettings.vue | 3 +- .../InstallationSettings.vue | 3 +- .../ui/instance_settings/JavaSettings.vue | 3 +- .../ui/instance_settings/WindowSettings.vue | 3 +- .../components/ui/modal/AppSettingsModal.vue | 3 +- .../ui/modal/InstanceSettingsModal.vue | 3 +- .../src/components/ui/world/InstanceItem.vue | 2 +- .../src/components/ui/world/WorldItem.vue | 5 +- .../ui/world/modal/AddServerModal.vue | 9 +- .../ui/world/modal/EditServerModal.vue | 9 +- .../modal/EditSingleplayerWorldModal.vue | 10 +- .../ui/world/modal/HideFromHomeOption.vue | 3 +- .../ui/world/modal/ServerModalBody.vue | 3 +- apps/app-frontend/src/i18n.config.ts | 18 + apps/app-frontend/src/main.js | 21 +- apps/app-frontend/src/pages/Browse.vue | 3 +- apps/app-frontend/src/pages/instance/Mods.vue | 3 +- .../src/pages/instance/Worlds.vue | 2 +- apps/frontend/nuxt.config.ts | 190 +- apps/frontend/package.json | 6 +- .../src/components/ui/ModrinthFooter.vue | 316 ++++ .../src/components/ui/ProjectMemberHeader.vue | 9 +- .../stages/AddFilesStage.vue | 8 +- .../ui/create/CollectionCreateModal.vue | 9 +- .../components/ui/create/CreateLimitAlert.vue | 3 +- .../ui/create/OrganizationCreateModal.vue | 9 +- .../ui/create/ProjectCreateModal.vue | 10 +- .../ui/dashboard/CreatorTaxFormModal.vue | 5 +- .../ui/dashboard/CreatorWithdrawModal.vue | 10 +- .../ui/dashboard/RevenueInputField.vue | 9 +- .../ui/dashboard/WithdrawFeeBreakdown.vue | 2 +- .../withdraw-stages/CompletionStage.vue | 4 +- .../LegacyPaypalDetailsStage.vue | 5 +- .../withdraw-stages/MethodSelectionStage.vue | 5 +- .../withdraw-stages/MuralpayDetailsStage.vue | 5 +- .../withdraw-stages/MuralpayKycStage.vue | 10 +- .../withdraw-stages/TaxFormStage.vue | 11 +- .../TremendousDetailsStage.vue | 5 +- .../ui/moderation/ModerationProjectNags.vue | 3 +- .../src/components/ui/news/LatestNewsRow.vue | 3 +- .../ui/servers/PanelServerActionButton.vue | 2 +- .../ui/servers/PlatformVersionSelectModal.vue | 1 + .../ui/servers/ServerInstallation.vue | 2 +- .../servers/marketing/ServerPlanSelector.vue | 4 +- .../ui/servers/notice/NoticeDashboardItem.vue | 2 +- apps/frontend/src/composables/generated.ts | 3 + apps/frontend/src/error.vue | 5 +- apps/frontend/src/i18n.config.ts | 15 + apps/frontend/src/layouts/default.vue | 339 +--- apps/frontend/src/locales/en-US/index.json | 24 - apps/frontend/src/pages/[type]/[id].vue | 4 +- .../src/pages/[type]/[id]/settings.vue | 2 +- .../[type]/[id]/settings/environment.vue | 3 +- .../pages/[type]/[id]/settings/general.vue | 4 +- .../frontend/src/pages/admin/billing/[id].vue | 2 + .../src/pages/admin/servers/notices.vue | 3 +- apps/frontend/src/pages/app.vue | 12 +- apps/frontend/src/pages/auth/authorize.vue | 4 +- .../src/pages/auth/reset-password.vue | 2 +- apps/frontend/src/pages/auth/sign-in.vue | 9 +- apps/frontend/src/pages/auth/sign-up.vue | 10 +- apps/frontend/src/pages/auth/verify-email.vue | 2 +- apps/frontend/src/pages/auth/welcome.vue | 10 +- apps/frontend/src/pages/collection/[id].vue | 6 +- apps/frontend/src/pages/dashboard.vue | 2 +- .../src/pages/dashboard/affiliate-links.vue | 3 +- .../src/pages/dashboard/collections.vue | 2 +- .../frontend/src/pages/dashboard/projects.vue | 1 + .../src/pages/dashboard/revenue/index.vue | 2 +- .../src/pages/dashboard/revenue/transfers.vue | 3 +- apps/frontend/src/pages/discover.vue | 4 +- .../src/pages/discover/[type]/index.vue | 1 + apps/frontend/src/pages/frog.vue | 2 +- apps/frontend/src/pages/hosting/index.vue | 2 +- .../src/pages/hosting/manage/[id].vue | 3 +- apps/frontend/src/pages/index.vue | 12 +- apps/frontend/src/pages/moderation.vue | 3 +- apps/frontend/src/pages/moderation/index.vue | 11 +- .../src/pages/moderation/reports/index.vue | 10 +- .../src/pages/moderation/technical-review.vue | 3 +- apps/frontend/src/pages/organization/[id].vue | 9 +- .../organization/[id]/settings/projects.vue | 1 + apps/frontend/src/pages/plus.vue | 2 +- apps/frontend/src/pages/report.vue | 7 +- apps/frontend/src/pages/settings.vue | 2 +- .../src/pages/settings/applications.vue | 1 + .../src/pages/settings/authorizations.vue | 1 + .../src/pages/settings/billing/charges.vue | 2 +- .../src/pages/settings/billing/index.vue | 2 + apps/frontend/src/pages/settings/index.vue | 12 +- apps/frontend/src/pages/settings/language.vue | 262 +-- apps/frontend/src/pages/settings/pats.vue | 4 +- apps/frontend/src/pages/settings/profile.vue | 12 +- apps/frontend/src/pages/settings/sessions.vue | 2 + apps/frontend/src/pages/user/[id].vue | 4 +- .../src/providers/creator-withdraw.ts | 2 +- apps/frontend/src/types/vintl.d.ts | 26 +- apps/frontend/src/utils/i18n-project-type.ts | 2 + apps/frontend/src/utils/muralpay-rails.ts | 2 +- packages/moderation/package.json | 4 +- packages/moderation/src/data/nags/core.ts | 2 +- .../moderation/src/data/nags/description.ts | 2 +- packages/moderation/src/data/nags/links.ts | 2 +- packages/moderation/src/data/nags/tags.ts | 2 +- packages/moderation/src/types/nags.ts | 2 +- packages/ui/package.json | 5 +- .../affiliate/AffiliateLinkCard.vue | 4 +- .../affiliate/AffiliateLinkCreateModal.vue | 4 +- packages/ui/src/components/base/Badge.vue | 3 +- packages/ui/src/components/base/CopyCode.vue | 3 +- .../components/base/EnvironmentIndicator.vue | 3 +- packages/ui/src/components/base/FilterBar.vue | 3 +- .../ui/src/components/base/IconSelect.vue | 2 +- .../ui/src/components/base/IntlFormatted.vue | 70 + .../ui/src/components/base/MarkdownEditor.vue | 2 +- .../ui/src/components/base/OptionGroup.vue | 2 +- .../ui/src/components/base/ServerNotice.vue | 2 +- .../ui/src/components/base/SettingsLabel.vue | 5 +- .../components/base/UnsavedChangesPopup.vue | 2 +- packages/ui/src/components/base/index.ts | 1 + .../billing/AddPaymentMethodModal.vue | 3 +- .../billing/ExpandableInvoiceTotal.vue | 2 +- .../billing/FormattedPaymentMethod.vue | 2 +- .../billing/ModalBasedServerPlan.vue | 2 +- .../billing/ModrinthServersPurchaseModal.vue | 2 +- .../src/components/billing/PurchaseModal.vue | 2 +- .../billing/ServersPurchase0Plan.vue | 2 +- .../billing/ServersPurchase1Region.vue | 4 +- .../billing/ServersPurchase2PaymentMethod.vue | 2 +- .../billing/ServersPurchase3Review.vue | 2 +- .../billing/ServersRegionButton.vue | 3 +- .../components/changelog/ChangelogEntry.vue | 2 +- .../ui/src/components/modal/TabbedModal.vue | 3 +- .../project/ProjectPageVersions.vue | 2 +- .../project/ProjectSidebarCompatibility.vue | 7 +- .../project/ProjectSidebarCreators.vue | 2 +- .../project/ProjectSidebarDetails.vue | 2 +- .../project/ProjectSidebarLinks.vue | 3 +- .../components/project/ProjectStatusBadge.vue | 2 +- .../ProjectSettingsEnvSelector.vue | 2 +- .../components/search/SearchFilterControl.vue | 2 +- .../components/search/SearchSidebarFilter.vue | 2 +- .../components/servers/backups/BackupItem.vue | 2 +- .../src/components/settings/ThemeSelector.vue | 2 +- .../version/VersionChannelIndicator.vue | 3 +- .../src/components/version/VersionSummary.vue | 1 + packages/ui/src/composables/how-ago.ts | 65 +- packages/ui/src/composables/i18n.ts | 195 ++ packages/ui/src/composables/index.ts | 1 + packages/ui/src/utils/common-messages.ts | 2 +- packages/ui/src/utils/game-modes.ts | 3 +- packages/ui/src/utils/notices.ts | 2 +- packages/ui/src/utils/regions.ts | 2 +- packages/ui/src/utils/search.ts | 3 +- pnpm-lock.yaml | 1643 ++++------------- 161 files changed, 1449 insertions(+), 2314 deletions(-) create mode 100644 apps/app-frontend/src/i18n.config.ts create mode 100644 apps/frontend/src/components/ui/ModrinthFooter.vue create mode 100644 apps/frontend/src/i18n.config.ts create mode 100644 packages/ui/src/components/base/IntlFormatted.vue create mode 100644 packages/ui/src/composables/i18n.ts diff --git a/apps/app-frontend/package.json b/apps/app-frontend/package.json index 44439c79..a0468e28 100644 --- a/apps/app-frontend/package.json +++ b/apps/app-frontend/package.json @@ -28,7 +28,8 @@ "@tauri-apps/plugin-updater": "^2.7.1", "@tauri-apps/plugin-window-state": "^2.2.2", "@types/three": "^0.172.0", - "@vintl/vintl": "^4.4.1", + "intl-messageformat": "^10.7.7", + "vue-i18n": "^9.14.0", "@vueuse/core": "^11.1.0", "dayjs": "^1.11.10", "floating-vue": "^5.2.2", diff --git a/apps/app-frontend/src/App.vue b/apps/app-frontend/src/App.vue index 26f041fd..4901748d 100644 --- a/apps/app-frontend/src/App.vue +++ b/apps/app-frontend/src/App.vue @@ -31,6 +31,7 @@ import { Button, ButtonStyled, commonMessages, + defineMessages, NewsArticleCard, NotificationPanel, OverflowMenu, @@ -39,6 +40,7 @@ import { provideNotificationManager, providePageContext, useDebugLogger, + useVIntl, } from '@modrinth/ui' import { renderString } from '@modrinth/utils' import { useQuery } from '@tanstack/vue-query' @@ -48,7 +50,6 @@ import { getCurrentWindow } from '@tauri-apps/api/window' import { openUrl } from '@tauri-apps/plugin-opener' import { type } from '@tauri-apps/plugin-os' import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state' -import { defineMessages, useVIntl } from '@vintl/vintl' import { $fetch } from 'ofetch' import { computed, onMounted, onUnmounted, provide, ref, watch } from 'vue' import { RouterView, useRoute, useRouter } from 'vue-router' diff --git a/apps/app-frontend/src/components/ui/UpdateToast.vue b/apps/app-frontend/src/components/ui/UpdateToast.vue index af967608..b9b95f23 100644 --- a/apps/app-frontend/src/components/ui/UpdateToast.vue +++ b/apps/app-frontend/src/components/ui/UpdateToast.vue @@ -1,8 +1,7 @@ + + + diff --git a/apps/frontend/src/components/ui/ProjectMemberHeader.vue b/apps/frontend/src/components/ui/ProjectMemberHeader.vue index be287995..3cf8f8e5 100644 --- a/apps/frontend/src/components/ui/ProjectMemberHeader.vue +++ b/apps/frontend/src/components/ui/ProjectMemberHeader.vue @@ -24,9 +24,14 @@ diff --git a/apps/frontend/src/pages/settings/pats.vue b/apps/frontend/src/pages/settings/pats.vue index bf55bb70..8294f2ae 100644 --- a/apps/frontend/src/pages/settings/pats.vue +++ b/apps/frontend/src/pages/settings/pats.vue @@ -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 { diff --git a/apps/frontend/src/pages/settings/profile.vue b/apps/frontend/src/pages/settings/profile.vue index 12be87dd..b898d5c8 100644 --- a/apps/frontend/src/pages/settings/profile.vue +++ b/apps/frontend/src/pages/settings/profile.vue @@ -91,8 +91,16 @@ + + diff --git a/packages/ui/src/components/base/MarkdownEditor.vue b/packages/ui/src/components/base/MarkdownEditor.vue index 5cd84290..90217e25 100644 --- a/packages/ui/src/components/base/MarkdownEditor.vue +++ b/packages/ui/src/components/base/MarkdownEditor.vue @@ -292,11 +292,11 @@ import { XIcon, YouTubeIcon, } from '@modrinth/assets' -import NewModal from '@modrinth/ui/src/components/modal/NewModal.vue' import { markdownCommands, modrinthMarkdownEditorKeymap } from '@modrinth/utils/codemirror' import { renderHighlightedString } from '@modrinth/utils/highlightjs' import { type Component, computed, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue' +import NewModal from '../modal/NewModal.vue' import Button from './Button.vue' import Chips from './Chips.vue' import FileInput from './FileInput.vue' diff --git a/packages/ui/src/components/base/OptionGroup.vue b/packages/ui/src/components/base/OptionGroup.vue index 556e2cdb..d14c4e0a 100644 --- a/packages/ui/src/components/base/OptionGroup.vue +++ b/packages/ui/src/components/base/OptionGroup.vue @@ -31,7 +31,7 @@