Most web browsers send an “Accept-Language” HTTP header which specifies the user’s language preferences. This header will look something like:
Accept-Language: en, fr;q=0.9, de;q=0.8
That is, each language has “q-value” which specifies the strength of the preference. If a q-value is not specified, then it is assumed to be 1.0. Here, English gets a q-value of 1.0, French of 0.9, and German of 0.8.
Q-values are not simply relative preferences; that is, changing the German q-value from 0.8 down to 0.6 could change which language gets served up, even though the order of preferred languages is completely unchanged. HTTP specifies that the “quality” of each translation be multiplied by the client’s corresponding q-value, then the language with the highest resulting value be chosen. That is,
LanguageScore = ClientQValue * TranslationQuality
How does Boss define translation quality for a language? Simple: it just uses the fraction of translatable strings in a given template that have been translated for that language.
Quick example: say a template has 3 translatable strings (in English), and the client q-values are 1.0 for French and 0.5 for English. The language score for English is
EnglishScore = 0.5 * (3 / 3) = 0.5
If two of the three strings are available in French, then
FrenchScore = 1.0 * (2 / 3) = 0.67
And French will be served, because 0.67 is greater than 0.5. But if only one of the three strings is available in French, then
FrenchScore = 1.0 * (1 / 3) = 0.33
And English will be served, because 0.33 is less than 0.5.
One side effect is that if strings in some templates have more translations than other templates, users could see different languages as they navigate the site. Sounds weird, but of course we’re always delivering the best translation to the user that we can. The best thing to do is to translate all your strings, or else override the inferred language by setting the “Content-Language” header based on a user preference.