0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-03-10 22:22:45 -05:00

feat(cli): add option to skip core check in translate cli commands (#5085)

* feat(cli): add option to skip core check in translate cli commands

* chore(cli): add changeset

* feat(cli): support any string value package name in translate command

* chore: update changeset
This commit is contained in:
Charles Zhao 2023-12-20 16:45:01 +08:00 committed by GitHub
parent 6b2e1c8908
commit e4c73e7bb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 40 deletions

View file

@ -0,0 +1,5 @@
---
"@logto/cli": minor
---
Add "--skip-core-check" option in translate cli commands, in order to support any arbitrary package name other than "phrases" and "phrases-experience".

View file

@ -16,6 +16,11 @@ const translate: CommandModule = {
type: 'string',
describe: 'The path to your Logto instance directory',
})
.option('skip-core-check', {
alias: 'sc',
type: 'boolean',
describe: 'Skip checking if the core package is existed',
})
.command(create)
.command(listTags)
.command(sync)

View file

@ -10,8 +10,15 @@ import { consoleLog, inquireInstancePath, lintLocaleFiles } from '../../../utils
import { parseLocaleFiles, syncPhraseKeysAndFileStructure } from './utils.js';
const syncKeys: CommandModule<
{ path?: string },
{ path?: string; baseline: string; target: string; skipLint?: boolean; package: string }
{ path?: string; skipCoreCheck?: boolean },
{
path?: string;
skipCoreCheck?: boolean;
baseline: string;
target: string;
skipLint?: boolean;
package: string;
}
> = {
command: ['sync-keys', 'sk'],
describe: [
@ -31,7 +38,7 @@ const syncKeys: CommandModule<
.option('package', {
alias: 'pkg',
type: 'string',
describe: 'The package name of the phrases, one of `phrases` or `phrases-experience`',
describe: 'The package name of the phrases, e.g. `phrases` or `phrases-experience`',
default: 'phrases',
})
.option('target', {
@ -40,13 +47,14 @@ const syncKeys: CommandModule<
describe: 'The target language tag, or `all` to sync all languages',
})
.option('skip-lint', {
alias: 's',
alias: 'sl',
type: 'boolean',
describe: 'Skip running `eslint --fix` for locales after syncing',
})
.demandOption(['baseline', 'target']),
handler: async ({
path: inputPath,
skipCoreCheck,
baseline: baselineTag,
target: targetTag,
skipLint,
@ -64,11 +72,7 @@ const syncKeys: CommandModule<
consoleLog.fatal('Baseline and target cannot be the same');
}
if (packageName !== 'phrases' && packageName !== 'phrases-experience') {
consoleLog.fatal('Invalid package name, expected `phrases` or `phrases-experience`');
}
const instancePath = await inquireInstancePath(inputPath);
const instancePath = await inquireInstancePath(inputPath, skipCoreCheck);
const phrasesPath = path.join(instancePath, 'packages', packageName);
const localesPath = path.join(phrasesPath, 'src/locales');
const entrypoint = path.join(localesPath, baselineTag.toLowerCase(), 'index.ts');

View file

@ -1,6 +1,5 @@
import { languages } from '@logto/language-kit';
import { isBuiltInLanguageTag as isPhrasesBuiltInLanguageTag } from '@logto/phrases';
import { isBuiltInLanguageTag as isPhrasesUiBuiltInLanguageTag } from '@logto/phrases-experience';
import PQueue from 'p-queue';
import type { CommandModule } from 'yargs';
@ -8,13 +7,24 @@ import { inquireInstancePath, lintLocaleFiles } from '../../utils.js';
import { type TranslationOptions, baseLanguage, syncTranslation } from './utils.js';
const sync: CommandModule<{ path?: string }, { path?: string }> = {
const sync: CommandModule<
{ path?: string; skipCoreCheck?: boolean },
{ path?: string; skipCoreCheck?: boolean; package: string }
> = {
command: ['sync'],
describe:
'Translate all untranslated phrases using ChatGPT. Note the environment variable `OPENAI_API_KEY` is required to work.',
handler: async ({ path: inputPath }) => {
builder: (yargs) =>
yargs.option('package', {
alias: 'pkg',
type: 'string',
describe: 'The package name of the phrases, e.g. `phrases` or `phrases-experience`',
default: 'phrases',
}),
handler: async ({ path: inputPath, skipCoreCheck, package: packageName }) => {
const queue = new PQueue({ concurrency: 5 });
const instancePath = await inquireInstancePath(inputPath);
const instancePath = await inquireInstancePath(inputPath, skipCoreCheck);
const packages = packageName ? [packageName] : ['phrases', 'phrases-experience'];
for (const languageTag of Object.keys(languages)) {
if (languageTag === baseLanguage) {
@ -27,28 +37,22 @@ const sync: CommandModule<{ path?: string }, { path?: string }> = {
queue,
} satisfies Partial<TranslationOptions>;
/* eslint-disable no-await-in-loop */
if (isPhrasesBuiltInLanguageTag(languageTag)) {
await syncTranslation({
...baseOptions,
packageName: 'phrases',
languageTag,
});
for (const packageName of packages) {
/* eslint-disable no-await-in-loop */
if (isPhrasesBuiltInLanguageTag(languageTag)) {
await syncTranslation({
...baseOptions,
packageName,
languageTag,
});
}
/* eslint-enable no-await-in-loop */
}
if (isPhrasesUiBuiltInLanguageTag(languageTag)) {
await syncTranslation({
...baseOptions,
packageName: 'phrases-experience',
languageTag,
});
}
/* eslint-enable no-await-in-loop */
}
await queue.onIdle();
void lintLocaleFiles(instancePath);
void lintLocaleFiles(instancePath, packageName);
},
};

View file

@ -43,7 +43,7 @@ export const readBaseLocaleFiles = async (directory: string): Promise<string[]>
export type TranslationOptions = {
instancePath: string;
packageName: 'phrases' | 'phrases-experience';
packageName: string;
languageTag: LanguageTag;
verbose?: boolean;
queue?: PQueue;

View file

@ -7,7 +7,7 @@ import { promisify } from 'node:util';
import { ConsoleLog } from '@logto/shared';
import type { Optional } from '@silverhand/essentials';
import { assert, conditionalString } from '@silverhand/essentials';
import { assert, conditional, conditionalString } from '@silverhand/essentials';
import chalk from 'chalk';
import type { Progress } from 'got';
import { got } from 'got';
@ -197,9 +197,9 @@ const validatePath = async (value: string) => {
return true;
};
export const inquireInstancePath = async (initialPath?: string) => {
export const inquireInstancePath = async (initialPath?: string, skipCoreCheck?: boolean) => {
const inquire = async () => {
if (!initialPath && (await validatePath('.')) === true) {
if (!initialPath && (skipCoreCheck ?? (await validatePath('.')) === true)) {
return path.resolve('.');
}
@ -216,7 +216,7 @@ export const inquireInstancePath = async (initialPath?: string) => {
type: 'input',
default: defaultPath,
filter: (value: string) => value.trim(),
validate: validatePath,
validate: conditional(!skipCoreCheck && validatePath),
},
{ instancePath: initialPath }
);
@ -225,10 +225,13 @@ export const inquireInstancePath = async (initialPath?: string) => {
};
const instancePath = await inquire();
const validated = await validatePath(instancePath);
if (validated !== true) {
consoleLog.fatal(validated);
if (!skipCoreCheck) {
const validated = await validatePath(instancePath);
if (validated !== true) {
consoleLog.fatal(validated);
}
}
return instancePath;
@ -274,8 +277,8 @@ const execPromise = promisify(execFile);
export const lintLocaleFiles = async (
/** Logto instance path */
instancePath: string,
/** Target package name, ignore to lint both packages */
packageName?: 'phrases' | 'phrases-experience'
/** Target package name, ignore to lint both `phrases` and `phrases-experience` packages */
packageName?: string
) => {
const spinner = ora({
text: 'Running `eslint --fix` for locales',