UNPKG

i18ntk

Version:

🚀 The fastest i18n toolkit with 97% performance boost! Zero-dependency, enterprise-grade internationalization for React, Vue, Angular, Python, Java, PHP & more. Features PIN protection, auto framework detection, 7+ UI languages, and comprehensive transla

229 lines (210 loc) • 7.66 kB
/** * Centralized CLI Helper - Shared readline interface management * * This module provides a single readline interface instance to prevent * multiple instances and simplify cleanup across the application. * * @version 1.10.0 * @since 2025-08-08 */ const { getGlobalReadline, closeGlobalReadline, ask, askHidden } = require('./cli'); class CliHelper { constructor() { // Use the global readline interface from cli.js instead of creating our own this.rl = null; this.isInitialized = false; } /** * Initialize the shared readline interface * @returns {readline.Interface} The readline interface */ initialize() { if (!this.isInitialized) { this.rl = getGlobalReadline(); this.isInitialized = true; } return this.rl; } /** * Get the shared readline interface * @returns {readline.Interface} The readline interface */ getInterface() { return this.initialize(); } /** * Prompt user for input with optional masking * @param {string} question - The prompt question * @param {boolean} maskInput - Whether to mask the input (for passwords) * @returns {Promise<string>} The user's input */ async prompt(question, maskInput = false) { if (maskInput) { return askHidden(question); } else { return ask(question); } } /** * Prompt for PIN with secure masking * @param {string} message - Custom message for PIN prompt * @returns {Promise<string>} The PIN entered by user */ async promptPin(message = 'Enter PIN: ') { return askHidden(message); } /** * Close the readline interface and clean up resources */ close() { if (this.isInitialized) { const { closeGlobalReadline } = require('./cli'); closeGlobalReadline(); this.rl = null; this.isInitialized = false; } } /** * Check if the interface is initialized * @returns {boolean} Whether the interface is initialized */ isActive() { return this.isInitialized && this.rl !== null; } /** * Get a yes/no confirmation from user * @param {string} question - The confirmation question * @param {boolean} defaultValue - Default value if user just presses enter * @returns {Promise<boolean>} The user's confirmation */ async confirm(question, defaultValue = false) { const promptText = `${question} (${defaultValue ? 'Y/n' : 'y/N'}): `; const answer = await ask(promptText); const normalized = answer.trim().toLowerCase(); if (normalized === '') { return defaultValue; } else { return normalized === 'y' || normalized === 'yes'; } } /** * Display a menu and get user selection * @param {Array<string>} options - Array of menu options * @param {string} title - Optional menu title * @returns {Promise<number>} The selected option index (0-based) */ async selectMenu(options, title = 'Please select an option:') { console.log(`\n${title}`); options.forEach((option, index) => { console.log(` ${index + 1}. ${option}`); }); while (true) { const answer = await ask('\nEnter your choice: '); const choice = parseInt(answer.trim(), 10); if (isNaN(choice) || choice < 1 || choice > options.length) { console.log('Invalid choice. Please try again.'); continue; } else { return choice - 1; } } } } // Utility: Show framework suggestion warning only once per process let frameworkWarningShown = false; function showFrameworkWarningOnce(ui) { if (frameworkWarningShown) return; frameworkWarningShown = true; // Try to use the proper translation system first let t; if (ui && typeof ui.t === 'function') { t = ui.t.bind(ui); } else { // Fallback to loading the UI i18n system properly try { const UIi18n = require('../main/i18ntk-ui'); const fallbackUI = new UIi18n(); fallbackUI.loadLanguage('en'); // Load English as fallback t = fallbackUI.t.bind(fallbackUI); } catch (error) { // Last resort: use locale files directly try { const path = require('path'); const fs = require('fs'); const localePath = path.join(__dirname, '..', 'ui-locales', 'en.json'); if (fs.existsSync(localePath)) { const translations = JSON.parse(fs.readFileSync(localePath, 'utf8')); t = (key) => { const keys = key.split('.'); let result = translations; for (const k of keys) { result = result && result[k]; } return result || key; }; } else { throw new Error('Locale file not found'); } } catch (fallbackError) { // Final fallback: load from current UI locale or English try { const path = require('path'); const fs = require('fs'); // Try to determine current language from settings const settingsManager = require('../settings/settings-manager'); const settings = settingsManager.loadSettings(); const currentLang = settings.uiLanguage || 'en'; const localePath = path.join(__dirname, '..', 'ui-locales', `${currentLang}.json`); if (fs.existsSync(localePath)) { const translations = JSON.parse(fs.readFileSync(localePath, 'utf8')); t = (key) => { const keys = key.split('.'); let result = translations; for (const k of keys) { result = result && result[k]; } return result || key; }; } else { // Fallback to English const enLocalePath = path.join(__dirname, '..', 'ui-locales', 'en.json'); if (fs.existsSync(enLocalePath)) { const translations = JSON.parse(fs.readFileSync(enLocalePath, 'utf8')); t = (key) => { const keys = key.split('.'); let result = translations; for (const k of keys) { result = result && result[k]; } return result || key; }; } else { throw new Error('No locale files found'); } } } catch (finalError) { // Absolute last resort: basic hardcoded fallback const messages = { 'init.suggestions.noFramework': 'No i18n framework detected. Consider using one of the following:', 'init.frameworks.react': ' - React i18next (react-i18next)', 'init.frameworks.vue': ' - Vue i18n (vue-i18next)', 'init.frameworks.i18next': ' - i18next (i18next)', 'init.frameworks.nuxt': ' - Nuxt i18n (@nuxtjs/i18next)', 'init.frameworks.svelte': ' - Svelte i18n (svelte-i18next)' }; t = (key) => messages[key] || key; } } } } console.log(t('init.suggestions.noFramework')); console.log(t('init.frameworks.react')); console.log(t('init.frameworks.vue')); console.log(t('init.frameworks.i18next')); console.log(t('init.frameworks.nuxt')); console.log(t('init.frameworks.svelte')); } // Export a singleton instance and attach utility for backward compatibility const cliHelper = new CliHelper(); cliHelper.showFrameworkWarningOnce = showFrameworkWarningOnce; module.exports = cliHelper;