[framework] Add textField OCR support for framework side (#96637)

iOS OCR keyboard input support.
This commit is contained in:
luckysmg 2023-07-06 23:51:06 +08:00 committed by GitHub
parent 2f7614a818
commit e0ad12969f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
97 changed files with 868 additions and 46 deletions

View File

@ -25,6 +25,7 @@ export 'src/services/hardware_keyboard.dart';
export 'src/services/keyboard_inserted_content.dart';
export 'src/services/keyboard_key.g.dart';
export 'src/services/keyboard_maps.g.dart';
export 'src/services/live_text.dart';
export 'src/services/message_codec.dart';
export 'src/services/message_codecs.dart';
export 'src/services/mouse_cursor.dart';

View File

@ -94,6 +94,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget {
required VoidCallback? onCut,
required VoidCallback? onPaste,
required VoidCallback? onSelectAll,
required VoidCallback? onLiveTextInput,
required this.anchors,
}) : children = null,
buttonItems = EditableText.getEditableButtonItems(
@ -102,6 +103,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget {
onCut: onCut,
onPaste: onPaste,
onSelectAll: onSelectAll,
onLiveTextInput: onLiveTextInput
);
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the

View File

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:math';
import 'package:flutter/widgets.dart';
import 'button.dart';
@ -103,6 +105,7 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget {
return localizations.pasteButtonLabel;
case ContextMenuButtonType.selectAll:
return localizations.selectAllButtonLabel;
case ContextMenuButtonType.liveTextInput:
case ContextMenuButtonType.delete:
case ContextMenuButtonType.custom:
return '';
@ -131,6 +134,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec
@override
Widget build(BuildContext context) {
final Widget content = _getContentWidget(context);
final Widget child = CupertinoButton(
color: isPressed
? _kToolbarPressedColor.resolveFrom(context)
@ -145,15 +149,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec
// There's no foreground fade on iOS toolbar anymore, just the background
// is darkened.
pressedOpacity: 1.0,
child: widget.child ?? Text(
widget.text ?? CupertinoTextSelectionToolbarButton.getButtonLabel(context, widget.buttonItem!),
overflow: TextOverflow.ellipsis,
style: _kToolbarButtonFontStyle.copyWith(
color: widget.onPressed != null
? _kToolbarTextColor.resolveFrom(context)
: CupertinoColors.inactiveGray,
),
),
child: content,
);
if (widget.onPressed != null) {
@ -170,4 +166,85 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec
return child;
}
}
Widget _getContentWidget(BuildContext context) {
if (widget.child != null) {
return widget.child!;
}
final Widget textWidget = Text(
widget.text ?? CupertinoTextSelectionToolbarButton.getButtonLabel(context, widget.buttonItem!),
overflow: TextOverflow.ellipsis,
style: _kToolbarButtonFontStyle.copyWith(
color: widget.onPressed != null
? _kToolbarTextColor.resolveFrom(context)
: CupertinoColors.inactiveGray,
),
);
if (widget.buttonItem == null) {
return textWidget;
}
switch (widget.buttonItem!.type) {
case ContextMenuButtonType.cut:
case ContextMenuButtonType.copy:
case ContextMenuButtonType.paste:
case ContextMenuButtonType.selectAll:
case ContextMenuButtonType.delete:
case ContextMenuButtonType.custom:
return textWidget;
case ContextMenuButtonType.liveTextInput:
return SizedBox(
width: 13.0,
height: 13.0,
child: CustomPaint(
painter: _LiveTextIconPainter(color: _kToolbarTextColor.resolveFrom(context)),
),
);
}
}
}
class _LiveTextIconPainter extends CustomPainter {
_LiveTextIconPainter({required this.color});
final Color color;
final Paint _painter = Paint()
..strokeCap = StrokeCap.round
..strokeJoin = StrokeJoin.round
..strokeWidth = 1.0
..style = PaintingStyle.stroke;
@override
void paint(Canvas canvas, Size size) {
_painter.color = color;
canvas.save();
canvas.translate(size.width / 2.0, size.height / 2.0);
final Offset origin = Offset(-size.width / 2.0, -size.height / 2.0);
// Path for the one corner.
final Path path = Path()
..moveTo(origin.dx, origin.dy + 3.5)
..lineTo(origin.dx, origin.dy + 1.0)
..arcToPoint(Offset(origin.dx + 1.0, origin.dy), radius: const Radius.circular(1))
..lineTo(origin.dx + 3.5, origin.dy);
// Rotate to draw corner four times.
final Matrix4 rotationMatrix = Matrix4.identity()..rotateZ(pi / 2.0);
for (int i = 0; i < 4; i += 1) {
canvas.drawPath(path, _painter);
canvas.transform(rotationMatrix.storage);
}
// Draw three lines.
canvas.drawLine(const Offset(-3.0, -3.0), const Offset(3.0, -3.0), _painter);
canvas.drawLine(const Offset(-3.0, 0.0), const Offset(3.0, 0.0), _painter);
canvas.drawLine(const Offset(-3.0, 3.0), const Offset(1.0, 3.0), _painter);
canvas.restore();
}
@override
bool shouldRepaint(covariant _LiveTextIconPainter oldDelegate) {
return oldDelegate.color != color;
}
}

View File

@ -103,6 +103,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
required VoidCallback? onCut,
required VoidCallback? onPaste,
required VoidCallback? onSelectAll,
required VoidCallback? onLiveTextInput,
required this.anchors,
}) : children = null,
buttonItems = EditableText.getEditableButtonItems(
@ -111,6 +112,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
onCut: onCut,
onPaste: onPaste,
onSelectAll: onSelectAll,
onLiveTextInput: onLiveTextInput
);
/// Create an instance of [AdaptiveTextSelectionToolbar] with the default
@ -213,6 +215,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
return localizations.selectAllButtonLabel;
case ContextMenuButtonType.delete:
return localizations.deleteButtonTooltip.toUpperCase();
case ContextMenuButtonType.liveTextInput:
return localizations.scanTextButtonLabel;
case ContextMenuButtonType.custom:
return '';
}
@ -242,9 +246,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
switch (Theme.of(context).platform) {
case TargetPlatform.iOS:
return buttonItems.map((ContextMenuButtonItem buttonItem) {
return CupertinoTextSelectionToolbarButton.text(
onPressed: buttonItem.onPressed,
text: getButtonLabel(context, buttonItem),
return CupertinoTextSelectionToolbarButton.buttonItem(
buttonItem: buttonItem,
);
});
case TargetPlatform.fuchsia:

View File

@ -103,6 +103,9 @@ abstract class MaterialLocalizations {
/// Label for "cut" edit buttons and menu items.
String get cutButtonLabel;
/// Label for "scan text" OCR edit buttons and menu items.
String get scanTextButtonLabel;
/// Label for OK buttons and menu items.
String get okButtonLabel;
@ -1159,6 +1162,9 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
@override
String get cutButtonLabel => 'Cut';
@override
String get scanTextButtonLabel => 'Scan text';
@override
String get okButtonLabel => 'OK';

View File

@ -0,0 +1,35 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'system_channels.dart';
/// Utility methods for interacting with the system's Live Text.
///
/// For example, the Live Text input feature of iOS turns the keyboard into a camera view for
/// directly inserting text obtained through OCR into the active field.
///
/// See also:
/// * <https://developer.apple.com/documentation/uikit/uiresponder/3778577-capturetextfromcamera>
/// * <https://support.apple.com/guide/iphone/use-live-text-iphcf0b71b0e/ios>
class LiveText {
// This class is not meant to be instantiated or extended; this constructor
// prevents instantiation and extension.
LiveText._();
/// Returns true if the Live Text input feature is available on the current device.
static Future<bool> isLiveTextInputAvailable() async {
final bool supportLiveTextInput =
await SystemChannels.platform.invokeMethod('LiveText.isLiveTextInputAvailable') ?? false;
return supportLiveTextInput;
}
/// Start Live Text input.
///
/// If any [TextInputConnection] is currently active, calling this method will tell the text field
/// to start Live Text input. If the current device doesn't support Live Text input,
/// nothing will happen.
static void startLiveTextInput() {
SystemChannels.textInput.invokeMethod('TextInput.startLiveTextInput');
}
}

View File

@ -1050,6 +1050,13 @@ mixin TextSelectionDelegate {
/// Whether select all is enabled, must not be null.
bool get selectAllEnabled => true;
/// Whether Live Text input is enabled.
///
/// See also:
/// * [LiveText], where the availability of Live Text input can be obtained.
/// * [LiveTextInputStatusNotifier], where the status of Live Text can be listened to.
bool get liveTextInputEnabled => false;
/// Cut current selection to [Clipboard].
///
/// If and only if [cause] is [SelectionChangedCause.toolbar], the toolbar

View File

@ -26,6 +26,13 @@ enum ContextMenuButtonType {
/// A button that deletes the current text selection.
delete,
/// A button for starting Live Text input.
///
/// See also:
/// * [LiveText], where the availability of Live Text input can be obtained.
/// * [LiveTextInputStatusNotifier], where the status of Live Text can be listened to.
liveTextInput,
/// Anything other than the default button types.
custom,
}

View File

@ -1835,36 +1835,48 @@ class EditableText extends StatefulWidget {
required final VoidCallback? onCut,
required final VoidCallback? onPaste,
required final VoidCallback? onSelectAll,
required final VoidCallback? onLiveTextInput,
}) {
// If the paste button is enabled, don't render anything until the state
// of the clipboard is known, since it's used to determine if paste is
// shown.
if (onPaste != null && clipboardStatus == ClipboardStatus.unknown) {
return <ContextMenuButtonItem>[];
final List<ContextMenuButtonItem> resultButtonItem = <ContextMenuButtonItem>[];
// Configure button items with clipboard.
if (onPaste == null || clipboardStatus != ClipboardStatus.unknown) {
// If the paste button is enabled, don't render anything until the state
// of the clipboard is known, since it's used to determine if paste is
// shown.
resultButtonItem.addAll(<ContextMenuButtonItem>[
if (onCut != null)
ContextMenuButtonItem(
onPressed: onCut,
type: ContextMenuButtonType.cut,
),
if (onCopy != null)
ContextMenuButtonItem(
onPressed: onCopy,
type: ContextMenuButtonType.copy,
),
if (onPaste != null)
ContextMenuButtonItem(
onPressed: onPaste,
type: ContextMenuButtonType.paste,
),
if (onSelectAll != null)
ContextMenuButtonItem(
onPressed: onSelectAll,
type: ContextMenuButtonType.selectAll,
),
]);
}
return <ContextMenuButtonItem>[
if (onCut != null)
ContextMenuButtonItem(
onPressed: onCut,
type: ContextMenuButtonType.cut,
),
if (onCopy != null)
ContextMenuButtonItem(
onPressed: onCopy,
type: ContextMenuButtonType.copy,
),
if (onPaste != null)
ContextMenuButtonItem(
onPressed: onPaste,
type: ContextMenuButtonType.paste,
),
if (onSelectAll != null)
ContextMenuButtonItem(
onPressed: onSelectAll,
type: ContextMenuButtonType.selectAll,
),
];
// Config button items with Live Text.
if (onLiveTextInput != null) {
resultButtonItem.add(ContextMenuButtonItem(
onPressed: onLiveTextInput,
type: ContextMenuButtonType.liveTextInput,
));
}
return resultButtonItem;
}
// Infer the keyboard type of an `EditableText` if it's not specified.
@ -2063,6 +2075,13 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
/// Detects whether the clipboard can paste.
final ClipboardStatusNotifier clipboardStatus = ClipboardStatusNotifier();
/// Detects whether the Live Text input is enabled.
///
/// See also:
/// * [LiveText], where the availability of Live Text input can be obtained.
final LiveTextInputStatusNotifier? _liveTextInputStatus =
kIsWeb ? null : LiveTextInputStatusNotifier();
TextInputConnection? _textInputConnection;
bool get _hasInputConnection => _textInputConnection?.attached ?? false;
@ -2196,12 +2215,26 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
}
@override
bool get liveTextInputEnabled {
return _liveTextInputStatus?.value == LiveTextInputStatus.enabled &&
!widget.obscureText &&
!widget.readOnly &&
textEditingValue.selection.isCollapsed;
}
void _onChangedClipboardStatus() {
setState(() {
// Inform the widget that the value of clipboardStatus has changed.
});
}
void _onChangedLiveTextInputStatus() {
setState(() {
// Inform the widget that the value of liveTextInputStatus has changed.
});
}
TextEditingValue get _textEditingValueforTextLayoutMetrics {
final Widget? editableWidget =_editableKey.currentContext?.widget;
if (editableWidget is! _Editable) {
@ -2347,6 +2380,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
}
void _startLiveTextInput(SelectionChangedCause cause) {
if (!liveTextInputEnabled) {
return;
}
if (_hasInputConnection) {
LiveText.startLiveTextInput();
}
if (cause == SelectionChangedCause.toolbar) {
hideToolbar();
}
}
/// Finds specified [SuggestionSpan] that matches the provided index using
/// binary search.
///
@ -2561,6 +2606,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
onSelectAll: selectAllEnabled
? () => selectAll(SelectionChangedCause.toolbar)
: null,
onLiveTextInput: liveTextInputEnabled
? () => _startLiveTextInput(SelectionChangedCause.toolbar)
: null,
);
}
@ -2569,6 +2617,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
void initState() {
super.initState();
_liveTextInputStatus?.addListener(_onChangedLiveTextInputStatus);
clipboardStatus.addListener(_onChangedClipboardStatus);
widget.controller.addListener(_didChangeTextEditingValue);
widget.focusNode.addListener(_handleFocusChanged);
@ -2734,6 +2783,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay = null;
widget.focusNode.removeListener(_handleFocusChanged);
WidgetsBinding.instance.removeObserver(this);
_liveTextInputStatus?.removeListener(_onChangedLiveTextInputStatus);
_liveTextInputStatus?.dispose();
clipboardStatus.removeListener(_onChangedClipboardStatus);
clipboardStatus.dispose();
_cursorVisibilityNotifier.dispose();
@ -3986,6 +4037,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if (_selectionOverlay == null) {
return false;
}
_liveTextInputStatus?.update();
clipboardStatus.update();
_selectionOverlay!.showToolbar();
return true;

View File

@ -3383,6 +3383,115 @@ enum ClipboardStatus {
notPasteable,
}
/// A [ValueNotifier] whose [value] indicates whether the current device supports the Live Text
/// (OCR) function.
///
/// See also:
/// * [LiveText], where the availability of Live Text input can be obtained.
/// * [LiveTextInputStatus], an enumeration that indicates whether the current device is available
/// for Live Text input.
///
/// Call [update] to asynchronously update [value] if needed.
class LiveTextInputStatusNotifier extends ValueNotifier<LiveTextInputStatus> with WidgetsBindingObserver {
/// Create a new LiveTextStatusNotifier.
LiveTextInputStatusNotifier({
LiveTextInputStatus value = LiveTextInputStatus.unknown,
}) : super(value);
bool _disposed = false;
/// Check the [LiveTextInputStatus] and update [value] if needed.
Future<void> update() async {
if (_disposed) {
return;
}
final bool isLiveTextInputEnabled;
try {
isLiveTextInputEnabled = await LiveText.isLiveTextInputAvailable();
} catch (exception, stack) {
FlutterError.reportError(FlutterErrorDetails(
exception: exception,
stack: stack,
library: 'widget library',
context: ErrorDescription('while checking the availability of Live Text input'),
));
// In the case of an error from the Live Text API, set the value to
// unknown so that it will try to update again later.
if (_disposed || value == LiveTextInputStatus.unknown) {
return;
}
value = LiveTextInputStatus.unknown;
return;
}
final LiveTextInputStatus nextStatus = isLiveTextInputEnabled
? LiveTextInputStatus.enabled
: LiveTextInputStatus.disabled;
if (_disposed || nextStatus == value) {
return;
}
value = nextStatus;
}
@override
void addListener(VoidCallback listener) {
if (!hasListeners) {
WidgetsBinding.instance.addObserver(this);
}
if (value == LiveTextInputStatus.unknown) {
update();
}
super.addListener(listener);
}
@override
void removeListener(VoidCallback listener) {
super.removeListener(listener);
if (!_disposed && !hasListeners) {
WidgetsBinding.instance.removeObserver(this);
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
update();
case AppLifecycleState.detached:
case AppLifecycleState.inactive:
case AppLifecycleState.paused:
case AppLifecycleState.hidden:
// Nothing to do.
}
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_disposed = true;
super.dispose();
}
}
/// An enumeration that indicates whether the current device is available for Live Text input.
///
/// See also:
/// * [LiveText], where the availability of Live Text input can be obtained.
enum LiveTextInputStatus {
/// This device supports Live Text input currently.
enabled,
/// The status of the Live Text input is unknown. Since getting the Live Text input availability
/// is asynchronous (see [LiveText.isLiveTextInputAvailable]), this status often exists while
/// waiting to receive the status value for the first time.
unknown,
/// The current device doesn't support Live Text input.
disabled,
}
// TODO(justinmc): Deprecate this after TextSelectionControls.buildToolbar is
// deleted, when users should migrate back to TextSelectionControls.buildHandle.
// See https://github.com/flutter/flutter/pull/124262

View File

@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import '../widgets/clipboard_utils.dart';
import '../widgets/live_text_utils.dart';
void main() {
final MockClipboard mockClipboard = MockClipboard();
@ -166,6 +167,7 @@ void main() {
onCut: () {},
onPaste: () {},
onSelectAll: () {},
onLiveTextInput: () {},
),
),
));
@ -178,13 +180,16 @@ void main() {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.fuchsia:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(4));
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
expect(findLiveTextButton(), findsOneWidget);
case TargetPlatform.macOS:
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(4));
expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(5));
}
},
skip: kIsWeb, // [intended] on web the browser handles the context menu.

