# Buggy code
def numeric_phrase(singular, plural, n, template_var=None):
    """Returns a final locale-specific phrase with pluralisation if necessary
    and grouping of the number.

    This is added to custom gettext keywords to allow us to use as-is.

    Args:
        singular (text_type)
        plural (text_type)
        n (int)
        template_var (text_type)
    Returns:
        text_type

    For example,

    ``numeric_phrase('Add %d song', 'Add %d songs', 12345)``
    returns
    `"Add 12,345 songs"`
    (in `en_US` locale at least)
    """
    num_text = locale.format("%d", n, grouping=True)
    if not template_var:
        template_var = "%d"
        replacement = "%s"
        params = num_text
    else:
        template_var = "%(" + template_var + ")d"
        replacement = "%(" + template_var + ")s"
        params = dict()
        params[template_var] = num_text
    return (
        ngettext(
            singular.replace(template_var, replacement),
            plural.replace(template_var, replacement),
            n,
        )
        % params
    )


# Traceback (UnicodeDecodeError)
=== SYSTEM INFORMATION:
Quod Libet 3.8.1 (e57d03b)
Mutagen 1.35
Python 2.7.12 (default, Nov  7 2016, 12:09:29)  [GCC 6.2.0 32 bit] win32
Platform Windows-7-6.1.7601-SP1
=== STACK TRACE

Traceback (most recent call last):

File "C:\msys64\home\xy\quodlibet\win_installer\_rebuild_root\mingw32\lib\python2.7\site-packages\quodlibet\qltk\quodlibetwindow.py", line 1497, in __set_totals

File "C:\msys64\home\xy\quodlibet\win_installer\_rebuild_root\mingw32\lib\python2.7\site-packages\quodlibet\browsers\_base.py", line 274, in status_text

File "C:\msys64\home\xy\quodlibet\win_installer\_rebuild_root\mingw32\lib\python2.7\site-packages\quodlibet\util\i18n.py", line 291, in numeric_phrase

UnicodeDecodeError: 'utf8' codec can't decode byte 0xa0 in position 1: invalid start byte

=== LOG:
D: 12.278: GStreamerPlayer._end: End song
D: 12.280: util.cover.manager.run: Found local cover from FilesystemCover: <open file u'c:\\users\\user\\music\\logh\\2007_north\\cover.jpg', mode 'rb' at 0x09579b20>
D: 12.284: GStreamerPlayer._end: Next song
D: 12.322: SongFileLibrary._changed(<libraries.SongFileLibrary object at 0x035d76e4 (quodlibet+library+libraries+SongFileLibrary at 0x0321b710)>): Changing 2 items.
D: 12.323: qltk.completion.__update_song: Updating tag model for 2 songs
D: 12.323: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 03.375: config.save: Writing config...
D: 03.391: library.save: Saving all libraries...
D: 17.994: player.gstbe.player.__about_to_finish: About to finish (async)
D: 17.996: player.gstbe.player.__about_to_finish_sync: About to finish (sync)
D: 17.996: player.gstbe.player.__about_to_finish_sync: Select next song in mainloop..
D: 17.997: PlaylistModel.next_ended: Using <Dans l'ordre>.next_implicit() to get next song
D: 17.997: player.gstbe.player.__about_to_finish_sync: ..done.
D: 17.997: player.gstbe.player.__about_to_finish: About to finish (async): done
D: 19.797: player.gstbe.player.__message: Stream EOS
D: 19.797: GStreamerPlayer._end: End song
D: 19.802: GStreamerPlayer._end: Next song
D: 19.943: SongFileLibrary._changed(<libraries.SongFileLibrary object at 0x035d76e4 (quodlibet+library+libraries+SongFileLibrary at 0x0321b710)>): Changing 1 items.
D: 19.944: qltk.completion.__update_song: Updating tag model for 1 songs
D: 19.944: qltk.completion.__update_song: Done updating tag model for 1 songs
D: 29.476: PlaylistModel.set: Filling view model with 8 songs.
D: 45.912: GStreamerPlayer.go_to: Going to <Gtk.TreeIter object at 0x097f571c (GtkTreeIter at 0x0ca2e240)>
D: 45.912: PlaylistMux.go_to: Told to go to <Gtk.TreeIter object at 0x097f571c (GtkTreeIter at 0x0ca2e240)>
D: 45.912: QueueModel.go_to: Told to go to None
D: 45.912: PlaylistModel.go_to: Told to go to <Gtk.TreeIter object at 0x097f571c (GtkTreeIter at 0x0ca2e240)>
D: 45.912: GStreamerPlayer._end: End song
D: 45.923: util.cover.manager.run: Found local cover from FilesystemCover: <open file u'c:\\users\\user\\music\\65daysofstatic\\2013_wild_light\\cover.jpg', mode 'rb' at 0x09579c28>
D: 45.935: GStreamerPlayer._end: Next song
D: 45.984: player.gstbe.player.__message: Recalculate latency
D: 45.986: SongFileLibrary._changed(<libraries.SongFileLibrary object at 0x035d76e4 (quodlibet+library+libraries+SongFileLibrary at 0x0321b710)>): Changing 1 items.
D: 45.987: qltk.completion.__update_song: Updating tag model for 1 songs
D: 45.987: qltk.completion.__update_song: Done updating tag model for 1 songs
D: 03.397: config.save: Writing config...
D: 03.419: library.save: Saving all libraries...
D: 03.419: SongFileLibrary.save(<libraries.SongFileLibrary object at 0x035d76e4 (quodlibet+library+libraries+SongFileLibrary at 0x0321b710)>): Saving contents to u'C:\\Users\\user\\AppData\\Roaming\\Quod Libet\\songs'.
D: 51.139: player.gstbe.player.__about_to_finish: About to finish (async)
D: 51.140: player.gstbe.player.__about_to_finish_sync: About to finish (sync)
D: 51.140: player.gstbe.player.__about_to_finish_sync: Select next song in mainloop..
D: 51.140: PlaylistModel.next_ended: Using <Dans l'ordre>.next_implicit() to get next song
D: 51.140: player.gstbe.player.__about_to_finish_sync: ..done.
D: 51.141: player.gstbe.player.__about_to_finish: About to finish (async): setting uri
D: 51.141: player.gstbe.player.__about_to_finish: About to finish (async): done
D: 52.240: player.gstbe.player.__message: Stream changed
D: 52.240: GStreamerPlayer._end: End song
D: 52.242: util.cover.manager.run: Found local cover from FilesystemCover: <open file u'c:\\users\\user\\music\\65daysofstatic\\2013_wild_light\\cover.jpg', mode 'rb' at 0x09579d30>
D: 52.246: GStreamerPlayer._end: Next song
D: 52.263: SongFileLibrary._changed(<libraries.SongFileLibrary object at 0x035d76e4 (quodlibet+library+libraries+SongFileLibrary at 0x0321b710)>): Changing 2 items.
D: 52.264: qltk.completion.__update_song: Updating tag model for 2 songs
D: 52.264: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 03.419: config.save: Writing config...
D: 03.435: library.save: Saving all libraries...
D: 08.865: player.gstbe.player.__about_to_finish: About to finish (async)
D: 08.866: player.gstbe.player.__about_to_finish_sync: About to finish (sync)
D: 08.866: player.gstbe.player.__about_to_finish_sync: Select next song in mainloop..
D: 08.866: PlaylistModel.next_ended: Using <Dans l'ordre>.next_implicit() to get next song
D: 08.866: player.gstbe.player.__about_to_finish_sync: ..done.
D: 08.867: player.gstbe.player.__about_to_finish: About to finish (async): setting uri
D: 08.867: player.gstbe.player.__about_to_finish: About to finish (async): done
D: 09.969: player.gstbe.player.__message: Stream changed
D: 09.969: GStreamerPlayer._end: End song
D: 09.974: util.cover.manager.run: Found local cover from FilesystemCover: <open file u'c:\\users\\user\\music\\65daysofstatic\\2013_wild_light\\cover.jpg', mode 'rb' at 0x09579548>
D: 09.984: GStreamerPlayer._end: Next song
D: 10.000: SongFileLibrary._changed(<libraries.SongFileLibrary object at 0x035d76e4 (quodlibet+library+libraries+SongFileLibrary at 0x0321b710)>): Changing 2 items.
D: 10.001: qltk.completion.__update_song: Updating tag model for 2 songs
D: 10.001: qltk.completion.__update_song: Done updating tag model for 2 songs
D: 03.441: config.save: Writing config...
D: 03.456: library.save: Saving all libraries...
D: 03.464: config.save: Writing config...
D: 03.483: library.save: Saving all libraries...
D: 30.235: PlaylistModel.set: Filling view model with 0 songs.
D: 30.695: PlaylistModel.set: Filling view model with 13086 songs.
D: 30.970: PlaylistModel.set: Filling view model with 13086 songs.
D: 31.121: PlaylistModel.set: Filling view model with 3 songs.
D: 52.019: PlaylistModel.set: Filling view model with 3 songs.
D: 58.217: PlaylistModel.set: Filling view model with 3721 songs.

# Fixed code
def numeric_phrase(singular, plural, n, template_var=None):
    """Returns a final locale-specific phrase with pluralisation if necessary
    and grouping of the number.

    This is added to custom gettext keywords to allow us to use as-is.

    Args:
        singular (text_type)
        plural (text_type)
        n (int)
        template_var (text_type)
    Returns:
        text_type

    For example,

    ``numeric_phrase('Add %d song', 'Add %d songs', 12345)``
    returns
    `"Add 12,345 songs"`
    (in `en_US` locale at least)
    """
    num_text = locale_format("%d", n, grouping=True)
    if not template_var:
        template_var = "%d"
        replacement = "%s"
        params = num_text
    else:
        template_var = "%(" + template_var + ")d"
        replacement = "%(" + template_var + ")s"
        params = dict()
        params[template_var] = num_text
    return (
        ngettext(
            singular.replace(template_var, replacement),
            plural.replace(template_var, replacement),
            n,
        )
        % params
    )