halkyon/packages/halkyon_app/test/l10n/arb_files_test.dart
Tizian 「ティツィアーン」 e23cc77f7c
halkyon_app: instances, sign-in and sync plumbing for Halkyon's apps
What every Halkyon app's shell needs, taken from Halkyon Learn's and set
on halkyon_base's client: the instances a device keeps an account on,
the first start's tiles and where an instance keeps people's data, the
account switcher; signing in anonymously, with GitHub or an email code,
switching person and the start screen; the gates that build an app's
dependencies per instance and per person; and the sync service with its
status, Settings card and banner. Texts of its own in English and
German take the app's name; what only the app can say, it passes in.
Fakes for apps' tests are in testing.dart.

An instance's basics now name the app it serves (`app`, set by the
host's configuration), and an app accepts only an instance of its own.
SerialQueue and CoalescingRunner move into halkyon_core.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-19 15:31:40 +02:00

70 lines
2.1 KiB
Dart

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_app_en.arb');
test('German has every message, with the same placeholders', () {
final german = _messages('halkyon_app_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_app_en_GB.arb', 'halkyon_app_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',
);
}
}
});
}