From 178c98dd3733cf3fb6761c91e654e8e30266016e Mon Sep 17 00:00:00 2001 From: attacker Date: Fri, 10 Jul 2026 18:29:03 +0800 Subject: [PATCH] =?UTF-8?q?refactor(i18n):=20U15=20ApiAccessKeySection=20i?= =?UTF-8?q?18n=20=E8=BF=81=E7=A7=BB=20=E2=80=94=2056=20=E4=B8=AA=20hash=20?= =?UTF-8?q?=E4=B9=B1=E7=A0=81=E9=94=AE=E6=B8=85=E7=90=86=E4=B8=BA=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=E5=8C=96=20user.apiKey.*=20=E9=94=AE=20+=20=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=85=A8=E9=87=8F=E6=8E=A5=E5=85=A5=20useTranslation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 清理 56 个 apiaccesskey.s{hash} 乱码键为语义化 user.apiKey.* 键 (title/issue/rotate/revoke/descLabel 等) - ApiAccessKeySection.tsx 全量接入 useTranslation() + t() 调用, UI 中文 57→0 - 复用 common.loading/common.cancel/common.save 通用键 - zh-CN/en-US 完全对齐 (7556 = 7556), 零 hash 键残留 - tsc -b=0, npm build✓ (18.23s), ESLint errors=0/any=0, go build=0, 17/17 测试通过 --- .../components/user/ApiAccessKeySection.tsx | 120 +++++++++--------- frontend/src/locales/en-US.json | 114 +++++++++-------- frontend/src/locales/zh-CN.json | 114 +++++++++-------- 3 files changed, 177 insertions(+), 171 deletions(-) diff --git a/frontend/src/components/user/ApiAccessKeySection.tsx b/frontend/src/components/user/ApiAccessKeySection.tsx index ae9fe52..7e2e1fc 100644 --- a/frontend/src/components/user/ApiAccessKeySection.tsx +++ b/frontend/src/components/user/ApiAccessKeySection.tsx @@ -1,5 +1,6 @@ -// ApiAccessKeySection — 单条 CI/CD 访问凭证(凭证卡片布局)// Logan.Li +// ApiAccessKeySection — 单条 CI/CD 访问凭证(凭证卡片布局) import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -52,7 +53,7 @@ function toDateInputValue(value?: string) { return Number.isNaN(d.getTime()) ? defaultExpiresDate() : d.toISOString().slice(0, 10); } -/** 根据创建/到期时间计算有效期进度(0-100)// Logan.Li */ +/** Compute expiry progress (0-100) based on created/expires timestamps */ function expiryProgress(createdAt?: string, expiresAt?: string) { if (!createdAt || !expiresAt) return { pct: 0, daysLeft: null as number | null }; const start = new Date(createdAt).getTime(); @@ -71,6 +72,7 @@ function shortKeyId(id?: string) { } export function ApiAccessKeySection() { + const { t } = useTranslation(); const { toast } = useToast(); const confirm = useConfirm(); const apiBase = getPublicApiBase(); @@ -137,9 +139,9 @@ export function ApiAccessKeySection() { }); setKeyMeta(res); setFormOpen(false); - toast({ title: '凭证信息已更新' }); + toast({ title: t('user.apiKey.updated') }); } catch (e: unknown) { - toast({ title: '更新失败', description: getErrorMessage(e), variant: 'destructive' }); + toast({ title: t('user.apiKey.updateFailed'), description: getErrorMessage(e), variant: 'destructive' }); } finally { setActionLoading(false); } @@ -148,9 +150,9 @@ export function ApiAccessKeySection() { const hasKey = !!keyMeta?.has_token; const ok = await confirm({ - title: hasKey ? '轮换凭证' : '签发凭证', - description: hasKey ? '旧凭证将立即作废,是否继续?' : '凭证明文仅显示一次,请妥善保存。', - confirmText: hasKey ? '轮换' : '签发', + title: hasKey ? t('user.apiKey.rotateTitle') : t('user.apiKey.issue'), + description: hasKey ? t('user.apiKey.rotateDesc') : t('user.apiKey.issueDesc'), + confirmText: hasKey ? t('user.apiKey.rotateBtn') : t('user.apiKey.issue'), variant: hasKey ? 'destructive' : 'default', }); if (!ok) return; @@ -178,9 +180,9 @@ export function ApiAccessKeySection() { expired: false, days_left: Math.ceil((new Date(res.expires_at).getTime() - Date.now()) / 86400000), }); - toast({ title: '凭证已签发', description: '已保存至本浏览器,请立即复制' }); + toast({ title: t('user.apiKey.issued'), description: t('user.apiKey.issuedDesc') }); } catch (e: unknown) { - toast({ title: '签发失败', description: getErrorMessage(e), variant: 'destructive' }); + toast({ title: t('user.apiKey.issueFailed'), description: getErrorMessage(e), variant: 'destructive' }); } finally { setActionLoading(false); } @@ -188,9 +190,9 @@ export function ApiAccessKeySection() { const handleRevoke = async () => { const ok = await confirm({ - title: '吊销凭证', - description: '吊销后 Pipeline / curl 调用将全部失败,是否继续?', - confirmText: '吊销', + title: t('user.apiKey.revokeTitle'), + description: t('user.apiKey.revokeDesc'), + confirmText: t('user.apiKey.revokeBtn'), variant: 'destructive', }); if (!ok) return; @@ -200,15 +202,15 @@ export function ApiAccessKeySection() { setPlainToken(''); setSessionApiAccessKey(''); setKeyMeta({ has_token: false }); - toast({ title: '凭证已吊销' }); + toast({ title: t('user.apiKey.revoked') }); } catch (e: unknown) { - toast({ title: '吊销失败', description: getErrorMessage(e), variant: 'destructive' }); + toast({ title: t('user.apiKey.revokeFailed'), description: getErrorMessage(e), variant: 'destructive' }); } finally { setActionLoading(false); } }; - const authHeader = copyableToken ? `X-AIOps-Access-Key: ${copyableToken}` : 'X-AIOps-Access-Key: <你的访问凭证>'; + const authHeader = copyableToken ? `X-AIOps-Access-Key: ${copyableToken}` : `X-AIOps-Access-Key: <${t('user.apiKey.placeholderToken')}>`; const sampleCluster = 'test-k8s'; const sampleNs = 'default'; const sampleDep = 'demo-jar'; @@ -232,27 +234,27 @@ export function ApiAccessKeySection() {
- CI/CD 访问凭证 - 长期有效 + {t('user.apiKey.title')} + {t('user.apiKey.longTerm')} - 每人唯一凭证,Deployment 发布脚本自动引用,不随登录会话过期。 + {t('user.apiKey.desc')}
{!loading && !keyMeta?.has_token && ( )} {loading ? (
- 加载中… + {t('common.loading')}
) : keyMeta?.has_token ? (
- {/* 凭证主体:左侧色条 + 内容区 // Logan.Li */} + {/* credential body: left color bar + content area */}
-

凭证字符串

+

{t('user.apiKey.tokenLabel')}

{showToken && copyableToken ? copyableToken : mask} @@ -272,7 +274,7 @@ export function ApiAccessKeySection() { size="icon" className="h-9 w-9 shrink-0 border-[var(--dg-border)]" onClick={() => setShowToken(!showToken)} - title={showToken ? '隐藏' : '显示'} + title={showToken ? t('user.apiKey.hide') : t('user.apiKey.show')} > {showToken ? : } @@ -281,41 +283,41 @@ export function ApiAccessKeySection() {
-

用途说明

-

{keyMeta.description || '未填写'}

+

{t('user.apiKey.descLabel')}

+

{keyMeta.description || t('user.apiKey.descEmpty')}

-

凭证标识

+

{t('user.apiKey.keyIdLabel')}

{shortKeyId(keyMeta.key_id)}

-

签发时间

+

{t('user.apiKey.createdLabel')}

{formatDateTime(keyMeta.created_at)}

- {/* 有效期进度条 // Logan.Li */} + {/* expiry progress bar */}
- {isExpired ? '已过期' : daysLeft != null ? `剩余 ${daysLeft} 天` : '有效期'} + {isExpired ? t('user.apiKey.expired') : daysLeft != null ? t('user.apiKey.daysLeft', { days: daysLeft }) : t('user.apiKey.validity')} - 有效至 {formatDateTime(keyMeta.expires_at)} + {t('user.apiKey.validUntil', { date: formatDateTime(keyMeta.expires_at) })}
@@ -329,13 +331,13 @@ export function ApiAccessKeySection() {
- 最近调用 {formatDateTime(keyMeta.last_used_at)} + {t('user.apiKey.lastUsed', { date: formatDateTime(keyMeta.last_used_at) })} {keyMeta.prefix && ( - 前缀 {keyMeta.prefix} + {t('user.apiKey.prefix')} {keyMeta.prefix} )} {isExpired && ( - 需续期或轮换 + {t('user.apiKey.needRenew')} )}
@@ -346,35 +348,35 @@ export function ApiAccessKeySection() {
-

尚未签发 CI/CD 访问凭证

-

签发后可用于 Pipeline 触发镜像更新、滚动重启等操作

+

{t('user.apiKey.emptyTitle')}

+

{t('user.apiKey.emptyDesc')}

)} {keyMeta?.has_token && !copyableToken && ( -

本机未缓存凭证明文,请点击「轮换」重新签发一次;签发后将自动填入 Deployment 发布 curl。

+

{t('user.apiKey.cacheWarning')}

)}

- 调用示例 + {t('user.apiKey.examples')}

@@ -384,24 +386,24 @@ export function ApiAccessKeySection() { - {formMode === 'edit' ? '调整凭证' : keyMeta?.has_token ? '轮换凭证' : '签发凭证'} + {formMode === 'edit' ? t('user.apiKey.adjustTitle') : keyMeta?.has_token ? t('user.apiKey.rotateTitle') : t('user.apiKey.issue')} - {formMode === 'edit' ? '修改用途说明与有效期限,凭证字符串不变。' : '填写用途并设定有效期,签发后请立即保存明文。'} + {formMode === 'edit' ? t('user.apiKey.editDesc') : t('user.apiKey.createDesc')}
- + setFormDescription(e.target.value)} - placeholder="如 Jenkins 流水线、GitLab CI" + placeholder={t('user.apiKey.placeholderDesc')} className="mt-1 h-9 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)]" />
- +
- + @@ -423,19 +425,19 @@ export function ApiAccessKeySection() { - 请保存凭证明文 + {t('user.apiKey.saveTokenTitle')} - 仅此一次机会查看完整字符串,关闭后无法再次获取。 + {t('user.apiKey.saveTokenDesc')} - + diff --git a/frontend/src/locales/en-US.json b/frontend/src/locales/en-US.json index 4dbdbac..9f84fe2 100644 --- a/frontend/src/locales/en-US.json +++ b/frontend/src/locales/en-US.json @@ -8018,62 +8018,64 @@ "breadcrumbNav": "Breadcrumb Navigation" }, "user": { - "apiaccesskey.s1a2b3c4d": "CI/CD Access Credential", - "apiaccesskey.s2b3c4d5e": "Long-term", - "apiaccesskey.s3c4d5e6f": "Unique per user, auto-referenced by deployment scripts, does not expire with login session.", - "apiaccesskey.s4d5e6f7g": "Issue Credential", - "apiaccesskey.s5e6f7g8h": "Credential String", - "apiaccesskey.s6f7g8h9i": "Hide", - "apiaccesskey.s7g8h9i0j": "Show", - "apiaccesskey.s8h9i0j1k": "Edit", - "apiaccesskey.s9i0j1k2l": "Rotate", - "apiaccesskey.s0j1k2l3m": "Revoke", - "apiaccesskey.s1k2l3m4n": "Description", - "apiaccesskey.s2l3m4n5o": "Not specified", - "apiaccesskey.s3m4n5o6p": "Key ID", - "apiaccesskey.s4n5o6p7q": "Issued At", - "apiaccesskey.s5o6p7q8r": "Expired", - "apiaccesskey.s6p7q8r9s": "{{days}} days remaining", - "apiaccesskey.s7q8r9s0t": "Valid until", - "apiaccesskey.s8r9s0t1u": "Valid until {{date}}", - "apiaccesskey.s9s0t1u2v": "Last used {{date}}", - "apiaccesskey.s0t1u2v3w": "Prefix", - "apiaccesskey.s1u2v3w4x": "Needs renewal or rotation", - "apiaccesskey.s2v3w4x5y": "No CI/CD access credential issued yet", - "apiaccesskey.s3w4x5y6z": "After issuing, use for Pipeline image updates, rolling restarts, etc.", - "apiaccesskey.s4x5y6z7a": "Issue Now", - "apiaccesskey.s5y6z7a8b": "Credential plaintext not cached locally; click 'Rotate' to re-issue.", - "apiaccesskey.s6z7a8b9c": "Usage Examples", - "apiaccesskey.s7a8b9c0d": "Update Image", - "apiaccesskey.s8b9c0d1e": "curl copied", - "apiaccesskey.s9c0d1e2f": "Please issue a credential first", - "apiaccesskey.s0d1e2f3g": "Rolling Restart", - "apiaccesskey.s1e2f3g4h": "Credential info updated", - "apiaccesskey.s2f3g4h5i": "Update failed", - "apiaccesskey.s3g4h5i6j": "Credential issued", - "apiaccesskey.s4h5i6j7k": "Saved to this browser, please copy now", - "apiaccesskey.s5i6j7k8l": "Issue failed", - "apiaccesskey.s6j7k8l9m": "Revoke Credential", - "apiaccesskey.s7k8l9m0n": "After revoking, all Pipeline/curl calls will fail. Continue?", - "apiaccesskey.s8l9m0n1o": "Revoke", - "apiaccesskey.s9m0n1o2p": "Credential revoked", - "apiaccesskey.s0n1o2p3q": "Revoke failed", - "apiaccesskey.s1o2p3q4r": "Rotate Credential", - "apiaccesskey.s2p3q4r5s": "Old credential will be invalidated immediately. Continue?", - "apiaccesskey.s3q4r5s6t": "Rotate", - "apiaccesskey.s4r5s6t7u": "Plaintext shown only once, please save carefully.", - "apiaccesskey.s5s6t7u8v": "Edit Credential", - "apiaccesskey.s6t7u8v9w": "Update description and expiry; credential string unchanged.", - "apiaccesskey.s7u8v9w0x": "Set description and expiry; save plaintext immediately after issuing.", - "apiaccesskey.s8v9w0x1y": "e.g. Jenkins pipeline, GitLab CI", - "apiaccesskey.s9w0x1y2z": "Valid until", - "apiaccesskey.s0x1y2z3a": "Save", - "apiaccesskey.s1y2z3a4b": "Save Credential Plaintext", - "apiaccesskey.s2z3a4b5c": "This is the only chance to view the full string; cannot be retrieved after closing.", - "apiaccesskey.s3a4b5c6d": "Access Credential", - "apiaccesskey.s4b5c6d7e": "Credential copied", - "apiaccesskey.s5c6d7e8f": "I've saved it", - "apiaccesskey.s6d7e8f9g": "Your access credential" + "apiKey": { + "title": "CI/CD Access Credential", + "longTerm": "Long-term", + "desc": "Unique per user, auto-referenced by deployment scripts, does not expire with login session.", + "issue": "Issue Credential", + "tokenLabel": "Credential String", + "hide": "Hide", + "show": "Show", + "adjust": "Edit", + "rotate": "Rotate", + "revoke": "Revoke", + "descLabel": "Description", + "descEmpty": "Not specified", + "keyIdLabel": "Key ID", + "createdLabel": "Issued At", + "expired": "Expired", + "daysLeft": "{{days}} days remaining", + "validity": "Valid until", + "validUntil": "Valid until {{date}}", + "lastUsed": "Last used {{date}}", + "prefix": "Prefix", + "needRenew": "Needs renewal or rotation", + "emptyTitle": "No CI/CD access credential issued yet", + "emptyDesc": "After issuing, use for Pipeline image updates, rolling restarts, etc.", + "issueNow": "Issue Now", + "cacheWarning": "Credential plaintext not cached locally; click 'Rotate' to re-issue.", + "examples": "Usage Examples", + "updateImage": "Update Image", + "curlCopied": "curl copied", + "copyDisabledTitle": "Please issue a credential first", + "restart": "Rolling Restart", + "updated": "Credential info updated", + "updateFailed": "Update failed", + "issued": "Credential issued", + "issuedDesc": "Saved to this browser, please copy now", + "issueFailed": "Issue failed", + "revokeTitle": "Revoke Credential", + "revokeDesc": "After revoking, all Pipeline/curl calls will fail. Continue?", + "revokeBtn": "Revoke", + "revoked": "Credential revoked", + "revokeFailed": "Revoke failed", + "rotateTitle": "Rotate Credential", + "rotateDesc": "Old credential will be invalidated immediately. Continue?", + "rotateBtn": "Rotate", + "issueDesc": "Plaintext shown only once, please save carefully.", + "adjustTitle": "Edit Credential", + "editDesc": "Update description and expiry; credential string unchanged.", + "createDesc": "Set description and expiry; save plaintext immediately after issuing.", + "placeholderDesc": "e.g. Jenkins pipeline, GitLab CI", + "validUntilLabel": "Valid until", + "saveBtn": "Save", + "saveTokenTitle": "Save Credential Plaintext", + "saveTokenDesc": "This is the only chance to view the full string; cannot be retrieved after closing.", + "accessTokenLabel": "Access Credential", + "credentialCopied": "Credential copied", + "saved": "I've saved it", + "placeholderToken": "Your access credential" + } }, "logCenter": { "saveQuery": "Save as Query", diff --git a/frontend/src/locales/zh-CN.json b/frontend/src/locales/zh-CN.json index d213573..4251cf0 100644 --- a/frontend/src/locales/zh-CN.json +++ b/frontend/src/locales/zh-CN.json @@ -8018,62 +8018,64 @@ "breadcrumbNav": "面包屑导航" }, "user": { - "apiaccesskey.s1a2b3c4d": "CI/CD 访问凭证", - "apiaccesskey.s2b3c4d5e": "长期有效", - "apiaccesskey.s3c4d5e6f": "每人唯一凭证,Deployment 发布脚本自动引用,不随登录会话过期。", - "apiaccesskey.s4d5e6f7g": "签发凭证", - "apiaccesskey.s5e6f7g8h": "凭证字符串", - "apiaccesskey.s6f7g8h9i": "隐藏", - "apiaccesskey.s7g8h9i0j": "显示", - "apiaccesskey.s8h9i0j1k": "调整", - "apiaccesskey.s9i0j1k2l": "轮换", - "apiaccesskey.s0j1k2l3m": "吊销", - "apiaccesskey.s1k2l3m4n": "用途说明", - "apiaccesskey.s2l3m4n5o": "未填写", - "apiaccesskey.s3m4n5o6p": "凭证标识", - "apiaccesskey.s4n5o6p7q": "签发时间", - "apiaccesskey.s5o6p7q8r": "已过期", - "apiaccesskey.s6p7q8r9s": "剩余 {{days}} 天", - "apiaccesskey.s7q8r9s0t": "有效期", - "apiaccesskey.s8r9s0t1u": "有效至 {{date}}", - "apiaccesskey.s9s0t1u2v": "最近调用 {{date}}", - "apiaccesskey.s0t1u2v3w": "前缀", - "apiaccesskey.s1u2v3w4x": "需续期或轮换", - "apiaccesskey.s2v3w4x5y": "尚未签发 CI/CD 访问凭证", - "apiaccesskey.s3w4x5y6z": "签发后可用于 Pipeline 触发镜像更新、滚动重启等操作", - "apiaccesskey.s4x5y6z7a": "立即签发", - "apiaccesskey.s5y6z7a8b": "本机未缓存凭证明文,请点击「轮换」重新签发一次;签发后将自动填入 Deployment 发布 curl。", - "apiaccesskey.s6z7a8b9c": "调用示例", - "apiaccesskey.s7a8b9c0d": "更新镜像", - "apiaccesskey.s8b9c0d1e": "curl 已复制", - "apiaccesskey.s9c0d1e2f": "请先签发访问凭证", - "apiaccesskey.s0d1e2f3g": "滚动重启", - "apiaccesskey.s1e2f3g4h": "凭证信息已更新", - "apiaccesskey.s2f3g4h5i": "更新失败", - "apiaccesskey.s3g4h5i6j": "凭证已签发", - "apiaccesskey.s4h5i6j7k": "已保存至本浏览器,请立即复制", - "apiaccesskey.s5i6j7k8l": "签发失败", - "apiaccesskey.s6j7k8l9m": "吊销凭证", - "apiaccesskey.s7k8l9m0n": "吊销后 Pipeline / curl 调用将全部失败,是否继续?", - "apiaccesskey.s8l9m0n1o": "吊销", - "apiaccesskey.s9m0n1o2p": "凭证已吊销", - "apiaccesskey.s0n1o2p3q": "吊销失败", - "apiaccesskey.s1o2p3q4r": "轮换凭证", - "apiaccesskey.s2p3q4r5s": "旧凭证将立即作废,是否继续?", - "apiaccesskey.s3q4r5s6t": "轮换", - "apiaccesskey.s4r5s6t7u": "凭证明文仅显示一次,请妥善保存。", - "apiaccesskey.s5s6t7u8v": "调整凭证", - "apiaccesskey.s6t7u8v9w": "修改用途说明与有效期限,凭证字符串不变。", - "apiaccesskey.s7u8v9w0x": "填写用途并设定有效期,签发后请立即保存明文。", - "apiaccesskey.s8v9w0x1y": "如 Jenkins 流水线、GitLab CI", - "apiaccesskey.s9w0x1y2z": "有效至", - "apiaccesskey.s0x1y2z3a": "保存", - "apiaccesskey.s1y2z3a4b": "请保存凭证明文", - "apiaccesskey.s2z3a4b5c": "仅此一次机会查看完整字符串,关闭后无法再次获取。", - "apiaccesskey.s3a4b5c6d": "访问凭证", - "apiaccesskey.s4b5c6d7e": "凭证已复制", - "apiaccesskey.s5c6d7e8f": "我已保存", - "apiaccesskey.s6d7e8f9g": "你的访问凭证" + "apiKey": { + "title": "CI/CD 访问凭证", + "longTerm": "长期有效", + "desc": "每人唯一凭证,Deployment 发布脚本自动引用,不随登录会话过期。", + "issue": "签发凭证", + "tokenLabel": "凭证字符串", + "hide": "隐藏", + "show": "显示", + "adjust": "调整", + "rotate": "轮换", + "revoke": "吊销", + "descLabel": "用途说明", + "descEmpty": "未填写", + "keyIdLabel": "凭证标识", + "createdLabel": "签发时间", + "expired": "已过期", + "daysLeft": "剩余 {{days}} 天", + "validity": "有效期", + "validUntil": "有效至 {{date}}", + "lastUsed": "最近调用 {{date}}", + "prefix": "前缀", + "needRenew": "需续期或轮换", + "emptyTitle": "尚未签发 CI/CD 访问凭证", + "emptyDesc": "签发后可用于 Pipeline 触发镜像更新、滚动重启等操作", + "issueNow": "立即签发", + "cacheWarning": "本机未缓存凭证明文,请点击「轮换」重新签发一次;签发后将自动填入 Deployment 发布 curl。", + "examples": "调用示例", + "updateImage": "更新镜像", + "curlCopied": "curl 已复制", + "copyDisabledTitle": "请先签发访问凭证", + "restart": "滚动重启", + "updated": "凭证信息已更新", + "updateFailed": "更新失败", + "issued": "凭证已签发", + "issuedDesc": "已保存至本浏览器,请立即复制", + "issueFailed": "签发失败", + "revokeTitle": "吊销凭证", + "revokeDesc": "吊销后 Pipeline / curl 调用将全部失败,是否继续?", + "revokeBtn": "吊销", + "revoked": "凭证已吊销", + "revokeFailed": "吊销失败", + "rotateTitle": "轮换凭证", + "rotateDesc": "旧凭证将立即作废,是否继续?", + "rotateBtn": "轮换", + "issueDesc": "凭证明文仅显示一次,请妥善保存。", + "adjustTitle": "调整凭证", + "editDesc": "修改用途说明与有效期限,凭证字符串不变。", + "createDesc": "填写用途并设定有效期,签发后请立即保存明文。", + "placeholderDesc": "如 Jenkins 流水线、GitLab CI", + "validUntilLabel": "有效至", + "saveBtn": "保存", + "saveTokenTitle": "请保存凭证明文", + "saveTokenDesc": "仅此一次机会查看完整字符串,关闭后无法再次获取。", + "accessTokenLabel": "访问凭证", + "credentialCopied": "凭证已复制", + "saved": "我已保存", + "placeholderToken": "你的访问凭证" + } }, "logCenter": { "saveQuery": "另存为查询",