Files
OSGKeyboard/docs/index.html
T
Rocky cc8dd1070a feat: macOS architecture, cloud ASR/LLM providers, and 6-step iOS onboarding
- Add macOS menu-bar dictation app with local ASR models (SenseVoice/Qwen3),
  global Option hotkey, and bottom overlay
- Add cloud ASR/LLM providers (Anthropic, Volcengine, Bailian, and more) with
  provider logos, model listing, and connection checks
- Add shared 7-day usage stats UI (UsageStatsCluster / SevenDayUsageChart)
- Add iOS onboarding step 6 for polish LLM setup; hide custom-language-model
  diagnostic toggle behind DEBUG
- Unify iOS onboarding tagline with the macOS brand line ("开口即文字。")
- Rewrite README (Chinese-first, product-oriented) and refresh GitHub Pages
2026-07-11 19:10:20 +08:00

752 lines
31 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-Hans">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Primary SEO -->
<title>OSGKeyboard — 开口即文字 · iOS &amp; Mac 语音输入</title>
<meta name="description" content="OSGKeyboardiPhone、iPad、Mac 通用的语音输入工具。本地识别,AI 润色,任意 App 即说即写。Tap or hold Option — polished text lands at your cursor.">
<meta name="keywords" content="voice keyboard, dictation, speech to text, iOS keyboard, macOS dictation, 语音输入, 听写, OSGKeyboard, 开口即文字">
<meta name="author" content="OSGKeyboard">
<meta name="robots" content="index, follow, max-image-preview:large">
<meta name="theme-color" content="#0a0a0b">
<link rel="canonical" href="https://hkgood.github.io/OSGKeyboard/">
<link rel="icon" href="assets/app-icon.png" type="image/png">
<link rel="apple-touch-icon" href="assets/app-icon.png">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="OSGKeyboard">
<meta property="og:title" content="OSGKeyboard — 开口即文字 · iOS &amp; Mac 语音输入">
<meta property="og:description" content="本地识别,AI 润色,任意 App 即说即写。iPhone、iPad、Mac 通用。">
<meta property="og:url" content="https://hkgood.github.io/OSGKeyboard/">
<meta property="og:image" content="https://hkgood.github.io/OSGKeyboard/assets/app-icon.png">
<meta property="og:image:width" content="1024">
<meta property="og:image:height" content="1024">
<meta property="og:locale" content="en_US">
<meta property="og:locale:alternate" content="zh_CN">
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="OSGKeyboard — 开口即文字">
<meta name="twitter:description" content="iPhone、iPad、Mac 语音输入。本地识别,AI 润色,任意 App 即说即写。">
<meta name="twitter:image" content="https://hkgood.github.io/OSGKeyboard/assets/app-icon.png">
<!-- Structured data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "OSGKeyboard",
"operatingSystem": "iOS 26.0 or later, macOS 14.0 or later",
"applicationCategory": "UtilitiesApplication",
"url": "https://hkgood.github.io/OSGKeyboard/",
"image": "https://hkgood.github.io/OSGKeyboard/assets/app-icon.png",
"description": "Voice input for iPhone, iPad, and Mac. On-device recognition, AI polish, personal dictionary, and iCloud sync. Speak in any app — polished text lands at your cursor.",
"softwareVersion": "0.5.3",
"isAccessibleForFree": true,
"offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
"author": { "@type": "Organization", "name": "OSGKeyboard" },
"featureList": [
"Custom keyboard for iOS and iPadOS",
"macOS global dictation with Option hotkey",
"On-device speech recognition",
"AI text polish with multiple LLM providers",
"Personal dictionary with iCloud sync",
"Post-polish translation"
]
}
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,300,0,0" rel="stylesheet">
<style>
:root {
color-scheme: light dark;
--bg: #ffffff;
--bg-soft: #f7f7f8;
--text: #0c0c0e;
--text-secondary: #55555f;
--text-tertiary: #90909a;
--line: rgba(0, 0, 0, 0.08);
--accent: #2d8a4a;
--accent-soft: rgba(45, 138, 74, 0.10);
--nav-bg: rgba(255, 255, 255, 0.72);
--max: 1020px;
--radius: 18px;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0a0a0b;
--bg-soft: #131316;
--text: #f4f4f6;
--text-secondary: #a6a6b0;
--text-tertiary: #6e6e78;
--line: rgba(255, 255, 255, 0.10);
--accent: #4cc46e;
--accent-soft: rgba(76, 196, 110, 0.14);
--nav-bg: rgba(10, 10, 11, 0.72);
}
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
a { color: inherit; text-decoration: none; }
.material-symbols-outlined {
font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24;
line-height: 1;
user-select: none;
}
.wrap {
max-width: var(--max);
margin: 0 auto;
padding: 0 1.5rem;
}
/* Nav */
.nav {
position: sticky;
top: 0;
z-index: 20;
background: var(--nav-bg);
backdrop-filter: blur(20px) saturate(1.6);
-webkit-backdrop-filter: blur(20px) saturate(1.6);
border-bottom: 1px solid var(--line);
}
.nav-inner {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 60px;
gap: 1rem;
}
.brand {
display: flex;
align-items: center;
gap: 0.6rem;
font-weight: 650;
letter-spacing: -0.01em;
}
.brand img { width: 28px; height: 28px; border-radius: 7px; }
.nav-right { display: flex; align-items: center; gap: 0.5rem; }
.lang-toggle {
display: inline-flex;
padding: 2px;
border-radius: 999px;
border: 1px solid var(--line);
}
.lang-toggle button {
border: 0;
background: transparent;
color: var(--text-tertiary);
font: inherit;
font-size: 0.8rem;
font-weight: 600;
padding: 0.3rem 0.7rem;
border-radius: 999px;
cursor: pointer;
transition: color 0.2s, background 0.2s;
}
.lang-toggle button.active { background: var(--text); color: var(--bg); }
.ghost-link {
display: inline-flex;
align-items: center;
gap: 0.35rem;
font-size: 0.85rem;
font-weight: 600;
color: var(--text-secondary);
padding: 0.4rem 0.6rem;
border-radius: 999px;
transition: color 0.2s;
}
.ghost-link:hover { color: var(--text); }
.ghost-link .material-symbols-outlined { font-size: 18px; }
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: 0.45rem;
font-weight: 600;
font-size: 0.95rem;
padding: 0.75rem 1.3rem;
border-radius: 999px;
transition: transform 0.15s ease, opacity 0.15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn .material-symbols-outlined { font-size: 20px; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-quiet { color: var(--text); border: 1px solid var(--line); }
/* Hero */
.hero { padding: 5.5rem 0 3.5rem; }
.hero-grid {
display: grid;
grid-template-columns: 1.05fr 0.95fr;
gap: 3rem;
align-items: center;
}
@media (max-width: 860px) {
.hero { padding: 3.5rem 0 2.5rem; }
.hero-grid { grid-template-columns: 1fr; gap: 2.5rem; }
.hero-visual { order: -1; }
}
.eyebrow {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-size: 0.8rem;
font-weight: 600;
color: var(--accent);
margin-bottom: 1.25rem;
}
.eyebrow .material-symbols-outlined { font-size: 17px; }
h1 {
margin: 0 0 1.25rem;
font-size: clamp(2.3rem, 5.4vw, 3.6rem);
line-height: 1.05;
letter-spacing: -0.035em;
font-weight: 700;
}
.lead {
margin: 0 0 2rem;
font-size: 1.14rem;
color: var(--text-secondary);
max-width: 33rem;
}
.hero-cta { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-bottom: 1.75rem; }
.hero-meta {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1.25rem;
font-size: 0.85rem;
color: var(--text-tertiary);
}
.hero-meta span { display: inline-flex; align-items: center; gap: 0.35rem; }
.hero-meta .material-symbols-outlined { font-size: 17px; color: var(--accent); }
/* Phone mock */
.phone {
max-width: 300px;
margin: 0 auto;
border-radius: 40px;
padding: 10px;
background: var(--bg-soft);
border: 1px solid var(--line);
box-shadow: 0 40px 90px rgba(0, 0, 0, 0.18);
}
.phone-screen {
border-radius: 32px;
overflow: hidden;
background: #16161a;
display: flex;
flex-direction: column;
min-height: 440px;
}
.screen-top { padding: 1.3rem 1.2rem 0.4rem; color: #f4f4f6; }
.screen-app { font-size: 0.8rem; color: #8a8a94; margin: 0 0 0.15rem; }
.screen-line { font-size: 0.95rem; line-height: 1.5; margin: 0; color: #e8e8ec; }
.screen-caret { color: #4cc46e; font-weight: 700; }
.kb {
margin-top: auto;
background: #1e1e22;
border-top: 1px solid rgba(255,255,255,0.06);
padding: 0.9rem 0.9rem 1.1rem;
}
.kb-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem; }
.kb-chip {
font-size: 0.68rem;
font-weight: 600;
color: #cfcfd6;
padding: 0.28rem 0.6rem;
border-radius: 999px;
background: rgba(255,255,255,0.08);
display: inline-flex;
align-items: center;
gap: 0.3rem;
}
.kb-chip .material-symbols-outlined { font-size: 14px; }
.kb-mic {
width: 60px; height: 60px;
margin: 0.2rem auto 0;
border-radius: 50%;
background: var(--accent);
display: grid;
place-items: center;
color: #fff;
box-shadow: 0 0 0 8px var(--accent-soft);
position: relative;
}
.kb-mic .material-symbols-outlined { font-size: 28px; }
.kb-mic::after {
content: "";
position: absolute;
inset: -8px;
border-radius: 50%;
border: 2px solid var(--accent);
opacity: 0;
animation: ring 2.6s ease-out infinite;
}
@keyframes ring {
0% { transform: scale(0.85); opacity: 0.5; }
100% { transform: scale(1.55); opacity: 0; }
}
/* Section */
section.block { padding: 3.5rem 0; }
.block-head { max-width: 40rem; margin: 0 0 2.75rem; }
.block-head h2 {
margin: 0 0 0.6rem;
font-size: clamp(1.6rem, 3.2vw, 2.1rem);
letter-spacing: -0.025em;
font-weight: 700;
}
.block-head p { margin: 0; color: var(--text-secondary); font-size: 1.02rem; }
/* Features — light, editorial, no heavy cards */
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem 2.5rem;
}
@media (max-width: 780px) { .features { grid-template-columns: repeat(2, 1fr); gap: 2rem; } }
@media (max-width: 480px) { .features { grid-template-columns: 1fr; } }
.feature .ficon {
width: 44px; height: 44px;
border-radius: 12px;
background: var(--accent-soft);
color: var(--accent);
display: grid;
place-items: center;
margin-bottom: 0.9rem;
}
.feature .ficon .material-symbols-outlined { font-size: 24px; }
.feature h3 { margin: 0 0 0.35rem; font-size: 1.02rem; font-weight: 650; letter-spacing: -0.01em; }
.feature p { margin: 0; font-size: 0.93rem; color: var(--text-secondary); }
/* Steps */
.steps {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2.5rem;
counter-reset: s;
}
@media (max-width: 720px) { .steps { grid-template-columns: 1fr; gap: 2rem; } }
.step { position: relative; padding-top: 0.5rem; }
.step::before {
counter-increment: s;
content: counter(s);
display: grid;
place-items: center;
width: 30px; height: 30px;
border-radius: 50%;
border: 1.5px solid var(--accent);
color: var(--accent);
font-size: 0.85rem;
font-weight: 700;
margin-bottom: 0.85rem;
}
.step h3 { margin: 0 0 0.35rem; font-size: 1.05rem; font-weight: 650; }
.step p { margin: 0; color: var(--text-secondary); font-size: 0.95rem; }
/* Platforms */
.platforms {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1.25rem;
}
@media (max-width: 640px) { .platforms { grid-template-columns: 1fr; } }
.platform {
padding: 1.5rem;
border-radius: var(--radius);
border: 1px solid var(--line);
background: var(--bg-soft);
}
.platform-head {
display: flex;
align-items: center;
gap: 0.6rem;
margin-bottom: 0.75rem;
}
.platform-head .material-symbols-outlined { font-size: 22px; color: var(--accent); }
.platform h3 { margin: 0; font-size: 1.05rem; font-weight: 650; }
.platform p { margin: 0; font-size: 0.93rem; color: var(--text-secondary); line-height: 1.55; }
/* Closing */
.closing {
border-top: 1px solid var(--line);
border-bottom: 1px solid var(--line);
padding: 3.5rem 0;
}
.closing-inner {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 1.5rem;
}
.closing h2 { margin: 0 0 0.5rem; font-size: 1.5rem; letter-spacing: -0.02em; }
.closing p { margin: 0; color: var(--text-secondary); max-width: 34rem; }
.closing .lock { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--accent); font-weight: 600; font-size: 0.85rem; margin-bottom: 0.75rem; }
.closing .lock .material-symbols-outlined { font-size: 18px; }
/* Footer */
footer { padding: 2.5rem 0 3rem; color: var(--text-tertiary); font-size: 0.85rem; }
.footer-inner { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.75rem; align-items: center; }
.footer-links { display: flex; flex-wrap: wrap; gap: 1.1rem; }
.footer-links a { color: var(--text-secondary); }
.footer-links a:hover { color: var(--text); }
</style>
</head>
<body>
<header class="nav">
<div class="wrap nav-inner">
<a class="brand" href="#top">
<img src="assets/app-icon.png" width="28" height="28" alt="OSGKeyboard app icon">
OSGKeyboard
</a>
<div class="nav-right">
<div class="lang-toggle" role="group" aria-label="Language">
<button type="button" data-lang="en">EN</button>
<button type="button" class="active" data-lang="zh">中文</button>
</div>
<a class="ghost-link" href="https://github.com/hkgood/OSGKeyboard" rel="noopener">
<span class="material-symbols-outlined" aria-hidden="true">code</span>
<span data-i18n="nav.github">GitHub</span>
</a>
</div>
</div>
</header>
<main id="top">
<!-- Hero -->
<section class="hero">
<div class="wrap hero-grid">
<div>
<div class="eyebrow">
<span class="material-symbols-outlined" aria-hidden="true">verified</span>
<span data-i18n="hero.eyebrow">iOS · iPadOS · macOS</span>
</div>
<h1 data-i18n="hero.title">开口即文字。</h1>
<p class="lead" data-i18n="hero.lead">iPhone、iPad、Mac 通用的语音输入工具。本地识别,AI 润色,任意 App 即说即写。</p>
<div class="hero-cta">
<a class="btn btn-primary" href="https://github.com/hkgood/OSGKeyboard" rel="noopener">
<span class="material-symbols-outlined" aria-hidden="true">download</span>
<span data-i18n="hero.cta.primary">立即获取</span>
</a>
<a class="btn btn-quiet" href="privacy/">
<span class="material-symbols-outlined" aria-hidden="true">shield</span>
<span data-i18n="hero.cta.secondary">隐私政策</span>
</a>
</div>
<div class="hero-meta">
<span><span class="material-symbols-outlined" aria-hidden="true">devices</span><span data-i18n="hero.meta1">默认本地识别</span></span>
<span><span class="material-symbols-outlined" aria-hidden="true">auto_awesome</span><span data-i18n="hero.meta2">AI 自动润色</span></span>
<span><span class="material-symbols-outlined" aria-hidden="true">apps</span><span data-i18n="hero.meta3">任意 App 可用</span></span>
</div>
</div>
<div class="hero-visual">
<div class="phone">
<div class="phone-screen">
<div class="screen-top">
<p class="screen-app" data-i18n="mock.app">Notes</p>
<p class="screen-line" data-i18n="mock.line">Tomorrow at 3 PM, sync with the design team on the new onboarding flow.<span class="screen-caret">|</span></p>
</div>
<div class="kb">
<div class="kb-bar">
<span class="kb-chip"><span class="material-symbols-outlined" aria-hidden="true">devices</span><span data-i18n="mock.chipEngine">On-device</span></span>
<span class="kb-chip"><span class="material-symbols-outlined" aria-hidden="true">translate</span><span data-i18n="mock.chipTranslate">Translate</span></span>
</div>
<div class="kb-mic"><span class="material-symbols-outlined" aria-hidden="true">mic</span></div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Platforms -->
<section class="block wrap">
<div class="block-head">
<h2 data-i18n="platforms.title">两个平台,同一种体验</h2>
<p data-i18n="platforms.subtitle">手机上用键盘,Mac 上按住 Option — 说完即落字。</p>
</div>
<div class="platforms">
<div class="platform">
<div class="platform-head">
<span class="material-symbols-outlined" aria-hidden="true">smartphone</span>
<h3 data-i18n="platform.ios.t">iOS / iPadOS</h3>
</div>
<p data-i18n="platform.ios.b">自定义键盘 + Flow 会话。点按麦克风说话,连续听写不用跳 App。灵动岛显示录音状态。</p>
</div>
<div class="platform">
<div class="platform-head">
<span class="material-symbols-outlined" aria-hidden="true">laptop_mac</span>
<h3 data-i18n="platform.mac.t">macOS</h3>
</div>
<p data-i18n="platform.mac.b">菜单栏常驻,按住 Option 全局听写。底部浮层实时反馈,支持 SenseVoice / Qwen3 本地模型。</p>
</div>
</div>
</section>
<!-- Features -->
<section class="block wrap">
<div class="block-head">
<h2 data-i18n="features.title">开口即写,所需尽在此</h2>
<p data-i18n="features.subtitle">本地优先,AI 加持 — 从识别到润色,一条链路搞定。</p>
</div>
<div class="features">
<div class="feature">
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">mic</span></div>
<h3 data-i18n="feat.dictation.t">点按听写</h3>
<p data-i18n="feat.dictation.b">点一下开始,再点一下结束。单次最长 3.5 分钟,倒计时实时显示。</p>
</div>
<div class="feature">
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">devices</span></div>
<h3 data-i18n="feat.ondevice.t">本地识别</h3>
<p data-i18n="feat.ondevice.b">iOS 端侧 SpeechAnalyzerMac 可选 SenseVoice / Qwen3。默认不上传录音。</p>
</div>
<div class="feature">
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">auto_awesome</span></div>
<h3 data-i18n="feat.polish.t">AI 润色</h3>
<p data-i18n="feat.polish.b">自动补标点、整理结构。内置润色开箱即用,也可接入 DeepSeek、OpenAI 等 API。</p>
</div>
<div class="feature">
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">translate</span></div>
<h3 data-i18n="feat.translate.t">润色后翻译</h3>
<p data-i18n="feat.translate.b">润色完成后一键翻译为 English、中文、日本語、한국어 等。</p>
</div>
<div class="feature">
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">menu_book</span></div>
<h3 data-i18n="feat.dict.t">个性词库</h3>
<p data-i18n="feat.dict.b">人名、产品名、专业术语 — AI 润色时原样保留,iCloud 多设备同步。</p>
</div>
<div class="feature">
<div class="ficon"><span class="material-symbols-outlined" aria-hidden="true">cloud_sync</span></div>
<h3 data-i18n="feat.sync.t">iCloud 同步</h3>
<p data-i18n="feat.sync.b">设置、词库、听写历史在多设备间自动同步,换机无缝衔接。</p>
</div>
</div>
</section>
<!-- How it works -->
<section class="block wrap">
<div class="block-head">
<h2 data-i18n="steps.title">三步,开始第一句话</h2>
<p data-i18n="steps.subtitle">设置一次,之后在任意输入处开口即写。</p>
</div>
<div class="steps">
<div class="step">
<h3 data-i18n="step1.t">安装并授权</h3>
<p data-i18n="step1.b">iOS 添加键盘并开启完全访问;Mac 授予麦克风与辅助功能权限。</p>
</div>
<div class="step">
<h3 data-i18n="step2.t">选引擎与润色</h3>
<p data-i18n="step2.b">本地识别 + 内置润色零配置可用;也可填入自己的 API Key 接入任意兼容模型。</p>
</div>
<div class="step">
<h3 data-i18n="step3.t">开口说话</h3>
<p data-i18n="step3.b">切换到 OSGKeyboard 键盘,或按住 Option 键。润色好的文字自动插入光标处。</p>
</div>
</div>
</section>
<!-- Closing / privacy -->
<section class="closing">
<div class="wrap closing-inner">
<div>
<span class="lock"><span class="material-symbols-outlined" aria-hidden="true">lock</span><span data-i18n="close.badge">隐私优先</span></span>
<h2 data-i18n="close.title">你的声音,始终属于你</h2>
<p data-i18n="close.body">默认在设备端识别,录音不上传。润色只发送转写文字,不记录日常击键。云端引擎需你主动开启,并适用所配置服务商的隐私条款。</p>
</div>
<a class="btn btn-quiet" href="privacy/">
<span class="material-symbols-outlined" aria-hidden="true">description</span>
<span data-i18n="close.cta">查看隐私政策</span>
</a>
</div>
</section>
</main>
<footer class="wrap">
<div class="footer-inner">
<span data-i18n="footer.copy">© OSGKeyboard · v0.5.3 · 源码可见</span>
<span class="footer-links">
<a href="https://github.com/hkgood/OSGKeyboard" rel="noopener" data-i18n="footer.source">Source</a>
<a href="privacy/" data-i18n="footer.privacy">Privacy</a>
<a href="https://github.com/hkgood/OSGKeyboard/blob/main/LICENSE" rel="noopener" data-i18n="footer.license">License</a>
</span>
</div>
</footer>
<script>
const copy = {
en: {
"nav.github": "GitHub",
"hero.eyebrow": "iOS · iPadOS · macOS",
"hero.title": "Speak it. It's typed.",
"hero.lead": "Voice input for iPhone, iPad, and Mac. On-device recognition, AI polish — speak in any app.",
"hero.cta.primary": "Get it now",
"hero.cta.secondary": "Privacy",
"hero.meta1": "On-device by default",
"hero.meta2": "AI polish",
"hero.meta3": "Works in every app",
"mock.app": "Notes",
"mock.line": "Tomorrow at 3 PM, sync with the design team on the new onboarding flow.",
"mock.chipEngine": "Local",
"mock.chipTranslate": "Translate",
"platforms.title": "Two platforms, one experience",
"platforms.subtitle": "Keyboard on phone, hold Option on Mac — speak and it's typed.",
"platform.ios.t": "iOS / iPadOS",
"platform.ios.b": "Custom keyboard + Flow session. Tap the mic, dictate take after take without leaving your app. Live Activity on Dynamic Island.",
"platform.mac.t": "macOS",
"platform.mac.b": "Menu-bar app with global Option hotkey. Bottom overlay with live feedback. Optional SenseVoice / Qwen3 local models.",
"features.title": "Everything you need to type by voice",
"features.subtitle": "Local first, AI refined — recognition to polish in one flow.",
"feat.dictation.t": "Tap-to-talk",
"feat.dictation.b": "Tap to start, tap to stop. Up to 3.5 minutes per take with a live countdown.",
"feat.ondevice.t": "On-device recognition",
"feat.ondevice.b": "iOS SpeechAnalyzer; Mac SenseVoice / Qwen3 optional. Audio stays local by default.",
"feat.polish.t": "AI polish",
"feat.polish.b": "Punctuation and structure, three intensity levels. Built-in polish or bring your own DeepSeek / OpenAI API.",
"feat.translate.t": "Post-polish translation",
"feat.translate.b": "Translate into English, 中文, 日本語, 한국어 and more after polish.",
"feat.dict.t": "Personal dictionary",
"feat.dict.b": "Names, products, jargon — preserved verbatim by the AI, synced via iCloud.",
"feat.sync.t": "iCloud sync",
"feat.sync.b": "Settings, dictionary, and history sync across devices seamlessly.",
"steps.title": "Three steps to your first message",
"steps.subtitle": "Set up once, then dictate anywhere.",
"step1.t": "Install & authorize",
"step1.b": "Add the iOS keyboard with Full Access; grant mic + Accessibility on Mac.",
"step2.t": "Pick engine & polish",
"step2.b": "Local ASR + built-in polish works out of the box. Or add your own API key.",
"step3.t": "Start talking",
"step3.b": "Switch to OSGKeyboard, or hold Option on Mac. Polished text lands at your cursor.",
"close.badge": "Privacy first",
"close.title": "Your voice stays yours",
"close.body": "On-device recognition by default — audio is not uploaded. Polish receives text only; we never log keystrokes. Cloud engine requires explicit opt-in.",
"close.cta": "Read the privacy policy",
"footer.copy": "© OSGKeyboard · v0.5.3 · source available",
"footer.source": "Source",
"footer.privacy": "Privacy",
"footer.license": "License"
},
zh: {
"nav.github": "GitHub",
"hero.eyebrow": "iOS · iPadOS · macOS",
"hero.title": "开口即文字。",
"hero.lead": "iPhone、iPad、Mac 通用的语音输入工具。本地识别,AI 润色,任意 App 即说即写。",
"hero.cta.primary": "立即获取",
"hero.cta.secondary": "隐私政策",
"hero.meta1": "默认本地识别",
"hero.meta2": "AI 自动润色",
"hero.meta3": "任意 App 可用",
"mock.app": "备忘录",
"mock.line": "明天下午三点,和设计团队同步新引导流程。",
"mock.chipEngine": "本地",
"mock.chipTranslate": "翻译",
"platforms.title": "两个平台,同一种体验",
"platforms.subtitle": "手机上用键盘,Mac 上按住 Option — 说完即落字。",
"platform.ios.t": "iOS / iPadOS",
"platform.ios.b": "自定义键盘 + Flow 会话。点按麦克风说话,连续听写不用跳 App。灵动岛显示录音状态。",
"platform.mac.t": "macOS",
"platform.mac.b": "菜单栏常驻,按住 Option 全局听写。底部浮层实时反馈,支持 SenseVoice / Qwen3 本地模型。",
"features.title": "开口即写,所需尽在此",
"features.subtitle": "本地优先,AI 加持 — 从识别到润色,一条链路搞定。",
"feat.dictation.t": "点按听写",
"feat.dictation.b": "点一下开始,再点一下结束。单次最长 3.5 分钟,倒计时实时显示。",
"feat.ondevice.t": "本地识别",
"feat.ondevice.b": "iOS 端侧 SpeechAnalyzerMac 可选 SenseVoice / Qwen3。默认不上传录音。",
"feat.polish.t": "AI 润色",
"feat.polish.b": "自动补标点、整理结构。内置润色开箱即用,也可接入 DeepSeek、OpenAI 等 API。",
"feat.translate.t": "润色后翻译",
"feat.translate.b": "润色完成后一键翻译为 English、中文、日本語、한국어 等。",
"feat.dict.t": "个性词库",
"feat.dict.b": "人名、产品名、专业术语 — AI 润色时原样保留,iCloud 多设备同步。",
"feat.sync.t": "iCloud 同步",
"feat.sync.b": "设置、词库、听写历史在多设备间自动同步,换机无缝衔接。",
"steps.title": "三步,开始第一句话",
"steps.subtitle": "设置一次,之后在任意输入处开口即写。",
"step1.t": "安装并授权",
"step1.b": "iOS 添加键盘并开启完全访问;Mac 授予麦克风与辅助功能权限。",
"step2.t": "选引擎与润色",
"step2.b": "本地识别 + 内置润色零配置可用;也可填入自己的 API Key 接入任意兼容模型。",
"step3.t": "开口说话",
"step3.b": "切换到 OSGKeyboard 键盘,或按住 Option 键。润色好的文字自动插入光标处。",
"close.badge": "隐私优先",
"close.title": "你的声音,始终属于你",
"close.body": "默认在设备端识别,录音不上传。润色只发送转写文字,不记录日常击键。云端引擎需你主动开启,并适用所配置服务商的隐私条款。",
"close.cta": "查看隐私政策",
"footer.copy": "© OSGKeyboard · v0.5.3 · 源码可见",
"footer.source": "源代码",
"footer.privacy": "隐私",
"footer.license": "许可协议"
}
};
function applyLang(lang) {
const strings = copy[lang] || copy.zh;
document.documentElement.lang = lang === "zh" ? "zh-Hans" : "en";
document.querySelectorAll("[data-i18n]").forEach((el) => {
const value = strings[el.getAttribute("data-i18n")];
if (value == null) return;
el.textContent = value;
});
document.querySelectorAll(".lang-toggle button").forEach((btn) => {
btn.classList.toggle("active", btn.dataset.lang === lang);
});
try { localStorage.setItem("osg-lang", lang); } catch (_) {}
}
document.querySelectorAll(".lang-toggle button").forEach((btn) => {
btn.addEventListener("click", () => applyLang(btn.dataset.lang));
});
const saved = (() => { try { return localStorage.getItem("osg-lang"); } catch (_) { return null; } })();
applyLang(saved || "zh");
</script>
</body>
</html>