1
0
mirror of https://gitcode.com/github-mirrors/react-native-update-cli.git synced 2025-09-16 01:41:37 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

add logic to support multi language (#11)

* add logic to support multi language

* Update en.ts

* Update en.ts

---------

Co-authored-by: Sunny Luo <sunnylqm@gmail.com>
This commit is contained in:
波仔糕
2025-04-13 17:02:52 +08:00
committed by GitHub
parent d853918d8d
commit 9cb8d458ad
8 changed files with 170 additions and 57 deletions

View File

@@ -214,17 +214,13 @@ async function runReactNativeBundleCommand({
reactNativeBundleProcess.on('close', async (exitCode) => { reactNativeBundleProcess.on('close', async (exitCode) => {
if (exitCode) { if (exitCode) {
reject( reject(new Error(t('bundleCommandError', { code: exitCode })));
new Error(
`"react-native bundle" command exited with code ${exitCode}.`,
),
);
} else { } else {
let hermesEnabled: boolean | undefined = false; let hermesEnabled: boolean | undefined = false;
if (disableHermes) { if (disableHermes) {
hermesEnabled = false; hermesEnabled = false;
console.log('Hermes disabled'); console.log(t('hermesDisabled'));
} else if (platform === 'android') { } else if (platform === 'android') {
const gradlePropeties = await new Promise<{ const gradlePropeties = await new Promise<{
hermesEnabled?: boolean; hermesEnabled?: boolean;
@@ -283,8 +279,8 @@ async function copyHarmonyBundle(outputFolder: string) {
await fs.ensureDir(outputFolder); await fs.ensureDir(outputFolder);
await fs.copy(harmonyRawPath, outputFolder); await fs.copy(harmonyRawPath, outputFolder);
} catch (error: any) { } catch (error: any) {
console.error('copyHarmonyBundle 错误:', error); console.error(t('copyHarmonyBundleError', { error }));
throw new Error(`复制文件失败: ${error.message}`); throw new Error(t('copyFileFailed', { error: error.message }));
} }
} }
@@ -355,7 +351,7 @@ async function compileHermesByteCode(
); );
args.push('-output-source-map'); args.push('-output-source-map');
} }
console.log(`Running hermesc: ${hermesCommand} ${args.join(' ')}`); console.log(t('runningHermesc', { command: hermesCommand, args: args.join(' ') }));
spawnSync(hermesCommand, args, { spawnSync(hermesCommand, args, {
stdio: 'ignore', stdio: 'ignore',
}); });
@@ -365,7 +361,7 @@ async function compileHermesByteCode(
if (!fs.existsSync(composerPath)) { if (!fs.existsSync(composerPath)) {
return; return;
} }
console.log('Composing source map'); console.log(t('composingSourceMap'));
spawnSync( spawnSync(
'node', 'node',
[ [
@@ -400,16 +396,14 @@ async function copyDebugidForSentry(
}, },
); );
} catch (error) { } catch (error) {
console.error( console.error(t('sentryCliNotFound'));
'无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native',
);
return; return;
} }
if (!fs.existsSync(copyDebugidPath)) { if (!fs.existsSync(copyDebugidPath)) {
return; return;
} }
console.log('Copying debugid'); console.log(t('copyingDebugId'));
spawnSync( spawnSync(
'node', 'node',
[ [
@@ -453,9 +447,9 @@ async function uploadSourcemapForSentry(
stdio: 'inherit', stdio: 'inherit',
}, },
); );
console.log(`Sentry release created for version: ${version}`); console.log(t('sentryReleaseCreated', { version }));
console.log('Uploading sourcemap'); console.log(t('uploadingSourcemap'));
spawnSync( spawnSync(
'node', 'node',
[ [
@@ -479,7 +473,7 @@ async function uploadSourcemapForSentry(
const ignorePackingFileNames = ['.', '..', 'index.bundlejs.map']; const ignorePackingFileNames = ['.', '..', 'index.bundlejs.map'];
const ignorePackingExtensions = ['DS_Store','txt.map']; const ignorePackingExtensions = ['DS_Store','txt.map'];
async function pack(dir: string, output: string) { async function pack(dir: string, output: string) {
console.log('Packing'); console.log(t('packing'));
fs.ensureDirSync(path.dirname(output)); fs.ensureDirSync(path.dirname(output));
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
const zipfile = new ZipFile(); const zipfile = new ZipFile();
@@ -516,7 +510,7 @@ async function pack(dir: string, output: string) {
}); });
zipfile.end(); zipfile.end();
}); });
console.log(t('ppkPackageGenerated', { output })); console.log(t('fileGenerated', { file: output }));
} }
export function readEntire(entry: string, zipFile: ZipFile) { export function readEntire(entry: string, zipFile: ZipFile) {
@@ -671,7 +665,7 @@ async function diffFromPPK(origin: string, next: string, output: string) {
for (const k in originEntries) { for (const k in originEntries) {
if (!newEntries[k]) { if (!newEntries[k]) {
console.log(`Delete ${k}`); console.log(t('deleteFile', { file: k }));
deletes[k] = 1; deletes[k] = 1;
} }
} }
@@ -844,7 +838,7 @@ export async function enumZipEntries(
await result; await result;
} }
} catch (error) { } catch (error) {
console.error('处理文件时出错:', error); console.error(t('processingError', { error }));
} }
zipfile.readEntry(); zipfile.readEntry();
@@ -860,7 +854,7 @@ function diffArgsCheck(args, options, diffFn) {
const [origin, next] = args; const [origin, next] = args;
if (!origin || !next) { if (!origin || !next) {
console.error(`Usage: pushy ${diffFn} <origin> <next>`); console.error(t('usageDiff', { command: diffFn }));
process.exit(1); process.exit(1);
} }
@@ -927,7 +921,7 @@ export const commands = {
const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`); const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
if (!platform) { if (!platform) {
throw new Error('Platform must be specified.'); throw new Error(t('platformRequired'));
} }
console.log(`Bundling with react-native: ${depVersions['react-native']}`); console.log(`Bundling with react-native: ${depVersions['react-native']}`);
@@ -972,14 +966,14 @@ export const commands = {
async diff({ args, options }) { async diff({ args, options }) {
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diff'); const { origin, next, realOutput } = diffArgsCheck(args, options, 'diff');
await diffFromPPK(origin, next, realOutput, 'index.bundlejs'); await diffFromPPK(origin, next, realOutput);
console.log(`${realOutput} generated.`); console.log(`${realOutput} generated.`);
}, },
async hdiff({ args, options }) { async hdiff({ args, options }) {
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiff'); const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiff');
await diffFromPPK(origin, next, realOutput, 'index.bundlejs'); await diffFromPPK(origin, next, realOutput);
console.log(`${realOutput} generated.`); console.log(`${realOutput} generated.`);
}, },

View File

@@ -40,4 +40,52 @@ This can reduce the risk of inconsistent dependencies and supply chain attacks.
operationSuccess: 'Operation successful', operationSuccess: 'Operation successful',
failedToParseUpdateJson: 'Failed to parse file `update.json`. Try to remove it manually.', failedToParseUpdateJson: 'Failed to parse file `update.json`. Try to remove it manually.',
ppkPackageGenerated: 'ppk package generated and saved to: {{- output}}', ppkPackageGenerated: 'ppk package generated and saved to: {{- output}}',
Message: 'Welcome to Cresc hot update service, {{name}}.',
loggedOut: 'Logged out',
usageUnderDevelopment: 'Usage is under development now.',
hermesDisabled: 'Hermes disabled',
hermesEnabled: 'Hermes enabled, now compiling to hermes bytecode:\n',
runningHermesc: 'Running hermesc: {{command}} {{args}}',
composingSourceMap: 'Composing source map',
copyingDebugId: 'Copying debugid',
sentryCliNotFound: 'Cannot find Sentry CLI tool, please make sure @sentry/cli is properly installed',
sentryReleaseCreated: 'Sentry release created for version: {{version}}',
uploadingSourcemap: 'Uploading sourcemap',
packing: 'Packing',
deletingFile: 'Delete {{file}}',
bundlingWithRN: 'Bundling with react-native: {{version}}',
fileGenerated: '{{file}} generated.',
processingError: 'Error processing file: {{error}}',
usageDiff: 'Usage: cresc {{command}} <origin> <next>',
pluginDetected: 'detected {{name}} plugin',
pluginDetectionError: 'error while detecting {{name}} plugin: {{error}}',
addedToGitignore: 'Added {{line}} to .gitignore',
processingStringPool: 'Processing the string pool ...',
processingPackage: 'Processing the package {{count}} ...',
typeStrings: 'Type strings:',
keyStrings: 'Key strings:',
failedToParseIcon: '[Warning] failed to parse icon: {{error}}',
errorInHarmonyApp: 'Error in getEntryFromHarmonyApp: {{error}}',
totalPackages: 'Total {{count}} packages',
usageUploadIpa: 'Usage: cresc uploadIpa <ipa file>',
usageUploadApk: 'Usage: cresc uploadApk <apk file>',
usageUploadApp: 'Usage: cresc uploadApp <app file>',
usageParseApp: 'Usage: cresc parseApp <app file>',
usageParseIpa: 'Usage: cresc parseIpa <ipa file>',
usageParseApk: 'Usage: cresc parseApk <apk file>',
offset: 'Offset {{offset}}',
packageUploadSuccess: 'Successfully uploaded new hot update package (id: {{id}})',
rolloutRangeError: 'rollout must be an integer between 1-100',
nativeVersionNotFound: 'No native version found >= {{version}}',
nativeVersionNotFoundLess: 'No native version found <= {{version}}',
nativeVersionNotFoundMatch: 'No matching native version found: {{version}}',
packageIdRequired: 'Please provide packageId or packageVersion parameter',
operationComplete: 'Operation complete, bound to {{count}} native versions',
platformRequired: 'Platform must be specified.',
bundleCommandError: '"react-native bundle" command exited with code {{code}}.',
copyHarmonyBundleError: 'Error copying Harmony bundle: {{error}}',
copyFileFailed: 'Failed to copy file: {{error}}',
deleteFile: 'Delete {{file}}',
rolloutConfigSet: 'Set {{rollout}}% rollout for version {{version}} on native version(s) {{versions}}',
versionBind: 'Bound version {{version}} to native version {{nativeVersion}} (id: {{id}})',
}; };

View File

@@ -38,4 +38,52 @@ export default {
operationSuccess: '操作成功', operationSuccess: '操作成功',
failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。', failedToParseUpdateJson: '无法解析文件 `update.json`。请手动删除它。',
ppkPackageGenerated: 'ppk 热更包已生成并保存到: {{- output}}', ppkPackageGenerated: 'ppk 热更包已生成并保存到: {{- output}}',
welcomeMessage: '欢迎使用 pushy 热更新服务,{{name}}。',
loggedOut: '已退出登录',
usageUnderDevelopment: '使用说明正在开发中。',
hermesDisabled: 'Hermes 已禁用',
hermesEnabled: 'Hermes 已启用,正在编译为 hermes 字节码:\n',
runningHermesc: '运行 hermesc{{command}} {{args}}',
composingSourceMap: '正在生成 source map',
copyingDebugId: '正在复制 debugid',
sentryCliNotFound: '无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli',
sentryReleaseCreated: '已为版本 {{version}} 创建 Sentry release',
uploadingSourcemap: '正在上传 sourcemap',
packing: '正在打包',
deletingFile: '删除 {{file}}',
bundlingWithRN: '正在使用 react-native {{version}} 打包',
fileGenerated: '已生成 {{file}}。',
processingError: '处理文件时出错:{{error}}',
usageDiff: '用法pushy {{command}} <origin> <next>',
pluginDetected: '检测到 {{name}} 插件',
pluginDetectionError: '检测 {{name}} 插件时出错:{{error}}',
addedToGitignore: '已将 {{line}} 添加到 .gitignore',
processingStringPool: '正在处理字符串池...',
processingPackage: '正在处理包 {{count}}...',
typeStrings: '类型字符串:',
keyStrings: '键字符串:',
failedToParseIcon: '[警告] 解析图标失败:{{error}}',
errorInHarmonyApp: '获取 Harmony 应用入口时出错:{{error}}',
totalPackages: '共 {{count}} 个包',
usageUploadIpa: '使用方法: pushy uploadIpa ipa后缀文件',
usageUploadApk: '使用方法: pushy uploadApk apk后缀文件',
usageUploadApp: '使用方法: pushy uploadApp app后缀文件',
usageParseApp: '使用方法: pushy parseApp app后缀文件',
usageParseIpa: '使用方法: pushy parseIpa ipa后缀文件',
usageParseApk: '使用方法: pushy parseApk apk后缀文件',
offset: '偏移量 {{offset}}',
packageUploadSuccess: '已成功上传新热更包id: {{id}}',
rolloutRangeError: 'rollout 必须是 1-100 的整数',
nativeVersionNotFound: '未查询到 >= {{version}} 的原生版本',
nativeVersionNotFoundLess: '未查询到 <= {{version}} 的原生版本',
nativeVersionNotFoundMatch: '未查询到匹配原生版本:{{version}}',
packageIdRequired: '请提供 packageId 或 packageVersion 参数',
operationComplete: '操作完成,共已绑定 {{count}} 个原生版本',
platformRequired: '必须指定平台。',
bundleCommandError: '"react-native bundle" 命令退出,代码为 {{code}}。',
copyHarmonyBundleError: '复制 Harmony bundle 错误:{{error}}',
copyFileFailed: '复制文件失败:{{error}}',
deleteFile: '删除 {{file}}',
rolloutConfigSet: '已在原生版本 {{versions}} 上设置灰度发布 {{rollout}}% 热更版本 {{version}}',
versionBind: '已将热更版本 {{version}} 绑定到原生版本 {{nativeVersion}} (id: {{id}})',
}; };

View File

@@ -1,5 +1,6 @@
import { get, post, uploadFile } from './api'; import { get, post, uploadFile } from './api';
import { question, saveToLocal } from './utils'; import { question, saveToLocal } from './utils';
import { t } from './utils/i18n';
import { checkPlatform, getSelectedApp } from './app'; import { checkPlatform, getSelectedApp } from './app';
@@ -34,7 +35,7 @@ export async function listPackage(appId: string) {
} }
console.log(Table(header, rows).render()); console.log(Table(header, rows).render());
console.log(`\n共 ${data.length} 个包`); console.log(t('totalPackages', { count: data.length }));
return data; return data;
} }
@@ -54,7 +55,7 @@ export const commands = {
uploadIpa: async ({ args }: { args: string[] }) => { uploadIpa: async ({ args }: { args: string[] }) => {
const fn = args[0]; const fn = args[0];
if (!fn || !fn.endsWith('.ipa')) { if (!fn || !fn.endsWith('.ipa')) {
throw new Error('使用方法: pushy uploadIpa ipa后缀文件'); throw new Error(t('usageUploadIpa'));
} }
const { const {
versionName, versionName,
@@ -93,7 +94,7 @@ export const commands = {
uploadApk: async ({ args }: { args: string[] }) => { uploadApk: async ({ args }: { args: string[] }) => {
const fn = args[0]; const fn = args[0];
if (!fn || !fn.endsWith('.apk')) { if (!fn || !fn.endsWith('.apk')) {
throw new Error('使用方法: pushy uploadApk apk后缀文件'); throw new Error(t('usageUploadApk'));
} }
const { const {
versionName, versionName,
@@ -132,7 +133,7 @@ export const commands = {
uploadApp: async ({ args }: { args: string[] }) => { uploadApp: async ({ args }: { args: string[] }) => {
const fn = args[0]; const fn = args[0];
if (!fn || !fn.endsWith('.app')) { if (!fn || !fn.endsWith('.app')) {
throw new Error('使用方法: pushy uploadApp app后缀文件'); throw new Error(t('usageUploadApp'));
} }
const { const {
versionName, versionName,
@@ -171,21 +172,21 @@ export const commands = {
parseApp: async ({ args }: { args: string[] }) => { parseApp: async ({ args }: { args: string[] }) => {
const fn = args[0]; const fn = args[0];
if (!fn || !fn.endsWith('.app')) { if (!fn || !fn.endsWith('.app')) {
throw new Error('使用方法: pushy parseApp app后缀文件'); throw new Error(t('usageParseApp'));
} }
console.log(await getAppInfo(fn)); console.log(await getAppInfo(fn));
}, },
parseIpa: async ({ args }: { args: string[] }) => { parseIpa: async ({ args }: { args: string[] }) => {
const fn = args[0]; const fn = args[0];
if (!fn || !fn.endsWith('.ipa')) { if (!fn || !fn.endsWith('.ipa')) {
throw new Error('使用方法: pushy parseIpa ipa后缀文件'); throw new Error(t('usageParseIpa'));
} }
console.log(await getIpaInfo(fn)); console.log(await getIpaInfo(fn));
}, },
parseApk: async ({ args }: { args: string[] }) => { parseApk: async ({ args }: { args: string[] }) => {
const fn = args[0]; const fn = args[0];
if (!fn || !fn.endsWith('.apk')) { if (!fn || !fn.endsWith('.apk')) {
throw new Error('使用方法: pushy parseApk apk后缀文件'); throw new Error(t('usageParseApk'));
} }
console.log(await getApkInfo(fn)); console.log(await getApkInfo(fn));
}, },

View File

@@ -1,6 +1,7 @@
import { question } from './utils'; import { question } from './utils';
import { post, get, replaceSession, saveSession, closeSession } from './api'; import { post, get, replaceSession, saveSession, closeSession } from './api';
import crypto from 'node:crypto'; import crypto from 'node:crypto';
import { t } from './utils/i18n';
function md5(str: string) { function md5(str: string) {
return crypto.createHash('md5').update(str).digest('hex'); return crypto.createHash('md5').update(str).digest('hex');
@@ -16,11 +17,11 @@ export const commands = {
}); });
replaceSession({ token }); replaceSession({ token });
await saveSession(); await saveSession();
console.log(`欢迎使用 pushy 热更新服务, ${info.name}.`); console.log(t('welcomeMessage', { name: info.name }));
}, },
logout: async () => { logout: async () => {
await closeSession(); await closeSession();
console.log('已退出登录'); console.log(t('loggedOut'));
}, },
me: async () => { me: async () => {
const me = await get('/user/me'); const me = await get('/user/me');

View File

@@ -1,6 +1,7 @@
import fs from 'node:fs'; import fs from 'node:fs';
// import path from 'node:path'; // import path from 'node:path';
import { credentialFile, tempDir } from './constants'; import { credentialFile, tempDir } from './constants';
import { t } from './i18n';
export function addGitIgnore() { export function addGitIgnore() {
const shouldIgnore = [credentialFile, tempDir]; const shouldIgnore = [credentialFile, tempDir];
@@ -26,7 +27,7 @@ export function addGitIgnore() {
gitignoreLines.push('# react-native-update'); gitignoreLines.push('# react-native-update');
for (const line of shouldIgnore) { for (const line of shouldIgnore) {
gitignoreLines.push(line); gitignoreLines.push(line);
console.log(`Added ${line} to .gitignore`); console.log(t('addedToGitignore', { line }));
} }
fs.writeFileSync(gitignorePath, gitignoreLines.join('\n')); fs.writeFileSync(gitignorePath, gitignoreLines.join('\n'));

View File

@@ -1,4 +1,5 @@
import { plugins } from './plugin-config'; import { plugins } from './plugin-config';
import { t } from './i18n';
interface BundleParams { interface BundleParams {
sentry: boolean; sentry: boolean;
@@ -17,10 +18,10 @@ export async function checkPlugins(): Promise<BundleParams> {
const isEnabled = await plugin.detect(); const isEnabled = await plugin.detect();
if (isEnabled && plugin.bundleParams) { if (isEnabled && plugin.bundleParams) {
Object.assign(params, plugin.bundleParams); Object.assign(params, plugin.bundleParams);
console.log(`detected ${plugin.name} plugin`); console.log(t('pluginDetected', { name: plugin.name }));
} }
} catch (err) { } catch (err) {
console.warn(`error while detecting ${plugin.name} plugin:`, err); console.warn(t('pluginDetectionError', { name: plugin.name, error: err }));
} }
} }

View File

@@ -1,5 +1,6 @@
import { get, post, put, uploadFile } from './api'; import { get, post, put, uploadFile } from './api';
import { question, saveToLocal } from './utils'; import { question, saveToLocal } from './utils';
import { t } from './utils/i18n';
import { checkPlatform, getSelectedApp } from './app'; import { checkPlatform, getSelectedApp } from './app';
import { choosePackage } from './package'; import { choosePackage } from './package';
@@ -35,7 +36,7 @@ interface CommandOptions {
async function showVersion(appId: string, offset: number) { async function showVersion(appId: string, offset: number) {
const { data, count } = await get(`/app/${appId}/version/list`); const { data, count } = await get(`/app/${appId}/version/list`);
console.log(`Offset ${offset}`); console.log(t('offset', { offset }));
for (const version of data) { for (const version of data) {
const pkgCount = version.packages?.length || 0; const pkgCount = version.packages?.length || 0;
let packageInfo = ''; let packageInfo = '';
@@ -149,7 +150,7 @@ export const commands = {
}); });
// TODO local diff // TODO local diff
saveToLocal(fn, `${appId}/ppk/${id}.ppk`); saveToLocal(fn, `${appId}/ppk/${id}.ppk`);
console.log(`已成功上传新热更包id: ${id}`); console.log(t('packageUploadSuccess', { id }));
const v = await question('是否现在将此热更应用到原生包上?(Y/N)'); const v = await question('是否现在将此热更应用到原生包上?(Y/N)');
if (v.toLowerCase() === 'y') { if (v.toLowerCase() === 'y') {
@@ -192,10 +193,10 @@ export const commands = {
try { try {
rollout = Number.parseInt(options.rollout); rollout = Number.parseInt(options.rollout);
} catch (e) { } catch (e) {
throw new Error('rollout 必须是 1-100 的整数'); throw new Error(t('rolloutRangeError'));
} }
if (rollout < 1 || rollout > 100) { if (rollout < 1 || rollout > 100) {
throw new Error('rollout 必须是 1-100 的整数'); throw new Error(t('rolloutRangeError'));
} }
} }
@@ -206,7 +207,7 @@ export const commands = {
compare(pkg.name, minPkgVersion, '>='), compare(pkg.name, minPkgVersion, '>='),
); );
if (pkgs.length === 0) { if (pkgs.length === 0) {
throw new Error(`未查询到 >= ${minPkgVersion} 的原生版本`); throw new Error(t('nativeVersionNotFound', { version: minPkgVersion }));
} }
if (rollout !== undefined) { if (rollout !== undefined) {
const rolloutConfig: Record<string, number> = {}; const rolloutConfig: Record<string, number> = {};
@@ -219,9 +220,10 @@ export const commands = {
}, },
}); });
console.log( console.log(
`已在原生版本 ${pkgs `${t('rolloutConfigSet', {
.map((pkg: Package) => pkg.name) versions: pkgs.map((pkg: Package) => pkg.name).join(', '),
.join(', ')} 上设置灰度发布 ${rollout}% 热更版本 ${versionId}`, rollout: rollout,
})}`,
); );
} }
for (const pkg of pkgs) { for (const pkg of pkgs) {
@@ -229,10 +231,14 @@ export const commands = {
versionId, versionId,
}); });
console.log( console.log(
`已将热更版本 ${versionId} 绑定到原生版本 ${pkg.name} (id: ${pkg.id})`, `${t('versionBind', {
version: versionId,
nativeVersion: pkg.name,
id: pkg.id,
})}`,
); );
} }
console.log(`操作完成,共已绑定 ${pkgs.length} 个原生版本`); console.log(t('operationComplete', { count: pkgs.length }));
return; return;
} }
if (maxPkgVersion) { if (maxPkgVersion) {
@@ -242,7 +248,7 @@ export const commands = {
compare(pkg.name, maxPkgVersion, '<='), compare(pkg.name, maxPkgVersion, '<='),
); );
if (pkgs.length === 0) { if (pkgs.length === 0) {
throw new Error(`未查询到 <= ${maxPkgVersion} 的原生版本`); throw new Error(t('nativeVersionNotFoundLess', { version: maxPkgVersion }));
} }
if (rollout !== undefined) { if (rollout !== undefined) {
const rolloutConfig: Record<string, number> = {}; const rolloutConfig: Record<string, number> = {};
@@ -255,9 +261,10 @@ export const commands = {
}, },
}); });
console.log( console.log(
`已在原生版本 ${pkgs `${t('rolloutConfigSet', {
.map((pkg: Package) => pkg.name) versions: pkgs.map((pkg: Package) => pkg.name).join(', '),
.join(', ')} 上设置灰度发布 ${rollout}% 热更版本 ${versionId}`, rollout: rollout,
})}`,
); );
} }
for (const pkg of pkgs) { for (const pkg of pkgs) {
@@ -265,10 +272,14 @@ export const commands = {
versionId, versionId,
}); });
console.log( console.log(
`已将热更版本 ${versionId} 绑定到原生版本 ${pkg.name} (id: ${pkg.id})`, `${t('versionBind', {
version: versionId,
nativeVersion: pkg.name,
id: pkg.id,
})}`,
); );
} }
console.log(`操作完成,共已绑定 ${pkgs.length} 个原生版本`); console.log(t('operationComplete', { count: pkgs.length }));
return; return;
} }
@@ -279,7 +290,7 @@ export const commands = {
if (pkg) { if (pkg) {
pkgId = pkg.id; pkgId = pkg.id;
} else { } else {
throw new Error(`未查询到匹配原生版本:${pkgVersion}`); throw new Error(t('nativeVersionNotFoundMatch', { version: pkgVersion }));
} }
} }
if (!pkgId) { if (!pkgId) {
@@ -287,7 +298,7 @@ export const commands = {
} }
if (!pkgId) { if (!pkgId) {
throw new Error('请提供 packageId 或 packageVersion 参数'); throw new Error(t('packageIdRequired'));
} }
if (!pkgVersion) { if (!pkgVersion) {
@@ -306,7 +317,10 @@ export const commands = {
}, },
}); });
console.log( console.log(
`已将在原生版本 ${pkgVersion} (id: ${pkgId}) 上设置灰度发布 ${rollout}% 热更版本 ${versionId} `, `${t('rolloutConfigSet', {
versions: pkgVersion,
rollout: rollout,
})}`,
); );
} }
@@ -315,9 +329,14 @@ export const commands = {
versionId, versionId,
}); });
console.log( console.log(
`已将热更版本 ${versionId} 绑定到原生版本 ${pkgVersion} (id: ${pkgId})`, `${t('versionBind', {
version: versionId,
nativeVersion: pkgVersion,
id: pkgId,
})}`,
); );
} }
console.log(t('operationSuccess'));
}, },
updateVersionInfo: async ({ updateVersionInfo: async ({
args, args,
@@ -339,6 +358,6 @@ export const commands = {
if (options.metaInfo) updateParams.metaInfo = options.metaInfo; if (options.metaInfo) updateParams.metaInfo = options.metaInfo;
await put(`/app/${appId}/version/${versionId}`, updateParams); await put(`/app/${appId}/version/${versionId}`, updateParams);
console.log('操作成功'); console.log(t('operationSuccess'));
}, },
}; };