@@ -17,34 +17,73 @@ const FILE_QUEUE_STORAGE_KEY = 'tbl_file_queue';
1717let lastUploadedFileName = null ;
1818
1919/**
20- * Generate output filename based on pattern
21- * @param {File } file - Original file
22- * @param {string } pattern - Output pattern (e.g., "{originalName} ({targetLang}).{ext}")
20+ * Sanitize a value to be safe in a filename across Windows/macOS/Linux.
21+ * Strips path separators and reserved chars, collapses whitespace.
22+ */
23+ function sanitizeFilenamePart ( value ) {
24+ if ( value === null || value === undefined ) return '' ;
25+ return String ( value )
26+ . replace ( / [ \/ \\ : * ? " < > | ] + / g, '_' )
27+ . replace ( / \s + / g, ' ' )
28+ . trim ( ) ;
29+ }
30+
31+ /**
32+ * Resolve a language value from a <select> + custom <input> pair,
33+ * falling back to 'Translated' / 'Source' when empty.
34+ */
35+ function resolveLanguageValue ( selectId , customId , fallback ) {
36+ const selectEl = DomHelpers . getElement ( selectId ) ;
37+ const customEl = DomHelpers . getElement ( customId ) ;
38+ let value = selectEl ?. value || '' ;
39+ if ( value === 'Other' ) {
40+ value = customEl ?. value ?. trim ( ) || '' ;
41+ }
42+ return value || fallback ;
43+ }
44+
45+ /**
46+ * Generate output filename based on pattern.
47+ * Supported placeholders: {originalName}, {targetLang}, {sourceLang}, {model}, {date}, {datetime}, {ext}
48+ *
49+ * @param {File|{name: string} } file - Original file (only .name is used)
50+ * @param {string } pattern - Output pattern
51+ * @param {Object } [overrides] - Optional explicit values that win over DOM lookups
52+ * @param {string } [overrides.sourceLang]
53+ * @param {string } [overrides.targetLang]
54+ * @param {string } [overrides.model]
2355 * @returns {string } Generated filename
2456 */
25- function generateOutputFilename ( file , pattern ) {
57+ export function generateOutputFilename ( file , pattern , overrides = { } ) {
2658 const fileExtension = file . name . split ( '.' ) . pop ( ) . toLowerCase ( ) ;
2759 const originalNameWithoutExt = file . name . replace ( / \. [ ^ / . ] + $ / , "" ) ;
2860
29- // Get target language from the form
30- const targetLangSelect = DomHelpers . getElement ( 'targetLang' ) ;
31- const customTargetLang = DomHelpers . getElement ( 'customTargetLang' ) ;
32- let targetLang = targetLangSelect ?. value || '' ;
33-
34- // If "Other" is selected, use the custom input value
35- if ( targetLang === 'Other' ) {
36- targetLang = customTargetLang ?. value ?. trim ( ) || '' ;
61+ const targetLang = overrides . targetLang
62+ || resolveLanguageValue ( 'targetLang' , 'customTargetLang' , 'Translated' ) ;
63+ const sourceLang = overrides . sourceLang
64+ || resolveLanguageValue ( 'sourceLang' , 'customSourceLang' , 'Source' ) ;
65+ const model = overrides . model ?? DomHelpers . getValue ( 'model' ) ?? '' ;
66+
67+ const now = new Date ( ) ;
68+ const pad = ( n ) => String ( n ) . padStart ( 2 , '0' ) ;
69+ const date = `${ now . getFullYear ( ) } -${ pad ( now . getMonth ( ) + 1 ) } -${ pad ( now . getDate ( ) ) } ` ;
70+ const datetime = `${ date } _${ pad ( now . getHours ( ) ) } -${ pad ( now . getMinutes ( ) ) } -${ pad ( now . getSeconds ( ) ) } ` ;
71+
72+ const replacements = {
73+ '{originalName}' : sanitizeFilenamePart ( originalNameWithoutExt ) ,
74+ '{targetLang}' : sanitizeFilenamePart ( targetLang ) ,
75+ '{sourceLang}' : sanitizeFilenamePart ( sourceLang ) ,
76+ '{model}' : sanitizeFilenamePart ( model ) ,
77+ '{date}' : date ,
78+ '{datetime}' : datetime ,
79+ '{ext}' : fileExtension
80+ } ;
81+
82+ let result = pattern || '{originalName} ({targetLang}).{ext}' ;
83+ for ( const [ token , value ] of Object . entries ( replacements ) ) {
84+ result = result . split ( token ) . join ( value ) ;
3785 }
38-
39- // Use "Translated" as fallback if no language specified
40- if ( ! targetLang ) {
41- targetLang = 'Translated' ;
42- }
43-
44- return pattern
45- . replace ( "{originalName}" , originalNameWithoutExt )
46- . replace ( "{targetLang}" , targetLang )
47- . replace ( "{ext}" , fileExtension ) ;
86+ return result ;
4887}
4988
5089/**
0 commit comments