View File

@ -21,6 +21,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart' show OverflowWidgetTextEditingController;
import '../widgets/live_text_utils.dart';
import '../widgets/semantics_tester.dart';
// On web, the context menu (aka toolbar) is provided by the browser.
@ -199,12 +200,56 @@ void main() {
Offset textOffsetToPosition(WidgetTester tester, int offset) => textOffsetToBottomLeftPosition(tester, offset) + const Offset(kIsWeb ? 1 : 0, -2);
setUp(() async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
EditableText.debugDeterministicCursor = false;
// Fill the clipboard so that the Paste option is available in the text
// selection menu.
await Clipboard.setData(const ClipboardData(text: 'Clipboard data'));
});
testWidgets(
'Live Text button shows and hides correctly when LiveTextStatus changes',
(WidgetTester tester) async {
final LiveTextInputTester liveTextInputTester = LiveTextInputTester();
addTearDown(liveTextInputTester.dispose);
final TextEditingController controller = TextEditingController(text: '');
const Key key = ValueKey<String>('TextField');
final FocusNode focusNode = FocusNode();
final Widget app = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
body: Center(
child: CupertinoTextField(
key: key,
controller: controller,
focusNode: focusNode,
),
),
),
);
liveTextInputTester.mockLiveTextInputEnabled = true;
await tester.pumpWidget(app);
focusNode.requestFocus();
await tester.pumpAndSettle();
final Finder textFinder = find.byType(EditableText);
await tester.longPress(textFinder);
await tester.pumpAndSettle();
expect(
findLiveTextButton(),
kIsWeb ? findsNothing : findsOneWidget,
);
liveTextInputTester.mockLiveTextInputEnabled = false;
await tester.longPress(textFinder);
await tester.pumpAndSettle();
expect(findLiveTextButton(), findsNothing);
},
);
testWidgets('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'blah1 blah2',

View File

@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../foundation/leak_tracking.dart';
import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart';
import '../widgets/live_text_utils.dart';
void main() {
final MockClipboard mockClipboard = MockClipboard();
@ -184,6 +185,7 @@ void main() {
onCut: () {},
onPaste: () {},
onSelectAll: () {},
onLiveTextInput: () {},
),
),
),
@ -199,17 +201,18 @@ void main() {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(4));
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(5));
case TargetPlatform.iOS:
expect(find.text('Select All'), findsOneWidget);
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(4));
expect(findLiveTextButton(), findsOneWidget);
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.linux:
case TargetPlatform.windows:
expect(find.text('Select all'), findsOneWidget);
expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(4));
expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.macOS:
expect(find.text('Select All'), findsOneWidget);
expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(4));
expect(find.byType(CupertinoDesktopTextSelectionToolbarButton), findsNWidgets(5));
}
},
skip: kIsWeb, // [intended] on web the browser handles the context menu.

