feat(frontend): add multi-language support (en, zh-Hans, zh-Hant, ja)
This commit is contained in:
@@ -7,6 +7,7 @@ import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
import '../l10n/app_localizations.dart';
|
||||
import '../providers/auth_provider.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
import '../services/api_service.dart';
|
||||
@@ -271,6 +272,7 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
|
||||
Future<void> _openVolumeSheet() async {
|
||||
_showControls();
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
await showModalBottomSheet<void>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
@@ -284,7 +286,7 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Volume',
|
||||
l10n.volume,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -353,6 +355,7 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
final nextResolution = await showModalBottomSheet<String>(
|
||||
context: context,
|
||||
@@ -364,11 +367,11 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text('Playback Resolution'),
|
||||
title: Text(l10n.playbackResolution),
|
||||
subtitle: Text(
|
||||
available.length > 1
|
||||
? 'Select an available transcoded stream.'
|
||||
: 'Only the source stream is available right now.',
|
||||
? l10n.playbackOptionsDesc
|
||||
: l10n.sourceOnlyDesc,
|
||||
),
|
||||
),
|
||||
...options.map((option) {
|
||||
@@ -382,8 +385,8 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
),
|
||||
title: Text(option),
|
||||
subtitle: enabled
|
||||
? const Text('Available now')
|
||||
: const Text('Waiting for backend transcoding output'),
|
||||
? Text(l10n.availableNow)
|
||||
: Text(l10n.waitingForTranscoding),
|
||||
onTap: enabled ? () => Navigator.pop(context, option) : null,
|
||||
);
|
||||
}),
|
||||
@@ -590,6 +593,7 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
}
|
||||
|
||||
Widget _buildPlaybackControls() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return IgnorePointer(
|
||||
ignoring: !_controlsVisible,
|
||||
child: AnimatedOpacity(
|
||||
@@ -620,7 +624,7 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
children: [
|
||||
_buildControlButton(
|
||||
icon: Icons.refresh,
|
||||
label: "Refresh",
|
||||
label: l10n.refresh,
|
||||
onPressed: _refreshPlayer,
|
||||
),
|
||||
_buildControlButton(
|
||||
@@ -629,19 +633,19 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
: _volume < 0.5
|
||||
? Icons.volume_down
|
||||
: Icons.volume_up,
|
||||
label: "Volume",
|
||||
label: l10n.volume,
|
||||
onPressed: _openVolumeSheet,
|
||||
),
|
||||
_buildControlButton(
|
||||
icon: _showDanmaku ? Icons.subtitles : Icons.subtitles_off,
|
||||
label: _showDanmaku ? "Danmaku On" : "Danmaku Off",
|
||||
label: _showDanmaku ? l10n.danmakuOn : l10n.danmakuOff,
|
||||
onPressed: _toggleDanmaku,
|
||||
),
|
||||
_buildControlButton(
|
||||
icon: _isFullscreen
|
||||
? Icons.fullscreen_exit
|
||||
: Icons.fullscreen,
|
||||
label: _isFullscreen ? "Exit Fullscreen" : "Fullscreen",
|
||||
label: _isFullscreen ? l10n.exitFullscreen : l10n.fullscreen,
|
||||
onPressed: _toggleFullscreen,
|
||||
),
|
||||
_buildControlButton(
|
||||
@@ -679,23 +683,24 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
|
||||
// 抽离聊天区域组件
|
||||
Widget _buildChatSection() {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(Icons.chat_bubble_outline, size: 16),
|
||||
SizedBox(width: 8),
|
||||
Text("Live Chat", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||
const Icon(Icons.chat_bubble_outline, size: 16),
|
||||
const SizedBox(width: 8),
|
||||
Text(l10n.liveChat, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
reverse: true,
|
||||
padding: EdgeInsets.all(8),
|
||||
padding: const EdgeInsets.all(8),
|
||||
itemCount: _messages.length,
|
||||
itemBuilder: (context, index) {
|
||||
final m = _messages[index];
|
||||
@@ -703,7 +708,7 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
},
|
||||
),
|
||||
),
|
||||
Divider(height: 1),
|
||||
const Divider(height: 1),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
@@ -712,11 +717,11 @@ class _PlayerPageState extends State<PlayerPage> {
|
||||
child: TextField(
|
||||
controller: _msgController,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Send a message...",
|
||||
hintText: l10n.sendMessage,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user