readsight 1.0.2

Multilingual readability library — 86 languages, 17 formulas, TeX-based syllable counting via the Frank M. Liang algorithm.
Documentation
//! Flesch Reading Ease and Flesch-Kincaid Grade Level.

use crate::formula::{grade_clamp, inputs, round_to, Formula, FormulaResult};
use crate::language::Language;
use crate::text::TextStatistics;

const FLESCH_LANGS: &[&str] = &[
    "en-us",
    "en-gb",
    "de-1996",
    "de-1901",
    "de-ch-1901",
    "ru",
    "es",
    "it",
    "fr",
    "nl",
    "pt",
    "tr",
];

/// Flesch Reading Ease.
pub struct FleschReadingEase;

impl Formula for FleschReadingEase {
    fn name(&self) -> &'static str {
        "flesch_reading_ease"
    }
    fn description(&self) -> &'static str {
        "Flesch Reading Ease - measures text readability on a 0-100 scale (higher = easier). Coefficients vary by language."
    }
    fn supported_languages(&self) -> &'static [&'static str] {
        FLESCH_LANGS
    }
    fn calculate(&self, stats: &TextStatistics, language: &Language) -> FormulaResult {
        let base = language
            .formula_number(self.name(), "base")
            .unwrap_or(206.835);
        let asl = language
            .formula_number(self.name(), "aslMult")
            .unwrap_or(1.015);
        let asw = language
            .formula_number(self.name(), "aswMult")
            .unwrap_or(84.6);
        let score =
            base - asl * stats.average_words_per_sentence - asw * stats.average_syllables_per_word;
        FormulaResult {
            formula_name: self.name().to_string(),
            language_code: language.code.clone(),
            score: round_to(score, 1),
            grade_level: None,
            interpretation: interpret_fre(score).to_string(),
            inputs: inputs(&[
                ("asl", stats.average_words_per_sentence),
                ("asw", stats.average_syllables_per_word),
            ]),
        }
    }
}

fn interpret_fre(score: f64) -> &'static str {
    if score >= 90.0 {
        "Very Easy"
    } else if score >= 80.0 {
        "Easy"
    } else if score >= 70.0 {
        "Fairly Easy"
    } else if score >= 60.0 {
        "Standard"
    } else if score >= 50.0 {
        "Fairly Hard"
    } else if score >= 30.0 {
        "Hard"
    } else {
        "Very Hard"
    }
}

/// Flesch-Kincaid Grade Level.
pub struct FleschKincaidGradeLevel;

impl Formula for FleschKincaidGradeLevel {
    fn name(&self) -> &'static str {
        "flesch_kincaid_grade_level"
    }
    fn description(&self) -> &'static str {
        "Flesch-Kincaid Grade Level - converts Reading Ease into a U.S. school grade level."
    }
    fn supported_languages(&self) -> &'static [&'static str] {
        FLESCH_LANGS
    }
    fn calculate(&self, stats: &TextStatistics, language: &Language) -> FormulaResult {
        let score = 0.39 * stats.average_words_per_sentence
            + 11.8 * stats.average_syllables_per_word
            - 15.59;
        FormulaResult {
            formula_name: self.name().to_string(),
            language_code: language.code.clone(),
            score: round_to(score, 1),
            grade_level: Some(grade_clamp(score, 0.0, 18.0)),
            interpretation: interpret_fkgl(score).to_string(),
            inputs: inputs(&[
                ("asl", stats.average_words_per_sentence),
                ("asw", stats.average_syllables_per_word),
            ]),
        }
    }
}

fn interpret_fkgl(score: f64) -> &'static str {
    if score <= 1.0 {
        "1st Grade"
    } else if score <= 2.0 {
        "2nd Grade"
    } else if score <= 3.0 {
        "3rd Grade"
    } else if score <= 4.0 {
        "4th Grade"
    } else if score <= 5.0 {
        "5th Grade"
    } else if score <= 6.0 {
        "6th Grade"
    } else if score <= 7.0 {
        "7th Grade"
    } else if score <= 8.0 {
        "8th Grade"
    } else if score <= 9.0 {
        "9th Grade"
    } else if score <= 10.0 {
        "10th Grade"
    } else if score <= 11.0 {
        "11th Grade"
    } else if score <= 12.0 {
        "12th Grade"
    } else if score <= 16.0 {
        "College"
    } else {
        "Graduate"
    }
}