From b5bc753adac7c29002acf53dc2d1d1b0f4beafe6 Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Fri, 23 Oct 2026 18:06:48 +0900 Subject: [PATCH 1/2] feat(cli): add --locale and deprecate --lang ko|en Add a --locale flag that selects the output language. Docs and READMEs now use --locale. --lang ko|en still sets the locale for now but prints a deprecation warning, and this transition lasts one minor release. Any other --lang value, or an unknown --locale value, exits 1 with an error instead of being silently ignored. This keeps the planned programming-language meaning of --lang from ever applying silently. Refs pleaseai/code-style#65 --- apps/docs/src/content/docs/en/cli.mdx | 10 ++++--- apps/docs/src/content/docs/ko/cli.mdx | 10 ++++--- packages/cli/README.ko.md | 8 +++-- packages/cli/README.md | 10 +++++-- packages/cli/src/check/run-check.ts | 2 +- packages/cli/src/i18n.ts | 43 +++++++++++++++++++++++++-- packages/cli/src/index.ts | 13 ++++++-- packages/cli/test/i18n.test.ts | 25 +++++++++++++++- packages/cli/test/index.test.ts | 35 ++++++++++++++++++++++ 9 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 packages/cli/test/index.test.ts diff --git a/apps/docs/src/content/docs/en/cli.mdx b/apps/docs/src/content/docs/en/cli.mdx index 2b07151..916f11c 100644 --- a/apps/docs/src/content/docs/en/cli.mdx +++ b/apps/docs/src/content/docs/en/cli.mdx @@ -131,24 +131,26 @@ The full canonical rules are shipped per language for AI assistants that prefer | Flag | Description | | --- | --- | | `--yes`, `-y` | Accept defaults and overwrite existing files without prompting | -| `--lang ` | Force the CLI locale (defaults to `$LC_ALL` / `$LANG`) | +| `--locale ` | Force the CLI locale (defaults to `$LC_ALL` / `$LANG`) | | `--help`, `-h` | Print help | | `--version`, `-v` | Print the CLI version | ## Localisation -The CLI auto-detects your locale from `LC_ALL`, `LANG`, or `LC_MESSAGES` and currently ships Korean and English messages. Override with `--lang ko` or `--lang en`: +The CLI auto-detects your locale from `LC_ALL`, `LANG`, or `LC_MESSAGES` and currently ships Korean and English messages. Override with `--locale ko` or `--locale en`: ```bash -pleaseai-code-style --lang ko init +pleaseai-code-style --locale ko init ``` +`--lang ko` and `--lang en` still set the locale for now, with a deprecation warning. A future release uses `--lang` to select programming languages, so any other `--lang` value exits with an error instead of being ignored. + ## CI Usage Combine `--yes` with a locale override for a fully non-interactive invocation suitable for CI or project templates: ```bash -pleaseai-code-style --yes --lang en init +pleaseai-code-style --yes --locale en init ``` This accepts defaults for every tool, overwrites any existing config files, and uses English output. diff --git a/apps/docs/src/content/docs/ko/cli.mdx b/apps/docs/src/content/docs/ko/cli.mdx index c805fb6..ef0ec13 100644 --- a/apps/docs/src/content/docs/ko/cli.mdx +++ b/apps/docs/src/content/docs/ko/cli.mdx @@ -131,24 +131,26 @@ CLI는 두 마커 주석 사이의 내용 **만** 관리하며 — `AGENTS.md` | 플래그 | 설명 | | --- | --- | | `--yes`, `-y` | 기본값을 수락하고 기존 파일을 확인 없이 덮어씀 | -| `--lang ` | CLI 언어 강제 지정 (기본값은 `$LC_ALL` / `$LANG`) | +| `--locale ` | CLI 언어 강제 지정 (기본값은 `$LC_ALL` / `$LANG`) | | `--help`, `-h` | 도움말 출력 | | `--version`, `-v` | CLI 버전 출력 | ## 현지화 -CLI는 `LC_ALL`, `LANG`, `LC_MESSAGES`에서 locale을 자동 감지하며, 현재 한국어와 영어 메시지를 제공합니다. `--lang ko` 또는 `--lang en`으로 강제 지정할 수 있습니다: +CLI는 `LC_ALL`, `LANG`, `LC_MESSAGES`에서 locale을 자동 감지하며, 현재 한국어와 영어 메시지를 제공합니다. `--locale ko` 또는 `--locale en`으로 강제 지정할 수 있습니다: ```bash -pleaseai-code-style --lang ko init +pleaseai-code-style --locale ko init ``` +`--lang ko`와 `--lang en`도 당분간은 로케일을 지정하지만 사용 중단 경고를 출력합니다. 이후 릴리스에서 `--lang`은 프로그래밍 언어 선택에 쓰이므로, 그 밖의 `--lang` 값은 무시되지 않고 오류로 종료합니다. + ## CI에서의 사용 `--yes`와 언어 옵션을 조합하면 CI나 프로젝트 템플릿에 적합한 완전 비대화형 실행을 만들 수 있습니다: ```bash -pleaseai-code-style --yes --lang en init +pleaseai-code-style --yes --locale en init ``` 모든 도구의 기본값을 수락하고, 기존 설정 파일을 덮어쓰며, 영어로 출력합니다. diff --git a/packages/cli/README.ko.md b/packages/cli/README.ko.md index 8d9fb5e..36949da 100644 --- a/packages/cli/README.ko.md +++ b/packages/cli/README.ko.md @@ -220,14 +220,18 @@ CLI는 아래 마커 사이의 내용만 관리합니다 — `AGENTS.md`의 나 | 플래그 | 설명 | | --- | --- | | `--yes`, `-y` | 기본값을 수락하고 기존 파일을 확인 없이 덮어씀 | -| `--lang ` | CLI 언어 강제 지정 (기본값은 `$LANG`) | +| `--locale ` | CLI 언어 강제 지정 (기본값은 `$LANG`) | | `--help`, `-h` | 도움말 출력 | | `--version`, `-v` | 버전 출력 | ## 현지화 CLI는 `LC_ALL` / `LANG` / `LC_MESSAGES`에서 locale을 자동 감지하며, 현재 한국어와 -영어 메시지를 제공합니다. `--lang ko` 또는 `--lang en`으로 강제 지정할 수 있습니다. +영어 메시지를 제공합니다. `--locale ko` 또는 `--locale en`으로 강제 지정할 수 있습니다. + +`--lang ko`와 `--lang en`도 당분간은 로케일을 지정하지만 사용 중단 경고를 출력합니다. +이후 릴리스에서 `--lang`은 프로그래밍 언어 선택에 쓰이므로, 그 밖의 `--lang` 값은 +무시되지 않고 오류로 종료합니다. ## 라이선스 diff --git a/packages/cli/README.md b/packages/cli/README.md index 0211004..d5991bb 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -404,15 +404,19 @@ JavaScript). | Flag | Description | | --- | --- | | `--yes`, `-y` | Accept defaults, overwrite existing files without prompting | -| `--lang ` | Force the CLI locale (defaults to `$LANG`) | +| `--locale ` | Force the CLI locale (defaults to `$LANG`) | | `--help`, `-h` | Print help | | `--version`, `-v` | Print version | ## Localisation The CLI auto-detects your locale from `LC_ALL` / `LANG` / `LC_MESSAGES` and -currently ships Korean and English messages. Override with `--lang ko` or -`--lang en`. +currently ships Korean and English messages. Override with `--locale ko` or +`--locale en`. + +`--lang ko` and `--lang en` still set the locale for now, with a deprecation +warning. A future release uses `--lang` to select programming languages, so any +other `--lang` value exits with an error instead of being ignored. ## License diff --git a/packages/cli/src/check/run-check.ts b/packages/cli/src/check/run-check.ts index aa0c546..bd77682 100644 --- a/packages/cli/src/check/run-check.ts +++ b/packages/cli/src/check/run-check.ts @@ -22,7 +22,7 @@ export function runCheck(argv: string[], version: () => string): number { config: { type: 'string' }, help: { type: 'boolean', short: 'h' }, version: { type: 'boolean', short: 'v' }, - // Global option, already applied by the entry point. + locale: { type: 'string' }, lang: { type: 'string' }, }, }) diff --git a/packages/cli/src/i18n.ts b/packages/cli/src/i18n.ts index 1d1e108..daef6d8 100644 --- a/packages/cli/src/i18n.ts +++ b/packages/cli/src/i18n.ts @@ -27,6 +27,8 @@ interface Messages { unknownCommand: (cmd: string) => string unexpectedArguments: (args: string) => string optionBeforeCheck: (option: string) => string + deprecatedLangFlag: (locale: Locale) => string + invalidLocaleFlag: (flag: LocaleFlag, value: string) => string usage: string checkUsage: string } @@ -57,6 +59,10 @@ const messages: Record = { unknownCommand: cmd => `Unknown command: ${cmd}`, unexpectedArguments: args => `Unexpected arguments: ${args}`, optionBeforeCheck: option => `${option} is a check option; put it after \`check\` (please-style check ${option})`, + deprecatedLangFlag: locale => `--lang ${locale} is deprecated; use --locale ${locale}. A future release will use --lang to select programming languages.`, + invalidLocaleFlag: (flag, value) => flag === '--locale' + ? `Unknown --locale value: "${value}". Use ko or en.` + : `Unknown --lang value: "${value}". To set the CLI locale, use --locale .`, usage: `Usage: pleaseai-code-style [options] @@ -68,7 +74,7 @@ Commands: Options: --yes, -y Accept defaults, overwrite existing files - --lang Force CLI locale + --locale Force CLI locale --help, -h Show this message --version, -v Print version`, checkUsage: `Usage: @@ -113,6 +119,10 @@ Exit codes: 0 ok or warnings only, 1 findings with --strict, 2 usage or config e unknownCommand: cmd => `알 수 없는 명령어: ${cmd}`, unexpectedArguments: args => `예상하지 못한 인자: ${args}`, optionBeforeCheck: option => `${option}는 check 옵션입니다. \`check\` 뒤에 쓰세요 (please-style check ${option})`, + deprecatedLangFlag: locale => `--lang ${locale}는 더 이상 권장하지 않습니다. --locale ${locale}를 쓰세요. 이후 릴리스에서 --lang은 프로그래밍 언어 선택에 쓰입니다.`, + invalidLocaleFlag: (flag, value) => flag === '--locale' + ? `알 수 없는 --locale 값: "${value}". ko 또는 en을 쓰세요.` + : `알 수 없는 --lang 값: "${value}". CLI 로케일은 --locale 으로 지정하세요.`, usage: `사용법: pleaseai-code-style [options] @@ -124,7 +134,7 @@ Exit codes: 0 ok or warnings only, 1 findings with --strict, 2 usage or config e 옵션: --yes, -y 기본값 수락, 기존 파일 덮어쓰기 - --lang CLI 로케일 강제 지정 + --locale CLI 로케일 강제 지정 --help, -h 이 메시지 표시 --version, -v 버전 출력`, checkUsage: `사용법: @@ -154,6 +164,35 @@ export function detectLocale(override?: string): Locale { return env.toLowerCase().startsWith('ko') ? 'ko' : 'en' } +export type LocaleFlag = '--locale' | '--lang' + +type FlagValue = string | boolean | undefined + +export type LocaleFlags + = | { kind: 'ok', locale: Locale, deprecatedLang?: Locale } + | { kind: 'invalid', locale: Locale, flag: LocaleFlag, value: string } + +function asLocale(value: FlagValue): Locale | undefined { + return value === 'ko' || value === 'en' ? value : undefined +} + +function flagText(value: FlagValue): string { + return typeof value === 'string' ? value : '' +} + +export function resolveLocaleFlags(flags: { locale?: FlagValue, lang?: FlagValue }): LocaleFlags { + const fromLocale = asLocale(flags.locale) + const fromLang = asLocale(flags.lang) + const locale = fromLocale ?? fromLang ?? detectLocale() + if (flags.locale !== undefined && fromLocale === undefined) { + return { kind: 'invalid', locale, flag: '--locale', value: flagText(flags.locale) } + } + if (flags.lang !== undefined && fromLang === undefined) { + return { kind: 'invalid', locale, flag: '--lang', value: flagText(flags.lang) } + } + return { kind: 'ok', locale, deprecatedLang: fromLang } +} + let current: Locale = 'en' export function setLocale(locale: Locale): void { diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 883e579..8a1d1a1 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -5,12 +5,13 @@ import { fileURLToPath } from 'node:url' import { parseArgs } from 'node:util' import { runCheck } from './check/run-check.js' import { runDoctor, runInit, runUpdate } from './commands.js' -import { detectLocale, setLocale, t } from './i18n.js' +import { resolveLocaleFlags, setLocale, t } from './i18n.js' const GLOBAL_OPTIONS = { yes: { type: 'boolean', short: 'y' }, help: { type: 'boolean', short: 'h' }, version: { type: 'boolean', short: 'v' }, + locale: { type: 'string' }, lang: { type: 'string' }, } as const @@ -23,7 +24,15 @@ const { values: allValues, positionals, tokens } = parseArgs({ options: GLOBAL_OPTIONS, }) -setLocale(detectLocale(typeof allValues.lang === 'string' ? allValues.lang : undefined)) +const localeFlags = resolveLocaleFlags({ locale: allValues.locale, lang: allValues.lang }) +setLocale(localeFlags.locale) +if (localeFlags.kind === 'invalid') { + process.stderr.write(`${t('invalidLocaleFlag')(localeFlags.flag, localeFlags.value)}\n`) + process.exit(1) +} +else if (localeFlags.deprecatedLang !== undefined) { + process.stderr.write(`${t('deprecatedLangFlag')(localeFlags.deprecatedLang)}\n`) +} const command = positionals[0] ?? 'init' // `check` parses its own flags strictly, so only what precedes it is global diff --git a/packages/cli/test/i18n.test.ts b/packages/cli/test/i18n.test.ts index f46fbcf..25ad035 100644 --- a/packages/cli/test/i18n.test.ts +++ b/packages/cli/test/i18n.test.ts @@ -1,6 +1,6 @@ import process from 'node:process' import { afterEach, describe, expect, test } from 'bun:test' -import { detectLocale, setLocale, t } from '../src/i18n.js' +import { detectLocale, resolveLocaleFlags, setLocale, t } from '../src/i18n.js' describe('detectLocale', () => { const originalLang = process.env.LANG @@ -57,6 +57,29 @@ describe('detectLocale', () => { }) }) +describe('resolveLocaleFlags', () => { + test('--locale sets the locale without a warning', () => { + expect(resolveLocaleFlags({ locale: 'ko' })).toEqual({ kind: 'ok', locale: 'ko', deprecatedLang: undefined }) + }) + + test('--lang ko|en still sets the locale and is reported as deprecated', () => { + expect(resolveLocaleFlags({ lang: 'en' })).toEqual({ kind: 'ok', locale: 'en', deprecatedLang: 'en' }) + }) + + test('--locale wins over --lang', () => { + expect(resolveLocaleFlags({ locale: 'en', lang: 'ko' })).toMatchObject({ kind: 'ok', locale: 'en', deprecatedLang: 'ko' }) + }) + + test('an unknown --lang value is invalid instead of ignored', () => { + expect(resolveLocaleFlags({ lang: 'dart' })).toMatchObject({ kind: 'invalid', flag: '--lang', value: 'dart' }) + expect(resolveLocaleFlags({ lang: true })).toMatchObject({ kind: 'invalid', flag: '--lang', value: '' }) + }) + + test('an unknown --locale value is invalid', () => { + expect(resolveLocaleFlags({ locale: 'fr' })).toMatchObject({ kind: 'invalid', flag: '--locale', value: 'fr' }) + }) +}) + describe('t (translation lookup)', () => { test('returns English messages when locale is en', () => { setLocale('en') diff --git a/packages/cli/test/index.test.ts b/packages/cli/test/index.test.ts new file mode 100644 index 0000000..fb559c9 --- /dev/null +++ b/packages/cli/test/index.test.ts @@ -0,0 +1,35 @@ +import { spawnSync } from 'node:child_process' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { describe, expect, test } from 'bun:test' + +const CLI = fileURLToPath(new URL('../src/index.ts', import.meta.url)) + +function run(args: string[]): { status: number | null, stdout: string, stderr: string } { + const env = { ...process.env, LC_ALL: 'en_US.UTF-8', LANG: 'en_US.UTF-8', LC_MESSAGES: 'en_US.UTF-8' } + const res = spawnSync('bun', [CLI, ...args], { encoding: 'utf-8', env }) + return { status: res.status, stdout: res.stdout, stderr: res.stderr } +} + +describe('locale flags', () => { + test('--locale sets the message language', () => { + const res = run(['--locale', 'ko', '--help']) + expect(res.status).toBe(0) + expect(res.stdout).toContain('사용법:') + expect(res.stderr).toBe('') + }) + + test('--lang ko warns that it moved to --locale and still sets the locale', () => { + const res = run(['--lang', 'ko', '--help']) + expect(res.status).toBe(0) + expect(res.stdout).toContain('사용법:') + expect(res.stderr).toContain('--locale ko') + }) + + test('an unknown --lang value exits non-zero instead of being ignored', () => { + const res = run(['--lang', 'dart', '--help']) + expect(res.status).toBe(1) + expect(res.stdout).toBe('') + expect(res.stderr).toContain('Unknown --lang value: "dart"') + }) +}) From 7fd6040d6b613ec51432c9e586cce08dfe64c3ce Mon Sep 17 00:00:00 2001 From: Minsu Lee Date: Fri, 23 Oct 2026 18:48:26 +0900 Subject: [PATCH 2/2] chore(cli): apply AI code review suggestions - Warn that --lang is ignored, not that it is the migration target, when --locale overrides it - Fix the Korean particles in the --lang deprecation message - Describe the current --lang/--locale error behavior and precedence in docs Refs pleaseai/code-style#65 --- apps/docs/src/content/docs/en/cli.mdx | 2 +- apps/docs/src/content/docs/ko/cli.mdx | 2 +- packages/cli/README.ko.md | 5 +++-- packages/cli/README.md | 5 +++-- packages/cli/src/i18n.ts | 17 ++++++++++++++--- packages/cli/src/index.ts | 5 +++-- packages/cli/test/i18n.test.ts | 8 ++++---- packages/cli/test/index.test.ts | 7 +++++++ 8 files changed, 36 insertions(+), 15 deletions(-) diff --git a/apps/docs/src/content/docs/en/cli.mdx b/apps/docs/src/content/docs/en/cli.mdx index 916f11c..ed20c08 100644 --- a/apps/docs/src/content/docs/en/cli.mdx +++ b/apps/docs/src/content/docs/en/cli.mdx @@ -143,7 +143,7 @@ The CLI auto-detects your locale from `LC_ALL`, `LANG`, or `LC_MESSAGES` and cur pleaseai-code-style --locale ko init ``` -`--lang ko` and `--lang en` still set the locale for now, with a deprecation warning. A future release uses `--lang` to select programming languages, so any other `--lang` value exits with an error instead of being ignored. +`--lang ko` and `--lang en` still set the locale for now, with a deprecation warning. When both flags are given, `--locale` wins. Any other `--lang` value, or a `--locale` value other than `ko` or `en`, exits with an error (exit code 1). A future release uses `--lang` to select programming languages. ## CI Usage diff --git a/apps/docs/src/content/docs/ko/cli.mdx b/apps/docs/src/content/docs/ko/cli.mdx index ef0ec13..224e67c 100644 --- a/apps/docs/src/content/docs/ko/cli.mdx +++ b/apps/docs/src/content/docs/ko/cli.mdx @@ -143,7 +143,7 @@ CLI는 `LC_ALL`, `LANG`, `LC_MESSAGES`에서 locale을 자동 감지하며, 현 pleaseai-code-style --locale ko init ``` -`--lang ko`와 `--lang en`도 당분간은 로케일을 지정하지만 사용 중단 경고를 출력합니다. 이후 릴리스에서 `--lang`은 프로그래밍 언어 선택에 쓰이므로, 그 밖의 `--lang` 값은 무시되지 않고 오류로 종료합니다. +`--lang ko`와 `--lang en`도 당분간은 로케일을 지정하지만 사용 중단 경고를 출력합니다. 두 플래그를 함께 주면 `--locale`이 우선합니다. 그 밖의 `--lang` 값이나 지원하지 않는 `--locale` 값은 무시되지 않고 오류로 종료합니다(종료 코드 1). 이후 릴리스에서는 `--lang`이 프로그래밍 언어 선택에 쓰입니다. ## CI에서의 사용 diff --git a/packages/cli/README.ko.md b/packages/cli/README.ko.md index 36949da..edcf83b 100644 --- a/packages/cli/README.ko.md +++ b/packages/cli/README.ko.md @@ -230,8 +230,9 @@ CLI는 `LC_ALL` / `LANG` / `LC_MESSAGES`에서 locale을 자동 감지하며, 영어 메시지를 제공합니다. `--locale ko` 또는 `--locale en`으로 강제 지정할 수 있습니다. `--lang ko`와 `--lang en`도 당분간은 로케일을 지정하지만 사용 중단 경고를 출력합니다. -이후 릴리스에서 `--lang`은 프로그래밍 언어 선택에 쓰이므로, 그 밖의 `--lang` 값은 -무시되지 않고 오류로 종료합니다. +두 플래그를 함께 주면 `--locale`이 우선합니다. 그 밖의 `--lang` 값이나 지원하지 않는 +`--locale` 값은 무시되지 않고 오류로 종료합니다(종료 코드 1). 이후 릴리스에서는 +`--lang`이 프로그래밍 언어 선택에 쓰입니다. ## 라이선스 diff --git a/packages/cli/README.md b/packages/cli/README.md index d5991bb..6c8862b 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -415,8 +415,9 @@ currently ships Korean and English messages. Override with `--locale ko` or `--locale en`. `--lang ko` and `--lang en` still set the locale for now, with a deprecation -warning. A future release uses `--lang` to select programming languages, so any -other `--lang` value exits with an error instead of being ignored. +warning. When both flags are given, `--locale` wins. Any other `--lang` value, or +a `--locale` value other than `ko` or `en`, exits with an error (exit code 1). A +future release uses `--lang` to select programming languages. ## License diff --git a/packages/cli/src/i18n.ts b/packages/cli/src/i18n.ts index daef6d8..e08e083 100644 --- a/packages/cli/src/i18n.ts +++ b/packages/cli/src/i18n.ts @@ -28,6 +28,7 @@ interface Messages { unexpectedArguments: (args: string) => string optionBeforeCheck: (option: string) => string deprecatedLangFlag: (locale: Locale) => string + ignoredLangFlag: (locale: Locale) => string invalidLocaleFlag: (flag: LocaleFlag, value: string) => string usage: string checkUsage: string @@ -60,6 +61,7 @@ const messages: Record = { unexpectedArguments: args => `Unexpected arguments: ${args}`, optionBeforeCheck: option => `${option} is a check option; put it after \`check\` (please-style check ${option})`, deprecatedLangFlag: locale => `--lang ${locale} is deprecated; use --locale ${locale}. A future release will use --lang to select programming languages.`, + ignoredLangFlag: locale => `--lang ${locale} is deprecated and ignored because --locale is set; remove it. A future release will use --lang to select programming languages.`, invalidLocaleFlag: (flag, value) => flag === '--locale' ? `Unknown --locale value: "${value}". Use ko or en.` : `Unknown --lang value: "${value}". To set the CLI locale, use --locale .`, @@ -119,7 +121,8 @@ Exit codes: 0 ok or warnings only, 1 findings with --strict, 2 usage or config e unknownCommand: cmd => `알 수 없는 명령어: ${cmd}`, unexpectedArguments: args => `예상하지 못한 인자: ${args}`, optionBeforeCheck: option => `${option}는 check 옵션입니다. \`check\` 뒤에 쓰세요 (please-style check ${option})`, - deprecatedLangFlag: locale => `--lang ${locale}는 더 이상 권장하지 않습니다. --locale ${locale}를 쓰세요. 이후 릴리스에서 --lang은 프로그래밍 언어 선택에 쓰입니다.`, + deprecatedLangFlag: locale => `--lang ${locale} 옵션은 더 이상 권장하지 않습니다. 대신 --locale ${locale} 옵션을 쓰세요. 이후 릴리스에서 --lang은 프로그래밍 언어 선택에 쓰입니다.`, + ignoredLangFlag: locale => `--lang ${locale} 옵션은 더 이상 권장하지 않으며, --locale 옵션이 있어 무시합니다. 이 옵션을 지우세요. 이후 릴리스에서 --lang은 프로그래밍 언어 선택에 쓰입니다.`, invalidLocaleFlag: (flag, value) => flag === '--locale' ? `알 수 없는 --locale 값: "${value}". ko 또는 en을 쓰세요.` : `알 수 없는 --lang 값: "${value}". CLI 로케일은 --locale 으로 지정하세요.`, @@ -168,8 +171,13 @@ export type LocaleFlag = '--locale' | '--lang' type FlagValue = string | boolean | undefined +export interface LangWarning { + kind: 'deprecated' | 'ignored' + locale: Locale +} + export type LocaleFlags - = | { kind: 'ok', locale: Locale, deprecatedLang?: Locale } + = | { kind: 'ok', locale: Locale, langWarning?: LangWarning } | { kind: 'invalid', locale: Locale, flag: LocaleFlag, value: string } function asLocale(value: FlagValue): Locale | undefined { @@ -190,7 +198,10 @@ export function resolveLocaleFlags(flags: { locale?: FlagValue, lang?: FlagValue if (flags.lang !== undefined && fromLang === undefined) { return { kind: 'invalid', locale, flag: '--lang', value: flagText(flags.lang) } } - return { kind: 'ok', locale, deprecatedLang: fromLang } + if (fromLang === undefined) { + return { kind: 'ok', locale } + } + return { kind: 'ok', locale, langWarning: { kind: fromLocale === undefined ? 'deprecated' : 'ignored', locale: fromLang } } } let current: Locale = 'en' diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 8a1d1a1..fafd3c7 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -30,8 +30,9 @@ if (localeFlags.kind === 'invalid') { process.stderr.write(`${t('invalidLocaleFlag')(localeFlags.flag, localeFlags.value)}\n`) process.exit(1) } -else if (localeFlags.deprecatedLang !== undefined) { - process.stderr.write(`${t('deprecatedLangFlag')(localeFlags.deprecatedLang)}\n`) +else if (localeFlags.langWarning !== undefined) { + const { kind, locale } = localeFlags.langWarning + process.stderr.write(`${t(kind === 'deprecated' ? 'deprecatedLangFlag' : 'ignoredLangFlag')(locale)}\n`) } const command = positionals[0] ?? 'init' diff --git a/packages/cli/test/i18n.test.ts b/packages/cli/test/i18n.test.ts index 25ad035..88157b1 100644 --- a/packages/cli/test/i18n.test.ts +++ b/packages/cli/test/i18n.test.ts @@ -59,15 +59,15 @@ describe('detectLocale', () => { describe('resolveLocaleFlags', () => { test('--locale sets the locale without a warning', () => { - expect(resolveLocaleFlags({ locale: 'ko' })).toEqual({ kind: 'ok', locale: 'ko', deprecatedLang: undefined }) + expect(resolveLocaleFlags({ locale: 'ko' })).toEqual({ kind: 'ok', locale: 'ko' }) }) test('--lang ko|en still sets the locale and is reported as deprecated', () => { - expect(resolveLocaleFlags({ lang: 'en' })).toEqual({ kind: 'ok', locale: 'en', deprecatedLang: 'en' }) + expect(resolveLocaleFlags({ lang: 'en' })).toEqual({ kind: 'ok', locale: 'en', langWarning: { kind: 'deprecated', locale: 'en' } }) }) - test('--locale wins over --lang', () => { - expect(resolveLocaleFlags({ locale: 'en', lang: 'ko' })).toMatchObject({ kind: 'ok', locale: 'en', deprecatedLang: 'ko' }) + test('--locale wins over --lang, which is reported as ignored', () => { + expect(resolveLocaleFlags({ locale: 'en', lang: 'ko' })).toEqual({ kind: 'ok', locale: 'en', langWarning: { kind: 'ignored', locale: 'ko' } }) }) test('an unknown --lang value is invalid instead of ignored', () => { diff --git a/packages/cli/test/index.test.ts b/packages/cli/test/index.test.ts index fb559c9..016f076 100644 --- a/packages/cli/test/index.test.ts +++ b/packages/cli/test/index.test.ts @@ -26,6 +26,13 @@ describe('locale flags', () => { expect(res.stderr).toContain('--locale ko') }) + test('--lang overridden by --locale is reported as ignored, not as the migration target', () => { + const res = run(['--locale', 'en', '--lang', 'ko', '--help']) + expect(res.status).toBe(0) + expect(res.stdout).toContain('Usage:') + expect(res.stderr).toContain('--lang ko is deprecated and ignored because --locale is set; remove it.') + }) + test('an unknown --lang value exits non-zero instead of being ignored', () => { const res = run(['--lang', 'dart', '--help']) expect(res.status).toBe(1)