Tools

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:

Etymology websites:

Grammar Resources:


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:

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, '&aacute;');
		x = x.replace(/é/g, '&eacute;');
		x = x.replace(/í/g, '&iacute;');
		x = x.replace(/ó/g, '&oacute;');
		x = x.replace(/ú/g, '&uacute;');
		x = x.replace(/ñ/g, '&ntilde;');
		x = x.replace(/ö/g, '&ouml;');
		x = x.replace(/ü/g, '&uuml;');

		x = x.replace(/Á/g, '&Aacute;');
		x = x.replace(/É/g, '&Eacute;');
		x = x.replace(/Í/g, '&Iacute;');
		x = x.replace(/Ó/g, '&Oacute;');
		x = x.replace(/Ú/g, '&Uacute;');
		x = x.replace(/Ñ/g, '&Ntilde;');
		
		x = x.replace(/¿/g, '&iquest;');
		x = x.replace(/¡/g, '&iexcl;');
		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