[Python] Traduttore automatico di sottotitoli

La mia smodata passione per le serie tv made in USA mi ha iniziato al binge watching molto prima che ne venisse coniato il termine per diventare una moda. Ricordo ancora il week end di una decina di anni fa, passato a ‘recuperare’ su internet gli episodi delle prime tre stagioni di «Battlestar Galactica» poco prima della trasmissione in America della quarta stagione. Di lì ho scoperto che non mi piaceva attendere qualche anno prima di poter guardare una serie tv che mi interessava e che internet da questo punto di vista era una notevole risorsa se si era disposti ad abituare l’occhio a non perdersi nessuna scena sbirciando contemporaneamente i sottotitoli sullo schermo (ancora tante grazie Italiansubs!).


Ora che i sottotitoli in italiano si fa più fatica a trovarli, un po’ per gioco e un po’ per utilità, ho pensato di creare uno script in Python che traduce un file di sottotitoli in inglese nel corrispettivo in italiano utilizzando la libreria googletrans (link) che sfrutta l’API di Google Translate. Il risultato non sarà dei più corretti ma IMHO abbastanza accettabile per godersi un episodio della propria serie tv preferita.


Ingredienti:

    • python 3
    • libreria googletrans (per la traduzione)
    • librerie sys, os (per la gestione dei file)
    • libreria timeit (per computare le prestazioni)

Per installare la libreria avendo a disposizione l’utility PIP è sufficiente digitare il seguente comando:

pip install googletrans

Analizziamo le parti principali del sorgente:

Innanzitutto importiamo le librerie che ci necessitano:

import sys, os
from googletrans import Translator
from timeit import default_timer as timer

Memorizziamo in una variabile il tempo iniziale che ci servirà per calcolare successivamente le prestazioni dello script:

start = timer()

E inizializziamo il traduttore sull’API pubblica di Google Translate:

translator = Translator(service_urls=[
      'translate.google.com',
      'translate.google.it',
    ])

Il progetto prevede di dare in pasto al traduttore le frasi contenute in un file in formato .srt contenente i sottotitoli in inglese, strutturalmente fatto in questo modo:

Per quanto riguarda il nome del file da tradurre lo passeremo come argomento nell’istruzione di esecuzione del programma. Il nome del file prodotto con i sottotitoli tradotti in italiano sarà generato conseguentemente aggiungendo il suffisso “_tradotto”. Viene anche controllata l’esistenza di un eventuale precedente file di traduzione avente lo stesso nome di quello in produzione e nel caso verrà cancellato.

try:
sourcefile = sys.argv[1]
resultfile = sys.argv[1].replace('.srt', '')+'_tradotto.srt'
except:
sourcefile = "sottotitolo.srt"
resultfile = sourcefile.replace('.srt', '')+'_tradotto.srt'

if os.path.isfile(resultfile) == True:
os.remove(resultfile)

Nessun problema ad aprire il file in questione e scomporre le righe di testo in elementi di una lista. Inoltre già che ci siamo cancelliamo gli eventuali inutili spazi vuoti in testa e in coda a ciascuna riga con il metodo strip():

with open(sourcefile) as f:
    content = f.readlines()
content = [x.strip() for x in content]

Ovviamente al nostro traduttore dovremo passare ‘solo’ i testi e non gli altri elementi utili alla renderizzazione a video dei sottotitoli. Inoltre al traduttore dobbiamo passare delle frasi intere, anche se nel file dovessero risultare ‘spezzate’ su più righe.

