feat: add Brazilian Portuguese locale and configurable token pricing

Enable Portuguese-speaking users with full pt-BR translations and let users
set per-million token rates so home cost estimates reflect their actual pricing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Usuario Exemplo
2026-09-14 18:47:23 -03:00
co-authored by Cursor
parent 3b37c33607
commit 0ce64e20ba
16 changed files with 1133 additions and 176 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ import { normalizePath, type Plugin } from "vite"
const traverse = traverseModule.default ?? traverseModule
const SOURCE_LOCALE = "zh-CN"
const SUPPORTED_LOCALES = ["zh-CN", "en-US"]
const SUPPORTED_LOCALES = ["zh-CN", "en-US", "pt-BR"]
const CHINESE_SOURCE_PATTERN = /[\u3400-\u9fff]/u
const PLACEHOLDER_PATTERN = /\{([A-Za-z_][A-Za-z0-9_]*)\}/g
const AUTO_IMPORT_NAME = "__staticI18nT"
@@ -1,4 +1,5 @@
import { formatCompactInteger, formatInteger } from "../../../shared/utils/numberFormat";
import { useAppStore } from "../../../shared/store/appStore";
import { Icon } from "../../../shared/ui/Icon";
import { useTooltip, type TooltipAnchor } from "../../../shared/ui/Tooltip";
import { informationOutlineIcon } from "../../../shared/ui/icons";
@@ -15,13 +16,6 @@ export type HomeMetricsData = {
cacheWriteTokens: number;
};
const TOKEN_PRICE_PER_MILLION = {
input: 5,
output: 25,
cacheRead: 0.5,
cacheWrite: 6.25,
} as const;
function formatMetricValue(value: number) {
const full = formatInteger(value);
const compact = formatCompactInteger(value);
@@ -66,6 +60,7 @@ function InfoTooltip({ content }: { content: string }) {
}
export function HomeMetrics({ data, refreshVersion = 0 }: { data: HomeMetricsData; refreshVersion?: number }) {
const { pricing } = useAppStore();
const inputTokens = Math.max(0, data.promptTokens - data.cacheReadTokens - data.cacheWriteTokens);
const outputTokens = Math.max(0, data.tokenUsage - data.promptTokens);
const defaultCacheHitRate = calculateRate(data.cacheReadTokens, data.cacheReadTokens + inputTokens);
@@ -75,10 +70,10 @@ export function HomeMetrics({ data, refreshVersion = 0 }: { data: HomeMetricsDat
);
const successfulCallRate = calculateRate(data.successfulCalls, data.llmCalls);
const costs = {
input: priceTokens(inputTokens, TOKEN_PRICE_PER_MILLION.input),
output: priceTokens(outputTokens, TOKEN_PRICE_PER_MILLION.output),
cacheRead: priceTokens(data.cacheReadTokens, TOKEN_PRICE_PER_MILLION.cacheRead),
cacheWrite: priceTokens(data.cacheWriteTokens, TOKEN_PRICE_PER_MILLION.cacheWrite),
input: priceTokens(inputTokens, pricing.input_per_million),
output: priceTokens(outputTokens, pricing.output_per_million),
cacheRead: priceTokens(data.cacheReadTokens, pricing.cache_read_per_million),
cacheWrite: priceTokens(data.cacheWriteTokens, pricing.cache_write_per_million),
};
const totalCost = costs.input + costs.output + costs.cacheRead + costs.cacheWrite;
const cacheCost = costs.cacheRead + costs.cacheWrite;
@@ -111,27 +106,27 @@ export function HomeMetrics({ data, refreshVersion = 0 }: { data: HomeMetricsDat
t("缓存读写已计入提示词侧统计。"),
].join("\n");
const costTooltip = [
t("按 Claude Opus 4.7 价格估算。"),
t("按配置的 Token 价格估算。"),
t("缓存统计策略:默认口径({rate})", { rate: formatRate(defaultCacheHitRate) }),
"",
t("普通输入:{tokens} × ${price}/1M = {cost}", {
tokens: formatMetricValue(inputTokens),
price: TOKEN_PRICE_PER_MILLION.input,
price: pricing.input_per_million,
cost: formatUSD(costs.input),
}),
t("模型输出:{tokens} × ${price}/1M = {cost}", {
tokens: formatMetricValue(outputTokens),
price: TOKEN_PRICE_PER_MILLION.output,
price: pricing.output_per_million,
cost: formatUSD(costs.output),
}),
t("缓存读取:{tokens} × ${price}/1M = {cost}", {
tokens: formatMetricValue(data.cacheReadTokens),
price: TOKEN_PRICE_PER_MILLION.cacheRead,
price: pricing.cache_read_per_million,
cost: formatUSD(costs.cacheRead),
}),
t("缓存写入:{tokens} × ${price}/1M = {cost}", {
tokens: formatMetricValue(data.cacheWriteTokens),
price: TOKEN_PRICE_PER_MILLION.cacheWrite,
price: pricing.cache_write_per_million,
cost: formatUSD(costs.cacheWrite),
}),
"",
@@ -0,0 +1,165 @@
import { useEffect, useState } from "react";
import type { TokenPricingSettings } from "../../shared/api";
import { appStore, DEFAULT_TOKEN_PRICING, useAppStore } from "../../shared/store/appStore";
import { Button } from "../../shared/ui/Button";
import { FormField, TextInput } from "../../shared/ui/FormControls";
import { TitledCard } from "../../shared/ui/TitledCard";
import { useMessage } from "../../shared/ui/message";
import styles from "./ProxySettingsCard.module.scss";
type PricingDraft = {
input_per_million: string;
output_per_million: string;
cache_read_per_million: string;
cache_write_per_million: string;
};
function toDraft(pricing: TokenPricingSettings): PricingDraft {
return {
input_per_million: String(pricing.input_per_million),
output_per_million: String(pricing.output_per_million),
cache_read_per_million: String(pricing.cache_read_per_million),
cache_write_per_million: String(pricing.cache_write_per_million),
};
}
function formatPrice(value: number) {
return `$${value}`;
}
function parsePrice(value: string, label: string) {
const price = Number(value);
if (!Number.isFinite(price) || price < 0) {
throw new Error(t("{label}必须是非负数", { label }));
}
return price;
}
function toSettings(draft: PricingDraft): TokenPricingSettings {
return {
input_per_million: parsePrice(draft.input_per_million, t("输入价格")),
output_per_million: parsePrice(draft.output_per_million, t("输出价格")),
cache_read_per_million: parsePrice(draft.cache_read_per_million, t("缓存读取价格")),
cache_write_per_million: parsePrice(draft.cache_write_per_million, t("缓存写入价格")),
};
}
export function PricingSettingsCard() {
const { pricing } = useAppStore();
const message = useMessage();
const [draft, setDraft] = useState<PricingDraft>(() => toDraft(pricing));
const [editing, setEditing] = useState(false);
const [saving, setSaving] = useState(false);
useEffect(() => {
if (!editing) setDraft(toDraft(pricing));
}, [pricing, editing]);
const edit = () => {
setDraft(toDraft(pricing));
setEditing(true);
};
const cancel = () => {
setDraft(toDraft(pricing));
setEditing(false);
};
const save = async () => {
try {
setSaving(true);
const next = toSettings(draft);
if (await appStore.updatePricingSettings(next)) {
setEditing(false);
message(t("定价设置已保存"));
}
} catch (cause) {
message(cause instanceof Error ? cause.message : String(cause));
} finally {
setSaving(false);
}
};
const restoreDefault = () => {
setDraft(toDraft(DEFAULT_TOKEN_PRICING));
};
const action = editing ? (
<div className={styles.actionGroup}>
<Button size="small" disabled={saving} onClick={restoreDefault}>{t("恢复默认")}</Button>
<Button size="small" disabled={saving} onClick={cancel}>{t("取消")}</Button>
<Button variant="primary" size="small" disabled={saving} onClick={() => void save()}>
{saving ? t("保存中…") : t("保存")}
</Button>
</div>
) : (
<button type="button" className={styles.headerAction} onClick={edit}>{t("编辑")}</button>
);
return (
<TitledCard title={t("Token 定价")} action={action}>
<div className={styles.content}>
<small>{t("用于首页价值估算的 Token 单价,单位:美元 / 百万 Token。")}</small>
{editing ? (
<div className={styles.customFields}>
<FormField label={t("输入价格($/1M)")}>
<TextInput
type="number"
min={0}
step="any"
value={draft.input_per_million}
onChange={(event) => setDraft({ ...draft, input_per_million: event.target.value })}
/>
</FormField>
<FormField label={t("输出价格($/1M)")}>
<TextInput
type="number"
min={0}
step="any"
value={draft.output_per_million}
onChange={(event) => setDraft({ ...draft, output_per_million: event.target.value })}
/>
</FormField>
<FormField label={t("缓存读取价格($/1M)")}>
<TextInput
type="number"
min={0}
step="any"
value={draft.cache_read_per_million}
onChange={(event) => setDraft({ ...draft, cache_read_per_million: event.target.value })}
/>
</FormField>
<FormField label={t("缓存写入价格($/1M)")}>
<TextInput
type="number"
min={0}
step="any"
value={draft.cache_write_per_million}
onChange={(event) => setDraft({ ...draft, cache_write_per_million: event.target.value })}
/>
</FormField>
</div>
) : (
<>
<div className={styles.row}>
<strong>{t("输入价格($/1M)")}</strong>
<span className={styles.value}>{formatPrice(pricing.input_per_million)}</span>
</div>
<div className={styles.row}>
<strong>{t("输出价格($/1M)")}</strong>
<span className={styles.value}>{formatPrice(pricing.output_per_million)}</span>
</div>
<div className={styles.row}>
<strong>{t("缓存读取价格($/1M)")}</strong>
<span className={styles.value}>{formatPrice(pricing.cache_read_per_million)}</span>
</div>
<div className={styles.row}>
<strong>{t("缓存写入价格($/1M)")}</strong>
<span className={styles.value}>{formatPrice(pricing.cache_write_per_million)}</span>
</div>
</>
)}
</div>
</TitledCard>
);
}
@@ -4,6 +4,7 @@ import { PageContent } from "../../shell/layout/PageContent";
import { LegacyModelImport } from "../models/LegacyModelImport";
import { AppLifecycleSettingsCard } from "./AppLifecycleSettingsCard";
import { CommitSettingsCard } from "./CommitSettingsCard";
import { PricingSettingsCard } from "./PricingSettingsCard";
import { ProxySettingsCard } from "./ProxySettingsCard";
import { TabSettingsCard } from "./TabSettingsCard";
import { Button } from "../../shared/ui/Button";
@@ -231,6 +232,7 @@ export function SettingsPage() {
<ProxySettingsCard settings={outboundProxy} draft={proxyDraft} editing={editingProxy} saving={savingProxy} onDraftChange={setProxyDraft} onEdit={editProxy} onCancel={cancelProxyEdit} onSave={() => void saveProxy()} />
<TabSettingsCard settings={tabSettings} draft={tabDraft} editing={editingTab} saving={savingTab} onDraftChange={setTabDraft} onEdit={editTab} onCancel={cancelTabEdit} onSave={() => void saveTab()} />
<CommitSettingsCard />
<PricingSettingsCard />
<AppLifecycleSettingsCard />
<LegacyModelImport>{({ busy, previewing, open }) => <TitledCard title={t("导入")}>
<div className={styles.importRow}>
@@ -247,7 +249,7 @@ export function SettingsPage() {
<div className={styles.settingRow}>
<div>
<strong>{t("界面语言")}</strong>
<small>{t("默认跟随操作系统;不支持的系统语言使用英文。当前:{language}", { language: locale === "zh-CN" ? "简体中文" : "English" })}</small>
<small>{t("默认跟随操作系统;不支持的系统语言使用英文。当前:{language}", { language: locale === "zh-CN" ? "简体中文" : locale === "pt-BR" ? "Português (Brasil)" : "English" })}</small>
</div>
<div className={styles.languageControl}>
<Select
@@ -257,6 +259,7 @@ export function SettingsPage() {
{ value: "system", label: t("跟随系统") },
{ value: "zh-CN", label: "简体中文" },
{ value: "en-US", label: "English" },
{ value: "pt-BR", label: "Português (Brasil)" },
]}
onChange={(value) => setLocalePreference(value as LocalePreference)}
/>
File diff suppressed because it is too large Load Diff
+13 -1
View File
@@ -27,8 +27,10 @@
"0e41f8e3d59ec47b": "Storage management",
"0e67021ebf0a3580": "Import complete: added {imported} models and skipped {skipped} existing models",
"0ec1e85b0c3cfa65": "Call details",
"0ecfbbe0697af7ea": "Input price ($/1M)",
"100fad4a0b3ab781": "Last 24 hours",
"105a9082c346f958": "Testing…",
"12430375c0db4727": "Estimated using configured token pricing.",
"124be3f86f197802": "Token usage",
"12ae77e6202d063e": "Custom Headers",
"133340e53175128a": "Test all",
@@ -100,6 +102,7 @@
"3a3f595df70ec8ff": "Clear storage",
"3a5040b68abf75f9": "Select all",
"3a8c76b2ce785f96": "Review and import",
"3b63f1f9d5922e65": "Cache write price ($/1M)",
"3b67824289b5fa1e": "Dock icon hidden",
"3c94b4c75940c178": "Input Tokens",
"3cfae5728b92b334": "Token usage: {tokens}",
@@ -117,6 +120,7 @@
"43cb41d62de2d179": "Proxy requires authentication",
"461d6a57900c2ed7": "Connectivity test failed: {error}",
"470049252e54de6a": "Success rate: {rate}",
"4791868cb0a4be4d": "Output price",
"47d1c20aa017ff05": "Hide the main window on startup and keep only the tray icon.",
"48a3bf87eb254591": "Start sign-in",
"48b970b568a7f8f9": "Proxy settings",
@@ -141,10 +145,12 @@
"5401344227e49e2f": "TAB settings",
"54644705e9c61009": "Port settings",
"54c53e5fe791d1f3": "Initialize CA",
"54d735fcd15e8c93": "Output price ($/1M)",
"54e6745ff43c9c74": "Unable to save model order",
"550eddc3c7fefa99": "Sponsored",
"552a5d4baf45d878": "Commit Message Model Settings",
"56432ba297009bdc": "Initialize the CA first",
"565678b3704a383d": "Pricing settings saved",
"56627c94a9decee6": "Maximum output tokens",
"576d81bb0631b165": "Import",
"5886afc1c71df1fe": "Shown in the Cursor model description.",
@@ -163,6 +169,7 @@
"6003d3246f0fca2b": "Model management",
"6078a681a306930d": "Cache write",
"609640f72d422b57": "Quick time ranges",
"60e7671141df2731": "Input price",
"61a4c7bac12dc125": "Failed calls: {count}",
"61c7d1f758b647d5": "Call information",
"621f63a5f08384ac": "Cache read: {tokens}",
@@ -177,6 +184,7 @@
"656ab25e264cc4e4": "No models are available to Cursor yet",
"65a6318e07ec1e07": "Tools",
"65cb9a7b4f620b6b": "Prompt {tokens}",
"66f7ceff962da68c": "Token unit prices used for the home page estimated value. Unit: USD per million tokens.",
"680680288a6d2ad2": "Show in Dock",
"68102220092c1f0f": "Detailed records cleared",
"68ad603fafe4e0d6": "Import legacy configuration",
@@ -259,6 +267,7 @@
"9fb48101d237ff96": "Last week",
"a026f37e613cf48b": "Output Tokens",
"a03a1a0cb35414f8": " must be an integer from 0 to 65535",
"a0ad0c340abf41c7": "Cache read price",
"a0c42c24e74f8380": "{name} Copy",
"a12ee6a3e98a29c2": "Hide sensitive content",
"a1a42cd9b16e2162": "Application",
@@ -389,16 +398,18 @@
"e9d8d890d33584e8": "No reset cards available.",
"ea26b760e930a7ca": "Call observability",
"eb11e2df1d8ae387": "Provider URL",
"eb1be07f2ca6e506": "Estimated using Claude Opus 4.7 pricing.",
"eb4a3db23661fb52": "Applies to every model in this group and is used as the badge label in Cursor's model picker; clear it to fall back to the server domain.",
"eb77492c9f76a7e1": "The install command has been copied. Click “Open terminal”, paste it into the terminal, and enter your password when prompted.",
"eba54690937bc532": "Manage accounts",
"ec917db99e814b58": "{label} must be a non-negative number",
"ed31fbb483ee1b0a": "Actions",
"edc70de18c6da1a6": "Install local CA",
"ee239f3943293f87": "Sunday",
"ee6b89a6a740a4c4": "If a port is occupied, a new random port is selected and saved automatically. Restart the app after changing these settings.",
"eec6bf2dad677b9f": "Granted: {time}",
"ef5d9908c45f4b88": "Cache read price ($/1M)",
"f4694c46b1e19602": "Final request type",
"f4a0b686421619eb": "Cache write price",
"f4dcb6a3ceb32247": "Page {page} of {count}",
"f4f0ead1116b5b62": "Enabled",
"f4fa9f31ea2ae58d": "Token usage calendar for the past year",
@@ -425,6 +436,7 @@
"fd415f8e0097c832": "Cache reads and writes are included in prompt-side statistics.",
"fd77192739703811": "Bulk import",
"fdc4cabc370fa3f7": "No options",
"fe6ec799e02ed9a7": "Token pricing",
"fea405f9b01d1416": "Summary",
"fec45092945f8790": "User guide",
"fec7210590309465": "Clear all statistics",
+446
View File
@@ -0,0 +1,446 @@
{
"0006d696d8e1ec28": "Novo",
"00929f23850e4ff0": "Chamadas com sucesso: {count}",
"01f3e69a5a9b2c9b": "A chave necessária para acessar o serviço do modelo.",
"023810003eb4563d": "{count} modelos",
"028a4de61bff743d": "Entrada padrão: {tokens} × ${price}/1M = {cost}",
"028c60a8a8e30a1b": "Página {page} / {total}",
"03ff62ab4b818492": "Gravação em cache: {tokens} × ${price}/1M = {cost}",
"051836569928a9f9": "Editar",
"0525054436acdb6e": "Prompt da mensagem de commit",
"05468af47054d488": "Teste de conectividade do modelo {model} realizado com sucesso ({duration} ms)",
"0580e0a99a6f1afc": "Artefatos",
"06619f339fa0ab46": "Preparando o runtime de plugins",
"076832c1b2de22c3": "Gravação em cache: {tokens}",
"07879e064ae16542": "Saída estimada: {tokens}",
"07c657ed4747126e": "Parâmetros adicionais da Anthropic",
"08791ba06e7441de": "{accounts} contas · {models} modelos",
"092b520558eff5f2": "Não testado",
"099008ea7a42ebd1": "Todos os valores de cabeçalhos personalizados devem ser strings",
"09ebc2643631ba25": "Valor estimado",
"0b96da34f6fbdd3b": "Leitura de cache: {tokens} × ${price}/1M = {cost}",
"0bbb2c0ce279d6d5": "Nenhum modelo sincronizado ainda",
"0c70665b6eb65f1a": "Não",
"0c72229b7db0e1a9": "Saída do modelo",
"0d2dab3d62eb73d6": "Todas as estatísticas foram limpas",
"0d5e2bdb15579fc4": "Mensagens",
"0e41f8e3d59ec47b": "Gerenciamento de armazenamento",
"0e67021ebf0a3580": "Importação concluída: {imported} modelos adicionados e {skipped} modelos existentes ignorados",
"0ec1e85b0c3cfa65": "Detalhes da chamada",
"0ecfbbe0697af7ea": "Preço de entrada ($/1M)",
"100fad4a0b3ab781": "Últimas 24 horas",
"105a9082c346f958": "Testando…",
"12430375c0db4727": "Estimado com base nos preços de tokens configurados.",
"124be3f86f197802": "Uso de tokens",
"12ae77e6202d063e": "Cabeçalhos personalizados",
"133340e53175128a": "Testar tudo",
"13a9ac7a68c5fd96": "A CA é armazenada apenas neste dispositivo e é usada para inspecionar com segurança as requisições HTTPS do Cursor.",
"13b61c5f697b6700": "Taxa de acerto de cache",
"146da2e2a991493e": "Obtendo…",
"15730c19fd7eef51": "Protocolo de requisição",
"168e845a86bc3703": "Adicionar modelo",
"16d0d7e2b332af72": "Total de chamadas: {count}",
"1813d362a82fd437": "Maximizar janela",
"18165f8865eacc91": "Nenhum plugin instalado",
"19658d9fa9aa8de4": "Instalando…",
"19bb071f8c362695": "Configurações de prompt",
"1a3f0617d6de8e52": "Nome de usuário",
"1a60c9eb3cf1dbb5": "Importação concluída: {added} adicionados, {updated} atualizados",
"1aa65c55c6cc6163": "Código do dispositivo",
"1ae6b0a0f8266382": "Fechar janela",
"1b5932b8946d2d68": "Excluir modelo",
"1b7d5b1a9315fc64": "Calculando…",
"1c6926877b1bbfb2": "Total de requisições: {tokens}",
"1cb7e646ac883fb2": "Porta do proxy",
"1cdde778cfe6a130": "Fórmula: leitura de cache / (leitura de cache + entrada não em cache)",
"1d19efc260a0a18f": "Usar cartão de redefinição",
"1d27f02ed278ebc9": "Arquivo de configuração",
"1f9b46e61efcccb5": "Filtro: {label}, {summary}",
"202064bb84804852": "Deixe em branco para usar o padrão.",
"20e14248fd4fb981": "{label} deve ser um número inteiro maior que 0",
"217cfe7db1e3d10a": "Seguir o sistema",
"21bd738e0d7191a7": "Carregando…",
"22c6b4eb4caee6ae": "Configurações de proxy salvas",
"22d7895ea5fca72e": "Por provedor",
"23ae7a90b1b9816d": "Escopo de limpeza",
"23e49479e15e6770": "Nova versão {version} disponível",
"2400fbd0aeab9e13": "Baixado {downloaded}",
"24a0a24864454575": "Já existe, ignorado",
"2555d6c7fbb7e070": "Insira o ID do modelo diretamente ou carregue os modelos retornados pela API.",
"29585d7193539200": "Versão atual {version}",
"296da37506328d89": "Desativar integração com o Cursor",
"29fbbef32a6eb58b": "Não mostrar este anúncio novamente",
"2a2773134a829016": "Agrupado pelo histórico de chamadas LLM; chamadas em andamento não são incluídas.",
"2caeaec539e78898": "Tokens de orçamento de pensamento",
"2cbc58108d78b06c": "Aguardando confirmação de autorização no navegador…",
"2cd0f3be8738a86c": "Cancelar",
"2cdf7d3275016cc2": "Desativar integração com o Cursor?",
"2d30c2a98ebb5278": "Atual: {rate}",
"2eb2bf7c6597ab9a": "Registros detalhados",
"2f280a8120c0db12": "Usado apenas para exibição na interface; não altera o nome do modelo enviado ao serviço.",
"2f4a361f878176d1": "{label} deve ser um JSON válido",
"2f4a9609285d8f49": "Configurações do TAB salvas",
"2f5f1d6fbfb061ed": "Não definido",
"2f6416a2c424856b": "URL final da requisição",
"2f7ba5fd1d12f7f9": "Abrir o tutorial de uso?",
"2f9daa828907b93f": "Excluir",
"2fe0e3339ac4d1bb": "Expirado",
"2fe5a8d0eee9f14c": "Inválido",
"303c30f301514250": "Pesquisar recursos",
"3260348163d03b8e": "Deixe em branco para manter inalterado",
"32896fdaaaa4c106": "Conta salva e catálogo de modelos sincronizado.",
"346ff60e6c7c5181": "Lendo…",
"36f33adaf0942634": "Confirmar",
"37125ef2e1d707cb": "Endereço do servidor ou URL completa da requisição, chave de API, nome do modelo, nome de exibição e observações são obrigatórios",
"378bb0eec39fa8a2": "Última página",
"37cb98ff4d5dcfcc": "Sucesso {successful} / Falha {failed}",
"382f2e3419a02fef": "Apenas limpar registros detalhados",
"38844b135cf70dfc": "Mais",
"393e1241552b1870": "Requisição",
"39f52eee100131d7": "Entrada em cache",
"3a0fb74abe2460b6": "Chunks",
"3a3f595df70ec8ff": "Limpar espaço de armazenamento",
"3a5040b68abf75f9": "Selecionar tudo",
"3a8c76b2ce785f96": "Revisar e importar",
"3b63f1f9d5922e65": "Preço de gravação em cache ($/1M)",
"3b67824289b5fa1e": "Ícone do Dock ocultado",
"3c94b4c75940c178": "Tokens de entrada",
"3cfae5728b92b334": "Uso de tokens: {tokens}",
"3d13868593ae4eeb": "Idioma da interface",
"3da0bf1610ff5db5": "Recomendados",
"3f6c25aa329163a4": "O caminho original do endpoint será adicionado a este endereço de serviço.",
"3fd118e2ffe0b2b6": "Cancelar todos os testes",
"3fd47edce45b3603": "Fechar",
"402495402ce333b1": "Reinicializar plugins",
"40a08e7cf320ae07": "Tem certeza de que deseja limpar os registros detalhados?",
"4125fc7ba333524c": "Claro padrão",
"42655ed8e4108ae2": "Entrada (não em cache)",
"42a1d9e5b037c210": "Bytes",
"42aa8e01e98c0d8c": "Duração total",
"43cb41d62de2d179": "O proxy requer autenticação",
"461d6a57900c2ed7": "Falha no teste de conectividade: {error}",
"470049252e54de6a": "Taxa de sucesso: {rate}",
"4791868cb0a4be4d": "Preço de saída",
"47d1c20aa017ff05": "Ocultar a janela principal ao iniciar com o sistema, mantendo apenas o ícone na bandeja.",
"48a3bf87eb254591": "Iniciar login",
"48b970b568a7f8f9": "Configurações de proxy",
"48d8db17bae06246": "{count} no total",
"492042ed1fdc29ed": "A versão {version} está pronta para ser instalada",
"4927a53bcc886afb": "Carregando…",
"497c85690c4cc0fc": "Nenhum dado disponível",
"499c729eb09aa2a6": "Tokens da janela de contexto",
"49be72e6045c007d": "Cancelar teste",
"4a861200ad513a3c": "Inicializar runtime de plugins",
"4a8d6841b4023edf": "Confirmar importação",
"4aca6a31090fe2b8": "Inicializando…",
"4b458e6e147221d7": "O caminho padrão do endpoint é adicionado automaticamente de acordo com o protocolo selecionado.",
"4d0680f9efaef147": "Não lido",
"4d99c976beb8827e": "Disponível",
"4e30d7c9ed2b0eee": "Não definir",
"4eafa9e925b30bcd": "Personalizado",
"51d04bc3d286f018": "Último dia civil",
"51de3bcec137ab1b": "Testes de conectividade concluídos com sucesso para todos os {count} modelos",
"5228358a6db59fe7": "Ex.: agora, 2026-08-23 18:00",
"5319e7374f78fb38": "Integrado",
"5401344227e49e2f": "Configurações do TAB",
"54644705e9c61009": "Configurações de porta",
"54c53e5fe791d1f3": "Inicializar CA",
"54d735fcd15e8c93": "Preço de saída ($/1M)",
"54e6745ff43c9c74": "Não foi possível salvar a ordenação dos modelos",
"550eddc3c7fefa99": "Patrocinado",
"552a5d4baf45d878": "Configurações do modelo de mensagem de commit",
"56432ba297009bdc": "Inicialize a CA primeiro",
"565678b3704a383d": "Configurações de preço salvas",
"56627c94a9decee6": "Tokens máximos de saída",
"576d81bb0631b165": "Importar",
"5886afc1c71df1fe": "Exibido na descrição do modelo no Cursor.",
"59346e82b3dd2998": "Endereço do serviço TAB",
"5a284a1a2be8da0e": "Lê modelos da configuração legada local. Modelos novos e existentes são exibidos antes da confirmação.",
"5a3bd99fa69a40c1": "Usar serviço público",
"5acb7d61688e3c4f": "Confirmar uso",
"5b17f59d33bde39e": "Erro: {error}",
"5ba65a74c4e792c5": "Por tipo",
"5c55a67935af8f45": "Todos",
"5c62e36c152dfc7c": "Runtime de plugins inicializado com sucesso",
"5d59857bf039cac9": "Assistente Cursor v{version}",
"5f8d556a9c47da3c": "Inicialização com o sistema desativada",
"5f9acfb945229062": "Tem certeza de que não deseja mais ver este anúncio?",
"5fd2ec5a6e9b654c": "Total: {cost}",
"6003d3246f0fca2b": "Gerenciamento de modelos",
"6078a681a306930d": "Gravação em cache",
"609640f72d422b57": "Intervalos de tempo rápidos",
"60e7671141df2731": "Preço de entrada",
"61a4c7bac12dc125": "Chamadas com falha: {count}",
"61c7d1f758b647d5": "Informações da chamada",
"621f63a5f08384ac": "Leitura de cache: {tokens}",
"6320b4a8722a851f": "Status",
"63c73c4730f4473e": "Aplicar",
"63d90d977348ab1f": "Duplicar",
"6449a43900b609a4": "Gerenciamento de modelos {name}",
"6478a5f1218c484e": "Use o aplicativo de desktop para copiar para a área de transferência",
"651f274470153a05": "Atualizações de software",
"652ec5d40c29fd6a": "Velocidade {speed} tokens/s · primeiro token {firstText} ms · tempo total {duration} ms · saída {tokens} tokens{estimated} · resposta: {output}",
"653b123c956d3bcb": "Chamadas",
"656ab25e264cc4e4": "Nenhum modelo disponível para o Cursor ainda",
"65a6318e07ec1e07": "Ferramentas",
"65cb9a7b4f620b6b": "Prompt {tokens}",
"66f7ceff962da68c": "Preços unitários de tokens usados no valor estimado da página inicial. Unidade: USD por milhão de tokens.",
"680680288a6d2ad2": "Exibir no Dock",
"68102220092c1f0f": "Registros detalhados limpos",
"68ad603fafe4e0d6": "Importar configuração legada",
"68ea5dd4d7af20e6": "Configurações do sistema",
"6a9906c79f26c0ba": "Horário de início",
"6aa8f49cc992dfd7": "Testar",
"6ae80538c2b2572d": "Minimizar janela",
"6d1876364ac6457d": "Modo do proxy",
"6e86570183c3cdd0": "Você já está na versão mais recente",
"7005693f4f050bce": "E/S de cache {cost}",
"72644ec4389da2f7": "Layout padrão",
"736c9dc2a04c65fd": "A configuração do modelo foi alterada. Atualize e tente novamente.",
"7392e20d61abaa07": "Também armazena requisições completas e respostas em fluxo; por padrão, apenas tempo, status e uso são gravados.",
"77c9e582e85583af": "Falha no teste",
"788db1cfec2a3db5": "Tema",
"7995087e5a3dfe66": "Restaurar janela",
"7a2229f6a6d330a5": "Abra um terminal no aplicativo de desktop para instalar a CA",
"7a3cec4ca715de80": "Estatísticas de chamadas",
"7ba2d6728fe2531b": "Confirmar limpeza",
"7c10d97162c96dbd": "Validando o runtime de plugins",
"7cea2f3c46565d29": "Parâmetros adicionais da OpenAI",
"7d9f043f8f7ab45c": "Versão {version} disponível nas Configurações",
"7e0891860c9e6374": "O endereço do serviço TAB é obrigatório",
"7e7df68f2a82e09e": "Importar a mesma configuração novamente não criará modelos duplicados. Modelos existentes são ignorados automaticamente.",
"7f3c8312816fe26a": "Atualizando…",
"7f68ebad19ba6bcd": "Verificar atualizações",
"802b0faf0ceb513e": "{label}: {percent}% restante",
"80a57e03f0717f91": "Não configurado",
"811a3b22a5a7f2d5": "Não foi possível conectar ao serviço de gerenciamento local",
"8213941f12320ce1": "Este sistema operacional ou arquitetura de CPU não é suportado no momento",
"83c4efccd9a6bf69": "Teste de conectividade cancelado: {successful} com sucesso, {failed} com falha",
"83e8d0b7aff2b394": "Baixado {downloaded} / {total}",
"83fcfb4c1f2c1641": "Obter modelos",
"842b9f11cdd96bda": "Iniciar com o sistema",
"843ac7e15a5047a7": "Confirmar importação da configuração legada de modelos",
"844b8cc8dff7c1d8": "Padrão",
"864597982c308d72": "Inicialização silenciosa ativada",
"86de7c4ee8fa7689": "Sincronizar modelos",
"8716e1344b0daddb": "Cursor Oficial",
"878a8ab176429a86": "Ver instruções",
"8911e4f1407d58cb": "Baixando o runtime de plugins",
"89a101b809be7cfc": "Este endereço é usado exatamente como informado, sem alterar nem adicionar caminhos à requisição.",
"8a8542f6964852dc": "Próxima página",
"8b6ff498515bcc2f": "Horário",
"8cbcf741e727dbf7": "Modelos",
"8ccaf87ddb9ca3f4": "Configuração legada",
"8d0c47eb9eac2d34": "Tipo de chamada",
"8df48894086d6fbd": "Motivo (opcional)",
"8e2d04638a11a7cb": "Determina apenas o formato da requisição e resposta; não altera o endereço da URL.",
"8f6f8d979c981ced": "Copiado",
"8f9b0d6cc477d334": "Escolha como o Cursor se conecta aos endpoints do TAB.",
"90800c48a1dd0655": "{label} deve ser um objeto JSON",
"919cb0ce0c8db4e7": "Deixe em branco para manter a senha atual",
"91aaf184cfc17ffd": "Visão geral",
"91af6e57e7453fbe": "Adicionar conta",
"92156a483d4ba248": "Apenas o conteúdo detalhado de requisições, respostas e anexos de rastreamento são excluídos; resumos de chamadas, métricas e configurações são mantidos.",
"92e26b27d5ea8f0e": "Falha ao verificar atualizações: {error}",
"9305c0e13642cab4": "Não integrado",
"940a168911ade998": "Itens por página",
"945fb1c67eca8493": "Instalando o runtime de plugins",
"946b3ffc02f026c0": "Tem certeza de que deseja excluir este modelo?",
"954ec984cd4f49d1": "Sincronizando…",
"966498853d801a52": "Conexão do TAB",
"96f7642963ca0dbf": "Ativar integração com o Cursor",
"9845c165151daee3": "Utilizado",
"9850ed41a5bfbb0c": "{count} selecionados",
"997ec8201c2adeda": "Abrir terminal para instalar CA",
"9a84733cc9ab1706": "Detalhes do recurso",
"9b1b7ed518ee401d": "O tutorial de uso será aberto no navegador padrão. Deseja continuar?",
"9b9bc9cd7c76406f": "Abrir página de autorização",
"9c41b3a9e12ac994": "Esforço de raciocínio",
"9db205c6055bacc4": "Falha na inicialização do runtime de plugins",
"9e356080c56877f8": "Inicialização silenciosa desativada",
"9e46da6923836182": "Ex.: 2026-08-23 09:00, há 1 hora",
"9ebeab8c4532d671": "Contas de {name}",
"9ec4caa5fe43b8e3": "Os plugins instalados aparecerão aqui.",
"9ed11266ead88f5b": "Verificando o arquivo baixado do runtime de plugins",
"9ef7da883941091c": "Conta salva, mas falha ao sincronizar modelos: {error}",
"9f6fee1aba17a565": "Idioma",
"9fb48101d237ff96": "Última semana",
"a026f37e613cf48b": "Tokens de saída",
"a03a1a0cb35414f8": " deve ser um número inteiro entre 0 e 65535",
"a0ad0c340abf41c7": "Preço de leitura de cache",
"a0c42c24e74f8380": "Cópia de {name}",
"a12ee6a3e98a29c2": "Ocultar conteúdo sensível",
"a1a42cd9b16e2162": "Configurações do aplicativo",
"a1b8c98f29374a2f": "Inicialização silenciosa",
"a3030bf8f16dc63c": "Salvar",
"a340bdf12a15fd80": "Todos os {count} modelos nesta configuração já existem; nenhuma importação necessária",
"a363743025795ec7": "Já inicializei, atualizar",
"a3ab741ceb188e9e": "Conteúdo da requisição não gravado. Ative os registros detalhados e tente novamente.",
"a49ffd73bc85333d": "Média",
"a4d222236dc1003d": "Falha ao cancelar o teste: {error}",
"a5fb6189a8ad011d": "Abrir tutorial",
"a621ab606db2a11f": "Senha",
"a66e11477dcc97c1": "Adicionar conta {name}",
"a693d69af48bfe48": "Salvar e testar",
"a748cc074f78de00": "Ver detalhes",
"a7617f42f898b2bf": "Usar URL completa da requisição",
"a8036485f9227f2c": "Arrastar para reordenar",
"a80b53f8848e6d27": "Falha ao instalar atualização: {error}",
"a98585871c5313ff": "Nome de exibição",
"ab9084a640fbb864": "Desmarcar todos",
"abecab6701177721": "Inicialização com o sistema ativada",
"ac58d0f9a3f8d389": "Insira observações sobre o modelo",
"ac69f68b7010ec79": "Baixar e instalar",
"ad6a60ee93d3ba3e": "Carregando detalhes da chamada…",
"ae2d0b7f79cea4a3": "Saída do modelo: {tokens} × ${price}/1M = {cost}",
"aecb952b1e6cce36": "Oculta o ícone do Dock quando desativado. Você ainda pode abrir o aplicativo pelo ícone da barra de menus.",
"aee88743413144a2": "Atualizar",
"affb73206cfa035d": "Expira em: {time}",
"b06325c5660f0c29": "Conexão direta",
"b16c3b2ecedd6fe1": "A integração com o Cursor está ativa. Adicione uma configuração de modelo para usar modelos BYOK.",
"b254ff315d861346": "Tente inicializar novamente",
"b2617bf9ae663752": "Configurações do grupo",
"b4411558b932266f": "Tipo de provedor",
"b4c9e08870d41aa2": "É necessário inicializar o runtime de plugins primeiro",
"b502b1d414664337": "Prompt: {tokens}",
"b5141d3d19e9a048": "Sim",
"b6725f218ebaef26": "Ícone do Dock exibido",
"b67e408132f4dbd7": "Tem certeza de que deseja limpar todas as estatísticas?",
"b75a46aad3e7c132": "Entrada não em cache: {tokens}",
"b79354009c614ae9": "Estatísticas",
"b86967982067d295": " (estimado)",
"b89a0e4584f27ab5": "Abrir terminal",
"b8c9b486c83b5778": "Não exibir anúncio",
"b9670c85a4ab939e": "Rota",
"b9af2de88d903be7": "Endereço do proxy",
"ba2e93e73037c71e": "Restaurar padrão",
"ba5865fbc734e672": "Por exemplo: Modelo principal",
"ba6403d22876d626": "Em resfriamento",
"baff6c144180b185": "Testes de conectividade concluídos: {successful} com sucesso, {failed} com falha",
"bb2b7736433ae867": "Rastreamento do Cursor",
"bb7efdcb6af6e805": "Escuro padrão",
"bda62ce1d5e4ace9": "Conte-nos o motivo",
"bda74b5674b6a57d": "Inicializar plugins",
"be961dc60ab610da": "Quando alterado, aplica-se a todos os modelos deste grupo; deixe em branco para manter a configuração atual de cada modelo.",
"bf57afd709694b55": "Intervalo de tempo da visão geral",
"bfc01caf9fe0c841": "Taxa de acerto de cache {rate}",
"c0b3fbff51ccc40b": "Concluído",
"c1e98892a77f7a19": "{count} itens/página",
"c3760858cdb6d9f4": "Corpo da requisição",
"c54863655e879b36": "O runtime de plugins não é suportado neste sistema operacional",
"c6e7e1a9da356efc": "Nenhum recurso ainda. Adicione um primeiro.",
"c7ea2c9bc43134bd": "Editar modelo",
"c8c14507b2d37395": "Intensidade de raciocínio",
"c8df3c14a003bfcd": "Não foi possível carregar os detalhes da chamada",
"c98e118e0a43f078": "Modelo",
"c9b9ae7a61444ab7": "Página anterior",
"c9d146d006993cc1": "Política de estatísticas de cache: padrão ({rate})",
"cb2f1709f983d2f4": "Nome do modelo",
"cb99f0138b032687": "A inicialização baixará e instalará o runtime de plugins.",
"cea1aafe9416de7b": "Cabeçalhos da requisição",
"cfae1a14d2120c57": "Modo detalhado",
"cfe085015632e9c8": "Porta do serviço de gerenciamento local usada pelo frontend desktop. Digite 0 para escolher uma porta aleatória ao iniciar.",
"d0bfccc77315d887": "Último mês",
"d1251cd752d4ec25": "Deixe em branco para usar adaptive thinking.",
"d1a3d72618d1ed27": "Todos os resumos de chamadas, conteúdos detalhados e registros de rastreamento serão excluídos. Configurações de modelo, CA e aplicativo não serão afetadas. Esta ação não pode ser desfeita.",
"d2d648bd1c94b7f9": "Autenticação",
"d2fcdde81f06645c": "Exportar em lote",
"d34335433395cd3a": "Iniciar o Cursor BYOK automaticamente ao fazer login no sistema.",
"d3716cc5a2f5a810": "Endereço do servidor",
"d3d21191f32e79a5": "Processando…",
"d507652243a2151e": "Mostrar conteúdo sensível",
"d58c88688e1a949d": "Predefinições comuns",
"d59e47070f7f358e": "Disponível para chamada",
"d60669bb26a22f5d": "Deixe em branco para usar o padrão",
"d6b1f203680f5496": "Deixe em branco para usar adaptive thinking",
"d71b0171c44b668a": "Desativar removerá a configuração de proxy local do Cursor. Se você precisa fazer login em uma conta oficial, geralmente não é necessário desativar; basta fazer login diretamente, pois os modelos BYOK e da conta oficial agora funcionam juntos perfeitamente. Deseja continuar desativando e limpando o proxy?",
"d766536c18e8e990": "O runtime de plugins {version} está instalado e pronto para uso.",
"d7e266bdc8064193": "Nome do grupo",
"d896c62fb6712bda": "Ativar {model}",
"d8c47e9776cf1082": "Menu principal",
"d8c589c455675b46": "Configurações de prompt salvas",
"da521d1c1cbd36af": "É necessária autorização para instalar o certificado",
"da7ae985487c38e6": "Última hora",
"daede9881787abe7": "Observações",
"db340a9896306d08": "Teste cancelado",
"dbd3596e4a86f3c2": "Modelos configurados",
"ddde16f8839da3ce": "Total de requisições",
"de8184da1ef88d03": "Configurado",
"de878020fe02f0e9": "O uso deste cartão o consumirá imediatamente e não poderá ser desfeito. Deseja continuar?",
"dea7749c4cd77e6d": "O total de tokens de requisição inclui o prompt e a saída do modelo.",
"df1baa9f706d970b": "A adicionar",
"df3d58c7d84b85f2": "Configurações",
"df8b71c74d9b8478": "Fluxo de resposta",
"dfb802238b38fbd4": "Ativado",
"e025f1ff71996425": "Definido",
"e049096ab5614581": "Este plugin não precisa de recursos.",
"e0fae77446a389a3": "Velocidade: {speed} tokens/s",
"e1295adecbb77755": "Fechar anúncio",
"e14115de7f7c5795": "Uso de tokens no último ano",
"e14f20d572c02611": "Sequência de chamadas do provedor",
"e17a5b9c90cda6ab": "Modelo duplicado",
"e18516550b9a5105": "Sem uso",
"e231f1f3428d1c93": "Solicitando código de autorização…",
"e24096c81b1a8af4": "A autorização foi recusada ou falhou.",
"e24ebe4a866d69bf": "Falha no teste: {error}",
"e25bf3f419bb68f0": "Histórico de chamadas",
"e2ebc59779f012ed": "Modelo de geração",
"e3fee05f688708b4": "Chamadas LLM",
"e4760c6a1df24f17": "URL completa da requisição",
"e5043c7a2b408271": "Últimos 10 minutos",
"e59ae97924d62f01": "Primeira página",
"e5b9961a0d5242e3": "Configurações de porta salvas. Reinicie o aplicativo para que tenham efeito.",
"e5c84c9aa7826566": "Não preparado",
"e77e3d58b0dcffaa": "Duração",
"e825a2a42c22380e": "Tipo de modelo",
"e828bd3a0151edc2": "A CA local deve ser confiada pelo sistema",
"e8b1268c1e3610f2": "Já existe",
"e9d8d890d33584e8": "Nenhum cartão de redefinição disponível.",
"ea26b760e930a7ca": "Observabilidade de chamadas",
"eb11e2df1d8ae387": "URL do provedor",
"eb4a3db23661fb52": "Aplica-se a todos os modelos deste grupo e é usado como rótulo de destaque no seletor de modelos do Cursor; limpe para voltar a exibir o domínio do servidor.",
"eb77492c9f76a7e1": "O comando de instalação foi copiado automaticamente. Clique em \"Abrir terminal\", cole o comando no terminal e insira sua senha quando solicitado.",
"eba54690937bc532": "Gerenciamento de contas",
"ec917db99e814b58": "{label} deve ser um número não negativo",
"ed31fbb483ee1b0a": "Ações",
"edc70de18c6da1a6": "Instalar CA local",
"ee239f3943293f87": "Domingo",
"ee6b89a6a740a4c4": "Se uma porta estiver ocupada, uma nova porta aleatória será selecionada e salva automaticamente. Reinicie o aplicativo após alterar essas configurações.",
"eec6bf2dad677b9f": "Concedido em: {time}",
"ef5d9908c45f4b88": "Preço de leitura de cache ($/1M)",
"f4694c46b1e19602": "Tipo final de requisição",
"f4a0b686421619eb": "Preço de gravação em cache",
"f4dcb6a3ceb32247": "Página {page} de {count}",
"f4f0ead1116b5b62": "Ativado",
"f4fa9f31ea2ae58d": "Calendário de uso de tokens do último ano",
"f50276449943286c": "Horário de término",
"f69273dbbebfb3a1": "Formatar",
"f6dc1b1641600dd0": "Importando…",
"f78265089144369a": "Plugins",
"f78413c36d36f090": "Por padrão segue o sistema operacional; idiomas não suportados usam inglês. Atual: {language}",
"f784b165bd3fcb0e": "Últimas 4 horas",
"f85537d1fd2ef6f6": "Filtros personalizados da visão geral",
"f95ea7f4c063eea7": "Desativado",
"f9615d05d8e18595": "Limpar filtro de {label}",
"f9aa11dbb15ce647": "Sábado",
"f9b55ca75425161b": "Conteúdo da resposta não gravado. Ative os registros detalhados e tente novamente.",
"fa5b4b8a751c7d1b": "Porta do proxy local usada pelo Cursor; digite 0 para selecionar aleatoriamente ao iniciar.",
"fac2a67ad87807c4": "Confirmar",
"fad86bf65f72c747": "Progresso do download",
"fb11aa6f29827095": "Verificando…",
"fbe8778fa8b9bab5": "É necessário inicializar a CA local primeiro",
"fc22d1ab9ac73c6f": "Verificando o runtime de plugins",
"fc3947ebe6b2177b": "Padrão {defaultRate} / inclui criação {reuseRate}",
"fc50d0b72bc871db": "Desativar integração",
"fcd311fd8ad42462": "Abrir lista de modelos",
"fd415f8e0097c832": "Leituras e gravações de cache já estão incluídas nas estatísticas do prompt.",
"fd77192739703811": "Importação em lote",
"fdc4cabc370fa3f7": "Nenhuma opção",
"fe6ec799e02ed9a7": "Preços de tokens",
"fea405f9b01d1416": "Visão geral",
"fec45092945f8790": "Tutorial de uso",
"fec7210590309465": "Limpar todas as estatísticas",
"ff509c9ba052a21c": "Salvando…",
"ff66b1c7e010bbc2": "Cole o comando de autorização no terminal e insira sua senha; ao concluir, clique no botão abaixo",
"ff673195f05fb056": "Porta do serviço"
}
+13 -1
View File
@@ -27,8 +27,10 @@
"0e41f8e3d59ec47b": "存储管理",
"0e67021ebf0a3580": "导入完成:新增 {imported} 个模型,跳过 {skipped} 个已存在模型",
"0ec1e85b0c3cfa65": "调用详情",
"0ecfbbe0697af7ea": "输入价格($/1M)",
"100fad4a0b3ab781": "近24小时",
"105a9082c346f958": "测试中…",
"12430375c0db4727": "按配置的 Token 价格估算。",
"124be3f86f197802": "Token 消耗",
"12ae77e6202d063e": "自定义 Headers",
"133340e53175128a": "一键测试",
@@ -100,6 +102,7 @@
"3a3f595df70ec8ff": "清理存储空间",
"3a5040b68abf75f9": "全选",
"3a8c76b2ce785f96": "查看并导入",
"3b63f1f9d5922e65": "缓存写入价格($/1M)",
"3b67824289b5fa1e": "已隐藏 Dock 栏图标",
"3c94b4c75940c178": "输入 Token",
"3cfae5728b92b334": "Token 用量:{tokens}",
@@ -117,6 +120,7 @@
"43cb41d62de2d179": "代理需要认证",
"461d6a57900c2ed7": "连通性测试失败:{error}",
"470049252e54de6a": "成功占比:{rate}",
"4791868cb0a4be4d": "输出价格",
"47d1c20aa017ff05": "开机启动时不显示主窗口,仅保留系统托盘图标。",
"48a3bf87eb254591": "开始登录",
"48b970b568a7f8f9": "代理设置",
@@ -141,10 +145,12 @@
"5401344227e49e2f": "TAB 设置",
"54644705e9c61009": "端口设置",
"54c53e5fe791d1f3": "初始化 CA",
"54d735fcd15e8c93": "输出价格($/1M)",
"54e6745ff43c9c74": "排序失败",
"550eddc3c7fefa99": "推广",
"552a5d4baf45d878": "Commit 提交代码模型设置",
"56432ba297009bdc": "请先初始化 CA",
"565678b3704a383d": "定价设置已保存",
"56627c94a9decee6": "最大输出 Token",
"576d81bb0631b165": "导入",
"5886afc1c71df1fe": "显示在 Cursor 模型说明中。",
@@ -163,6 +169,7 @@
"6003d3246f0fca2b": "模型管理",
"6078a681a306930d": "缓存写入",
"609640f72d422b57": "快捷时间范围",
"60e7671141df2731": "输入价格",
"61a4c7bac12dc125": "异常调用:{count}",
"61c7d1f758b647d5": "调用信息",
"621f63a5f08384ac": "缓存读取:{tokens}",
@@ -177,6 +184,7 @@
"656ab25e264cc4e4": "还没有可供 Cursor 使用的模型",
"65a6318e07ec1e07": "工具数",
"65cb9a7b4f620b6b": "提示词 {tokens}",
"66f7ceff962da68c": "用于首页价值估算的 Token 单价,单位:美元 / 百万 Token。",
"680680288a6d2ad2": "在 Dock 栏显示",
"68102220092c1f0f": "详细记录已清理",
"68ad603fafe4e0d6": "导入旧版配置",
@@ -259,6 +267,7 @@
"9fb48101d237ff96": "近一周",
"a026f37e613cf48b": "输出 Token",
"a03a1a0cb35414f8": "必须是 0–65535 之间的整数",
"a0ad0c340abf41c7": "缓存读取价格",
"a0c42c24e74f8380": "{name} 副本",
"a12ee6a3e98a29c2": "隐藏敏感内容",
"a1a42cd9b16e2162": "应用设置",
@@ -389,16 +398,18 @@
"e9d8d890d33584e8": "没有可用的重置卡。",
"ea26b760e930a7ca": "调用观测",
"eb11e2df1d8ae387": "上游地址",
"eb1be07f2ca6e506": "按 Claude Opus 4.7 价格估算。",
"eb4a3db23661fb52": "应用于该分组下的全部模型,并作为 Cursor 模型选择器中的徽章标签;清空则恢复显示服务器域名。",
"eb77492c9f76a7e1": "安装命令已自动复制。点击“打开终端”,将命令粘贴到终端中执行,并按提示输入密码。",
"eba54690937bc532": "账号管理",
"ec917db99e814b58": "{label}必须是非负数",
"ed31fbb483ee1b0a": "操作",
"edc70de18c6da1a6": "安装本地 CA",
"ee239f3943293f87": "周日",
"ee6b89a6a740a4c4": "端口被占用时会自动选择新的随机端口并保存。修改后需要重启软件才会生效。",
"eec6bf2dad677b9f": "发放时间:{time}",
"ef5d9908c45f4b88": "缓存读取价格($/1M)",
"f4694c46b1e19602": "最终请求类型",
"f4a0b686421619eb": "缓存写入价格",
"f4dcb6a3ceb32247": "第 {page} / {count} 页",
"f4f0ead1116b5b62": "启用",
"f4fa9f31ea2ae58d": "过去一年的 Token 用量日历",
@@ -425,6 +436,7 @@
"fd415f8e0097c832": "缓存读写已计入提示词侧统计。",
"fd77192739703811": "批量导入",
"fdc4cabc370fa3f7": "暂无选项",
"fe6ec799e02ed9a7": "Token 定价",
"fea405f9b01d1416": "概览",
"fec45092945f8790": "使用教程",
"fec7210590309465": "清理全部统计数据",
+3 -1
View File
@@ -1,7 +1,8 @@
import zhCN from "./locales/zh-CN.json";
import enUS from "./locales/en-US.json";
import ptBR from "./locales/pt-BR.json";
export type Locale = "zh-CN" | "en-US";
export type Locale = "zh-CN" | "en-US" | "pt-BR";
export type TranslationValue = string | number;
export type TranslationParams = Readonly<Record<string, TranslationValue>>;
@@ -9,6 +10,7 @@ const sourceMessages = zhCN as Record<string, string>;
const localeMessages: Record<Locale, Record<string, string>> = {
"zh-CN": sourceMessages,
"en-US": enUS as Record<string, string>,
"pt-BR": ptBR as Record<string, string>,
};
let currentMessages: Record<string, string> = {};
+2 -1
View File
@@ -14,7 +14,7 @@ let initialized = false;
let snapshot: I18nSnapshot = { preference: "system", locale: "en-US" };
function isLocale(value: string | null): value is Locale {
return value === "zh-CN" || value === "en-US";
return value === "zh-CN" || value === "en-US" || value === "pt-BR";
}
export function resolveSystemLocale(
@@ -24,6 +24,7 @@ export function resolveSystemLocale(
): Locale {
const normalized = languages[0]?.toLowerCase() ?? "";
if (normalized === "zh" || normalized.startsWith("zh-")) return "zh-CN";
if (normalized === "pt" || normalized.startsWith("pt-")) return "pt-BR";
if (normalized === "en" || normalized.startsWith("en-")) return "en-US";
return "en-US";
}
+9
View File
@@ -161,6 +161,13 @@ export interface CommitSettingsView extends CommitSettings {
default_prompt: string;
}
export interface TokenPricingSettings {
input_per_million: number;
output_per_million: number;
cache_read_per_million: number;
cache_write_per_million: number;
}
export type PluginRuntimeState = "uninitialized" | "initializing" | "ready" | "failed" | "unsupported";
export type PluginRuntimePhase = "checking" | "downloading" | "verifying" | "installing" | "validating";
@@ -545,4 +552,6 @@ export const api = {
setDesktopSettings: (settings: DesktopSettings) => request<DesktopSettings>("/settings/desktop", { method: "PUT", body: JSON.stringify(settings) }),
commitSettings: (locale: Locale) => request<CommitSettingsView>("/settings/commit", { headers: { "accept-language": locale } }),
setCommitSettings: (settings: CommitSettings) => request<CommitSettingsView>("/settings/commit", { method: "PUT", body: JSON.stringify(settings) }),
pricingSettings: () => request<TokenPricingSettings>("/settings/pricing"),
setPricingSettings: (settings: TokenPricingSettings) => request<TokenPricingSettings>("/settings/pricing", { method: "PUT", body: JSON.stringify(settings) }),
};
+23 -3
View File
@@ -1,13 +1,21 @@
import { useSyncExternalStore } from "react";
import { api, type CursorHarnessStatus, type LlmCall, type Model, type ModelInput, type Overview, type PluginDescriptor, type PluginRuntimeStatus, type PortSettings } from "../api";
import { api, type CursorHarnessStatus, type LlmCall, type Model, type ModelInput, type Overview, type PluginDescriptor, type PluginRuntimeStatus, type PortSettings, type TokenPricingSettings } from "../api";
import { applyTheme, isThemeId, type ThemeId } from "../theme/theme";
export const DEFAULT_TOKEN_PRICING: TokenPricingSettings = {
input_per_million: 5.0,
output_per_million: 25.0,
cache_read_per_million: 0.5,
cache_write_per_million: 6.25,
};
export type AppSnapshot = {
models: Model[];
calls: LlmCall[];
overview: Overview;
detailed: boolean;
ports: PortSettings;
pricing: TokenPricingSettings;
busy: boolean;
error: string | null;
theme: ThemeId;
@@ -42,6 +50,7 @@ let snapshot: AppSnapshot = {
},
detailed: false,
ports: { proxy_port: 0, service_port: 0 },
pricing: DEFAULT_TOKEN_PRICING,
busy: false,
error: null,
theme: savedTheme(),
@@ -77,17 +86,18 @@ export const appStore = {
async refresh() {
update({ busy: true, error: null });
try {
const [models, calls, overview, settings, ports, cursorHarness, pluginRuntime, plugins] = await Promise.all([
const [models, calls, overview, settings, ports, pricing, cursorHarness, pluginRuntime, plugins] = await Promise.all([
api.models(),
api.calls(),
api.overview(),
api.observability(),
api.ports(),
api.pricingSettings(),
api.cursorHarness(),
api.pluginRuntime(),
api.plugins(),
]);
update({ models, calls, overview, detailed: settings.detailed, ports, cursorHarness, pluginRuntime, plugins });
update({ models, calls, overview, detailed: settings.detailed, ports, pricing, cursorHarness, pluginRuntime, plugins });
} catch (cause) {
update({ error: cause instanceof Error ? cause.message : String(cause) });
} finally {
@@ -256,6 +266,16 @@ export const appStore = {
return false;
}
},
async updatePricingSettings(pricing: TokenPricingSettings) {
try {
update({ error: null });
update({ pricing: await api.setPricingSettings(pricing) });
return true;
} catch (cause) {
update({ error: cause instanceof Error ? cause.message : String(cause) });
return false;
}
},
selectTheme(theme: ThemeId) {
localStorage.setItem("cursor-byok.theme", theme);
applyTheme(theme);