View File

@ -28,6 +28,7 @@ void main() {
expect(localizations.continueButtonLabel, isNotNull);
expect(localizations.copyButtonLabel, isNotNull);
expect(localizations.cutButtonLabel, isNotNull);
expect(localizations.scanTextButtonLabel, isNotNull);
expect(localizations.okButtonLabel, isNotNull);
expect(localizations.pasteButtonLabel, isNotNull);
expect(localizations.selectAllButtonLabel, isNotNull);

View File

@ -26,6 +26,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart';
import '../widgets/live_text_utils.dart';
import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart';
@ -203,6 +204,47 @@ void main() {
);
}
testWidgets(
'Live Text button shows and hides correctly when LiveTextStatus changes',
(WidgetTester tester) async {
final LiveTextInputTester liveTextInputTester = LiveTextInputTester();
addTearDown(liveTextInputTester.dispose);
final TextEditingController controller = TextEditingController(text: '');
const Key key = ValueKey<String>('TextField');
final FocusNode focusNode = FocusNode();
final Widget app = MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
home: Scaffold(
body: Center(
child: TextField(
key: key,
controller: controller,
focusNode: focusNode,
),
),
),
);
liveTextInputTester.mockLiveTextInputEnabled = true;
await tester.pumpWidget(app);
focusNode.requestFocus();
await tester.pumpAndSettle();
final Finder textFinder = find.byType(EditableText);
await tester.longPress(textFinder);
await tester.pumpAndSettle();
expect(
findLiveTextButton(),
kIsWeb ? findsNothing : findsOneWidget,
);
liveTextInputTester.mockLiveTextInputEnabled = false;
await tester.longPress(textFinder);
await tester.pumpAndSettle();
expect(findLiveTextButton(), findsNothing);
},
);
testWidgets('text field selection toolbar should hide when the user starts typing', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(

View File

@ -15,6 +15,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/clipboard_utils.dart';
import 'editable_text_utils.dart';
import 'live_text_utils.dart';
import 'semantics_tester.dart';
Matcher matchesMethodCall(String method, { dynamic args }) => _MatchesMethodCall(method, arguments: args == null ? null : wrapMatcher(args));
@ -118,6 +119,72 @@ void main() {
expect(tester.testTextInput.setClientArgs!['inputAction'], equals(serializedActionName));
}
testWidgets(
'Tapping the Live Text button calls onLiveTextInput',
(WidgetTester tester) async {
bool invokedLiveTextInputSuccessfully = false;
final GlobalKey key = GlobalKey();
final TextEditingController controller = TextEditingController(text: '');
await tester.pumpWidget(
MaterialApp(
home: Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: 400,
child: EditableText(
maxLines: 10,
controller: controller,
showSelectionHandles: true,
autofocus: true,
focusNode: FocusNode(),
style: Typography.material2018().black.subtitle1!,
cursorColor: Colors.blue,
backgroundCursorColor: Colors.grey,
keyboardType: TextInputType.text,
textAlign: TextAlign.right,
selectionControls: materialTextSelectionHandleControls,
contextMenuBuilder: (
BuildContext context,
EditableTextState editableTextState,
) {
return CupertinoAdaptiveTextSelectionToolbar.editable(
key: key,
clipboardStatus: ClipboardStatus.pasteable,
onCopy: null,
onCut: null,
onPaste: null,
onSelectAll: null,
onLiveTextInput: () {
invokedLiveTextInputSuccessfully = true;
},
anchors: const TextSelectionToolbarAnchors(primaryAnchor: Offset.zero),
);
},
),
),
),
),
);
await tester.pump(); // Wait for autofocus to take effect.
expect(find.byKey(key), findsNothing);
// Long-press to bring up the context menu.
final Finder textFinder = find.byType(EditableText);
await tester.longPress(textFinder);
tester.state<EditableTextState>(textFinder).showToolbar();
await tester.pumpAndSettle();
expect(find.byKey(key), findsOneWidget);
expect(findLiveTextButton(), findsOneWidget);
await tester.tap(findLiveTextButton());
await tester.pump();
expect(invokedLiveTextInputSuccessfully, isTrue);
},
skip: kIsWeb, // [intended]
);
// Regression test for https://github.com/flutter/flutter/issues/126312.
testWidgets('when open input connection in didUpdateWidget, should not throw', (WidgetTester tester) async {
final Key key = GlobalKey();

View File

@ -0,0 +1,40 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
/// A mock class to control the return result of Live Text input functions.
class LiveTextInputTester {
LiveTextInputTester() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, _handler);
}
bool mockLiveTextInputEnabled = false;
Future<Object?> _handler(MethodCall methodCall) async {
// Need to set Clipboard.hasStrings method handler because when showing the tool bar,
// the Clipboard.hasStrings will also be invoked. If this isn't handled,
// an exception will be thrown.
if (methodCall.method == 'Clipboard.hasStrings') {
return <String, bool>{'value': true};
}
if (methodCall.method == 'LiveText.isLiveTextInputAvailable') {
return mockLiveTextInputEnabled;
}
return false;
}
void dispose() {
assert(TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.checkMockMessageHandler(SystemChannels.platform.name, _handler));
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, null);
}
}
/// A function to find the live text button.
Finder findLiveTextButton() => find.byWidgetPredicate((Widget widget) =>
widget is CustomPaint &&
'${widget.painter?.runtimeType}' == '_LiveTextIconPainter',
);

View File

