🌐 Localized files
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
@@ -54,7 +55,7 @@ class PublicationSiteDetailScreen extends HookConsumerWidget {
|
||||
appBar: AppBar(
|
||||
title: siteAsync.maybeWhen(
|
||||
data: (site) => Text(site.name),
|
||||
orElse: () => const Text('Site Details'),
|
||||
orElse: () => Text('siteDetails'.tr()),
|
||||
),
|
||||
actions: [
|
||||
siteAsync.maybeWhen(
|
||||
@@ -105,26 +106,26 @@ class PublicationSiteDetailScreen extends HookConsumerWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Site Information',
|
||||
'siteInformation'.tr(),
|
||||
style: theme.textTheme.titleMedium
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Gap(16),
|
||||
InfoRow(
|
||||
label: 'Name',
|
||||
label: 'name'.tr(),
|
||||
value: site.name,
|
||||
icon: Symbols.title,
|
||||
),
|
||||
const Gap(8),
|
||||
InfoRow(
|
||||
label: 'Slug',
|
||||
label: 'slug'.tr(),
|
||||
value: site.slug,
|
||||
icon: Symbols.tag,
|
||||
monospace: true,
|
||||
),
|
||||
const Gap(8),
|
||||
InfoRow(
|
||||
label: 'Domain',
|
||||
label: 'siteDomain'.tr(),
|
||||
value: '${site.slug}.solian.page',
|
||||
icon: Symbols.globe,
|
||||
monospace: true,
|
||||
@@ -136,31 +137,31 @@ class PublicationSiteDetailScreen extends HookConsumerWidget {
|
||||
),
|
||||
const Gap(8),
|
||||
InfoRow(
|
||||
label: 'Mode',
|
||||
label: 'siteMode'.tr(),
|
||||
value:
|
||||
site.mode == 0
|
||||
? 'Fully Managed'
|
||||
: 'Self-Managed',
|
||||
? 'siteModeFullyManaged'.tr()
|
||||
: 'siteModeSelfManaged'.tr(),
|
||||
icon: Symbols.settings,
|
||||
),
|
||||
if (site.description != null &&
|
||||
site.description!.isNotEmpty) ...[
|
||||
const Gap(8),
|
||||
InfoRow(
|
||||
label: 'Description',
|
||||
label: 'description'.tr(),
|
||||
value: site.description!,
|
||||
icon: Symbols.description,
|
||||
),
|
||||
],
|
||||
const Gap(8),
|
||||
InfoRow(
|
||||
label: 'Created',
|
||||
label: 'siteCreated'.tr(),
|
||||
value: site.createdAt.formatSystem(),
|
||||
icon: Symbols.calendar_add_on,
|
||||
),
|
||||
const Gap(8),
|
||||
InfoRow(
|
||||
label: 'Updated',
|
||||
label: 'siteUpdated'.tr(),
|
||||
value: site.updatedAt.formatSystem(),
|
||||
icon: Symbols.update,
|
||||
),
|
||||
@@ -191,7 +192,7 @@ class PublicationSiteDetailScreen extends HookConsumerWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'Failed to load site',
|
||||
'failedToLoadSite'.tr(),
|
||||
style: Theme.of(context).textTheme.headlineSmall,
|
||||
),
|
||||
const Gap(16),
|
||||
@@ -202,7 +203,7 @@ class PublicationSiteDetailScreen extends HookConsumerWidget {
|
||||
() => ref.invalidate(
|
||||
publicationSiteDetailProvider(pubName, siteSlug),
|
||||
),
|
||||
child: const Text('Retry'),
|
||||
child: Text('retry'.tr()),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -31,20 +31,20 @@ class SiteForm extends HookConsumerWidget {
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: slugController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Slug',
|
||||
hintText: 'my-site',
|
||||
decoration: InputDecoration(
|
||||
labelText: 'siteSlug'.tr(),
|
||||
hintText: 'siteSlugHint'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter a slug';
|
||||
return 'siteSlugRequired'.tr();
|
||||
}
|
||||
final slugRegex = RegExp(r'^[a-z0-9]+(?:-[a-z0-9]+)*$');
|
||||
if (!slugRegex.hasMatch(value)) {
|
||||
return 'Slug can only contain lowercase letters, numbers, and dashes';
|
||||
return 'siteSlugInvalid'.tr();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -53,16 +53,16 @@ class SiteForm extends HookConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Site Name',
|
||||
hintText: 'My Publication Site',
|
||||
decoration: InputDecoration(
|
||||
labelText: 'siteName'.tr(),
|
||||
hintText: 'siteNameHint'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter a site name';
|
||||
return 'siteNameRequired'.tr();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -71,8 +71,8 @@ class SiteForm extends HookConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: descriptionController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Description',
|
||||
decoration: InputDecoration(
|
||||
labelText: 'description'.tr(),
|
||||
alignLabelWithHint: true,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
@@ -84,15 +84,18 @@ class SiteForm extends HookConsumerWidget {
|
||||
const SizedBox(height: 16),
|
||||
DropdownButtonFormField<int>(
|
||||
value: modeController.value,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Mode',
|
||||
decoration: InputDecoration(
|
||||
labelText: 'siteMode'.tr(),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 0, child: Text('Fully Managed')),
|
||||
DropdownMenuItem(value: 1, child: Text('Self-Managed')),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: 0,
|
||||
child: Text('siteModeFullyManaged'.tr()),
|
||||
),
|
||||
DropdownMenuItem(value: 1, child: Text('siteModeSelfManaged'.tr())),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
@@ -104,7 +107,7 @@ class SiteForm extends HookConsumerWidget {
|
||||
).padding(all: 20);
|
||||
|
||||
return SheetScaffold(
|
||||
titleText: 'Edit Publication Site',
|
||||
titleText: 'editPublicationSite'.tr(),
|
||||
child: Builder(
|
||||
builder:
|
||||
(context) => SingleChildScrollView(
|
||||
@@ -116,7 +119,7 @@ class SiteForm extends HookConsumerWidget {
|
||||
TextButton.icon(
|
||||
onPressed: deleteSite,
|
||||
icon: const Icon(Symbols.delete_forever),
|
||||
label: const Text('Delete Publication Site'),
|
||||
label: Text('deletePublicationSite'.tr()),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.red,
|
||||
),
|
||||
@@ -171,7 +174,7 @@ class SiteForm extends HookConsumerWidget {
|
||||
ref.invalidate(siteListNotifierProvider(pubName));
|
||||
|
||||
if (context.mounted) {
|
||||
showSnackBar('Publication site saved successfully');
|
||||
showSnackBar('publicationSiteSavedSuccess'.tr());
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -185,8 +188,8 @@ class SiteForm extends HookConsumerWidget {
|
||||
if (siteSlug == null) return; // Shouldn't happen for editing
|
||||
|
||||
final confirmed = await showConfirmAlert(
|
||||
'Are you sure you want to delete this publication site? This action cannot be undone.',
|
||||
'Delete Publication Site',
|
||||
'publicationSiteDeleteConfirm'.tr(),
|
||||
'deletePublicationSite'.tr(),
|
||||
);
|
||||
if (confirmed != true) return;
|
||||
|
||||
@@ -199,7 +202,7 @@ class SiteForm extends HookConsumerWidget {
|
||||
ref.invalidate(siteListNotifierProvider(pubName));
|
||||
|
||||
if (context.mounted) {
|
||||
showSnackBar('Publication site deleted successfully');
|
||||
showSnackBar('publicationSiteDeletedSuccess'.tr());
|
||||
Navigator.pop(context);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -243,13 +246,13 @@ class SiteForm extends HookConsumerWidget {
|
||||
editingSiteSlug,
|
||||
),
|
||||
loading:
|
||||
() => const SheetScaffold(
|
||||
titleText: 'Edit Publication Site',
|
||||
() => SheetScaffold(
|
||||
titleText: 'editPublicationSite'.tr(),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
error:
|
||||
(error, _) => SheetScaffold(
|
||||
titleText: 'Edit Publication Site',
|
||||
titleText: 'editPublicationSite'.tr(),
|
||||
child: ResponseErrorWidget(
|
||||
error: error.toString(),
|
||||
onRetry: () {
|
||||
@@ -327,9 +330,12 @@ class SiteForm extends HookConsumerWidget {
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
),
|
||||
),
|
||||
items: const [
|
||||
DropdownMenuItem(value: 0, child: Text('Fully Managed')),
|
||||
DropdownMenuItem(value: 1, child: Text('Self-Managed')),
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: 0,
|
||||
child: Text('siteModeFullyManaged'.tr()),
|
||||
),
|
||||
DropdownMenuItem(value: 1, child: Text('siteModeSelfManaged'.tr())),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
@@ -348,7 +354,9 @@ class SiteForm extends HookConsumerWidget {
|
||||
|
||||
return SheetScaffold(
|
||||
titleText:
|
||||
siteSlug == null ? 'New Publication Site' : 'Edit Publication Site',
|
||||
siteSlug == null
|
||||
? 'newPublicationSite'.tr()
|
||||
: 'editPublicationSite'.tr(),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -359,7 +367,7 @@ class SiteForm extends HookConsumerWidget {
|
||||
TextButton.icon(
|
||||
onPressed: isLoading.value ? null : deleteSite,
|
||||
icon: const Icon(Symbols.delete_forever),
|
||||
label: const Text('Delete Publication Site'),
|
||||
label: Text('deletePublicationSite'.tr()),
|
||||
style: TextButton.styleFrom(foregroundColor: Colors.red),
|
||||
).alignment(Alignment.centerRight),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
@@ -74,7 +74,7 @@ class CreatorSiteListScreen extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return AppScaffold(
|
||||
isNoBackground: false,
|
||||
appBar: AppBar(title: Text('Publication Sites')),
|
||||
appBar: AppBar(title: Text('publicationSites'.tr())),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => _createSite(context),
|
||||
child: Icon(Icons.add),
|
||||
@@ -201,21 +201,19 @@ class _CreatorSiteItem extends HookConsumerWidget {
|
||||
context: context,
|
||||
builder:
|
||||
(context) => AlertDialog(
|
||||
title: Text('Delete Site'),
|
||||
content: Text(
|
||||
'Are you sure you want to delete this site?',
|
||||
),
|
||||
title: Text('deleteSite'.tr()),
|
||||
content: Text('deleteSiteConfirm'.tr()),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed:
|
||||
() =>
|
||||
Navigator.of(context).pop(false),
|
||||
child: Text('Cancel'),
|
||||
child: Text('cancel'.tr()),
|
||||
),
|
||||
TextButton(
|
||||
onPressed:
|
||||
() => Navigator.of(context).pop(true),
|
||||
child: Text('Delete'),
|
||||
child: Text('delete'.tr()),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -225,7 +223,7 @@ class _CreatorSiteItem extends HookConsumerWidget {
|
||||
final client = ref.read(apiClientProvider);
|
||||
await client.delete('/zone/sites/${site.id}');
|
||||
ref.invalidate(siteListNotifierProvider(pubName));
|
||||
showSnackBar('Site deleted successfully');
|
||||
showSnackBar('siteDeletedSuccess'.tr());
|
||||
} catch (e) {
|
||||
showErrorAlert(e);
|
||||
}
|
||||
|
||||
@@ -534,7 +534,7 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
|
||||
),
|
||||
const Gap(4),
|
||||
Text(
|
||||
'The last selected number will be your special number.',
|
||||
'lotteryLastNumberSpecial'.tr(),
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontWeight: FontWeight.w500,
|
||||
@@ -738,11 +738,11 @@ class _LotteryPurchaseSheetState extends State<LotteryPurchaseSheet> {
|
||||
},
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter a multiplier';
|
||||
return 'lotteryMultiplierRequired'.tr();
|
||||
}
|
||||
final parsed = int.tryParse(value);
|
||||
if (parsed == null || parsed < 1 || parsed > 10) {
|
||||
return 'Multiplier must be between 1 and 10';
|
||||
return 'lotteryMultiplierRange'.tr();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user