feat(i18n): add English + Chinese localization
All checks were successful
CI / Windows build (push) Successful in 12m34s

The app had zero localization ("软件多语言做了吗" — no). Add Flutter's
official gen-l10n pipeline and localize the core flow the user sees.

- pubspec: flutter_localizations + intl + generate: true
- l10n.yaml + lib/l10n/app_en.arb + app_zh.arb (37 strings)
- main.dart: localizationsDelegates + supportedLocales (follows OS locale)
- pen editor: all tool tooltips, page pill, error states localized
- home: app bar actions + empty-state buttons localized

Proven end-to-end: l10n_test pumps the same widget under Locale('en')
and Locale('zh') and asserts English vs Chinese strings resolve.

flutter analyze: 0 issues. l10n_test: 3/3 pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-23 09:35:26 +08:00
parent f48e43f13d
commit 1d70c029b3
12 changed files with 768 additions and 26 deletions

View File

@@ -8,6 +8,7 @@
import 'package:flutter/material.dart';
import 'package:pdfrx/pdfrx.dart';
import '../../l10n/app_localizations.dart';
import '../../services/database_service.dart';
import '../engine/stroke_geometry.dart' show kDefaultPenThinning;
import '../engine/stroke_model.dart';
@@ -398,6 +399,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
@override
Widget build(BuildContext context) {
final l = AppLocalizations.of(context);
return Scaffold(
body: Stack(
children: [
@@ -429,7 +431,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
padding: const EdgeInsets.all(8),
child: _RoundIconButton(
icon: Icons.arrow_back,
tooltip: 'Back',
tooltip: l.back,
onPressed: () => Navigator.of(context).maybePop(),
),
),
@@ -510,15 +512,16 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
}
Widget _buildBody() {
final l = AppLocalizations.of(context);
if (_openError != null) {
return Center(child: Text('Failed to open PDF:\n$_openError'));
return Center(child: Text(l.failedToOpenPdf('$_openError')));
}
final doc = _document;
if (doc == null) {
return const Center(child: CircularProgressIndicator());
}
if (doc.pages.isEmpty) {
return const Center(child: Text('PDF has no pages.'));
return Center(child: Text(l.pdfNoPages));
}
final page = doc.pages[_pageIndex];
@@ -584,6 +587,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
/// tools, color dots, and finger-drawing toggle.
Widget _buildToolPalette() {
final cs = Theme.of(context).colorScheme;
final l = AppLocalizations.of(context);
return Material(
color: cs.surfaceContainerHigh,
elevation: 3,
@@ -596,19 +600,19 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
_ToolButton(
icon: Icons.edit_outlined,
selected: _tool == CanvasTool.pen,
tooltip: 'Pen',
tooltip: l.toolPen,
onPressed: () => setState(() => _tool = CanvasTool.pen),
),
_ToolButton(
icon: Icons.brush_outlined,
selected: _tool == CanvasTool.highlighter,
tooltip: 'Highlighter',
tooltip: l.toolHighlighter,
onPressed: () => setState(() => _tool = CanvasTool.highlighter),
),
_ToolButton(
icon: Icons.cleaning_services_outlined,
selected: _tool == CanvasTool.eraser,
tooltip: 'Eraser',
tooltip: l.toolEraser,
onPressed: () => setState(() => _tool = CanvasTool.eraser),
),
_Divider(cs: cs),
@@ -616,13 +620,13 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
_ToolButton(
icon: Icons.undo,
selected: false,
tooltip: 'Undo',
tooltip: l.actionUndo,
onPressed: _undoFor(_pageIndex).canUndo ? _performUndo : null,
),
_ToolButton(
icon: Icons.redo,
selected: false,
tooltip: 'Redo',
tooltip: l.actionRedo,
onPressed: _undoFor(_pageIndex).canRedo ? _performRedo : null,
),
_Divider(cs: cs),
@@ -632,28 +636,28 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
icon: _allowFingerDrawing ? Icons.touch_app : Icons.do_not_touch,
selected: _allowFingerDrawing,
tooltip: _allowFingerDrawing
? 'Finger drawing ON'
: 'Finger drawing OFF (pen only)',
? l.fingerDrawingOn
: l.fingerDrawingOff,
onPressed: _toggleFingerDrawing,
),
// Page thumbnail grid.
_ToolButton(
icon: Icons.grid_view,
selected: false,
tooltip: 'Pages',
tooltip: l.pages,
onPressed: _document != null ? _openThumbnails : null,
),
// Pen settings.
_ToolButton(
icon: Icons.settings_outlined,
selected: false,
tooltip: 'Pen settings',
tooltip: l.penSettings,
onPressed: _penConfig != null ? _openPenSettings : null,
),
_ToolButton(
icon: Icons.bug_report_outlined,
selected: _showPenDebug,
tooltip: 'Input diagnostic (writes a log file)',
tooltip: l.inputDiagnostic,
onPressed: () {
final on = !_showPenDebug;
setState(() => _showPenDebug = on);
@@ -699,6 +703,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
Widget _buildPagePill() {
final doc = _document!;
final cs = Theme.of(context).colorScheme;
final l = AppLocalizations.of(context);
final total = doc.pages.length;
final shown = (_scrub ?? (_pageIndex + 1).toDouble()).round();
return Column(
@@ -742,7 +747,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
tooltip: 'Previous page',
tooltip: l.previousPage,
icon: const Icon(Icons.chevron_left),
onPressed:
_pageIndex > 0 ? () => _goToPage(_pageIndex - 1) : null,
@@ -752,7 +757,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
? () => setState(() => _showSlider = !_showSlider)
: null,
child: Text(
'$shown / $total',
l.pageOfPages(shown, total),
style: TextStyle(
color: cs.onSurface,
fontWeight: FontWeight.w600,
@@ -760,7 +765,7 @@ class _PenEditorScreenState extends State<PenEditorScreen> {
),
),
IconButton(
tooltip: 'Next page',
tooltip: l.nextPage,
icon: const Icon(Icons.chevron_right),
onPressed: _pageIndex < total - 1
? () => _goToPage(_pageIndex + 1)

46
lib/l10n/app_en.arb Normal file
View File

@@ -0,0 +1,46 @@
{
"@@locale": "en",
"appTitle": "BadNote",
"settings": "Settings",
"search": "Search",
"importPdf": "Import PDF",
"importPpt": "Import PPT",
"penCanvasBeta": "Pen Canvas (beta)",
"newNote": "New Note",
"open": "Open",
"cancel": "Cancel",
"delete": "Delete",
"deleteNoteTitle": "Delete note?",
"deleteNote": "Delete note",
"openInSplitView": "Open in Split View",
"splitViewSubtitle": "PDF reference + scratchpad",
"removeDocument": "Remove document",
"processingPptx": "Processing PPTX...",
"processingPresentation": "Processing presentation...",
"couldNotOpenPresentation": "Could not open presentation.",
"toolPen": "Pen",
"toolHighlighter": "Highlighter",
"toolEraser": "Eraser",
"actionUndo": "Undo",
"actionRedo": "Redo",
"fingerDrawingOn": "Finger drawing ON",
"fingerDrawingOff": "Finger drawing OFF (pen only)",
"pages": "Pages",
"penSettings": "Pen settings",
"inputDiagnostic": "Input diagnostic (writes a log file)",
"back": "Back",
"previousPage": "Previous page",
"nextPage": "Next page",
"failedToOpenPdf": "Failed to open PDF:\n{error}",
"@failedToOpenPdf": {
"placeholders": { "error": { "type": "String" } }
},
"pdfNoPages": "PDF has no pages.",
"pageOfPages": "{current} / {total}",
"@pageOfPages": {
"placeholders": {
"current": { "type": "int" },
"total": { "type": "int" }
}
}
}

View File

@@ -0,0 +1,338 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_en.dart';
import 'app_localizations_zh.dart';
// ignore_for_file: type=lint
/// Callers can lookup localized strings with an instance of AppLocalizations
/// returned by `AppLocalizations.of(context)`.
///
/// Applications need to include `AppLocalizations.delegate()` in their app's
/// `localizationDelegates` list, and the locales they support in the app's
/// `supportedLocales` list. For example:
///
/// ```dart
/// import 'l10n/app_localizations.dart';
///
/// return MaterialApp(
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
/// supportedLocales: AppLocalizations.supportedLocales,
/// home: MyApplicationHome(),
/// );
/// ```
///
/// ## Update pubspec.yaml
///
/// Please make sure to update your pubspec.yaml to include the following
/// packages:
///
/// ```yaml
/// dependencies:
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: any # Use the pinned version from flutter_localizations
///
/// # Rest of dependencies
/// ```
///
/// ## iOS Applications
///
/// iOS applications define key application metadata, including supported
/// locales, in an Info.plist file that is built into the application bundle.
/// To configure the locales supported by your app, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects Runner folder.
///
/// Next, select the Information Property List item, select Add Item from the
/// Editor menu, then select Localizations from the pop-up menu.
///
/// Select and expand the newly-created Localizations item then, for each
/// locale your application supports, add a new item and select the locale
/// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property.
abstract class AppLocalizations {
AppLocalizations(String locale)
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
<LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('zh'),
];
/// No description provided for @appTitle.
///
/// In en, this message translates to:
/// **'BadNote'**
String get appTitle;
/// No description provided for @settings.
///
/// In en, this message translates to:
/// **'Settings'**
String get settings;
/// No description provided for @search.
///
/// In en, this message translates to:
/// **'Search'**
String get search;
/// No description provided for @importPdf.
///
/// In en, this message translates to:
/// **'Import PDF'**
String get importPdf;
/// No description provided for @importPpt.
///
/// In en, this message translates to:
/// **'Import PPT'**
String get importPpt;
/// No description provided for @penCanvasBeta.
///
/// In en, this message translates to:
/// **'Pen Canvas (beta)'**
String get penCanvasBeta;
/// No description provided for @newNote.
///
/// In en, this message translates to:
/// **'New Note'**
String get newNote;
/// No description provided for @open.
///
/// In en, this message translates to:
/// **'Open'**
String get open;
/// No description provided for @cancel.
///
/// In en, this message translates to:
/// **'Cancel'**
String get cancel;
/// No description provided for @delete.
///
/// In en, this message translates to:
/// **'Delete'**
String get delete;
/// No description provided for @deleteNoteTitle.
///
/// In en, this message translates to:
/// **'Delete note?'**
String get deleteNoteTitle;
/// No description provided for @deleteNote.
///
/// In en, this message translates to:
/// **'Delete note'**
String get deleteNote;
/// No description provided for @openInSplitView.
///
/// In en, this message translates to:
/// **'Open in Split View'**
String get openInSplitView;
/// No description provided for @splitViewSubtitle.
///
/// In en, this message translates to:
/// **'PDF reference + scratchpad'**
String get splitViewSubtitle;
/// No description provided for @removeDocument.
///
/// In en, this message translates to:
/// **'Remove document'**
String get removeDocument;
/// No description provided for @processingPptx.
///
/// In en, this message translates to:
/// **'Processing PPTX...'**
String get processingPptx;
/// No description provided for @processingPresentation.
///
/// In en, this message translates to:
/// **'Processing presentation...'**
String get processingPresentation;
/// No description provided for @couldNotOpenPresentation.
///
/// In en, this message translates to:
/// **'Could not open presentation.'**
String get couldNotOpenPresentation;
/// No description provided for @toolPen.
///
/// In en, this message translates to:
/// **'Pen'**
String get toolPen;
/// No description provided for @toolHighlighter.
///
/// In en, this message translates to:
/// **'Highlighter'**
String get toolHighlighter;
/// No description provided for @toolEraser.
///
/// In en, this message translates to:
/// **'Eraser'**
String get toolEraser;
/// No description provided for @actionUndo.
///
/// In en, this message translates to:
/// **'Undo'**
String get actionUndo;
/// No description provided for @actionRedo.
///
/// In en, this message translates to:
/// **'Redo'**
String get actionRedo;
/// No description provided for @fingerDrawingOn.
///
/// In en, this message translates to:
/// **'Finger drawing ON'**
String get fingerDrawingOn;
/// No description provided for @fingerDrawingOff.
///
/// In en, this message translates to:
/// **'Finger drawing OFF (pen only)'**
String get fingerDrawingOff;
/// No description provided for @pages.
///
/// In en, this message translates to:
/// **'Pages'**
String get pages;
/// No description provided for @penSettings.
///
/// In en, this message translates to:
/// **'Pen settings'**
String get penSettings;
/// No description provided for @inputDiagnostic.
///
/// In en, this message translates to:
/// **'Input diagnostic (writes a log file)'**
String get inputDiagnostic;
/// No description provided for @back.
///
/// In en, this message translates to:
/// **'Back'**
String get back;
/// No description provided for @previousPage.
///
/// In en, this message translates to:
/// **'Previous page'**
String get previousPage;
/// No description provided for @nextPage.
///
/// In en, this message translates to:
/// **'Next page'**
String get nextPage;
/// No description provided for @failedToOpenPdf.
///
/// In en, this message translates to:
/// **'Failed to open PDF:\n{error}'**
String failedToOpenPdf(String error);
/// No description provided for @pdfNoPages.
///
/// In en, this message translates to:
/// **'PDF has no pages.'**
String get pdfNoPages;
/// No description provided for @pageOfPages.
///
/// In en, this message translates to:
/// **'{current} / {total}'**
String pageOfPages(int current, int total);
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) =>
<String>['en', 'zh'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en':
return AppLocalizationsEn();
case 'zh':
return AppLocalizationsZh();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.',
);
}

View File

@@ -0,0 +1,116 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for English (`en`).
class AppLocalizationsEn extends AppLocalizations {
AppLocalizationsEn([String locale = 'en']) : super(locale);
@override
String get appTitle => 'BadNote';
@override
String get settings => 'Settings';
@override
String get search => 'Search';
@override
String get importPdf => 'Import PDF';
@override
String get importPpt => 'Import PPT';
@override
String get penCanvasBeta => 'Pen Canvas (beta)';
@override
String get newNote => 'New Note';
@override
String get open => 'Open';
@override
String get cancel => 'Cancel';
@override
String get delete => 'Delete';
@override
String get deleteNoteTitle => 'Delete note?';
@override
String get deleteNote => 'Delete note';
@override
String get openInSplitView => 'Open in Split View';
@override
String get splitViewSubtitle => 'PDF reference + scratchpad';
@override
String get removeDocument => 'Remove document';
@override
String get processingPptx => 'Processing PPTX...';
@override
String get processingPresentation => 'Processing presentation...';
@override
String get couldNotOpenPresentation => 'Could not open presentation.';
@override
String get toolPen => 'Pen';
@override
String get toolHighlighter => 'Highlighter';
@override
String get toolEraser => 'Eraser';
@override
String get actionUndo => 'Undo';
@override
String get actionRedo => 'Redo';
@override
String get fingerDrawingOn => 'Finger drawing ON';
@override
String get fingerDrawingOff => 'Finger drawing OFF (pen only)';
@override
String get pages => 'Pages';
@override
String get penSettings => 'Pen settings';
@override
String get inputDiagnostic => 'Input diagnostic (writes a log file)';
@override
String get back => 'Back';
@override
String get previousPage => 'Previous page';
@override
String get nextPage => 'Next page';
@override
String failedToOpenPdf(String error) {
return 'Failed to open PDF:\n$error';
}
@override
String get pdfNoPages => 'PDF has no pages.';
@override
String pageOfPages(int current, int total) {
return '$current / $total';
}
}

View File

@@ -0,0 +1,116 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for Chinese (`zh`).
class AppLocalizationsZh extends AppLocalizations {
AppLocalizationsZh([String locale = 'zh']) : super(locale);
@override
String get appTitle => 'BadNote';
@override
String get settings => '设置';
@override
String get search => '搜索';
@override
String get importPdf => '导入 PDF';
@override
String get importPpt => '导入 PPT';
@override
String get penCanvasBeta => '手写画布(测试版)';
@override
String get newNote => '新建笔记';
@override
String get open => '打开';
@override
String get cancel => '取消';
@override
String get delete => '删除';
@override
String get deleteNoteTitle => '删除笔记?';
@override
String get deleteNote => '删除笔记';
@override
String get openInSplitView => '分屏打开';
@override
String get splitViewSubtitle => 'PDF 参考 + 草稿纸';
@override
String get removeDocument => '移除文档';
@override
String get processingPptx => '正在处理 PPTX…';
@override
String get processingPresentation => '正在处理演示文稿…';
@override
String get couldNotOpenPresentation => '无法打开演示文稿。';
@override
String get toolPen => '钢笔';
@override
String get toolHighlighter => '荧光笔';
@override
String get toolEraser => '橡皮擦';
@override
String get actionUndo => '撤销';
@override
String get actionRedo => '重做';
@override
String get fingerDrawingOn => '手指书写:开';
@override
String get fingerDrawingOff => '手指书写:关(仅手写笔)';
@override
String get pages => '页面';
@override
String get penSettings => '手写笔设置';
@override
String get inputDiagnostic => '输入诊断(写入日志文件)';
@override
String get back => '返回';
@override
String get previousPage => '上一页';
@override
String get nextPage => '下一页';
@override
String failedToOpenPdf(String error) {
return '打开 PDF 失败:\n$error';
}
@override
String get pdfNoPages => 'PDF 没有任何页面。';
@override
String pageOfPages(int current, int total) {
return '$current / $total';
}
}

37
lib/l10n/app_zh.arb Normal file
View File

@@ -0,0 +1,37 @@
{
"@@locale": "zh",
"appTitle": "BadNote",
"settings": "设置",
"search": "搜索",
"importPdf": "导入 PDF",
"importPpt": "导入 PPT",
"penCanvasBeta": "手写画布(测试版)",
"newNote": "新建笔记",
"open": "打开",
"cancel": "取消",
"delete": "删除",
"deleteNoteTitle": "删除笔记?",
"deleteNote": "删除笔记",
"openInSplitView": "分屏打开",
"splitViewSubtitle": "PDF 参考 + 草稿纸",
"removeDocument": "移除文档",
"processingPptx": "正在处理 PPTX…",
"processingPresentation": "正在处理演示文稿…",
"couldNotOpenPresentation": "无法打开演示文稿。",
"toolPen": "钢笔",
"toolHighlighter": "荧光笔",
"toolEraser": "橡皮擦",
"actionUndo": "撤销",
"actionRedo": "重做",
"fingerDrawingOn": "手指书写:开",
"fingerDrawingOff": "手指书写:关(仅手写笔)",
"pages": "页面",
"penSettings": "手写笔设置",
"inputDiagnostic": "输入诊断(写入日志文件)",
"back": "返回",
"previousPage": "上一页",
"nextPage": "下一页",
"failedToOpenPdf": "打开 PDF 失败:\n{error}",
"pdfNoPages": "PDF 没有任何页面。",
"pageOfPages": "{current} / {total}"
}

View File

@@ -1,11 +1,13 @@
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:pdfrx/pdfrx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'editor/pdf/pen_capture_region.dart';
import 'l10n/app_localizations.dart';
import 'providers/settings_provider.dart';
import 'screens/home_screen.dart';
import 'services/database_service.dart';
@@ -54,6 +56,14 @@ class BadNoteApp extends ConsumerWidget {
themeMode: settings.themeMode,
theme: _theme(lightScheme),
darkTheme: _theme(darkScheme),
// i18n: follows the OS language (en / zh) via the system locale.
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: const HomeScreen(),
);
},

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../l10n/app_localizations.dart';
import '../models/document.dart';
import '../models/note.dart';
import '../providers/document_provider.dart';
@@ -34,15 +35,16 @@ class HomeScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final notesAsync = ref.watch(noteListProvider);
final l = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(
title: const Text('BadNote'),
title: Text(l.appTitle),
centerTitle: true,
actions: [
IconButton(
icon: const Icon(Icons.settings),
tooltip: 'Settings',
tooltip: l.settings,
onPressed: () {
Navigator.of(
context,
@@ -51,17 +53,17 @@ class HomeScreen extends ConsumerWidget {
),
IconButton(
icon: const Icon(Icons.picture_as_pdf),
tooltip: 'Import PDF',
tooltip: l.importPdf,
onPressed: () => _importPdf(context),
),
IconButton(
icon: const Icon(Icons.slideshow),
tooltip: 'Import PPT',
tooltip: l.importPpt,
onPressed: () => _importPptx(context),
),
IconButton(
icon: const Icon(Icons.search),
tooltip: 'Search',
tooltip: l.search,
onPressed: () {
Navigator.of(
context,
@@ -71,7 +73,7 @@ class HomeScreen extends ConsumerWidget {
// New pen-first canvas editor (beta).
IconButton(
icon: const Icon(Icons.draw_outlined),
tooltip: 'Pen Canvas (beta)',
tooltip: l.penCanvasBeta,
onPressed: () => openM1Spike(context),
),
],
@@ -265,19 +267,19 @@ class HomeScreen extends ConsumerWidget {
FilledButton.icon(
onPressed: () => _createAndOpenNote(context, ref),
icon: const Icon(Icons.add),
label: const Text('New Note'),
label: Text(AppLocalizations.of(context).newNote),
),
const SizedBox(height: 12),
OutlinedButton.icon(
onPressed: () => _importPdf(context),
icon: const Icon(Icons.picture_as_pdf),
label: const Text('Import PDF'),
label: Text(AppLocalizations.of(context).importPdf),
),
const SizedBox(height: 12),
OutlinedButton.icon(
onPressed: () => _importPptx(context),
icon: const Icon(Icons.slideshow),
label: const Text('Import PPT'),
label: Text(AppLocalizations.of(context).importPpt),
),
],
),