diff --git a/knip.jsonc b/knip.jsonc index ced8214ddc..f1bf40dba9 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -9,6 +9,7 @@ "local.ts", "scripts/*.{js,mjs,ts}", "taze.config.ts", + "x18n.config.ts", "tests/{e2e,docs-screenshots}/**/*.ts" ], "project": [ diff --git a/package.json b/package.json index 2b7e99a0c1..02b78ee3b2 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "watch": "turbo watch build", "dev": "pnpm run build && pnpm -C packages/devtools dev", "lint": "eslint --cache .", + "i18n:check": "x18n check", "knip": "knip", "release": "pnpm test && bumpp -r --all", "test": "pnpm lint && pnpm test:unit", @@ -43,6 +44,7 @@ "@types/node": "catalog:types", "@unocss/eslint-config": "catalog:buildtools", "@vitejs/devtools-kit": "catalog:types", + "@x18n/cli": "catalog:cli", "bumpp": "catalog:cli", "eslint": "catalog:cli", "eslint-flat-config-utils": "catalog:cli", diff --git a/packages/devtools/client/app.vue b/packages/devtools/client/app.vue index 192b1b240d..c678062348 100644 --- a/packages/devtools/client/app.vue +++ b/packages/devtools/client/app.vue @@ -7,6 +7,7 @@ import { useCopy } from '~/composables/editor' import { setupFrameNav } from '~/composables/frame-nav' import { WS_DEBOUNCE_TIME } from '~/composables/rpc' import { registerCommands } from '~/composables/state-commands' +import { i18n } from '~/i18n' import { wsConnectedOnce } from './composables/rpc' import { useSchemaInput } from './composables/state-schema' import { useDevToolsOptions } from './composables/storage-options' @@ -117,7 +118,7 @@ registerCommands(() => [ ? [ { id: 'action:eye-dropper', - title: 'Color Picker', + title: i18n.global.t('commands.colorPicker'), icon: 'i-carbon-eyedropper', action: async () => { const { sRGBHex } = await eyeDropper.open() || {} @@ -130,13 +131,13 @@ registerCommands(() => [ ...[ { id: 'action:refresh-data', - title: 'Refresh Data', + title: i18n.global.t('commands.refreshData'), icon: 'i-carbon-data-backup', action: refreshData, }, { id: 'action:reload-page', - title: 'Reload Page', + title: i18n.global.t('commands.reloadPage'), icon: 'i-carbon-reset', action: reloadPage, }, @@ -148,7 +149,7 @@ registerCommands(() => [
- Connecting.... + {{ $t('common.connecting') }}
- Disconnected from Server + {{ $t('connection.disconnected') }}
- Retrying... + {{ $t('connection.retrying') }}
- Reload DevTools Page + {{ $t('connection.reload') }}
diff --git a/packages/devtools/client/composables/frame-nav.ts b/packages/devtools/client/composables/frame-nav.ts index 78a19903a5..7ea3b10fb5 100644 --- a/packages/devtools/client/composables/frame-nav.ts +++ b/packages/devtools/client/composables/frame-nav.ts @@ -2,6 +2,7 @@ import type { ModuleBuiltinTab, ModuleCustomTab } from '~/../src/types' import { computed, watch } from 'vue' import { useRouter } from '#app/composables/router' import { useEnabledTabs } from '~/composables/state-tabs' +import { i18n } from '~/i18n' // `devframe:frame-nav` — the embedded-app half of the shared-iframe soft-nav // protocol (devframe#128 / vitejs/devtools#464). The Vite DevTools dock owns @@ -31,9 +32,8 @@ interface FrameNavTab { } /** The DevTools settings page, surfaced as its own dock member. */ -const SETTINGS_TAB: FrameNavTab = { +const SETTINGS_TAB: Omit = { id: 'settings', - title: 'Settings', icon: 'carbon:settings', category: '~builtin', // sort last within its sub-category (higher `order` renders earlier) @@ -88,7 +88,10 @@ export function setupFrameNav(): void { path: tabPath(tab), }, })), - SETTINGS_TAB, + { + ...SETTINGS_TAB, + title: i18n.global.t('common.settings'), + }, ]) function currentTabId(): string | undefined { @@ -138,8 +141,9 @@ export function setupFrameNav(): void { // Announce proactively in case the host attached before this shim loaded. announce('ready') - // Re-announce when the conditional tab set changes (show()/settings/etc). - watch(() => manifest.value.map(entry => entry.id).join(','), () => announce('manifest')) + // Re-announce when the conditional tab set changes (show()/settings/etc), + // or when the titles change (the DevTools language was switched). + watch(() => manifest.value.map(entry => `${entry.id}:${entry.title}`).join(','), () => announce('manifest')) // Report in-app navigation so the dock highlight follows. watch(() => router.currentRoute.value.path, () => { diff --git a/packages/devtools/client/composables/locale.ts b/packages/devtools/client/composables/locale.ts new file mode 100644 index 0000000000..7da9012f31 --- /dev/null +++ b/packages/devtools/client/composables/locale.ts @@ -0,0 +1,112 @@ +import type { DevToolsRpcClient } from '@vitejs/devtools-kit/client' +import type { ComputedRef, Ref } from 'vue' +import type { DevToolsLocale } from '../i18n/locales' +import { matchLocale } from '@devframes/hub' +import { useLocalStorage, useNavigatorLanguage } from '@vueuse/core' +import { computed, ref, shallowRef, watch } from 'vue' +import { DEFAULT_LOCALE, DEVFRAME_LOCALE_STORAGE_KEY, DEVTOOLS_LOCALES, LOCALE_AUTO } from '../i18n/locales' +import { rpcClient } from './rpc' + +const available = Object.keys(DEVTOOLS_LOCALES) as DevToolsLocale[] + +/** Closest supported DevTools locale for a BCP 47 tag, using Devframe's matching rules. */ +export function matchDevToolsLocale(tag: string | undefined | null): DevToolsLocale | undefined { + return matchLocale(tag ?? undefined, available) as DevToolsLocale | undefined +} + +/** + * The visitor's language pick, owned by the Devframe hub UI (Settings → + * Appearance): `'auto'` or a locale tag. DevTools only reads the hub's own + * `localStorage` key, so a change in the hub reaches DevTools live via the + * `storage` event. + */ +function useLocalePreference(): Ref { + try { + return useLocalStorage(DEVFRAME_LOCALE_STORAGE_KEY, LOCALE_AUTO, { + // Never write: an absent key already means `auto` to the hub. + writeDefaults: false, + listenToStorageChanges: true, + }) + } + catch { + // Reading `window.localStorage` throws when the browser blocks storage. + // Fall back to `auto` rather than failing the whole client at startup. + return ref(LOCALE_AUTO) + } +} + +/** + * The host's default language, as the server published it in + * `__connection.json` (`createUi({ locale })` → `configs.ui.locale`). + * + * The live `client.connectionMeta` can't be used for this: the running hub UI + * overwrites `configs.ui.locale` there with the language it resolved, and an + * embedded frame shares the hub's connection object (devframe reads it from + * the parent window). Fetching the descriptor again gives the untouched value. + */ +async function fetchHostDefault(client: DevToolsRpcClient): Promise { + try { + const response = await fetch(client.connection.metaBaseUrl) + if (!response.ok) + return undefined + const meta = await response.json() as { configs?: { ui?: { locale?: string } } } + return matchDevToolsLocale(meta.configs?.ui?.locale) + } + catch { + return undefined + } +} + +let resolved: ComputedRef | undefined + +/** + * The language DevTools renders in, resolved the same way the Devframe hub UI + * resolves its own: + * + * 1. the visitor's pick in the hub settings (unless `auto`); + * 2. the host's default, `configs.ui.locale` in `__connection.json`; + * 3. the browser language; + * 4. English. + */ +export function useDevToolsLocale(): ComputedRef { + if (resolved) + return resolved + + const pick = useLocalePreference() + const { language } = useNavigatorLanguage() + + const hostDefault = shallowRef() + let hostDefaultRequested = false + watch(rpcClient, async (client) => { + if (!client || hostDefaultRequested) + return + hostDefaultRequested = true + hostDefault.value = await fetchHostDefault(client) + }, { immediate: true }) + + resolved = computed(() => { + if (pick.value && pick.value !== LOCALE_AUTO) { + const matched = matchDevToolsLocale(pick.value) + if (matched) + return matched + } + + if (hostDefault.value) + return hostDefault.value + + // Read `language` unconditionally so the `languagechange` event + // re-evaluates this, then prefer the full `navigator.languages` list. + const primary = language.value + const languages = typeof navigator !== 'undefined' && navigator.languages?.length + ? navigator.languages + : [primary] + for (const tag of languages) { + const matched = matchDevToolsLocale(tag) + if (matched) + return matched + } + + return DEFAULT_LOCALE + }) + return resolved +} diff --git a/packages/devtools/client/composables/state-commands.ts b/packages/devtools/client/composables/state-commands.ts index 2b43f81879..9a91deb7ef 100644 --- a/packages/devtools/client/composables/state-commands.ts +++ b/packages/devtools/client/composables/state-commands.ts @@ -2,6 +2,7 @@ import type { MaybeRefOrGetter } from 'vue' import { randomStr } from '@antfu/utils' import { computed, onUnmounted, reactive, toValue } from 'vue' import { useRouter } from '#app/composables/router' +import { i18n } from '../i18n' import { useEnabledTabs } from './state-tabs' export interface CommandItem { @@ -18,10 +19,10 @@ export function useCommands() { const tabs = useEnabledTabs() const router = useRouter() - const fixedCommands: CommandItem[] = [ + const fixedCommands = computed((): CommandItem[] => [ { id: 'fixed:settings', - title: 'Settings', + title: i18n.global.t('common.settings'), icon: 'carbon-settings-adjust', action: () => { router.push('/settings') @@ -29,13 +30,13 @@ export function useCommands() { }, { id: 'fixed:docs', - title: 'Nuxt Documentations', + title: i18n.global.t('commands.nuxtDocs'), icon: 'logos-nuxt-icon', action: () => { return getNuxtDocsCommands() }, }, - ] + ]) const tabCommands = computed(() => tabs.value .map((i): CommandItem => { @@ -58,7 +59,7 @@ export function useCommands() { return computed(() => { return [ - ...fixedCommands, + ...fixedCommands.value, ...tabCommands.value, ...[ ...registeredCommands.values(), diff --git a/packages/devtools/client/composables/state-tabs.ts b/packages/devtools/client/composables/state-tabs.ts index cd43322984..79c1ac42b2 100644 --- a/packages/devtools/client/composables/state-tabs.ts +++ b/packages/devtools/client/composables/state-tabs.ts @@ -2,6 +2,7 @@ import type { ModuleBuiltinTab, ModuleCustomTab, RouteInfo, TabCategory } from ' import { objectPick } from '@antfu/utils' import { computed, toValue } from 'vue' import { useRouter } from '#app/composables/router' +import { i18n } from '../i18n' import { useClientRouter } from './client' import { useCustomTabs, useServerPages } from './state' import { useDevToolsOptions } from './storage-options' @@ -17,11 +18,16 @@ export function useAllTabs() { .filter(route => !route.meta.experimental || (route.meta.experimental && settings.showExperimentalFeatures.value)) .sort((a, b) => (a.meta.order as number || 100) - (b.meta.order as number || 100)) .map((i): ModuleBuiltinTab => { + const name = i.name as string return { - name: i.name as string, + name, path: i.path, defaultOrder: i.meta.order as number | undefined, ...i.meta, + // `meta.title` is the English fallback for routes without a message. + title: i18n.global.te(`tabs.${name}`) + ? i18n.global.t(`tabs.${name}`) + : i.meta.title as string, } }), // { diff --git a/packages/devtools/client/composables/utils.ts b/packages/devtools/client/composables/utils.ts index 8268e17ade..41e2b36d6f 100644 --- a/packages/devtools/client/composables/utils.ts +++ b/packages/devtools/client/composables/utils.ts @@ -158,12 +158,6 @@ export function getComponentRelationships(component: Component, relationships?: } } -export function pluralizeByCount(count: number, singular: string, plural = `${singular}s`) { - return `${count} ${count <= 1 - ? singular - : plural}` -} - export function refreshData() { const client = useClient() const nuxt = useNuxtApp() diff --git a/packages/devtools/client/i18n/index.ts b/packages/devtools/client/i18n/index.ts new file mode 100644 index 0000000000..7843cbb3e3 --- /dev/null +++ b/packages/devtools/client/i18n/index.ts @@ -0,0 +1,65 @@ +import type { DevToolsLocale } from './locales' +import { createI18n } from 'vue-i18n' +import de from '../locales/de.json' +import en from '../locales/en.json' +import es from '../locales/es.json' +import fr from '../locales/fr.json' +import ja from '../locales/ja.json' +import ko from '../locales/ko.json' +import ptBR from '../locales/pt-BR.json' +import ru from '../locales/ru.json' +import zhCN from '../locales/zh-CN.json' +import zhTW from '../locales/zh-TW.json' +import { DEFAULT_LOCALE } from './locales' + +export type MessageSchema = typeof en + +const messages: Record = { + 'en': en, + 'zh-CN': zhCN, + 'zh-TW': zhTW, + 'ja': ja, + 'ko': ko, + 'es': es, + 'fr': fr, + 'de': de, + 'pt-BR': ptBR, + 'ru': ru, +} + +/** + * Russian has three plural forms: `one | few | many` + * (1 страница, 2 страницы, 5 страниц). + */ +function russianPlural(choice: number, choicesLength: number): number { + if (choicesLength < 3) { + return choice === 1 + ? 0 + : 1 + } + const mod10 = choice % 10 + const mod100 = choice % 100 + if (mod10 === 1 && mod100 !== 11) + return 0 + if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) + return 1 + return 2 +} + +/** + * The single i18n instance of the DevTools client. Exported so composables + * running outside a component (tab lists, commands) can translate with + * `i18n.global.t`, which stays reactive to locale changes. + */ +export const i18n = createI18n<[MessageSchema], DevToolsLocale, false>({ + legacy: false, + globalInjection: true, + locale: DEFAULT_LOCALE, + fallbackLocale: DEFAULT_LOCALE, + messages, + pluralRules: { + ru: russianPlural, + }, + missingWarn: false, + fallbackWarn: false, +}) diff --git a/packages/devtools/client/i18n/locales.ts b/packages/devtools/client/i18n/locales.ts new file mode 100644 index 0000000000..89d4e5f0e0 --- /dev/null +++ b/packages/devtools/client/i18n/locales.ts @@ -0,0 +1,32 @@ +/** + * UI languages Nuxt DevTools ships translations for. Mirrors + * `HUB_UI_LOCALES` from `@devframes/hub-ui`, so DevTools speaks every + * language the Devframe hub UI offers. Each key needs a matching + * `client/locales/.json` (checked by `x18n check` and the unit test). + */ +export const DEVTOOLS_LOCALES = { + 'en': 'English', + 'zh-CN': '简体中文', + 'zh-TW': '繁體中文', + 'ja': '日本語', + 'ko': '한국어', + 'es': 'Español', + 'fr': 'Français', + 'de': 'Deutsch', + 'pt-BR': 'Português (Brasil)', + 'ru': 'Русский', +} as const + +export type DevToolsLocale = keyof typeof DEVTOOLS_LOCALES + +export const DEFAULT_LOCALE: DevToolsLocale = 'en' + +/** + * The `localStorage` key the Devframe hub UI keeps the visitor's language + * pick under (Settings → Appearance), `'auto'` or a locale tag. The DevTools + * client is served from the same origin as the hub and only reads this key, + * so the hub stays the single place to change the language. + */ +export const DEVFRAME_LOCALE_STORAGE_KEY = 'devframes-locale' + +export const LOCALE_AUTO = 'auto' diff --git a/packages/devtools/client/locales/de.json b/packages/devtools/client/locales/de.json new file mode 100644 index 0000000000..14da561614 --- /dev/null +++ b/packages/devtools/client/locales/de.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "Wird geladen...", + "connecting": "Verbindung wird hergestellt...", + "settings": "Einstellungen" + }, + "connection": { + "disconnected": "Verbindung zum Server getrennt", + "retrying": "Neuer Versuch...", + "reload": "DevTools-Seite neu laden" + }, + "tabs": { + "modules-overview": "Übersicht", + "modules-pages": "Seiten", + "modules-components": "Komponenten", + "modules-imports": "Importe", + "modules-modules": "Module", + "modules-plugins": "Plugins", + "modules-payload": "Payload", + "modules-runtime-configs": "Laufzeitkonfiguration", + "modules-hooks": "Hooks", + "modules-timeline": "Zeitleiste", + "modules-error": "Fehler", + "modules-virtual-files": "Virtuelle Dateien", + "modules-analyze-build": "Build-Analyse", + "modules-server-routes": "Server-Routen", + "modules-server-tasks": "Server-Tasks", + "modules-storage": "Speicher", + "modules-debug": "Debug" + }, + "commands": { + "nuxtDocs": "Nuxt-Dokumentation", + "colorPicker": "Farbpipette", + "refreshData": "Daten aktualisieren", + "reloadPage": "Seite neu laden" + }, + "overview": { + "pages": "{n} Seite | {n} Seiten", + "components": "{n} Komponente | {n} Komponenten", + "imports": "{n} Import | {n} Importe", + "modules": "{n} Modul | {n} Module", + "plugins": "{n} Plugin | {n} Plugins", + "ssrToFullLoad": "SSR bis vollständig geladen", + "pageLoad": "Seitenladezeit", + "navigation": "Navigation", + "hmr": "HMR", + "notConnected": "Nicht mit der Client-App verbunden, es werden nur serverseitige Daten angezeigt. Verwende den eingebetteten Modus für alle Funktionen.", + "starOnGitHub": "Auf GitHub mit Stern markieren", + "ideas": "Ideen & Vorschläge", + "roadmap": "Projekt-Roadmap", + "bugReports": "Fehler melden", + "openCommandPalette": "Befehlspalette öffnen", + "toggleDevTools": "DevTools ein-/ausblenden" + }, + "settings": { + "title": "DevTools-Einstellungen", + "appearance": "Darstellung", + "uiScale": "UI-Skalierung", + "scale": { + "tiny": "Winzig", + "small": "Klein", + "normal": "Normal", + "large": "Groß", + "huge": "Riesig" + }, + "features": "Funktionen", + "showHelpButtons": "Hilfe-Schaltflächen anzeigen", + "openInEditor": "Im Editor öffnen", + "editorAuto": "Automatisch", + "feedback": "Feedback", + "telemetry": "Anonyme Statistiken senden und so helfen, DevTools zu verbessern", + "learnMore": "Mehr erfahren", + "ideas": "Ideen & Vorschläge", + "bugReports": "Fehler melden", + "debug": "Debug", + "reset": "Lokale Einstellungen & Status zurücksetzen", + "resetConfirm": "Möchtest du wirklich alle lokalen Einstellungen und den Status zurücksetzen? Die App wird neu geladen." + } +} diff --git a/packages/devtools/client/locales/en.json b/packages/devtools/client/locales/en.json new file mode 100644 index 0000000000..f17525943d --- /dev/null +++ b/packages/devtools/client/locales/en.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "Loading...", + "connecting": "Connecting...", + "settings": "Settings" + }, + "connection": { + "disconnected": "Disconnected from Server", + "retrying": "Retrying...", + "reload": "Reload DevTools Page" + }, + "tabs": { + "modules-overview": "Overview", + "modules-pages": "Pages", + "modules-components": "Components", + "modules-imports": "Imports", + "modules-modules": "Modules", + "modules-plugins": "Plugins", + "modules-payload": "Payload", + "modules-runtime-configs": "Runtime Configs", + "modules-hooks": "Hooks", + "modules-timeline": "Timeline", + "modules-error": "Error", + "modules-virtual-files": "Virtual Files", + "modules-analyze-build": "Build Analyze", + "modules-server-routes": "Server Routes", + "modules-server-tasks": "Server Tasks", + "modules-storage": "Storage", + "modules-debug": "Debug" + }, + "commands": { + "nuxtDocs": "Nuxt Documentations", + "colorPicker": "Color Picker", + "refreshData": "Refresh Data", + "reloadPage": "Reload Page" + }, + "overview": { + "pages": "{n} page | {n} pages", + "components": "{n} component | {n} components", + "imports": "{n} import | {n} imports", + "modules": "{n} module | {n} modules", + "plugins": "{n} plugin | {n} plugins", + "ssrToFullLoad": "SSR to full load", + "pageLoad": "Page load", + "navigation": "Navigation", + "hmr": "HMR", + "notConnected": "Not connected to the client app, showing server-side data only. Use the embedded mode for full features.", + "starOnGitHub": "Star on GitHub", + "ideas": "Ideas & Suggestions", + "roadmap": "Project Roadmap", + "bugReports": "Bug Reports", + "openCommandPalette": "Open Command Palette", + "toggleDevTools": "Toggle DevTools" + }, + "settings": { + "title": "DevTools Settings", + "appearance": "Appearance", + "uiScale": "UI Scale", + "scale": { + "tiny": "Tiny", + "small": "Small", + "normal": "Normal", + "large": "Large", + "huge": "Huge" + }, + "features": "Features", + "showHelpButtons": "Show help buttons", + "openInEditor": "Open In Editor", + "editorAuto": "Auto", + "feedback": "Feedback", + "telemetry": "Send anonymous statistics, help us improving DevTools", + "learnMore": "Learn more", + "ideas": "Ideas & Suggestions", + "bugReports": "Bug Reports", + "debug": "Debug", + "reset": "Reset Local Settings & State", + "resetConfirm": "Are you sure you to reset all local settings & state? The app will reload." + } +} diff --git a/packages/devtools/client/locales/es.json b/packages/devtools/client/locales/es.json new file mode 100644 index 0000000000..8b9ec99466 --- /dev/null +++ b/packages/devtools/client/locales/es.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "Cargando...", + "connecting": "Conectando...", + "settings": "Ajustes" + }, + "connection": { + "disconnected": "Desconectado del servidor", + "retrying": "Reintentando...", + "reload": "Recargar la página de DevTools" + }, + "tabs": { + "modules-overview": "Resumen", + "modules-pages": "Páginas", + "modules-components": "Componentes", + "modules-imports": "Importaciones", + "modules-modules": "Módulos", + "modules-plugins": "Plugins", + "modules-payload": "Payload", + "modules-runtime-configs": "Configuración de ejecución", + "modules-hooks": "Hooks", + "modules-timeline": "Línea de tiempo", + "modules-error": "Error", + "modules-virtual-files": "Archivos virtuales", + "modules-analyze-build": "Análisis de compilación", + "modules-server-routes": "Rutas del servidor", + "modules-server-tasks": "Tareas del servidor", + "modules-storage": "Almacenamiento", + "modules-debug": "Depuración" + }, + "commands": { + "nuxtDocs": "Documentación de Nuxt", + "colorPicker": "Selector de color", + "refreshData": "Actualizar datos", + "reloadPage": "Recargar página" + }, + "overview": { + "pages": "{n} página | {n} páginas", + "components": "{n} componente | {n} componentes", + "imports": "{n} importación | {n} importaciones", + "modules": "{n} módulo | {n} módulos", + "plugins": "{n} plugin | {n} plugins", + "ssrToFullLoad": "De SSR a carga completa", + "pageLoad": "Carga de página", + "navigation": "Navegación", + "hmr": "HMR", + "notConnected": "No hay conexión con la app cliente; solo se muestran datos del servidor. Usa el modo integrado para tener todas las funciones.", + "starOnGitHub": "Dar estrella en GitHub", + "ideas": "Ideas y sugerencias", + "roadmap": "Hoja de ruta del proyecto", + "bugReports": "Reportar errores", + "openCommandPalette": "Abrir la paleta de comandos", + "toggleDevTools": "Mostrar u ocultar DevTools" + }, + "settings": { + "title": "Ajustes de DevTools", + "appearance": "Apariencia", + "uiScale": "Escala de la interfaz", + "scale": { + "tiny": "Diminuta", + "small": "Pequeña", + "normal": "Normal", + "large": "Grande", + "huge": "Enorme" + }, + "features": "Funciones", + "showHelpButtons": "Mostrar botones de ayuda", + "openInEditor": "Abrir en el editor", + "editorAuto": "Automático", + "feedback": "Comentarios", + "telemetry": "Enviar estadísticas anónimas para ayudarnos a mejorar DevTools", + "learnMore": "Más información", + "ideas": "Ideas y sugerencias", + "bugReports": "Reportar errores", + "debug": "Depuración", + "reset": "Restablecer ajustes y estado locales", + "resetConfirm": "¿Seguro que quieres restablecer todos los ajustes y el estado locales? La app se recargará." + } +} diff --git a/packages/devtools/client/locales/fr.json b/packages/devtools/client/locales/fr.json new file mode 100644 index 0000000000..0aab37657f --- /dev/null +++ b/packages/devtools/client/locales/fr.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "Chargement...", + "connecting": "Connexion...", + "settings": "Paramètres" + }, + "connection": { + "disconnected": "Déconnecté du serveur", + "retrying": "Nouvelle tentative...", + "reload": "Recharger la page DevTools" + }, + "tabs": { + "modules-overview": "Vue d'ensemble", + "modules-pages": "Pages", + "modules-components": "Composants", + "modules-imports": "Imports", + "modules-modules": "Modules", + "modules-plugins": "Plugins", + "modules-payload": "Payload", + "modules-runtime-configs": "Configuration d'exécution", + "modules-hooks": "Hooks", + "modules-timeline": "Chronologie", + "modules-error": "Erreur", + "modules-virtual-files": "Fichiers virtuels", + "modules-analyze-build": "Analyse du build", + "modules-server-routes": "Routes serveur", + "modules-server-tasks": "Tâches serveur", + "modules-storage": "Stockage", + "modules-debug": "Débogage" + }, + "commands": { + "nuxtDocs": "Documentation Nuxt", + "colorPicker": "Pipette à couleurs", + "refreshData": "Actualiser les données", + "reloadPage": "Recharger la page" + }, + "overview": { + "pages": "{n} page | {n} pages", + "components": "{n} composant | {n} composants", + "imports": "{n} import | {n} imports", + "modules": "{n} module | {n} modules", + "plugins": "{n} plugin | {n} plugins", + "ssrToFullLoad": "Du SSR au chargement complet", + "pageLoad": "Chargement de la page", + "navigation": "Navigation", + "hmr": "HMR", + "notConnected": "Non connecté à l'application cliente : seules les données côté serveur sont affichées. Utilisez le mode intégré pour toutes les fonctionnalités.", + "starOnGitHub": "Ajouter une étoile sur GitHub", + "ideas": "Idées et suggestions", + "roadmap": "Feuille de route du projet", + "bugReports": "Signaler un bug", + "openCommandPalette": "Ouvrir la palette de commandes", + "toggleDevTools": "Afficher ou masquer DevTools" + }, + "settings": { + "title": "Paramètres de DevTools", + "appearance": "Apparence", + "uiScale": "Échelle de l'interface", + "scale": { + "tiny": "Minuscule", + "small": "Petite", + "normal": "Normale", + "large": "Grande", + "huge": "Énorme" + }, + "features": "Fonctionnalités", + "showHelpButtons": "Afficher les boutons d'aide", + "openInEditor": "Ouvrir dans l'éditeur", + "editorAuto": "Automatique", + "feedback": "Retours", + "telemetry": "Envoyer des statistiques anonymes pour nous aider à améliorer DevTools", + "learnMore": "En savoir plus", + "ideas": "Idées et suggestions", + "bugReports": "Signaler un bug", + "debug": "Débogage", + "reset": "Réinitialiser les paramètres et l'état locaux", + "resetConfirm": "Voulez-vous vraiment réinitialiser tous les paramètres et l'état locaux ? L'application va se recharger." + } +} diff --git a/packages/devtools/client/locales/ja.json b/packages/devtools/client/locales/ja.json new file mode 100644 index 0000000000..3e6b107afb --- /dev/null +++ b/packages/devtools/client/locales/ja.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "読み込み中...", + "connecting": "接続中...", + "settings": "設定" + }, + "connection": { + "disconnected": "サーバーから切断されました", + "retrying": "再試行中...", + "reload": "DevTools ページを再読み込み" + }, + "tabs": { + "modules-overview": "概要", + "modules-pages": "ページ", + "modules-components": "コンポーネント", + "modules-imports": "インポート", + "modules-modules": "モジュール", + "modules-plugins": "プラグイン", + "modules-payload": "ペイロード", + "modules-runtime-configs": "ランタイム設定", + "modules-hooks": "フック", + "modules-timeline": "タイムライン", + "modules-error": "エラー", + "modules-virtual-files": "仮想ファイル", + "modules-analyze-build": "ビルド分析", + "modules-server-routes": "サーバールート", + "modules-server-tasks": "サーバータスク", + "modules-storage": "ストレージ", + "modules-debug": "デバッグ" + }, + "commands": { + "nuxtDocs": "Nuxt ドキュメント", + "colorPicker": "カラーピッカー", + "refreshData": "データを更新", + "reloadPage": "ページを再読み込み" + }, + "overview": { + "pages": "{n} ページ", + "components": "{n} コンポーネント", + "imports": "{n} インポート", + "modules": "{n} モジュール", + "plugins": "{n} プラグイン", + "ssrToFullLoad": "SSR から完全読み込みまで", + "pageLoad": "ページ読み込み", + "navigation": "ナビゲーション", + "hmr": "HMR", + "notConnected": "クライアントアプリに接続されていません。サーバー側のデータのみを表示しています。すべての機能を使うには埋め込みモードを使用してください。", + "starOnGitHub": "GitHub でスターする", + "ideas": "アイデアと提案", + "roadmap": "プロジェクトのロードマップ", + "bugReports": "バグ報告", + "openCommandPalette": "コマンドパレットを開く", + "toggleDevTools": "DevTools の表示切り替え" + }, + "settings": { + "title": "DevTools 設定", + "appearance": "外観", + "uiScale": "UI の拡大率", + "scale": { + "tiny": "極小", + "small": "小", + "normal": "標準", + "large": "大", + "huge": "特大" + }, + "features": "機能", + "showHelpButtons": "ヘルプボタンを表示", + "openInEditor": "エディターで開く", + "editorAuto": "自動", + "feedback": "フィードバック", + "telemetry": "匿名の統計情報を送信して DevTools の改善に協力する", + "learnMore": "詳細", + "ideas": "アイデアと提案", + "bugReports": "バグ報告", + "debug": "デバッグ", + "reset": "ローカル設定と状態をリセット", + "resetConfirm": "すべてのローカル設定と状態をリセットしますか?アプリは再読み込みされます。" + } +} diff --git a/packages/devtools/client/locales/ko.json b/packages/devtools/client/locales/ko.json new file mode 100644 index 0000000000..285649ec05 --- /dev/null +++ b/packages/devtools/client/locales/ko.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "불러오는 중...", + "connecting": "연결 중...", + "settings": "설정" + }, + "connection": { + "disconnected": "서버와의 연결이 끊어졌습니다", + "retrying": "다시 시도하는 중...", + "reload": "DevTools 페이지 새로고침" + }, + "tabs": { + "modules-overview": "개요", + "modules-pages": "페이지", + "modules-components": "컴포넌트", + "modules-imports": "임포트", + "modules-modules": "모듈", + "modules-plugins": "플러그인", + "modules-payload": "페이로드", + "modules-runtime-configs": "런타임 설정", + "modules-hooks": "훅", + "modules-timeline": "타임라인", + "modules-error": "오류", + "modules-virtual-files": "가상 파일", + "modules-analyze-build": "빌드 분석", + "modules-server-routes": "서버 라우트", + "modules-server-tasks": "서버 작업", + "modules-storage": "스토리지", + "modules-debug": "디버그" + }, + "commands": { + "nuxtDocs": "Nuxt 문서", + "colorPicker": "색상 선택기", + "refreshData": "데이터 새로고침", + "reloadPage": "페이지 새로고침" + }, + "overview": { + "pages": "페이지 {n}개", + "components": "컴포넌트 {n}개", + "imports": "임포트 {n}개", + "modules": "모듈 {n}개", + "plugins": "플러그인 {n}개", + "ssrToFullLoad": "SSR부터 전체 로드까지", + "pageLoad": "페이지 로드", + "navigation": "탐색", + "hmr": "HMR", + "notConnected": "클라이언트 앱에 연결되지 않아 서버 측 데이터만 표시합니다. 모든 기능을 사용하려면 임베디드 모드를 사용하세요.", + "starOnGitHub": "GitHub에서 스타 주기", + "ideas": "아이디어 및 제안", + "roadmap": "프로젝트 로드맵", + "bugReports": "버그 신고", + "openCommandPalette": "명령 팔레트 열기", + "toggleDevTools": "DevTools 전환" + }, + "settings": { + "title": "DevTools 설정", + "appearance": "모양", + "uiScale": "UI 배율", + "scale": { + "tiny": "아주 작게", + "small": "작게", + "normal": "보통", + "large": "크게", + "huge": "아주 크게" + }, + "features": "기능", + "showHelpButtons": "도움말 버튼 표시", + "openInEditor": "에디터에서 열기", + "editorAuto": "자동", + "feedback": "피드백", + "telemetry": "익명 통계를 보내 DevTools 개선에 도움 주기", + "learnMore": "자세히 알아보기", + "ideas": "아이디어 및 제안", + "bugReports": "버그 신고", + "debug": "디버그", + "reset": "로컬 설정 및 상태 초기화", + "resetConfirm": "모든 로컬 설정과 상태를 초기화할까요? 앱이 다시 로드됩니다." + } +} diff --git a/packages/devtools/client/locales/pt-BR.json b/packages/devtools/client/locales/pt-BR.json new file mode 100644 index 0000000000..199b11f6ec --- /dev/null +++ b/packages/devtools/client/locales/pt-BR.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "Carregando...", + "connecting": "Conectando...", + "settings": "Configurações" + }, + "connection": { + "disconnected": "Desconectado do servidor", + "retrying": "Tentando novamente...", + "reload": "Recarregar a página do DevTools" + }, + "tabs": { + "modules-overview": "Visão geral", + "modules-pages": "Páginas", + "modules-components": "Componentes", + "modules-imports": "Importações", + "modules-modules": "Módulos", + "modules-plugins": "Plugins", + "modules-payload": "Payload", + "modules-runtime-configs": "Configurações de runtime", + "modules-hooks": "Hooks", + "modules-timeline": "Linha do tempo", + "modules-error": "Erro", + "modules-virtual-files": "Arquivos virtuais", + "modules-analyze-build": "Análise do build", + "modules-server-routes": "Rotas do servidor", + "modules-server-tasks": "Tarefas do servidor", + "modules-storage": "Armazenamento", + "modules-debug": "Depuração" + }, + "commands": { + "nuxtDocs": "Documentação do Nuxt", + "colorPicker": "Seletor de cor", + "refreshData": "Atualizar dados", + "reloadPage": "Recarregar página" + }, + "overview": { + "pages": "{n} página | {n} páginas", + "components": "{n} componente | {n} componentes", + "imports": "{n} importação | {n} importações", + "modules": "{n} módulo | {n} módulos", + "plugins": "{n} plugin | {n} plugins", + "ssrToFullLoad": "Do SSR ao carregamento completo", + "pageLoad": "Carregamento da página", + "navigation": "Navegação", + "hmr": "HMR", + "notConnected": "Sem conexão com o app cliente; mostrando apenas dados do servidor. Use o modo incorporado para ter todos os recursos.", + "starOnGitHub": "Dar estrela no GitHub", + "ideas": "Ideias e sugestões", + "roadmap": "Roadmap do projeto", + "bugReports": "Relatar bugs", + "openCommandPalette": "Abrir a paleta de comandos", + "toggleDevTools": "Mostrar ou ocultar o DevTools" + }, + "settings": { + "title": "Configurações do DevTools", + "appearance": "Aparência", + "uiScale": "Escala da interface", + "scale": { + "tiny": "Minúscula", + "small": "Pequena", + "normal": "Normal", + "large": "Grande", + "huge": "Enorme" + }, + "features": "Recursos", + "showHelpButtons": "Mostrar botões de ajuda", + "openInEditor": "Abrir no editor", + "editorAuto": "Automático", + "feedback": "Feedback", + "telemetry": "Enviar estatísticas anônimas para nos ajudar a melhorar o DevTools", + "learnMore": "Saiba mais", + "ideas": "Ideias e sugestões", + "bugReports": "Relatar bugs", + "debug": "Depuração", + "reset": "Redefinir configurações e estado locais", + "resetConfirm": "Tem certeza de que deseja redefinir todas as configurações e o estado locais? O app será recarregado." + } +} diff --git a/packages/devtools/client/locales/ru.json b/packages/devtools/client/locales/ru.json new file mode 100644 index 0000000000..e0c2b2b53a --- /dev/null +++ b/packages/devtools/client/locales/ru.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "Загрузка...", + "connecting": "Подключение...", + "settings": "Настройки" + }, + "connection": { + "disconnected": "Соединение с сервером потеряно", + "retrying": "Повторная попытка...", + "reload": "Перезагрузить страницу DevTools" + }, + "tabs": { + "modules-overview": "Обзор", + "modules-pages": "Страницы", + "modules-components": "Компоненты", + "modules-imports": "Импорты", + "modules-modules": "Модули", + "modules-plugins": "Плагины", + "modules-payload": "Payload", + "modules-runtime-configs": "Конфигурация среды выполнения", + "modules-hooks": "Хуки", + "modules-timeline": "Хронология", + "modules-error": "Ошибка", + "modules-virtual-files": "Виртуальные файлы", + "modules-analyze-build": "Анализ сборки", + "modules-server-routes": "Серверные маршруты", + "modules-server-tasks": "Серверные задачи", + "modules-storage": "Хранилище", + "modules-debug": "Отладка" + }, + "commands": { + "nuxtDocs": "Документация Nuxt", + "colorPicker": "Пипетка", + "refreshData": "Обновить данные", + "reloadPage": "Перезагрузить страницу" + }, + "overview": { + "pages": "{n} страница | {n} страницы | {n} страниц", + "components": "{n} компонент | {n} компонента | {n} компонентов", + "imports": "{n} импорт | {n} импорта | {n} импортов", + "modules": "{n} модуль | {n} модуля | {n} модулей", + "plugins": "{n} плагин | {n} плагина | {n} плагинов", + "ssrToFullLoad": "От SSR до полной загрузки", + "pageLoad": "Загрузка страницы", + "navigation": "Навигация", + "hmr": "HMR", + "notConnected": "Нет подключения к клиентскому приложению, показаны только серверные данные. Используйте встроенный режим для всех функций.", + "starOnGitHub": "Поставить звезду на GitHub", + "ideas": "Идеи и предложения", + "roadmap": "Дорожная карта проекта", + "bugReports": "Сообщить об ошибке", + "openCommandPalette": "Открыть палитру команд", + "toggleDevTools": "Показать или скрыть DevTools" + }, + "settings": { + "title": "Настройки DevTools", + "appearance": "Внешний вид", + "uiScale": "Масштаб интерфейса", + "scale": { + "tiny": "Крошечный", + "small": "Маленький", + "normal": "Обычный", + "large": "Большой", + "huge": "Огромный" + }, + "features": "Функции", + "showHelpButtons": "Показывать кнопки справки", + "openInEditor": "Открывать в редакторе", + "editorAuto": "Авто", + "feedback": "Обратная связь", + "telemetry": "Отправлять анонимную статистику, чтобы помочь улучшить DevTools", + "learnMore": "Подробнее", + "ideas": "Идеи и предложения", + "bugReports": "Сообщить об ошибке", + "debug": "Отладка", + "reset": "Сбросить локальные настройки и состояние", + "resetConfirm": "Вы уверены, что хотите сбросить все локальные настройки и состояние? Приложение будет перезагружено." + } +} diff --git a/packages/devtools/client/locales/zh-CN.json b/packages/devtools/client/locales/zh-CN.json new file mode 100644 index 0000000000..ef1f3d2338 --- /dev/null +++ b/packages/devtools/client/locales/zh-CN.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "加载中...", + "connecting": "连接中...", + "settings": "设置" + }, + "connection": { + "disconnected": "与服务器的连接已断开", + "retrying": "正在重试...", + "reload": "重新加载 DevTools 页面" + }, + "tabs": { + "modules-overview": "概览", + "modules-pages": "页面", + "modules-components": "组件", + "modules-imports": "导入", + "modules-modules": "模块", + "modules-plugins": "插件", + "modules-payload": "Payload", + "modules-runtime-configs": "运行时配置", + "modules-hooks": "钩子", + "modules-timeline": "时间线", + "modules-error": "错误", + "modules-virtual-files": "虚拟文件", + "modules-analyze-build": "构建分析", + "modules-server-routes": "服务端路由", + "modules-server-tasks": "服务端任务", + "modules-storage": "存储", + "modules-debug": "调试" + }, + "commands": { + "nuxtDocs": "Nuxt 文档", + "colorPicker": "取色器", + "refreshData": "刷新数据", + "reloadPage": "重新加载页面" + }, + "overview": { + "pages": "{n} 个页面", + "components": "{n} 个组件", + "imports": "{n} 个导入", + "modules": "{n} 个模块", + "plugins": "{n} 个插件", + "ssrToFullLoad": "SSR 到完全加载", + "pageLoad": "页面加载", + "navigation": "导航", + "hmr": "HMR", + "notConnected": "未连接到客户端应用,仅显示服务端数据。请使用嵌入模式以获得完整功能。", + "starOnGitHub": "在 GitHub 上点星", + "ideas": "想法与建议", + "roadmap": "项目路线图", + "bugReports": "问题反馈", + "openCommandPalette": "打开命令面板", + "toggleDevTools": "切换 DevTools" + }, + "settings": { + "title": "DevTools 设置", + "appearance": "外观", + "uiScale": "界面缩放", + "scale": { + "tiny": "极小", + "small": "小", + "normal": "正常", + "large": "大", + "huge": "极大" + }, + "features": "功能", + "showHelpButtons": "显示帮助按钮", + "openInEditor": "在编辑器中打开", + "editorAuto": "自动", + "feedback": "反馈", + "telemetry": "发送匿名统计数据,帮助我们改进 DevTools", + "learnMore": "了解更多", + "ideas": "想法与建议", + "bugReports": "问题反馈", + "debug": "调试", + "reset": "重置本地设置与状态", + "resetConfirm": "确定要重置所有本地设置与状态吗?应用将会重新加载。" + } +} diff --git a/packages/devtools/client/locales/zh-TW.json b/packages/devtools/client/locales/zh-TW.json new file mode 100644 index 0000000000..384fdb22c9 --- /dev/null +++ b/packages/devtools/client/locales/zh-TW.json @@ -0,0 +1,79 @@ +{ + "common": { + "loading": "載入中...", + "connecting": "連線中...", + "settings": "設定" + }, + "connection": { + "disconnected": "與伺服器的連線已中斷", + "retrying": "正在重試...", + "reload": "重新載入 DevTools 頁面" + }, + "tabs": { + "modules-overview": "概覽", + "modules-pages": "頁面", + "modules-components": "元件", + "modules-imports": "匯入", + "modules-modules": "模組", + "modules-plugins": "外掛", + "modules-payload": "Payload", + "modules-runtime-configs": "執行時設定", + "modules-hooks": "鉤子", + "modules-timeline": "時間軸", + "modules-error": "錯誤", + "modules-virtual-files": "虛擬檔案", + "modules-analyze-build": "建置分析", + "modules-server-routes": "伺服器路由", + "modules-server-tasks": "伺服器任務", + "modules-storage": "儲存", + "modules-debug": "除錯" + }, + "commands": { + "nuxtDocs": "Nuxt 文件", + "colorPicker": "取色器", + "refreshData": "重新整理資料", + "reloadPage": "重新載入頁面" + }, + "overview": { + "pages": "{n} 個頁面", + "components": "{n} 個元件", + "imports": "{n} 個匯入", + "modules": "{n} 個模組", + "plugins": "{n} 個外掛", + "ssrToFullLoad": "SSR 到完全載入", + "pageLoad": "頁面載入", + "navigation": "導覽", + "hmr": "HMR", + "notConnected": "未連線到用戶端應用程式,僅顯示伺服器端資料。請使用嵌入模式以取得完整功能。", + "starOnGitHub": "在 GitHub 上給星", + "ideas": "想法與建議", + "roadmap": "專案路線圖", + "bugReports": "問題回報", + "openCommandPalette": "開啟命令面板", + "toggleDevTools": "切換 DevTools" + }, + "settings": { + "title": "DevTools 設定", + "appearance": "外觀", + "uiScale": "介面縮放", + "scale": { + "tiny": "極小", + "small": "小", + "normal": "正常", + "large": "大", + "huge": "極大" + }, + "features": "功能", + "showHelpButtons": "顯示說明按鈕", + "openInEditor": "在編輯器中開啟", + "editorAuto": "自動", + "feedback": "意見回饋", + "telemetry": "傳送匿名統計資料,協助我們改進 DevTools", + "learnMore": "了解更多", + "ideas": "想法與建議", + "bugReports": "問題回報", + "debug": "除錯", + "reset": "重設本機設定與狀態", + "resetConfirm": "確定要重設所有本機設定與狀態嗎?應用程式將重新載入。" + } +} diff --git a/packages/devtools/client/nuxt.config.ts b/packages/devtools/client/nuxt.config.ts index 08c3f37879..3b90781c68 100644 --- a/packages/devtools/client/nuxt.config.ts +++ b/packages/devtools/client/nuxt.config.ts @@ -113,6 +113,13 @@ export default defineNuxtConfig({ vite: { warmupEntry: false, + // vue-i18n feature flags: Composition API only, no legacy API or + // intlify devtools in the bundle. + define: { + __VUE_I18N_FULL_INSTALL__: true, + __VUE_I18N_LEGACY_API__: false, + __INTLIFY_PROD_DEVTOOLS__: false, + }, vue: { // floating-vue still implements its poppers with Options API mixins, // computed properties, and methods. Keep that runtime enabled even when @@ -156,6 +163,7 @@ export default defineNuxtConfig({ 'devframe/utils/hash', 'perfect-debounce', 'scule', + 'vue-i18n', 'vue-virtual-scroller', 'vis-data', 'vis-network', diff --git a/packages/devtools/client/pages/modules/overview.vue b/packages/devtools/client/pages/modules/overview.vue index a9430d6730..8a804c439e 100644 --- a/packages/devtools/client/pages/modules/overview.vue +++ b/packages/devtools/client/pages/modules/overview.vue @@ -9,7 +9,7 @@ import { useAllRoutes } from '~/composables/state-tabs' import { getIsMacOS } from '~/composables/utils' import { version } from '../../../package.json' import { showConnectionWarning } from '../../composables/client' -import { formatDuration, pluralizeByCount } from '../../composables/utils' +import { formatDuration } from '../../composables/utils' definePageMeta({ icon: 'carbon-information', @@ -32,7 +32,7 @@ const metricsLoading = computed(() => client.value?.metrics.loading())