import 'package:fluent/fluent.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:flutter/widgets.dart'; import 'locales.dart'; /// Loads and formats the app's Fluent messages. All user-facing strings come /// from `locales//main.ftl`. /// /// A message missing from the chosen language falls back to English, and a /// message missing from English too comes back as its own id, so a gap shows /// in the interface rather than crashing or rendering as nothing. class Strings { FluentBundle _bundle = FluentBundle(fallbackLocale); FluentBundle _fallback = FluentBundle(fallbackLocale); String _tag = fallbackLocale; /// The language now in use, as a shipped locale tag. String get tag => _tag; bool get isRtl => isRightToLeft(_tag); /// Loads English, which every other language falls back to. Future load() async { _fallback = await _bundleFor(fallbackLocale); _bundle = _fallback; _tag = fallbackLocale; } /// Switches to [tag], keeping English underneath it. Future use(String tag) async { if (tag == _tag) return; _bundle = tag == fallbackLocale ? _fallback : await _bundleFor(tag); _tag = tag; } Future _bundleFor(String tag) async { final bundle = FluentBundle(tag); bundle.addMessages(await rootBundle.loadString('locales/$tag/main.ftl')); return bundle; } /// Loads messages from an already-read source, so tests can read files from /// disk instead of the asset bundle. void loadSource(String source, {String tag = fallbackLocale}) { final bundle = FluentBundle(tag); bundle.addMessages(source); _bundle = bundle; _tag = tag; if (tag == fallbackLocale) _fallback = bundle; } /// The message for [id], or null when neither the chosen language nor /// English has one. Used where a missing message is expected, such as a /// plural form a language does not need. String? lookup(String id, [Map args = const {}]) => _bundle.format(id, args: args) ?? _fallback.format(id, args: args); String t(String id, [Map args = const {}]) => lookup(id, args) ?? id; /// Which plural message [count] needs in the language in use. String pluralSuffixFor(int count) => pluralSuffix(_tag, count); } /// Provides [Strings] to the widget tree. class StringsScope extends InheritedWidget { const StringsScope({required this.strings, required super.child, super.key}); final Strings strings; static Strings of(BuildContext context) => context.getInheritedWidgetOfExactType()!.strings; @override bool updateShouldNotify(StringsScope oldWidget) => false; }