Files
geo/apps/admin-web/src/i18n/messages/en-US.ts
T
root 9d6181260a
Desktop Client Build / Resolve Build Metadata (push) Successful in 43s
Frontend CI / Frontend (push) Successful in 3m49s
Backend CI / Backend (push) Failing after 7m10s
Desktop Client Build / Build Desktop Client (push) Successful in 23m4s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 28s
feat(media-supply): add media resource supply marketplace
Introduce an end-to-end media-supply feature: tenant-side resource sync
service/worker backed by a Meijiequan supplier client, ops-side management
APIs, and admin/ops web views for resources, orders, favorites and
submission. Adds a shared digitocr helper, MediaSupply config blocks for
tenant and ops, shared types, and migrations for supplier media resources,
price overrides, customer visibility and order refunds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 23:17:01 +08:00

1830 lines
72 KiB
TypeScript

const enUS = {
app: {
name: 'GEO Console',
loginIntro: 'A workspace for brand assets and GEO content operations.',
},
locale: {
'zh-CN': 'Simplified Chinese',
'en-US': 'English',
},
common: {
cancel: 'Cancel',
close: 'Close',
confirm: 'Confirm',
create: 'Create',
edit: 'Edit',
delete: 'Delete',
reset: 'Reset',
refresh: 'Refresh',
loading: 'Loading',
search: 'Search',
save: 'Save',
back: 'Back',
next: 'Next',
previous: 'Previous',
submit: 'Submit',
submitGenerate: 'Generate',
actions: 'Actions',
title: 'Title',
name: 'Name',
description: 'Description',
website: 'Website',
wordCount: 'Words',
createdAt: 'Created At',
updatedAt: 'Updated At',
status: 'Status',
required: 'Required',
noData: 'No data',
optional: 'Optional',
preview: 'Preview',
details: 'Details',
versions: 'Versions',
total: 'Total',
balance: 'Balance',
used: 'Used',
source: 'Source',
templateType: 'Template',
generateStatus: 'Generation',
publishStatus: 'Publish',
selectPlease: 'Please select',
inputPlease: 'Please input',
upgrade: 'Upgrade',
copy: 'Copy',
copySuccess: 'Content copied',
regenerate: 'Regenerate',
regenerateConfirm: 'Regenerate this article?',
regenerateSuccess: 'Regeneration queued',
regenerateError: 'Regeneration failed, please try again',
yes: 'Yes',
no: 'No',
imageUploadProgress: {
title: 'Processing image',
stages: {
idle: 'Waiting to start',
validating: 'Validating file',
decoding: 'Decoding image',
encoding: 'Converting to WebP',
uploading: 'Uploading to server',
finishing: 'Finishing',
},
},
},
nav: {
workspace: 'Workspace',
articleCreation: 'Article Creation',
templates: 'Templates',
custom: 'Custom Generation',
freeCreate: 'Free Create',
imitation: 'Imitation Create',
media: 'Media',
publishManagement: 'Publish Management',
brandManagement: 'Brand Management',
tracking: 'Tracking',
trackingDetail: 'Data Details',
contentManagement: 'Content Management',
knowledge: 'Knowledge Base',
images: 'Image Management',
kolMarket: 'Refined Template Marketplace',
kolMarketplace: 'Refined Template Marketplace',
kolWorkspace: 'KOL Workspace',
kolManage: 'Prompt Management',
kolDashboard: 'Dashboard',
kolProfile: 'Profile',
authorityMedia: 'Authority News Media',
mediaSupplyResources: 'Single Submission Media',
mediaSupplyOrders: 'Submission Records',
mediaSupplyFavorites: 'Frequent Media',
personalCenter: 'Personal Center',
aiPointUsage: 'AI Point Usage',
},
auth: {
welcomeBack: 'Welcome back',
loginAndEnter: 'Sign in to workspace',
email: 'Email',
loginIdentifier: 'Phone / Email',
password: 'Password',
rememberAccount: 'Remember account and password',
forgotPassword: 'Forgot password',
},
membershipBlocked: {
eyebrow: 'Access Paused',
title: 'This tenant plan is unavailable',
expiredMessage: 'Membership expired. Please renew or contact support.',
userDisabledMessage: 'User has been disabled. Please contact support.',
reasonUserDisabled:
'This user has been disabled. Business pages are now locked. Please contact support to restore access.',
reasonTrialExpired:
"The free trial's 3-day page access window has ended. All business pages are now locked. Please contact an administrator to reactivate trial access.",
reasonRequired:
'This tenant does not have an active plan. All business pages are now locked. Please contact an administrator.',
reasonInactive:
'This tenant plan has expired or been disabled. All business pages are now locked. Please contact an administrator to restore access.',
plan: 'Current Plan',
expiredAt: 'Expired At',
articleLimit: 'Article Limit',
companyLimit: 'Company Limit',
contactAdmin: 'Once the administrator reactivates access, refresh this page to continue.',
logout: 'Log out',
refresh: 'Check again',
refreshing: 'Checking…',
stillBlocked:
'Access is still blocked. Please contact your administrator before checking again.',
},
shell: {
localeLabel: 'Language',
quotaTitle: 'Plan & Quota',
quotaStatus: 'Healthy',
membershipExpiresAt: 'Expires',
remainingQuota: 'Article quota',
aiPoints: 'AI points',
resetAt: 'Reset at',
userFallback: 'Admin',
logout: 'Logout',
planFallback: 'Free Plan',
currentCompany: 'Company',
currentCompanyPlaceholder: 'Select company',
createCompany: 'Create company',
changePassword: 'Change password',
changePasswordTitle: 'Change password',
oldPassword: 'Current password',
newPassword: 'New password',
confirmNewPassword: 'Confirm new password',
passwordMinHint: 'At least 8 characters',
passwordValidation:
'Enter your current password and set the new password to at least 8 characters.',
passwordMismatch: 'The new passwords do not match.',
passwordChanged: 'Password updated. Please sign in again with the new password.',
openNavigation: 'Open navigation',
collapseNavigation: 'Collapse navigation',
expandNavigation: 'Expand navigation',
aiUsageTitle: 'AI Point Usage',
aiUsageRecent: 'Recent Usage',
aiUsageEmpty: 'No AI point usage yet',
aiUsageBase: 'Tiered every {base} chars',
aiUsageRule: '{chars} chars / base {base}',
aiUsagePendingHelp:
'Points have been reserved. They will be confirmed once the AI task completes; if generation fails, the points are returned automatically.',
aiUsageTypes: {
article_selection_optimize: 'Article Selection Optimize',
template_analyze: 'AI Analysis',
template_title_generate: 'AI Title Generation',
template_outline_generate: 'AI Outline Generation',
kol_prompt_generate: 'KOL Prompt Generation',
kol_prompt_optimize: 'KOL Prompt Optimize',
question_distill: 'AI Candidate Search Term Generation',
question_combination_fill: 'Expansion Tool AI Fill',
},
aiUsageStatus: {
pending: 'Processing',
completed: 'Charged',
refunded: 'Refunded',
failed: 'Failed',
},
},
route: {
login: {
title: 'Welcome back',
description: 'Sign in with a real tenant account.',
},
brandOnboarding: {
title: 'Choose a brand',
description: 'Create the first brand and initialize its keyword library.',
},
workspace: {
title: 'Workspace',
description: 'Template shortcuts, overview data, and recent generations in one place.',
},
templates: {
title: 'Template Creation',
description:
'Manage both general-purpose and refined templates, with all related generation records gathered here.',
},
wizard: {
title: 'Template Wizard',
description:
'Follow the template-driven three-step flow to fill inputs, confirm structure, and generate the article.',
},
articleEditor: {
title: 'Article Editor',
description: 'Edit titles, content, and publishing settings in a dedicated workspace.',
},
custom: {
title: 'Custom Generation',
description: 'Generate articles with custom prompt rules, instant or scheduled.',
},
freeCreate: {
title: 'Free Create',
description: 'Create and edit articles freely, no templates or AI generation required.',
},
imitation: {
title: 'Imitation Create',
description: 'Manage rewritten articles generated from citation sources or external URLs.',
},
imitationCreate: {
title: 'Imitation Create',
description: 'Extract an article from a URL, then generate a new article in one step.',
},
media: {
title: 'Media Management',
description:
'Review desktop-managed media bindings, authorization state, and sync results in one place.',
},
publishManagement: {
title: 'Publish Management',
description:
'Review desktop publish tasks, external links, account workbench entry points, and retry state.',
},
mediaSupplyResources: {
title: 'Single Submission Media',
description: 'Filter authority news media resources and submit articles.',
},
mediaSupplySubmit: {
title: 'Submit Article',
description: 'Confirm media resources, choose article content, and queue the submission.',
},
mediaSupplyOrders: {
title: 'Submission Records',
description: 'Review submission orders and billing state for the current account.',
},
mediaSupplyFavorites: {
title: 'Frequent Media Groups',
description: 'Group the media resources you submit to most often.',
},
brands: {
title: 'Company & Lexicon',
description: 'Manage the keyword library (search terms) and competitors around each brand.',
},
brandQuestionCreate: {
title: 'New search term',
description:
'Create brand search terms with the expansion tool, AI expansion, or manual input.',
},
tracking: {
title: 'Data Details',
description:
'Inspect plugin-sampled brand performance, platform coverage, hot questions, and citation attribution.',
},
trackingQuestion: {
title: 'Question Detail',
description:
'Inspect answer content, citation sources, citation analysis, and content citations for a single question.',
},
knowledge: {
title: 'Knowledge Base',
description: 'No matching backend APIs exist in this repository yet.',
},
images: {
title: 'Image Management',
description:
'Manage image assets, including folders, reference analysis, and cover library usage.',
},
aiPoints: {
title: 'AI Point Usage',
description: 'Review AI point balance, cycle rules, and recent usage records.',
},
notFound: {
title: 'Page not found',
description: 'The link you opened might have moved or no longer exists.',
},
},
onboardingBrand: {
eyebrow: 'Brand Onboarding',
title: 'Choose a brand or company',
subtitle: 'You have access to multiple brands or companies. Choose one to start working.',
createBrand: 'Create new brand or company',
createHint: 'After creation, keyword initialization starts automatically.',
emptyDescription:
'New users need to create a brand or company before entering the workspace.',
noWebsite: 'No website yet',
form: {
title: 'Create brand or company',
name: 'Brand or company name',
namePlaceholder: 'Example: GEO Console / Acme Furniture',
website: 'Website (optional)',
websitePlaceholder: 'https://example.com',
description: 'Description',
descriptionPlaceholder: 'Briefly describe the business, products, service area, or core value.',
},
ai: {
title: 'Generating brand or company questions',
stages: {
fetch: 'Fetching website and business context...',
generate: 'Generating candidate search terms for monitoring...',
refine: 'Deduplicating and filtering savable questions...',
},
},
questions: {
title: 'Select brand or company questions',
subtitle:
'Choose up to {limit} questions to save to the keyword library. You can add or edit more later.',
confirm: 'Save and enter workspace',
skip: 'Skip and enter',
empty: 'No usable questions were generated. You can enter the workspace and add them manually.',
selectionLimit: 'Choose up to {limit} questions.',
},
messages: {
nameRequired: 'Enter a brand or company name.',
questionRequired: 'Select at least one question, or skip and add them manually later.',
aiCharged: 'This generation consumed {count} AI point.',
},
},
notFound: {
title: 'This page got lost',
description:
"We couldn't find anything at this address. The URL might be mistyped, or the page has been removed.",
pathLabel: 'Requested path',
back: 'Go back',
home: 'Back to workspace',
},
aiPoints: {
balance: 'Available Points',
baseChars: 'Base Characters',
usageTypeFallback: 'AI Service Call',
ledgerTitle: 'Usage Ledger',
ledgerLimit: 'Latest {limit} records',
ledgerTotal: '{total} records',
refundedHelp:
'The system deducted points first. After the task failed, the points were returned automatically, so net usage is 0.',
amount: {
netZero: 'Net 0',
zero: '0',
pendingFlow: '{points} pts reserved',
completedFlow: '{points} pts charged',
refundedFlow: '{points} pts deducted, then returned',
failedFlow: 'No charge',
},
table: {
usageType: 'Usage',
points: 'Points',
requestChars: 'Metered Chars',
},
},
kol: {
marketplace: {
title: 'Refined Templates',
filter: {
industry: 'Industry',
keyword: 'Keyword',
all: 'All',
},
empty: 'No published subscription packages yet',
subscribers: '{count} subscribed tenants',
prompts: '{count} refined templates',
},
package: {
subscribe: 'Request subscription',
pending: 'Pending',
subscribed: 'Subscribed',
revoked: 'Revoked',
expired: 'Expired',
notSubscribed: 'Not subscribed',
},
generate: {
title: 'Refined Template Generation',
submit: 'Generate',
fillVariables: 'Please fill in the following variables and click generate',
},
manage: {
title: 'KOL Prompt Management',
subtitle:
'Manage refined template packages, prompts, platforms, variables, and publishing status.',
packageTitle: 'Packages',
promptTitle: 'Prompts',
createPackage: 'Create package',
editPackage: 'Edit package',
publishPackage: 'Publish',
archivePackage: 'Archive',
createPrompt: 'Create prompt',
activatePrompt: 'Go live',
archivePrompt: 'Take offline',
confirmDeletePackage: 'Are you sure you want to delete this package?',
confirmDeletePrompt: 'Are you sure you want to delete this prompt?',
emptyPromptSelection: 'Select a package on the left to view its prompts',
platformHint: 'Platform',
platformHintDefault: 'General',
packageStatus: {
draft: 'Draft',
published: 'Published',
archived: 'Archived',
},
messages: {
packageCreated: 'Package created successfully',
packageUpdated: 'Package updated successfully',
packagePublished: 'Package published successfully',
packageArchived: 'Package archived successfully',
packageDeleted: 'Package deleted successfully',
promptCreated: 'Prompt created successfully',
promptActivated: 'Prompt is live',
promptArchived: 'Prompt is offline',
promptDeleted: 'Prompt deleted successfully',
},
packageForm: {
tags: 'Tags',
tagsPlaceholder: 'Type a tag and press Enter',
priceNote: 'Price Note',
priceNotePlaceholder: 'For example: Contact me for pricing',
cover: 'Cover Image',
coverHint:
'Choose from the image library or upload a local image and convert it to WebP automatically.',
selectCover: 'Select cover image',
changeCover: 'Change cover image',
removeCover: 'Remove cover image',
noCover: 'No cover image selected',
nameRequired: 'Package title is required',
coverPicker: {
title: 'Select package cover',
localTab: 'Local upload',
emptyTitle: 'Choose an image for this package cover',
emptyHint:
'Choose from the image library or upload a local image and convert it to WebP automatically.',
},
},
status: {
draft: 'Draft',
active: 'Live',
archived: 'Offline',
},
editor: {
basicInfo: 'Basic info',
saveMeta: 'Save basic info',
saveDraft: 'Save draft',
publish: 'Publish',
preview: 'Preview form',
aiGenerate: 'AI Generate',
aiOptimize: 'AI Optimize',
aiPlaceholder: 'Describe the prompt effect you want, and AI will generate it...',
aiOptimizePromptPlaceholder:
'For example: make this prompt clearer, keep variable placeholders, and reduce ambiguity.',
aiOptimizeDisclaimer:
'AI output is for reference only. Review it before replacing the selected prompt text.',
aiOptimizeReplace: 'Replace selection',
},
variable: {
input: 'Input',
textarea: 'Textarea',
select: 'Select',
number: 'Number',
checkbox: 'Checkbox',
key: 'Variable key',
label: 'Label',
required: 'Required',
placeholder: 'Placeholder',
options: 'Options (comma separated)',
maxLength: 'Max length',
defaultValue: 'Default value',
minValue: 'Min number',
maxValue: 'Max number',
defaultNumber: 'Default number',
},
},
dashboard: {
title: 'KOL Dashboard',
subtitle: 'Track subscriptions and generation metrics in real time.',
totalSubs: 'Total subscribed tenants',
monthSubs: 'New this month',
totalUsage: 'Total usage',
monthUsage: 'Usage this month',
failRate: 'Failure rate',
byPackage: 'By package',
trend: 'Trend',
},
profile: {
title: 'KOL Profile',
subtitle:
'These fields are shown in the KOL Marketplace and are separate from your account settings.',
persona: {
displayNameLabel: 'Display name',
displayNamePlaceholder: 'Enter your public display name',
bioLabel: 'Bio',
bioPlaceholder: 'A short intro for your subscribers',
avatarLabel: 'Avatar',
avatarHint: 'PNG/JPG/GIF/WebP, up to 2 MB',
avatarUploading: 'Uploading avatar…',
saveSuccess: 'Updated',
saveError: 'Failed to update',
displayNameRequired: 'Display name is required',
displayNameTooLong: 'Display name must be at most 40 characters',
bioTooLong: 'Bio must be at most 500 characters',
avatarInvalidType: 'Only PNG/JPG/GIF/WebP are supported',
avatarTooLarge: 'Avatar size cannot exceed 2 MB',
notActive: 'You are not an active KOL',
},
},
},
workspace: {
eyebrow: 'Dashboard',
metrics: {
articles: 'Generated',
published: 'Published',
brands: 'Brands',
mediaAccounts: 'Media accounts',
},
sections: {
generalTemplates: 'General-Purpose Templates',
recent: 'Recent Generations',
overview: 'Overview',
quota: 'Plan & Quota',
},
actions: {
enterTemplates: 'Open Templates',
},
quota: {
remaining: 'Remaining quota',
total: 'Total quota',
used: 'Used quota',
},
emptyTemplates: 'No template cards available yet',
noRecentArticles: 'No recent generations yet',
},
tracking: {
brandPlaceholder: 'Select brand',
keywordPlaceholder: 'Select keyword library (search terms)',
allQuestionSets: 'All keyword library (search terms)',
collectNow: 'Collect Now',
collectBrandRequired: 'Select a brand before collecting.',
collectKeywordRequired: 'Select a keyword library (search terms) before collecting.',
collectTodayOnly: "Collect Now only supports today's data. Switch back to today to continue.",
collectClientChecking: "Checking whether the current account's desktop client is online.",
collectClientOnlineRequired:
"The current account's desktop client must be online before collecting.",
noDesktopClientCollectReason:
'This account has no registered desktop client, so collection cannot start.',
noAuthorizedPlatformsCollectReason:
'This account has no authorized AI platforms, so collection cannot start.',
collectPlatformUnauthorized: 'The selected platform is not authorized for this account.',
pluginMode: 'Plugin sampling',
pluginHint:
'Plugin-mode data depends on device uptime. Low coverage should be treated as directional only.',
awaitingSnapshot: 'Waiting for the next valid snapshot',
infoStrip:
'{mode} · target {desired} · planned {planned} · sampled {actual} · coverage {coverage} · updated {updatedAt} · {trigger}',
latestSnapshot: 'Latest Snapshot',
coverage: 'Coverage',
coverageTitle: 'Sampling Coverage',
coverageSummary: 'Target {desired} · Sampled {actual} · Coverage {coverage}',
platformMatrix: 'Platform Matrix',
platformMatrixTitle: 'Platform Comparison Matrix',
hotQuestions: 'Hot Questions',
hotQuestionsTitle: 'Hot Questions',
hotQuestionsHint:
'Choose the full keyword library (search terms) or one specific search term. Selecting one search term limits display and collection to that term.',
questionSearchPlaceholder: 'Search questions in the selected scope',
questionDetailEyebrow: 'Question Detail',
questionDetailCollectedAt: 'Collected at {time}',
questionDetailFallback: 'Question Detail',
backToQuestions: 'Back to questions',
citationRanking: 'Citation Ranking',
citationRankingTitle: 'Citation Ranking',
citationRankingHint:
'Attribute SaaS-published content by published-link identity across model citation sources.',
citationWindow7: 'Last 7 days',
citationWindow30: 'Last 30 days',
citationWindowLabel: 'Last {days} days',
citedArticles: 'Cited Articles',
citedArticlesTitle: 'Cited Articles',
answerContent: 'Answer Content',
citationSources: 'Citation Sources',
citationSourcesTitle: 'Citation Sources',
citationAnalysis: 'Citation Analysis',
citationAnalysisTitle: 'Citation Analysis',
contentCitations: 'Content Citations',
contentCitationsTitle: 'Content Citations',
imitationAction: 'Imitation create',
taskDebugTitle: 'Async Task Debug',
taskDebugHint:
'For troubleshooting the callback -> queue -> worker flow only. The four main content sections above stay unchanged.',
contentCitationBadge: 'Content Citation',
noQuestions: 'No hot questions for the current filters',
noCitationRanking: 'No attributable citations in the current window',
noCitedArticles: 'No content citations in the current window',
noAnswer: 'No sampled answer for this platform',
noCitations: 'No citations for this platform',
noCitationAnalysis: 'No citation analysis for this platform',
noContentCitations: 'No content citations for the active platform',
noTaskDebug: 'No async task debug data for the current filters',
noPlatformBreakdown: 'No platform data is available for the current filters',
selectedPlatformUnauthorizedTitle: 'Selected Platform Not Authorized',
selectedPlatformUnauthorizedDescription:
'This AI platform has no active authorization for the current account. Switch to an authorized platform or authorize it in the desktop client.',
noDetailPlatformsTitle: 'No Platforms Available',
noDetailPlatformsDescription: 'No AI platform data is available for the current filters.',
platformAuthorization: {
authorized: {
title: 'AI Platform Authorization Active',
description:
'This account has AI platform authorization available for monitoring collection.',
},
no_desktop_client: {
title: 'No Desktop Client Detected',
description:
'This account has not registered a desktop client. Daily tasks will wait for an eligible client before dispatch, and the dashboard will not show collection as available.',
},
no_authorized_platforms: {
title: 'No Authorized AI Platforms',
description:
'This account has no bound or authorized AI platform accounts. The system will not generate or dispatch collection tasks for unauthorized platforms.',
},
},
samples: 'samples',
citations: 'citations',
citedArticleMeta: '{count} cited articles',
contentCitationMeta: '{count} content references',
manual: 'Manual',
automatic: 'Automatic',
noChange: 'Flat',
metrics: {
mentionRate: 'Mention Rate',
top1MentionRate: 'Top-1 Mention Rate',
firstRecommendRate: 'First Recommendation Rate',
positiveMentionRate: 'Positive Mention Rate',
},
columns: {
platform: 'Platform',
appearances: 'Appearances',
citedAnswers: 'Cited Answers',
citedArticles: 'Cited Articles',
citationRate: 'Citation Rate',
saasSourceRate: 'Source Share',
citations: 'Citations',
sourcePlatform: 'Source',
channelName: 'Channel',
domain: 'Domain',
share: 'Share',
contentName: 'Content',
publishPlatform: 'Publish Platform',
distinctSites: 'Distinct Sites',
brandContent: 'Has Brand Content',
},
status: {
sampled: 'Sampled',
partial: 'Partially Sampled',
unsampled: 'Unsampled',
pending: 'Pending',
not_logged_in: 'Not Logged In',
unavailable: 'Unavailable',
},
confidence: {
high: 'High confidence',
medium: 'Medium confidence',
low: 'Low confidence',
},
taskDebug: {
labels: {
plannedAt: 'Planned At',
leasedAt: 'Leased At',
callbackReceivedAt: 'Callback Received At',
queueEnqueuedAt: 'Queued At',
completedAt: 'Completed At',
leaseExpiresAt: 'Lease Expires At',
runId: 'Run ID',
runStatus: 'Run Status',
providerModel: 'Model',
requestId: 'Request ID',
providerRequestId: 'Provider Request ID',
receivedAlertCount: 'Received Alert Count',
receivedAlertedAt: 'Last Alerted At',
skipReason: 'Skip Reason',
errorMessage: 'Task Error',
lastQueuePublishError: 'Queue Publish Error',
},
taskStatus: {
pending: 'Pending',
leased: 'Leased',
received: 'Received',
completed: 'Completed',
failed: 'Failed',
skipped: 'Skipped',
expired: 'Expired',
},
queueStatus: {
pending: 'Pending Queue',
queued: 'Queued',
publish_failed: 'Publish Failed',
invalid_payload: 'Invalid Payload',
},
},
},
templateMeta: {
top_x_article: {
eyebrow: 'Ranked Content',
helper: 'Good for listicles, comparisons, and recommendation-driven output.',
accent: 'Top X',
action: 'Create ranking',
},
product_review: {
eyebrow: 'Product Review',
helper: 'Good for benefits, trade-offs, and suitability analysis.',
accent: 'Review',
action: 'Start review',
},
research_report: {
eyebrow: 'Research Report',
helper: 'Good for longer analysis, trends, and market insight.',
accent: 'Report',
action: 'Create report',
},
brand_search_expansion: {
eyebrow: 'Brand Expansion',
helper: 'Expand brand plus search intent into a richer GEO article.',
accent: 'GEO',
action: 'Expand',
},
default: {
eyebrow: 'Content Template',
helper: 'This template is already usable and can go straight into generation.',
accent: 'Ready',
action: 'Open template',
},
},
status: {
generate: {
draft: 'Draft',
queued: 'Queued',
generating: 'Generating',
running: 'Running',
completed: 'Completed',
partial_success: 'Partially successful',
partial_completed: 'Partially successful',
failed: 'Failed',
},
publish: {
unpublished: 'Unpublished',
publishing: 'Publishing',
success: 'Published',
failed: 'Failed',
partial_success: 'Partially Published',
published: 'Published',
publish_success: 'Published',
publish_failed: 'Failed',
pending_review: 'Pending Review',
blocked_by_compliance: 'Blocked by compliance',
},
sourceType: {
template: 'Template generation',
custom_generation: 'Custom generation',
instant_task: 'Instant task',
schedule_task: 'Scheduled task',
free_create: 'Free create',
imitation: 'Imitation create',
kol: 'Refined template generation',
},
},
imitation: {
actions: {
create: 'New Rewrite',
submit: 'Submit and generate',
},
filters: {
publishStatus: 'Publish status',
generateStatus: 'Generation status',
keyword: 'Search',
createdTime: 'Created time',
createdTimeStart: 'Start time',
createdTimeEnd: 'End time',
keywordPlaceholder: 'Search by article title',
},
list: {
eyebrow: 'Imitation Create',
count: '{count} articles',
sourceArticle: 'Source',
empty: 'No rewritten articles yet. Start from a citation source or create one manually.',
deleteConfirm: 'Delete this rewritten article?',
deleteSuccess: 'Article deleted.',
deleteError: 'Failed to delete article.',
},
create: {
title: 'Create rewritten article',
subtitle:
'The backend fetches the source article first, then generates a new original article from your settings.',
sourceSection: 'Source article',
settingsSection: 'Rewrite settings',
sourceURL: 'Article URL',
sourceTitle: 'Source title',
language: 'Article language',
brandName: 'Current company',
region: 'Region',
keywords: 'Optimization keywords',
preservePoints: 'Keep / emphasize',
avoidPoints: 'Avoid',
extraRequirements: 'Extra requirements',
enableWebSearch: 'Allow web search supplement',
webSearchHint:
'When enabled, generation can reference live web information for newer facts or industry context.',
knowledgeBase: 'Reference knowledge base',
knowledgeBasePlaceholder: 'Optional. Add facts, brand material, and industry background.',
knowledgeBaseHint:
'Selected groups are retrieved in the backend and passed to generation as reference context.',
sourceURLPlaceholder: 'https://example.com/article',
sourceTitlePlaceholder: 'Optional. Citation titles are prefilled automatically.',
brandNamePlaceholder: 'Select the current company in the top bar first.',
regionPlaceholder: 'For example: Shanghai, East China, nationwide, North America',
keywordsPlaceholder:
'Type optimization keywords and press Enter. Search-term options appear after selecting the current company.',
preservePointsPlaceholder: 'List facts, data, arguments, or examples that must be kept.',
avoidPointsPlaceholder: 'List claims, competitors, compliance risks, or wording to avoid.',
extraRequirementsPlaceholder:
'Add channel, structure, title style, or industry-specific instructions.',
queued: 'Rewrite task submitted and queued.',
sourceURLRequired: 'Enter the source article URL first.',
brandNameRequired: 'Select the current company in the top bar first.',
submitError: 'Failed to submit rewrite task.',
backToList: 'Back to rewrites',
},
},
freeCreate: {
actions: {
create: 'New Article',
},
filters: {
publishStatus: 'Publish Status',
keyword: 'Search',
createdTime: 'Created Time',
createdTimeStart: 'Start',
createdTimeEnd: 'End',
keywordPlaceholder: 'Search by title',
},
list: {
eyebrow: 'Free Create',
count: '{count} articles',
empty: 'No articles yet. Click "New Article" to start creating.',
edit: 'Edit article',
deleteConfirm: 'Are you sure you want to delete this article?',
deleteSuccess: 'Article deleted',
deleteError: 'Failed to delete article',
},
createError: 'Failed to create article',
},
templates: {
eyebrow: 'Article Creation',
sections: {
generalTemplates: 'General-Purpose Templates',
refinedTemplates: 'Refined Templates',
records: 'Template Creation Records',
},
actions: {
batchGenerate: 'Batch generate',
chooseTemplate: 'Choose template',
},
filters: {
template: 'Template',
publishStatus: 'Publish status',
generateStatus: 'Generation status',
keyword: 'Search',
generationTime: 'Generation time',
generationTimeStart: 'Start time',
generationTimeEnd: 'End time',
keywordPlaceholder: 'Search by article title',
},
list: {
eyebrow: 'Template Creation Records',
count: '{count} articles',
empty: 'No articles have been created yet.',
preview: 'Preview',
edit: 'Edit article',
editDisabled: 'Only draft, failed, or completed articles can be edited',
publishDisabled: 'Only completed articles can be published',
versions: 'Versions',
deleteConfirm: 'Delete this article?',
deleteSuccess: 'Article deleted.',
deleteError: 'Failed to delete article.',
},
picker: {
title: 'Choose the template you want to use',
empty: 'Choose either general-purpose templates or refined template generation first',
generalDescription: 'Choose a general-purpose template to start creating',
refinedDescription: 'Choose a refined template and start refined generation directly',
viewExample: 'View example',
},
wizard: {
drawerTitle: 'Template generation',
steps: {
basic: 'Basic info',
basicDesc: 'Language, template fields, and company context',
structure: 'Structure',
structureDesc: 'Title and outline',
generate: 'Generate',
generateDesc: 'Confirm the outline, add key points, and submit the task',
},
sections: {
templateFields: 'Template fields',
brandContext: 'Company context',
language: 'Language',
brandInfo: 'Company',
brandLibrary: 'Company library',
brandName: 'Current company',
website: 'Official website',
brandSummary: 'AI company summary',
keywords: 'Keywords',
brandQuestions: 'Keyword library (search terms)',
primaryQuestion: 'Optimization keyword',
supplementalQuestions: 'Supplemental keywords',
competitors: 'Competitors',
chooseTitle: 'Choose a title',
customTitle: 'Custom title',
structure: 'Article structure',
customOutline: 'Custom section',
preview: 'Article preview',
generatedOutline: 'Confirm outline',
outlinePreview: 'Outline preview',
keyPoints: 'Key points',
review: 'Review',
notes: 'Notes',
inputParams: 'Input params',
},
hints: {
brandContext: 'The current company pulls in keywords and competitor context.',
brandFlow:
'Articles use the current company selected in the top bar. After you choose an optimization keyword, AI will prepare the summary, competitors, and title options.',
brandSummaryPlaceholder:
'After analysis, AI will summarize the company angle, positioning, and content opportunities here.',
keywords:
'Type keywords directly or reuse brand-library keywords. AI results will be merged into this list.',
brandQuestions:
'The optimization keyword controls the article spine; supplemental keywords broaden nearby search intent.',
supplementalQuestions:
'Choose up to 3 so the article covers related intent without drifting.',
questionEmpty: 'No questions are available for this company yet.',
selectBrandFirst: 'Select the current company in the top bar first.',
competitors:
'Competitors stay editable. You can add rows manually; saving to the competitor library is available after selecting the current company.',
competitorEmptyEditable:
'No competitors yet. Add one manually or let AI fill the list first.',
templateFields:
'Keep any extra template-specific fields here to constrain the writing direction.',
titleSelection:
'AI will return 5 better title options before you move forward. Choose one or rewrite it.',
structure: 'Keep the default outline or trim sections for this draft.',
preview: 'The panel on the right updates the article frame in real time.',
previewEmpty: 'Select one or more sections to preview the article frame here.',
generatedOutline:
'AI generates the full article outline first. You can edit, add, or delete nodes before creating the final article.',
outlinePreview: 'The panel on the right updates from the current outline in real time.',
outlineEmpty: 'Generate the outline first to edit the article structure here.',
review: 'Check the final setup before creating the generation task.',
competitorEmpty: 'No competitors are available under this company yet.',
customTitle: 'Use this field if you want to override the title manually.',
keyPoints: 'Add any key messages, angles, or style notes here.',
async:
'The backend creates the article and task first, then completes content generation asynchronously.',
},
actions: {
analyze: 'Analyze',
analyzeCompetitors: 'AI fill competitors',
addCompetitor: 'Add competitor',
addSection: 'Add section',
addOutlineNode: 'Add node',
addOutlineChild: 'Add child',
favorite: 'Save',
saved: 'Saved',
unfavorite: 'Unsave',
submit: 'Submit and generate',
},
review: {
templateName: 'Template',
articleTitle: 'Article title',
brandContext: 'Company context',
outline: 'Outline',
currentTemplate: 'Current template',
promptVisibility: 'Prompt visibility',
selectedKeywords: 'Selected keywords',
selectedCompetitors: 'Selected competitors',
},
localeOptions: {
zh: 'Simplified Chinese',
en: 'English',
},
table: {
website: 'Website',
name: 'Name',
description: 'Description',
actions: 'Actions',
},
placeholders: {
brandLibrary: 'Choose the current company',
brandName: 'Current company from the top bar',
website: 'Official website, optional',
keywords: 'Type keywords and press Enter',
primaryQuestion: 'Choose one optimization keyword',
supplementalQuestions: 'Optional, choose up to 3 supplemental keywords',
customTitle: 'Override the AI title here if needed',
customOutline: 'Add another section, for example “Buying advice”',
keyPoints: 'Add any extra instructions, key angles, or constraints for the article',
competitorWebsite: 'Official site or landing page',
competitorName: 'Competitor name',
competitorDescription: 'One-line positioning or summary',
outlineNode: 'Enter a title',
},
promptVisible: 'Prompt visible',
promptSealed: 'Prompt sealed',
aiBanner: {
title: 'One-click AI analysis',
defaultDescription:
'AI will use the optimization keyword to complete the brand summary and extract competitor context.',
productReviewDescription:
'AI will use the optimization keyword to organize the product context and suggest comparable alternatives.',
researchReportDescription:
'AI will use the brand question to organize the topic context and suggest reference targets.',
},
assist: {
analyzeTitle: 'AI is filling competitor information. Please wait…',
analyzeTitleNoCompetitors: 'AI is filling competitor information. Please wait…',
titleTitle: 'AI is generating titles. Please wait…',
outlineTitle: 'AI is generating the article outline. Please wait…',
analyzeStages: {
brand: 'Analyzing the brand context…',
keywords: 'Extracting keyword opportunities…',
questions: 'Organizing brand questions…',
competitors: 'Mapping competitors and websites…',
context: 'Organizing brand and website context…',
refine: 'Merging and filtering competitor suggestions…',
},
titleStages: {
context: 'Preparing the current brief…',
strategy: 'Generating title directions from brand questions and competitors…',
strategyNoCompetitors: 'Generating title directions from the brand question and brief…',
finalize: 'Returning 5 title options…',
},
outlineStages: {
context: 'Preparing the title, brand questions, and competitor context…',
contextNoCompetitors: 'Preparing the title, brand questions, and content context…',
structure: 'Generating the article outline from the selected structure…',
finalize: 'Returning the editable outline result…',
},
},
messages: {
requiredField: 'Please fill in {field} first.',
missingBrand: 'Select the current company in the top bar first.',
selectBrandBeforeQuestion:
'Select the current company in the top bar before continuing.',
missingPrimaryQuestion: 'Choose one primary brand question.',
missingTitle: 'Please choose or enter an article title.',
missingOutline: 'Please select at least one outline section.',
missingGeneratedOutline: 'Please generate and confirm the article outline first.',
customOutlineTooLong: 'Custom sections cannot exceed {count} characters.',
selectBrandBeforeCompetitors:
'Select the current company in the top bar before managing competitors.',
selectBrandBeforeFavorite:
'Select the current company in the top bar before saving competitors.',
missingCompetitorName: 'Enter a competitor name before saving it to the library.',
savedCompetitor: 'Competitor saved to the brand library.',
unsavedCompetitor: 'Competitor removed from the brand library.',
assistReady: 'AI analysis is ready. You can keep refining the draft.',
assistFailed: 'AI analysis failed. Please try again.',
assistTimeout: 'AI analysis timed out. Please try again.',
titleFailed: 'Title generation failed. Please try again.',
titleTimeout: 'Title generation timed out. Please try again.',
outlineFailed: 'Outline generation failed. Please try again.',
outlineTimeout: 'Outline generation timed out. Please try again.',
draftSaved: 'Draft saved. Returning to the template list.',
draftSaveFailed: 'Failed to save the draft. Please try again.',
queued: 'Task submitted. The article is now waiting in the generation queue.',
submitted: 'Generation task submitted. Refreshing article data.',
},
leaveConfirm: {
title: 'Save as draft?',
content: 'This template wizard has content. Save it as a draft before leaving.',
stay: 'Keep editing',
discard: 'Leave without saving',
save: 'Save draft',
},
},
},
article: {
drawerTitle: 'Article details',
preview: 'Content preview',
versionHistory: 'Version history',
publishedDetails: 'Published details',
untitled: 'Untitled article',
noContent: 'This article does not have generated content yet.',
editor: {
publish: 'Publish',
download: 'Download',
downloadFormats: {
word: 'Word',
pdf: 'PDF',
markdown: 'Markdown',
},
downloadMessages: {
success: 'Download started.',
failed: 'Export failed. Please try again.',
},
markdownExportConfirm: {
title: 'Download Markdown',
description:
'Images will be removed from the Markdown file. Text content such as headings, tables, and links will be kept.',
confirm: 'Download',
},
titlePlaceholder: 'Enter article title',
leaveConfirm: {
title: 'Unsaved changes',
description:
'This article has unsaved edits. Leave now to discard them, or save first before going back.',
discard: 'Discard changes',
saveAndLeave: 'Save and leave',
},
platformsTitle: 'Publish platforms',
platformsHint:
"This stays in sync with Media Management so you can edit the article's publish platforms directly.",
coverTitle: 'Cover image',
coverHint: 'Off by default. Once uploaded, the cover is saved with the article.',
coverRequired: 'A selected publishing platform requires a cover image.',
coverUpload: 'Upload cover image',
coverReplace: 'Choose again',
coverRemove: 'Remove cover',
coverSaved: 'Cover asset saved',
coverOff: 'Cover image is currently off. Turn it on to upload and crop a cover asset.',
coverTagRequired: 'Required',
coverTagOptional: 'Optional',
imagePrompt: 'Enter image URL',
tablePicker: {
empty: 'Drag to choose a table size',
hint: 'Keep dragging near the edge to expand the grid',
},
tableMenu: {
addRowBefore: 'Insert row above',
addRowAfter: 'Insert row below',
deleteRow: 'Delete row',
addColBefore: 'Insert left column',
addColAfter: 'Insert right column',
deleteCol: 'Delete column',
alignLeft: 'Align left',
alignCenter: 'Align center',
alignRight: 'Align right',
deleteTable: 'Delete table',
},
imageMenu: {
replace: 'Replace image',
caption: 'Toggle caption',
alignLeft: 'Align left',
alignCenter: 'Align center',
alignRight: 'Align right',
resetSize: 'Reset size',
delete: 'Delete image',
},
imagePicker: {
title: 'Select image',
emptyTitle: 'Choose an image for the article body',
emptyHint:
'Pick from the image library or upload locally. Local uploads are converted to WebP before upload.',
},
aiOptimize: {
title: 'AI Optimize',
subtitle:
'Supports contiguous multi-block selections and generates a rewrite from your instruction',
originalLabel: 'Selected text',
previewLabel: 'Preview',
previewPlaceholder: 'After you enter an instruction, the AI rewrite will stream here.',
generating: 'Generating...',
streamingHint: 'Building a stronger version of the selected text in real time...',
disclaimer:
'AI output is for reference only. Review it before replacing the original text.',
promptLabel: 'Instruction',
promptPlaceholder:
'For example: make it more natural, classroom-friendly, and persuasive while keeping the facts unchanged.',
generate: 'Generate',
regenerate: 'Regenerate',
stop: 'Stop',
replace: 'Replace selection',
close: 'Keep original',
messages: {
selectionRequired:
'Select one block or multiple contiguous blocks of article text first.',
promptRequired: 'Enter an instruction first.',
selectionChanged:
'The original selection changed. Please select it again before replacing.',
empty: 'There is no AI content ready to replace yet.',
failed: 'AI optimization failed. Please try again later.',
},
},
messages: {
saved: 'Article saved.',
generating: 'This article is still generating. Try editing it later.',
locked: 'Only completed articles can be edited.',
publishPending: 'Save the article first, then choose the target platforms.',
},
platforms: {
zhihu: 'Zhihu',
},
},
meta: {
templateType: 'Template',
currentVersion: 'Current version',
source: 'Source label',
sourceArticle: 'Source article',
wordCount: 'Word count',
},
versionUntitled: 'Untitled version',
},
media: {
hero: {
eyebrow: 'Publisher',
},
plugin: {
title: 'Browser Publisher',
ready: 'Extension connected',
notInstalled: 'Extension not connected',
installTitle: 'Install and open the GEO Publisher extension first',
installDesc:
"Binding and publishing depend on the browser's local platform sessions. The extension stores its own installation identity so future background checks can continue after the SaaS page is closed.",
backgroundHint:
"The extension should not reuse the web app's access token directly. This implementation already registers a dedicated installation identity for future background scanning and inclusion checks.",
versionLabel: 'Extension version',
installationLabel: 'Installation ID',
connectedSummary: 'Locally signed-in platforms',
registerRequired: 'The extension installation is not registered yet. Please re-detect first.',
},
actions: {
redetect: 'Re-detect',
bind: 'Bind',
rebind: 'Rebind',
unbind: 'Unbind',
},
card: {
bound: 'Bound',
unbound: 'Unbound',
unboundHint: '{platform} has not been bound to this tenant yet.',
needsAttention: 'Needs attention',
expiredHint: 'This account is no longer healthy. Rebind it to restore publishing.',
localMissing: 'Local session missing',
localMismatch: 'Local account mismatch',
readyHint:
'The correct local account is available and ready for publish or future background checks.',
accountLabel: 'SaaS account',
uidLabel: 'Platform UID',
localLabel: 'Local state',
localConnected: 'Session detected',
localDisconnected: 'No session detected',
updatedAt: 'Last sync',
multiAccount: '{count} accounts bound',
openPlatform: 'Open platform',
},
account: {
localMissing:
'The tenant account is bound, but this browser does not currently have the matching local session.',
localMismatch:
'This browser is signed in to a different account. Rebind or switch the local account first.',
ready: 'Ready',
selectable: 'Selectable',
unavailable: 'Unavailable',
},
empty: {
accounts: 'No publishable media accounts are bound yet.',
},
messages: {
bindSuccess: '{platform} bound successfully.',
bindSuccessTitle: 'Binding successful',
bindSuccessDetail: 'Bound account [{account}] on [{platform}]',
bindPending:
'The extension did not detect a local session for this platform yet. Sign in via the extension and retry.',
bindPendingTitle: 'Binding incomplete',
bindFailureTitle: 'Binding failed',
unbindSuccess: 'Account unbound.',
unbindSuccessTitle: 'Unbind successful',
unbindFailureTitle: 'Unbind failed',
unbindConfirm:
'Unbind this platform account? Publishing will no longer be available until it is bound again.',
},
publish: {
title: 'Publish',
subtitle: 'Multi-platform Dispatch',
description:
'Choose tenant-bound accounts that are currently signed in locally. The extension executes the real publish flow and writes back the resulting links.',
platformsTitle: 'Target platforms',
platformsHint:
'Previously selected and bound accounts are prefilled first. Unbound or locally unavailable platforms stay disabled.',
coverTitle: 'Cover image',
coverHint: 'Off by default. Uploading opens the cover picker and cropper.',
coverUpload: 'Upload cover image',
coverPlaceholder: 'Enter an optional cover asset URL',
messages: {
success: '{count} publish tasks submitted.',
successTitle: 'Publish successful',
partial: 'Publish finished with {success} succeeded and {failed} failed.',
partialTitle: 'Partial publish failure',
selectPlatform: 'Choose at least one available platform first.',
coverRequired:
'A selected publishing platform requires a cover image. Please upload one first.',
failureTitle: 'Publish failed',
failureItem: 'Publishing to [{platform}] failed: [{reason}]',
unknownFailure: 'Unknown error',
},
},
records: {
tabTitle: 'Published details',
platform: 'Platform',
status: 'Status',
publishedAt: 'Published at',
link: 'Published link',
open: 'Open',
copy: 'Copy',
empty: 'No publish records yet',
linkEmpty: 'No link is available for this record yet.',
copySuccess: 'Link copied.',
},
},
coverPicker: {
title: 'Select cover image',
tabs: {
local: 'Body / Local Upload',
ai: 'AI Cover',
},
dropzoneTitle: 'Upload image',
dropzoneHint:
'Supports PNG, JPG, GIF, and WebP up to 10MB. Uploads are converted to WebP in the browser first.',
previewTitle: 'Cover crop preview',
previewHintLocked:
'A selected platform requires a fixed cover ratio, so the cover will be exported using the current platform requirement.',
previewHintFree:
'There is no forced cover ratio right now. You can upload the original image directly or adjust framing before confirming.',
requirementsTitle: 'Platform requirements',
requirementsHint:
'Requirements switch automatically based on the selected publish platforms. WeChat Official Account, Baijiahao, and Dongchedi require a cover image.',
recommendedRatio: 'Recommended ratio',
recommendedSize: 'Recommended size',
required: 'Required',
optional: 'Optional',
zoom: 'Zoom',
fileLabel: 'Current cover',
emptyTitle: 'No publish platform selected',
emptyPlatforms:
"Choose publish platforms first and each platform's cover requirements will appear here.",
emptyHint: 'Supports PNG, JPG, JPEG, GIF, WebP, BMP, SVG, and AVIF up to 10MB.',
aiTitle: 'AI cover is coming soon',
aiHint:
'For now this flow supports local upload and cropping. AI cover generation can be plugged in here later.',
actions: {
upload: 'Local upload',
reset: 'Reset framing',
remove: 'Remove cover',
},
notes: {
required:
'This platform currently requires a cover image in the publish flow. Publishing is blocked until one is uploaded.',
optional:
'This platform already supports standalone covers and reuses the current crop when publishing.',
unsupported:
"This platform's current integration does not consume a standalone cover yet and falls back to body content or the platform default.",
},
messages: {
invalidType: 'Only PNG, JPG, JPEG, GIF, WebP, BMP, SVG, and AVIF images are supported.',
tooLarge: 'Image size cannot exceed 10MB.',
missingImage: 'Select a cover image first.',
missingArticle: 'The article is not ready yet. Refresh and try again.',
imageLoadFailed: 'Failed to load the cover image. Please choose another image.',
},
},
brands: {
eyebrow: 'Company & Lexicon',
title: 'Company & Lexicon',
description: 'Manage the keyword library (search terms) and competitor assets around each brand.',
railTitle: 'Brands',
selectBrand: 'Pick a brand to continue managing the keyword library (search terms).',
newBrand: 'New brand',
editBrand: 'Edit brand',
deleteBrand: 'Delete brand',
guide: {
title: 'Brand management guide',
body:
'Manage brands, the keyword library (search terms), and competitor libraries for AI platform monitoring and GEO analysis.',
},
tabs: {
questions: 'Keyword library (search terms)',
competitors: 'Competitors',
},
quota: {
plan: 'Current plan',
planHint: 'Brand library limits are enforced from the active plan.',
brands: 'Brand companies',
brandsHint: 'Free defaults to 1 and paid defaults to 2.',
keywords: 'Total keywords',
keywordsHint: 'The total number of keywords this account can bind.',
questions: 'Account question quota',
questionsHint: 'All brands share this account question quota.',
},
meta: {
keywordCount: '{count} keywords',
questionCount: '{count} questions',
competitorCount: '{count} competitors',
brandKeywordCount: '{count} keywords under this brand',
globalKeywordUsage: 'Total keywords used {used} / {total}',
keywordQuestionUsage: 'Questions {used} / {total}',
},
sections: {
keywords: 'Keywords',
questions: 'Keyword library (search terms)',
competitors: 'Competitor library',
versions: 'Version history',
},
actions: {
addBrand: 'Add brand',
newKeyword: 'New keyword',
newQuestion: 'New search term',
newCompetitor: 'New competitor',
viewVersions: 'View versions',
},
empty: {
brands: 'No brand data yet. Create your first brand to start.',
questions: 'No search terms under this brand yet.',
competitors: 'No competitors under this brand yet.',
brandDescription: 'No brand description yet',
competitorDescription: 'No competitor description yet',
},
form: {
brandName: 'Brand name',
brandWebsite: 'Company website (optional)',
brandDescription: 'Brand description',
keywordName: 'Keyword',
questionText: 'Search term',
competitorName: 'Competitor name',
competitorWebsite: 'Competitor website',
competitorDescription: 'Competitor description',
competitorLines: 'Product lines',
competitorLinesHint: 'Separate multiple product lines with commas.',
},
messages: {
createBrand: 'Brand created.',
updateBrand: 'Brand updated.',
deleteBrand: 'Brand deleted.',
createKeyword: 'Keyword created.',
updateKeyword: 'Keyword updated.',
deleteKeyword: 'Keyword deleted.',
createQuestion: 'Search term created.',
updateQuestion: 'Search term updated.',
deleteQuestion: 'Search term deleted.',
createCompetitor: 'Competitor created.',
updateCompetitor: 'Competitor updated.',
deleteCompetitor: 'Competitor deleted.',
chooseBrand: 'Please choose a brand first.',
chooseKeyword: 'Please choose a keyword first.',
brandLimitReached: 'Your current plan allows up to {limit} brand companies.',
keywordLimitReached: 'This account allows up to {limit} keywords.',
questionLimitReached: 'This account allows up to {limit} search terms.',
},
questions: {
create: 'New search term',
createSingle: 'Add single search term',
expand: 'Bulk expand search terms',
usage: 'Search terms {used} / {total}',
remaining: '{count} remaining',
generate: 'Generate candidates',
emptyCandidates: 'No candidates yet. Generate or paste search terms above.',
table: {
question: 'Keyword library (search terms)',
},
modal: {
title: 'New search term',
currentBrand: 'Current brand',
methods: {
single: 'Single',
combination: 'Expansion tool',
aiDistill: 'AI expansion',
manualBatch: 'Manual batch',
},
preview: 'Candidate preview',
summary:
'{total} candidates · {selected} selected · {tooShort} too short · {duplicate} duplicates',
save: 'Save search terms ({count})',
},
combination: {
region: '1. Region',
prefix: '2. Prefix',
core: '3. Precise term (required)',
industry: '4. Industry (required)',
suffix: '5. Suffix',
defaultWord: 'Default',
estimate: '{count} candidates estimated',
coreRequired: 'Precise term is required',
industryRequired: 'Industry is required',
},
aiFill: {
button: 'AI fill',
success: 'Word columns filled. You can keep editing.',
charged: 'Word columns filled. This used {count} AI point.',
waitingTitle: 'AI is filling the expansion tool. Please wait...',
waitingStages: {
region: 'Detecting city, province capital, and macro region...',
generate: 'Analyzing brand context and high-frequency intent...',
refine: 'Refining short combinable precise term groups...',
},
},
ai: {
note: 'AI expansion consumes 1 AI point. Failed generations are refunded automatically.',
seedTopic: 'User search term',
seedTopicPlaceholder: 'Enter a search term and press Enter; multiple terms supported',
seedTopicHint:
'Candidates expand from user search terms with strong commercial intent. The company name is a target term, not a candidate search term.',
generate: 'Generate with AI',
waitingTitle: 'AI is generating candidate search terms. Please wait...',
waitingStages: {
context: 'Organizing user search terms and the target term...',
generate: 'Generating commercial candidate search terms suited for recommending companies...',
refine: 'Deduplicating and filtering savable search terms...',
},
},
batch: {
label: 'One search term per line',
},
badges: {
duplicate: 'Duplicate',
tooShort: 'Too short',
},
messages: {
partialSaved: 'Saved {created}; skipped {skipped}.',
limitReached: 'This account allows up to {limit} search terms shared across all brands.',
selectionLimitReached:
'This plan allows up to {limit} search terms. Selection limit reached.',
truncated: 'Candidates exceeded the limit and were truncated to 500.',
cacheHit: 'Used the most recent AI expansion result.',
aiCharged: 'This AI expansion consumed {count} AI point.',
},
errors: {
emptyInput: 'Enter search term content first.',
aiSeedTopicTooShort:
'{terms} is too short. Enter a user search term with at least 2 characters, such as "mattress recommendation" or "how to choose a kids bed".',
aiSeedTopicTooShortWithMore:
'{terms} and {count} more search terms are too short. Enter user search terms with at least 2 characters, such as "mattress recommendation" or "how to choose a kids bed".',
noSelection: 'Select at least one candidate.',
noValidQuestions: 'No valid search terms can be saved. Adjust candidates and try again.',
},
page: {
title: 'New search term',
subtitle:
'Generate candidates, review them, then save them to this brand keyword library (search terms).',
steps: {
configure: 'Configure',
preview: 'Review candidates',
},
methodTitle: 'Choose a creation method',
methodHint:
'Candidates remain temporary until saved, so you can generate, edit, and select first.',
methods: {
combination: 'Expand search term candidates from the column-based word tool.',
ai: 'Let AI generate search term candidates around a seed topic.',
batch: 'Paste search terms from a sheet or document.',
},
expansionHint:
'One word per line. Empty optional columns are skipped; precise term and industry are required.',
batchHint: 'One search term per line. You can edit and select each one before saving.',
},
},
},
custom: {
eyebrow: 'Custom Generation',
title: 'Custom Generation',
description: 'Generate articles with custom prompt rules, instant or scheduled.',
cards: {
instantTitle: 'Instant Generation',
instantDesc: 'Quickly create custom content tasks',
scheduleTitle: 'Scheduled Generation',
scheduleDesc: 'Set up automated content generation plans',
},
tabs: {
articles: 'Articles',
instantTasks: 'Instant Tasks',
scheduleTasks: 'Scheduled Tasks',
promptRules: 'Prompt Rules',
},
promptRule: {
name: 'Rule name',
namePlaceholder: 'Enter prompt name',
content: 'Prompt content',
scene: 'Scene',
tone: 'Default tone',
wordCount: 'Default word count',
status: 'Status',
articleCount: 'Article count',
createTitle: 'Create Prompt Rule',
editTitle: 'Edit Prompt Rule',
deleteConfirm: 'Delete this rule?',
enabled: 'Enabled',
disabled: 'Disabled',
ungrouped: 'Ungrouped',
groupPlaceholder: 'Select a prompt group',
contentPlaceholder: 'Enter prompt content, variables supported',
},
task: {
basicSection: 'I Basic Information',
advancedSection: 'I Advanced Settings',
name: 'Task name',
namePlaceholder: 'Use a simple name so the task is easy to identify later.',
prompt: 'Select Prompt',
promptPlaceholder: 'Select a prompt',
createPrompt: 'New Prompt',
platforms: 'Publish platforms',
platformsHint:
'Synced from Media Management. This field is optional and supports multiple selection.',
platformConnected: 'Connected',
platformUnauthorized: 'Unauthorized',
platformEmptyTitle: 'No publish platforms',
platformEmptyHint:
'No platform data is available yet. Please verify the Media Management setup first.',
publishSection: 'Publish Settings',
autoPublish: 'Auto publish',
autoPublishHint: 'When enabled, scheduled articles enter the publish queue after generation.',
publishAccounts: 'Media accounts',
publishAccountsHint:
'Choose specific accounts. Offline clients queue first and continue after reconnecting.',
publishAccountEmptyTitle: 'No media accounts',
publishAccountEmptyHint:
'Bind media accounts in the desktop client before configuring auto publish.',
cover: 'Cover image',
coverHint: 'Keep the cover clear, complete, and visually polished.',
scheduleCoverHint:
'Cover is off by default. Enable it to save a cover to generated articles for publishing.',
scheduleCoverRequiredHint:
'A selected account platform requires a cover image before publishing.',
coverUpload: 'Upload cover image',
coverUploadHint: 'Local preview only for now',
scheduleCoverUploadHint: 'Choose from local files or the asset library',
source: 'Generation source',
sourcePromptRule: 'Custom Prompt',
sourceKolTemplate: 'Refined Template',
kolTemplate: 'Refined template',
kolTemplatePlaceholder: 'Select a subscribed refined template',
kolTemplateEmptyTitle: 'No refined templates available',
kolTemplateEmptyHint:
'This account has no active subscribed refined template package yet. Subscribe in the marketplace first.',
scheduleSection: 'Schedule Policy',
kolInputSection: 'Refined Variables',
kolWebSearch: 'Web search',
kolWebSearchHint: 'Enable it when this refined template allows web search.',
kolKnowledge: 'Knowledge base',
kolKnowledgePlaceholder: 'Optional. Select your knowledge groups for generation',
scheduleTime: 'Schedule article generation',
scheduleEveryDay: 'Every day',
enableWebSearch: 'Enable web search for generation',
generateCount: 'Article count',
submit: 'Create task',
},
group: {
title: 'Rule Groups',
createTitle: 'Create Group',
editTitle: 'Edit Group',
deleteConfirm: 'Deleting this group will move its rules to ungrouped. Continue?',
name: 'Group name',
allRules: 'All Rules',
},
schedule: {
name: 'Task name',
rule: 'Prompt rule',
target: 'Target',
plan: 'Schedule',
cron: 'Frequency',
frequency: 'Frequency',
kindDaily: 'Every day',
kindWeekly: 'Weekdays',
weekdaysLabel: 'Run days',
executionTime: 'Run time',
executionTimeHint:
'New tasks default to a random time between 01:00 and 05:00 to smooth overnight load. You can edit it before saving.',
executionTimeDefault: 'Default staggered time',
to: 'to',
autoPublishPlatforms: 'Auto publish platforms',
autoPublish: 'Auto publish',
manualPublish: 'Manual publish',
nextRun: 'Next run',
dispatchStatus: 'Last dispatch',
dispatchSuccess: 'Success',
dispatchFailed: 'Failed',
dispatchPartialSuccess: 'Partial success',
notDispatched: 'Not dispatched',
footerHint:
'New tasks start with a random time between 01:00 and 05:00, then run at the saved time.',
startAt: 'Start time',
endAt: 'End time',
brand: 'Brand',
createTitle: 'Create Scheduled Task',
editTitle: 'Edit Scheduled Task',
deleteConfirm: 'Delete this scheduled task?',
enabled: 'Enabled',
disabled: 'Disabled',
enableAction: 'Enable',
disableAction: 'Disable',
cronOptions: {
daily: 'Once daily',
twiceDaily: 'Twice daily',
weekly: 'Once weekly',
custom: 'Custom Cron',
},
weekdays: {
mon: 'Mon',
tue: 'Tue',
wed: 'Wed',
thu: 'Thu',
fri: 'Fri',
sat: 'Sat',
sun: 'Sun',
},
},
instant: {
title: 'Instant Generate',
createTitle: 'Create Instant Task',
selectRule: 'Select prompt rule',
selectBrand: 'Select brand',
selectPlatform: 'Target platform',
submit: 'Generate now',
extraParams: 'Extra parameters',
name: 'Task name',
executionStatus: 'Execution status',
executionTime: 'Execution time',
createdTime: 'Created time',
generatedArticles: 'Generated article links',
articleLinksEmpty: 'No generated articles',
openArticle: 'Open article',
empty: 'No instant tasks yet.',
},
filters: {
promptRule: 'Prompt rule',
publishStatus: 'Publish status',
generateStatus: 'Generation status',
title: 'Title',
generateTime: 'Generation time',
status: 'Status',
name: 'Name',
namePlaceholder: 'Search by task name',
createdTime: 'Created time',
},
article: {
titleColumn: 'Article title',
titleGenerating: 'Generating title',
},
messages: {
ruleCreated: 'Rule created.',
ruleUpdated: 'Rule updated.',
ruleDeleted: 'Rule deleted.',
ruleEnabled: 'Rule enabled.',
ruleDisabled: 'Rule disabled.',
groupCreated: 'Group created.',
groupUpdated: 'Group updated.',
groupDeleted: 'Group deleted.',
scheduleCreated: 'Scheduled task created.',
scheduleUpdated: 'Scheduled task updated.',
scheduleDeleted: 'Scheduled task deleted.',
scheduleEnabled: 'Scheduled task enabled.',
scheduleDisabled: 'Scheduled task disabled.',
generateSubmitted: 'Generation task submitted.',
missingTaskName: 'Enter a task name first.',
missingPromptRule: 'Choose a prompt first.',
missingKolTemplate: 'Choose a subscribed refined template first.',
invalidGenerateCount: 'Article count must be at least 1.',
invalidScheduleTime: 'Choose a valid schedule time.',
invalidRandomWindow: 'The schedule time configuration is invalid.',
missingScheduleDays: 'Select at least one run day.',
missingPublishAccounts: 'Choose at least one media account when auto publish is enabled.',
missingScheduleCover: 'A selected media account platform requires a cover image.',
missingPromptName: 'Enter a prompt name first.',
missingPromptContent: 'Enter prompt content first.',
},
},
featureStub: {
eyebrow: 'Feature Placeholder',
currentStatus: 'Current status',
nextPriority: 'Next priority',
integrationStrategy: 'Integration strategy',
currentStatusText: 'The page shell is ready with navigation and auth guard support.',
integrationStrategyText:
'Keep the UI aligned with tenant-api envelopes and wire real read flows before write flows.',
},
images: {
title: 'Image Management',
description: 'Manage image library with folder organization and reference analysis.',
uploadBtn: 'Upload Image',
folders: 'Folders',
uncategorized: 'Uncategorized',
searchPlaceholder: 'Search image name...',
newFolder: 'New Folder',
folderName: 'Folder Name',
rename: 'Rename',
move: 'Move',
deleteImage: 'Delete Image',
deleteFolder: 'Delete Folder',
forceDelete: 'Force Delete',
confirmDeleteTitle: 'Confirm Delete',
confirmDeleteImage: 'Are you sure you want to delete this image? This action cannot be undone.',
confirmDeleteFolder: 'Confirm delete folder {name}?',
imageInUse: 'Image is in use',
folderHasRefs:
'This folder contains {count} images. They may already be referenced by articles. Deleting the folder will also delete these images permanently.',
refArticleBody: 'Body reference',
refArticleCover: 'Cover reference',
storageUsage: 'Storage Usage',
storageUsageDetail: '{used} / {total} ({percent}%)',
quotaExceeded: 'Storage is full, please clean up before uploading more.',
uploadSuccess: 'Image uploaded successfully',
uploadReusedSuccess: 'Matching image already exists in the library and was reused',
uploadFailed: 'Image upload failed',
deleteSuccess: 'Deleted successfully',
folderCreated: 'Folder created successfully',
folderRenamed: 'Folder renamed successfully',
folderDeleted: 'Folder deleted',
imageRenamed: 'Image renamed successfully',
imageMoved: 'Image moved successfully',
noImages: 'No images yet. Click upload to start.',
allFolders: 'All Folders',
selectImage: 'Select Image',
libraryTab: 'Library',
},
} as const
export default enUS