validate static method
Validates locale files and returns a ValidationResult.
baseLocale is the schema of truth. Extra keys in non-base locales
are errors. Missing keys in non-base locales are warnings.
Implementation
static ValidationResult validate(
List<ParsedLocaleFile> localeFiles, {
String? baseLocale,
}) {
if (localeFiles.isEmpty) {
return const ValidationResult(
isValid: false,
errors: ['No locale files provided'],
warnings: [],
);
}
final base = baseLocale ?? localeFiles.first.languageCode;
final baseFile = localeFiles.firstWhere(
(f) => f.languageCode == base,
orElse: () => throw SwayValidationException(
'Base locale "$base" not found among provided locale files',
errors: ['Base locale file missing'],
),
);
final errors = <String>[];
final warnings = <String>[];
final baseKeys = _flattenKeys(baseFile.data);
// Validate base locale file key names
_validateKeyNames(baseFile, errors);
// Validate base locale has no duplicate keys
_validateNoDuplicateKeys(baseFile, errors);
// Validate each non-base locale
for (final file in localeFiles) {
if (file.languageCode == base) continue;
_validateKeyNames(file, errors);
_validateNoDuplicateKeys(file, errors);
final localeKeys = _flattenKeys(file.data);
// Check for extra keys (error — base is schema of truth)
for (final key in localeKeys) {
if (!baseKeys.contains(key)) {
errors.add(
'${file.languageCode}: has extra key "$key" not in base locale',
);
}
}
// Check for missing keys (warning)
final missingKeys = <String>[];
for (final key in baseKeys) {
if (!localeKeys.contains(key)) {
missingKeys.add(key);
}
}
if (missingKeys.isNotEmpty) {
warnings.add(
'${file.languageCode}: missing keys: ${missingKeys.join(', ')}',
);
}
}
// Validate placeholders across locales
_validatePlaceholders(localeFiles, baseFile, errors);
// Validate plural categories across locales
_validatePluralCategories(localeFiles, errors, warnings);
return ValidationResult(
isValid: errors.isEmpty,
errors: errors,
warnings: warnings,
);
}