dvNegotiateLocale function
Picks a locale from a path prefix, a stored preference and Accept-Language.
Precedence is path, then preference, then header, then tenantDefault,
then fallback. The path wins because it is in the URL the user shared, so
it has to survive being opened by someone whose browser prefers another
language. A stored preference beats the header because the user chose it,
where Accept-Language is whatever their OS was installed as. A tenant's
default never overrides what a person asked for; it is what they get when
they asked for nothing, and it is skipped when the application does not
support it, or a tenant configured for a removed catalogue would pin every
visitor to a locale nothing can render.
Implementation
DVLocaleChoice dvNegotiateLocale({
required List<String> supported,
required String fallback,
String? path,
String? acceptLanguage,
String? preferred,
String? tenantDefault,
}) {
final String route = (path == null || path.isEmpty) ? '/' : path;
// The path first, and only when the segment is a locale that exists --
// otherwise "/orders" reads as locale "orders" with an empty path.
final List<String> segments =
route.split('/').where((String s) => s.isNotEmpty).toList();
if (segments.isNotEmpty) {
final String? matched = _exact(supported, segments.first);
if (matched != null) {
final String rest = segments.skip(1).join('/');
return DVLocaleChoice(
locale: matched,
source: DVLocaleSource.path,
path: rest.isEmpty ? '/' : '/$rest',
);
}
}
// A stale preference naming a locale that has since been removed must not
// pin the user to it.
if (preferred != null) {
final String? matched = _best(supported, preferred);
if (matched != null) {
return DVLocaleChoice(
locale: matched,
source: DVLocaleSource.preference,
path: route,
);
}
}
final String? fromHeader = _fromAcceptLanguage(supported, acceptLanguage);
if (fromHeader != null) {
return DVLocaleChoice(
locale: fromHeader,
source: DVLocaleSource.header,
path: route,
);
}
if (tenantDefault != null) {
final String? matched = _best(supported, tenantDefault);
if (matched != null) {
return DVLocaleChoice(
locale: matched,
source: DVLocaleSource.tenant,
path: route,
);
}
}
return DVLocaleChoice(
locale: fallback,
source: DVLocaleSource.fallback,
path: route,
);
}