ukraine 2.0.0

Glory to Ukraine. Library for transliterating Ukrainian Cyrillic text into Latin script representation
Documentation
// ukraine-rs — Ukrainian Cyrillic transliteration, numerals and dates.
// Copyright (c) 2022-2026 Mykhailo Krainik <https://github.com/mykhailokrainik>
//
// This program is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License, version 3, as published by
// the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License along
// with this program. If not, see <https://www.gnu.org/licenses/>.
//
// SPDX-License-Identifier: AGPL-3.0-only

/// Utilities for working with Ukrainian Latin transliteration schemes.
///
/// https://uk.wikipedia.org/wiki/%D0%90%D0%B1%D0%B5%D1%86%D0%B0%D0%B4%D0%BB%D0%BE
/// https://en.wikipedia.org/wiki/Abecad%C5%82o
///
const LOZYNSKY_RULES: &[(&str, &str)] = &[
    // Softened consonant clusters must be matched first.
    ("Дь", "Ď"),
    ("дь", "ď"),
    ("Ль", "L"),
    ("ль", "l"),
    ("Нь", "Ń"),
    ("нь", "ń"),
    ("Рь", "R’"),
    ("рь", "r’"),
    ("Сь", "Ś"),
    ("сь", "ś"),
    ("Ть", "Ť"),
    ("ть", "ť"),
    ("Ць", "Ć"),
    ("ць", "ć"),
    ("Зь", "Ź"),
    ("зь", "ź"),
    // Single letters.
    ("А", "A"),
    ("а", "a"),
    ("Б", "B"),
    ("б", "b"),
    ("В", "W"),
    ("в", "w"),
    ("Г", "H"),
    ("г", "h"),
    ("Ґ", "G"),
    ("ґ", "g"),
    ("Д", "D"),
    ("д", "d"),
    ("Е", "E"),
    ("е", "e"),
    ("Є", "Je"),
    ("є", "je"),
    ("Ж", "Ż"),
    ("ж", "ż"),
    ("З", "Z"),
    ("з", "z"),
    ("И", "Y"),
    ("и", "y"),
    ("І", "I"),
    ("і", "i"),
    ("Ї", "Ji"),
    ("ї", "ji"),
    ("Й", "J"),
    ("й", "j"),
    ("К", "K"),
    ("к", "k"),
    ("Л", "Ł"),
    ("л", "ł"),
    ("М", "M"),
    ("м", "m"),
    ("Н", "N"),
    ("н", "n"),
    ("О", "O"),
    ("о", "o"),
    ("П", "P"),
    ("п", "p"),
    ("Р", "R"),
    ("р", "r"),
    ("С", "S"),
    ("с", "s"),
    ("Т", "T"),
    ("т", "t"),
    ("У", "U"),
    ("у", "u"),
    ("Ф", "F"),
    ("ф", "f"),
    ("Х", "Ch"),
    ("х", "ch"),
    ("Ц", "C"),
    ("ц", "c"),
    ("Ч", "Cz"),
    ("ч", "cz"),
    ("Ш", "Sz"),
    ("ш", "sz"),
    ("Щ", "Szcz"),
    ("щ", "szcz"),
    ("Ю", "Ju"),
    ("ю", "ju"),
    ("Я", "Ja"),
    ("я", "ja"),
    ("Ь", ""),
    ("ь", ""),
];

/// Transliterate Ukrainian Cyrillic text into the Lozynsky Latin alphabet.
/// Characters without a known mapping are passed through unchanged.
///
/// # Examples
/// ```rust
/// use ukraine::latin::transliterate_lozynsky;
/// # fn main() {
/// let original = "Слава Україні. Героям слава!";
/// let transliterated = transliterate_lozynsky(original);
/// assert_eq!(transliterated, "Sława Ukrajini. Herojam sława!");
/// }
/// ```
pub fn transliterate_lozynsky(text: &str) -> String {
    let mut output = String::with_capacity(text.len());
    let mut index = 0;

    while index < text.len() {
        let mut matched = false;

        for (cyrillic, latin) in LOZYNSKY_RULES {
            if text[index..].starts_with(cyrillic) {
                output.push_str(latin);
                index += cyrillic.len();
                matched = true;
                break;
            }
        }

        if !matched {
            if let Some(ch) = text[index..].chars().next() {
                output.push(ch);
                index += ch.len_utf8();
            } else {
                break;
            }
        }
    }

    output
}