0

recorder: Add language selector dialog

If there're multiple languages available, we will use the language
selector dialog for users to set their transcript language in
onboarding.

Bug: b:376605365
Test: manually
Change-Id: Ic1031befcb3a28a358a3e668050b1f8b8fac3361
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5997734
Reviewed-by: Pi-Hsun Shih <pihsun@chromium.org>
Commit-Queue: Jennifer Ling <hsuanling@google.com>
Cr-Commit-Position: refs/heads/main@{#1379561}
This commit is contained in:
hsuanling
2024-11-07 10:00:10 +00:00
committed by Chromium LUCI CQ
parent 5cc6a239e2
commit bc3bab8307
18 changed files with 432 additions and 18 deletions

@ -46,6 +46,7 @@ const webui::LocalizedString kLocalizedStrings[] = {
IDS_RECORDER_GENAI_NEGATIVE_FEEDBACK_BUTTON_TOOLTIP},
{"genaiPositiveFeedbackButtonTooltip",
IDS_RECORDER_GENAI_POSITIVE_FEEDBACK_BUTTON_TOOLTIP},
{"languageDropdownHintOption", IDS_RECORDER_LANGUAGE_DROPDOWN_HINT_OPTION},
{"mainRecordingBarLandmarkAriaLabel",
IDS_RECORDER_MAIN_RECORDING_BAR_LANDMARK_ARIA_LABEL},
{"mainRecordingsListLandmarkAriaLabel",
@ -59,6 +60,14 @@ const webui::LocalizedString kLocalizedStrings[] = {
IDS_RECORDER_MIC_SELECTION_MENU_BUTTON_TOOLTIP},
{"micSelectionMenuChromebookAudioOption",
IDS_RECORDER_MIC_SELECTION_MENU_CHROMEBOOK_AUDIO_OPTION},
{"onboardingDialogLanguageSelectionCancelButton",
IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_CANCEL_BUTTON},
{"onboardingDialogLanguageSelectionDescription",
IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_DESCRIPTION},
{"onboardingDialogLanguageSelectionDownloadButton",
IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_DOWNLOAD_BUTTON},
{"onboardingDialogLanguageSelectionHeader",
IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_HEADER},
{"onboardingDialogSpeakerLabelAllowButton",
IDS_RECORDER_ONBOARDING_DIALOG_SPEAKER_LABEL_ALLOW_BUTTON},
{"onboardingDialogSpeakerLabelDeferButton",
@ -85,10 +94,16 @@ const webui::LocalizedString kLocalizedStrings[] = {
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DEFER_BUTTON},
{"onboardingDialogTranscriptionDescription",
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DESCRIPTION},
{"onboardingDialogTranscriptionDownloadButton",
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DOWNLOAD_BUTTON},
{"onboardingDialogTranscriptionHeader",
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_HEADER},
{"onboardingDialogTranscriptionTurnOnButton",
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_TURN_ON_BUTTON},
{"onboardingDialogTranscriptionTurnOnDescription",
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_TURN_ON_DESCRIPTION},
{"onboardingDialogTranscriptionTurnOnHeader",
IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_TURN_ON_HEADER},
{"onboardingDialogWelcomeDescription",
IDS_RECORDER_ONBOARDING_DIALOG_WELCOME_DESCRIPTION},
{"onboardingDialogWelcomeHeader",

@ -24,6 +24,8 @@ component_files = [
"genai-error.ts",
"genai-feedback-buttons.ts",
"genai-placeholder.ts",
"language-dropdown.ts",
"language-selection-dialog.ts",
"mic-selection-button.ts",
"onboarding-dialog.ts",
"recording-file-list.ts",

@ -0,0 +1,86 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import './cra/cra-dropdown.js';
import {
css,
html,
map,
PropertyDeclarations,
} from 'chrome://resources/mwc/lit/index.js';
import {i18n} from '../core/i18n.js';
import {ReactiveLitElement} from '../core/reactive/lit.js';
import {LangPackInfo, LanguageCode} from '../core/soda/language_info.js';
import {assertInstanceof, checkEnumVariant} from '../core/utils/assert.js';
import {CraDropdown} from './cra/cra-dropdown.js';
/**
* Dropdown menu that display available languages.
*/
export class LanguageDropdown extends ReactiveLitElement {
static override styles = css`
:host {
display: block;
}
`;
static override properties: PropertyDeclarations = {
languageList: {attribute: false},
};
languageList: LangPackInfo[] = [];
value: LanguageCode|null = null;
private onChanged(ev: Event) {
this.value = checkEnumVariant(
LanguageCode,
assertInstanceof(ev.target, CraDropdown).value,
);
}
private renderDropdownOptions(): RenderResult {
return map(this.languageList, (langPack) => {
return html`
<cros-dropdown-option
headline=${langPack.displayName}
value=${langPack.languageCode}
>
</cros-dropdown-option>
`;
});
}
override render(): RenderResult {
// CrOS dropdown does not support showing default text when no item
// selected. Use a disabled hint text as default option as a workaround.
// TODO: b/377629564 - Modify CrOS dropdown to support default text for
// correct a11y behavior.
// TODO(hsuanling): Add leading icon after UI spec is done.
return html`
<cra-dropdown
@change=${this.onChanged}
>
<cros-dropdown-option
headline=${i18n.languageDropdownHintOption}
selected
disabled
>
</cros-dropdown-option>
${this.renderDropdownOptions()}
</cra-dropdown>
`;
}
}
window.customElements.define('language-dropdown', LanguageDropdown);
declare global {
interface HTMLElementTagNameMap {
'language-dropdown': LanguageDropdown;
}
}

@ -0,0 +1,131 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import './cra/cra-button.js';
import './language-dropdown.js';
import './cra/cra-feature-tour-dialog.js';
import {createRef, css, html, ref} from 'chrome://resources/mwc/lit/index.js';
import {i18n} from '../core/i18n.js';
import {usePlatformHandler} from '../core/lit/context.js';
import {ReactiveLitElement} from '../core/reactive/lit.js';
import {
setTranscriptionLanguage,
} from '../core/state/transcription.js';
import {assertExists} from '../core/utils/assert.js';
import {CraFeatureTourDialog} from './cra/cra-feature-tour-dialog.js';
import {LanguageDropdown} from './language-dropdown.js';
import {SpeakerLabelConsentDialog} from './speaker-label-consent-dialog.js';
/**
* Dialog for selecting transcript language when onboarding.
*
* Note that this is different from onboarding dialog and is only used when
* user defers transcription consent on onboarding, and then enable it later.
*
* The main difference to the onboarding dialog is that onboarding dialog is
* not dismissable from user by clicking outside / pressing ESC, but this
* dialog is, so this dialog can use cra-dialog as underlying implementation and
* the onboarding dialog needs to be implemented manually, makes it hard for
* these two to share implementation.
*
* TODO(hsuanling): Consider other way to share part of the implementation.
*/
export class LanguageSelectionDialog extends ReactiveLitElement {
static override styles = css`
:host {
display: contents;
}
.left {
margin-right: auto;
}
cra-feature-tour-dialog {
height: 512px;
}
language-dropdown {
margin-top: 16px;
}
`;
private readonly dialog = createRef<CraFeatureTourDialog>();
private readonly dropdown = createRef<LanguageDropdown>();
private readonly speakerLabelConsentDialog =
createRef<SpeakerLabelConsentDialog>();
private readonly platformHandler = usePlatformHandler();
async show(): Promise<void> {
await this.dialog.value?.show();
}
hide(): void {
this.dialog.value?.hide();
}
private cancelSelection() {
this.hide();
}
private downloadLanguage() {
const languageCode = assertExists(this.dropdown.value).value;
if (languageCode === null) {
return;
}
setTranscriptionLanguage(languageCode);
if (this.platformHandler.canUseSpeakerLabel.value) {
this.speakerLabelConsentDialog.value?.show();
}
this.hide();
}
override render(): RenderResult {
// TODO(hsuanling): The dialogs (like speaker-label-consent-dialog) are
// currently initialized at multiple places when it needs to be used,
// consider making it "global" so it'll only be rendered once?
return html`<cra-feature-tour-dialog
${ref(this.dialog)}
illustrationName="onboarding_transcription"
header=${i18n.onboardingDialogLanguageSelectionHeader}
>
<div slot="content">
${i18n.onboardingDialogLanguageSelectionDescription}
<language-dropdown
.languageList=${this.platformHandler.getLangPackList()}
${ref(this.dropdown)}
>
</language-dropdown>
</div>
<div slot="actions">
<cra-button
.label=${i18n.onboardingDialogLanguageSelectionCancelButton}
@click=${this.cancelSelection}
></cra-button>
<cra-button
label=${i18n.onboardingDialogLanguageSelectionDownloadButton}
@click=${this.downloadLanguage}
></cra-button>
</div>
</cra-feature-tour-dialog>
<speaker-label-consent-dialog ${ref(this.speakerLabelConsentDialog)}>
</speaker-label-consent-dialog>`;
}
}
window.customElements.define(
'language-selection-dialog',
LanguageSelectionDialog,
);
declare global {
interface HTMLElementTagNameMap {
'language-selection-dialog': LanguageSelectionDialog;
}
}

@ -4,6 +4,7 @@
import './cra/cra-button.js';
import './cra/cra-image.js';
import './language-dropdown.js';
import './speaker-label-consent-dialog-content.js';
import {
@ -19,6 +20,7 @@ import {
import {i18n, NoArgStringName} from '../core/i18n.js';
import {usePlatformHandler} from '../core/lit/context.js';
import {ReactiveLitElement} from '../core/reactive/lit.js';
import {LanguageCode} from '../core/soda/language_info.js';
import {
settings,
SpeakerLabelEnableState,
@ -26,10 +28,16 @@ import {
import {
disableTranscription,
enableTranscription,
setTranscriptionLanguage,
} from '../core/state/transcription.js';
import {assertExhaustive, assertInstanceof} from '../core/utils/assert.js';
import {
assertExhaustive,
assertExists,
assertInstanceof,
} from '../core/utils/assert.js';
import {CraButton} from './cra/cra-button.js';
import {LanguageDropdown} from './language-dropdown.js';
import {
DESCRIPTION_NAMES as SPEAKER_LABEL_DIALOG_DESCRIPTION_NAMES,
} from './speaker-label-consent-dialog-content.js';
@ -91,6 +99,10 @@ export class OnboardingDialog extends ReactiveLitElement {
margin: 0 0 16px;
}
language-dropdown {
margin-top: 16px;
}
#description {
color: var(--cros-sys-on_surface_variant);
flex: 1;
@ -123,13 +135,26 @@ export class OnboardingDialog extends ReactiveLitElement {
/**
* The currently shown step index starting from 0.
*
* Step 0: Welcoming page.
* Step 1: Transcription consent dialog for users to turn on transcription and
* download en-US model.
* Step 2: Transcription consent dialog for users to turn on transcription.
* Step 3: Transcription language selection dialog for users to choose and
* download language model.
* Step 4: Speaker label consent dialog for users to turn on speaker label.
*
* When there are multiple language options, skip step 1. Otherwise, skip step
* 2 and step 3.
*/
step: 0|1|2 = 0;
step: 0|1|2|3|4 = 0;
private readonly platformHandler = usePlatformHandler();
private readonly autoFocusItem = createRef<CraButton>();
private readonly dropdown = createRef<LanguageDropdown>();
get dialog(): HTMLDivElement {
return assertInstanceof(
this.shadowRoot?.getElementById('dialog'),
@ -219,7 +244,8 @@ export class OnboardingDialog extends ReactiveLitElement {
this.close();
return;
}
this.step = 1;
this.step =
this.platformHandler.getLangPackList().length <= 1 ? 1 : 2;
};
return this.renderDialog(
this.step,
@ -236,12 +262,13 @@ export class OnboardingDialog extends ReactiveLitElement {
case 1: {
const turnOnTranscription = () => {
enableTranscription();
setTranscriptionLanguage(LanguageCode.EN_US);
if (!this.platformHandler.canUseSpeakerLabel.value) {
// Speaker label isn't supported on this platform.
this.close();
return;
}
this.step = 2;
this.step = 4;
};
const turnOffTranscription = () => {
disableTranscription(/* firstTime= */ true);
@ -264,13 +291,90 @@ export class OnboardingDialog extends ReactiveLitElement {
@click=${turnOffTranscription}
></cra-button>
<cra-button
.label=${i18n.onboardingDialogTranscriptionTurnOnButton}
.label=${i18n.onboardingDialogTranscriptionDownloadButton}
@click=${turnOnTranscription}
></cra-button>
`,
);
}
case 2: {
const turnOnTranscription = () => {
enableTranscription();
this.step = 3;
};
const turnOffTranscription = () => {
disableTranscription(/* firstTime= */ true);
this.close();
};
return this.renderDialog(
this.step,
'onboarding_transcription',
i18n.onboardingDialogTranscriptionTurnOnHeader,
i18n.onboardingDialogTranscriptionTurnOnDescription,
html`
<cra-button
.label=${i18n.onboardingDialogTranscriptionDeferButton}
class="left"
@click=${this.close}
${ref(this.autoFocusItem)}
></cra-button>
<cra-button
.label=${i18n.onboardingDialogTranscriptionCancelButton}
@click=${turnOffTranscription}
></cra-button>
<cra-button
.label=${i18n.onboardingDialogTranscriptionTurnOnButton}
@click=${turnOnTranscription}
></cra-button>
`,
);
}
case 3: {
const dialogBody = html`
${i18n.onboardingDialogLanguageSelectionDescription}
<language-dropdown
.languageList=${this.platformHandler.getLangPackList()}
${ref(this.dropdown)}
>
</language-dropdown>
`;
const downloadLanguage = () => {
const languageCode = assertExists(this.dropdown.value).value;
if (languageCode === null) {
return;
}
setTranscriptionLanguage(languageCode);
if (!this.platformHandler.canUseSpeakerLabel.value) {
// Speaker label isn't supported on this platform.
this.close();
return;
}
this.step = 4;
};
const cancelSelection = () => {
this.close();
};
return this.renderDialog(
this.step,
'onboarding_transcription',
i18n.onboardingDialogLanguageSelectionHeader,
dialogBody,
html`
<cra-button
.label=${i18n.onboardingDialogLanguageSelectionCancelButton}
@click=${cancelSelection}
></cra-button>
<cra-button
label=${i18n.onboardingDialogLanguageSelectionDownloadButton}
@click=${downloadLanguage}
></cra-button>
`,
);
}
case 4: {
const ALLOW_BUTTON_NAME: NoArgStringName =
'onboardingDialogSpeakerLabelAllowButton';
const DISALLOW_BUTTON_NAME: NoArgStringName =

@ -4,6 +4,7 @@
import './cra/cra-button.js';
import './cra/cra-feature-tour-dialog.js';
import './language-selection-dialog.js';
import './speaker-label-consent-dialog.js';
import {createRef, css, html, ref} from 'chrome://resources/mwc/lit/index.js';
@ -11,12 +12,15 @@ import {createRef, css, html, ref} from 'chrome://resources/mwc/lit/index.js';
import {i18n} from '../core/i18n.js';
import {usePlatformHandler} from '../core/lit/context.js';
import {ReactiveLitElement} from '../core/reactive/lit.js';
import {LanguageCode} from '../core/soda/language_info.js';
import {
disableTranscription,
enableTranscription,
setTranscriptionLanguage,
} from '../core/state/transcription.js';
import {CraFeatureTourDialog} from './cra/cra-feature-tour-dialog.js';
import {LanguageSelectionDialog} from './language-selection-dialog.js';
import {SpeakerLabelConsentDialog} from './speaker-label-consent-dialog.js';
/**
@ -50,11 +54,17 @@ export class TranscriptionConsentDialog extends ReactiveLitElement {
private readonly dialog = createRef<CraFeatureTourDialog>();
private readonly languageSelectionDialog =
createRef<LanguageSelectionDialog>();
private readonly speakerLabelConsentDialog =
createRef<SpeakerLabelConsentDialog>();
private readonly platformHandler = usePlatformHandler();
private readonly shouldShowSelector =
this.platformHandler.getLangPackList().length > 1;
async show(): Promise<void> {
await this.dialog.value?.show();
}
@ -70,8 +80,13 @@ export class TranscriptionConsentDialog extends ReactiveLitElement {
private enableTranscription() {
enableTranscription();
if (this.platformHandler.canUseSpeakerLabel.value) {
this.speakerLabelConsentDialog.value?.show();
if (!this.shouldShowSelector) {
setTranscriptionLanguage(LanguageCode.EN_US);
if (this.platformHandler.canUseSpeakerLabel.value) {
this.speakerLabelConsentDialog.value?.show();
}
} else {
this.languageSelectionDialog.value?.show();
}
this.hide();
}
@ -80,13 +95,23 @@ export class TranscriptionConsentDialog extends ReactiveLitElement {
// TODO(pihsun): The dialogs (like speaker-label-consent-dialog) are
// currently initialized at multiple places when it needs to be used,
// consider making it "global" so it'll only be rendered once?
const header = this.shouldShowSelector ?
i18n.onboardingDialogTranscriptionTurnOnHeader :
i18n.onboardingDialogTranscriptionHeader;
const description = this.shouldShowSelector ?
i18n.onboardingDialogTranscriptionTurnOnDescription :
i18n.onboardingDialogTranscriptionDescription;
const turnOnButtonLabel = this.shouldShowSelector ?
i18n.onboardingDialogTranscriptionTurnOnButton :
i18n.onboardingDialogTranscriptionDownloadButton;
return html`<cra-feature-tour-dialog
${ref(this.dialog)}
illustrationName="onboarding_transcription"
header=${i18n.onboardingDialogTranscriptionHeader}
header=${header}
>
<div slot="content">
${i18n.onboardingDialogTranscriptionDescription}
${description}
</div>
<div slot="actions">
<cra-button
@ -99,11 +124,13 @@ export class TranscriptionConsentDialog extends ReactiveLitElement {
@click=${this.disableTranscription}
></cra-button>
<cra-button
.label=${i18n.onboardingDialogTranscriptionTurnOnButton}
.label=${turnOnButtonLabel}
@click=${this.enableTranscription}
></cra-button>
</div>
</cra-feature-tour-dialog>
<language-selection-dialog ${ref(this.languageSelectionDialog)}>
</language-selection-dialog>
<speaker-label-consent-dialog ${ref(this.speakerLabelConsentDialog)}>
</speaker-label-consent-dialog>`;
}

@ -39,6 +39,7 @@ const noArgStringNames = [
'genAiLearnMoreLinkTooltip',
'genaiNegativeFeedbackButtonTooltip',
'genaiPositiveFeedbackButtonTooltip',
'languageDropdownHintOption',
'mainRecordingBarLandmarkAriaLabel',
'mainRecordingsListLandmarkAriaLabel',
'mainSearchLandmarkAriaLabel',
@ -46,6 +47,10 @@ const noArgStringNames = [
'mainStartRecordNudge',
'micSelectionMenuButtonTooltip',
'micSelectionMenuChromebookAudioOption',
'onboardingDialogLanguageSelectionCancelButton',
'onboardingDialogLanguageSelectionDescription',
'onboardingDialogLanguageSelectionDownloadButton',
'onboardingDialogLanguageSelectionHeader',
'onboardingDialogSpeakerLabelAllowButton',
'onboardingDialogSpeakerLabelDeferButton',
'onboardingDialogSpeakerLabelDescriptionListItem1',
@ -59,8 +64,11 @@ const noArgStringNames = [
'onboardingDialogTranscriptionCancelButton',
'onboardingDialogTranscriptionDeferButton',
'onboardingDialogTranscriptionDescription',
'onboardingDialogTranscriptionDownloadButton',
'onboardingDialogTranscriptionHeader',
'onboardingDialogTranscriptionTurnOnButton',
'onboardingDialogTranscriptionTurnOnDescription',
'onboardingDialogTranscriptionTurnOnHeader',
'onboardingDialogWelcomeDescription',
'onboardingDialogWelcomeHeader',
'onboardingDialogWelcomeNextButton',

@ -24,17 +24,26 @@ export function disableTranscription(firstTime = false): void {
}
/**
* Enables transcription and installs Soda.
* Enables transcription.
*/
export function enableTranscription(): void {
settings.mutate((s) => {
s.transcriptionEnabled = TranscriptionEnableState.ENABLED;
});
// TODO(hsuanling): Move download logic to language picker.
const selectedLanguage = settings.value.transcriptionLanguage;
if (selectedLanguage !== null) {
void usePlatformHandler().installSoda(selectedLanguage);
}
}
/**
* Set transcription language and install Soda.
*/
export function setTranscriptionLanguage(language: LanguageCode): void {
settings.mutate((s) => {
s.transcriptionLanguage = LanguageCode.EN_US;
s.transcriptionLanguage = language;
});
void usePlatformHandler().installSoda(LanguageCode.EN_US);
void usePlatformHandler().installSoda(language);
}
/**

@ -74,6 +74,9 @@
<message desc="Tooltip of the link to more information about generative AI disclaimer." name="IDS_RECORDER_GEN_AI_LEARN_MORE_LINK_TOOLTIP">
Learn more about Generative AI
</message>
<message desc="Hint text for users to choose language from the dropdown." name="IDS_RECORDER_LANGUAGE_DROPDOWN_HINT_OPTION">
Select language
</message>
<message desc="Accessibility label of the landmark for the list of recordings in the main page." name="IDS_RECORDER_MAIN_RECORDINGS_LIST_LANDMARK_ARIA_LABEL">
List of audio recordings
</message>
@ -95,6 +98,18 @@
<message desc="Label of the option to include system audio in the recording." name="IDS_RECORDER_MIC_SELECTION_MENU_CHROMEBOOK_AUDIO_OPTION">
Chromebook audio
</message>
<message desc="Button to defer transcription language selection and go next step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_CANCEL_BUTTON">
Cancel
</message>
<message desc="Description of the transcription language selection step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_DESCRIPTION">
You can change this later in Recorder settings
</message>
<message desc="Button to download transcription model and go next step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_DOWNLOAD_BUTTON">
Download
</message>
<message desc="Header of the transcription language selection step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_LANGUAGE_SELECTION_HEADER">
Select transcription language and download model
</message>
<message desc="Button to enable speaker label and go next step in the speaker label enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_SPEAKER_LABEL_ALLOW_BUTTON">
Allow
</message>
@ -131,15 +146,24 @@
<message desc="Button to defer enabling transcription and go next step in the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DEFER_BUTTON">
Skip
</message>
<message desc="Description of the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DESCRIPTION">
<message desc="Description of the transcription enable and download step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DESCRIPTION">
Recorder can create transcriptions for recordings with speech.
Download the transcription model (up to 100MB) to get these transcriptions.
</message>
<message desc="Header of the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_HEADER">
<message desc="Button to enable transcription and download transcription model, and go next step in the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_DOWNLOAD_BUTTON">
Turn on and download
</message>
<message desc="Header of the transcription enable and download step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_HEADER">
Turn on transcription and download transcription model?
</message>
<message desc="Button to enable transcription and go next step in the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_TURN_ON_BUTTON">
Turn on and download
Turn on
</message>
<message desc="Description of the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_TURN_ON_DESCRIPTION">
Recorder can create transcriptions for recordings with speech. In the next step, you need to select the transcription language and download the model (up to 100MB).
</message>
<message desc="Header of the transcription enable step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_TRANSCRIPTION_TURN_ON_HEADER">
Turn on transcription?
</message>
<message desc="Description of the welcome step in the onboarding dialog." name="IDS_RECORDER_ONBOARDING_DIALOG_WELCOME_DESCRIPTION">
Automatically create transcriptions, get recording summaries using Google AI, and search audio. Create recordings even when youre not connected to the internet.

@ -0,0 +1 @@
bf8045fdb5a3a106dd6b586b60da8bc517dd41bb

@ -0,0 +1 @@
3988167e248a40bb6a905533df3fd0e1489b77eb

@ -0,0 +1 @@
3988167e248a40bb6a905533df3fd0e1489b77eb

@ -0,0 +1 @@
3988167e248a40bb6a905533df3fd0e1489b77eb

@ -0,0 +1 @@
3988167e248a40bb6a905533df3fd0e1489b77eb

@ -0,0 +1 @@
47c71b179258bcba5e93c9e7f00ecc77b7d9f77d

@ -1 +1 @@
e89e893311695bc80806d4facbb30a0bc9b9af0a
8cd5630f8ca1043eb7e50a7148865f14752d0503

@ -0,0 +1 @@
8cd5630f8ca1043eb7e50a7148865f14752d0503

@ -0,0 +1 @@
8cd5630f8ca1043eb7e50a7148865f14752d0503