7f059dbd45
Migrate keyboard dictation to continuous Flow sessions with auto-start, tap-to-toggle recording, 60s countdown, five-step onboarding, and App Group IPC. Add docs/ GitHub Pages site with en/zh privacy policy for App Store compliance.
186 lines
9.0 KiB
Plaintext
186 lines
9.0 KiB
Plaintext
/* OSGKeyboard · English localization (development language) */
|
||
|
||
"OSGKeyboard" = "OSGKeyboard";
|
||
|
||
/* Onboarding */
|
||
"onboarding.welcome.subtitle" = "Tap to talk. Tap again to finish — polished text in any app.";
|
||
"onboarding.enable.fullAccessNote" = "Full Access lets the keyboard reach the microphone and your LLM API. We never log what you type.";
|
||
"onboarding.permission.mic.title" = "Microphone access";
|
||
"onboarding.permission.mic.body" = "Required for voice input. Audio is processed on your device for transcription.";
|
||
"onboarding.permission.mic.allow" = "Allow microphone";
|
||
"onboarding.permission.mic.deniedHint" = "Microphone was denied. Open Settings to enable it, or tap Next to continue.";
|
||
"onboarding.permission.speech.title" = "Speech recognition";
|
||
"onboarding.permission.speech.body" = "On-device speech recognition turns your voice into text. Audio never leaves your device.";
|
||
"onboarding.permission.speech.allow" = "Allow speech recognition";
|
||
"onboarding.permission.speech.deniedHint" = "Speech recognition was denied. Open Settings to enable it, or tap Next to continue.";
|
||
"onboarding.permission.openSettings" = "Open Settings";
|
||
"onboarding.permission.status.undetermined" = "Not requested yet";
|
||
"onboarding.permission.status.granted" = "Allowed";
|
||
"onboarding.permission.status.denied" = "Denied";
|
||
"legal.privacyPolicy" = "Privacy Policy";
|
||
"onboarding.enable.title" = "Enable OSGKeyboard";
|
||
"onboarding.enable.step1" = "Settings → General → Keyboard → Keyboards";
|
||
"onboarding.enable.step2" = "Tap “Add New Keyboard…” and choose OSGKeyboard";
|
||
"onboarding.enable.step3" = "Tap OSGKeyboard and enable “Allow Full Access”";
|
||
"onboarding.enable.step4" = "Allow Full Access is required for the microphone and LLM calls.";
|
||
"onboarding.enable.openSettings" = "Open iOS Settings";
|
||
"onboarding.api.title" = "Choose engine";
|
||
"onboarding.api.subtitle" = "Local needs no API key; Cloud polishes your text via LLM.";
|
||
"onboarding.api.localReady.title" = "No API key needed";
|
||
"onboarding.api.localReady.body" = "Local recognition is ready to use. Tap Done to start.";
|
||
|
||
/* Common navigation */
|
||
"common.back" = "Back";
|
||
"common.next" = "Next";
|
||
"common.done" = "Done";
|
||
"common.continue" = "Continue";
|
||
"common.reset" = "Reset";
|
||
"common.cancel" = "Cancel";
|
||
"common.delete" = "Delete";
|
||
"common.space" = "Space";
|
||
"common.newline" = "Return";
|
||
|
||
/* Privacy footnote (onboarding welcome page) */
|
||
"privacy.audio.title" = "Audio stays on device";
|
||
"privacy.audio.body" = "Transcribed locally with Apple’s speech engine.";
|
||
"privacy.network.title" = "Only the polished text is sent";
|
||
"privacy.network.body" = "Sent to your chosen LLM to add structure & punctuation.";
|
||
"privacy.universal.title" = "Works everywhere";
|
||
"privacy.universal.body" = "WeChat, Notes, Mail, ChatGPT, Claude, Cursor — anywhere a keyboard appears.";
|
||
|
||
/* Home */
|
||
"home.status.ready" = "Ready";
|
||
"home.status.setupIncomplete" = "Setup incomplete";
|
||
"home.hero.label" = "Tap to configure";
|
||
"home.action.enableInSettings" = "Enable in iOS Settings";
|
||
"home.action.editApi" = "Edit API Configuration";
|
||
"home.action.keyboardPreview" = "Keyboard Preview (Debug)";
|
||
"home.action.openSettingsA11y" = "Open OSGKeyboard settings";
|
||
|
||
/* API settings */
|
||
"api.baseUrl" = "Base URL";
|
||
"api.model" = "Model";
|
||
"api.getKey" = "Get an API key";
|
||
"api.key" = "API Key";
|
||
"api.key.placeholder" = "sk-…";
|
||
"api.key.show" = "Show";
|
||
"api.key.hide" = "Hide";
|
||
"api.connection" = "Connection";
|
||
"api.test.idle" = "Test connection";
|
||
"api.test.running" = "Testing…";
|
||
"api.test.success" = "Success · Retry";
|
||
"api.test.failure" = "Failed · Retry";
|
||
"api.test.connected" = "Connected";
|
||
"api.test.missing" = "API key missing";
|
||
"api.test.rateLimited" = "Rate limited (429)";
|
||
"api.test.http" = "HTTP %d";
|
||
"api.test.network" = "Network error";
|
||
"api.test.connectedWith" = "“%@”";
|
||
"api.test.transportWith" = "%@";
|
||
|
||
/* Settings */
|
||
"settings.title" = "Settings";
|
||
"settings.reset.title" = "Reset all settings?";
|
||
"settings.reset.message" = "API key, model, and base URL will be cleared.";
|
||
"settings.reset.confirm" = "Reset all settings";
|
||
"settings.engine.title" = "Engine";
|
||
"settings.engine.subtitle" = "Pick the recognition engine. Local engine does transcription only, no API key needed.";
|
||
"settings.engine.local.title" = "On-device";
|
||
"settings.engine.local.ios26" = "Always on-device, no network.";
|
||
"settings.engine.local.legacy" = "On-device ASR. Transcription only, no polish.";
|
||
"settings.engine.cloud.title" = "Cloud polish";
|
||
"settings.engine.cloud.subtitle" = "ASR + LLM polish. API key required.";
|
||
"settings.provider.title" = "Provider";
|
||
"settings.provider.subtitle" = "Pick the LLM that polishes your dictation.";
|
||
"settings.api.title" = "API";
|
||
"settings.language.title" = "Language";
|
||
"settings.language.subtitle.cloud" = "Recognition language and text processing mode.";
|
||
"settings.language.subtitle.local" = "Recognition language.";
|
||
"settings.mode.title" = "Mode";
|
||
"settings.mode.off" = "Off";
|
||
"settings.mode.transcribe" = "Transcribe";
|
||
"settings.mode.polish" = "Polish";
|
||
"settings.systemPrompt.title" = "System Prompt";
|
||
"settings.systemPrompt.reset" = "Reset";
|
||
"settings.asrLocale" = "ASR locale";
|
||
"settings.engineBadge.ios26" = "SpeechAnalyzer — always on-device";
|
||
"settings.engineRow.title" = "Recognition engine";
|
||
"settings.onDeviceOnly.title" = "On-device only";
|
||
"settings.onDeviceOnly.body" = "Disable cloud fallback. The keyboard reports an error instead of going online.";
|
||
"settings.legend.onDevice" = "On-device";
|
||
"settings.legend.cloudFallback" = "Cloud fallback";
|
||
"settings.privacy.title" = "Privacy";
|
||
"settings.privacy.policy" = "Privacy Policy";
|
||
"settings.privacy.fullAccess.title" = "About Full Access";
|
||
"settings.privacy.fullAccess.body" = "Full Access is required for the microphone and to read your API key. OSGKeyboard does not record or upload what you type with the keyboard.";
|
||
|
||
/* App group error */
|
||
"appGroup.error.title" = "App Group not configured";
|
||
"appGroup.error.body" = "OSGKeyboard needs an App Group to share config between the main app and the keyboard extension.";
|
||
"appGroup.error.step1" = "Create group.com.osgkeyboard.shared in the Apple Developer portal";
|
||
"appGroup.error.step2" = "Enable it for both the main app and the keyboard extension";
|
||
"appGroup.error.step3" = "Re-generate the provisioning profile and download it";
|
||
|
||
/* Keyboard preview */
|
||
"preview.title" = "Keyboard Preview";
|
||
"preview.subtitle" = "Tap Start/Stop Recording to test here. On the real keyboard, tap the mic disc to dictate.";
|
||
"preview.placeholder" = "Type here or tap the record button";
|
||
"preview.placeholder" = "Type here or tap the record button";
|
||
"preview.clear" = "Clear text";
|
||
"preview.openSettingsA11y" = "Open OSGKeyboard settings";
|
||
"preview.modeChip.cycle" = "Cycle input mode";
|
||
"preview.localeChip.cycle" = "Cycle recognition language";
|
||
"preview.error.audioSession" = "Audio session error: %@";
|
||
"preview.error.micUnavailable" = "Microphone unavailable (hw format %.0f Hz / %d ch)";
|
||
"preview.error.formatCreate" = "Failed to create 16 kHz audio format.";
|
||
"preview.error.converterCreate" = "Failed to create audio converter.";
|
||
"preview.error.engineStart" = "Engine start failed: %@";
|
||
|
||
/* Keyboard (ext) */
|
||
"keyboard.placeholder.idle" = "Tap to talk";
|
||
"keyboard.placeholder.preparing" = "Preparing";
|
||
"keyboard.placeholder.processing" = "Processing";
|
||
"keyboard.placeholder.error" = "Polishing failed";
|
||
"keyboard.placeholder.localBadge" = "On-device";
|
||
"keyboard.rec" = "REC";
|
||
"keyboard.space" = "Space";
|
||
"keyboard.denied.mic" = "Mic denied";
|
||
"keyboard.denied.speech" = "Speech denied";
|
||
"keyboard.openSettingsA11y" = "Open OSGKeyboard settings";
|
||
"keyboard.deniedHint" = "Opens the OSGKeyboard settings page where you can grant microphone or speech recognition access.";
|
||
"keyboard.tapToTalkA11y" = "Tap to talk";
|
||
|
||
/* Mode chip labels (used in both ext + preview stub) */
|
||
"mode.off" = "Off";
|
||
"mode.transcribe" = "Transcribe";
|
||
"mode.polish" = "Polish";
|
||
|
||
/* Locale chip labels (preview stub) */
|
||
"locale.zh-Hans" = "ZH-Hans";
|
||
|
||
/* Locale menu items (settings) */
|
||
"locale.auto" = "Auto";
|
||
"locale.zh-Hans" = "Chinese (Simplified)";
|
||
"locale.zh-Hant" = "Chinese (Traditional)";
|
||
"locale.en-US" = "English (US)";
|
||
"locale.ja-JP" = "Japanese";
|
||
"locale.ko-KR" = "Korean";
|
||
|
||
/* Flow session */
|
||
"flow.error.noSpeech" = "No speech detected. Please try again.";
|
||
"keyboard.denied.mic" = "Microphone access denied";
|
||
"keyboard.denied.speech" = "Speech recognition denied";
|
||
|
||
/* Home · Flow session */
|
||
"home.flow.active" = "Voice session active";
|
||
"home.flow.inactive" = "Voice session inactive";
|
||
"home.flow.hint" = "Voice session starts automatically. Switch to any app and tap the keyboard mic to dictate.";
|
||
"home.flow.starting" = "Starting voice session…";
|
||
"home.flow.openSettings" = "Open Settings to grant permissions";
|
||
"home.flow.start" = "Start voice session";
|
||
"home.flow.end" = "End voice session";
|
||
"flow.error.speechRequired" = "Speech recognition access is required for voice sessions.";
|
||
"flow.error.micRequired" = "Microphone access is required for background voice sessions.";
|
||
"flow.error.micUnavailable" = "Microphone is unavailable on this device.";
|
||
"flow.error.audioUnavailable" = "Could not start background audio.";
|