8081d98c67
Initial public release. Anonymous on-device identity (no phone number, e-mail, or password), Signal-protocol cryptography (X3DH + PQXDH, Double Ratchet, sealed sender) via libsignal, a metadata-minimizing relay, group chats, disappearing messages, encrypted local storage, optional Tor transport, and a UI localized into Czech, English, German, Russian, and Italian. Monorepo: Flutter client (app/), Rust relay + wire types (rust/), protobuf definitions (proto/), self-host deploy (deploy/). Licensed under AGPL-3.0 with an app-store distribution exception (§7).
92 lines
2.9 KiB
Dart
92 lines
2.9 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:sepot/features/settings/language_settings_tile.dart';
|
|
import 'package:sepot/l10n/generated/app_localizations.dart';
|
|
|
|
/// Všech 5 podporovaných jazyků se musí načíst a mít neprázdné texty.
|
|
/// Chybějící překlad = gen-l10n doplní text šablony (cs) — to hlídá
|
|
/// porovnání ARB souborů níže, ne runtime.
|
|
void main() {
|
|
const locales = [
|
|
Locale('cs'),
|
|
Locale('en'),
|
|
Locale('de'),
|
|
Locale('ru'),
|
|
Locale('it'),
|
|
];
|
|
|
|
test('podporované locale sedí s MaterialApp seznamem', () {
|
|
expect(
|
|
AppLocalizations.supportedLocales.toSet(),
|
|
locales.toSet(),
|
|
);
|
|
});
|
|
|
|
for (final locale in locales) {
|
|
test('AppLocalizations se načte pro $locale', () async {
|
|
final l10n = await AppLocalizations.delegate.load(locale);
|
|
expect(l10n.appTitle, 'Šepot');
|
|
expect(l10n.settingsLanguage, isNotEmpty);
|
|
expect(l10n.languageSystem, isNotEmpty);
|
|
});
|
|
}
|
|
|
|
// Wiring delegátů ve widget tree: skutečný widget se musí vykreslit
|
|
// v jazyce vynuceného locale (ne jen delegate.load v izolaci).
|
|
const tileTitles = {
|
|
'cs': 'Jazyk aplikace',
|
|
'en': 'App language',
|
|
'de': 'App-Sprache',
|
|
'ru': 'Язык приложения',
|
|
'it': "Lingua dell'app",
|
|
};
|
|
|
|
for (final entry in tileTitles.entries) {
|
|
testWidgets('LanguageSettingsTile se vykreslí v ${entry.key}',
|
|
(tester) async {
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
child: MaterialApp(
|
|
locale: Locale(entry.key),
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
home: const Scaffold(body: LanguageSettingsTile()),
|
|
),
|
|
),
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text(entry.value), findsOneWidget);
|
|
});
|
|
}
|
|
|
|
test('žádný jazyk nemá chybějící klíče proti šabloně (cs)', () {
|
|
final dir = Directory('lib/l10n');
|
|
final template = json.decode(
|
|
File('${dir.path}/app_cs.arb').readAsStringSync(),
|
|
) as Map<String, dynamic>;
|
|
final templateKeys =
|
|
template.keys.where((k) => !k.startsWith('@')).toSet();
|
|
|
|
for (final code in ['en', 'de', 'ru', 'it']) {
|
|
final other = json.decode(
|
|
File('${dir.path}/app_$code.arb').readAsStringSync(),
|
|
) as Map<String, dynamic>;
|
|
final keys = other.keys.where((k) => !k.startsWith('@')).toSet();
|
|
expect(
|
|
templateKeys.difference(keys),
|
|
isEmpty,
|
|
reason: 'app_$code.arb nemá všechny klíče šablony',
|
|
);
|
|
expect(
|
|
keys.difference(templateKeys),
|
|
isEmpty,
|
|
reason: 'app_$code.arb má klíče navíc oproti šabloně',
|
|
);
|
|
}
|
|
});
|
|
}
|