dvNegotiateLocale function

DVLocaleChoice dvNegotiateLocale({
  1. required List<String> supported,
  2. required String fallback,
  3. String? path,
  4. String? acceptLanguage,
  5. String? preferred,
  6. String? tenantDefault,
})

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,
  );
}