@ -416,6 +416,9 @@ class MaterialLocalizationAf extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Stoor';
@override
String get scanTextButtonLabel => 'Skena umbhalo';
@override
String get scrimLabel => 'Skerm';
@ -891,6 +894,9 @@ class MaterialLocalizationAm extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'አስቀምጥ';
@override
String get scanTextButtonLabel => 'ጽሑፍ ይቃኙ';
@override
String get scrimLabel => 'ገዳቢ';
@ -1366,6 +1372,9 @@ class MaterialLocalizationAr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'الحفظ';
@override
String get scanTextButtonLabel => 'مسح النص';
@override
String get scrimLabel => 'تمويه';
@ -1841,6 +1850,9 @@ class MaterialLocalizationAs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'ছেভ কৰক';
@override
String get scanTextButtonLabel => 'স্কেন টেক্সট';
@override
String get scrimLabel => 'স্ক্ৰিম';
@ -2316,6 +2328,9 @@ class MaterialLocalizationAz extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Yadda saxlayın';
@override
String get scanTextButtonLabel => 'Mətni skan edin';
@override
String get scrimLabel => 'Kətan';
@ -2791,6 +2806,9 @@ class MaterialLocalizationBe extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Захаваць';
@override
String get scanTextButtonLabel => 'Сканаваць тэкст';
@override
String get scrimLabel => 'Палатно';
@ -3266,6 +3284,9 @@ class MaterialLocalizationBg extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Запазване';
@override
String get scanTextButtonLabel => 'Сканиране на текст';
@override
String get scrimLabel => 'Скрим';
@ -3741,6 +3762,9 @@ class MaterialLocalizationBn extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'সেভ করুন';
@override
String get scanTextButtonLabel => 'পাঠ্য স্ক্যান করুন';
@override
String get scrimLabel => 'স্ক্রিম';
@ -4216,6 +4240,9 @@ class MaterialLocalizationBs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Sačuvaj';
@override
String get scanTextButtonLabel => 'Skeniraj tekst';
@override
String get scrimLabel => 'Rubno';
@ -4691,6 +4718,9 @@ class MaterialLocalizationCa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Desa';
@override
String get scanTextButtonLabel => 'Escaneja el text';
@override
String get scrimLabel => 'Fons atenuat';
@ -5166,6 +5196,9 @@ class MaterialLocalizationCs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Uložit';
@override
String get scanTextButtonLabel => 'Naskenujte text';
@override
String get scrimLabel => 'Scrim';
@ -5641,6 +5674,9 @@ class MaterialLocalizationCy extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Cadw';
@override
String get scanTextButtonLabel => 'Scan text';
@override
String get scrimLabel => 'Scrim';
@ -6116,6 +6152,9 @@ class MaterialLocalizationDa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Gem';
@override
String get scanTextButtonLabel => 'Scan tekst';
@override
String get scrimLabel => 'Dæmpeskærm';
@ -6591,6 +6630,9 @@ class MaterialLocalizationDe extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Speichern';
@override
String get scanTextButtonLabel => 'Text scannen';
@override
String get scrimLabel => 'Gitter';
@ -7130,6 +7172,9 @@ class MaterialLocalizationEl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Αποθήκευση';
@override
String get scanTextButtonLabel => 'Σάρωση κειμένου';
@override
String get scrimLabel => 'Επικάλυψη';
@ -7605,6 +7650,9 @@ class MaterialLocalizationEn extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Save';
@override
String get scanTextButtonLabel => 'Scan text';
@override
String get scrimLabel => 'Scrim';
@ -8814,6 +8862,9 @@ class MaterialLocalizationEs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Guardar';
@override
String get scanTextButtonLabel => 'Escanear texto';
@override
String get scrimLabel => 'Sombreado';
@ -12672,6 +12723,9 @@ class MaterialLocalizationEt extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Salvesta';
@override
String get scanTextButtonLabel => 'Skanni teksti';
@override
String get scrimLabel => 'Sirm';
@ -13147,6 +13201,9 @@ class MaterialLocalizationEu extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Gorde';
@override
String get scanTextButtonLabel => 'Eskaneatu testua';
@override
String get scrimLabel => 'Barrera';
@ -13622,6 +13679,9 @@ class MaterialLocalizationFa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'ذخیره';
@override
String get scanTextButtonLabel => 'اسکن متن';
@override
String get scrimLabel => 'رویه';
@ -14097,6 +14157,9 @@ class MaterialLocalizationFi extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Tallenna';
@override
String get scanTextButtonLabel => 'Skannaa tekstiä';
@override
String get scrimLabel => 'Sermi';
@ -14572,6 +14635,9 @@ class MaterialLocalizationFil extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'I-save';
@override
String get scanTextButtonLabel => 'I-scan ang text';
@override
String get scrimLabel => 'Scrim';
@ -15047,6 +15113,9 @@ class MaterialLocalizationFr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Enregistrer';
@override
String get scanTextButtonLabel => 'Numériser du texte';
@override
String get scrimLabel => 'Fond';
@ -15664,6 +15733,9 @@ class MaterialLocalizationGl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Gardar';
@override
String get scanTextButtonLabel => 'Escanear texto';
@override
String get scrimLabel => 'Sombreado';
@ -16139,6 +16211,9 @@ class MaterialLocalizationGsw extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Speichern';
@override
String get scanTextButtonLabel => 'Text scannen';
@override
String get scrimLabel => 'Gitter';
@ -16614,6 +16689,9 @@ class MaterialLocalizationGu extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'સાચવો';
@override
String get scanTextButtonLabel => 'ટેક્સ્ટ સ્કેન કરો';
@override
String get scrimLabel => 'સ્ક્રિમ';
@ -17089,6 +17167,9 @@ class MaterialLocalizationHe extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'שמירה';
@override
String get scanTextButtonLabel => 'סרוק טקסט';
@override
String get scrimLabel => 'מיסוך';
@ -17564,6 +17645,9 @@ class MaterialLocalizationHi extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'सेव करें';
@override
String get scanTextButtonLabel => 'पाठ स्कैन करें';
@override
String get scrimLabel => 'स्क्रिम';
@ -18039,6 +18123,9 @@ class MaterialLocalizationHr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Spremi';
@override
String get scanTextButtonLabel => 'Skeniraj tekst';
@override
String get scrimLabel => 'Rubno';
@ -18514,6 +18601,9 @@ class MaterialLocalizationHu extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Mentés';
@override
String get scanTextButtonLabel => 'Szöveg beolvasása';
@override
String get scrimLabel => 'Borítás';
@ -18989,6 +19079,9 @@ class MaterialLocalizationHy extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Պահել';
@override
String get scanTextButtonLabel => 'Սկանավորեք տեքստը';
@override
String get scrimLabel => 'Դիմակ';
@ -19464,6 +19557,9 @@ class MaterialLocalizationId extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Simpan';
@override
String get scanTextButtonLabel => 'Pindai teks';
@override
String get scrimLabel => 'Scrim';
@ -19939,6 +20035,9 @@ class MaterialLocalizationIs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Vista';
@override
String get scanTextButtonLabel => 'Skannaðu texta';
@override
String get scrimLabel => 'Möskvi';
@ -20414,6 +20513,9 @@ class MaterialLocalizationIt extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Salva';
@override
String get scanTextButtonLabel => 'Scansiona il testo';
@override
String get scrimLabel => 'Rete';
@ -20889,6 +20991,9 @@ class MaterialLocalizationJa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => '保存';
@override
String get scanTextButtonLabel => 'テキストをスキャン';
@override
String get scrimLabel => 'スクリム';
@ -21364,6 +21469,9 @@ class MaterialLocalizationKa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'შენახვა';
@override
String get scanTextButtonLabel => 'ტექსტის სკანირება';
@override
String get scrimLabel => 'სკრიმი';
@ -21839,6 +21947,9 @@ class MaterialLocalizationKk extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Сақтау';
@override
String get scanTextButtonLabel => 'Мәтінді сканерлеу';
@override
String get scrimLabel => 'Кенеп';
@ -22314,6 +22425,9 @@ class MaterialLocalizationKm extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'រក្សាទុក';
@override
String get scanTextButtonLabel => 'ស្កេនអត្ថបទ';
@override
String get scrimLabel => 'ផ្ទាំងស្រអាប់';
@ -22789,6 +22903,9 @@ class MaterialLocalizationKn extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => '\u{c89}\u{cb3}\u{cbf}\u{cb8}\u{cbf}';
@override
String get scanTextButtonLabel => '\u{caa}\u{ca0}\u{ccd}\u{caf}\u{cb5}\u{ca8}\u{ccd}\u{ca8}\u{cc1}\u{20}\u{cb8}\u{ccd}\u{c95}\u{ccd}\u{caf}\u{cbe}\u{ca8}\u{ccd}\u{20}\u{cae}\u{cbe}\u{ca1}\u{cbf}';
@override
String get scrimLabel => '\u{cb8}\u{ccd}\u{c95}\u{ccd}\u{cb0}\u{cbf}\u{cae}\u{ccd}';
@ -23264,6 +23381,9 @@ class MaterialLocalizationKo extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => '저장';
@override
String get scanTextButtonLabel => '스캔 텍스트';
@override
String get scrimLabel => '스크림';
@ -23739,6 +23859,9 @@ class MaterialLocalizationKy extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Сактоо';
@override
String get scanTextButtonLabel => 'Текстти скандоо';
@override
String get scrimLabel => 'Кенеп';
@ -24214,6 +24337,9 @@ class MaterialLocalizationLo extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'ບັນທຶກ';
@override
String get scanTextButtonLabel => 'ສະແກນຂໍ້ຄວາມ';
@override
String get scrimLabel => 'Scrim';
@ -24689,6 +24815,9 @@ class MaterialLocalizationLt extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Išsaugoti';
@override
String get scanTextButtonLabel => 'Nuskaityti tekstą';
@override
String get scrimLabel => 'Užsklanda';
@ -25164,6 +25293,9 @@ class MaterialLocalizationLv extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Saglabāt';
@override
String get scanTextButtonLabel => 'Skenēt tekstu';
@override
String get scrimLabel => 'Pārklājums';
@ -25639,6 +25771,9 @@ class MaterialLocalizationMk extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Зачувај';
@override
String get scanTextButtonLabel => 'Скенирајте текст';
@override
String get scrimLabel => 'Скрим';
@ -26114,6 +26249,9 @@ class MaterialLocalizationMl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'സംരക്ഷിക്കുക';
@override
String get scanTextButtonLabel => 'ടെക്സ്റ്റ് സ്കാൻ ചെയ്യുക';
@override
String get scrimLabel => 'സ്ക്രിം';
@ -26589,6 +26727,9 @@ class MaterialLocalizationMn extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Хадгалах';
@override
String get scanTextButtonLabel => 'Текст сканнердах';
@override
String get scrimLabel => 'Скрим';
@ -27064,6 +27205,9 @@ class MaterialLocalizationMr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'सेव्ह करा';
@override
String get scanTextButtonLabel => 'मजकूर स्कॅन करा';
@override
String get scrimLabel => 'स्क्रिम';
@ -27539,6 +27683,9 @@ class MaterialLocalizationMs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Simpan';
@override
String get scanTextButtonLabel => 'Pindai teks';
@override
String get scrimLabel => 'Scrim';
@ -28014,6 +28161,9 @@ class MaterialLocalizationMy extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'သိမ်းရန်';
@override
String get scanTextButtonLabel => 'စာသားကို စကင်ဖတ်ပါ။';
@override
String get scrimLabel => 'Scrim';
@ -28489,6 +28639,9 @@ class MaterialLocalizationNb extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Lagre';
@override
String get scanTextButtonLabel => 'Scan tekst';
@override
String get scrimLabel => 'Vev';
@ -28964,6 +29117,9 @@ class MaterialLocalizationNe extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'सेभ गर्नुहोस्';
@override
String get scanTextButtonLabel => 'पाठ स्क्यान गर्नुहोस्';
@override
String get scrimLabel => 'स्क्रिम';
@ -29439,6 +29595,9 @@ class MaterialLocalizationNl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Opslaan';
@override
String get scanTextButtonLabel => 'Tekst scannen';
@override
String get scrimLabel => 'Scrim';
@ -29914,6 +30073,9 @@ class MaterialLocalizationNo extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Lagre';
@override
String get scanTextButtonLabel => 'Skann tekst';
@override
String get scrimLabel => 'Vev';
@ -30389,6 +30551,9 @@ class MaterialLocalizationOr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'ସେଭ କରନ୍ତୁ';
@override
String get scanTextButtonLabel => 'ପାଠ୍ୟ ସ୍କାନ୍ କରନ୍ତୁ';
@override
String get scrimLabel => 'ସ୍କ୍ରିମ';
@ -30864,6 +31029,9 @@ class MaterialLocalizationPa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'ਰੱਖਿਅਤ ਕਰੋ';
@override
String get scanTextButtonLabel => 'ਟੈਕਸਟ ਸਕੈਨ ਕਰੋ';
@override
String get scrimLabel => 'ਸਕ੍ਰਿਮ';
@ -31339,6 +31507,9 @@ class MaterialLocalizationPl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Zapisz';
@override
String get scanTextButtonLabel => 'Zeskanuj tekst';
@override
String get scrimLabel => 'Siatka';
@ -31814,6 +31985,9 @@ class MaterialLocalizationPs extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'SAVE';
@override
String get scanTextButtonLabel => 'متن سکین کړئ';
@override
String get scrimLabel => 'Scrim';
@ -32289,6 +32463,9 @@ class MaterialLocalizationPt extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Salvar';
@override
String get scanTextButtonLabel => 'Digitalizar texto';
@override
String get scrimLabel => 'Scrim';
@ -32915,6 +33092,9 @@ class MaterialLocalizationRo extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Salvați';
@override
String get scanTextButtonLabel => 'Scanați textul';
@override
String get scrimLabel => 'Material';
@ -33390,6 +33570,9 @@ class MaterialLocalizationRu extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Сохранить';
@override
String get scanTextButtonLabel => 'Сканировать текст';
@override
String get scrimLabel => 'Маска';
@ -33865,6 +34048,9 @@ class MaterialLocalizationSi extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'සුරකින්න';
@override
String get scanTextButtonLabel => 'පෙළ පරිලෝකනය කරන්න';
@override
String get scrimLabel => 'ස්ක්‍රිම්';
@ -34340,6 +34526,9 @@ class MaterialLocalizationSk extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Uložiť';
@override
String get scanTextButtonLabel => 'Naskenujte text';
@override
String get scrimLabel => 'Scrim';
@ -34815,6 +35004,9 @@ class MaterialLocalizationSl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Shrani';
@override
String get scanTextButtonLabel => 'Skeniraj besedilo';
@override
String get scrimLabel => 'Scrim';
@ -35290,6 +35482,9 @@ class MaterialLocalizationSq extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Ruaj';
@override
String get scanTextButtonLabel => 'Skanoni tekstin';
@override
String get scrimLabel => 'Kanavacë';
@ -35765,6 +35960,9 @@ class MaterialLocalizationSr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Сачувај';
@override
String get scanTextButtonLabel => 'Скенирајте текст';
@override
String get scrimLabel => 'Скрим';
@ -36554,6 +36752,9 @@ class MaterialLocalizationSv extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Spara';
@override
String get scanTextButtonLabel => 'Skanna text';
@override
String get scrimLabel => 'Scrim';
@ -37029,6 +37230,9 @@ class MaterialLocalizationSw extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Hifadhi';
@override
String get scanTextButtonLabel => 'Changanua maandishi';
@override
String get scrimLabel => 'Scrim';
@ -37504,6 +37708,9 @@ class MaterialLocalizationTa extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'சேமி';
@override
String get scanTextButtonLabel => 'உரையை ஸ்கேன் செய்யவும்';
@override
String get scrimLabel => 'ஸ்க்ரிம்';
@ -37979,6 +38186,9 @@ class MaterialLocalizationTe extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'సేవ్ చేయండి';
@override
String get scanTextButtonLabel => 'వచనాన్ని స్కాన్ చేయండి';
@override
String get scrimLabel => 'స్క్రిమ్';
@ -38454,6 +38664,9 @@ class MaterialLocalizationTh extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'บันทึก';
@override
String get scanTextButtonLabel => 'สแกนข้อความ';
@override
String get scrimLabel => 'Scrim';
@ -38929,6 +39142,9 @@ class MaterialLocalizationTl extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'I-save';
@override
String get scanTextButtonLabel => 'I-scan ang text';
@override
String get scrimLabel => 'Scrim';
@ -39404,6 +39620,9 @@ class MaterialLocalizationTr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Kaydet';
@override
String get scanTextButtonLabel => 'Metni tara';
@override
String get scrimLabel => 'opaklık katmanı';
@ -39879,6 +40098,9 @@ class MaterialLocalizationUk extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Зберегти';
@override
String get scanTextButtonLabel => 'Сканувати текст';
@override
String get scrimLabel => 'Маскувальний фон';
@ -40354,6 +40576,9 @@ class MaterialLocalizationUr extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'محفوظ کریں';
@override
String get scanTextButtonLabel => 'متن کو اسکین کریں';
@override
String get scrimLabel => 'اسکریم';
@ -40829,6 +41054,9 @@ class MaterialLocalizationUz extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Saqlash';
@override
String get scanTextButtonLabel => 'Matnni skanerlash';
@override
String get scrimLabel => 'Kanop';
@ -41304,6 +41532,9 @@ class MaterialLocalizationVi extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Lưu';
@override
String get scanTextButtonLabel => 'Quét văn bản';
@override
String get scrimLabel => 'Scrim';
@ -41779,6 +42010,9 @@ class MaterialLocalizationZh extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => '保存';
@override
String get scanTextButtonLabel => '扫描文本';
@override
String get scrimLabel => '纱罩';
@ -42747,6 +42981,9 @@ class MaterialLocalizationZu extends GlobalMaterialLocalizations {
@override
String get saveButtonLabel => 'Londoloza';
@override
String get scanTextButtonLabel => 'Skena umbhalo';
@override
String get scrimLabel => 'I-Scrim';

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Gaan voort",
"copyButtonLabel": "Kopieer",
"cutButtonLabel": "Knip",
"scanTextButtonLabel": "Skena umbhalo",
"okButtonLabel": "OK",
"pasteButtonLabel": "Plak",
"selectAllButtonLabel": "Kies alles",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ቀጥል",
"copyButtonLabel": "ቅዳ",
"cutButtonLabel": "ቁረጥ",
"scanTextButtonLabel": "ጽሑፍ ይቃኙ",
"okButtonLabel": "እሺ",
"pasteButtonLabel": "ለጥፍ",
"selectAllButtonLabel": "ሁሉንም ምረጥ",

View File

@ -35,6 +35,7 @@
"continueButtonLabel": "المتابعة",
"copyButtonLabel": "نسخ",
"cutButtonLabel": "قص",
"scanTextButtonLabel": "مسح النص",
"okButtonLabel": "حسنًا",
"pasteButtonLabel": "لصق",
"selectAllButtonLabel": "اختيار الكل",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "অব্যাহত ৰাখক",
"copyButtonLabel": "প্ৰতিলিপি কৰক",
"cutButtonLabel": "কাট কৰক",
"scanTextButtonLabel": "স্কেন টেক্সট",
"okButtonLabel": "ঠিক আছে",
"pasteButtonLabel": "পে'ষ্ট কৰক",
"selectAllButtonLabel": "সকলো বাছনি কৰক",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Davam edin",
"copyButtonLabel": "Kopyalayın",
"cutButtonLabel": "Kəsin",
"scanTextButtonLabel": "Mətni skan edin",
"okButtonLabel": "OK",
"pasteButtonLabel": "Yerləşdirin",
"selectAllButtonLabel": "Hamısını seçin",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Працягнуць",
"copyButtonLabel": "Капіраваць",
"cutButtonLabel": "Выразаць",
"scanTextButtonLabel": "Сканаваць тэкст",
"okButtonLabel": "ОК",
"pasteButtonLabel": "Уставіць",
"selectAllButtonLabel": "Выбраць усе",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Напред",
"copyButtonLabel": "Копиране",
"cutButtonLabel": "Изрязване",
"scanTextButtonLabel": "Сканиране на текст",
"okButtonLabel": "OK",
"pasteButtonLabel": "Поставяне",
"selectAllButtonLabel": "Избиране на всички",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "চালিয়ে যান",
"copyButtonLabel": "কপি করুন",
"cutButtonLabel": "কাট করুন",
"scanTextButtonLabel": "পাঠ্য স্ক্যান করুন",
"okButtonLabel": "ঠিক আছে",
"pasteButtonLabel": "পেস্ট করুন",
"selectAllButtonLabel": "সব বেছে নিন",

View File

@ -28,6 +28,7 @@
"continueButtonLabel": "Nastavi",
"copyButtonLabel": "Kopiraj",
"cutButtonLabel": "Izreži",
"scanTextButtonLabel": "Skeniraj tekst",
"okButtonLabel": "Uredu",
"pasteButtonLabel": "Zalijepi",
"selectAllButtonLabel": "Odaberi sve",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Continua",
"copyButtonLabel": "Copia",
"cutButtonLabel": "Retalla",
"scanTextButtonLabel": "Escaneja el text",
"okButtonLabel": "D'ACORD",
"pasteButtonLabel": "Enganxa",
"selectAllButtonLabel": "Selecciona-ho tot",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Pokračovat",
"copyButtonLabel": "Kopírovat",
"cutButtonLabel": "Vyjmout",
"scanTextButtonLabel": "Naskenujte text",
"okButtonLabel": "OK",
"pasteButtonLabel": "Vložit",
"selectAllButtonLabel": "Vybrat vše",

View File

@ -150,5 +150,6 @@
"expansionTileExpandedTapHint": "Collapse",
"expansionTileCollapsedTapHint": "Expand for more details",
"expandedHint": "Collapsed",
"collapsedHint": "Expanded"
"collapsedHint": "Expanded",
"scanTextButtonLabel": "Scan text"
}

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Fortsæt",
"copyButtonLabel": "Kopiér",
"cutButtonLabel": "Klip",
"scanTextButtonLabel": "Scan tekst",
"okButtonLabel": "OK",
"pasteButtonLabel": "Indsæt",
"selectAllButtonLabel": "Markér alt",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Weiter",
"copyButtonLabel": "Kopieren",
"cutButtonLabel": "Ausschneiden",
"scanTextButtonLabel": "Text scannen",
"okButtonLabel": "OK",
"pasteButtonLabel": "Einsetzen",
"selectAllButtonLabel": "Alle auswählen",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Συνέχεια",
"copyButtonLabel": "Αντιγραφή",
"cutButtonLabel": "Αποκοπή",
"scanTextButtonLabel": "Σάρωση κειμένου",
"okButtonLabel": "ΟΚ",
"pasteButtonLabel": "Επικόλληση",
"selectAllButtonLabel": "Επιλογή όλων",

