mirror of
https://github.com/storytold/craft-launcher.git
synced 2026-11-14 14:12:50 +00:00
Settings: list the languages alphabetically by their own name (#720)
- English stays first as the source language and fallback; the rest sort by native name with accents folded, so Čeština is under C and Magyar under M; Cyrillic and CJK names follow the Latin ones - Lang::for_picker holds the order; the picker used the registry order, which is the order the languages were added
This commit is contained in:
1 parent
16285cd62e
commit
f58b237275
3 files changed
+49
-2
No files matched your search
@@ -275,6 +275,17 @@ impl Lang {
|
||||
LANGUAGES.iter().map(Lang)
|
||||
}
|
||||
|
||||
/// Every registered language in the order the Settings picker lists them: English first
|
||||
/// (the source language and the fallback), then the rest by their own name with accents
|
||||
/// folded, so Čeština sits under C rather than after Z. Names in other scripts follow the
|
||||
/// Latin ones in code point order: Cyrillic, then the CJK languages. The order follows the
|
||||
/// native name even where the picker shows a CJK language's English name instead.
|
||||
pub fn for_picker() -> Vec<Lang> {
|
||||
let mut rest: Vec<Lang> = Lang::all().filter(|l| l.code() != "en").collect();
|
||||
rest.sort_by_cached_key(|l| name_sort_key(l.name()));
|
||||
std::iter::once(Lang::EN).chain(rest).collect()
|
||||
}
|
||||
|
||||
pub fn name(self) -> &'static str {
|
||||
self.0.name
|
||||
}
|
||||
@@ -355,3 +366,24 @@ fn chinese(tag: &str) -> Option<Lang> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// `name` lowercased with the Latin accents that occur in language names folded away, so a
|
||||
/// byte-wise sort reads alphabetically. Other scripts are left as they are.
|
||||
pub(super) fn name_sort_key(name: &str) -> String {
|
||||
name.chars()
|
||||
.flat_map(char::to_lowercase)
|
||||
.map(|c| match c {
|
||||
'à'..='å' | 'ā' | 'ă' | 'ą' => 'a',
|
||||
'ç' | 'ć' | 'č' => 'c',
|
||||
'è'..='ë' | 'ē' | 'ě' | 'ę' | 'ế' | 'ệ' => 'e',
|
||||
'ì'..='ï' | 'ī' => 'i',
|
||||
'ñ' | 'ń' | 'ň' => 'n',
|
||||
'ò'..='ö' | 'ø' | 'ő' => 'o',
|
||||
'ś' | 'š' => 's',
|
||||
'ù'..='ü' | 'ū' | 'ů' | 'ű' => 'u',
|
||||
'ý' | 'ÿ' => 'y',
|
||||
'ź' | 'ż' | 'ž' => 'z',
|
||||
c => c,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
use std::collections::{BTreeSet, HashSet};
|
||||
|
||||
use super::catalog::{Catalog, unescape};
|
||||
use super::lang::{plural_czech, plural_east_slavic, plural_polish};
|
||||
use super::lang::{name_sort_key, plural_czech, plural_east_slavic, plural_polish};
|
||||
use super::{LANGUAGES, Lang, LangInfo, lang_from_tag, message, tr, trn};
|
||||
|
||||
/// Each catalog's rows as (line number, context, source, translation), split exactly as the
|
||||
@@ -547,3 +547,18 @@ fn complete_catalogs_translate_package_formats() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picker_lists_english_first_then_names_alphabetically() {
|
||||
let order = Lang::for_picker();
|
||||
assert_eq!(order.first().map(|l| l.code()), Some("en"));
|
||||
assert_eq!(order.len(), Lang::all().count());
|
||||
let keys: Vec<String> = order[1..].iter().map(|l| name_sort_key(l.name())).collect();
|
||||
assert!(keys.windows(2).all(|w| w[0] <= w[1]), "{keys:?}");
|
||||
let pos = |code: &str| order.iter().position(|l| l.code() == code).unwrap_or_else(|| panic!("{code} registered"));
|
||||
assert!(pos("cs") < pos("de"), "Čeština sorts under C, not after Z");
|
||||
assert!(pos("fr") < pos("hu"), "Magyar sorts under M, not under its code");
|
||||
assert!(pos("pt-BR") < pos("ru"), "Latin names come before Cyrillic");
|
||||
assert!(pos("ru") < pos("ja"), "Cyrillic names come before CJK");
|
||||
assert_eq!(name_sort_key("Čeština"), "cestina");
|
||||
}
|
||||
@@ -123,7 +123,7 @@ impl LauncherUi {
|
||||
let width = ui.available_width();
|
||||
egui::ComboBox::from_id_salt("language").selected_text(Settings::language_label(&lang_code, installed)).width(width).show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut lang_code, Settings::LANGUAGE_AUTO.to_string(), tl!("Auto"));
|
||||
for lang in crate::i18n::Lang::all() {
|
||||
for lang in crate::i18n::Lang::for_picker() {
|
||||
ui.selectable_value(&mut lang_code, lang.code().to_string(), Settings::language_label(lang.code(), installed));
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user