Add a configuration file

This commit is contained in:
Savanni D'Gerinel 2025-02-22 18:39:32 -05:00
parent 1c3d0711e1
commit 200c13a14e
8 changed files with 99 additions and 23 deletions

View File

@ -9,6 +9,7 @@ clap = { version = "4.5.30", features = ["derive"] }
icu_locid = { version = "1.5.0", features = ["serde"] } icu_locid = { version = "1.5.0", features = ["serde"] }
serde = { version = "1.0.218", features = ["derive"] } serde = { version = "1.0.218", features = ["derive"] }
tempfile = "3.17.1" tempfile = "3.17.1"
thiserror = "2.0.11"
toml = "0.8.20" toml = "0.8.20"
# [lib] # [lib]

8
l10n-db/config.toml Normal file
View File

@ -0,0 +1,8 @@
db_path = "./i18n"
base_locale = "en"
locales = [
"en",
"eo",
"de",
"es",
]

View File

@ -1,7 +1,12 @@
key = "OpenSandbox" key = "OpenSandbox"
description = "A sandbox vault refers to a stock vault that contains test data and allows the user to make edits and run experiments on test data." description = "A sandbox vault refers to a stock vault that contains test data and allows the user to make edits and run experiments on test data."
[variants.en-US] [variants.eo]
locale = "en-US" locale = "eo"
content = "Malfermi sekurkofro"
modified = "2025-02-22T23:35:29.692299091Z"
[variants.en]
locale = "en"
content = "Open Sandbox vault" content = "Open Sandbox vault"
modified = "2025-02-22T21:35:02.032300406Z" modified = "2025-02-22T21:35:02.032300406Z"

View File

