The difference in your case is in filters being applied to output of these functions.
While bloginfo applies one of these filters:
if ( 'display' == $filter ) {
if ( $url )
$output = apply_filters('bloginfo_url', $output, $show);
else
$output = apply_filters('bloginfo', $output, $show);
}
Function home_url applies this filter:
return apply_filters( 'home_url', $url, $path, $orig_scheme, $blog_id );
Adn finally site_url applies this filter:
return apply_filters( 'site_url', $url, $path, $scheme, $blog_id );
It is true that bloginfo uses one of mentioned functions (home_url and site_url). It is clear from its source code:
function get_bloginfo( $show = '', $filter="raw" ) {
switch( $show ) {
case 'home' : // DEPRECATED
case 'siteurl' : // DEPRECATED
_deprecated_argument( __FUNCTION__, '2.2', sprintf( __('The <code>%s</code> option is deprecated for the family of <code>bloginfo()</code> functions.' ), $show ) . ' ' . sprintf( __( 'Use the <code>%s</code> option instead.' ), 'url' ) );
case 'url' :
$output = home_url();
break;
case 'wpurl' :
$output = site_url();
break;
...
From this piece of code, it is clear that when calling bloginfo(‘home_url’) or bloginfo(‘site_url’), all mentioned filters ale applied. When calling home_url or site_url, bloginfo’s filters are not applied.
The thing is, that qTranslate, probably, hooks only bloginfo’s filters.