Unverified Commit e0ad1296 authored by luckysmg's avatar luckysmg Committed by GitHub

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

iOS OCR keyboard input support.
parent 2f7614a8
...@@ -25,6 +25,7 @@ export 'src/services/hardware_keyboard.dart'; ...@@ -25,6 +25,7 @@ export 'src/services/hardware_keyboard.dart';
export 'src/services/keyboard_inserted_content.dart'; export 'src/services/keyboard_inserted_content.dart';
export 'src/services/keyboard_key.g.dart'; export 'src/services/keyboard_key.g.dart';
export 'src/services/keyboard_maps.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_codec.dart';
export 'src/services/message_codecs.dart'; export 'src/services/message_codecs.dart';
export 'src/services/mouse_cursor.dart'; export 'src/services/mouse_cursor.dart';
......
...@@ -94,6 +94,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { ...@@ -94,6 +94,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget {
required VoidCallback? onCut, required VoidCallback? onCut,
required VoidCallback? onPaste, required VoidCallback? onPaste,
required VoidCallback? onSelectAll, required VoidCallback? onSelectAll,
required VoidCallback? onLiveTextInput,
required this.anchors, required this.anchors,
}) : children = null, }) : children = null,
buttonItems = EditableText.getEditableButtonItems( buttonItems = EditableText.getEditableButtonItems(
...@@ -102,6 +103,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget { ...@@ -102,6 +103,7 @@ class CupertinoAdaptiveTextSelectionToolbar extends StatelessWidget {
onCut: onCut, onCut: onCut,
onPaste: onPaste, onPaste: onPaste,
onSelectAll: onSelectAll, onSelectAll: onSelectAll,
onLiveTextInput: onLiveTextInput
); );
/// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the /// Create an instance of [CupertinoAdaptiveTextSelectionToolbar] with the
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:math';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'button.dart'; import 'button.dart';
...@@ -103,6 +105,7 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget { ...@@ -103,6 +105,7 @@ class CupertinoTextSelectionToolbarButton extends StatefulWidget {
return localizations.pasteButtonLabel; return localizations.pasteButtonLabel;
case ContextMenuButtonType.selectAll: case ContextMenuButtonType.selectAll:
return localizations.selectAllButtonLabel; return localizations.selectAllButtonLabel;
case ContextMenuButtonType.liveTextInput:
case ContextMenuButtonType.delete: case ContextMenuButtonType.delete:
case ContextMenuButtonType.custom: case ContextMenuButtonType.custom:
return ''; return '';
...@@ -131,6 +134,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec ...@@ -131,6 +134,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Widget content = _getContentWidget(context);
final Widget child = CupertinoButton( final Widget child = CupertinoButton(
color: isPressed color: isPressed
? _kToolbarPressedColor.resolveFrom(context) ? _kToolbarPressedColor.resolveFrom(context)
...@@ -145,15 +149,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec ...@@ -145,15 +149,7 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec
// There's no foreground fade on iOS toolbar anymore, just the background // There's no foreground fade on iOS toolbar anymore, just the background
// is darkened. // is darkened.
pressedOpacity: 1.0, pressedOpacity: 1.0,
child: widget.child ?? Text( child: content,
widget.text ?? CupertinoTextSelectionToolbarButton.getButtonLabel(context, widget.buttonItem!),
overflow: TextOverflow.ellipsis,
style: _kToolbarButtonFontStyle.copyWith(
color: widget.onPressed != null
? _kToolbarTextColor.resolveFrom(context)
: CupertinoColors.inactiveGray,
),
),
); );
if (widget.onPressed != null) { if (widget.onPressed != null) {
...@@ -170,4 +166,85 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec ...@@ -170,4 +166,85 @@ class _CupertinoTextSelectionToolbarButtonState extends State<CupertinoTextSelec
return child; 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;
}
} }
...@@ -103,6 +103,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { ...@@ -103,6 +103,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
required VoidCallback? onCut, required VoidCallback? onCut,
required VoidCallback? onPaste, required VoidCallback? onPaste,
required VoidCallback? onSelectAll, required VoidCallback? onSelectAll,
required VoidCallback? onLiveTextInput,
required this.anchors, required this.anchors,
}) : children = null, }) : children = null,
buttonItems = EditableText.getEditableButtonItems( buttonItems = EditableText.getEditableButtonItems(
...@@ -111,6 +112,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { ...@@ -111,6 +112,7 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
onCut: onCut, onCut: onCut,
onPaste: onPaste, onPaste: onPaste,
onSelectAll: onSelectAll, onSelectAll: onSelectAll,
onLiveTextInput: onLiveTextInput
); );
/// Create an instance of [AdaptiveTextSelectionToolbar] with the default /// Create an instance of [AdaptiveTextSelectionToolbar] with the default
...@@ -213,6 +215,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { ...@@ -213,6 +215,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
return localizations.selectAllButtonLabel; return localizations.selectAllButtonLabel;
case ContextMenuButtonType.delete: case ContextMenuButtonType.delete:
return localizations.deleteButtonTooltip.toUpperCase(); return localizations.deleteButtonTooltip.toUpperCase();
case ContextMenuButtonType.liveTextInput:
return localizations.scanTextButtonLabel;
case ContextMenuButtonType.custom: case ContextMenuButtonType.custom:
return ''; return '';
} }
...@@ -242,9 +246,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget { ...@@ -242,9 +246,8 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
switch (Theme.of(context).platform) { switch (Theme.of(context).platform) {
case TargetPlatform.iOS: case TargetPlatform.iOS:
return buttonItems.map((ContextMenuButtonItem buttonItem) { return buttonItems.map((ContextMenuButtonItem buttonItem) {
return CupertinoTextSelectionToolbarButton.text( return CupertinoTextSelectionToolbarButton.buttonItem(
onPressed: buttonItem.onPressed, buttonItem: buttonItem,
text: getButtonLabel(context, buttonItem),
); );
}); });
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
......
...@@ -103,6 +103,9 @@ abstract class MaterialLocalizations { ...@@ -103,6 +103,9 @@ abstract class MaterialLocalizations {
/// Label for "cut" edit buttons and menu items. /// Label for "cut" edit buttons and menu items.
String get cutButtonLabel; String get cutButtonLabel;
/// Label for "scan text" OCR edit buttons and menu items.
String get scanTextButtonLabel;
/// Label for OK buttons and menu items. /// Label for OK buttons and menu items.
String get okButtonLabel; String get okButtonLabel;
...@@ -1159,6 +1162,9 @@ class DefaultMaterialLocalizations implements MaterialLocalizations { ...@@ -1159,6 +1162,9 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
@override @override
String get cutButtonLabel => 'Cut'; String get cutButtonLabel => 'Cut';
@override
String get scanTextButtonLabel => 'Scan text';
@override @override
String get okButtonLabel => 'OK'; String get okButtonLabel => 'OK';
......
// 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');
}
}
...@@ -1050,6 +1050,13 @@ mixin TextSelectionDelegate { ...@@ -1050,6 +1050,13 @@ mixin TextSelectionDelegate {
/// Whether select all is enabled, must not be null. /// Whether select all is enabled, must not be null.
bool get selectAllEnabled => true; 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]. /// Cut current selection to [Clipboard].
/// ///
/// If and only if [cause] is [SelectionChangedCause.toolbar], the toolbar /// If and only if [cause] is [SelectionChangedCause.toolbar], the toolbar
......
...@@ -26,6 +26,13 @@ enum ContextMenuButtonType { ...@@ -26,6 +26,13 @@ enum ContextMenuButtonType {
/// A button that deletes the current text selection. /// A button that deletes the current text selection.
delete, 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. /// Anything other than the default button types.
custom, custom,
} }
......
...@@ -1835,36 +1835,48 @@ class EditableText extends StatefulWidget { ...@@ -1835,36 +1835,48 @@ class EditableText extends StatefulWidget {
required final VoidCallback? onCut, required final VoidCallback? onCut,
required final VoidCallback? onPaste, required final VoidCallback? onPaste,
required final VoidCallback? onSelectAll, required final VoidCallback? onSelectAll,
required final VoidCallback? onLiveTextInput,
}) { }) {
// If the paste button is enabled, don't render anything until the state final List<ContextMenuButtonItem> resultButtonItem = <ContextMenuButtonItem>[];
// of the clipboard is known, since it's used to determine if paste is
// shown. // Configure button items with clipboard.
if (onPaste != null && clipboardStatus == ClipboardStatus.unknown) { if (onPaste == null || clipboardStatus != ClipboardStatus.unknown) {
return <ContextMenuButtonItem>[]; // 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>[ // Config button items with Live Text.
if (onCut != null) if (onLiveTextInput != null) {
ContextMenuButtonItem( resultButtonItem.add(ContextMenuButtonItem(
onPressed: onCut, onPressed: onLiveTextInput,
type: ContextMenuButtonType.cut, type: ContextMenuButtonType.liveTextInput,
), ));
if (onCopy != null) }
ContextMenuButtonItem(
onPressed: onCopy, return resultButtonItem;
type: ContextMenuButtonType.copy,
),
if (onPaste != null)
ContextMenuButtonItem(
onPressed: onPaste,
type: ContextMenuButtonType.paste,
),
if (onSelectAll != null)
ContextMenuButtonItem(
onPressed: onSelectAll,
type: ContextMenuButtonType.selectAll,
),
];
} }
// Infer the keyboard type of an `EditableText` if it's not specified. // Infer the keyboard type of an `EditableText` if it's not specified.
...@@ -2063,6 +2075,13 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2063,6 +2075,13 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
/// Detects whether the clipboard can paste. /// Detects whether the clipboard can paste.
final ClipboardStatusNotifier clipboardStatus = ClipboardStatusNotifier(); 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; TextInputConnection? _textInputConnection;
bool get _hasInputConnection => _textInputConnection?.attached ?? false; bool get _hasInputConnection => _textInputConnection?.attached ?? false;
...@@ -2196,12 +2215,26 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -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() { void _onChangedClipboardStatus() {
setState(() { setState(() {
// Inform the widget that the value of clipboardStatus has changed. // 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 { TextEditingValue get _textEditingValueforTextLayoutMetrics {
final Widget? editableWidget =_editableKey.currentContext?.widget; final Widget? editableWidget =_editableKey.currentContext?.widget;
if (editableWidget is! _Editable) { if (editableWidget is! _Editable) {
...@@ -2347,6 +2380,18 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -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 /// Finds specified [SuggestionSpan] that matches the provided index using
/// binary search. /// binary search.
/// ///
...@@ -2561,6 +2606,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2561,6 +2606,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
onSelectAll: selectAllEnabled onSelectAll: selectAllEnabled
? () => selectAll(SelectionChangedCause.toolbar) ? () => selectAll(SelectionChangedCause.toolbar)
: null, : null,
onLiveTextInput: liveTextInputEnabled
? () => _startLiveTextInput(SelectionChangedCause.toolbar)
: null,
); );
} }
...@@ -2569,6 +2617,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2569,6 +2617,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_liveTextInputStatus?.addListener(_onChangedLiveTextInputStatus);
clipboardStatus.addListener(_onChangedClipboardStatus); clipboardStatus.addListener(_onChangedClipboardStatus);
widget.controller.addListener(_didChangeTextEditingValue); widget.controller.addListener(_didChangeTextEditingValue);
widget.focusNode.addListener(_handleFocusChanged); widget.focusNode.addListener(_handleFocusChanged);
...@@ -2734,6 +2783,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -2734,6 +2783,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_selectionOverlay = null; _selectionOverlay = null;
widget.focusNode.removeListener(_handleFocusChanged); widget.focusNode.removeListener(_handleFocusChanged);
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
_liveTextInputStatus?.removeListener(_onChangedLiveTextInputStatus);
_liveTextInputStatus?.dispose();
clipboardStatus.removeListener(_onChangedClipboardStatus); clipboardStatus.removeListener(_onChangedClipboardStatus);
clipboardStatus.dispose(); clipboardStatus.dispose();
_cursorVisibilityNotifier.dispose(); _cursorVisibilityNotifier.dispose();
...@@ -3986,6 +4037,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -3986,6 +4037,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
if (_selectionOverlay == null) { if (_selectionOverlay == null) {
return false; return false;
} }
_liveTextInputStatus?.update();
clipboardStatus.update(); clipboardStatus.update();
_selectionOverlay!.showToolbar(); _selectionOverlay!.showToolbar();
return true; return true;
......
...@@ -3383,6 +3383,115 @@ enum ClipboardStatus { ...@@ -3383,6 +3383,115 @@ enum ClipboardStatus {
notPasteable, 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 // TODO(justinmc): Deprecate this after TextSelectionControls.buildToolbar is
// deleted, when users should migrate back to TextSelectionControls.buildHandle. // deleted, when users should migrate back to TextSelectionControls.buildHandle.
// See https://github.com/flutter/flutter/pull/124262 // See https://github.com/flutter/flutter/pull/124262
......
...@@ -8,6 +8,7 @@ import 'package:flutter/services.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../widgets/clipboard_utils.dart'; import '../widgets/clipboard_utils.dart';
import '../widgets/live_text_utils.dart';
void main() { void main() {
final MockClipboard mockClipboard = MockClipboard(); final MockClipboard mockClipboard = MockClipboard();
...@@ -166,6 +167,7 @@ void main() { ...@@ -166,6 +167,7 @@ void main() {
onCut: () {}, onCut: () {},
onPaste: () {}, onPaste: () {},
onSelectAll: () {}, onSelectAll: () {},
onLiveTextInput: () {},
), ),
), ),
)); ));
...@@ -178,13 +180,16 @@ void main() { ...@@ -178,13 +180,16 @@ void main() {
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.android: case TargetPlatform.android:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.iOS: case TargetPlatform.iOS:
expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(4)); expect(find.byType(CupertinoTextSelectionToolbarButton), findsNWidgets(5));
expect(findLiveTextButton(), findsOneWidget);
case TargetPlatform.macOS: case TargetPlatform.macOS:
case TargetPlatform.linux: case TargetPlatform.linux:
case TargetPlatform.windows: 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. skip: kIsWeb, // [intended] on web the browser handles the context menu.
......
...@@ -21,6 +21,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -21,6 +21,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/clipboard_utils.dart'; import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart' show OverflowWidgetTextEditingController; import '../widgets/editable_text_utils.dart' show OverflowWidgetTextEditingController;
import '../widgets/live_text_utils.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
// On web, the context menu (aka toolbar) is provided by the browser. // On web, the context menu (aka toolbar) is provided by the browser.
...@@ -199,12 +200,56 @@ void main() { ...@@ -199,12 +200,56 @@ void main() {
Offset textOffsetToPosition(WidgetTester tester, int offset) => textOffsetToBottomLeftPosition(tester, offset) + const Offset(kIsWeb ? 1 : 0, -2); Offset textOffsetToPosition(WidgetTester tester, int offset) => textOffsetToBottomLeftPosition(tester, offset) + const Offset(kIsWeb ? 1 : 0, -2);
setUp(() async { setUp(() async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, mockClipboard.handleMethodCall);
EditableText.debugDeterministicCursor = false; EditableText.debugDeterministicCursor = false;
// Fill the clipboard so that the Paste option is available in the text // Fill the clipboard so that the Paste option is available in the text
// selection menu. // selection menu.
await Clipboard.setData(const ClipboardData(text: 'Clipboard data')); 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 { testWidgets('can use the desktop cut/copy/paste buttons on Mac', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController( final TextEditingController controller = TextEditingController(
text: 'blah1 blah2', text: 'blah1 blah2',
......
...@@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -11,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../foundation/leak_tracking.dart'; import '../foundation/leak_tracking.dart';
import '../widgets/clipboard_utils.dart'; import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart'; import '../widgets/editable_text_utils.dart';
import '../widgets/live_text_utils.dart';
void main() { void main() {
final MockClipboard mockClipboard = MockClipboard(); final MockClipboard mockClipboard = MockClipboard();
...@@ -184,6 +185,7 @@ void main() { ...@@ -184,6 +185,7 @@ void main() {
onCut: () {}, onCut: () {},
onPaste: () {}, onPaste: () {},
onSelectAll: () {}, onSelectAll: () {},
onLiveTextInput: () {},
), ),
), ),
), ),
...@@ -199,17 +201,18 @@ void main() { ...@@ -199,17 +201,18 @@ void main() {
case TargetPlatform.android: case TargetPlatform.android:
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
expect(find.text('Select all'), findsOneWidget); expect(find.text('Select all'), findsOneWidget);
expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(4)); expect(find.byType(TextSelectionToolbarTextButton), findsNWidgets(5));
case TargetPlatform.iOS: case TargetPlatform.iOS:
expect(find.text('Select All'), findsOneWidget); 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.linux:
case TargetPlatform.windows: case TargetPlatform.windows:
expect(find.text('Select all'), findsOneWidget); expect(find.text('Select all'), findsOneWidget);
expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(4)); expect(find.byType(DesktopTextSelectionToolbarButton), findsNWidgets(5));
case TargetPlatform.macOS: case TargetPlatform.macOS:
expect(find.text('Select All'), findsOneWidget); 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. skip: kIsWeb, // [intended] on web the browser handles the context menu.
......
...@@ -28,6 +28,7 @@ void main() { ...@@ -28,6 +28,7 @@ void main() {
expect(localizations.continueButtonLabel, isNotNull); expect(localizations.continueButtonLabel, isNotNull);
expect(localizations.copyButtonLabel, isNotNull); expect(localizations.copyButtonLabel, isNotNull);
expect(localizations.cutButtonLabel, isNotNull); expect(localizations.cutButtonLabel, isNotNull);
expect(localizations.scanTextButtonLabel, isNotNull);
expect(localizations.okButtonLabel, isNotNull); expect(localizations.okButtonLabel, isNotNull);
expect(localizations.pasteButtonLabel, isNotNull); expect(localizations.pasteButtonLabel, isNotNull);
expect(localizations.selectAllButtonLabel, isNotNull); expect(localizations.selectAllButtonLabel, isNotNull);
......
...@@ -26,6 +26,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -26,6 +26,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../widgets/clipboard_utils.dart'; import '../widgets/clipboard_utils.dart';
import '../widgets/editable_text_utils.dart'; import '../widgets/editable_text_utils.dart';
import '../widgets/live_text_utils.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart'; import 'feedback_tester.dart';
...@@ -203,6 +204,47 @@ void main() { ...@@ -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 { testWidgets('text field selection toolbar should hide when the user starts typing', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
const MaterialApp( const MaterialApp(
......
...@@ -15,6 +15,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -15,6 +15,7 @@ import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/clipboard_utils.dart'; import '../widgets/clipboard_utils.dart';
import 'editable_text_utils.dart'; import 'editable_text_utils.dart';
import 'live_text_utils.dart';
import 'semantics_tester.dart'; import 'semantics_tester.dart';
Matcher matchesMethodCall(String method, { dynamic args }) => _MatchesMethodCall(method, arguments: args == null ? null : wrapMatcher(args)); Matcher matchesMethodCall(String method, { dynamic args }) => _MatchesMethodCall(method, arguments: args == null ? null : wrapMatcher(args));
...@@ -118,6 +119,72 @@ void main() { ...@@ -118,6 +119,72 @@ void main() {
expect(tester.testTextInput.setClientArgs!['inputAction'], equals(serializedActionName)); 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. // Regression test for https://github.com/flutter/flutter/issues/126312.
testWidgets('when open input connection in didUpdateWidget, should not throw', (WidgetTester tester) async { testWidgets('when open input connection in didUpdateWidget, should not throw', (WidgetTester tester) async {
final Key key = GlobalKey(); final Key key = GlobalKey();
......
// 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',
);
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Gaan voort", "continueButtonLabel": "Gaan voort",
"copyButtonLabel": "Kopieer", "copyButtonLabel": "Kopieer",
"cutButtonLabel": "Knip", "cutButtonLabel": "Knip",
"scanTextButtonLabel": "Skena umbhalo",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Plak", "pasteButtonLabel": "Plak",
"selectAllButtonLabel": "Kies alles", "selectAllButtonLabel": "Kies alles",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ቀጥል", "continueButtonLabel": "ቀጥል",
"copyButtonLabel": "ቅዳ", "copyButtonLabel": "ቅዳ",
"cutButtonLabel": "ቁረጥ", "cutButtonLabel": "ቁረጥ",
"scanTextButtonLabel": "ጽሑፍ ይቃኙ",
"okButtonLabel": "እሺ", "okButtonLabel": "እሺ",
"pasteButtonLabel": "ለጥፍ", "pasteButtonLabel": "ለጥፍ",
"selectAllButtonLabel": "ሁሉንም ምረጥ", "selectAllButtonLabel": "ሁሉንም ምረጥ",
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
"continueButtonLabel": "المتابعة", "continueButtonLabel": "المتابعة",
"copyButtonLabel": "نسخ", "copyButtonLabel": "نسخ",
"cutButtonLabel": "قص", "cutButtonLabel": "قص",
"scanTextButtonLabel": "مسح النص",
"okButtonLabel": "حسنًا", "okButtonLabel": "حسنًا",
"pasteButtonLabel": "لصق", "pasteButtonLabel": "لصق",
"selectAllButtonLabel": "اختيار الكل", "selectAllButtonLabel": "اختيار الكل",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "অব্যাহত ৰাখক", "continueButtonLabel": "অব্যাহত ৰাখক",
"copyButtonLabel": "প্ৰতিলিপি কৰক", "copyButtonLabel": "প্ৰতিলিপি কৰক",
"cutButtonLabel": "কাট কৰক", "cutButtonLabel": "কাট কৰক",
"scanTextButtonLabel": "স্কেন টেক্সট",
"okButtonLabel": "ঠিক আছে", "okButtonLabel": "ঠিক আছে",
"pasteButtonLabel": "পে'ষ্ট কৰক", "pasteButtonLabel": "পে'ষ্ট কৰক",
"selectAllButtonLabel": "সকলো বাছনি কৰক", "selectAllButtonLabel": "সকলো বাছনি কৰক",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Davam edin", "continueButtonLabel": "Davam edin",
"copyButtonLabel": "Kopyalayın", "copyButtonLabel": "Kopyalayın",
"cutButtonLabel": "Kəsin", "cutButtonLabel": "Kəsin",
"scanTextButtonLabel": "Mətni skan edin",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Yerləşdirin", "pasteButtonLabel": "Yerləşdirin",
"selectAllButtonLabel": "Hamısını seçin", "selectAllButtonLabel": "Hamısını seçin",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Працягнуць", "continueButtonLabel": "Працягнуць",
"copyButtonLabel": "Капіраваць", "copyButtonLabel": "Капіраваць",
"cutButtonLabel": "Выразаць", "cutButtonLabel": "Выразаць",
"scanTextButtonLabel": "Сканаваць тэкст",
"okButtonLabel": "ОК", "okButtonLabel": "ОК",
"pasteButtonLabel": "Уставіць", "pasteButtonLabel": "Уставіць",
"selectAllButtonLabel": "Выбраць усе", "selectAllButtonLabel": "Выбраць усе",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Напред", "continueButtonLabel": "Напред",
"copyButtonLabel": "Копиране", "copyButtonLabel": "Копиране",
"cutButtonLabel": "Изрязване", "cutButtonLabel": "Изрязване",
"scanTextButtonLabel": "Сканиране на текст",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Поставяне", "pasteButtonLabel": "Поставяне",
"selectAllButtonLabel": "Избиране на всички", "selectAllButtonLabel": "Избиране на всички",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "চালিয়ে যান", "continueButtonLabel": "চালিয়ে যান",
"copyButtonLabel": "কপি করুন", "copyButtonLabel": "কপি করুন",
"cutButtonLabel": "কাট করুন", "cutButtonLabel": "কাট করুন",
"scanTextButtonLabel": "পাঠ্য স্ক্যান করুন",
"okButtonLabel": "ঠিক আছে", "okButtonLabel": "ঠিক আছে",
"pasteButtonLabel": "পেস্ট করুন", "pasteButtonLabel": "পেস্ট করুন",
"selectAllButtonLabel": "সব বেছে নিন", "selectAllButtonLabel": "সব বেছে নিন",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"continueButtonLabel": "Nastavi", "continueButtonLabel": "Nastavi",
"copyButtonLabel": "Kopiraj", "copyButtonLabel": "Kopiraj",
"cutButtonLabel": "Izreži", "cutButtonLabel": "Izreži",
"scanTextButtonLabel": "Skeniraj tekst",
"okButtonLabel": "Uredu", "okButtonLabel": "Uredu",
"pasteButtonLabel": "Zalijepi", "pasteButtonLabel": "Zalijepi",
"selectAllButtonLabel": "Odaberi sve", "selectAllButtonLabel": "Odaberi sve",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Continua", "continueButtonLabel": "Continua",
"copyButtonLabel": "Copia", "copyButtonLabel": "Copia",
"cutButtonLabel": "Retalla", "cutButtonLabel": "Retalla",
"scanTextButtonLabel": "Escaneja el text",
"okButtonLabel": "D'ACORD", "okButtonLabel": "D'ACORD",
"pasteButtonLabel": "Enganxa", "pasteButtonLabel": "Enganxa",
"selectAllButtonLabel": "Selecciona-ho tot", "selectAllButtonLabel": "Selecciona-ho tot",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Pokračovat", "continueButtonLabel": "Pokračovat",
"copyButtonLabel": "Kopírovat", "copyButtonLabel": "Kopírovat",
"cutButtonLabel": "Vyjmout", "cutButtonLabel": "Vyjmout",
"scanTextButtonLabel": "Naskenujte text",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Vložit", "pasteButtonLabel": "Vložit",
"selectAllButtonLabel": "Vybrat vše", "selectAllButtonLabel": "Vybrat vše",
......
...@@ -150,5 +150,6 @@ ...@@ -150,5 +150,6 @@
"expansionTileExpandedTapHint": "Collapse", "expansionTileExpandedTapHint": "Collapse",
"expansionTileCollapsedTapHint": "Expand for more details", "expansionTileCollapsedTapHint": "Expand for more details",
"expandedHint": "Collapsed", "expandedHint": "Collapsed",
"collapsedHint": "Expanded" "collapsedHint": "Expanded",
"scanTextButtonLabel": "Scan text"
} }
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Fortsæt", "continueButtonLabel": "Fortsæt",
"copyButtonLabel": "Kopiér", "copyButtonLabel": "Kopiér",
"cutButtonLabel": "Klip", "cutButtonLabel": "Klip",
"scanTextButtonLabel": "Scan tekst",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Indsæt", "pasteButtonLabel": "Indsæt",
"selectAllButtonLabel": "Markér alt", "selectAllButtonLabel": "Markér alt",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Weiter", "continueButtonLabel": "Weiter",
"copyButtonLabel": "Kopieren", "copyButtonLabel": "Kopieren",
"cutButtonLabel": "Ausschneiden", "cutButtonLabel": "Ausschneiden",
"scanTextButtonLabel": "Text scannen",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Einsetzen", "pasteButtonLabel": "Einsetzen",
"selectAllButtonLabel": "Alle auswählen", "selectAllButtonLabel": "Alle auswählen",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Συνέχεια", "continueButtonLabel": "Συνέχεια",
"copyButtonLabel": "Αντιγραφή", "copyButtonLabel": "Αντιγραφή",
"cutButtonLabel": "Αποκοπή", "cutButtonLabel": "Αποκοπή",
"scanTextButtonLabel": "Σάρωση κειμένου",
"okButtonLabel": "ΟΚ", "okButtonLabel": "ΟΚ",
"pasteButtonLabel": "Επικόλληση", "pasteButtonLabel": "Επικόλληση",
"selectAllButtonLabel": "Επιλογή όλων", "selectAllButtonLabel": "Επιλογή όλων",
......
...@@ -192,6 +192,11 @@ ...@@ -192,6 +192,11 @@
"description": "The label for cut buttons and menu items." "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": "OK",
"@okButtonLabel": { "@okButtonLabel": {
"description": "The label for OK buttons and menu items." "description": "The label for OK buttons and menu items."
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Continuar", "continueButtonLabel": "Continuar",
"copyButtonLabel": "Copiar", "copyButtonLabel": "Copiar",
"cutButtonLabel": "Cortar", "cutButtonLabel": "Cortar",
"scanTextButtonLabel": "Escanear texto",
"okButtonLabel": "ACEPTAR", "okButtonLabel": "ACEPTAR",
"pasteButtonLabel": "Pegar", "pasteButtonLabel": "Pegar",
"selectAllButtonLabel": "Seleccionar todo", "selectAllButtonLabel": "Seleccionar todo",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Jätka", "continueButtonLabel": "Jätka",
"copyButtonLabel": "Kopeeri", "copyButtonLabel": "Kopeeri",
"cutButtonLabel": "Lõika", "cutButtonLabel": "Lõika",
"scanTextButtonLabel": "Skanni teksti",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Kleebi", "pasteButtonLabel": "Kleebi",
"selectAllButtonLabel": "Vali kõik", "selectAllButtonLabel": "Vali kõik",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Egin aurrera", "continueButtonLabel": "Egin aurrera",
"copyButtonLabel": "Kopiatu", "copyButtonLabel": "Kopiatu",
"cutButtonLabel": "Ebaki", "cutButtonLabel": "Ebaki",
"scanTextButtonLabel": "Eskaneatu testua",
"okButtonLabel": "Ados", "okButtonLabel": "Ados",
"pasteButtonLabel": "Itsatsi", "pasteButtonLabel": "Itsatsi",
"selectAllButtonLabel": "Hautatu guztiak", "selectAllButtonLabel": "Hautatu guztiak",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ادامه", "continueButtonLabel": "ادامه",
"copyButtonLabel": "کپی", "copyButtonLabel": "کپی",
"cutButtonLabel": "برش", "cutButtonLabel": "برش",
"scanTextButtonLabel": "اسکن متن",
"okButtonLabel": "تأیید", "okButtonLabel": "تأیید",
"pasteButtonLabel": "جای‌گذاری", "pasteButtonLabel": "جای‌گذاری",
"selectAllButtonLabel": "انتخاب همه", "selectAllButtonLabel": "انتخاب همه",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Jatka", "continueButtonLabel": "Jatka",
"copyButtonLabel": "Kopioi", "copyButtonLabel": "Kopioi",
"cutButtonLabel": "Leikkaa", "cutButtonLabel": "Leikkaa",
"scanTextButtonLabel": "Skannaa tekstiä",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Liitä", "pasteButtonLabel": "Liitä",
"selectAllButtonLabel": "Valitse kaikki", "selectAllButtonLabel": "Valitse kaikki",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Magpatuloy", "continueButtonLabel": "Magpatuloy",
"copyButtonLabel": "Kopyahin", "copyButtonLabel": "Kopyahin",
"cutButtonLabel": "I-cut", "cutButtonLabel": "I-cut",
"scanTextButtonLabel": "I-scan ang text",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "I-paste", "pasteButtonLabel": "I-paste",
"selectAllButtonLabel": "Piliin lahat", "selectAllButtonLabel": "Piliin lahat",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Continuer", "continueButtonLabel": "Continuer",
"copyButtonLabel": "Copier", "copyButtonLabel": "Copier",
"cutButtonLabel": "Couper", "cutButtonLabel": "Couper",
"scanTextButtonLabel": "Numériser du texte",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Coller", "pasteButtonLabel": "Coller",
"selectAllButtonLabel": "Tout sélectionner", "selectAllButtonLabel": "Tout sélectionner",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Continuar", "continueButtonLabel": "Continuar",
"copyButtonLabel": "Copiar", "copyButtonLabel": "Copiar",
"cutButtonLabel": "Cortar", "cutButtonLabel": "Cortar",
"scanTextButtonLabel": "Escanear texto",
"okButtonLabel": "Aceptar", "okButtonLabel": "Aceptar",
"pasteButtonLabel": "Pegar", "pasteButtonLabel": "Pegar",
"selectAllButtonLabel": "Seleccionar todo", "selectAllButtonLabel": "Seleccionar todo",
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
"continueButtonLabel": "Weiter", "continueButtonLabel": "Weiter",
"copyButtonLabel": "Kopieren", "copyButtonLabel": "Kopieren",
"cutButtonLabel": "Ausschneiden", "cutButtonLabel": "Ausschneiden",
"scanTextButtonLabel": "Text scannen",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Einsetzen", "pasteButtonLabel": "Einsetzen",
"selectAllButtonLabel": "Alle auswählen", "selectAllButtonLabel": "Alle auswählen",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ચાલુ રાખો", "continueButtonLabel": "ચાલુ રાખો",
"copyButtonLabel": "કૉપિ કરો", "copyButtonLabel": "કૉપિ કરો",
"cutButtonLabel": "કાપો", "cutButtonLabel": "કાપો",
"scanTextButtonLabel": "ટેક્સ્ટ સ્કેન કરો",
"okButtonLabel": "ઓકે", "okButtonLabel": "ઓકે",
"pasteButtonLabel": "પેસ્ટ કરો", "pasteButtonLabel": "પેસ્ટ કરો",
"selectAllButtonLabel": "બધા પસંદ કરો", "selectAllButtonLabel": "બધા પસંદ કરો",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "המשך", "continueButtonLabel": "המשך",
"copyButtonLabel": "העתקה", "copyButtonLabel": "העתקה",
"cutButtonLabel": "גזירה", "cutButtonLabel": "גזירה",
"scanTextButtonLabel": "סרוק טקסט",
"okButtonLabel": "אישור", "okButtonLabel": "אישור",
"pasteButtonLabel": "הדבקה", "pasteButtonLabel": "הדבקה",
"selectAllButtonLabel": "בחירת הכול", "selectAllButtonLabel": "בחירת הכול",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "जारी रखें", "continueButtonLabel": "जारी रखें",
"copyButtonLabel": "कॉपी करें", "copyButtonLabel": "कॉपी करें",
"cutButtonLabel": "काटें", "cutButtonLabel": "काटें",
"scanTextButtonLabel": "पाठ स्कैन करें",
"okButtonLabel": "ठीक है", "okButtonLabel": "ठीक है",
"pasteButtonLabel": "चिपकाएं", "pasteButtonLabel": "चिपकाएं",
"selectAllButtonLabel": "सभी को चुनें", "selectAllButtonLabel": "सभी को चुनें",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"continueButtonLabel": "Nastavi", "continueButtonLabel": "Nastavi",
"copyButtonLabel": "Kopiraj", "copyButtonLabel": "Kopiraj",
"cutButtonLabel": "Izreži", "cutButtonLabel": "Izreži",
"scanTextButtonLabel": "Skeniraj tekst",
"okButtonLabel": "U REDU", "okButtonLabel": "U REDU",
"pasteButtonLabel": "Zalijepi", "pasteButtonLabel": "Zalijepi",
"selectAllButtonLabel": "Odaberi sve", "selectAllButtonLabel": "Odaberi sve",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Folytatás", "continueButtonLabel": "Folytatás",
"copyButtonLabel": "Másolás", "copyButtonLabel": "Másolás",
"cutButtonLabel": "Kivágás", "cutButtonLabel": "Kivágás",
"scanTextButtonLabel": "Szöveg beolvasása",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Beillesztés", "pasteButtonLabel": "Beillesztés",
"selectAllButtonLabel": "Összes kijelölése", "selectAllButtonLabel": "Összes kijelölése",
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
"continueButtonLabel": "Շարունակել", "continueButtonLabel": "Շարունակել",
"copyButtonLabel": "Պատճենել", "copyButtonLabel": "Պատճենել",
"cutButtonLabel": "Կտրել", "cutButtonLabel": "Կտրել",
"scanTextButtonLabel": "Սկանավորեք տեքստը",
"okButtonLabel": "Եղավ", "okButtonLabel": "Եղավ",
"pasteButtonLabel": "Տեղադրել", "pasteButtonLabel": "Տեղադրել",
"selectAllButtonLabel": "Նշել բոլորը", "selectAllButtonLabel": "Նշել բոլորը",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Lanjutkan", "continueButtonLabel": "Lanjutkan",
"copyButtonLabel": "Salin", "copyButtonLabel": "Salin",
"cutButtonLabel": "Potong", "cutButtonLabel": "Potong",
"scanTextButtonLabel": "Pindai teks",
"okButtonLabel": "OKE", "okButtonLabel": "OKE",
"pasteButtonLabel": "Tempel", "pasteButtonLabel": "Tempel",
"selectAllButtonLabel": "Pilih semua", "selectAllButtonLabel": "Pilih semua",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Áfram", "continueButtonLabel": "Áfram",
"copyButtonLabel": "Afrita", "copyButtonLabel": "Afrita",
"cutButtonLabel": "Klippa", "cutButtonLabel": "Klippa",
"scanTextButtonLabel": "Skannaðu texta",
"okButtonLabel": "Í lagi", "okButtonLabel": "Í lagi",
"pasteButtonLabel": "Líma", "pasteButtonLabel": "Líma",
"selectAllButtonLabel": "Velja allt", "selectAllButtonLabel": "Velja allt",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Continua", "continueButtonLabel": "Continua",
"copyButtonLabel": "Copia", "copyButtonLabel": "Copia",
"cutButtonLabel": "Taglia", "cutButtonLabel": "Taglia",
"scanTextButtonLabel": "Scansiona il testo",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Incolla", "pasteButtonLabel": "Incolla",
"selectAllButtonLabel": "Seleziona tutto", "selectAllButtonLabel": "Seleziona tutto",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "続行", "continueButtonLabel": "続行",
"copyButtonLabel": "コピー", "copyButtonLabel": "コピー",
"cutButtonLabel": "切り取り", "cutButtonLabel": "切り取り",
"scanTextButtonLabel": "テキストをスキャン",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "貼り付け", "pasteButtonLabel": "貼り付け",
"selectAllButtonLabel": "すべて選択", "selectAllButtonLabel": "すべて選択",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "გაგრძელება", "continueButtonLabel": "გაგრძელება",
"copyButtonLabel": "კოპირება", "copyButtonLabel": "კოპირება",
"cutButtonLabel": "ამოჭრა", "cutButtonLabel": "ამოჭრა",
"scanTextButtonLabel": "ტექსტის სკანირება",
"okButtonLabel": "კარგი", "okButtonLabel": "კარგი",
"pasteButtonLabel": "ჩასმა", "pasteButtonLabel": "ჩასმა",
"selectAllButtonLabel": "ყველას არჩევა", "selectAllButtonLabel": "ყველას არჩევა",
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
"continueButtonLabel": "Жалғастыру", "continueButtonLabel": "Жалғастыру",
"copyButtonLabel": "Көшіру", "copyButtonLabel": "Көшіру",
"cutButtonLabel": "Қию", "cutButtonLabel": "Қию",
"scanTextButtonLabel": "Мәтінді сканерлеу",
"okButtonLabel": "Иә", "okButtonLabel": "Иә",
"pasteButtonLabel": "Қою", "pasteButtonLabel": "Қою",
"selectAllButtonLabel": "Барлығын таңдау", "selectAllButtonLabel": "Барлығын таңдау",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "បន្ត", "continueButtonLabel": "បន្ត",
"copyButtonLabel": "ចម្លង", "copyButtonLabel": "ចម្លង",
"cutButtonLabel": "កាត់", "cutButtonLabel": "កាត់",
"scanTextButtonLabel": "ស្កេនអត្ថបទ",
"okButtonLabel": "យល់ព្រម", "okButtonLabel": "យល់ព្រម",
"pasteButtonLabel": "ដាក់​ចូល", "pasteButtonLabel": "ដាក់​ចូល",
"selectAllButtonLabel": "ជ្រើសរើស​ទាំងអស់", "selectAllButtonLabel": "ជ្រើសរើស​ទាំងអស់",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "\u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf", "continueButtonLabel": "\u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf",
"copyButtonLabel": "\u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cbf", "copyButtonLabel": "\u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cbf",
"cutButtonLabel": "\u0c95\u0ca4\u0ccd\u0ca4\u0cb0\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", "okButtonLabel": "\u0cb8\u0cb0\u0cbf",
"pasteButtonLabel": "\u0c85\u0c82\u0c9f\u0cbf\u0cb8\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", "selectAllButtonLabel": "\u0c8e\u0cb2\u0ccd\u0cb2\u0cb5\u0ca8\u0ccd\u0ca8\u0cc2\u0020\u0c86\u0caf\u0ccd\u0c95\u0cc6\u0020\u0cae\u0cbe\u0ca1\u0cbf",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "계속", "continueButtonLabel": "계속",
"copyButtonLabel": "복사", "copyButtonLabel": "복사",
"cutButtonLabel": "잘라냄", "cutButtonLabel": "잘라냄",
"scanTextButtonLabel": "스캔 텍스트",
"okButtonLabel": "확인", "okButtonLabel": "확인",
"pasteButtonLabel": "붙여넣기", "pasteButtonLabel": "붙여넣기",
"selectAllButtonLabel": "전체 선택", "selectAllButtonLabel": "전체 선택",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Улантуу", "continueButtonLabel": "Улантуу",
"copyButtonLabel": "Көчүрүү", "copyButtonLabel": "Көчүрүү",
"cutButtonLabel": "Кесүү", "cutButtonLabel": "Кесүү",
"scanTextButtonLabel": "Текстти скандоо",
"okButtonLabel": "Макул", "okButtonLabel": "Макул",
"pasteButtonLabel": "Чаптоо", "pasteButtonLabel": "Чаптоо",
"selectAllButtonLabel": "Баарын тандоо", "selectAllButtonLabel": "Баарын тандоо",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ສືບຕໍ່", "continueButtonLabel": "ສືບຕໍ່",
"copyButtonLabel": "ສຳເນົາ", "copyButtonLabel": "ສຳເນົາ",
"cutButtonLabel": "ຕັດ", "cutButtonLabel": "ຕັດ",
"scanTextButtonLabel": "ສະແກນຂໍ້ຄວາມ",
"okButtonLabel": "ຕົກລົງ", "okButtonLabel": "ຕົກລົງ",
"pasteButtonLabel": "ວາງ", "pasteButtonLabel": "ວາງ",
"selectAllButtonLabel": "ເລືອກທັງໝົດ", "selectAllButtonLabel": "ເລືອກທັງໝົດ",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Tęsti", "continueButtonLabel": "Tęsti",
"copyButtonLabel": "Kopijuoti", "copyButtonLabel": "Kopijuoti",
"cutButtonLabel": "Iškirpti", "cutButtonLabel": "Iškirpti",
"scanTextButtonLabel": "Nuskaityti tekstą",
"okButtonLabel": "GERAI", "okButtonLabel": "GERAI",
"pasteButtonLabel": "Įklijuoti", "pasteButtonLabel": "Įklijuoti",
"selectAllButtonLabel": "Pasirinkti viską", "selectAllButtonLabel": "Pasirinkti viską",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Turpināt", "continueButtonLabel": "Turpināt",
"copyButtonLabel": "Kopēt", "copyButtonLabel": "Kopēt",
"cutButtonLabel": "Izgriezt", "cutButtonLabel": "Izgriezt",
"scanTextButtonLabel": "Skenēt tekstu",
"okButtonLabel": "LABI", "okButtonLabel": "LABI",
"pasteButtonLabel": "Ielīmēt", "pasteButtonLabel": "Ielīmēt",
"selectAllButtonLabel": "Atlasīt visu", "selectAllButtonLabel": "Atlasīt visu",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Продолжи", "continueButtonLabel": "Продолжи",
"copyButtonLabel": "Копирај", "copyButtonLabel": "Копирај",
"cutButtonLabel": "Исечи", "cutButtonLabel": "Исечи",
"scanTextButtonLabel": "Скенирајте текст",
"okButtonLabel": "Во ред", "okButtonLabel": "Во ред",
"pasteButtonLabel": "Залепи", "pasteButtonLabel": "Залепи",
"selectAllButtonLabel": "Избери ги сите", "selectAllButtonLabel": "Избери ги сите",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "തുടരുക", "continueButtonLabel": "തുടരുക",
"copyButtonLabel": "പകർത്തുക", "copyButtonLabel": "പകർത്തുക",
"cutButtonLabel": "മുറിക്കുക", "cutButtonLabel": "മുറിക്കുക",
"scanTextButtonLabel": "ടെക്സ്റ്റ് സ്കാൻ ചെയ്യുക",
"okButtonLabel": "ശരി", "okButtonLabel": "ശരി",
"pasteButtonLabel": "ഒട്ടിക്കുക", "pasteButtonLabel": "ഒട്ടിക്കുക",
"selectAllButtonLabel": "എല്ലാം തിരഞ്ഞെടുക്കുക", "selectAllButtonLabel": "എല്ലാം തിരഞ്ഞെടുക്കുക",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Үргэлжлүүлэх", "continueButtonLabel": "Үргэлжлүүлэх",
"copyButtonLabel": "Хуулах", "copyButtonLabel": "Хуулах",
"cutButtonLabel": "Таслах", "cutButtonLabel": "Таслах",
"scanTextButtonLabel": "Текст сканнердах",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Буулгах", "pasteButtonLabel": "Буулгах",
"selectAllButtonLabel": "Бүгдийг сонгох", "selectAllButtonLabel": "Бүгдийг сонгох",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "पुढे सुरू ठेवा", "continueButtonLabel": "पुढे सुरू ठेवा",
"copyButtonLabel": "कॉपी करा", "copyButtonLabel": "कॉपी करा",
"cutButtonLabel": "कट करा", "cutButtonLabel": "कट करा",
"scanTextButtonLabel": "मजकूर स्कॅन करा",
"okButtonLabel": "ओके", "okButtonLabel": "ओके",
"pasteButtonLabel": "पेस्ट करा", "pasteButtonLabel": "पेस्ट करा",
"selectAllButtonLabel": "सर्व निवडा", "selectAllButtonLabel": "सर्व निवडा",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Teruskan", "continueButtonLabel": "Teruskan",
"copyButtonLabel": "Salin", "copyButtonLabel": "Salin",
"cutButtonLabel": "Potong", "cutButtonLabel": "Potong",
"scanTextButtonLabel": "Pindai teks",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Tampal", "pasteButtonLabel": "Tampal",
"selectAllButtonLabel": "Pilih semua", "selectAllButtonLabel": "Pilih semua",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ရှေ့ဆက်ရန်", "continueButtonLabel": "ရှေ့ဆက်ရန်",
"copyButtonLabel": "မိတ္တူကူးရန်", "copyButtonLabel": "မိတ္တူကူးရန်",
"cutButtonLabel": "ဖြတ်ယူရန်", "cutButtonLabel": "ဖြတ်ယူရန်",
"scanTextButtonLabel": "စာသားကို စကင်ဖတ်ပါ။",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "ကူးထည့်ရန်", "pasteButtonLabel": "ကူးထည့်ရန်",
"selectAllButtonLabel": "အားလုံး ရွေးရန်", "selectAllButtonLabel": "အားလုံး ရွေးရန်",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"continueButtonLabel": "Fortsett", "continueButtonLabel": "Fortsett",
"copyButtonLabel": "Kopiér", "copyButtonLabel": "Kopiér",
"cutButtonLabel": "Klipp ut", "cutButtonLabel": "Klipp ut",
"scanTextButtonLabel": "Scan tekst",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Lim inn", "pasteButtonLabel": "Lim inn",
"selectAllButtonLabel": "Velg alle", "selectAllButtonLabel": "Velg alle",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "जारी राख्नुहोस्", "continueButtonLabel": "जारी राख्नुहोस्",
"copyButtonLabel": "प्रतिलिपि गर्नुहोस्", "copyButtonLabel": "प्रतिलिपि गर्नुहोस्",
"cutButtonLabel": "काट्नुहोस्", "cutButtonLabel": "काट्नुहोस्",
"scanTextButtonLabel": "पाठ स्क्यान गर्नुहोस्",
"okButtonLabel": "ठिक छ", "okButtonLabel": "ठिक छ",
"pasteButtonLabel": "टाँस्नुहोस्", "pasteButtonLabel": "टाँस्नुहोस्",
"selectAllButtonLabel": "सबै बटनहरू चयन गर्नुहोस्", "selectAllButtonLabel": "सबै बटनहरू चयन गर्नुहोस्",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Doorgaan", "continueButtonLabel": "Doorgaan",
"copyButtonLabel": "Kopiëren", "copyButtonLabel": "Kopiëren",
"cutButtonLabel": "Knippen", "cutButtonLabel": "Knippen",
"scanTextButtonLabel": "Tekst scannen",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Plakken", "pasteButtonLabel": "Plakken",
"selectAllButtonLabel": "Alles selecteren", "selectAllButtonLabel": "Alles selecteren",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"continueButtonLabel": "Fortsett", "continueButtonLabel": "Fortsett",
"copyButtonLabel": "Kopiér", "copyButtonLabel": "Kopiér",
"cutButtonLabel": "Klipp ut", "cutButtonLabel": "Klipp ut",
"scanTextButtonLabel": "Skann tekst",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Lim inn", "pasteButtonLabel": "Lim inn",
"selectAllButtonLabel": "Velg alle", "selectAllButtonLabel": "Velg alle",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ଜାରି ରଖନ୍ତୁ", "continueButtonLabel": "ଜାରି ରଖନ୍ତୁ",
"copyButtonLabel": "କପି କରନ୍ତୁ", "copyButtonLabel": "କପି କରନ୍ତୁ",
"cutButtonLabel": "କଟ୍ କରନ୍ତୁ", "cutButtonLabel": "କଟ୍ କରନ୍ତୁ",
"scanTextButtonLabel": "ପାଠ୍ୟ ସ୍କାନ୍ କରନ୍ତୁ",
"okButtonLabel": "ଠିକ୍ ଅଛି", "okButtonLabel": "ଠିକ୍ ଅଛି",
"pasteButtonLabel": "ପେଷ୍ଟ କରନ୍ତୁ", "pasteButtonLabel": "ପେଷ୍ଟ କରନ୍ତୁ",
"selectAllButtonLabel": "ସବୁ ଚୟନ କରନ୍ତୁ", "selectAllButtonLabel": "ସବୁ ଚୟନ କରନ୍ତୁ",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ਜਾਰੀ ਰੱਖੋ", "continueButtonLabel": "ਜਾਰੀ ਰੱਖੋ",
"copyButtonLabel": "ਕਾਪੀ ਕਰੋ", "copyButtonLabel": "ਕਾਪੀ ਕਰੋ",
"cutButtonLabel": "ਕੱਟ ਕਰੋ", "cutButtonLabel": "ਕੱਟ ਕਰੋ",
"scanTextButtonLabel": "ਟੈਕਸਟ ਸਕੈਨ ਕਰੋ",
"okButtonLabel": "ਠੀਕ ਹੈ", "okButtonLabel": "ਠੀਕ ਹੈ",
"pasteButtonLabel": "ਪੇਸਟ ਕਰੋ", "pasteButtonLabel": "ਪੇਸਟ ਕਰੋ",
"selectAllButtonLabel": "ਸਭ ਚੁਣੋ", "selectAllButtonLabel": "ਸਭ ਚੁਣੋ",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Dalej", "continueButtonLabel": "Dalej",
"copyButtonLabel": "Kopiuj", "copyButtonLabel": "Kopiuj",
"cutButtonLabel": "Wytnij", "cutButtonLabel": "Wytnij",
"scanTextButtonLabel": "Zeskanuj tekst",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Wklej", "pasteButtonLabel": "Wklej",
"selectAllButtonLabel": "Zaznacz wszystko", "selectAllButtonLabel": "Zaznacz wszystko",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"continueButtonLabel": "منځپانګې", "continueButtonLabel": "منځپانګې",
"copyButtonLabel": "کاپی", "copyButtonLabel": "کاپی",
"cutButtonLabel": "کم کړئ", "cutButtonLabel": "کم کړئ",
"scanTextButtonLabel": "متن سکین کړئ",
"okButtonLabel": "سمه ده", "okButtonLabel": "سمه ده",
"pasteButtonLabel": "پیټ کړئ", "pasteButtonLabel": "پیټ کړئ",
"selectAllButtonLabel": "غوره کړئ", "selectAllButtonLabel": "غوره کړئ",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"continueButtonLabel": "Continuar", "continueButtonLabel": "Continuar",
"copyButtonLabel": "Copiar", "copyButtonLabel": "Copiar",
"cutButtonLabel": "Cortar", "cutButtonLabel": "Cortar",
"scanTextButtonLabel": "Digitalizar texto",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Colar", "pasteButtonLabel": "Colar",
"selectAllButtonLabel": "Selecionar tudo", "selectAllButtonLabel": "Selecionar tudo",
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
"continueButtonLabel": "Continuați", "continueButtonLabel": "Continuați",
"copyButtonLabel": "Copiați", "copyButtonLabel": "Copiați",
"cutButtonLabel": "Decupați", "cutButtonLabel": "Decupați",
"scanTextButtonLabel": "Scanați textul",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Inserați", "pasteButtonLabel": "Inserați",
"selectAllButtonLabel": "Selectați tot", "selectAllButtonLabel": "Selectați tot",
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
"continueButtonLabel": "Продолжить", "continueButtonLabel": "Продолжить",
"copyButtonLabel": "Копировать", "copyButtonLabel": "Копировать",
"cutButtonLabel": "Вырезать", "cutButtonLabel": "Вырезать",
"scanTextButtonLabel": "Сканировать текст",
"okButtonLabel": "ОК", "okButtonLabel": "ОК",
"pasteButtonLabel": "Вставить", "pasteButtonLabel": "Вставить",
"selectAllButtonLabel": "Выбрать все", "selectAllButtonLabel": "Выбрать все",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ඉදිරියට යන්න", "continueButtonLabel": "ඉදිරියට යන්න",
"copyButtonLabel": "පිටපත් කරන්න", "copyButtonLabel": "පිටපත් කරන්න",
"cutButtonLabel": "කපන්න", "cutButtonLabel": "කපන්න",
"scanTextButtonLabel": "පෙළ පරිලෝකනය කරන්න",
"okButtonLabel": "හරි", "okButtonLabel": "හරි",
"pasteButtonLabel": "අලවන්න", "pasteButtonLabel": "අලවන්න",
"selectAllButtonLabel": "සියල්ල තෝරන්න", "selectAllButtonLabel": "සියල්ල තෝරන්න",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Pokračovať", "continueButtonLabel": "Pokračovať",
"copyButtonLabel": "Kopírovať", "copyButtonLabel": "Kopírovať",
"cutButtonLabel": "Vystrihnúť", "cutButtonLabel": "Vystrihnúť",
"scanTextButtonLabel": "Naskenujte text",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Prilepiť", "pasteButtonLabel": "Prilepiť",
"selectAllButtonLabel": "Vybrať všetko", "selectAllButtonLabel": "Vybrať všetko",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Naprej", "continueButtonLabel": "Naprej",
"copyButtonLabel": "Kopiraj", "copyButtonLabel": "Kopiraj",
"cutButtonLabel": "Izreži", "cutButtonLabel": "Izreži",
"scanTextButtonLabel": "Skeniraj besedilo",
"okButtonLabel": "V REDU", "okButtonLabel": "V REDU",
"pasteButtonLabel": "Prilepi", "pasteButtonLabel": "Prilepi",
"selectAllButtonLabel": "Izberi vse", "selectAllButtonLabel": "Izberi vse",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Vazhdo", "continueButtonLabel": "Vazhdo",
"copyButtonLabel": "Kopjo", "copyButtonLabel": "Kopjo",
"cutButtonLabel": "Prit", "cutButtonLabel": "Prit",
"scanTextButtonLabel": "Skanoni tekstin",
"okButtonLabel": "Në rregull", "okButtonLabel": "Në rregull",
"pasteButtonLabel": "Ngjit", "pasteButtonLabel": "Ngjit",
"selectAllButtonLabel": "Zgjidh të gjitha", "selectAllButtonLabel": "Zgjidh të gjitha",
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
"continueButtonLabel": "Настави", "continueButtonLabel": "Настави",
"copyButtonLabel": "Копирај", "copyButtonLabel": "Копирај",
"cutButtonLabel": "Исеци", "cutButtonLabel": "Исеци",
"scanTextButtonLabel": "Скенирајте текст",
"okButtonLabel": "Потврди", "okButtonLabel": "Потврди",
"pasteButtonLabel": "Налепи", "pasteButtonLabel": "Налепи",
"selectAllButtonLabel": "Изабери све", "selectAllButtonLabel": "Изабери све",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Fortsätt", "continueButtonLabel": "Fortsätt",
"copyButtonLabel": "Kopiera", "copyButtonLabel": "Kopiera",
"cutButtonLabel": "Klipp ut", "cutButtonLabel": "Klipp ut",
"scanTextButtonLabel": "Skanna text",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Klistra in", "pasteButtonLabel": "Klistra in",
"selectAllButtonLabel": "Markera allt", "selectAllButtonLabel": "Markera allt",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"continueButtonLabel": "Endelea", "continueButtonLabel": "Endelea",
"copyButtonLabel": "Nakili", "copyButtonLabel": "Nakili",
"cutButtonLabel": "Kata", "cutButtonLabel": "Kata",
"scanTextButtonLabel": "Changanua maandishi",
"okButtonLabel": "Sawa", "okButtonLabel": "Sawa",
"pasteButtonLabel": "Bandika", "pasteButtonLabel": "Bandika",
"selectAllButtonLabel": "Chagua vyote", "selectAllButtonLabel": "Chagua vyote",
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
"reorderItemLeft": "இடப்புறம் நகர்த்தவும்", "reorderItemLeft": "இடப்புறம் நகர்த்தவும்",
"reorderItemRight": "வலப்புறம் நகர்த்தவும்", "reorderItemRight": "வலப்புறம் நகர்த்தவும்",
"cutButtonLabel": "வெட்டு", "cutButtonLabel": "வெட்டு",
"scanTextButtonLabel": "உரையை ஸ்கேன் செய்யவும்",
"pasteButtonLabel": "ஒட்டு", "pasteButtonLabel": "ஒட்டு",
"previousMonthTooltip": "முந்தைய மாதம்", "previousMonthTooltip": "முந்தைய மாதம்",
"nextMonthTooltip": "அடுத்த மாதம்", "nextMonthTooltip": "அடுத்த மாதம்",
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"closeButtonLabel": "మూసివేయండి", "closeButtonLabel": "మూసివేయండి",
"continueButtonLabel": "కొనసాగించండి", "continueButtonLabel": "కొనసాగించండి",
"copyButtonLabel": "కాపీ చేయి", "copyButtonLabel": "కాపీ చేయి",
"scanTextButtonLabel": "వచనాన్ని స్కాన్ చేయండి",
"cutButtonLabel": "కత్తిరించండి", "cutButtonLabel": "కత్తిరించండి",
"okButtonLabel": "సరే", "okButtonLabel": "సరే",
"pasteButtonLabel": "పేస్ట్ చేయండి", "pasteButtonLabel": "పేస్ట్ చేయండి",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "ต่อไป", "continueButtonLabel": "ต่อไป",
"copyButtonLabel": "คัดลอก", "copyButtonLabel": "คัดลอก",
"cutButtonLabel": "ตัด", "cutButtonLabel": "ตัด",
"scanTextButtonLabel": "สแกนข้อความ",
"okButtonLabel": "ตกลง", "okButtonLabel": "ตกลง",
"pasteButtonLabel": "วาง", "pasteButtonLabel": "วาง",
"selectAllButtonLabel": "เลือกทั้งหมด", "selectAllButtonLabel": "เลือกทั้งหมด",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Magpatuloy", "continueButtonLabel": "Magpatuloy",
"copyButtonLabel": "Kopyahin", "copyButtonLabel": "Kopyahin",
"cutButtonLabel": "I-cut", "cutButtonLabel": "I-cut",
"scanTextButtonLabel": "I-scan ang text",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "I-paste", "pasteButtonLabel": "I-paste",
"selectAllButtonLabel": "Piliin lahat", "selectAllButtonLabel": "Piliin lahat",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Devam", "continueButtonLabel": "Devam",
"copyButtonLabel": "Kopyala", "copyButtonLabel": "Kopyala",
"cutButtonLabel": "Kes", "cutButtonLabel": "Kes",
"scanTextButtonLabel": "Metni tara",
"okButtonLabel": "Tamam", "okButtonLabel": "Tamam",
"pasteButtonLabel": "Yapıştır", "pasteButtonLabel": "Yapıştır",
"selectAllButtonLabel": "Tümünü seç", "selectAllButtonLabel": "Tümünü seç",
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
"continueButtonLabel": "Продовжити", "continueButtonLabel": "Продовжити",
"copyButtonLabel": "Копіювати", "copyButtonLabel": "Копіювати",
"cutButtonLabel": "Вирізати", "cutButtonLabel": "Вирізати",
"scanTextButtonLabel": "Сканувати текст",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Вставити", "pasteButtonLabel": "Вставити",
"selectAllButtonLabel": "Вибрати всі", "selectAllButtonLabel": "Вибрати всі",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "جاری رکھیں", "continueButtonLabel": "جاری رکھیں",
"copyButtonLabel": "کاپی کریں", "copyButtonLabel": "کاپی کریں",
"cutButtonLabel": "کٹ کریں", "cutButtonLabel": "کٹ کریں",
"scanTextButtonLabel": "متن کو اسکین کریں",
"okButtonLabel": "ٹھیک ہے", "okButtonLabel": "ٹھیک ہے",
"pasteButtonLabel": "پیسٹ کریں", "pasteButtonLabel": "پیسٹ کریں",
"selectAllButtonLabel": "سبھی کو منتخب کریں", "selectAllButtonLabel": "سبھی کو منتخب کریں",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Davom etish", "continueButtonLabel": "Davom etish",
"copyButtonLabel": "Nusxa olish", "copyButtonLabel": "Nusxa olish",
"cutButtonLabel": "Kesib olish", "cutButtonLabel": "Kesib olish",
"scanTextButtonLabel": "Matnni skanerlash",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Joylash", "pasteButtonLabel": "Joylash",
"selectAllButtonLabel": "Hammasi", "selectAllButtonLabel": "Hammasi",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Tiếp tục", "continueButtonLabel": "Tiếp tục",
"copyButtonLabel": "Sao chép", "copyButtonLabel": "Sao chép",
"cutButtonLabel": "Cắt", "cutButtonLabel": "Cắt",
"scanTextButtonLabel": "Quét văn bản",
"okButtonLabel": "OK", "okButtonLabel": "OK",
"pasteButtonLabel": "Dán", "pasteButtonLabel": "Dán",
"selectAllButtonLabel": "Chọn tất cả", "selectAllButtonLabel": "Chọn tất cả",
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
"closeButtonLabel": "关闭", "closeButtonLabel": "关闭",
"copyButtonLabel": "复制", "copyButtonLabel": "复制",
"cutButtonLabel": "剪切", "cutButtonLabel": "剪切",
"scanTextButtonLabel": "扫描文本",
"okButtonLabel": "确定", "okButtonLabel": "确定",
"pasteButtonLabel": "粘贴", "pasteButtonLabel": "粘贴",
"selectAllButtonLabel": "全选", "selectAllButtonLabel": "全选",
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"continueButtonLabel": "Qhubeka", "continueButtonLabel": "Qhubeka",
"copyButtonLabel": "Kopisha", "copyButtonLabel": "Kopisha",
"cutButtonLabel": "Sika", "cutButtonLabel": "Sika",
"scanTextButtonLabel": "Skena umbhalo",
"okButtonLabel": "KULUNGILE", "okButtonLabel": "KULUNGILE",
"pasteButtonLabel": "Namathisela", "pasteButtonLabel": "Namathisela",
"selectAllButtonLabel": "Khetha konke", "selectAllButtonLabel": "Khetha konke",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment