A GTK application that tests out several different ICU apis
This commit is contained in:
commit
b022153a68
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
.direnv
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "locale"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
adw = { version = "0.4", package = "libadwaita", features = ["v1_2"] }
|
||||
gio = "0.18.3"
|
||||
gtk = { version = "0.6", package = "gtk4" }
|
||||
icu = { version = "1.4.0", features = ["experimental"] }
|
||||
icu_provider = "1.4.0"
|
||||
icu_locid = "1.4.0"
|
||||
libc = "0.2.150"
|
||||
chrono = "*"
|
||||
|
||||
[build-dependencies]
|
||||
glib-build-tools = "0.16"
|
|
@ -0,0 +1,7 @@
|
|||
fn main() {
|
||||
glib_build_tools::compile_resources(
|
||||
"resources",
|
||||
"resources/gresources.xml",
|
||||
"com.luminescent-dreams.locale.gresource",
|
||||
);
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
{
|
||||
"nodes": {
|
||||
"cargo2nix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1699033427,
|
||||
"narHash": "sha256-OVtd5IPbb4NvHibN+QvMrMxq7aZN5GFoINZSAXKjUdA=",
|
||||
"owner": "cargo2nix",
|
||||
"repo": "cargo2nix",
|
||||
"rev": "c6f33051f412352f293e738cc8da6fd4c457080f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cargo2nix",
|
||||
"repo": "cargo2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1697382362,
|
||||
"narHash": "sha256-PvFjWFmSYOF6TjNZ/WjOeqa+sgaWm+83Fz37vEuATHA=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ad9a253a0d34f313707f9c25fb8c95c65b1c8882",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "release-23.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1699099776,
|
||||
"narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"cargo2nix": "cargo2nix",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"cargo2nix",
|
||||
"flake-utils"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"cargo2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1697336027,
|
||||
"narHash": "sha256-ctmmw7j4liyfSh63v9rdFZeIoNYCkCvgqvtEOB7KhX8=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "e494404d36a41247987eeb1bfc2f1ca903e97764",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
description = "POSIX locale testing";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
cargo2nix.url = "github:cargo2nix/cargo2nix";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, cargo2nix, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
c2n = import cargo2nix { inherit system; };
|
||||
in {
|
||||
devShells.default = pkgs.mkShell {
|
||||
name = "locale-devshell";
|
||||
buildInputs = [
|
||||
# c2n.cargo2nix
|
||||
pkgs.gtk4
|
||||
pkgs.gtkd
|
||||
pkgs.libadwaita
|
||||
pkgs.pkg-config
|
||||
pkgs.rustup
|
||||
];
|
||||
};
|
||||
|
||||
packages.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
|
||||
|
||||
packages.default = self.packages.x86_64-linux.hello;
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
</gresources>
|
|
@ -0,0 +1,2 @@
|
|||
[toolchain]
|
||||
channel = "1.73.0"
|
|
@ -0,0 +1,317 @@
|
|||
use chrono::{Datelike, Local, Timelike};
|
||||
use gtk::prelude::*;
|
||||
use icu::{
|
||||
calendar::{
|
||||
types::{IsoHour, IsoMinute, IsoSecond, NanoSecond, Time},
|
||||
Date, DateTime,
|
||||
},
|
||||
datetime::{
|
||||
options::length::{self, Bag},
|
||||
DateTimeFormatter,
|
||||
},
|
||||
locid::locale,
|
||||
};
|
||||
use icu_locid::Locale;
|
||||
use icu_provider::DataLocale;
|
||||
use libc::{self, LC_MESSAGES, LC_TIME};
|
||||
use std::{
|
||||
env,
|
||||
ffi::{CStr, CString},
|
||||
sync::{Arc, RwLock},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
fn get_langinfo(value: libc::nl_item) -> String {
|
||||
unsafe {
|
||||
let r = libc::nl_langinfo(value);
|
||||
CStr::from_ptr(r).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
trait ProvidesLocale {
|
||||
fn language(&self) -> String;
|
||||
fn time(&self) -> String;
|
||||
// fn date_time_fmt(&self) -> String;
|
||||
}
|
||||
|
||||
struct Linux {}
|
||||
|
||||
impl ProvidesLocale for Linux {
|
||||
fn language(&self) -> String {
|
||||
unsafe {
|
||||
let locale_param = CString::new("").unwrap();
|
||||
let lc_c = libc::setlocale(LC_MESSAGES, locale_param.as_ptr());
|
||||
CStr::from_ptr(lc_c).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
fn time(&self) -> String {
|
||||
unsafe {
|
||||
let locale_param = CString::new("").unwrap();
|
||||
let lc_c = libc::setlocale(LC_TIME, locale_param.as_ptr());
|
||||
CStr::from_ptr(lc_c).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
/*
|
||||
fn date_time_fmt(&self) -> String {
|
||||
unsafe {
|
||||
let r = libc::nl_langinfo(LC_TIME);
|
||||
CStr::from_ptr(r).to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
fn create_label(name: &str, value: &str) -> gtk::Widget {
|
||||
let name = gtk::Label::builder()
|
||||
.justify(gtk::Justification::Left)
|
||||
.label(name)
|
||||
.halign(gtk::Align::Start)
|
||||
.build();
|
||||
let value = gtk::Label::builder()
|
||||
.justify(gtk::Justification::Left)
|
||||
.label(value)
|
||||
.halign(gtk::Align::Start)
|
||||
.build();
|
||||
let layout = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.homogeneous(true)
|
||||
.build();
|
||||
layout.append(&name);
|
||||
layout.append(&value);
|
||||
layout.upcast::<gtk::Widget>()
|
||||
}
|
||||
|
||||
fn render_data() -> gtk::Box {
|
||||
let provider = Linux {};
|
||||
|
||||
let layout = gtk::Box::builder()
|
||||
.halign(gtk::Align::Start)
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(8)
|
||||
.homogeneous(true)
|
||||
.build();
|
||||
|
||||
layout.append(
|
||||
>k::Label::builder()
|
||||
.justify(gtk::Justification::Left)
|
||||
.label(format!("{:?}", Instant::now()))
|
||||
.build(),
|
||||
);
|
||||
|
||||
layout.append(&create_label("Language", &provider.language()));
|
||||
layout.append(&create_label("Time", &provider.time()));
|
||||
|
||||
/* let time_locale = provider.language().parse::<Locale>().unwrap();*/
|
||||
|
||||
let now = chrono::Utc::now();
|
||||
let now: icu::calendar::DateTime<icu::calendar::Gregorian> = icu::calendar::DateTime::new(
|
||||
Date::try_new_gregorian_date(now.year() as i32, now.month() as u8, now.day() as u8)
|
||||
.unwrap(),
|
||||
Time::new(
|
||||
IsoHour::try_from(now.hour() as u8).unwrap(),
|
||||
IsoMinute::try_from(now.minute() as u8).unwrap(),
|
||||
IsoSecond::try_from(now.second() as u8).unwrap(),
|
||||
NanoSecond::try_from(0 as u32).unwrap(),
|
||||
),
|
||||
);
|
||||
|
||||
let locales = ["en-US", "eo", "de-DE", "fr-FR", "es-ES", "zh-CN", "ja-JA"];
|
||||
let styles: Vec<(String, Locale, Bag)> = locales
|
||||
.into_iter()
|
||||
.map(|locale| {
|
||||
let lc = locale.parse::<Locale>().unwrap();
|
||||
vec![
|
||||
(
|
||||
format!("{}, full date", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_date_style(length::Date::Full).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, long date", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_date_style(length::Date::Long).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, medium date", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_date_style(length::Date::Medium).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, short date", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_date_style(length::Date::Short).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, full time", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_time_style(length::Time::Full).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, long time", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_time_style(length::Time::Long).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, medium time", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_time_style(length::Time::Medium).into(),
|
||||
),
|
||||
(
|
||||
format!("{}, short time", locale),
|
||||
lc.clone(),
|
||||
length::Bag::from_time_style(length::Time::Short).into(),
|
||||
),
|
||||
]
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
for (descriptor, locale, bag) in styles {
|
||||
let formatter = DateTimeFormatter::try_new(&DataLocale::from(locale), bag.into());
|
||||
|
||||
match formatter {
|
||||
Ok(formatter) => layout.append(&create_label(
|
||||
&descriptor,
|
||||
&formatter.format_to_string(&now.to_any()).unwrap(),
|
||||
)),
|
||||
Err(formatter_err) => layout.append(&create_label(
|
||||
&descriptor,
|
||||
&format!("unhandled formatter: {:?}", formatter_err),
|
||||
)),
|
||||
}
|
||||
}
|
||||
/*
|
||||
layout.append(&create_label(
|
||||
"formatted date and time",
|
||||
dt_fmt.format_to_string(DateTime::try_new_iso_datetime(2023, 10, 13, 3, 28, 0).unwrap()),
|
||||
))
|
||||
*/
|
||||
|
||||
/*
|
||||
layout.append(&create_label(
|
||||
"date and time format",
|
||||
&provider.date_time_fmt(),
|
||||
));
|
||||
*/
|
||||
|
||||
layout.append(&create_label(
|
||||
"codeset",
|
||||
get_langinfo(libc::CODESET).as_ref(),
|
||||
));
|
||||
layout.append(&create_label(
|
||||
"d_t_fmt",
|
||||
get_langinfo(libc::D_T_FMT).as_ref(),
|
||||
));
|
||||
layout.append(&create_label("d_fmt", get_langinfo(libc::D_FMT).as_ref()));
|
||||
layout.append(&create_label("t_fmt", get_langinfo(libc::T_FMT).as_ref()));
|
||||
layout.append(&create_label("am_str", get_langinfo(libc::AM_STR).as_ref()));
|
||||
layout.append(&create_label("pm_str", get_langinfo(libc::PM_STR).as_ref()));
|
||||
layout.append(&create_label(
|
||||
"t_fmt_ampm",
|
||||
get_langinfo(libc::T_FMT_AMPM).as_ref(),
|
||||
));
|
||||
layout.append(&create_label("era", get_langinfo(libc::ERA).as_ref()));
|
||||
layout.append(&create_label(
|
||||
"era_d_t_fmt",
|
||||
get_langinfo(libc::ERA_D_T_FMT).as_ref(),
|
||||
));
|
||||
layout.append(&create_label(
|
||||
"era_d_fmt",
|
||||
get_langinfo(libc::ERA_D_FMT).as_ref(),
|
||||
));
|
||||
layout.append(&create_label(
|
||||
"era_t_fmt",
|
||||
get_langinfo(libc::ERA_T_FMT).as_ref(),
|
||||
));
|
||||
layout.append(&create_label("%c", &Local::now().format("%c").to_string()));
|
||||
layout.append(&create_label("%x", &Local::now().format("%c").to_string()));
|
||||
layout.append(&create_label("%X", &Local::now().format("%c").to_string()));
|
||||
/*
|
||||
layout.append(&create_label("day_1", get_langinfo(libc::DAY_1).as_ref()));
|
||||
layout.append(&create_label(
|
||||
"abday_1",
|
||||
get_langinfo(libc::ABDAY_1).as_ref(),
|
||||
));
|
||||
layout.append(&create_label("mon_1", get_langinfo(libc::MON_1).as_ref()));
|
||||
layout.append(&create_label(
|
||||
"abmon_1",
|
||||
get_langinfo(libc::ABMON_1).as_ref(),
|
||||
));
|
||||
layout.append(&create_label(
|
||||
"radixchar",
|
||||
get_langinfo(libc::RADIXCHAR).as_ref(),
|
||||
));
|
||||
layout.append(&create_label(
|
||||
"thousep",
|
||||
get_langinfo(libc::THOUSEP).as_ref(),
|
||||
));
|
||||
layout.append(&create_label(
|
||||
"yesexpr",
|
||||
get_langinfo(libc::YESEXPR).as_ref(),
|
||||
));
|
||||
layout.append(&create_label("noexpr", get_langinfo(libc::NOEXPR).as_ref()));
|
||||
layout.append(&create_label(
|
||||
"crncystr",
|
||||
get_langinfo(libc::CRNCYSTR).as_ref(),
|
||||
));
|
||||
*/
|
||||
|
||||
layout
|
||||
}
|
||||
|
||||
fn main() {
|
||||
gio::resources_register_include!("com.luminescent-dreams.locale.gresource")
|
||||
.expect("failed to register resources");
|
||||
|
||||
let app = gtk::Application::builder()
|
||||
.application_id("com.luminescent-dreams.locale")
|
||||
.resource_base_path("/com/luminescent-dreams/dashboard")
|
||||
.build();
|
||||
|
||||
app.connect_activate(move |app| {
|
||||
let window = gtk::ApplicationWindow::new(app);
|
||||
|
||||
let layout = gtk::Box::builder()
|
||||
.halign(gtk::Align::Start)
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(8)
|
||||
.build();
|
||||
|
||||
let menubar = gtk::Box::builder()
|
||||
.halign(gtk::Align::End)
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.spacing(8)
|
||||
.build();
|
||||
|
||||
let refresh_button = gtk::Button::builder().label("Refresh").build();
|
||||
menubar.append(&refresh_button);
|
||||
|
||||
let data_layout = Arc::new(RwLock::new(render_data()));
|
||||
|
||||
layout.append(&menubar);
|
||||
layout.append(&*data_layout.read().unwrap());
|
||||
|
||||
refresh_button.connect_clicked({
|
||||
let layout = layout.clone();
|
||||
let data_layout = data_layout.clone();
|
||||
move |_| {
|
||||
layout.remove(&*data_layout.read().unwrap());
|
||||
let new_layout = render_data();
|
||||
*data_layout.write().unwrap() = new_layout;
|
||||
layout.append(&*data_layout.read().unwrap());
|
||||
}
|
||||
});
|
||||
|
||||
window.set_child(Some(&layout));
|
||||
|
||||
window.present();
|
||||
});
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
ApplicationExtManual::run_with_args(&app, &args);
|
||||
}
|
||||
|
||||
/*
|
||||
println!("locale: {}", get_locale(libc::LC_ALL));
|
||||
|
||||
*/
|
Loading…
Reference in New Issue