View File

@ -192,6 +192,11 @@
"description": "The label for cut buttons and menu items."
},
"scanTextButtonLabel": "Scan text",
"@scanTextButtonLabel": {
"description": "The label for scan text buttons and menu items for starting the insertion of text via OCR."
},
"okButtonLabel": "OK",
"@okButtonLabel": {
"description": "The label for OK buttons and menu items."

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Continuar",
"copyButtonLabel": "Copiar",
"cutButtonLabel": "Cortar",
"scanTextButtonLabel": "Escanear texto",
"okButtonLabel": "ACEPTAR",
"pasteButtonLabel": "Pegar",
"selectAllButtonLabel": "Seleccionar todo",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Jätka",
"copyButtonLabel": "Kopeeri",
"cutButtonLabel": "Lõika",
"scanTextButtonLabel": "Skanni teksti",
"okButtonLabel": "OK",
"pasteButtonLabel": "Kleebi",
"selectAllButtonLabel": "Vali kõik",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Egin aurrera",
"copyButtonLabel": "Kopiatu",
"cutButtonLabel": "Ebaki",
"scanTextButtonLabel": "Eskaneatu testua",
"okButtonLabel": "Ados",
"pasteButtonLabel": "Itsatsi",
"selectAllButtonLabel": "Hautatu guztiak",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ادامه",
"copyButtonLabel": "کپی",
"cutButtonLabel": "برش",
"scanTextButtonLabel": "اسکن متن",
"okButtonLabel": "تأیید",
"pasteButtonLabel": "جای‌گذاری",
"selectAllButtonLabel": "انتخاب همه",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Jatka",
"copyButtonLabel": "Kopioi",
"cutButtonLabel": "Leikkaa",
"scanTextButtonLabel": "Skannaa tekstiä",
"okButtonLabel": "OK",
"pasteButtonLabel": "Liitä",
"selectAllButtonLabel": "Valitse kaikki",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Magpatuloy",
"copyButtonLabel": "Kopyahin",
"cutButtonLabel": "I-cut",
"scanTextButtonLabel": "I-scan ang text",
"okButtonLabel": "OK",
"pasteButtonLabel": "I-paste",
"selectAllButtonLabel": "Piliin lahat",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Continuer",
"copyButtonLabel": "Copier",
"cutButtonLabel": "Couper",
"scanTextButtonLabel": "Numériser du texte",
"okButtonLabel": "OK",
"pasteButtonLabel": "Coller",
"selectAllButtonLabel": "Tout sélectionner",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Continuar",
"copyButtonLabel": "Copiar",
"cutButtonLabel": "Cortar",
"scanTextButtonLabel": "Escanear texto",
"okButtonLabel": "Aceptar",
"pasteButtonLabel": "Pegar",
"selectAllButtonLabel": "Seleccionar todo",

View File

@ -30,6 +30,7 @@
"continueButtonLabel": "Weiter",
"copyButtonLabel": "Kopieren",
"cutButtonLabel": "Ausschneiden",
"scanTextButtonLabel": "Text scannen",
"okButtonLabel": "OK",
"pasteButtonLabel": "Einsetzen",
"selectAllButtonLabel": "Alle auswählen",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ચાલુ રાખો",
"copyButtonLabel": "કૉપિ કરો",
"cutButtonLabel": "કાપો",
"scanTextButtonLabel": "ટેક્સ્ટ સ્કેન કરો",
"okButtonLabel": "ઓકે",
"pasteButtonLabel": "પેસ્ટ કરો",
"selectAllButtonLabel": "બધા પસંદ કરો",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "המשך",
"copyButtonLabel": "העתקה",
"cutButtonLabel": "גזירה",
"scanTextButtonLabel": "סרוק טקסט",
"okButtonLabel": "אישור",
"pasteButtonLabel": "הדבקה",
"selectAllButtonLabel": "בחירת הכול",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "जारी रखें",
"copyButtonLabel": "कॉपी करें",
"cutButtonLabel": "काटें",
"scanTextButtonLabel": "पाठ स्कैन करें",
"okButtonLabel": "ठीक है",
"pasteButtonLabel": "चिपकाएं",
"selectAllButtonLabel": "सभी को चुनें",

View File

@ -28,6 +28,7 @@
"continueButtonLabel": "Nastavi",
"copyButtonLabel": "Kopiraj",
"cutButtonLabel": "Izreži",
"scanTextButtonLabel": "Skeniraj tekst",
"okButtonLabel": "U REDU",
"pasteButtonLabel": "Zalijepi",
"selectAllButtonLabel": "Odaberi sve",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Folytatás",
"copyButtonLabel": "Másolás",
"cutButtonLabel": "Kivágás",
"scanTextButtonLabel": "Szöveg beolvasása",
"okButtonLabel": "OK",
"pasteButtonLabel": "Beillesztés",
"selectAllButtonLabel": "Összes kijelölése",

View File

@ -30,6 +30,7 @@
"continueButtonLabel": "Շարունակել",
"copyButtonLabel": "Պատճենել",
"cutButtonLabel": "Կտրել",
"scanTextButtonLabel": "Սկանավորեք տեքստը",
"okButtonLabel": "Եղավ",
"pasteButtonLabel": "Տեղադրել",
"selectAllButtonLabel": "Նշել բոլորը",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Lanjutkan",
"copyButtonLabel": "Salin",
"cutButtonLabel": "Potong",
"scanTextButtonLabel": "Pindai teks",
"okButtonLabel": "OKE",
"pasteButtonLabel": "Tempel",
"selectAllButtonLabel": "Pilih semua",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Áfram",
"copyButtonLabel": "Afrita",
"cutButtonLabel": "Klippa",
"scanTextButtonLabel": "Skannaðu texta",
"okButtonLabel": "Í lagi",
"pasteButtonLabel": "Líma",
"selectAllButtonLabel": "Velja allt",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Continua",
"copyButtonLabel": "Copia",
"cutButtonLabel": "Taglia",
"scanTextButtonLabel": "Scansiona il testo",
"okButtonLabel": "OK",
"pasteButtonLabel": "Incolla",
"selectAllButtonLabel": "Seleziona tutto",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "続行",
"copyButtonLabel": "コピー",
"cutButtonLabel": "切り取り",
"scanTextButtonLabel": "テキストをスキャン",
"okButtonLabel": "OK",
"pasteButtonLabel": "貼り付け",
"selectAllButtonLabel": "すべて選択",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "გაგრძელება",
"copyButtonLabel": "კოპირება",
"cutButtonLabel": "ამოჭრა",
"scanTextButtonLabel": "ტექსტის სკანირება",
"okButtonLabel": "კარგი",
"pasteButtonLabel": "ჩასმა",
"selectAllButtonLabel": "ყველას არჩევა",

View File

@ -27,6 +27,7 @@
"continueButtonLabel": "Жалғастыру",
"copyButtonLabel": "Көшіру",
"cutButtonLabel": "Қию",
"scanTextButtonLabel": "Мәтінді сканерлеу",
"okButtonLabel": "Иә",
"pasteButtonLabel": "Қою",
"selectAllButtonLabel": "Барлығын таңдау",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "បន្ត",
"copyButtonLabel": "ចម្លង",
"cutButtonLabel": "កាត់",
"scanTextButtonLabel": "ស្កេនអត្ថបទ",
"okButtonLabel": "យល់ព្រម",
"pasteButtonLabel": "ដាក់​ចូល",
"selectAllButtonLabel": "ជ្រើសរើស​ទាំងអស់",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "\u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf",
"copyButtonLabel": "\u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cbf",
"cutButtonLabel": "\u0c95\u0ca4\u0ccd\u0ca4\u0cb0\u0cbf\u0cb8\u0cbf",
"scanTextButtonLabel": "\u0caa\u0ca0\u0ccd\u0caf\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1\u0020\u0cb8\u0ccd\u0c95\u0ccd\u0caf\u0cbe\u0ca8\u0ccd\u0020\u0cae\u0cbe\u0ca1\u0cbf",
"okButtonLabel": "\u0cb8\u0cb0\u0cbf",
"pasteButtonLabel": "\u0c85\u0c82\u0c9f\u0cbf\u0cb8\u0cbf",
"selectAllButtonLabel": "\u0c8e\u0cb2\u0ccd\u0cb2\u0cb5\u0ca8\u0ccd\u0ca8\u0cc2\u0020\u0c86\u0caf\u0ccd\u0c95\u0cc6\u0020\u0cae\u0cbe\u0ca1\u0cbf",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "계속",
"copyButtonLabel": "복사",
"cutButtonLabel": "잘라냄",
"scanTextButtonLabel": "스캔 텍스트",
"okButtonLabel": "확인",
"pasteButtonLabel": "붙여넣기",
"selectAllButtonLabel": "전체 선택",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Улантуу",
"copyButtonLabel": "Көчүрүү",
"cutButtonLabel": "Кесүү",
"scanTextButtonLabel": "Текстти скандоо",
"okButtonLabel": "Макул",
"pasteButtonLabel": "Чаптоо",
"selectAllButtonLabel": "Баарын тандоо",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ສືບຕໍ່",
"copyButtonLabel": "ສຳເນົາ",
"cutButtonLabel": "ຕັດ",
"scanTextButtonLabel": "ສະແກນຂໍ້ຄວາມ",
"okButtonLabel": "ຕົກລົງ",
"pasteButtonLabel": "ວາງ",
"selectAllButtonLabel": "ເລືອກທັງໝົດ",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Tęsti",
"copyButtonLabel": "Kopijuoti",
"cutButtonLabel": "Iškirpti",
"scanTextButtonLabel": "Nuskaityti tekstą",
"okButtonLabel": "GERAI",
"pasteButtonLabel": "Įklijuoti",
"selectAllButtonLabel": "Pasirinkti viską",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Turpināt",
"copyButtonLabel": "Kopēt",
"cutButtonLabel": "Izgriezt",
"scanTextButtonLabel": "Skenēt tekstu",
"okButtonLabel": "LABI",
"pasteButtonLabel": "Ielīmēt",
"selectAllButtonLabel": "Atlasīt visu",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Продолжи",
"copyButtonLabel": "Копирај",
"cutButtonLabel": "Исечи",
"scanTextButtonLabel": "Скенирајте текст",
"okButtonLabel": "Во ред",
"pasteButtonLabel": "Залепи",
"selectAllButtonLabel": "Избери ги сите",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "തുടരുക",
"copyButtonLabel": "പകർത്തുക",
"cutButtonLabel": "മുറിക്കുക",
"scanTextButtonLabel": "ടെക്സ്റ്റ് സ്കാൻ ചെയ്യുക",
"okButtonLabel": "ശരി",
"pasteButtonLabel": "ഒട്ടിക്കുക",
"selectAllButtonLabel": "എല്ലാം തിരഞ്ഞെടുക്കുക",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Үргэлжлүүлэх",
"copyButtonLabel": "Хуулах",
"cutButtonLabel": "Таслах",
"scanTextButtonLabel": "Текст сканнердах",
"okButtonLabel": "OK",
"pasteButtonLabel": "Буулгах",
"selectAllButtonLabel": "Бүгдийг сонгох",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "पुढे सुरू ठेवा",
"copyButtonLabel": "कॉपी करा",
"cutButtonLabel": "कट करा",
"scanTextButtonLabel": "मजकूर स्कॅन करा",
"okButtonLabel": "ओके",
"pasteButtonLabel": "पेस्ट करा",
"selectAllButtonLabel": "सर्व निवडा",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Teruskan",
"copyButtonLabel": "Salin",
"cutButtonLabel": "Potong",
"scanTextButtonLabel": "Pindai teks",
"okButtonLabel": "OK",
"pasteButtonLabel": "Tampal",
"selectAllButtonLabel": "Pilih semua",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ရှေ့ဆက်ရန်",
"copyButtonLabel": "မိတ္တူကူးရန်",
"cutButtonLabel": "ဖြတ်ယူရန်",
"scanTextButtonLabel": "စာသားကို စကင်ဖတ်ပါ။",
"okButtonLabel": "OK",
"pasteButtonLabel": "ကူးထည့်ရန်",
"selectAllButtonLabel": "အားလုံး ရွေးရန်",

View File

@ -28,6 +28,7 @@
"continueButtonLabel": "Fortsett",
"copyButtonLabel": "Kopiér",
"cutButtonLabel": "Klipp ut",
"scanTextButtonLabel": "Scan tekst",
"okButtonLabel": "OK",
"pasteButtonLabel": "Lim inn",
"selectAllButtonLabel": "Velg alle",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "जारी राख्नुहोस्",
"copyButtonLabel": "प्रतिलिपि गर्नुहोस्",
"cutButtonLabel": "काट्नुहोस्",
"scanTextButtonLabel": "पाठ स्क्यान गर्नुहोस्",
"okButtonLabel": "ठिक छ",
"pasteButtonLabel": "टाँस्नुहोस्",
"selectAllButtonLabel": "सबै बटनहरू चयन गर्नुहोस्",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Doorgaan",
"copyButtonLabel": "Kopiëren",
"cutButtonLabel": "Knippen",
"scanTextButtonLabel": "Tekst scannen",
"okButtonLabel": "OK",
"pasteButtonLabel": "Plakken",
"selectAllButtonLabel": "Alles selecteren",

View File

@ -28,6 +28,7 @@
"continueButtonLabel": "Fortsett",
"copyButtonLabel": "Kopiér",
"cutButtonLabel": "Klipp ut",
"scanTextButtonLabel": "Skann tekst",
"okButtonLabel": "OK",
"pasteButtonLabel": "Lim inn",
"selectAllButtonLabel": "Velg alle",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ଜାରି ରଖନ୍ତୁ",
"copyButtonLabel": "କପି କରନ୍ତୁ",
"cutButtonLabel": "କଟ୍ କରନ୍ତୁ",
"scanTextButtonLabel": "ପାଠ୍ୟ ସ୍କାନ୍ କରନ୍ତୁ",
"okButtonLabel": "ଠିକ୍ ଅଛି",
"pasteButtonLabel": "ପେଷ୍ଟ କରନ୍ତୁ",
"selectAllButtonLabel": "ସବୁ ଚୟନ କରନ୍ତୁ",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ਜਾਰੀ ਰੱਖੋ",
"copyButtonLabel": "ਕਾਪੀ ਕਰੋ",
"cutButtonLabel": "ਕੱਟ ਕਰੋ",
"scanTextButtonLabel": "ਟੈਕਸਟ ਸਕੈਨ ਕਰੋ",
"okButtonLabel": "ਠੀਕ ਹੈ",
"pasteButtonLabel": "ਪੇਸਟ ਕਰੋ",
"selectAllButtonLabel": "ਸਭ ਚੁਣੋ",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Dalej",
"copyButtonLabel": "Kopiuj",
"cutButtonLabel": "Wytnij",
"scanTextButtonLabel": "Zeskanuj tekst",
"okButtonLabel": "OK",
"pasteButtonLabel": "Wklej",
"selectAllButtonLabel": "Zaznacz wszystko",

View File

@ -28,6 +28,7 @@
"continueButtonLabel": "منځپانګې",
"copyButtonLabel": "کاپی",
"cutButtonLabel": "کم کړئ",
"scanTextButtonLabel": "متن سکین کړئ",
"okButtonLabel": "سمه ده",
"pasteButtonLabel": "پیټ کړئ",
"selectAllButtonLabel": "غوره کړئ",

View File

@ -29,6 +29,7 @@
"continueButtonLabel": "Continuar",
"copyButtonLabel": "Copiar",
"cutButtonLabel": "Cortar",
"scanTextButtonLabel": "Digitalizar texto",
"okButtonLabel": "OK",
"pasteButtonLabel": "Colar",
"selectAllButtonLabel": "Selecionar tudo",

View File

@ -29,6 +29,7 @@
"continueButtonLabel": "Continuați",
"copyButtonLabel": "Copiați",
"cutButtonLabel": "Decupați",
"scanTextButtonLabel": "Scanați textul",
"okButtonLabel": "OK",
"pasteButtonLabel": "Inserați",
"selectAllButtonLabel": "Selectați tot",

View File

@ -32,6 +32,7 @@
"continueButtonLabel": "Продолжить",
"copyButtonLabel": "Копировать",
"cutButtonLabel": "Вырезать",
"scanTextButtonLabel": "Сканировать текст",
"okButtonLabel": "ОК",
"pasteButtonLabel": "Вставить",
"selectAllButtonLabel": "Выбрать все",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ඉදිරියට යන්න",
"copyButtonLabel": "පිටපත් කරන්න",
"cutButtonLabel": "කපන්න",
"scanTextButtonLabel": "පෙළ පරිලෝකනය කරන්න",
"okButtonLabel": "හරි",
"pasteButtonLabel": "අලවන්න",
"selectAllButtonLabel": "සියල්ල තෝරන්න",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Pokračovať",
"copyButtonLabel": "Kopírovať",
"cutButtonLabel": "Vystrihnúť",
"scanTextButtonLabel": "Naskenujte text",
"okButtonLabel": "OK",
"pasteButtonLabel": "Prilepiť",
"selectAllButtonLabel": "Vybrať všetko",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Naprej",
"copyButtonLabel": "Kopiraj",
"cutButtonLabel": "Izreži",
"scanTextButtonLabel": "Skeniraj besedilo",
"okButtonLabel": "V REDU",
"pasteButtonLabel": "Prilepi",
"selectAllButtonLabel": "Izberi vse",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Vazhdo",
"copyButtonLabel": "Kopjo",
"cutButtonLabel": "Prit",
"scanTextButtonLabel": "Skanoni tekstin",
"okButtonLabel": "Në rregull",
"pasteButtonLabel": "Ngjit",
"selectAllButtonLabel": "Zgjidh të gjitha",

View File

@ -28,6 +28,7 @@
"continueButtonLabel": "Настави",
"copyButtonLabel": "Копирај",
"cutButtonLabel": "Исеци",
"scanTextButtonLabel": "Скенирајте текст",
"okButtonLabel": "Потврди",
"pasteButtonLabel": "Налепи",
"selectAllButtonLabel": "Изабери све",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Fortsätt",
"copyButtonLabel": "Kopiera",
"cutButtonLabel": "Klipp ut",
"scanTextButtonLabel": "Skanna text",
"okButtonLabel": "OK",
"pasteButtonLabel": "Klistra in",
"selectAllButtonLabel": "Markera allt",

View File

@ -26,6 +26,7 @@
"continueButtonLabel": "Endelea",
"copyButtonLabel": "Nakili",
"cutButtonLabel": "Kata",
"scanTextButtonLabel": "Changanua maandishi",
"okButtonLabel": "Sawa",
"pasteButtonLabel": "Bandika",
"selectAllButtonLabel": "Chagua vyote",

View File

@ -17,6 +17,7 @@
"reorderItemLeft": "இடப்புறம் நகர்த்தவும்",
"reorderItemRight": "வலப்புறம் நகர்த்தவும்",
"cutButtonLabel": "வெட்டு",
"scanTextButtonLabel": "உரையை ஸ்கேன் செய்யவும்",
"pasteButtonLabel": "ஒட்டு",
"previousMonthTooltip": "முந்தைய மாதம்",
"nextMonthTooltip": "அடுத்த மாதம்",

View File

@ -24,6 +24,7 @@
"closeButtonLabel": "మూసివేయండి",
"continueButtonLabel": "కొనసాగించండి",
"copyButtonLabel": "కాపీ చేయి",
"scanTextButtonLabel": "వచనాన్ని స్కాన్ చేయండి",
"cutButtonLabel": "కత్తిరించండి",
"okButtonLabel": "సరే",
"pasteButtonLabel": "పేస్ట్ చేయండి",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "ต่อไป",
"copyButtonLabel": "คัดลอก",
"cutButtonLabel": "ตัด",
"scanTextButtonLabel": "สแกนข้อความ",
"okButtonLabel": "ตกลง",
"pasteButtonLabel": "วาง",
"selectAllButtonLabel": "เลือกทั้งหมด",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Magpatuloy",
"copyButtonLabel": "Kopyahin",
"cutButtonLabel": "I-cut",
"scanTextButtonLabel": "I-scan ang text",
"okButtonLabel": "OK",
"pasteButtonLabel": "I-paste",
"selectAllButtonLabel": "Piliin lahat",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Devam",
"copyButtonLabel": "Kopyala",
"cutButtonLabel": "Kes",
"scanTextButtonLabel": "Metni tara",
"okButtonLabel": "Tamam",
"pasteButtonLabel": "Yapıştır",
"selectAllButtonLabel": "Tümünü seç",

View File

@ -31,6 +31,7 @@
"continueButtonLabel": "Продовжити",
"copyButtonLabel": "Копіювати",
"cutButtonLabel": "Вирізати",
"scanTextButtonLabel": "Сканувати текст",
"okButtonLabel": "OK",
"pasteButtonLabel": "Вставити",
"selectAllButtonLabel": "Вибрати всі",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "جاری رکھیں",
"copyButtonLabel": "کاپی کریں",
"cutButtonLabel": "کٹ کریں",
"scanTextButtonLabel": "متن کو اسکین کریں",
"okButtonLabel": "ٹھیک ہے",
"pasteButtonLabel": "پیسٹ کریں",
"selectAllButtonLabel": "سبھی کو منتخب کریں",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Davom etish",
"copyButtonLabel": "Nusxa olish",
"cutButtonLabel": "Kesib olish",
"scanTextButtonLabel": "Matnni skanerlash",
"okButtonLabel": "OK",
"pasteButtonLabel": "Joylash",
"selectAllButtonLabel": "Hammasi",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Tiếp tục",
"copyButtonLabel": "Sao chép",
"cutButtonLabel": "Cắt",
"scanTextButtonLabel": "Quét văn bản",
"okButtonLabel": "OK",
"pasteButtonLabel": "Dán",
"selectAllButtonLabel": "Chọn tất cả",

View File

@ -21,6 +21,7 @@
"closeButtonLabel": "关闭",
"copyButtonLabel": "复制",
"cutButtonLabel": "剪切",
"scanTextButtonLabel": "扫描文本",
"okButtonLabel": "确定",
"pasteButtonLabel": "粘贴",
"selectAllButtonLabel": "全选",

View File

@ -25,6 +25,7 @@
"continueButtonLabel": "Qhubeka",
"copyButtonLabel": "Kopisha",
"cutButtonLabel": "Sika",
"scanTextButtonLabel": "Skena umbhalo",
"okButtonLabel": "KULUNGILE",
"pasteButtonLabel": "Namathisela",
"selectAllButtonLabel": "Khetha konke",