From 03454e6296175bbaa19d6e3a3c8f32d6ead036d7 Mon Sep 17 00:00:00 2001 From: Simon Boudrias Date: Wed, 12 Nov 2025 15:22:28 -0500 Subject: [PATCH] feat(@inquirer/prompts-i18n) New i18n package with first set of localization --- packages/prompts-i18n/README.md | 114 +++++++++++++ packages/prompts-i18n/package.json | 124 ++++++++++++++ packages/prompts-i18n/prompts-i18n.test.ts | 187 +++++++++++++++++++++ packages/prompts-i18n/src/index.ts | 152 +++++++++++++++++ packages/prompts-i18n/src/locales/en.ts | 1 + packages/prompts-i18n/src/locales/es.ts | 54 ++++++ packages/prompts-i18n/src/locales/fr.ts | 41 +++++ packages/prompts-i18n/src/locales/pr.ts | 41 +++++ packages/prompts-i18n/src/locales/zh.ts | 41 +++++ packages/prompts-i18n/src/types.ts | 63 +++++++ packages/prompts-i18n/tsconfig.json | 8 + yarn.lock | 17 ++ 12 files changed, 843 insertions(+) create mode 100644 packages/prompts-i18n/README.md create mode 100644 packages/prompts-i18n/package.json create mode 100644 packages/prompts-i18n/prompts-i18n.test.ts create mode 100644 packages/prompts-i18n/src/index.ts create mode 100644 packages/prompts-i18n/src/locales/en.ts create mode 100644 packages/prompts-i18n/src/locales/es.ts create mode 100644 packages/prompts-i18n/src/locales/fr.ts create mode 100644 packages/prompts-i18n/src/locales/pr.ts create mode 100644 packages/prompts-i18n/src/locales/zh.ts create mode 100644 packages/prompts-i18n/src/types.ts create mode 100644 packages/prompts-i18n/tsconfig.json diff --git a/packages/prompts-i18n/README.md b/packages/prompts-i18n/README.md new file mode 100644 index 000000000..917a69597 --- /dev/null +++ b/packages/prompts-i18n/README.md @@ -0,0 +1,114 @@ +Inquirer Logo + +# @inquirer/prompts-i18n + +[![npm](https://badge.fury.io/js/@inquirer%2Fprompts-i18n.svg)](https://www.npmjs.com/package/@inquirer/prompts-i18n) + +Internationalized Inquirer prompts - 100% drop-in replacements for `@inquirer/prompts` with built-in localization support. + +# Installation + + + + + + + + + + + + + + +
npmyarnpnpmbun
+ +```sh +npm install @inquirer/prompts-i18n +``` + + + +```sh +yarn add @inquirer/prompts-i18n +``` + + + +```sh +pnpm add @inquirer/prompts-i18n +``` + + + +```sh +bun add @inquirer/prompts-i18n +``` + +
+ +# Usage + +Simply replace your import from `@inquirer/prompts` with a language-specific import: + +```js +// Before +import { input, select, confirm } from '@inquirer/prompts'; + +// After (French) +import { input, select, confirm } from '@inquirer/prompts-i18n/fr'; + +// After (Spanish) +import { input, select, confirm } from '@inquirer/prompts-i18n/es'; +``` + +All prompts work exactly the same way as the original package. The only difference is that help text, validation messages, and UI labels are automatically translated to your chosen language. + +# Supported Languages + +- `@inquirer/prompts-i18n/en` - English (default, re-export of original) +- `@inquirer/prompts-i18n/fr` - French +- `@inquirer/prompts-i18n/es` - Spanish +- `@inquirer/prompts-i18n/zh` - Chinese (Simplified) +- `@inquirer/prompts-i18n/pr` - Portuguese + +# Example + +```js +import { input, confirm, select } from '@inquirer/prompts-i18n/fr'; + +const name = await input({ message: 'Quel est votre nom ?' }); + +const confirmed = await confirm({ message: 'Continuer ?' }); + +const choice = await select({ + message: 'Choisissez une option', + choices: [ + { name: 'Option 1', value: 'opt1' }, + { name: 'Option 2', value: 'opt2', disabled: true }, + ], +}); +``` + +# Available Prompts + +All prompts from `@inquirer/prompts` are available: + +- `input` +- `select` +- `checkbox` +- `confirm` +- `search` +- `password` +- `expand` +- `editor` +- `number` +- `rawlist` +- `Separator` + +See the [@inquirer/prompts documentation](https://github.com/SBoudrias/Inquirer.js/tree/main/packages/prompts) for full usage details. + +# License + +Copyright (c) 2025 Simon Boudrias (twitter: [@vaxilart](https://twitter.com/Vaxilart))
+Licensed under the MIT license. diff --git a/packages/prompts-i18n/package.json b/packages/prompts-i18n/package.json new file mode 100644 index 000000000..0458a8d3f --- /dev/null +++ b/packages/prompts-i18n/package.json @@ -0,0 +1,124 @@ +{ + "name": "@inquirer/prompts-i18n", + "version": "0.0.0", + "description": "Internationalized Inquirer prompts - drop-in package with i18n support", + "keywords": [ + "answer", + "answers", + "ask", + "base", + "cli", + "command", + "command-line", + "confirm", + "enquirer", + "generate", + "generator", + "hyper", + "input", + "inquire", + "inquirer", + "interface", + "iterm", + "javascript", + "menu", + "node", + "nodejs", + "prompt", + "promptly", + "prompts", + "question", + "readline", + "scaffold", + "scaffolder", + "scaffolding", + "stdin", + "stdout", + "terminal", + "tty", + "ui", + "yeoman", + "yo", + "zsh", + "internationalization", + "i18n", + "localization", + "l10n", + "types", + "typescript" + ], + "homepage": "https://github.com/SBoudrias/Inquirer.js/blob/main/packages/prompts-i18n/README.md", + "repository": { + "type": "git", + "url": "https://github.com/SBoudrias/Inquirer.js.git" + }, + "license": "MIT", + "author": "Simon Boudrias ", + "sideEffects": false, + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": "./src/index.ts", + "./en": "./src/locales/en.ts", + "./fr": "./src/locales/fr.ts", + "./zh": "./src/locales/zh.ts", + "./pr": "./src/locales/pr.ts", + "./es": "./src/locales/es.ts" + }, + "files": [ + "dist" + ], + "dependencies": { + "@inquirer/core": "^11.0.0", + "@inquirer/prompts": "^8.0.0" + }, + "devDependencies": { + "@inquirer/testing": "^3.0.0", + "@repo/tsconfig": "workspace:*", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "publishConfig": { + "access": "public", + "exports": { + "./package.json": "./package.json", + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./en": { + "types": "./dist/locales/en.d.ts", + "default": "./dist/locales/en.js" + }, + "./fr": { + "types": "./dist/locales/fr.d.ts", + "default": "./dist/locales/fr.js" + }, + "./zh": { + "types": "./dist/locales/zh.d.ts", + "default": "./dist/locales/zh.js" + }, + "./pr": { + "types": "./dist/locales/pr.d.ts", + "default": "./dist/locales/pr.js" + }, + "./es": { + "types": "./dist/locales/es.d.ts", + "default": "./dist/locales/es.js" + } + } + }, + "scripts": { + "tsc": "tsc" + } +} diff --git a/packages/prompts-i18n/prompts-i18n.test.ts b/packages/prompts-i18n/prompts-i18n.test.ts new file mode 100644 index 000000000..6a3d5481a --- /dev/null +++ b/packages/prompts-i18n/prompts-i18n.test.ts @@ -0,0 +1,187 @@ +import { describe, it, expect } from 'vitest'; +import { render } from '@inquirer/testing'; + +// Test all locale exports +import * as en from '@inquirer/prompts-i18n/en'; +import * as fr from '@inquirer/prompts-i18n/fr'; +import * as es from '@inquirer/prompts-i18n/es'; +import * as zh from '@inquirer/prompts-i18n/zh'; +import * as pr from '@inquirer/prompts-i18n/pr'; + +describe('@inquirer/prompts-i18n', () => { + const locales = { en, fr, es, zh, pr }; + + for (const [locale, exports] of Object.entries(locales)) { + describe(`${locale} locale`, () => { + it('exports all 10 prompt functions and Separator', () => { + expect(exports.checkbox).toBeTypeOf('function'); + expect(exports.confirm).toBeTypeOf('function'); + expect(exports.editor).toBeTypeOf('function'); + expect(exports.expand).toBeTypeOf('function'); + expect(exports.input).toBeTypeOf('function'); + expect(exports.number).toBeTypeOf('function'); + expect(exports.password).toBeTypeOf('function'); + expect(exports.rawlist).toBeTypeOf('function'); + expect(exports.search).toBeTypeOf('function'); + expect(exports.select).toBeTypeOf('function'); + expect(exports.Separator).toBeTypeOf('function'); + }); + }); + } + + describe('French locale (fr)', () => { + it('confirm shows French Yes/No labels', async () => { + const { answer, events, getScreen } = await render(fr.confirm, { + message: 'Voulez-vous continuer?', + }); + + expect(getScreen()).toMatchInlineSnapshot('"? Voulez-vous continuer? (O/n)"'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(true); + expect(getScreen()).toMatchInlineSnapshot('"✔ Voulez-vous continuer? Oui"'); + }); + + it('confirm shows French Yes/No labels with default false', async () => { + const { answer, events, getScreen } = await render(fr.confirm, { + message: 'Voulez-vous continuer?', + default: false, + }); + + expect(getScreen()).toMatchInlineSnapshot('"? Voulez-vous continuer? (o/N)"'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(false); + expect(getScreen()).toMatchInlineSnapshot('"✔ Voulez-vous continuer? Non"'); + }); + + it('select shows French help keys', async () => { + const { answer, events, getScreen } = await render(fr.select, { + message: 'Choisissez une option', + choices: [ + { name: 'Option 1', value: 1 }, + { name: 'Option 2', value: 2 }, + ], + }); + + const screen = getScreen(); + expect(screen).toContain('naviguer'); + expect(screen).toContain('sélectionner'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(1); + }); + + it('checkbox shows French help keys', async () => { + const { answer, events, getScreen } = await render(fr.checkbox, { + message: 'Sélectionnez des options', + choices: [ + { name: 'Option 1', value: 1 }, + { name: 'Option 2', value: 2 }, + ], + }); + + const screen = getScreen(); + expect(screen).toContain('naviguer'); + expect(screen).toContain('sélectionner'); + expect(screen).toContain('soumettre'); + + events.keypress('space'); + events.keypress('enter'); + await expect(answer).resolves.toEqual([1]); + }); + }); + + describe('Spanish locale (es)', () => { + it('confirm shows Spanish Sí/No labels', async () => { + const { answer, events, getScreen } = await render(es.confirm, { + message: '¿Quieres continuar?', + }); + + expect(getScreen()).toMatchInlineSnapshot('"? ¿Quieres continuar? (S/n)"'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(true); + expect(getScreen()).toMatchInlineSnapshot('"✔ ¿Quieres continuar? Sí"'); + }); + + it('select shows Spanish help keys', async () => { + const { answer, events, getScreen } = await render(es.select, { + message: 'Elige una opción', + choices: [ + { name: 'Opción 1', value: 1 }, + { name: 'Opción 2', value: 2 }, + ], + }); + + const screen = getScreen(); + expect(screen).toContain('navegar'); + expect(screen).toContain('seleccionar'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(1); + }); + }); + + describe('Chinese locale (zh)', () => { + it('confirm shows Chinese 是/否 labels', async () => { + const { answer, events, getScreen } = await render(zh.confirm, { + message: '你想继续吗?', + }); + + expect(getScreen()).toMatchInlineSnapshot('"? 你想继续吗? (是/否)"'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(true); + expect(getScreen()).toMatchInlineSnapshot('"✔ 你想继续吗? 是"'); + }); + + it('select shows Chinese help keys', async () => { + const { answer, events, getScreen } = await render(zh.select, { + message: '选择一个选项', + choices: [ + { name: '选项 1', value: 1 }, + { name: '选项 2', value: 2 }, + ], + }); + + const screen = getScreen(); + expect(screen).toContain('导航'); + expect(screen).toContain('选择'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(1); + }); + }); + + describe('Portuguese locale (pr)', () => { + it('confirm shows Portuguese Sim/Não labels', async () => { + const { answer, events, getScreen } = await render(pr.confirm, { + message: 'Você quer continuar?', + }); + + expect(getScreen()).toMatchInlineSnapshot('"? Você quer continuar? (S/n)"'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(true); + expect(getScreen()).toMatchInlineSnapshot('"✔ Você quer continuar? Sim"'); + }); + + it('select shows Portuguese help keys', async () => { + const { answer, events, getScreen } = await render(pr.select, { + message: 'Escolha uma opção', + choices: [ + { name: 'Opção 1', value: 1 }, + { name: 'Opção 2', value: 2 }, + ], + }); + + const screen = getScreen(); + expect(screen).toContain('navegar'); + expect(screen).toContain('selecionar'); + + events.keypress('enter'); + await expect(answer).resolves.toEqual(1); + }); + }); +}); diff --git a/packages/prompts-i18n/src/index.ts b/packages/prompts-i18n/src/index.ts new file mode 100644 index 000000000..49cfdbe11 --- /dev/null +++ b/packages/prompts-i18n/src/index.ts @@ -0,0 +1,152 @@ +import { + checkbox as checkboxPrompt, + confirm as confirmPrompt, + editor as editorPrompt, + expand as expandPrompt, + input as inputPrompt, + number as numberPrompt, + password as passwordPrompt, + rawlist as rawlistPrompt, + search as searchPrompt, + select as selectPrompt, +} from '@inquirer/prompts'; +import { makeTheme } from '@inquirer/core'; +import { styleText } from 'node:util'; +import type { Locale } from './types.js'; + +// Extract config types from the prompt functions +type ConfirmConfig = Parameters[0]; +type SelectConfig = Parameters>[0]; +type CheckboxConfig = Parameters>[0]; +type SearchConfig = Parameters>[0]; +type ExpandConfig = Parameters>[0]; +type RawlistConfig = Parameters>[0]; +type EditorConfig = Parameters[0]; +type InputConfig = Parameters[0]; +type NumberConfig = Parameters< + typeof numberPrompt +>[0]; +type PasswordConfig = Parameters[0]; +type Context = Parameters[1]; + +/** + * Factory function that creates localized prompt wrappers for a given locale. + * + * @param locale - The locale object containing all localized strings + * @returns An object containing all prompt functions with localization applied + */ +export function createLocalizedPrompts(locale: Locale) { + return { + confirm(this: void, config: ConfirmConfig, context?: Context) { + const theme = makeTheme(config.theme, { + style: { + defaultAnswer: (text: string) => { + if (text === 'Y/n') return styleText('dim', `(${locale.confirm.hintYes})`); + if (text === 'y/N') return styleText('dim', `(${locale.confirm.hintNo})`); + return styleText('dim', `(${text})`); + }, + }, + }); + + return confirmPrompt( + { + ...config, + theme, + transformer: + config.transformer ?? + ((answer: boolean) => + answer ? locale.confirm.yesLabel : locale.confirm.noLabel), + }, + context, + ); + }, + + select(this: void, config: SelectConfig, context?: Context) { + const theme = makeTheme(config.theme, { + style: { + keysHelpTip: (keys: Array<[string, string]>) => { + const localizedKeys = keys.map(([key, label]): [string, string] => { + if (label === 'navigate') return [key, locale.select.helpNavigate]; + if (label === 'select') return [key, locale.select.helpSelect]; + return [key, label]; + }); + return localizedKeys + .map(([k, l]) => `${styleText('bold', k)} ${styleText('dim', l)}`) + .join(styleText('dim', ' • ')); + }, + }, + }); + + return selectPrompt({ ...config, theme }, context); + }, + + checkbox(this: void, config: CheckboxConfig, context?: Context) { + const theme = makeTheme(config.theme, { + style: { + keysHelpTip: (keys: Array<[string, string]>) => { + const localizedKeys = keys.map(([key, label]): [string, string] => { + if (label === 'navigate') return [key, locale.checkbox.helpNavigate]; + if (label === 'select') return [key, locale.checkbox.helpSelect]; + if (label === 'submit') return [key, locale.checkbox.helpSubmit]; + if (label === 'all') return [key, locale.checkbox.helpAll]; + if (label === 'invert') return [key, locale.checkbox.helpInvert]; + return [key, label]; + }); + return localizedKeys + .map(([k, l]) => `${styleText('bold', k)} ${styleText('dim', l)}`) + .join(styleText('dim', ' • ')); + }, + }, + }); + + return checkboxPrompt({ ...config, theme }, context); + }, + + search(this: void, config: SearchConfig, context?: Context) { + const theme = makeTheme(config.theme, { + style: { + keysHelpTip: (keys: Array<[string, string]>) => { + const localizedKeys = keys.map(([key, label]): [string, string] => { + if (label === 'navigate') return [key, locale.search.helpNavigate]; + if (label === 'select') return [key, locale.search.helpSelect]; + return [key, label]; + }); + return localizedKeys + .map(([k, l]) => `${styleText('bold', k)} ${styleText('dim', l)}`) + .join(styleText('dim', ' • ')); + }, + }, + }); + + return searchPrompt({ ...config, theme }, context); + }, + + expand(this: void, config: ExpandConfig, context?: Context) { + return expandPrompt(config, context); + }, + + rawlist(this: void, config: RawlistConfig, context?: Context) { + return rawlistPrompt(config, context); + }, + + editor(this: void, config: EditorConfig, context?: Context) { + return editorPrompt(config, context); + }, + + input(this: void, config: InputConfig, context?: Context) { + return inputPrompt(config, context); + }, + + number( + this: void, + config: NumberConfig, + context?: Context, + ) { + return numberPrompt(config, context); + }, + + password(this: void, config: PasswordConfig, context?: Context) { + return passwordPrompt(config, context); + }, + }; +} diff --git a/packages/prompts-i18n/src/locales/en.ts b/packages/prompts-i18n/src/locales/en.ts new file mode 100644 index 000000000..a59c4a2af --- /dev/null +++ b/packages/prompts-i18n/src/locales/en.ts @@ -0,0 +1 @@ +export * from '@inquirer/prompts'; diff --git a/packages/prompts-i18n/src/locales/es.ts b/packages/prompts-i18n/src/locales/es.ts new file mode 100644 index 000000000..4eacb357f --- /dev/null +++ b/packages/prompts-i18n/src/locales/es.ts @@ -0,0 +1,54 @@ +import { createLocalizedPrompts } from '../index.ts'; +import type { Locale } from '../types.ts'; + +const esLocale: Locale = { + confirm: { + yesLabel: 'Sí', + noLabel: 'No', + hintYes: 'S/n', + hintNo: 's/N', + }, + select: { + helpNavigate: 'navegar', + helpSelect: 'seleccionar', + }, + checkbox: { + helpNavigate: 'navegar', + helpSelect: 'seleccionar', + helpSubmit: 'enviar', + helpAll: 'todos', + helpInvert: 'invertir', + }, + search: { + helpNavigate: 'navegar', + helpSelect: 'seleccionar', + }, +}; + +const { + confirm, + select, + checkbox, + search, + expand, + rawlist, + editor, + input, + number, + password, +} = createLocalizedPrompts(esLocale); + +export { + confirm, + select, + checkbox, + search, + expand, + rawlist, + editor, + input, + number, + password, +}; + +export { Separator } from '@inquirer/prompts'; diff --git a/packages/prompts-i18n/src/locales/fr.ts b/packages/prompts-i18n/src/locales/fr.ts new file mode 100644 index 000000000..b6ca21da2 --- /dev/null +++ b/packages/prompts-i18n/src/locales/fr.ts @@ -0,0 +1,41 @@ +import { createLocalizedPrompts } from '../index.ts'; +import type { Locale } from '../types.ts'; + +const frLocale: Locale = { + confirm: { + yesLabel: 'Oui', + noLabel: 'Non', + hintYes: 'O/n', + hintNo: 'o/N', + }, + select: { + helpNavigate: 'naviguer', + helpSelect: 'sélectionner', + }, + checkbox: { + helpNavigate: 'naviguer', + helpSelect: 'sélectionner', + helpSubmit: 'soumettre', + helpAll: 'tout', + helpInvert: 'inverser', + }, + search: { + helpNavigate: 'naviguer', + helpSelect: 'sélectionner', + }, +}; + +export const { + confirm, + select, + checkbox, + search, + expand, + rawlist, + editor, + input, + number, + password, +} = createLocalizedPrompts(frLocale); + +export { Separator } from '@inquirer/prompts'; diff --git a/packages/prompts-i18n/src/locales/pr.ts b/packages/prompts-i18n/src/locales/pr.ts new file mode 100644 index 000000000..cc570f014 --- /dev/null +++ b/packages/prompts-i18n/src/locales/pr.ts @@ -0,0 +1,41 @@ +import { createLocalizedPrompts } from '../index.ts'; +import type { Locale } from '../types.ts'; + +const prLocale: Locale = { + confirm: { + yesLabel: 'Sim', + noLabel: 'Não', + hintYes: 'S/n', + hintNo: 's/N', + }, + select: { + helpNavigate: 'navegar', + helpSelect: 'selecionar', + }, + checkbox: { + helpNavigate: 'navegar', + helpSelect: 'selecionar', + helpSubmit: 'enviar', + helpAll: 'todos', + helpInvert: 'inverter', + }, + search: { + helpNavigate: 'navegar', + helpSelect: 'selecionar', + }, +}; + +export const { + confirm, + select, + checkbox, + search, + expand, + rawlist, + editor, + input, + number, + password, +} = createLocalizedPrompts(prLocale); + +export { Separator } from '@inquirer/prompts'; diff --git a/packages/prompts-i18n/src/locales/zh.ts b/packages/prompts-i18n/src/locales/zh.ts new file mode 100644 index 000000000..7ac12bbf3 --- /dev/null +++ b/packages/prompts-i18n/src/locales/zh.ts @@ -0,0 +1,41 @@ +import { createLocalizedPrompts } from '../index.ts'; +import type { Locale } from '../types.ts'; + +const zhLocale: Locale = { + confirm: { + yesLabel: '是', + noLabel: '否', + hintYes: '是/否', + hintNo: '是/否', + }, + select: { + helpNavigate: '导航', + helpSelect: '选择', + }, + checkbox: { + helpNavigate: '导航', + helpSelect: '选择', + helpSubmit: '提交', + helpAll: '全选', + helpInvert: '反选', + }, + search: { + helpNavigate: '导航', + helpSelect: '选择', + }, +}; + +export const { + confirm, + select, + checkbox, + search, + expand, + rawlist, + editor, + input, + number, + password, +} = createLocalizedPrompts(zhLocale); + +export { Separator } from '@inquirer/prompts'; diff --git a/packages/prompts-i18n/src/types.ts b/packages/prompts-i18n/src/types.ts new file mode 100644 index 000000000..010508b49 --- /dev/null +++ b/packages/prompts-i18n/src/types.ts @@ -0,0 +1,63 @@ +/** + * Localized strings for the confirm prompt + */ +export interface ConfirmStrings { + /** Default label for "Yes" option */ + yesLabel: string; + /** Default label for "No" option */ + noLabel: string; + /** Hint text when default is true (e.g., "Y/n") */ + hintYes: string; + /** Hint text when default is false (e.g., "y/N") */ + hintNo: string; +} + +/** + * Localized strings for the select prompt + */ +export interface SelectStrings { + /** Help text for navigation keys */ + helpNavigate: string; + /** Help text for selection key */ + helpSelect: string; +} + +/** + * Localized strings for the checkbox prompt + */ +export interface CheckboxStrings { + /** Help text for navigation keys */ + helpNavigate: string; + /** Help text for selection key */ + helpSelect: string; + /** Help text for submit key */ + helpSubmit: string; + /** Help text for "select all" key */ + helpAll: string; + /** Help text for "invert selection" key */ + helpInvert: string; +} + +/** + * Localized strings for the search prompt + */ +export interface SearchStrings { + /** Help text for navigation keys */ + helpNavigate: string; + /** Help text for selection key */ + helpSelect: string; +} + +/** + * Complete locale definition containing all prompt strings + * + * Note: Only prompts with theme-injectable strings are included. + * Other prompts (expand, rawlist, editor, input, number, password) + * are pass-through wrappers pending upstream API enhancements. + */ +export interface Locale { + confirm: ConfirmStrings; + select: SelectStrings; + checkbox: CheckboxStrings; + search: SearchStrings; +} diff --git a/packages/prompts-i18n/tsconfig.json b/packages/prompts-i18n/tsconfig.json new file mode 100644 index 000000000..fcbe26b95 --- /dev/null +++ b/packages/prompts-i18n/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@repo/tsconfig", + "include": ["src"], + "exclude": ["src/**/*.test.ts"], + "compilerOptions": { + "outDir": "dist" + } +} diff --git a/yarn.lock b/yarn.lock index 96faa4e43..c3c5cd339 100644 --- a/yarn.lock +++ b/yarn.lock @@ -796,6 +796,23 @@ __metadata: languageName: unknown linkType: soft +"@inquirer/prompts-i18n@workspace:packages/prompts-i18n": + version: 0.0.0-use.local + resolution: "@inquirer/prompts-i18n@workspace:packages/prompts-i18n" + dependencies: + "@inquirer/core": "npm:^11.0.0" + "@inquirer/prompts": "npm:^8.0.0" + "@inquirer/testing": "npm:^3.0.0" + "@repo/tsconfig": "workspace:*" + typescript: "npm:^5.9.3" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + languageName: unknown + linkType: soft + "@inquirer/prompts@npm:^7.8.6": version: 7.10.1 resolution: "@inquirer/prompts@npm:7.10.1"