Halkyon's shared packages
A pub workspace of the Dart packages Halkyon's apps share: halkyon_ui, Halkyon's look (the theme, fonts, layout and shared widgets, with texts in English and German), halkyon_core's low-level primitives and halkyon_interop's cross-app contracts. Dart 3.13 with LeanCode's lints, configured once at the root; apps take a package by git, pinned to a signed commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
commit
80fa7b9628
2 changed files with 6762 additions and 0 deletions
70
packages/halkyon_ui/test/l10n/arb_files_test.dart
Normal file
70
packages/halkyon_ui/test/l10n/arb_files_test.dart
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
/// The messages of the `.arb` file [name] in `lib/l10n/`, without metadata.
|
||||
Map<String, String> _messages(String name) => {
|
||||
for (final MapEntry(:key, :value) in (jsonDecode(
|
||||
File('lib/l10n/$name').readAsStringSync(),
|
||||
) as Map<String, Object?>).entries)
|
||||
if (!key.startsWith('@')) key: value! as String,
|
||||
};
|
||||
|
||||
/// The names of the placeholders in [message], with plural and select
|
||||
/// arguments; the words of their branches don't count. (gen-l10n reads
|
||||
/// quotes as text here: `use-escaping` is off.)
|
||||
Set<String> _placeholders(String message) {
|
||||
final names = <String>{};
|
||||
// Even depths hold text and placeholders, odd ones a plural's branches.
|
||||
var depth = 0;
|
||||
for (var i = 0; i < message.length; i++) {
|
||||
switch (message[i]) {
|
||||
case '{':
|
||||
final name = RegExp(r'\{\s*(\w+)\s*[,}]').matchAsPrefix(message, i);
|
||||
if (name != null && depth.isEven) {
|
||||
names.add(name.group(1)!);
|
||||
}
|
||||
depth++;
|
||||
case '}':
|
||||
depth--;
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
void main() {
|
||||
final template = _messages('halkyon_ui_en.arb');
|
||||
|
||||
test('German has every message, with the same placeholders', () {
|
||||
final german = _messages('halkyon_ui_de.arb');
|
||||
|
||||
expect(
|
||||
template.keys.where((key) => !german.containsKey(key)),
|
||||
isEmpty,
|
||||
reason: 'untranslated',
|
||||
);
|
||||
expect(
|
||||
german.keys.where((key) => !template.containsKey(key)),
|
||||
isEmpty,
|
||||
reason: 'not in the template',
|
||||
);
|
||||
for (final MapEntry(:key, :value) in german.entries) {
|
||||
expect(_placeholders(value), _placeholders(template[key]!), reason: key);
|
||||
}
|
||||
});
|
||||
|
||||
test("the English variants override the template's messages only, with "
|
||||
'the same placeholders', () {
|
||||
for (final variant in ['halkyon_ui_en_GB.arb', 'halkyon_ui_en_US.arb']) {
|
||||
for (final MapEntry(:key, :value) in _messages(variant).entries) {
|
||||
expect(template, contains(key), reason: '$variant: $key');
|
||||
expect(
|
||||
_placeholders(value),
|
||||
_placeholders(template[key]!),
|
||||
reason: '$variant: $key',
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:halkyon_ui/halkyon_ui.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
import '../support/test_app.dart';
|
||||
|
||||
void main() {
|
||||
test('speaks British English, American English and German', () {
|
||||
expect(
|
||||
lookupHalkyonUiLocalizations(const Locale('en')).colorPickerLabel('X'),
|
||||
'Colour: X',
|
||||
);
|
||||
expect(
|
||||
lookupHalkyonUiLocalizations(
|
||||
const Locale('en', 'GB'),
|
||||
).colorPickerLabel('X'),
|
||||
'Colour: X',
|
||||
);
|
||||
expect(
|
||||
lookupHalkyonUiLocalizations(
|
||||
const Locale('en', 'US'),
|
||||
).colorPickerLabel('X'),
|
||||
'Color: X',
|
||||
);
|
||||
expect(
|
||||
lookupHalkyonUiLocalizations(const Locale('de')).colorPickerLabel('X'),
|
||||
'Farbe: X',
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets("an app adding the package's delegate gets its texts in the "
|
||||
"app's language", (tester) async {
|
||||
await tester.pumpWidget(
|
||||
testApp(
|
||||
locale: const Locale('de'),
|
||||
ReorderToggle(
|
||||
reordering: false,
|
||||
labelled: true,
|
||||
tooltip: 'Pfade umsortieren',
|
||||
onToggle: () {},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('Umsortieren'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue