feat: ship the interface in eight languages, with per-language plurals and mirroring

This commit is contained in:
randogoth 2026-10-11 14:54:43 +03:00
parent 6de6672ae3
commit a4a49f41d7
28 changed files with 1795 additions and 32 deletions

View file

@ -1,7 +1,10 @@
import 'dart:async' show unawaited;
import 'dart:ui' show PlatformDispatcher;
import 'package:actors/actors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:signals/signals_flutter.dart' show SignalBuilder;
import '../application/actors/fetch_actor.dart';
@ -13,6 +16,7 @@ import '../application/fonts.dart';
import '../application/internal_actions.dart';
import '../application/internal_pages.dart';
import '../database/database.dart';
import '../l10n/locales.dart';
import '../l10n/strings.dart';
import '../mews/document.dart';
import 'reader/palettes.dart';
@ -38,6 +42,7 @@ class AppDependencies {
strings: this.strings);
internalActions = InternalActions(
db: db,
applyLanguage: applyLanguage,
settings: settings,
bookmarks: bookmarks,
subscriptions: subscriptions,
@ -65,8 +70,20 @@ class AppDependencies {
late final InternalPages internalPages;
late final InternalActions internalActions;
/// The language to read the interface in: the reader's choice, or the best
/// match for what the device asks for.
String get activeLocale => settings.language.value == systemLanguage
? resolveLocale(
PlatformDispatcher.instance.locales.map((l) => l.toLanguageTag()))
: settings.language.value;
/// Loads the chosen language's messages. Called at startup and whenever the
/// reader changes the setting.
Future<void> applyLanguage() => strings.use(activeLocale);
Future<void> start() async {
await settings.load();
await applyLanguage();
await bookmarks.load();
await subscriptions.load();
await browser.restoreLastSession();
@ -129,13 +146,30 @@ class _ThemedApp extends StatelessWidget {
};
final settings = deps.settings;
final font = settings.font.value;
// Read so the whole app rebuilds when the reader changes language.
settings.language.value;
final page = deps.browser.currentPage.value;
final variant = settings.variant.value == 'site'
? (page?.variant ?? MewsVariant.plain)
: pageVariantFromName(settings.variant.value);
// Flutter's own widgets and the text direction follow the same
// language, so a right-to-left interface mirrors without us asking.
final locale = deps.activeLocale;
return MaterialApp(
title: 'Mews',
locale: Locale(locale.split('-').first,
locale.contains('-') ? locale.split('-').last : null),
supportedLocales: [
for (final l in appLocales)
Locale(l.tag.split('-').first,
l.tag.contains('-') ? l.tag.split('-').last : null),
],
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
themeMode: mode,
theme: _themeFor(
paletteFor(pageVariant: variant, readerVariant: 'site', dark: false),