run method
Inspect project and return findings. May return an empty list.
Should NOT throw — turn unexpected conditions into Issues so the
report surfaces them rather than crashing.
Implementation
@override
List<Issue> run(DialectProject project) {
final issues = <Issue>[];
final overrides = _parseOverrides(project);
final sourceByKey = <String, ArbEntry>{
for (final e in project.source.entries) e.key: e,
};
for (final entry in project.translations.entries) {
final locale = entry.key;
if (locale == project.config.sourceLocale) continue;
final arb = entry.value;
final range = overrides[locale] ?? defaultRange;
for (final t in arb.entries) {
final src = sourceByKey[t.key];
if (src == null) continue;
if (src.value.length < minSourceLength) continue;
if (t.value.isEmpty) continue; // empty_values rule covers this
final ratio = t.value.length / src.value.length;
if (ratio < range[0] || ratio > range[1]) {
final direction = ratio < range[0] ? 'shorter' : 'longer';
issues.add(
Issue(
severity: defaultSeverity,
ruleName: name,
message:
'Translation for `${t.key}` is '
'${ratio.toStringAsFixed(2)}× the source length — '
'$direction than the expected band '
'[${range[0]}, ${range[1]}].',
locale: locale,
key: t.key,
file: arb.sourcePath,
line: arb.entryLines[t.key],
hint:
'Common causes: truncated UI text, wrong-locale paste, '
'or an AI hallucinating extra prose. If `$locale` legitimately '
'expands or contracts this much, add an override under '
'`length_ratio:` in dialect.yaml.',
),
);
}
}
}
return issues;
}