# Ukraine 🇺🇦
[](https://crates.io/crates/ukraine)
[](https://docs.rs/ukraine)
[](https://github.com/mykhailokrainik/ukraine-rs/blob/master/LICENSE)
A Rust library for transliterating Ukrainian Cyrillic text into Latin-script representations. In the hope that one day the Ukrainian Latin script will be widely adopted and the last remnants of [russian aggressive imperialism](https://war.ukraine.ua/) will be erased from the history of modern Ukraine 💙💛
## Support Ukraine
[](https://u24.gov.ua/)
## Overview
This Rust crate provides functionality for converting Ukrainian Cyrillic text into various transliteration schemes described on the [Ukrainian Latin alphabet](https://en.m.wikipedia.org/wiki/Ukrainian_Latin_alphabet) page.
Currently supports the following transliteration systems from Ukrainian Cyrillic to Latin:
- **Lozynskyi's Abecadło** — A historical Ukrainian Latin alphabet proposal
- **DSTU 9112:2021 System A and B** — Official Ukrainian standard for Cyrillic-Latin transliteration [reference](https://en.wikipedia.org/wiki/DSTU_9112:2021)
- **KMU #55 (2010)** — Ukrainian National transliteration system for romanization of geographic names. Resolution of the Cabinet of Ministers of Ukraine [reference](https://www.kmu.gov.ua/npas/243262567)
This library is implemented in **pure Rust** with **zero dependencies** and **no regex**. All transliteration logic is built from scratch using native Rust string processing for maximum performance and minimal overhead.
## Features
- [x] ***Greeting:*** Say hello in various forms—formal or casual.
- [x] ***Ukrainian Transliteration:*** Convert Ukrainian text from Cyrillic to Latin script.
- [x] ***Number Conversion:*** Convert numbers into Ukrainian words.
- [x] ***Ordinal Number Conversion:*** Convert integers into Ukrainian ordinal words.
- [x] ***Date and Time Conversion:*** Format dates and times according to Ukrainian standards.
- [ ] ***Counting Endings:*** Properly display singular and plural forms.
- [ ] ***Feminization:*** Convert masculine forms to feminine forms and vice versa.
- [ ] ***Currency Formatting:*** Convert numerical currency values into Ukrainian words.
- [ ] ***Name generation:*** Generate placeholder names for persons, cities, and companies.
- [ ] ***Address Conversion:*** Convert addresses to Ukrainian standards.
- [ ] ***Phone Number Formatting:*** Convert phone numbers to Ukrainian standards.
## Installation
Add the following line to your `Cargo.toml` dependencies:
```toml
[dependencies]
ukraine = "2"
```
## Examples
### Say "Hello" in Ukrainian
```rust
// ukraine = { version = "2", default-features = false, features = ["greeting"] }
use ukraine::greeting::vitayu;
fn main() {
println!("{}", vitayu()); // Вітаю
}
```
### DSTU 9112:2021 System A (ДСТУ 9112:2021)
Cyrillic-Latin transliteration of Ukrainian texts
[DSTU 9112](https://en.wikipedia.org/wiki/DSTU_9112:2021)
```rust
// ukraine = { version = "2", default-features = false, features = ["dstu9112a"] }
use ukraine::latin::transliterate_dstu9112a;
fn main() {
assert_eq!(transliterate_dstu9112a("Привіт"), "Pryvit");
assert_eq!(transliterate_dstu9112a("Житомир"), "Žytomyr");
assert_eq!(transliterate_dstu9112a("Запоріжжя"), "Zaporižžja");
assert_eq!(transliterate_dstu9112a("Київ"), "Kyïv");
assert_eq!(transliterate_dstu9112a("Ужгород"), "Užğorod");
assert_eq!(transliterate_dstu9112a("Черкаси"), "Čerkasy");
assert_eq!(transliterate_dstu9112a("Чернівці"), "Černivci");
assert_eq!(transliterate_dstu9112a("Чернігів"), "Černiğiv");
assert_eq!(transliterate_dstu9112a("Україна"), "Ukraïna");
}
```
### DSTU 9112:2021 System B (ДСТУ 9112:2021)
Cyrillic-Latin transliteration of Ukrainian texts
[DSTU 9112](https://en.wikipedia.org/wiki/DSTU_9112:2021)
```rust
// ukraine = { version = "2", default-features = false, features = ["dstu9112b"] }
use ukraine::latin::transliterate_dstu9112b;
fn main() {
let input = "Ще не вмерла України і слава, і воля,
Ще нам, браття молодії, усміхнеться доля.
Згинуть наші воріженьки, як роса на сонці.
Запануєм і ми, браття, у своїй сторонці.";
let expected = "Shche ne vmerla Ukrajiny i slava, i volja,
Shche nam, brattja molodiji, usmikhnetjsja dolja.
Zghynutj nashi vorizhenjku, jak rosa na sonci.
Zapanujem i my, brattja, u svojij storonci.";
assert_eq!(transliterate_dstu9112b(input), expected);
}
```
### Transliteration system approved by Cabinet of Ministers resolution #55 (2010 year)
[KMU №55](https://www.kmu.gov.ua/npas/243262567)
```rust
// ukraine = { version = "2", default-features = false, features = ["kmu55"] }
use ukraine::latin::transliterate_kmu55;
fn main() {
assert_eq!(transliterate_kmu55("Київ"), "Kyiv");
assert_eq!(transliterate_kmu55("Михайло"), "Mykhailo");
assert_eq!(transliterate_kmu55("Юрій"), "Yurii");
assert_eq!(transliterate_kmu55("Борщ"), "Borshch");
// Note 1: "зг" is rendered "zgh" wherever it occurs, so that it never
// collapses onto "zh", the rendering of "ж".
assert_eq!(transliterate_kmu55("Згорани"), "Zghorany");
assert_eq!(transliterate_kmu55("Розгон"), "Rozghon");
// A fully capitalised word stays capitalised through its last letter.
assert_eq!(transliterate_kmu55("БОРЩ"), "BORSHCH");
}
```
### Lozynskyi's abecadło
[Abecadło](https://en.wikipedia.org/wiki/Abecad%C5%82o)
```rust
// ukraine = { version = "2", default-features = false, features = ["lozynsky"] }
use ukraine::latin::transliterate_lozynsky;
fn main() {
assert_eq!(transliterate_lozynsky("❤️ Україна"), "❤️ Ukrajina");
}
```
### Convert numbers into Ukrainian words
```rust
// ukraine = { version = "2", default-features = false, features = ["numbers"] }
use ukraine::numbers::{to_ordinal_words, to_words, OrdinalGender};
fn main() {
assert_eq!(
to_words(12_345_678),
"дванадцять мільйонів триста сорок п'ять тисяч шістсот сімдесят вісім"
);
}
```
### Convert numbers into Ukrainian ordinal words
```rust
// ukraine = { version = "2", default-features = false, features = ["numbers"] }
use ukraine::numbers::{to_ordinal_words, OrdinalGender};
fn main() {
assert_eq!(to_ordinal_words(123, OrdinalGender::Feminine), "сто двадцять третя");
assert_eq!(to_ordinal_words(123, OrdinalGender::Masculine), "сто двадцять третій");
assert_eq!(to_ordinal_words(123, OrdinalGender::Neuter), "сто двадцять третє");
assert_eq!(
to_ordinal_words(21, OrdinalGender::Masculine),
"двадцять перший"
);
assert_eq!(
to_ordinal_words(45, OrdinalGender::Feminine),
"сорок п'ята"
);
// An exact multiple of a scale fuses into a single adjective,
// while a compound keeps its thousands cardinal.
assert_eq!(to_ordinal_words(2_000, OrdinalGender::Masculine), "двохтисячний");
assert_eq!(
to_ordinal_words(2_345, OrdinalGender::Masculine),
"дві тисячі триста сорок п'ятий"
);
}
```
#### New in 2.0.0
`try_to_ordinal_words` returns the ordinal words, or nothing when the number is too
large to name. `MAX_ORDINAL` is the largest value the converter accepts.
```rust
// ukraine = { version = "2", default-features = false, features = ["numbers"] }
use ukraine::numbers::{try_to_ordinal_words, MAX_ORDINAL, OrdinalGender};
fn main() {
assert_eq!(
try_to_ordinal_words(1_000_000, OrdinalGender::Neuter),
Some("мільйонне".to_string())
);
assert_eq!(MAX_ORDINAL, 999_999_999_999_999);
assert_eq!(try_to_ordinal_words(MAX_ORDINAL + 1, OrdinalGender::Masculine), None);
}
```
### Format dates and times in Ukrainian
```rust
// ukraine = { version = "2", default-features = false, features = ["datetime"] }
use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
use ukraine::datetime::{
format_date, format_datetime, format_time, DateFormatStyle, FormatOptions, TimeFormatStyle,
};
fn main() {
let independence_day = NaiveDate::from_ymd_opt(2024, 8, 24).unwrap();
let ceremony = NaiveDateTime::new(
independence_day,
NaiveTime::from_hms_opt(9, 0, 0).unwrap(),
);
// Date format
assert_eq!(
format_date(independence_day, DateFormatStyle::Long),
"24 серпня 2024 року"
);
// Full date time format
assert_eq!(
format_datetime(ceremony, FormatOptions::default()),
"24 серпня 2024 року о 09:00"
);
// 12 hours
let time = NaiveTime::from_hms_opt(8, 10, 59).unwrap();
assert_eq!(
format_time(time, TimeFormatStyle::TwelveHourNoSeconds),
"08:10 ранку"
);
// 24 hours
let time = NaiveTime::from_hms_opt(23, 59, 59).unwrap();
assert_eq!(
format_time(time, TimeFormatStyle::TwentyFourHour),
"23:59:59"
);
// 24 hours no seconds
let time = NaiveTime::from_hms_opt(23, 59, 59).unwrap();
assert_eq!(
format_time(time, TimeFormatStyle::TwentyFourHourNoSeconds),
"23:59"
);
}
```
```rust
// ukraine = { version = "2", default-features = false, features = ["numbers", "dstu9112a"] }
use ukraine::numbers::to_words;
use ukraine::latin::dstu9112a::transliterate_dstu9112a;
fn main() {
assert_eq!(
transliterate_dstu9112a(&to_words(12_345_678)),
"dvanadcjatj miljjoniv trysta sorok p’jatj tysjač šistsot simdesjat visim"
);
}
```
## Documentation
The full API documentation is available at [docs.rs/ukraine](https://docs.rs/ukraine).
## Alternative
Alternative crates for supporting DSTU 9112:2021 and KMU 55:2010: the [uklatn](https://crates.io/crates/uklatn) crate provides a solid regex-based implementation of these transliteration schemes.
## Contributing
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
## License
Licensed under the
[GNU Affero General Public License v3.0 only](https://github.com/mykhailokrainik/ukraine-rs/blob/master/LICENSE)
(`AGPL-3.0-only`).
Note for anyone upgrading: versions 1.x were `LGPL-3.0-only`. The AGPL is stricter, and
its §13 extends the obligation to offer source code to users who interact with a modified
version of this crate over a network. If that does not suit your project, pin `ukraine = "1"`
or open an issue to discuss.