add option to override locale messages per-group, update readme

This commit is contained in:
2021-10-11 13:24:17 +02:00
parent 305d91d1dc
commit 63c4c5f2e8
8 changed files with 97 additions and 47 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ pub struct ProcessMention<'a> {
impl<'a> ProcessMention<'a> {
fn tr(&self) -> &TranslationTable {
self.cc.tr(self.config.get_locale())
self.config.tr()
}
async fn lookup_acct_id(&self, acct: &str, followed: bool) -> Result<Option<String>, GroupError> {
+1 -1
View File
@@ -529,7 +529,7 @@ impl GroupHandle {
}
fn tr(&self) -> &TranslationTable {
self.cc.tr(self.config.get_locale())
self.config.tr()
}
async fn handle_new_follow(&mut self, notif_acct: &str, notif_user_id: &str) {
+2
View File
@@ -7,6 +7,7 @@ use crate::tr::TranslationTable;
pub struct CommonConfig {
pub groups_dir: String,
pub locales_dir: String,
pub validate_locales: bool,
/// Max number of missed notifs to process after connect
pub max_catchup_notifs: usize,
/// Max number of missed statuses to process after connect
@@ -36,6 +37,7 @@ impl Default for CommonConfig {
Self {
groups_dir: "groups".to_string(),
locales_dir: "locales".to_string(),
validate_locales: true,
max_catchup_notifs: 30,
max_catchup_statuses: 50,
delay_fetch_page_s: 0.25,
+33 -20
View File
@@ -4,7 +4,8 @@ use std::path::{Path, PathBuf};
use elefren::AppData;
use crate::error::GroupError;
use crate::store::DEFAULT_LOCALE_NAME;
use crate::store::{DEFAULT_LOCALE_NAME, CommonConfig};
use crate::tr::TranslationTable;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default, deny_unknown_fields)]
@@ -69,6 +70,8 @@ pub struct GroupConfig {
control: MutableConfig,
/// State config with timestamps and transient data that is changed frequently
state: StateConfig,
/// Group-specific translation table; this is a clone of the global table with group-specific overrides applied.
_group_tr: TranslationTable,
}
impl Default for FixedConfig {
@@ -155,16 +158,6 @@ impl_change_tracking!(FixedConfig);
impl_change_tracking!(MutableConfig);
impl_change_tracking!(StateConfig);
impl Default for GroupConfig {
fn default() -> Self {
Self {
config: Default::default(),
control: Default::default(),
state: Default::default(),
}
}
}
async fn load_or_create_control_file(control_path: impl AsRef<Path>) -> Result<MutableConfig, GroupError> {
let control_path = control_path.as_ref();
let mut dirty = false;
@@ -209,7 +202,22 @@ async fn load_or_create_state_file(state_path: impl AsRef<Path>) -> Result<State
Ok(state)
}
async fn load_locale_override_file(locale_path: impl AsRef<Path>) -> Result<Option<TranslationTable>, GroupError> {
let locale_path = locale_path.as_ref();
if locale_path.is_file() {
let f = tokio::fs::read(&locale_path).await?;
let opt : TranslationTable = serde_json::from_slice(&f)?;
Ok(Some(opt))
} else {
Ok(None)
}
}
impl GroupConfig {
pub fn tr(&self) -> &TranslationTable {
&self._group_tr
}
pub(crate) fn is_dirty(&self) -> bool {
self.config.is_dirty() || self.control.is_dirty() || self.state.is_dirty()
}
@@ -251,7 +259,7 @@ impl GroupConfig {
}
/// (re)init using new authorization
pub(crate) async fn from_appdata(acct: String, appdata: AppData, group_dir: PathBuf) -> Result<Self, GroupError> {
pub(crate) async fn initialize_by_appdata(acct: String, appdata: AppData, group_dir: PathBuf) -> Result<(), GroupError> {
if !group_dir.is_dir() {
debug!("Creating group directory");
tokio::fs::create_dir_all(&group_dir).await?;
@@ -298,15 +306,16 @@ impl GroupConfig {
/* state */
let state = load_or_create_state_file(state_path).await?;
let g = GroupConfig { config, control, state };
let g = GroupConfig { config, control, state, _group_tr: TranslationTable::new() };
g.warn_of_bad_config();
Ok(g)
Ok(())
}
pub(crate) async fn from_dir(group_dir: PathBuf) -> Result<Self, GroupError> {
pub(crate) async fn from_dir(group_dir: PathBuf, cc : &CommonConfig) -> Result<Self, GroupError> {
let config_path = group_dir.join("config.json");
let control_path = group_dir.join("control.json");
let state_path = group_dir.join("state.json");
let locale_path = group_dir.join("messages.json");
// try to reuse content of the files, if present
@@ -321,7 +330,15 @@ impl GroupConfig {
/* state */
let state = load_or_create_state_file(state_path).await?;
let g = GroupConfig { config, control, state };
/* translation table */
let mut tr = cc.tr(&config.locale).clone();
if let Some(locale_overrides) = load_locale_override_file(locale_path).await? {
for (k, v) in locale_overrides.entries() {
tr.add_translation(k, v);
}
}
let g = GroupConfig { config, control, state, _group_tr: tr };
g.warn_of_bad_config();
Ok(g)
}
@@ -369,10 +386,6 @@ impl GroupConfig {
&self.config.appdata
}
pub(crate) fn get_locale(&self) -> &str {
&self.config.locale
}
pub(crate) fn set_appdata(&mut self, appdata: AppData) {
if self.config.appdata != appdata {
self.config.mark_dirty();
+9 -8
View File
@@ -127,7 +127,7 @@ impl ConfigStore {
let group_dir = self.groups_path.join(&opts.acct);
let _data = GroupConfig::from_appdata(opts.acct.clone(), appdata, group_dir).await?;
GroupConfig::initialize_by_appdata(opts.acct.clone(), appdata, group_dir).await?;
// save & persist
@@ -151,7 +151,7 @@ impl ConfigStore {
pub async fn reauth_group(&self, acct: &str) -> Result<(), GroupError> {
let group_dir = self.groups_path.join(&acct);
let mut config = GroupConfig::from_dir(group_dir).await?;
let mut config = GroupConfig::from_dir(group_dir, &self.config).await?;
println!("--- Re-authenticating bot user @{} ---", acct);
let registration = Registration::new(config.get_appdata().base.to_string())
@@ -233,11 +233,12 @@ impl ConfigStore {
for (k, v) in def_tr.entries() {
if !tr.translation_exists(k) {
warn!("locale \"{}\" is missing \"{}\", default: {:?}",
locale_name,
k,
def_tr.get_translation_raw(k).unwrap());
if self.config.validate_locales {
warn!("locale \"{}\" is missing \"{}\", default: {:?}",
locale_name,
k,
def_tr.get_translation_raw(k).unwrap());
}
tr.add_translation(k, v);
}
}
@@ -261,7 +262,7 @@ impl ConfigStore {
.map(|entry_maybe: Result<std::fs::DirEntry, std::io::Error>| async {
match entry_maybe {
Ok(entry) => {
let gc = GroupConfig::from_dir(entry.path()).await.ok()?;
let gc = GroupConfig::from_dir(entry.path(), &config).await.ok()?;
if !gc.is_enabled() {
debug!("Group @{} is DISABLED", gc.get_acct());
+1
View File
@@ -23,6 +23,7 @@ impl TranslationTable {
self.entries.get(key).map(|s| s.as_str())
}
/// Add or update a translation
pub fn add_translation(&mut self, key : impl ToString, subs : impl ToString) {
self.entries.insert(key.to_string(), subs.to_string());
}