File size: 6,847 Bytes
a1258b5
029ef5b
fa7018d
a1258b5
ec27e8c
6bbdef7
52d2425
 
 
 
 
a1258b5
029ef5b
 
52d2425
 
1a471fb
 
 
1826c30
029ef5b
 
 
 
 
 
 
 
 
 
 
 
91c078f
029ef5b
1a471fb
 
 
a1258b5
 
029ef5b
 
 
 
 
 
1a471fb
a1258b5
1a471fb
91c078f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52d2425
fa7018d
a1258b5
91c078f
 
 
 
1a471fb
 
 
91c078f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52d2425
 
1a471fb
 
 
52d2425
 
 
 
 
 
 
 
 
a1258b5
1a471fb
52d2425
 
 
 
 
 
 
a1258b5
1a471fb
 
 
 
 
 
 
dd0a059
1a471fb
 
dd0a059
 
 
 
 
 
 
1a471fb
91c078f
1a471fb
029ef5b
 
 
91c078f
 
 
029ef5b
 
91c078f
029ef5b
 
91c078f
 
 
029ef5b
 
 
 
 
 
 
 
91c078f
029ef5b
91c078f
a1258b5
 
029ef5b
52d2425
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1258b5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
from fasthtml.common import *
from fasthtml.xtend import CheckboxX
from translator import languages as VALID_LANGUAGES, translate_to_languages
import tempfile
from starlette.requests import Request
from typing import List
from starlette.responses import FileResponse, PlainTextResponse
import os
import mimetypes
import zipfile
import io

css = Style(':root {--pico-font-size:90%,--pico-font-family: Pacifico, cursive;}')
app = FastHTML(hdrs=(picolink, css))

TEMP_FILES = {}
# Extract form generation to a separate function
def generate_language_form():
    return Form(
        Input(type='file', name='sbv_file', accept='.sbv', required=True),
        H3('Select languages for translation'),
        Fieldset(
            Legend("Languages"),
            Div(
                *[CheckboxX(
                    label=lang,
                    value=lang,
                    id=f'lang_{lang}',
                    name='languages'
                ) for lang in VALID_LANGUAGES],
                class_='grid'
            )
        ),
        Button('Translate', class_="primary"),
        action="/upload", method='post', enctype='multipart/form-data'
    )

@app.get('/')
def home():
    return Container(
        Article(
            H1("SBV File Translator"),
            P("Upload an SBV File and select languages for translation:"),
            generate_language_form(),
        )
    )

# Extract file processing logic to a separate function
def translate_and_process_sbv(content: bytes, filename: str, languages: List[str]) -> dict:
    """
    Translate and process an SBV file for the given languages.

    Args:
        content (bytes): The content of the uploaded SBV file.
        filename (str): The name of the uploaded file.
        languages (List[str]): List of target languages for translation.

    Returns:
        dict: A dictionary containing translation results, file paths, and zip filename.
    """
    try:
        temp_dir = tempfile.mkdtemp()
        input_file = os.path.join(temp_dir, filename)
        
        # Ensure the directory exists
        os.makedirs(os.path.dirname(input_file), exist_ok=True)
        
        with open(input_file, 'wb') as f:
            f.write(content)

        selected_languages = [lang for lang in languages if lang in VALID_LANGUAGES]
        output_dir = os.path.join(temp_dir, "translations")
        os.makedirs(output_dir, exist_ok=True)

        translate_to_languages(input_file, output_dir, selected_languages)

        return create_translation_files(temp_dir, output_dir, filename, selected_languages)
    except Exception as e:
        print(f"Error in translate_and_process_sbv: {str(e)}")
        raise  # Re-raise the exception after logging

# Extract translation file creation logic to a separate function
def create_translation_files(temp_dir: str, output_dir: str, filename: str, languages: List[str]) -> dict:
    """
    Create translation files and organize them for download.

    This function processes the translated SBV files, organizes them in a temporary directory,
    creates a zip file containing all translations, and prepares the data for the response.

    Args:
        temp_dir (str): Path to the temporary directory for storing files.
        output_dir (str): Path to the directory containing the translated SBV files.
        filename (str): Name of the original uploaded file.
        languages (List[str]): List of languages for which translations were created.

    Returns:
        dict: A dictionary containing:
            - 'translations': Dict of language codes to translated content.
            - 'file_paths': Dict of language codes to paths of individual translation files.
            - 'zip_filename': Name of the zip file containing all translations.
    """
    translations = {}
    file_paths = {}
    base_filename = os.path.splitext(filename)[0]

    for lang in languages:
        translated_file = os.path.join(output_dir, f"{base_filename}_{lang}.sbv")
        with open(translated_file, 'r', encoding='utf-8') as f:
            translations[lang] = f.read()
        
        new_filename = f"{base_filename}_{lang}.sbv"
        new_path = os.path.join(temp_dir, new_filename)
        os.rename(translated_file, new_path)
        file_paths[lang] = new_path
        TEMP_FILES[new_filename] = new_path

    zip_filename = f"{base_filename}_{'_'.join(languages)}.zip"
    zip_path = os.path.join(temp_dir, zip_filename)
    
    with zipfile.ZipFile(zip_path, 'w') as zip_file:
        for lang, file_path in file_paths.items():
            zip_file.write(file_path, os.path.basename(file_path))
    
    TEMP_FILES[zip_filename] = zip_path

    return {
        'translations': translations,
        'file_paths': file_paths,
        'zip_filename': zip_filename
    }

@app.post('/upload')
async def upload_file(request: Request, sbv_file: UploadFile):
    content = await sbv_file.read()
    
    # Get form data
    form = await request.form()
    languages = form.getlist('languages')

    # Ensure languages is always a list
    if not languages:
        return PlainTextResponse("Please select at least one language for translation.", status_code=400)

    result = translate_and_process_sbv(content, sbv_file.filename, languages)

    return Container(
        Article(
            H1('Translations'),
            A("Download All Translations", 
              href=f"/download/{result['zip_filename']}", 
              download=True,
              class_="primary",
              role="button"
            ),
            *[Card(
                H3(f'{lang.capitalize()} Translation'),
                Pre(
                    '\n'.join(result['translations'][lang].split('\n')[:9]) + '\n...',
                ),
                Footer(
                    A(f"Download {lang.capitalize()} Translation", 
                      href=f"/download/{os.path.basename(result['file_paths'][lang])}", 
                      download=True, 
                      class_="secondary outline",
                      role="button"
                    )
                )
            ) for lang in result['translations']],
            class_="container-fluid"  # Add this class for full-width content
        )
    )

@app.get("/download/{filename}")
def get(filename: str):
    file_path = TEMP_FILES.get(filename)
    if file_path and os.path.exists(file_path):
        mime_type, _ = mimetypes.guess_type(file_path)
        return FileResponse(
            file_path,
            filename=filename,
            media_type=mime_type or "application/octet-stream",
            headers={
                "Content-Disposition": f"attachment; filename={filename}",
                "X-Content-Type-Options": "nosniff",
            }
        )
    else:
        return PlainTextResponse("File not found", status_code=404)

serve()