some tidying up and fuller comments; no logic changes
fix for bug in LanguageRouteDecorator.GetRouteData: trim of language suffix was not happening because of case-sentivity of TrimEnd method. Modified EndsWithAnyIgnoreCase extension to facilitate the fix.
Modification such that template PO files (where all msgstr elements are empty) are considered as unavailable. These .PO files are generated by the gettext merge mechanism as a result of the CreateEmptyMessages mechanism and so duping the GetLanguageIfAvailable into thinking valid translation are available when they aren't. At least one msgstr must now exist in a PO file for it to be used.
Refactoring after previous change to GetLanguageIfAvailable.
LocalizingService: Factored out cachekey generation to ensure consistency, notably to ensure it is lowercase.
Tidied up comment: Tested with a one-char msgstr entry and it does work.
Removed unnecessary lock