mihomo-party-org/clash-party · info · Error

Translation not ready

Error message

Translation not ready

What it means

safeShowErrorBox resolves an error-dialog title via i18next.t(titleKey). If i18next is not yet initialized (or the key is missing so t() echoes the key back), it deliberately throws the internal sentinel 'Translation not ready' to trigger the catch block, which falls back to a hardcoded zh-CN/en-US translation table. The error never escapes the function — it is a control-flow device to switch to the fallback path.

Source

Thrown at src/main/utils/init.ts:72

import { atomicWriteFile } from './safeFile'

let isInitBasicCompleted = false
let isRuntimeFilesCompleted = false
let initBasicPromise: Promise<void> | null = null
let runtimeFilesPromise: Promise<void> | null = null
let subStoreServicesPromise: Promise<SubStoreServicePorts> | null = null
let subStoreServicesStarted = false

interface SubStoreServicePorts {
  backendPort?: number
  frontendPort?: number
}

export function safeShowErrorBox(titleKey: string, message: string): void {
  let title: string
  try {
    title = i18next.t(titleKey)
    if (!title || title === titleKey) throw new Error('Translation not ready')
  } catch {
    const isZh = app.getLocale().startsWith('zh')
    const lang = isZh ? resources['zh-CN'].translation : resources['en-US'].translation
    title = lang[titleKey] || (isZh ? '错误' : 'Error')
  }
  dialog.showErrorBox(title, message)
}

async function fixDataDirPermissions(): Promise<void> {
  if (process.platform !== 'darwin') return

  const dataDirPath = dataDir()
  if (!existsSync(dataDirPath)) return

  try {
    const stats = await stat(dataDirPath)
    const currentUid = process.getuid?.() || 0

View on GitHub (pinned to 911e090537)

Solutions

  1. Nothing to fix if the fallback title appears — the function already shows the dialog using the built-in zh-CN/en-US strings.
  2. If titles show the raw key, add the missing key to both resources['zh-CN'].translation and resources['en-US'].translation.
  3. Ensure i18next.init() is awaited before any code path that may call safeShowErrorBox (move init earlier in the startup sequence).
  4. Verify the titleKey passed in matches a key in the translation resources exactly (case-sensitive).

Example fix

// before: dialog title shows raw key because translation missing
title = lang[titleKey] || (isZh ? '错误' : 'Error')
// after: after adding the key to both bundles
// resources['en-US'].translation['coreWatchFailed'] = 'Core monitor failed'
// resources['zh-CN'].translation['coreWatchFailed'] = '内核监控失败'
Defensive patterns

Strategy: fallback

Validate before calling

// ensure i18n is initialized before any error dialog can fire
if (!i18next.isInitialized) {
  await i18next.init({ resources })
}

Type guard

function translationReady(key: string): boolean {
  const v = i18next.t(key)
  return typeof v === 'string' && v.length > 0 && v !== key
}

Try / catch

// the function already implements the right pattern; mimic it elsewhere:
let title: string
try {
  title = i18next.t(key)
  if (!title || title === key) throw new Error('Translation not ready')
} catch {
  title = resources[app.getLocale().startsWith('zh') ? 'zh-CN' : 'en-US'].translation[key] ?? 'Error'
}

Prevention

When it happens

Trigger: safeShowErrorBox called (by initCoreWatcher, keepCoreAlive, handleDeepLink, queueLaunchTarget, appConfigPromise, ensureNoHighPrivilegeCore) before await i18next.init() resolves — typically a very early startup error dialog — or with a titleKey absent from the resource bundles.

Common situations: App crashes during startup before i18n init completes (config file corrupt, core fails instantly); deep-link activation racing app initialization; typo'd or newly added translation key missing from one locale's resources.

Related errors


AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30). Data as JSON: /api/errors/96deb78a8d84da1a. Report an issue: GitHub.