Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
e16fef2b14 | |||
e0392a4150 | |||
359ab96779 |
630
Cargo.lock
generated
630
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -33,4 +33,4 @@ members = [
|
||||
"tree",
|
||||
"visions/server",
|
||||
"gm-dash/server"
|
||||
]
|
||||
, "l10n-db"]
|
||||
|
20
l10n-db/Cargo.toml
Normal file
20
l10n-db/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
name = "l10n-db"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.30", features = ["derive"] }
|
||||
icu_locid = { version = "1.5.0", features = ["serde"] }
|
||||
serde = { version = "1.0.218", features = ["derive"] }
|
||||
tempfile = "3.17.1"
|
||||
toml = "0.8.20"
|
||||
|
||||
# [lib]
|
||||
# name = "l10n_db"
|
||||
# path = "src/lib.rs"
|
||||
#
|
||||
# [[bin]]
|
||||
# name = "l10n-db"
|
||||
# path = "src/main.rs"
|
||||
|
7
l10n-db/i18n/OpenSandbox.toml
Normal file
7
l10n-db/i18n/OpenSandbox.toml
Normal file
@ -0,0 +1,7 @@
|
||||
key = "OpenSandbox"
|
||||
description = "a basic description without any content"
|
||||
|
||||
[variants.en-US]
|
||||
locale = "en-US"
|
||||
content = ""
|
||||
modified = 1740241312
|
79
l10n-db/src/bin/main.rs
Normal file
79
l10n-db/src/bin/main.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use std::{io::{BufReader, Read, Write}, path::PathBuf, process::Command};
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use icu_locid::{langid, LanguageIdentifier};
|
||||
use l10n_db::{self, Bundle, Editor};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Edit, potentially creating, a key
|
||||
EditKey { name: String, locale: String },
|
||||
/// List al keys in the database
|
||||
ListKeys,
|
||||
// Search the database
|
||||
// Search { },
|
||||
/// Export the database
|
||||
Export {
|
||||
#[arg(short, long)]
|
||||
format: String,
|
||||
#[arg(short, long)]
|
||||
locale: String
|
||||
},
|
||||
}
|
||||
|
||||
fn edit_key(bundle: &mut Bundle, key: String, locale: LanguageIdentifier, editor: &str) {
|
||||
let message = bundle.message(key);
|
||||
|
||||
Editor::edit(message, locale, editor);
|
||||
|
||||
println!("final version");
|
||||
println!("{}", toml::to_string(&message).unwrap());
|
||||
|
||||
/*
|
||||
let mut editor_file = tempfile::NamedTempFile::new().unwrap();
|
||||
let _ = editor_file.write(toml::to_string(message).unwrap().as_bytes());
|
||||
let _ = editor_file.flush();
|
||||
let mut cmd = Command::new(editor).args([editor_file.path()]).spawn().unwrap();
|
||||
cmd.wait().unwrap();
|
||||
let _ = editor_file.flush();
|
||||
let mut reader = BufReader::new(editor_file);
|
||||
let mut content = Vec::new();
|
||||
let _ = reader.read_to_end(&mut content);
|
||||
|
||||
println!("content");
|
||||
println!("{}", String::from_utf8(content).unwrap());
|
||||
|
||||
|
||||
println!("message: {:?}", message);
|
||||
|
||||
message.set_description("Open a sandbox".to_owned());
|
||||
let variant = message.variant_mut(langid!("en-US"));
|
||||
variant.set_content("Open a sandbox vault".to_owned());
|
||||
*/
|
||||
|
||||
bundle.save();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let editor = std::env::var("EDITOR").unwrap();
|
||||
let db_path = std::env::var("DB_PATH").unwrap();
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
let mut bundle = Bundle::load_from_disk(PathBuf::from(&db_path));
|
||||
|
||||
match &cli.command {
|
||||
Some(Commands::EditKey{ name, locale } ) => edit_key(&mut bundle, name.to_owned(), langid!("en-US"), &editor),
|
||||
Some(Commands::ListKeys) => todo!(),
|
||||
Some(Commands::Export{..}) => todo!(),
|
||||
None => {},
|
||||
}
|
||||
}
|
40
l10n-db/src/bundle.rs
Normal file
40
l10n-db/src/bundle.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use std::{collections::HashMap, fs::File, io::Write, path::PathBuf};
|
||||
|
||||
use crate::Message;
|
||||
|
||||
pub struct Bundle {
|
||||
path: PathBuf,
|
||||
messages: HashMap<String, Message>,
|
||||
}
|
||||
|
||||
impl Bundle {
|
||||
pub fn load_from_disk(path: PathBuf) -> Self {
|
||||
Self {
|
||||
path,
|
||||
messages: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn message(&mut self, name: String) -> &mut Message {
|
||||
self.messages
|
||||
.entry(name.to_owned())
|
||||
.or_insert(Message::new(name.to_owned()))
|
||||
}
|
||||
|
||||
pub fn save(&self) {
|
||||
self.messages.iter().for_each(|(key, value)| {
|
||||
let mut path = self.path.clone();
|
||||
path.push(key);
|
||||
path.set_extension("toml");
|
||||
save_file(&path, toml::to_string(value).unwrap().as_bytes());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn save_file(path: &PathBuf, s: &[u8]) {
|
||||
let mut f = File::create(path).unwrap();
|
||||
f.write(s).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {}
|
52
l10n-db/src/editor.rs
Normal file
52
l10n-db/src/editor.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use std::{io::{BufReader, Read, Write}, path::Path, process::Command};
|
||||
|
||||
use icu_locid::LanguageIdentifier;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Message, Variant};
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
struct EditorMessage {
|
||||
description: String,
|
||||
content: String,
|
||||
}
|
||||
|
||||
impl EditorMessage {
|
||||
fn from_variant(description: String, variant: &Variant) -> Self {
|
||||
Self {
|
||||
description,
|
||||
content: variant.content().to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Editor {
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
pub fn edit(msg: &mut Message, locale: LanguageIdentifier, editor: &str) {
|
||||
let description = msg.description().to_owned();
|
||||
let variant = msg.variant_mut(locale);
|
||||
let editable_content = EditorMessage::from_variant(description, &variant);
|
||||
|
||||
let mut file = tempfile::NamedTempFile::new().unwrap();
|
||||
let _ = file.write(toml::to_string(&editable_content).unwrap().as_bytes());
|
||||
let _ = file.flush();
|
||||
let mut cmd = Command::new(editor).args([file.path()]).spawn().unwrap();
|
||||
cmd.wait().unwrap();
|
||||
let file = file.reopen().unwrap();
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut content = Vec::new();
|
||||
let _ = reader.read_to_end(&mut content);
|
||||
|
||||
println!("content");
|
||||
println!("{}", String::from_utf8(content.clone()).unwrap());
|
||||
|
||||
let new_variant: EditorMessage = toml::from_str(&String::from_utf8(content).unwrap()).unwrap();
|
||||
|
||||
variant.set_content(new_variant.content);
|
||||
msg.set_description(new_variant.description);
|
||||
}
|
||||
}
|
||||
|
23
l10n-db/src/lib.rs
Normal file
23
l10n-db/src/lib.rs
Normal file
@ -0,0 +1,23 @@
|
||||
mod bundle;
|
||||
pub use bundle::Bundle;
|
||||
|
||||
mod editor;
|
||||
pub use editor::Editor;
|
||||
|
||||
mod types;
|
||||
pub use types::{Message, Variant};
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn it_can_represent_an_untranslated_message() {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_can_represent_a_partially_translated_message() {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
*/
|
61
l10n-db/src/types.rs
Normal file
61
l10n-db/src/types.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use std::{collections::HashMap, time::{SystemTime, UNIX_EPOCH}};
|
||||
|
||||
use icu_locid::LanguageIdentifier;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct Message {
|
||||
key: String,
|
||||
description: String,
|
||||
variants: HashMap<LanguageIdentifier, Variant>,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub fn new(key: String) -> Self {
|
||||
Self {
|
||||
key,
|
||||
description: "".to_owned(),
|
||||
variants: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_description(&mut self, desc: String) {
|
||||
self.description = desc;
|
||||
}
|
||||
|
||||
pub fn description(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
|
||||
pub fn variant_mut(&mut self, locale: LanguageIdentifier) -> &mut Variant {
|
||||
self.variants.entry(locale.clone()).or_insert(Variant {
|
||||
locale,
|
||||
content: "".to_owned(),
|
||||
modified: SystemTime::now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct Variant {
|
||||
locale: LanguageIdentifier,
|
||||
content: String,
|
||||
#[serde(serialize_with = "time_to_number")]
|
||||
modified: SystemTime,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
pub fn content(&self) -> &str {
|
||||
&self.content
|
||||
}
|
||||
|
||||
pub fn set_content(&mut self, content: String) {
|
||||
self.content = content;
|
||||
self.modified = SystemTime::now();
|
||||
}
|
||||
}
|
||||
|
||||
fn time_to_number<S>(time: &SystemTime, s: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer {
|
||||
s.serialize_u64(time.duration_since(UNIX_EPOCH).unwrap().as_secs())
|
||||
}
|
Loading…
Reference in New Issue
Block a user