feat: i18n text support
This commit is contained in:
parent
52a278e969
commit
51af255ea7
|
@ -0,0 +1,6 @@
|
||||||
|
arb-dir: lib/l10n
|
||||||
|
template-arb-file: app_en.arb
|
||||||
|
output-class: AppLocalizations
|
||||||
|
output-localization-file: app_localizations.dart
|
||||||
|
nullable-getter: false
|
||||||
|
untranslated-messages-file: build/l10n_missing.txt
|
29
lib/app.dart
29
lib/app.dart
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
import 'package:pdf_signature/ui/features/pdf/widgets/pdf_screen.dart';
|
||||||
import 'ui/features/preferences/providers.dart';
|
import 'ui/features/preferences/providers.dart';
|
||||||
|
|
||||||
|
@ -18,13 +18,28 @@ class MyApp extends StatelessWidget {
|
||||||
loading: () => const SizedBox.shrink(),
|
loading: () => const SizedBox.shrink(),
|
||||||
error:
|
error:
|
||||||
(e, st) => MaterialApp(
|
(e, st) => MaterialApp(
|
||||||
home: Scaffold(body: Center(child: Text('Error: $e'))),
|
onGenerateTitle: (ctx) => AppLocalizations.of(ctx).appTitle,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
localizationsDelegates:
|
||||||
|
AppLocalizations.localizationsDelegates,
|
||||||
|
home: Builder(
|
||||||
|
builder:
|
||||||
|
(ctx) => Scaffold(
|
||||||
|
body: Center(
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(
|
||||||
|
ctx,
|
||||||
|
).errorWithMessage(e.toString()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
data: (_) {
|
data: (_) {
|
||||||
final themeMode = ref.watch(themeModeProvider);
|
final themeMode = ref.watch(themeModeProvider);
|
||||||
final appLocale = ref.watch(localeProvider);
|
final appLocale = ref.watch(localeProvider);
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'PDF Signature',
|
onGenerateTitle: (ctx) => AppLocalizations.of(ctx).appTitle,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(
|
colorScheme: ColorScheme.fromSeed(
|
||||||
seedColor: Colors.indigo,
|
seedColor: Colors.indigo,
|
||||||
|
@ -39,12 +54,8 @@ class MyApp extends StatelessWidget {
|
||||||
),
|
),
|
||||||
themeMode: themeMode,
|
themeMode: themeMode,
|
||||||
locale: appLocale,
|
locale: appLocale,
|
||||||
supportedLocales: supportedLocales,
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
GlobalMaterialLocalizations.delegate,
|
|
||||||
GlobalWidgetsLocalizations.delegate,
|
|
||||||
GlobalCupertinoLocalizations.delegate,
|
|
||||||
],
|
|
||||||
home: const PdfSignatureHomePage(),
|
home: const PdfSignatureHomePage(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"@@locale": "en",
|
||||||
|
"appTitle": "PDF Signature",
|
||||||
|
"errorWithMessage": "Error: {message}",
|
||||||
|
"@errorWithMessage": {
|
||||||
|
"description": "Generic error text with message",
|
||||||
|
"placeholders": {"message": {"type": "String"}}
|
||||||
|
},
|
||||||
|
|
||||||
|
"settings": "Settings",
|
||||||
|
"theme": "Theme",
|
||||||
|
"themeLight": "Light",
|
||||||
|
"themeDark": "Dark",
|
||||||
|
"themeSystem": "System",
|
||||||
|
"language": "Language",
|
||||||
|
"languageEnglish": "English",
|
||||||
|
"languageChineseTraditional": "Traditional Chinese",
|
||||||
|
"languageSpanish": "Spanish",
|
||||||
|
"resetToDefaults": "Reset to defaults",
|
||||||
|
|
||||||
|
"openPdf": "Open PDF...",
|
||||||
|
"prev": "Prev",
|
||||||
|
"next": "Next",
|
||||||
|
"pageInfo": "Page {current}/{total}",
|
||||||
|
"@pageInfo": {
|
||||||
|
"description": "Label showing current page and total",
|
||||||
|
"placeholders": {
|
||||||
|
"current": {"type": "int"},
|
||||||
|
"total": {"type": "int"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"goTo": "Go to:",
|
||||||
|
"dpi": "DPI:",
|
||||||
|
"markForSigning": "Mark for Signing",
|
||||||
|
"unmarkSigning": "Unmark Signing",
|
||||||
|
"saveSignedPdf": "Save Signed PDF",
|
||||||
|
"loadSignatureFromFile": "Load Signature from file",
|
||||||
|
"drawSignature": "Draw Signature",
|
||||||
|
"noPdfLoaded": "No PDF loaded",
|
||||||
|
"signature": "Signature",
|
||||||
|
"lockAspectRatio": "Lock aspect ratio",
|
||||||
|
"backgroundRemoval": "Background removal",
|
||||||
|
"contrast": "Contrast",
|
||||||
|
"brightness": "Brightness",
|
||||||
|
"exportingPleaseWait": "Exporting... Please wait",
|
||||||
|
|
||||||
|
"nothingToSaveYet": "Nothing to save yet",
|
||||||
|
"savedWithPath": "Saved: {path}",
|
||||||
|
"@savedWithPath": {
|
||||||
|
"description": "Snackbar text showing where file saved",
|
||||||
|
"placeholders": {"path": {"type": "String"}}
|
||||||
|
},
|
||||||
|
"failedToSavePdf": "Failed to save PDF",
|
||||||
|
"downloadStarted": "Download started",
|
||||||
|
"failedToGeneratePdf": "Failed to generate PDF",
|
||||||
|
"invalidOrUnsupportedFile": "Invalid or unsupported file",
|
||||||
|
|
||||||
|
"confirm": "Confirm",
|
||||||
|
"undo": "Undo",
|
||||||
|
"clear": "Clear"
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"@@locale": "es",
|
||||||
|
"appTitle": "Firma PDF",
|
||||||
|
"errorWithMessage": "Error: {message}",
|
||||||
|
|
||||||
|
"settings": "Ajustes",
|
||||||
|
"theme": "Tema",
|
||||||
|
"themeLight": "Claro",
|
||||||
|
"themeDark": "Oscuro",
|
||||||
|
"themeSystem": "Del sistema",
|
||||||
|
"language": "Idioma",
|
||||||
|
"languageEnglish": "Inglés",
|
||||||
|
"languageChineseTraditional": "Chino tradicional",
|
||||||
|
"languageSpanish": "Español",
|
||||||
|
"resetToDefaults": "Restablecer valores",
|
||||||
|
|
||||||
|
"openPdf": "Abrir PDF…",
|
||||||
|
"prev": "Anterior",
|
||||||
|
"next": "Siguiente",
|
||||||
|
"pageInfo": "Página {current}/{total}",
|
||||||
|
"goTo": "Ir a:",
|
||||||
|
"dpi": "DPI:",
|
||||||
|
"markForSigning": "Marcar para firmar",
|
||||||
|
"unmarkSigning": "Quitar marca",
|
||||||
|
"saveSignedPdf": "Guardar PDF firmado",
|
||||||
|
"loadSignatureFromFile": "Cargar firma desde archivo",
|
||||||
|
"drawSignature": "Dibujar firma",
|
||||||
|
"noPdfLoaded": "No hay PDF cargado",
|
||||||
|
"signature": "Firma",
|
||||||
|
"lockAspectRatio": "Bloquear relación de aspecto",
|
||||||
|
"backgroundRemoval": "Eliminación de fondo",
|
||||||
|
"contrast": "Contraste",
|
||||||
|
"brightness": "Brillo",
|
||||||
|
"exportingPleaseWait": "Exportando... Por favor espera",
|
||||||
|
|
||||||
|
"nothingToSaveYet": "Nada que guardar todavía",
|
||||||
|
"savedWithPath": "Guardado: {path}",
|
||||||
|
"failedToSavePdf": "Error al guardar el PDF",
|
||||||
|
"downloadStarted": "Descarga iniciada",
|
||||||
|
"failedToGeneratePdf": "Error al generar el PDF",
|
||||||
|
"invalidOrUnsupportedFile": "Archivo no válido o no compatible",
|
||||||
|
|
||||||
|
"confirm": "Confirmar",
|
||||||
|
"undo": "Deshacer",
|
||||||
|
"clear": "Limpiar"
|
||||||
|
}
|
|
@ -0,0 +1,385 @@
|
||||||
|
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_es.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, you’ll need to edit this
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||||
|
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||||
|
/// project’s 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('es'),
|
||||||
|
Locale('zh'),
|
||||||
|
Locale('zh', 'TW'),
|
||||||
|
];
|
||||||
|
|
||||||
|
/// No description provided for @appTitle.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'PDF Signature'**
|
||||||
|
String get appTitle;
|
||||||
|
|
||||||
|
/// Generic error text with message
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Error: {message}'**
|
||||||
|
String errorWithMessage(String message);
|
||||||
|
|
||||||
|
/// No description provided for @settings.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Settings'**
|
||||||
|
String get settings;
|
||||||
|
|
||||||
|
/// No description provided for @theme.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Theme'**
|
||||||
|
String get theme;
|
||||||
|
|
||||||
|
/// No description provided for @themeLight.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Light'**
|
||||||
|
String get themeLight;
|
||||||
|
|
||||||
|
/// No description provided for @themeDark.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Dark'**
|
||||||
|
String get themeDark;
|
||||||
|
|
||||||
|
/// No description provided for @themeSystem.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'System'**
|
||||||
|
String get themeSystem;
|
||||||
|
|
||||||
|
/// No description provided for @language.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Language'**
|
||||||
|
String get language;
|
||||||
|
|
||||||
|
/// No description provided for @languageEnglish.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'English'**
|
||||||
|
String get languageEnglish;
|
||||||
|
|
||||||
|
/// No description provided for @languageChineseTraditional.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Traditional Chinese'**
|
||||||
|
String get languageChineseTraditional;
|
||||||
|
|
||||||
|
/// No description provided for @languageSpanish.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Spanish'**
|
||||||
|
String get languageSpanish;
|
||||||
|
|
||||||
|
/// No description provided for @resetToDefaults.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Reset to defaults'**
|
||||||
|
String get resetToDefaults;
|
||||||
|
|
||||||
|
/// No description provided for @openPdf.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Open PDF...'**
|
||||||
|
String get openPdf;
|
||||||
|
|
||||||
|
/// No description provided for @prev.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Prev'**
|
||||||
|
String get prev;
|
||||||
|
|
||||||
|
/// No description provided for @next.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Next'**
|
||||||
|
String get next;
|
||||||
|
|
||||||
|
/// Label showing current page and total
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Page {current}/{total}'**
|
||||||
|
String pageInfo(int current, int total);
|
||||||
|
|
||||||
|
/// No description provided for @goTo.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Go to:'**
|
||||||
|
String get goTo;
|
||||||
|
|
||||||
|
/// No description provided for @dpi.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'DPI:'**
|
||||||
|
String get dpi;
|
||||||
|
|
||||||
|
/// No description provided for @markForSigning.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Mark for Signing'**
|
||||||
|
String get markForSigning;
|
||||||
|
|
||||||
|
/// No description provided for @unmarkSigning.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Unmark Signing'**
|
||||||
|
String get unmarkSigning;
|
||||||
|
|
||||||
|
/// No description provided for @saveSignedPdf.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Save Signed PDF'**
|
||||||
|
String get saveSignedPdf;
|
||||||
|
|
||||||
|
/// No description provided for @loadSignatureFromFile.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Load Signature from file'**
|
||||||
|
String get loadSignatureFromFile;
|
||||||
|
|
||||||
|
/// No description provided for @drawSignature.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Draw Signature'**
|
||||||
|
String get drawSignature;
|
||||||
|
|
||||||
|
/// No description provided for @noPdfLoaded.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No PDF loaded'**
|
||||||
|
String get noPdfLoaded;
|
||||||
|
|
||||||
|
/// No description provided for @signature.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Signature'**
|
||||||
|
String get signature;
|
||||||
|
|
||||||
|
/// No description provided for @lockAspectRatio.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Lock aspect ratio'**
|
||||||
|
String get lockAspectRatio;
|
||||||
|
|
||||||
|
/// No description provided for @backgroundRemoval.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Background removal'**
|
||||||
|
String get backgroundRemoval;
|
||||||
|
|
||||||
|
/// No description provided for @contrast.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Contrast'**
|
||||||
|
String get contrast;
|
||||||
|
|
||||||
|
/// No description provided for @brightness.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Brightness'**
|
||||||
|
String get brightness;
|
||||||
|
|
||||||
|
/// No description provided for @exportingPleaseWait.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Exporting... Please wait'**
|
||||||
|
String get exportingPleaseWait;
|
||||||
|
|
||||||
|
/// No description provided for @nothingToSaveYet.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Nothing to save yet'**
|
||||||
|
String get nothingToSaveYet;
|
||||||
|
|
||||||
|
/// Snackbar text showing where file saved
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Saved: {path}'**
|
||||||
|
String savedWithPath(String path);
|
||||||
|
|
||||||
|
/// No description provided for @failedToSavePdf.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Failed to save PDF'**
|
||||||
|
String get failedToSavePdf;
|
||||||
|
|
||||||
|
/// No description provided for @downloadStarted.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Download started'**
|
||||||
|
String get downloadStarted;
|
||||||
|
|
||||||
|
/// No description provided for @failedToGeneratePdf.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Failed to generate PDF'**
|
||||||
|
String get failedToGeneratePdf;
|
||||||
|
|
||||||
|
/// No description provided for @invalidOrUnsupportedFile.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Invalid or unsupported file'**
|
||||||
|
String get invalidOrUnsupportedFile;
|
||||||
|
|
||||||
|
/// No description provided for @confirm.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Confirm'**
|
||||||
|
String get confirm;
|
||||||
|
|
||||||
|
/// No description provided for @undo.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Undo'**
|
||||||
|
String get undo;
|
||||||
|
|
||||||
|
/// No description provided for @clear.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Clear'**
|
||||||
|
String get clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
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', 'es', 'zh'].contains(locale.languageCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||||
|
// Lookup logic when language+country codes are specified.
|
||||||
|
switch (locale.languageCode) {
|
||||||
|
case 'zh':
|
||||||
|
{
|
||||||
|
switch (locale.countryCode) {
|
||||||
|
case 'TW':
|
||||||
|
return AppLocalizationsZhTw();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup logic when only language code is specified.
|
||||||
|
switch (locale.languageCode) {
|
||||||
|
case 'en':
|
||||||
|
return AppLocalizationsEn();
|
||||||
|
case 'es':
|
||||||
|
return AppLocalizationsEs();
|
||||||
|
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.',
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
// 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 => 'PDF Signature';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String errorWithMessage(String message) {
|
||||||
|
return 'Error: $message';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settings => 'Settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get theme => 'Theme';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => 'Light';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => 'Dark';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystem => 'System';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get language => 'Language';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageEnglish => 'English';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageChineseTraditional => 'Traditional Chinese';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageSpanish => 'Spanish';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get resetToDefaults => 'Reset to defaults';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get openPdf => 'Open PDF...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get prev => 'Prev';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get next => 'Next';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pageInfo(int current, int total) {
|
||||||
|
return 'Page $current/$total';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get goTo => 'Go to:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get dpi => 'DPI:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get markForSigning => 'Mark for Signing';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unmarkSigning => 'Unmark Signing';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saveSignedPdf => 'Save Signed PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadSignatureFromFile => 'Load Signature from file';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawSignature => 'Draw Signature';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noPdfLoaded => 'No PDF loaded';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signature => 'Signature';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get lockAspectRatio => 'Lock aspect ratio';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backgroundRemoval => 'Background removal';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contrast => 'Contrast';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get brightness => 'Brightness';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get exportingPleaseWait => 'Exporting... Please wait';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get nothingToSaveYet => 'Nothing to save yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String savedWithPath(String path) {
|
||||||
|
return 'Saved: $path';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToSavePdf => 'Failed to save PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get downloadStarted => 'Download started';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToGeneratePdf => 'Failed to generate PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get invalidOrUnsupportedFile => 'Invalid or unsupported file';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get confirm => 'Confirm';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get undo => 'Undo';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get clear => 'Clear';
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
// ignore: unused_import
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
import 'app_localizations.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
|
||||||
|
/// The translations for Spanish Castilian (`es`).
|
||||||
|
class AppLocalizationsEs extends AppLocalizations {
|
||||||
|
AppLocalizationsEs([String locale = 'es']) : super(locale);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appTitle => 'Firma PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String errorWithMessage(String message) {
|
||||||
|
return 'Error: $message';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settings => 'Ajustes';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get theme => 'Tema';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => 'Claro';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => 'Oscuro';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystem => 'Del sistema';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get language => 'Idioma';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageEnglish => 'Inglés';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageChineseTraditional => 'Chino tradicional';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageSpanish => 'Español';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get resetToDefaults => 'Restablecer valores';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get openPdf => 'Abrir PDF…';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get prev => 'Anterior';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get next => 'Siguiente';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pageInfo(int current, int total) {
|
||||||
|
return 'Página $current/$total';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get goTo => 'Ir a:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get dpi => 'DPI:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get markForSigning => 'Marcar para firmar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unmarkSigning => 'Quitar marca';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saveSignedPdf => 'Guardar PDF firmado';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadSignatureFromFile => 'Cargar firma desde archivo';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawSignature => 'Dibujar firma';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noPdfLoaded => 'No hay PDF cargado';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signature => 'Firma';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get lockAspectRatio => 'Bloquear relación de aspecto';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backgroundRemoval => 'Eliminación de fondo';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contrast => 'Contraste';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get brightness => 'Brillo';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get exportingPleaseWait => 'Exportando... Por favor espera';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get nothingToSaveYet => 'Nada que guardar todavía';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String savedWithPath(String path) {
|
||||||
|
return 'Guardado: $path';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToSavePdf => 'Error al guardar el PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get downloadStarted => 'Descarga iniciada';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToGeneratePdf => 'Error al generar el PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get invalidOrUnsupportedFile => 'Archivo no válido o no compatible';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get confirm => 'Confirmar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get undo => 'Deshacer';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get clear => 'Limpiar';
|
||||||
|
}
|
|
@ -0,0 +1,261 @@
|
||||||
|
// 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 => 'PDF 簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String errorWithMessage(String message) {
|
||||||
|
return '錯誤:$message';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settings => '設定';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get theme => '主題';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => '淺色';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => '深色';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystem => '系統';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get language => '語言';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageEnglish => '英文';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageChineseTraditional => '繁體中文';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageSpanish => '西班牙文';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get resetToDefaults => '重設為預設值';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get openPdf => '開啟 PDF…';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get prev => '上一頁';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get next => '下一頁';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pageInfo(int current, int total) {
|
||||||
|
return '第 $current/$total 頁';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get goTo => '前往:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get dpi => 'DPI:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get markForSigning => '標記簽署';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unmarkSigning => '取消標記';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saveSignedPdf => '儲存已簽名 PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadSignatureFromFile => '從檔案載入簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawSignature => '手寫簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noPdfLoaded => '尚未載入 PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signature => '簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get lockAspectRatio => '鎖定長寬比';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backgroundRemoval => '去除背景';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contrast => '對比';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get brightness => '亮度';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get exportingPleaseWait => '匯出中…請稍候';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get nothingToSaveYet => '尚無可儲存的內容';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String savedWithPath(String path) {
|
||||||
|
return '已儲存:$path';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToSavePdf => '儲存 PDF 失敗';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get downloadStarted => '已開始下載';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToGeneratePdf => '產生 PDF 失敗';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get invalidOrUnsupportedFile => '無效或不支援的檔案';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get confirm => '確認';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get undo => '復原';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get clear => '清除';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The translations for Chinese, as used in Taiwan (`zh_TW`).
|
||||||
|
class AppLocalizationsZhTw extends AppLocalizationsZh {
|
||||||
|
AppLocalizationsZhTw() : super('zh_TW');
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get appTitle => 'PDF 簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String errorWithMessage(String message) {
|
||||||
|
return '錯誤:$message';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settings => '設定';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get theme => '主題';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeLight => '淺色';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeDark => '深色';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get themeSystem => '系統';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get language => '語言';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageEnglish => '英文';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageChineseTraditional => '繁體中文';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get languageSpanish => '西班牙文';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get resetToDefaults => '重設為預設值';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get openPdf => '開啟 PDF…';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get prev => '上一頁';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get next => '下一頁';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pageInfo(int current, int total) {
|
||||||
|
return '第 $current/$total 頁';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get goTo => '前往:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get dpi => 'DPI:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get markForSigning => '標記簽署';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unmarkSigning => '取消標記';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get saveSignedPdf => '儲存已簽名 PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get loadSignatureFromFile => '從檔案載入簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get drawSignature => '手寫簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get noPdfLoaded => '尚未載入 PDF';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get signature => '簽名';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get lockAspectRatio => '鎖定長寬比';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get backgroundRemoval => '去除背景';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contrast => '對比';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get brightness => '亮度';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get exportingPleaseWait => '匯出中…請稍候';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get nothingToSaveYet => '尚無可儲存的內容';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String savedWithPath(String path) {
|
||||||
|
return '已儲存:$path';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToSavePdf => '儲存 PDF 失敗';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get downloadStarted => '已開始下載';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get failedToGeneratePdf => '產生 PDF 失敗';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get invalidOrUnsupportedFile => '無效或不支援的檔案';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get confirm => '確認';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get undo => '復原';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get clear => '清除';
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"@@locale": "zh",
|
||||||
|
"appTitle": "PDF 簽名",
|
||||||
|
"errorWithMessage": "錯誤:{message}",
|
||||||
|
|
||||||
|
"settings": "設定",
|
||||||
|
"theme": "主題",
|
||||||
|
"themeLight": "淺色",
|
||||||
|
"themeDark": "深色",
|
||||||
|
"themeSystem": "系統",
|
||||||
|
"language": "語言",
|
||||||
|
"languageEnglish": "英文",
|
||||||
|
"languageChineseTraditional": "繁體中文",
|
||||||
|
"languageSpanish": "西班牙文",
|
||||||
|
"resetToDefaults": "重設為預設值",
|
||||||
|
|
||||||
|
"openPdf": "開啟 PDF…",
|
||||||
|
"prev": "上一頁",
|
||||||
|
"next": "下一頁",
|
||||||
|
"pageInfo": "第 {current}/{total} 頁",
|
||||||
|
"goTo": "前往:",
|
||||||
|
"dpi": "DPI:",
|
||||||
|
"markForSigning": "標記簽署",
|
||||||
|
"unmarkSigning": "取消標記",
|
||||||
|
"saveSignedPdf": "儲存已簽名 PDF",
|
||||||
|
"loadSignatureFromFile": "從檔案載入簽名",
|
||||||
|
"drawSignature": "手寫簽名",
|
||||||
|
"noPdfLoaded": "尚未載入 PDF",
|
||||||
|
"signature": "簽名",
|
||||||
|
"lockAspectRatio": "鎖定長寬比",
|
||||||
|
"backgroundRemoval": "去除背景",
|
||||||
|
"contrast": "對比",
|
||||||
|
"brightness": "亮度",
|
||||||
|
"exportingPleaseWait": "匯出中…請稍候",
|
||||||
|
|
||||||
|
"nothingToSaveYet": "尚無可儲存的內容",
|
||||||
|
"savedWithPath": "已儲存:{path}",
|
||||||
|
"failedToSavePdf": "儲存 PDF 失敗",
|
||||||
|
"downloadStarted": "已開始下載",
|
||||||
|
"failedToGeneratePdf": "產生 PDF 失敗",
|
||||||
|
"invalidOrUnsupportedFile": "無效或不支援的檔案",
|
||||||
|
|
||||||
|
"confirm": "確認",
|
||||||
|
"undo": "復原",
|
||||||
|
"clear": "清除"
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"@@locale": "zh_TW",
|
||||||
|
"appTitle": "PDF 簽名",
|
||||||
|
"errorWithMessage": "錯誤:{message}",
|
||||||
|
|
||||||
|
"settings": "設定",
|
||||||
|
"theme": "主題",
|
||||||
|
"themeLight": "淺色",
|
||||||
|
"themeDark": "深色",
|
||||||
|
"themeSystem": "系統",
|
||||||
|
"language": "語言",
|
||||||
|
"languageEnglish": "英文",
|
||||||
|
"languageChineseTraditional": "繁體中文",
|
||||||
|
"languageSpanish": "西班牙文",
|
||||||
|
"resetToDefaults": "重設為預設值",
|
||||||
|
|
||||||
|
"openPdf": "開啟 PDF…",
|
||||||
|
"prev": "上一頁",
|
||||||
|
"next": "下一頁",
|
||||||
|
"pageInfo": "第 {current}/{total} 頁",
|
||||||
|
"goTo": "前往:",
|
||||||
|
"dpi": "DPI:",
|
||||||
|
"markForSigning": "標記簽署",
|
||||||
|
"unmarkSigning": "取消標記",
|
||||||
|
"saveSignedPdf": "儲存已簽名 PDF",
|
||||||
|
"loadSignatureFromFile": "從檔案載入簽名",
|
||||||
|
"drawSignature": "手寫簽名",
|
||||||
|
"noPdfLoaded": "尚未載入 PDF",
|
||||||
|
"signature": "簽名",
|
||||||
|
"lockAspectRatio": "鎖定長寬比",
|
||||||
|
"backgroundRemoval": "去除背景",
|
||||||
|
"contrast": "對比",
|
||||||
|
"brightness": "亮度",
|
||||||
|
"exportingPleaseWait": "匯出中…請稍候",
|
||||||
|
|
||||||
|
"nothingToSaveYet": "尚無可儲存的內容",
|
||||||
|
"savedWithPath": "已儲存:{path}",
|
||||||
|
"failedToSavePdf": "儲存 PDF 失敗",
|
||||||
|
"downloadStarted": "已開始下載",
|
||||||
|
"failedToGeneratePdf": "產生 PDF 失敗",
|
||||||
|
"invalidOrUnsupportedFile": "無效或不支援的檔案",
|
||||||
|
|
||||||
|
"confirm": "確認",
|
||||||
|
"undo": "復原",
|
||||||
|
"clear": "清除"
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ import 'dart:math' as math;
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
import 'package:image/image.dart' as img;
|
import 'package:image/image.dart' as img;
|
||||||
|
|
||||||
import '../../../../data/model/model.dart';
|
import '../../../../data/model/model.dart';
|
||||||
|
@ -96,9 +97,10 @@ class SignatureController extends StateNotifier<SignatureState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInvalidSelected(BuildContext context) {
|
void setInvalidSelected(BuildContext context) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final l = AppLocalizations.of(context);
|
||||||
const SnackBar(content: Text('Invalid or unsupported file')),
|
ScaffoldMessenger.of(
|
||||||
);
|
context,
|
||||||
|
).showSnackBar(SnackBar(content: Text(l.invalidOrUnsupportedFile)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void drag(Offset delta) {
|
void drag(Offset delta) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
import 'package:hand_signature/signature.dart' as hand;
|
import 'package:hand_signature/signature.dart' as hand;
|
||||||
|
|
||||||
class DrawCanvas extends StatefulWidget {
|
class DrawCanvas extends StatefulWidget {
|
||||||
|
@ -35,6 +36,7 @@ class _DrawCanvasState extends State<DrawCanvas> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l = AppLocalizations.of(context);
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
|
@ -64,19 +66,19 @@ class _DrawCanvasState extends State<DrawCanvas> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Text('Confirm'),
|
child: Text(l.confirm),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
key: const Key('btn_canvas_undo'),
|
key: const Key('btn_canvas_undo'),
|
||||||
onPressed: () => _control.stepBack(),
|
onPressed: () => _control.stepBack(),
|
||||||
child: const Text('Undo'),
|
child: Text(l.undo),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
key: const Key('btn_canvas_clear'),
|
key: const Key('btn_canvas_clear'),
|
||||||
onPressed: () => _control.clear(),
|
onPressed: () => _control.clear(),
|
||||||
child: const Text('Clear'),
|
child: Text(l.clear),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:file_selector/file_selector.dart' as fs;
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
import 'package:pdfrx/pdfrx.dart';
|
import 'package:pdfrx/pdfrx.dart';
|
||||||
import 'package:printing/printing.dart' as printing;
|
import 'package:printing/printing.dart' as printing;
|
||||||
|
|
||||||
|
@ -101,8 +102,8 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
final messenger = ScaffoldMessenger.of(context);
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
if (!pdf.loaded || sig.rect == null) {
|
if (!pdf.loaded || sig.rect == null) {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
const SnackBar(
|
SnackBar(
|
||||||
content: Text('Nothing to save yet'),
|
content: Text(AppLocalizations.of(context).nothingToSaveYet),
|
||||||
), // guard per use-case
|
), // guard per use-case
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
@ -193,22 +194,32 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
// Desktop/mobile: we had a concrete path
|
// Desktop/mobile: we had a concrete path
|
||||||
if (ok) {
|
if (ok) {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
SnackBar(content: Text('Saved: ${savedPath ?? ''}')),
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
AppLocalizations.of(context).savedWithPath(savedPath ?? ''),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
const SnackBar(content: Text('Failed to save PDF')),
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context).failedToSavePdf),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Web: indicate whether we triggered a download dialog
|
// Web: indicate whether we triggered a download dialog
|
||||||
if (ok) {
|
if (ok) {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
const SnackBar(content: Text('Download started')),
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context).downloadStarted),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
messenger.showSnackBar(
|
messenger.showSnackBar(
|
||||||
const SnackBar(content: Text('Failed to generate PDF')),
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context).failedToGeneratePdf),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,8 +238,9 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final pdf = ref.watch(pdfProvider);
|
final pdf = ref.watch(pdfProvider);
|
||||||
final isExporting = ref.watch(exportingProvider);
|
final isExporting = ref.watch(exportingProvider);
|
||||||
|
final l = AppLocalizations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('PDF Signature')),
|
appBar: AppBar(title: Text(l.appTitle)),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
|
@ -260,15 +272,15 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.black45,
|
color: Colors.black45,
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
CircularProgressIndicator(),
|
CircularProgressIndicator(),
|
||||||
SizedBox(height: 12),
|
SizedBox(height: 12),
|
||||||
Text(
|
Text(
|
||||||
'Exporting... Please wait',
|
l.exportingPleaseWait,
|
||||||
style: TextStyle(color: Colors.white),
|
style: const TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -283,7 +295,8 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
|
|
||||||
Widget _buildToolbar(PdfState pdf, {bool disabled = false}) {
|
Widget _buildToolbar(PdfState pdf, {bool disabled = false}) {
|
||||||
final dpi = ref.watch(exportDpiProvider);
|
final dpi = ref.watch(exportDpiProvider);
|
||||||
final pageInfo = 'Page ${pdf.currentPage}/${pdf.pageCount}';
|
final l = AppLocalizations.of(context);
|
||||||
|
final pageInfo = l.pageInfo(pdf.currentPage, pdf.pageCount);
|
||||||
return Wrap(
|
return Wrap(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
|
@ -299,12 +312,12 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
MaterialPageRoute(builder: (_) => const SettingsScreen()),
|
MaterialPageRoute(builder: (_) => const SettingsScreen()),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const Text('Settings'),
|
child: Text(l.settings),
|
||||||
),
|
),
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
key: const Key('btn_open_pdf_picker'),
|
key: const Key('btn_open_pdf_picker'),
|
||||||
onPressed: disabled ? null : _pickPdf,
|
onPressed: disabled ? null : _pickPdf,
|
||||||
child: const Text('Open PDF...'),
|
child: Text(l.openPdf),
|
||||||
),
|
),
|
||||||
if (pdf.loaded) ...[
|
if (pdf.loaded) ...[
|
||||||
Row(
|
Row(
|
||||||
|
@ -315,7 +328,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
onPressed:
|
onPressed:
|
||||||
disabled ? null : () => _jumpToPage(pdf.currentPage - 1),
|
disabled ? null : () => _jumpToPage(pdf.currentPage - 1),
|
||||||
icon: const Icon(Icons.chevron_left),
|
icon: const Icon(Icons.chevron_left),
|
||||||
tooltip: 'Prev',
|
tooltip: l.prev,
|
||||||
),
|
),
|
||||||
Text(pageInfo, key: const Key('lbl_page_info')),
|
Text(pageInfo, key: const Key('lbl_page_info')),
|
||||||
IconButton(
|
IconButton(
|
||||||
|
@ -323,14 +336,14 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
onPressed:
|
onPressed:
|
||||||
disabled ? null : () => _jumpToPage(pdf.currentPage + 1),
|
disabled ? null : () => _jumpToPage(pdf.currentPage + 1),
|
||||||
icon: const Icon(Icons.chevron_right),
|
icon: const Icon(Icons.chevron_right),
|
||||||
tooltip: 'Next',
|
tooltip: l.next,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const Text('Go to:'),
|
Text(l.goTo),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 60,
|
width: 60,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
|
@ -348,7 +361,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const Text('DPI:'),
|
Text(l.dpi),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
DropdownButton<double>(
|
DropdownButton<double>(
|
||||||
key: const Key('ddl_export_dpi'),
|
key: const Key('ddl_export_dpi'),
|
||||||
|
@ -377,25 +390,25 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
key: const Key('btn_mark_signing'),
|
key: const Key('btn_mark_signing'),
|
||||||
onPressed: disabled ? null : _toggleMarkForSigning,
|
onPressed: disabled ? null : _toggleMarkForSigning,
|
||||||
child: Text(
|
child: Text(
|
||||||
pdf.markedForSigning ? 'Unmark Signing' : 'Mark for Signing',
|
pdf.markedForSigning ? l.unmarkSigning : l.markForSigning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (pdf.loaded)
|
if (pdf.loaded)
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
key: const Key('btn_save_pdf'),
|
key: const Key('btn_save_pdf'),
|
||||||
onPressed: disabled ? null : _saveSignedPdf,
|
onPressed: disabled ? null : _saveSignedPdf,
|
||||||
child: const Text('Save Signed PDF'),
|
child: Text(l.saveSignedPdf),
|
||||||
),
|
),
|
||||||
if (pdf.markedForSigning) ...[
|
if (pdf.markedForSigning) ...[
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
key: const Key('btn_load_signature_picker'),
|
key: const Key('btn_load_signature_picker'),
|
||||||
onPressed: disabled ? null : _loadSignatureFromFile,
|
onPressed: disabled ? null : _loadSignatureFromFile,
|
||||||
child: const Text('Load Signature from file'),
|
child: Text(l.loadSignatureFromFile),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
key: const Key('btn_draw_signature'),
|
key: const Key('btn_draw_signature'),
|
||||||
onPressed: disabled ? null : _openDrawCanvas,
|
onPressed: disabled ? null : _openDrawCanvas,
|
||||||
child: const Text('Draw Signature'),
|
child: Text(l.drawSignature),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -405,7 +418,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
|
|
||||||
Widget _buildPageArea(PdfState pdf) {
|
Widget _buildPageArea(PdfState pdf) {
|
||||||
if (!pdf.loaded) {
|
if (!pdf.loaded) {
|
||||||
return const Center(child: Text('No PDF loaded'));
|
return Center(child: Text(AppLocalizations.of(context).noPdfLoaded));
|
||||||
}
|
}
|
||||||
final useMock = ref.watch(useMockViewerProvider);
|
final useMock = ref.watch(useMockViewerProvider);
|
||||||
if (useMock) {
|
if (useMock) {
|
||||||
|
@ -422,7 +435,9 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
color: Colors.grey.shade200,
|
color: Colors.grey.shade200,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'Page ${pdf.currentPage}/${pdf.pageCount}',
|
AppLocalizations.of(
|
||||||
|
context,
|
||||||
|
).pageInfo(pdf.currentPage, pdf.pageCount),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: Colors.black54,
|
color: Colors.black54,
|
||||||
|
@ -544,7 +559,11 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
);
|
);
|
||||||
final bytes = processed ?? sig.imageBytes;
|
final bytes = processed ?? sig.imageBytes;
|
||||||
if (bytes == null) {
|
if (bytes == null) {
|
||||||
return const Center(child: Text('Signature'));
|
return Center(
|
||||||
|
child: Text(
|
||||||
|
AppLocalizations.of(context).signature,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return Image.memory(bytes, fit: BoxFit.contain);
|
return Image.memory(bytes, fit: BoxFit.contain);
|
||||||
},
|
},
|
||||||
|
@ -590,7 +609,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
.read(signatureProvider.notifier)
|
.read(signatureProvider.notifier)
|
||||||
.toggleAspect(v ?? false),
|
.toggleAspect(v ?? false),
|
||||||
),
|
),
|
||||||
const Text('Lock aspect ratio'),
|
Text(AppLocalizations.of(context).lockAspectRatio),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Switch(
|
Switch(
|
||||||
key: const Key('swt_bg_removal'),
|
key: const Key('swt_bg_removal'),
|
||||||
|
@ -598,12 +617,12 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
onChanged:
|
onChanged:
|
||||||
(v) => ref.read(signatureProvider.notifier).setBgRemoval(v),
|
(v) => ref.read(signatureProvider.notifier).setBgRemoval(v),
|
||||||
),
|
),
|
||||||
const Text('Background removal'),
|
Text(AppLocalizations.of(context).backgroundRemoval),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Text('Contrast'),
|
Text(AppLocalizations.of(context).contrast),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Slider(
|
child: Slider(
|
||||||
key: const Key('sld_contrast'),
|
key: const Key('sld_contrast'),
|
||||||
|
@ -619,7 +638,7 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Text('Brightness'),
|
Text(AppLocalizations.of(context).brightness),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Slider(
|
child: Slider(
|
||||||
key: const Key('sld_brightness'),
|
key: const Key('sld_brightness'),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:pdf_signature/l10n/app_localizations.dart';
|
||||||
import '../providers.dart';
|
import '../providers.dart';
|
||||||
|
|
||||||
class SettingsScreen extends ConsumerWidget {
|
class SettingsScreen extends ConsumerWidget {
|
||||||
|
@ -8,22 +9,23 @@ class SettingsScreen extends ConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final prefs = ref.watch(preferencesProvider);
|
final prefs = ref.watch(preferencesProvider);
|
||||||
|
final l = AppLocalizations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Settings')),
|
appBar: AppBar(title: Text(l.settings)),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text('Theme', style: TextStyle(fontWeight: FontWeight.bold)),
|
Text(l.theme, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
DropdownButton<String>(
|
DropdownButton<String>(
|
||||||
key: const Key('ddl_theme'),
|
key: const Key('ddl_theme'),
|
||||||
value: prefs.theme,
|
value: prefs.theme,
|
||||||
items: const [
|
items: [
|
||||||
DropdownMenuItem(value: 'light', child: Text('Light')),
|
DropdownMenuItem(value: 'light', child: Text(l.themeLight)),
|
||||||
DropdownMenuItem(value: 'dark', child: Text('Dark')),
|
DropdownMenuItem(value: 'dark', child: Text(l.themeDark)),
|
||||||
DropdownMenuItem(value: 'system', child: Text('System')),
|
DropdownMenuItem(value: 'system', child: Text(l.themeSystem)),
|
||||||
],
|
],
|
||||||
onChanged:
|
onChanged:
|
||||||
(v) =>
|
(v) =>
|
||||||
|
@ -32,18 +34,21 @@ class SettingsScreen extends ConsumerWidget {
|
||||||
: ref.read(preferencesProvider.notifier).setTheme(v),
|
: ref.read(preferencesProvider.notifier).setTheme(v),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const Text(
|
Text(
|
||||||
'Language',
|
l.language,
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
DropdownButton<String>(
|
DropdownButton<String>(
|
||||||
key: const Key('ddl_language'),
|
key: const Key('ddl_language'),
|
||||||
value: prefs.language,
|
value: prefs.language,
|
||||||
items: const [
|
items: [
|
||||||
DropdownMenuItem(value: 'en', child: Text('English')),
|
DropdownMenuItem(value: 'en', child: Text(l.languageEnglish)),
|
||||||
DropdownMenuItem(value: 'zh-TW', child: Text('繁體中文')),
|
DropdownMenuItem(
|
||||||
DropdownMenuItem(value: 'es', child: Text('Español')),
|
value: 'zh-TW',
|
||||||
|
child: Text(l.languageChineseTraditional),
|
||||||
|
),
|
||||||
|
DropdownMenuItem(value: 'es', child: Text(l.languageSpanish)),
|
||||||
],
|
],
|
||||||
onChanged:
|
onChanged:
|
||||||
(v) =>
|
(v) =>
|
||||||
|
@ -63,7 +68,7 @@ class SettingsScreen extends ConsumerWidget {
|
||||||
ref
|
ref
|
||||||
.read(preferencesProvider.notifier)
|
.read(preferencesProvider.notifier)
|
||||||
.resetToDefaults(),
|
.resetToDefaults(),
|
||||||
child: const Text('Reset to defaults'),
|
child: Text(l.resetToDefaults),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -73,6 +73,7 @@ dev_dependencies:
|
||||||
|
|
||||||
# The following section is specific to Flutter packages.
|
# The following section is specific to Flutter packages.
|
||||||
flutter:
|
flutter:
|
||||||
|
generate: true
|
||||||
|
|
||||||
# The following line ensures that the Material Icons font is
|
# The following line ensures that the Material Icons font is
|
||||||
# included with your application, so that you can use the icons in
|
# included with your application, so that you can use the icons in
|
||||||
|
|
Loading…
Reference in New Issue