mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-04 23:17:34 +08:00
feat: add i18n support for backend API and Telegram bot (#797)
* feat: add i18n support for backend API and Telegram bot - Add comprehensive i18n support for all backend API error messages (zh/en) - Add /lang command for Telegram bot to set language preference - Add bilingual command descriptions for Telegram bot - Support per-user language preference stored in KV - Global push uses DEFAULT_LANG, user push uses saved preference 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: improve Telegram bot language preference feature - Add internationalized message for disabled language feature - Fix hardcoded English message in /lang command - Optimize getTgMessages calls (reduce from 3 to 1 call) - Remove verbose comments for better code clarity - Add TgLangFeatureDisabledMsg to i18n (zh/en) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
5e227d2b2d
commit
3ebe22115a
@@ -4,6 +4,11 @@ import { cleanup } from '../common';
|
||||
import { CONSTANTS } from '../constants';
|
||||
import { getJsonSetting, saveSetting } from '../utils';
|
||||
import { CleanupSettings, CustomSqlCleanup } from '../models';
|
||||
import i18n from '../i18n';
|
||||
import { LocaleMessages } from '../i18n/type';
|
||||
|
||||
// SQL validation error types
|
||||
type SqlValidationError = 'empty' | 'too_long' | 'not_delete' | 'multiple_statements' | 'has_comments';
|
||||
|
||||
// Normalize SQL: trim and remove trailing semicolon
|
||||
const normalizeSql = (sql: string): string => {
|
||||
@@ -14,34 +19,45 @@ const normalizeSql = (sql: string): string => {
|
||||
return normalized;
|
||||
};
|
||||
|
||||
// Get error message from error type
|
||||
const getValidationErrorMsg = (errorType: SqlValidationError, msgs: LocaleMessages): string => {
|
||||
switch (errorType) {
|
||||
case 'empty': return msgs.SqlEmptyMsg;
|
||||
case 'too_long': return msgs.SqlTooLongMsg;
|
||||
case 'not_delete': return msgs.SqlOnlyDeleteMsg;
|
||||
case 'multiple_statements': return msgs.SqlSingleStatementMsg;
|
||||
case 'has_comments': return msgs.SqlNoCommentsMsg;
|
||||
}
|
||||
};
|
||||
|
||||
// Validate custom SQL cleanup statement
|
||||
export const validateCustomSql = (sql: string): { valid: boolean; error?: string } => {
|
||||
export const validateCustomSql = (sql: string): { valid: boolean; errorType?: SqlValidationError } => {
|
||||
if (!sql || !sql.trim()) {
|
||||
return { valid: false, error: "SQL statement is empty" };
|
||||
return { valid: false, errorType: 'empty' };
|
||||
}
|
||||
|
||||
const trimmedSql = normalizeSql(sql);
|
||||
|
||||
// Check SQL length (max 1000 characters)
|
||||
if (trimmedSql.length > 1000) {
|
||||
return { valid: false, error: "SQL statement is too long (max 1000 characters)" };
|
||||
return { valid: false, errorType: 'too_long' };
|
||||
}
|
||||
|
||||
const sqlUpper = trimmedSql.toUpperCase();
|
||||
|
||||
// Only allow DELETE statements
|
||||
if (!sqlUpper.startsWith('DELETE ')) {
|
||||
return { valid: false, error: "Only DELETE statements are allowed" };
|
||||
return { valid: false, errorType: 'not_delete' };
|
||||
}
|
||||
|
||||
// Only allow single statement (no semicolons after trimming)
|
||||
if (trimmedSql.includes(';')) {
|
||||
return { valid: false, error: "Only single SQL statement is allowed" };
|
||||
return { valid: false, errorType: 'multiple_statements' };
|
||||
}
|
||||
|
||||
// Forbid SQL comments
|
||||
if (/--/.test(trimmedSql) || /\/\*/.test(trimmedSql)) {
|
||||
return { valid: false, error: "SQL comments are not allowed" };
|
||||
return { valid: false, errorType: 'has_comments' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
@@ -52,13 +68,14 @@ export const executeCustomSqlCleanup = async (
|
||||
c: Context<HonoCustomType>,
|
||||
customSql: CustomSqlCleanup
|
||||
): Promise<{ success: boolean; rowsAffected?: number; error?: string }> => {
|
||||
const msgs = i18n.getMessagesbyContext(c);
|
||||
if (!customSql || !customSql.sql) {
|
||||
return { success: false, error: "Invalid custom SQL cleanup config" };
|
||||
return { success: false, error: msgs.InvalidCleanupConfigMsg };
|
||||
}
|
||||
|
||||
const validation = validateCustomSql(customSql.sql);
|
||||
if (!validation.valid) {
|
||||
return { success: false, error: validation.error };
|
||||
return { success: false, error: getValidationErrorMsg(validation.errorType!, msgs) };
|
||||
}
|
||||
|
||||
const sql = normalizeSql(customSql.sql);
|
||||
@@ -78,12 +95,13 @@ export const executeCustomSqlCleanup = async (
|
||||
|
||||
export default {
|
||||
cleanup: async (c: Context<HonoCustomType>) => {
|
||||
const msgs = i18n.getMessagesbyContext(c);
|
||||
const { cleanType, cleanDays } = await c.req.json();
|
||||
try {
|
||||
await cleanup(c, cleanType, cleanDays);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return c.text(`Failed to cleanup ${(error as Error).message}`, 500)
|
||||
return c.text(`${msgs.OperationFailedMsg}: ${(error as Error).message}`, 500)
|
||||
}
|
||||
return c.json({ success: true })
|
||||
},
|
||||
@@ -92,6 +110,7 @@ export default {
|
||||
return c.json(cleanupSetting)
|
||||
},
|
||||
saveCleanup: async (c: Context<HonoCustomType>) => {
|
||||
const msgs = i18n.getMessagesbyContext(c);
|
||||
const cleanupSetting = await c.req.json<CleanupSettings>();
|
||||
|
||||
// Validate custom SQL cleanup list
|
||||
@@ -100,7 +119,8 @@ export default {
|
||||
if (customSql.sql) {
|
||||
const validation = validateCustomSql(customSql.sql);
|
||||
if (!validation.valid) {
|
||||
return c.text(`Invalid SQL [${customSql.name || 'unnamed'}]: ${validation.error}`, 400);
|
||||
const errorMsg = getValidationErrorMsg(validation.errorType!, msgs);
|
||||
return c.text(`[${customSql.name || 'unnamed'}]: ${errorMsg}`, 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user