Processiamo ciascuna riga della lista creata e scartiamo quelle righe (senza eliminarle perché ci occorreranno poi per scrivere correttamente il file .srt dei sottotitoli tradotti) contenenti un numero intero (cioè il numero del sottotitolo) piuttosto che la durata del sottotitolo (che Python vede comunque come una stringa di testo da qui la trovata di pulire la riga dal segno di separazione (“:”) e di considerarne solo i primi 5 caratteri, in modo che ad esempio la riga “00:00:03,886 –> 00:00:07,961” venga computata come “00000” che Python riconosce giustamente come numero e quindi ce la fa scartare:

for item in content:
    count += 1
    if item.isdigit() == False:
        try:
            control = item.replace(":","")
            part = control[0:4].isdigit()
        except:
            part = False

Per risolvere il problema delle frasi spezzate su più righe come abbiamo ad esempio in questo caso:

Dove per ottenere una traduzione corretta occorre passare al traduttore una corretta frase interaBut you won’t fix the real problem” e non due righe separate come si presentano nel file. Si andrà quindi a tradurre quanto memorizzato in una lista ‘volatile’ solo dopo aver incontrato un salto di riga vuoto come questo:

Di seguito la mia soluzione che memorizza il testo da tradurre nella stringa “datradurre” che viene passata al traduttore istanziando l’oggetto translations da cui ricaviamo il testo tradotto quando la variabile trigger ‘accio’ processa una riga vuota. Ovviamente occorre tenere conto che sebbene al traduttore la frase di due righe verrà fornita in una riga sola, al momento della ricostruzione del sottotitolo tradotto la frase dovrà essere nuovamente divisa se troppo lunga per non perdere in leggibilità del sottotitolo: la frase sarà ‘spezzata in due righe dovesse essere composta da più di 5 parole e comunque da più di 40 caratteri (esclusi i segni ‘speciali di renderizzazione). Dopo aver passato la stringa al traduttore questa viene azzerata, pronta per le righe successive. Il tutto viene memorizzato in una lista denominata ‘traduzione’ a cui si aggiungeranno man mano tutte le righe processate, comprendenti il numero del sottotitolo, i tempi di inizio e fine visualizzazione e la traduzione ottenuta (o il testo originale se il programma non è riuscito a tradurre).

       if part != True:
            datradurre = datradurre +' '+item
            datrad_non.append(datradurre)
            accio = ("_______"+str(item)+"________________>")
            if accio == "_______________________>":
                try:
                    translations = translator.translate(datradurre, src='en', dest='it')
                    trad = translations.text
                    parole = 0
                    a = trad.split(" ")
                    for i in a:
                        if (i!=" " and i!="<i>" and i!="</" and i!="i>" and i!="-" and i!="..."):
                            parole=parole+1
                    if parole >5 and len(trad) >40:
                        frase = range(6,parole)
                        primariga = str(a[0])+' '+str(a[1])+' '+str(a[2])+' '+str(a[3])+' '+str(a[4])+' '+str(a[5])
                        secondariga = ''
                        for x in frase:
                            secondariga = secondariga+' '+str(a[x])
                        traduzione.append(primariga)
                        traduzione.append(secondariga[1:])
                        traduzione.append(item)
                        TRcount += 1
                    else:
                        traduzione.append(trad)
                        traduzione.append(item)
                        TRcount += 1
                except:
                    for x in datrad_non:
                        traduzione.append(x)
                    traduzione.append(item)
                    NOcount += 1
                datradurre = ""
                datrad_non.clear()
        else:
            traduzione.append(item)

Dopo aver processato tutte le righe si può procedere a generare scrivendo riga per riga il file .srt con i sottotitoli tradotti:

with open(resultfile, 'a') as f:
    for item in traduzione:
        f.write(item+'\n')

Possiamo calcolare a questo punto il tempo di esecuzione in secondi del programma:

end = timer()
tempo = "{0:.2f}".format((end - start))

E infine visualizzare le statistiche raccolte con i vari contatori alimentati durante il processo di traduzione:

print('\n')
print ('Totale righe _________ '+str(count))
print ('Totale traduzioni ____ '+str(TRcount))
print ('Problemi traduzioni __ '+str(NOcount))
print ('Totale tempo _________ '+tempo+'s')
print('\n')

Non sarà lo script meglio scritto, ma in un tempo ragionevole (circa 300 secondi per processare un episodio di tre quarti d’ora) riesce a sfornare dei sottotitoli in italiano discretamente accettabili.

Codice sorgente completo disponibile su GITHUB (link).

È morto l’attore Larry Hagman

Fu J.R. Ewing, spietato petroliere nella serie tv «Dallas», ma anche come il maggiore Anthony Nelson della popolare sitcom «Strega per amore». Si è spento in Texas a 81 anni per un tumore alla gola.

J.R., con il suo cappellone da cowboy e gli stivali, era il cattivo che il pubblico aveva imparato ad odiare negli anni ’80 nella storia della ricchissima famiglia texana Ewing. “Non riesco a ricordarmi con quante persone sono andato a letto, ho accoltellato alle spalle o ho spinto al suicidio”,  era solito raccontare Larry Hagman del suo personaggio che all’inizio doveva essere secondario ma che lui aveva imposto come centrale rendendolo sempre piu’ malvagio e crudele. Hagman aveva interpretato poco tempo fa un invecchiato J.R nel sequel della serie che ha avuto successo negli Usa ma non in Italia, dove quest’anno Canale5 lo ha ritirato dopo la seconda puntata per i pessimi ascolti.

Ai tempi del vecchio “Dallas”, avevo pressappoco una decina di anni e una volta alla settimana, subito dopo cena ci trasferivamo tutti in salotto per attendere la fine del barboso telegiornale della Rai per poi sintonizzarci sul canale privato che puntualmente alle ventietrenta ci portava al Southfork Ranch. Era uno dei primi tradimenti alla televisione di stato. Davanti al televisore vedevo scorrere immagini di una famiglia molto diversa dalla mia: i ricchissimi Ewing, invece di spassarsela con i soldi ricavati dal petrolio texano, complottavano spietatamente uno contro gli altri. E’ difficile per me oggi trovare una giustificazione al fascino del cattivo J.R. e soci. A casa mia non ci perdevamo una puntata: un natale ricevetti il gioco da tavolo di “Dallas” che era meglio del “monopoli” visto che potevamo giocare con minuscoli barili di petrolio di plastica nera e  maneggiare “veri” dollari di carta. Allora non lo sapevo, ma ero coinvolto in un fenomeno mediatico. I network americani stavano sdoganando in prima serata un genere di nicchia che qualche anno più tardi portò la televisione a scoprire quella vena inesauribile delle soap opera da “Dinasty” a “Beatiful” fino ad arrivare alla nostrana “Un posto al sole”. Come a tutti mi è poi capitato di vedere l’Hagman giovane in una “Strega per amore” quasi non riuscendo a collegare il bonaccione maggiore Nelson con il cattivo dal cappello texano. Non vi dico con quale nostalgia mi sono seduto di fronte al teleschermo per cercare di evocare seguendo Larry Hagman, Patrick Duffy e Linda Grey nel recente sequel di “Dallas”: ho cercato di ritrovare quella atmosfera che tanti anni fa mi incollava alla poltrona poi dopo cinque inutili minuti ho cambiato canale. Mi sa tanto che in tutti questi anni  ho visto fin troppe cattiverie da poter ritenere il vecchio J.R. oramai un sorpassato dilettante.

Il gusto di vederli prima (o meglio in contemporanea)

tvPrende sempre più piede l’abitudine degli internauti di non attendere i tempi del marketing televisivo ma di godersi il prima possibile le proprie serie televisive preferite. Già perchè da sempre le migliori serie tv vengono dall’America e noi italiani dobbiamo attendere che un dirigente di RAI, MEDIASET o di SKY ne acquisti i diritti per la tv italiana. Se va bene, complici anche i canali a pagamento satellitari e quelli del digitale terrestre, si potranno godere le puntate del Dr. HOUSE, di HEROES, di DOLLHOUSE, di FRINGE o di THE BEAST con un anno o due di ritardo rispetto alla loro messa in onda nel paese di origine. E se poi va male non vedremo mai la serie tv: come è successo a SPACE: ABOVE AND BEYOND che messa in onda nel Nord America, in Inghilterra e in mezzo mondo, non è purtroppo mai arrivata sui nostri schermi.

Comunque per chi non può attendere e sa sfruttare le risorse messe a disposizione dalla reteContinua a leggere

Serie Tv: FRINGE

fringe_poster_figure1Fringe è un serial televisivo statunitense ideato e coprodotto da J.J. Abrams (già creatore di FelicityAliasLost), che ha debuttato negli USA il 9 settembre 2008 sul network FOX e interpretato da Joshua Jackson, John Noble e l’esordiente Anna Torv.

In ogni episodio seguiamo il detective Dunham (Anna Torv) alle prese con incredibili casi dove la scienza è oltre e grazie all’eccentrico scienziato Bishop (John Noble) e a suo figlio  (Joshua Jackson)  cerca di venire a capo dello SCHEMA (in inglese PATTERN) che sembra essere il filo conduttore di ogni enigma.

Continua a leggere

Serie TV: The Beast

the-beastThe Beast è una serie tv ideata da Vincent Angell, William Rotko con Patrick Swayze, Travis Fimmel, Lindsay Pulsipher, Randy Bernales, F. David Roth, Dale Caba, Mike Bach, Bernadette Lords, Sarah Habel, Chad Manuel. Ambientata nella città di CHICAGO (come E.R.!!!) è prodotta in USA dalla Sony Pictures Television per conto della rete televisiva A&E. La serie viene trasmessa dal 15.01.2009 e per ora è composta da 1 stagione.

Confesso che ho iniziato a seguire questa serie televisiva per vedere come se la cavava sul lavoro Patrick Swayze che sta lottando contro il tumore al pancreas diagnosticatogli nel gennaio del 2008, ma devo dire che mi sono subito appassionato alle vicende di Charles Barker (interpretato da Swayze), un rozzo, ma efficiente agente dell’FBI che addestra il suo nuovo giovane partner Ellis Dove (interpretato da Fimmel), inconsapevole che questi è stato recrutato per indagare proprio su di lui.

Continua a leggere