///|
fn is_language_subtag(segment : String) -> Bool {
let length = segment.length()
length >= 2 && length <= 3 && segment.all(char => char.is_ascii_alphabetic())
}
///|
fn is_locale_subtag(segment : String) -> Bool {
let length = segment.length()
length >= 2 &&
length <= 8 &&
segment.all(char => char.is_ascii_alphabetic() || char.is_ascii_digit())
}
///|
fn is_locale_tag(input : String) -> Bool {
let segments : Array[String] = input
.split("-")
.map(segment => segment.to_owned())
.collect()
guard segments is [language, .. rest] else { return false }
is_language_subtag(language) && rest.all(is_locale_subtag)
}
///|
fn normalize_locale(input : String) -> String raise {
guard is_locale_tag(input) else { fail("invalid language code: \{input}") }
input.to_lower()
}
///|
fn extension_start(path : String) -> Int? {
if path.has_suffix(".mbt.md") {
Some(path.length() - ".mbt.md".length())
} else {
match path.rev_find(".") {
Some(index) =>
match path.rev_find("/") {
Some(slash) if index < slash => None
_ => Some(index)
}
None => None
}
}
}
///|
fn strip_locale_tag(path : @path.Path) -> @path.Path {
let text = path.to_string()
guard extension_start(text) is Some(extension) else { return path }
let stem = text[:extension].to_owned()
guard stem.rev_find(".") is Some(tag_start) else { return path }
let tag = stem[tag_start + 1:].to_owned()
if is_locale_tag(tag) {
@path.Path(stem[:tag_start].to_owned() + text[extension:].to_owned())
} else {
path
}
}
///|
fn target_path(file : @path.Path, lang : String) -> @path.Path {
let stripped = strip_locale_tag(file).to_string()
match extension_start(stripped) {
Some(index) =>
@path.Path(
stripped[:index].to_owned() + "." + lang + stripped[index:].to_owned(),
)
None => @path.Path(stripped + "." + lang)
}
}