@ -1,9 +1,14 @@
use std::{io::{BufReader, Read, Write}, path::PathBuf, process::Command}; use std::{
io::{BufReader, Read, Write},
path::PathBuf,
process::Command,
};
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use icu_locid::{langid, LanguageIdentifier}; use icu_locid::{langid, LanguageIdentifier};
use l10n_db::{self, Bundle, Editor}; use l10n_db::{self, read_file, Bundle, Editor, ReadError};
use serde::Deserialize;
#[derive(Parser)] #[derive(Parser)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@ -15,7 +20,12 @@ struct Cli {
#[derive(Subcommand)] #[derive(Subcommand)]
enum Commands { enum Commands {
/// Edit, potentially creating, a key /// Edit, potentially creating, a key
EditKey { name: String, locale: String }, EditKey {
#[arg(short, long)]
name: String,
#[arg(short, long)]
locale: String,
},
/// List al keys in the database /// List al keys in the database
ListKeys, ListKeys,
// Search the database // Search the database
@ -25,10 +35,17 @@ enum Commands {
#[arg(short, long)] #[arg(short, long)]
format: String, format: String,
#[arg(short, long)] #[arg(short, long)]
locale: String locale: String,
}, },
} }
#[derive(Debug, Deserialize)]
struct Config {
db_path: PathBuf,
base_locale: LanguageIdentifier,
locales: Vec<LanguageIdentifier>,
}
fn edit_key(bundle: &mut Bundle, key: String, locale: LanguageIdentifier, editor: &str) { fn edit_key(bundle: &mut Bundle, key: String, locale: LanguageIdentifier, editor: &str) {
let message = bundle.message(key); let message = bundle.message(key);
Editor::edit(message, locale, editor); Editor::edit(message, locale, editor);
@ -36,21 +53,28 @@ fn edit_key(bundle: &mut Bundle, key: String, locale: LanguageIdentifier, editor
} }
fn main() { fn main() {
let editor = std::env::var("EDITOR").unwrap(); let editor = std::env::var("EDITOR").expect("Set EDITOR to the path to your favorite editor");
let db_path = std::env::var("DB_PATH").unwrap();
let config: Config = read_file(&PathBuf::from("./config.toml"))
.and_then(|bytes| String::from_utf8(bytes).map_err(|_| ReadError::InvalidFormat))
.and_then(|content| toml::from_str(&content).map_err(|_| ReadError::InvalidFormat))
.unwrap();
let cli = Cli::parse(); let cli = Cli::parse();
let mut bundle = Bundle::load_from_disk(PathBuf::from(&db_path)); let mut bundle = Bundle::load_from_disk(PathBuf::from(&config.db_path));
match &cli.command { match &cli.command {
Some(Commands::EditKey{ name, locale } ) => edit_key(&mut bundle, name.to_owned(), langid!("en-US"), &editor), Some(Commands::EditKey { name, locale }) => {
let identifier = locale.parse::<LanguageIdentifier>().unwrap();
edit_key(&mut bundle, name.to_owned(), identifier, &editor)
}
Some(Commands::ListKeys) => { Some(Commands::ListKeys) => {
for (key, _) in bundle.message_iter() { for (key, _) in bundle.message_iter() {
println!("{}", key); println!("{}", key);
} }
}, }
Some(Commands::Export{..}) => todo!(), Some(Commands::Export { .. }) => todo!(),
None => {}, None => {}
} }
} }

View File

@ -1,17 +1,19 @@
use std::{io::{BufReader, Read, Write}, path::Path, process::Command}; use std::{io::{BufReader, Read, Write}, path::Path, process::Command};
use icu_locid::LanguageIdentifier; use icu_locid::{langid, LanguageIdentifier};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Message, Variant}; use crate::{read_fh, Message, Variant};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
struct EditorMessage { struct EditorMessage {
description: String, description: String,
source: String,
content: String, content: String,
} }
/*
impl EditorMessage { impl EditorMessage {
fn from_variant(description: String, variant: &Variant) -> Self { fn from_variant(description: String, variant: &Variant) -> Self {
Self { Self {
@ -20,6 +22,7 @@ impl EditorMessage {
} }
} }
} }
*/
pub struct Editor { pub struct Editor {
} }
@ -27,8 +30,14 @@ pub struct Editor {
impl Editor { impl Editor {
pub fn edit(msg: &mut Message, locale: LanguageIdentifier, editor: &str) { pub fn edit(msg: &mut Message, locale: LanguageIdentifier, editor: &str) {
let description = msg.description().to_owned(); let description = msg.description().to_owned();
let source_string = msg.variant_mut(langid!("en")).content().to_owned();
let variant = msg.variant_mut(locale); let variant = msg.variant_mut(locale);
let editable_content = EditorMessage::from_variant(description, &variant); // let editable_content = EditorMessage::from_variant(description, &variant);
let editable_content = EditorMessage {
description,
source: source_string,
content: variant.content().to_owned(),
};
let mut file = tempfile::NamedTempFile::new().unwrap(); let mut file = tempfile::NamedTempFile::new().unwrap();
let _ = file.write(toml::to_string(&editable_content).unwrap().as_bytes()); let _ = file.write(toml::to_string(&editable_content).unwrap().as_bytes());
@ -36,12 +45,7 @@ impl Editor {
let mut cmd = Command::new(editor).args([file.path()]).spawn().unwrap(); let mut cmd = Command::new(editor).args([file.path()]).spawn().unwrap();
cmd.wait().unwrap(); cmd.wait().unwrap();
let file = file.reopen().unwrap(); let file = file.reopen().unwrap();
let mut reader = BufReader::new(file); let content = read_fh(&file).unwrap();
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(); let new_variant: EditorMessage = toml::from_str(&String::from_utf8(content).unwrap()).unwrap();

View File

@ -7,6 +7,9 @@ pub use editor::Editor;
mod types; mod types;
pub use types::{Message, Variant}; pub use types::{Message, Variant};
mod utils;
pub use utils::*;
/* /*
#[cfg(test)] #[cfg(test)]
mod test { mod test {

View File

@ -45,7 +45,7 @@ impl Message {
} }
} }
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Variant { pub struct Variant {
locale: LanguageIdentifier, locale: LanguageIdentifier,
content: String, content: String,

31
l10n-db/src/utils.rs Normal file
View File

@ -0,0 +1,31 @@
use std::{fs::File, io::{BufReader, ErrorKind, Read}, path::Path};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ReadError {
#[error("file not found")]
FileNotFound,
#[error("invalid file format")]
InvalidFormat,
#[error("unhandled read error")]
Unhandled(ErrorKind),
}
pub fn read_file(path: &Path) -> Result<Vec<u8>, ReadError> {
let file = File::open(path).map_err(|err| {
match err.kind() {
ErrorKind::NotFound => ReadError::FileNotFound,
_ => ReadError::Unhandled( err.kind()),
}
})?;
read_fh(&file)
}
pub fn read_fh(file: &File) -> Result<Vec<u8>, ReadError> {
let mut content = Vec::new();
let mut reader = BufReader::new(file);
reader.read_to_end(&mut content).map_err(|err| ReadError::Unhandled(err.kind()))?;
Ok(content)
}