Translation tools
Bilingual or multilingual dictionaries and language resources:
- WordReference: Spanish-English – Bilingual dictionary. Also includes a monolingual Spanish dictionary and thesaurus. Recommended.
- Collins Dictionary: Inglés-Español – Bilingual dictionary. Recommended.
- Linguee.com – This website allows you to input a phrase, then cross-references occurrences of the phrase across media with available translations. This allows you to see how real people have translated the phrase before. It works best if you are already at least semi-bilingual. Recommended for advanced students.
- Bab.La: Loving Languages – Translation dictionary with automatic examples from the media.
Monolingual dictionaries and resources:
- Thesaurus.com (English) – Useful for finding the word with the right connotation.
- Diccionario Latinoamericano de la Lengua Española – Latin American monolingual Spanish dictionary
- RAE.es – the Royal Spanish Academy’s monolingual Spanish dictionary
- The Free Spanish Dictionary – monolingual Spanish dictionary
- Conjugation.org and WordReference Spanish Verb Conjugation – I use verb conjugation websites as spell checkers also.
- SpanishChecker.com – spellchecker provides tips to manually check homophones and accents.
- One Look’s Reverse Dictionary – Also for finding words.
Etymology websites:
- Diccionario Etimológico: Origen de las Palabras – Spanish language etymology website from Chile. To search, type your word in the box next to the button that says Busca! (Search!)
- El Castellano: La Página del idioma español – Spanish language etymology website from Spain. To search, scroll down to the text box Buscador (Search Engine) and type the word you want, then elect to search “www.elcastellano.org” not “web” and hit the Enviar (Send) button.
- Online Etymology Dictionary – for English. If you don’t find it here, use Merriam-Webster.
Grammar Resources:
- About.com: Spanish Homophones – Solo and sólo are both pronounced SO-lo, so why does one need an accent? Look up Spanish homophones (words pronounced the same way).
- Update 2010: the RAE (Royal Spanish Academy) proposed Spanish grammar rules changes such as removing useless accents, so sólo doesn’t need an accent anymore.
- Not everyone is happy about all the changes: “Rebelling Against Spain, This Time With Words“, New York Times, Nov 25, 2010.
- Some of the changes were rolled back or made optional, including whether we need to distinguish between solo and sólo.
Behind the scenes coding/web tools
Editing steps to consider:
- Replace accented characters and special grammar characters with their html code (e.g. á for á) to prevent special characters from becoming boxes in some browsers. If you see any character boxes in songlations.com, it’s because I made edits after my typical cleanup step. Let me know and I’ll fix them!
- Capitalize the beginning of each line.
- Add a text block header before the lyrics (e.g. “<h2>Translation:</h2>”) to reduce typing.
Web tools:
- RegEx101.com for regular expression testing – I use this to practice text editing patterns for the code I use to clean up lyrics and special characters before posting.
- Remove or replace line breaks
Programming languages:
JavaScript – To help me format posts before I start translating, I wrote an HTML document with textbox inputs for various parts of the post (title, title translation, YouTube link, genre, country, lyrics, etc). I made buttons for JavaScript-transformed outputs that I can paste into WordPress. It saves me time so I don’t need to manually format everything. To use, copy the following code to a text editor, save with extension .html, and open in a web browser. Version 2022.11 below:
<!DOCTYPE html UBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="es">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- tells IE to use the latest compatibility mode -->
<meta charset="utf-8">
<title>Songlations post formatting with JavaScript</title>
<style>
.column {
float: left;
width: 50%;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
.row {
display: flex;
}
.column {
flex: 50%;
}
</style>
</head>
<body>
<h1>Songlations.com Text Transformation Tools</h1>
<button type="button" onClick="charCodesButton();">Just Special Characters</button>
<button type="button" onClick="transform1();">Simple Format</button>
<button type="button" onClick="transform2();">Songlations.com Format</button>
<br /><br />
<div class="row">
<div class="column">
<b>Top Lines:</b><br />
<textarea rows = "2" cols = "65" id="TitleByArtist">
Title by Artist</textarea><br />
<textarea rows = "2" cols = "65" id="TitleTranslation">
Title Translation</textarea><br />
<textarea rows = "2" cols = "26" id="Album">
Album</textarea>
<textarea rows = "2" cols = "25" id="AlbumTranslation">
AlbumTranslation</textarea>
<textarea rows = "2" cols = "7" id="AlbumYear">
Year</textarea><br />
<textarea rows = "2" cols = "65" id="Style">
Style</textarea><br />
<textarea rows = "2" cols = "65" id="Country">
Country</textarea><br />
<textarea rows = "2" cols = "65" id="url">
YouTube url</textarea><br />
<br />
<b>Input:</b><br />
<textarea rows = "32" cols = "65" id="myInput">
Enter song lyrics here...
for example:
Te esperaré,
Te esperaré en las sombras,
Siempre allí estaré.
</textarea>
</div>
<div class="column">
<b>Output:</b><br />
<textarea rows = "32" cols = "65" id="myOutput">
Formatted song lyrics...
</textarea></div>
</div> <!-- end row-->
<!-- code here -->
<script>
//Add HTML special character codes only
function charCodes(){
// Get the input value and define variables
var inputVal = document.getElementById("myInput").value;
var x = "";
// Edit the input
x = inputVal.replace(/á/g, 'á');
x = x.replace(/é/g, 'é');
x = x.replace(/í/g, 'í');
x = x.replace(/ó/g, 'ó');
x = x.replace(/ú/g, 'ú');
x = x.replace(/ñ/g, 'ñ');
x = x.replace(/ö/g, 'ö');
x = x.replace(/ü/g, 'ü');
x = x.replace(/Á/g, 'Á');
x = x.replace(/É/g, 'É');
x = x.replace(/Í/g, 'Í');
x = x.replace(/Ó/g, 'Ó');
x = x.replace(/Ú/g, 'Ú');
x = x.replace(/Ñ/g, 'Ñ');
x = x.replace(/¿/g, '¿');
x = x.replace(/¡/g, '¡');
x = x.replace(/[“”]/g, '\"'); // replace curly quotes with non-curly
// Display the values
myInput.value = inputVal;
/* myOutput.value = x; */
return x;
}
//=====================================================
//Simple format: replace special characters, add line breaks, and add HTML tags around defined text
function songTransform(){
// Define variables
var x = "";
// Edit the input
x = charCodes(); // replace special characters with HTML codes
x = x.replace(/^\s+|\s+$/g, ''); // remove leading and trailing spaces from the text block
x = x.replace(/\n[\s+]/g, '\n'); // 3/12/2022 to trim each line
x = x.replace('Style:', '<b>Style:</b>');
x = x.replace('Album:', '<b>Album:</b>');
x = x.replace('Country:', '<b>Country:</b>');
x = x.replace('Countries:', '<b>Countries:</b>');
x = x.replace('Listen:', '<b>Listen:</b>');
/* x = x.replace('\n', '<br />\n'); */
x = x.replace(/[\n\r]/g, '<br />\n');
x = x.replace('Translation:', '<h2>Translation:</h2>');
x = x.replace('Translation Notes:', '<h2>Translation Notes:</h2>');
x = x.replace('About:', '<h2>About:</h2>');
/* x = x.replace('', '');
x = x.replace('', '');
x = x.replace('', ''); */
// Result for output box
return x;
}
//=====================================================
// Songlations.com post formatting
function songTransformMore() {
// pick up top line variables
var Title = document.getElementById("TitleByArtist").value;
var TitleTranslation = document.getElementById("TitleTranslation").value.replace(/["]+/g, '');
var Album = document.getElementById("Album").value;
var AlbumTranslation = document.getElementById("AlbumTranslation").value.replace(/["]+/g, '');
var Year = document.getElementById("AlbumYear").value;
var Style = document.getElementById("Style").value;
var Country = document.getElementById("Country").value;
var YouTubeURL = document.getElementById("url").value;
// format title ---------------------------------
var formatTitle = Title + ', English translation of lyrics\n\n'
// combine top lines ----------------------------
//var extraForFront = '<b>"" Lyrics</b><br /> \n<b>Album:</b><br /> \n<b>Style:</b><br /> \n<b>Country:</b><br /> \n<b>Listen:</b> YouTube<br />\n \n<h2>Translation:</h2>\n\n';
var extraForFront = '<b>"' + TitleTranslation + '" Lyrics</b><br /> \n<b>Album:</b> <i>' + Album + '</i> (' + AlbumTranslation + '), ' + Year +
'<br /> \n<b>Style:</b> ' + Style + '<br /> \n<b>Country:</b> ' + Country +
'<br /> \n<b>Listen:</b> <a href="' + YouTubeURL + '" target="_blank">' +
'YouTube</a><br />\n\n' + YouTubeURL + '\n' +
'\n<h2>Translation:</h2>\n\n';
// bottom lines -----------------------------------
var extraForEnd = '<br />\n \n<h2>Translation Notes:</h2>\n';
// output -------------------
x = songTransform()
y = formatTitle + extraForFront + '<i>' + x + '</i>' + extraForEnd;
return y;
}
//=====================================================
// Define buttons
function charCodesButton() {
myOutput.value = charCodes()
}
function transform1() {
myOutput.value = songTransform()
}
function transform2() {
myOutput.value = songTransformMore()
}
//=====================================================
</script>
</body>
</html>
Perl – Great for text editing (the best!) but opening and closing input and output files got annoying after a while so I switched to JavaScript, see code above. Below is my last Perl version (2016.11) which assumes an input file song_input.rtf saved in the same location as the code, and native Windows program wordpad.exe available to open it. You can comment out the system() functions and just manually edit the input file if you don’t have WordPad.
More details at my old LiveJournal site’s resources page.
#!/pkg/bin/perl -w
# Formatting script for songlations.livejournal.com posts.
# Place the raw song text into song_input.txt
# Run program. Edited text will be in song_output.txt
# Author: Cairaguas Gonzalez <cairaguas@gmail.com>
# Last modified: November 15, 2016
use warnings; #this replaces -w in Perl 5.6.x and above
use Win32::Console::ANSI
# http://stackoverflow.com/questions/700187/unicode-utf-ascii-ansi-format-differences
print "\nSONG_TRANSFORM by Cairaguas: \nIf WordPad.exe is not available, choose NO for all prompts to \nopen files and instead manually open and edit the text files \nin the folder with the Perl script.\n\n";
print "Open song_input.txt now? (y=1/n=0)\n";
$opennow = <>;
######################################################################
# INITIAL SONG INPUT AND DECISION OF TRANSFORMATION TYPE
if ($opennow == 1)
{
system("start wordpad.exe song_input.txt"); # This opens the input file in the foreground using WordPad.
print "Opening... \n";
}
else
{ print "Continuing with existing song_input.txt.\n";
}
print "Input song text, save, and close WordPad.
\nType 1 for simple transformation (just capitalization).\nType 3 for Songlations format transformation.\nType 5 for changing special characters to HTML code.\n";
$continue = <>; #This requests input from user.
#Press ENTER when input is finished.
open (IN, "<:encoding(Windows-1252)", "song_input.txt") or die("Could not open file song_input.txt from Perl folder."); #open file for reading
open (OUT, ">:encoding(Windows-1252)", "song_output.txt") or die("Could not open song_output.txt from Perl folder."); #open file for writing
######################################################################
# SIMPLE TRANSFORMATION
if ($continue == 1)
{
while ($line = <IN>)
{
chomp $line; #removes line break at end of string
if ($line =~ m/^http/)
{print OUT "$line\n";}
# do not capitalize url
# ^ is an anchor character, requires match to be at the beginning
elsif (($line =~ m/^[^a-zA-Z]/) && ($line !~ m/^\<[ibu]\>/))
# first char not letter character, not tag
# could also use \W to match a non-word character
{
$first = substr($line,0,1); # first character
$rest = substr($line,1); # rest of the string
print OUT "$first\u$rest\n";
}
elsif ($line =~ m/^\<[ibu]\>[^a-zA-Z]/)
# if line begins with tag preceding non-letter character
# not currently working for quotation marks and not sure why
{
$first = substr($line,0,4); # grab the tag and next character
$rest = substr($line,4); # grab the rest
print OUT "$first\u$rest\n";
}
elsif ($line =~ m/^\<[ibu]\>[a-zA-Z]/)
# if line begins with italics or bold or underline tag
{
$first = substr($line,0,3); # grab the <i> or <b> or <u> tag
$rest = substr($line,3); # grab the rest
print OUT "$first\u$rest\n";
}
else
{print OUT "\u$line\n";} # \u makes next letter uppercase
}
}
######################################################################
# COMPLEX TRANSFORMATION
elsif ($continue == 3)
{
print OUT ", English translation of lyrics \n\n";
print OUT "<b>\"\"<\/b> \n";
print OUT "Album: <i><\/i> \n";
print OUT "Style: \n";
print OUT "Country: \n\n";
print OUT "<b><u>Listen:<\/u><\/b>\r\n\n\n";
print OUT "<lj-spoiler text=\"Expand embedded video\"><\/lj-spoiler>\n\n";
print OUT "<b><u>Translation:<\/u><\/b> \n\n \n\n";
while ($line = <IN>)
{
if (($prevline !~ m/[a-zA-Z]/) && ($line !~ m/(Chorus|chorus)/) && ($prevline !~ m/^(---)/))
#If the previous line was empty, the current line isn't a chorus line, or following a dash
#This prevents double <i> after a dash line
{ print OUT "<i>";
}
if (($line !~ m/[a-zA-Z]/) && ($prevline =~ m/[a-zA-Z]/)) #If the line was empty.
{ print OUT "</i>\n$line";
#to do: rewrite so it doesn't do this before Chorus line
}
else #the current line isn't a line break
{
if ($prevline =~ m/[a-zA-Z]/)
{print OUT "\n";}
#adds line break as long as it's not after the <i> added above
chomp($line);
if ($line =~ m/^(http|---)/)
{print OUT "\n$line\n";}
# do not capitalize url; does not add italics to dash lines
# ^ is an anchor character, requires match to be at the beginning
elsif ($line =~ m/^(Chorus|chorus)/)
{
print OUT "\n<b>Chorus<\/b>\n<i>";
}
# encloses "chorus" line in bold tags and begins italics tag
# warning: removes anything else on the same line
elsif (($line =~ m/^[^a-zA-Z]/) && ($line !~ m/^\<[ibu]\>/) && ($line !~ m/^(Chorus|chorus)/))
# first char not letter character, not tag
# could also use \W to match a non-word character
{
$first = substr($line,0,1); # first character
$rest = substr($line,1); # rest of the string
print OUT "$first\u$rest";
}
elsif ($line =~ m/^\<[ibu]\>[^a-zA-Z]/)
# if line begins with tag preceding non-letter character
# not currently working for quotation marks and not sure why
{
$first = substr($line,0,4); # grab the tag and next character
$rest = substr($line,4); # grab the rest of the line
print OUT "$first\u$rest";
}
elsif ($line =~ m/^\<[ibu]\>[a-zA-Z]/)
# if line begins with italics or bold or underline tag
{
$first = substr($line,0,3); # grab the <i> or <b> or <u> tag
$rest = substr($line,3); # grab the rest
print OUT "$first\u$rest";
}
else
{print OUT "\u$line";} # \u makes next letter uppercase
}
$prevline = $line; #still inside the while loop
last if eof(IN); #breaks the while loop
} #ends while loop
print OUT "<\/i>\n\n" . "<b><u>Translation Notes:<\/u><\/b>\n\n<\/lj-cut>";
} #ends complex transformation script block
######################################################################
# ACCENT AND SPECIAL CHARACTER TO HTML CODE
elsif ($continue == 5)
{
while ($line = <IN>)
{
$line =~ s/\xE1/\á\;/g;
$line =~ s/\xE9/\é\;/g;
$line =~ s/\xED/\í\;/g;
$line =~ s/\xF3/\ó\;/g;
$line =~ s/\xFA/\ú\;/g;
$line =~ s/\xF1/\ñ\;/g;
$line =~ s/\xA1/\¡\;/g;
#see: https://en.wikipedia.org/wiki/Windows-1252
print OUT $line;
# last if eof(<IN>);
}
}
else {print OUT "else was used 456"};
######################################################################
# FINISHED TRANSFORMATIONS
print "\nTransforming...\nDone. \nTransformed text is located in song_output.txt. \n\n";
close (IN);
close (OUT);
print "Open song_output.txt now? (y=1/n=0).\n";
$opennow = <>;
if ($opennow == 1)
{
system("start wordpad.exe song_output.txt");
# This opens the ouput file in the foreground using WordPad.
}
else
{
print "Goodbye.\n";
}
# http://perldoc.perl.org/perlre.html#Regular-Expressions
# http://www.pjb.com.au/comp/diacritics.html
# http://users.cs.cf.ac.uk/Dave.Marshall/PERL/node79.html
# http://www.w3schools.com/charsets/ref_utf_dingbats.asp
# different encodings: http://htmlpurifier.org/docs/enduser-utf8.html
Last edited: February 25, 2023