🎉 Hyperse Wizard has been published.
Hyperse Wizard
Core API

i18n

Internationalization support

i18n

Wizard provides internationalization support across three levels: core, cli, and plugins. Each level is loaded in different namespaces, so you need to use the appropriate namespace based on your specific use case.

  • The core namespace is primarily used for error messages and log information within the wizard core. It does not support external extensions.

  • The cli namespace is used for information required when initializing a wizard instance, such as wizard descriptions and versions.

  • The plugins namespace is used for plugin internationalization. When creating custom plugins and loading commands, all internationalization-related information is loaded in the plugins namespace.

Wizard's internationalization is built on top of @hyperse/translator. Through TypeScript interface merging, different plugins and loading processes can achieve excellent type support.

Automatic Fallback Mechanism

Wizard provides a robust fallback mechanism for internationalization:

  • Language Fallback: When a message is not found in the current locale, Wizard automatically falls back to English (en) messages
  • English as Default: You only need to define English messages by default - other languages will automatically fall back to English if not configured
  • Message Validation: The translator uses plainMessageCheck to filter special characters using the PlainMessageRegex pattern /[!\/\<\|\{]/

This ensures that your application always has fallback text available, even when translations are incomplete.

How Fallback Works

Wizard implements a three-tier fallback system:

// Fallback Priority:
// 1. Primary Locale (e.g., 'zh')
// 2. English Fallback ('en')
// 3. Key Fallback (e.g., 'zh.command.[messageKey]')

Implementation Details

The fallback mechanism is implemented in the useLocale function:

export const useLocale = (
  locale: SupportedLocales,
  messages: LocaleMessagesObject = coreMessages,
  logger?: Logger
): I18n['t'] => {
  // Create fallback translator for English
  const fallbackTranslator = createFallbackTranslator(messages, logger);

  return createTranslator({
    locale: locale,
    messages: messages,
    namespace: locale,
    getMessageFallback: ({ error, key, namespace }) => {
      if (namespace === 'en') {
        return `${namespace}.${key}`;
      }
      // Fall back to English translator
      return fallbackTranslator(key);
    },
    // ... other options
  });
};

Message Validation

Wizard automatically validates messages using the plainMessageCheck function to ensure consistency and prevent formatting issues.

Validation Rules

The PlainMessageRegex pattern /[!\/\<\|\{]/ filters out special characters that could cause issues:

  • ! - Exclamation marks
  • / - Forward slashes
  • < - Less than symbols
  • | - Pipe characters
  • { - Opening braces

Why Validation Matters

  • Consistency: Ensures all messages follow the same format
  • Reliability: Prevents runtime errors from malformed messages
  • Maintainability: Makes message management easier for teams
  • User Experience: Provides consistent output across different locales

core namespace

The built-in internationalization messages are as follows:

export const messages = {
  en: {
    core: {
      command: {
        notProvider:
          'No command specified. Please provide a command to execute.',
        nameConflict:
          'Command name "{newCmdName}" conflicts with existing command "{oldCmdName}". This may be caused by duplicate aliases.',
        flagNotProvided:
          'Command "{cmdName}" requires the flag "{flagName}" but it was not provided.',
        notConfiguration: 'Command "{cmdName}" is not properly configured.',
        notFound:
          'Command "{cmdName}" not found. Use --help to see available commands.',
        processNotFound: 'Command "{cmdName}" has no process defined.',
        invalidName:
          'Invalid command name "{cmdName}" command names cannot contain spaces or multiple consecutive spaces.',
        invalidFlagsValue:
          'Invalid value "{flagValue}" for flag "{flagName}". Supported values are: {flagValues}',
      },
      flags: {
        noColor: 'Disable colored output in terminal',
        logLevel: 'Set log level. options: error, warn, info, debug, verbose',
      },
    },
  },
  zh: {
    core: {
      command: {
        notProvider: '未指定命令。请提供一个要执行的命令。',
        flagNotProvided: '命令 "{cmdName}" 需要参数 "{flagName}" 但未提供。',
        nameConflict:
          '命令名称 "{newCmdName}" 与现有命令 "{oldCmdName}" 冲突。这可能是由重复的别名导致的。',
        notConfiguration: '命令 "{cmdName}" 配置不正确。',
        notFound: '未找到命令 "{cmdName}"。使用 --help 查看可用命令。',
        processNotFound: '命令 "{cmdName}" 未定义处理函数。',
        invalidName:
          '无效的命令名称 "{cmdName}" 命令名称不能包含空格或连续多个空格。',
        invalidFlagsValue:
          '无效的参数值 "{flagValue}",参数 "{flagName}" 支持的值为:{flagValues}',
      },
      flags: {
        noColor: '禁用终端日志输出颜色',
        logLevel: '设置日志级别,可选值:error, warn, info, debug, verbose',
      },
    },
  },
};

cli namespace

Messages

// @filename: @hyperse/wizard/dist/index.d.ts
import {  } from '@hyperse/wizard';

export const  = ({
  : {
    : {
      : 'CLI description',
      : 'CLI v1.0.0',
    },
  },
  : {
    : {
      : '帮助信息插件',
      : 'CLI v1.0.0',
    },
  },
});

Fallback Support: You can define only English messages and other languages will automatically fall back to English:

export const minimalMessages = defineLocaleMessages({
  en: {
    helpCli: {
      description: 'CLI description',
      version: 'CLI v1.0.0',
    },
  },
  // zh is not defined - will automatically fall back to English
});

Type Merging

Use interface merging to combine your custom internationalization messages with CliLocaleMessages.

// @filename: @hyperse/wizard/dist/index.d.ts
import type {  } from '@hyperse/wizard';

declare module '@hyperse/wizard' {
  export interface CliLocaleMessages extends <
    typeof helpCliMessages
  > {}
}

Using

// @filename: @hyperse/wizard/dist/index.d.ts
import {
  ,
  ,
  ,
} from '@hyperse/wizard';

// define cli locale messages
const  = ({
  : {
    : {
      : 'CLI description',
      : 'CLI v1.0.0',
    },
  },
  : {
    : {
      : '帮助信息插件',
      : 'CLI v1.0.0',
    },
  },
});

// merge cli locale messages
declare module '@hyperse/wizard' {
  export interface CliLocaleMessages extends <
    typeof 
  > {}
}

const  = ({
  : 'hps_cli',
  : ,
  // Use internationalization messages
  : 'cli.helpCli.
  • cli.helpCli.description
  • cli.helpCli.version
description',
// Use internationalization messages : 'cli.helpCli.version', : () => { .('CLI errorHandler \n', ); }, });

plugins namespace

Messages

Use interface merging to combine your custom internationalization messages with PluginLocaleMessages.

// @filename: @hyperse/wizard/dist/index.d.ts
import {  } from '@hyperse/wizard';

export const  = ({
  : {
    : {
      : 'CLI Help Plugin',
      : {
        : 'Show help information',
        : 'cli --help or cli -h',
      },
      : {
        : 'Show help information',
      },
      : {
        : 'Name:',
        : 'Version:',
      },
    },
  },
  : {
    : {
      : '帮助信息插件',
      : {
        : '展示帮助信息',
        : 'cli --help 或 cli -h',
      },
      : {
        : '展示帮助信息',
      },
      : {
        : '名称:',
        : '版本:',
      },
    },
  },
});

Type Merging

// @filename: @hyperse/wizard/dist/index.d.ts
import type {  } from '@hyperse/wizard';

declare module '@hyperse/wizard' {
  export interface PluginLocaleMessages extends <
    typeof helpMessages
  > {}
}

Using

// @filename: @hyperse/wizard/dist/index.d.ts
import {
  ,
  ,
  PluginLocaleMessages,
  ,
  ,
} from '@hyperse/wizard';

// define plugin locale messages
const  = ({
  : {
    : {
      : 'CLI Help Plugin',
      : {
        : 'Show help information',
        : 'cli --help or cli -h',
      },
      : {
        : 'Show help information',
      },
      : {
        : 'Name:',
        : 'Version:',
      },
    },
  },
  : {
    : {
      : '帮助信息插件',
      : {
        : '展示帮助信息',
        : 'cli --help 或 cli -h',
      },
      : {
        : '展示帮助信息',
      },
      : {
        : '名称:',
        : '版本:',
      },
    },
  },
});

// merge plugin locale messages
declare module '@hyperse/wizard' {
  export interface PluginLocaleMessages extends <
    typeof 
  > {}
}

({
  : ,
  // Use internationalization messages
  : 'plugins.helpPlugin.
  • cli.helpCli.description
  • cli.helpCli.version
  • core.command.flagNotProvided
  • core.command.invalidFlagsValue
  • core.command.invalidName
  • core.command.nameConflict
  • core.command.notConfiguration
  • core.command.notFound
  • core.command.notProvider
  • core.command.processNotFound
  • core.flags.hpsAppEnv
  • core.flags.hpsEnvPath
  • core.flags.logLevel
  • core.flags.noColor
  • plugins.helpPlugin.command.description
  • plugins.helpPlugin.command.example
  • plugins.helpPlugin.flags.help
  • plugins.helpPlugin.message.name
  • plugins.helpPlugin.message.version
  • plugins.helpPlugin.name
name',
: (, ) => { const = .( ('help', { // Use internationalization messages : 'plugins.helpPlugin.command.description', // Use internationalization messages : 'plugins.helpPlugin.command.example', }).(() => {}) ); if (flag) { .('help', { : , // Use internationalization messages : 'plugins.helpPlugin.fl
    ags.help',
    : false, : 'h', }) .(async (, ) => {}); } return ; }, });

    On this page