i18n on the web - deepseek translations
This commit is contained in:
@@ -25,6 +25,7 @@ use crate::{
|
||||
AddTableColumnsRequest, CopyProfileRequest, CreateInvoiceTemplateTableRequest,
|
||||
DeleteTableRequest, RenameColumnAliasRequest,
|
||||
},
|
||||
{i18n::Locale, tr},
|
||||
schema::{ColumnForm, proto_columns},
|
||||
services::{authenticated_request, reject_cross_site},
|
||||
};
|
||||
@@ -144,7 +145,7 @@ async fn show(state: AppState, headers: HeaderMap, inputs: PageInputs, page: Pag
|
||||
loaded.active = page.name();
|
||||
Html(page.render_page(&loaded)).into_response()
|
||||
}
|
||||
Err(error) => load_error_response(error),
|
||||
Err(error) => load_error_response(&headers, error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,20 +170,21 @@ pub(crate) async fn update_columns(
|
||||
let mut definitions = state.definitions.clone();
|
||||
let catalog = match loader::load_column_catalog(&mut definitions, &headers).await {
|
||||
Ok(catalog) => catalog,
|
||||
Err(error) => return load_error_response(error),
|
||||
Err(error) => return load_error_response(&headers, error),
|
||||
};
|
||||
|
||||
let mut inputs = PageInputs::for_selection(selection);
|
||||
inputs.columns = form.to_draft(catalog, false);
|
||||
|
||||
let index = form.index.unwrap_or(0);
|
||||
let locale = Locale::from_headers(&headers);
|
||||
match form.action.as_str() {
|
||||
"add-column" => match inputs.columns.add_from_inputs() {
|
||||
"add-column" => match inputs.columns.add_from_inputs(locale) {
|
||||
Ok(status) => inputs.status = Some(status),
|
||||
Err(message) => inputs.error = Some(message),
|
||||
},
|
||||
"remove-column" => {
|
||||
if let Err(message) = inputs.columns.remove(index) {
|
||||
if let Err(message) = inputs.columns.remove(locale, index) {
|
||||
inputs.error = Some(message);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +197,7 @@ pub(crate) async fn update_columns(
|
||||
loaded.active = Page::Columns.name();
|
||||
Html(ui::render_column_panel(&loaded)).into_response()
|
||||
}
|
||||
Err(error) => load_error_response(error),
|
||||
Err(error) => load_error_response(&headers, error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,29 +217,43 @@ pub(crate) async fn add_columns(
|
||||
let mut definitions = state.definitions.clone();
|
||||
let catalog = match loader::load_column_catalog(&mut definitions, &headers).await {
|
||||
Ok(catalog) => catalog,
|
||||
Err(error) => return load_error_response(error),
|
||||
Err(error) => return load_error_response(&headers, error),
|
||||
};
|
||||
|
||||
let mut inputs = PageInputs::for_selection(selection);
|
||||
inputs.columns = form.to_draft(catalog.clone(), false);
|
||||
|
||||
if !inputs.selection.has_table() {
|
||||
return refuse(state, headers, inputs, Page::Columns, "Select a table first.".to_string())
|
||||
.await;
|
||||
}
|
||||
if inputs.columns.is_empty() {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-select-table-first"
|
||||
);
|
||||
return refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Columns,
|
||||
"Describe at least one column before adding.".to_string(),
|
||||
message,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
if inputs.columns.is_empty() {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-describe-column"
|
||||
);
|
||||
return refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Columns,
|
||||
message,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
// The same checks the server runs, applied to a draft that may have been
|
||||
// rebuilt from a posted form rather than through the panel.
|
||||
if let Err(message) = inputs.columns.validate() {
|
||||
if let Err(message) = inputs.columns.validate(Locale::from_headers(&headers)) {
|
||||
return refuse(state, headers, inputs, Page::Columns, message).await;
|
||||
}
|
||||
|
||||
@@ -259,10 +275,11 @@ pub(crate) async fn add_columns(
|
||||
Ok(response) if response.get_ref().success => {
|
||||
let added = inputs.columns.added.len();
|
||||
inputs.sql = Some(response.into_inner().sql);
|
||||
inputs.status = Some(format!(
|
||||
"{added} column{} added to `{}`.",
|
||||
if added == 1 { "" } else { "s" },
|
||||
inputs.selection.table
|
||||
inputs.status = Some(tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-columns-added",
|
||||
"count" => added as i64,
|
||||
"table" => inputs.selection.table.clone(),
|
||||
));
|
||||
// The columns are the table's now, so the panel starts empty.
|
||||
inputs.columns = crate::schema::ColumnDraft::for_append(catalog);
|
||||
@@ -271,7 +288,10 @@ pub(crate) async fn add_columns(
|
||||
Ok(response) => {
|
||||
let message = response.into_inner().sql;
|
||||
let message = if message.is_empty() {
|
||||
"The backend did not add the columns.".to_string()
|
||||
tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-backend-no-columns"
|
||||
)
|
||||
} else {
|
||||
message
|
||||
};
|
||||
@@ -300,12 +320,16 @@ pub(crate) async fn rename_column(
|
||||
inputs.rename = form.clone();
|
||||
|
||||
if form.old_column_name.is_empty() || form.new_column_name.trim().is_empty() {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-choose-rename"
|
||||
);
|
||||
return refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Columns,
|
||||
"Choose a column and type its new name.".to_string(),
|
||||
message,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -334,7 +358,10 @@ pub(crate) async fn rename_column(
|
||||
Ok(response) => {
|
||||
let message = response.into_inner().message;
|
||||
let message = if message.is_empty() {
|
||||
"The backend did not rename the column.".to_string()
|
||||
tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-backend-no-rename"
|
||||
)
|
||||
} else {
|
||||
message
|
||||
};
|
||||
@@ -367,12 +394,16 @@ pub(crate) async fn delete_table(
|
||||
// The typed name is the whole guard: the drop is CASCADE, and it takes the
|
||||
// profile with it when this was its last table.
|
||||
if form.confirm_table_name.trim() != form.table || form.table.is_empty() {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-type-name"
|
||||
);
|
||||
return refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Delete,
|
||||
"Type the table's name exactly to confirm the deletion.".to_string(),
|
||||
message,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -404,7 +435,10 @@ pub(crate) async fn delete_table(
|
||||
Ok(response) => {
|
||||
let message = response.into_inner().message;
|
||||
let message = if message.is_empty() {
|
||||
"The backend did not delete the table.".to_string()
|
||||
tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-backend-no-delete"
|
||||
)
|
||||
} else {
|
||||
message
|
||||
};
|
||||
@@ -433,12 +467,16 @@ pub(crate) async fn copy_profile(
|
||||
inputs.copy = form.clone();
|
||||
|
||||
if form.target_profile_name.trim().is_empty() {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-name-profile"
|
||||
);
|
||||
return refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Copy,
|
||||
"Name the profile to copy into.".to_string(),
|
||||
message,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -456,9 +494,12 @@ pub(crate) async fn copy_profile(
|
||||
match definitions.copy_profile(request).await {
|
||||
Ok(response) if response.get_ref().success => {
|
||||
let response = response.into_inner();
|
||||
inputs.status = Some(format!(
|
||||
"{} — {} table(s) and {} script(s) copied.",
|
||||
response.message, response.tables_copied, response.scripts_copied
|
||||
inputs.status = Some(tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-profile-copied",
|
||||
"message" => response.message.clone(),
|
||||
"tables" => response.tables_copied as i64,
|
||||
"scripts" => response.scripts_copied as i64,
|
||||
));
|
||||
inputs.copy = CopyForm {
|
||||
profile: form.profile,
|
||||
@@ -469,7 +510,10 @@ pub(crate) async fn copy_profile(
|
||||
Ok(response) => {
|
||||
let message = response.into_inner().message;
|
||||
let message = if message.is_empty() {
|
||||
"The backend did not copy the profile.".to_string()
|
||||
tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-backend-no-copy"
|
||||
)
|
||||
} else {
|
||||
message
|
||||
};
|
||||
@@ -496,12 +540,16 @@ pub(crate) async fn create_from_invoice_template(
|
||||
inputs.invoice = form.clone();
|
||||
|
||||
if form.table_name.trim().is_empty() || form.typst_source.trim().is_empty() {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-template-required"
|
||||
);
|
||||
return refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Template,
|
||||
"A table name and the template's source are both required.".to_string(),
|
||||
message,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -520,9 +568,10 @@ pub(crate) async fn create_from_invoice_template(
|
||||
match definitions.create_invoice_template_table(request).await {
|
||||
Ok(response) if response.get_ref().success => {
|
||||
let response = response.into_inner();
|
||||
inputs.status = Some(format!(
|
||||
"{} table(s) created from the template.",
|
||||
response.tables.len()
|
||||
inputs.status = Some(tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-template-tables-created",
|
||||
"count" => response.tables.len() as i64,
|
||||
));
|
||||
inputs.generated = response
|
||||
.tables
|
||||
@@ -540,12 +589,16 @@ pub(crate) async fn create_from_invoice_template(
|
||||
respond(state, headers, inputs, Page::Template, StatusCode::OK).await
|
||||
}
|
||||
Ok(_) => {
|
||||
let message = tr!(
|
||||
Locale::from_headers(&headers),
|
||||
"td-err-backend-no-template"
|
||||
);
|
||||
refuse(
|
||||
state,
|
||||
headers,
|
||||
inputs,
|
||||
Page::Template,
|
||||
"The backend did not create the template's tables.".to_string(),
|
||||
message,
|
||||
)
|
||||
.await
|
||||
}
|
||||
@@ -568,7 +621,7 @@ async fn respond(
|
||||
loaded.active = page.name();
|
||||
(status, Html(page.render_fragment(&loaded))).into_response()
|
||||
}
|
||||
Err(error) => load_error_response(error),
|
||||
Err(error) => load_error_response(&headers, error),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,19 +637,23 @@ async fn refuse(
|
||||
respond(state, headers, inputs, page, StatusCode::UNPROCESSABLE_ENTITY).await
|
||||
}
|
||||
|
||||
fn load_error_response(error: LoadError) -> Response {
|
||||
fn load_error_response(headers: &HeaderMap, error: LoadError) -> Response {
|
||||
match error {
|
||||
LoadError::Unauthenticated => Redirect::to("/login").into_response(),
|
||||
LoadError::Forbidden => (
|
||||
StatusCode::FORBIDDEN,
|
||||
Html(ui::render_load_error(
|
||||
"Table-management permission is required.",
|
||||
Locale::from_headers(headers),
|
||||
&tr!(
|
||||
Locale::from_headers(headers),
|
||||
"td-err-permission"
|
||||
),
|
||||
)),
|
||||
)
|
||||
.into_response(),
|
||||
LoadError::Backend(message) => (
|
||||
StatusCode::BAD_GATEWAY,
|
||||
Html(ui::render_load_error(&message)),
|
||||
Html(ui::render_load_error(Locale::from_headers(headers), &message)),
|
||||
)
|
||||
.into_response(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user