Why TalkBack keeps switching accents

Here’s an interesting issue. Imagine a page, written entirely in English. The markup is setting the page language correctly using <html lang="en">. The code is clean. HTML is valid. Yet when you test it with TalkBack, it’s reading some of the content in a completely different accent.

Weird, right?

It’s an issue I’ve noticed only tends to happen on short strings of text, rather than full paragraphs. I’ll maybe hear it on a form label, a button, or a lede sentence which introduces an article. Usually, it’s the kind of text that sits alone, rather than inside of a long block of prose content.

If you’re like me, you’ll probably spend an annoying amount of time inspecting the DOM trying to figure out why. And, like me, you’ll likely find there’s no stray lang attributes, no hidden characters, and no broken code. It’s all just seemingly ordinary HTML, written in the same English as everything else on the page.

So why does it happen? Well, I’ve found the cause is likely the same single attribute we’ve already checked, at the very top of the page. It turns out that we can unwittingly give Chrome permission to meddle with the language if we’re not specific enough. And, annoyingly, once you know about it, the fix is only adding three characters!

English is not always just English

On most websites, we declare the language of the page as English by using the following attribute:

<html lang="en">

This passes 3.1.1 Language of Page. It will also pass every popular automated accessibility checker. But, it’s the reason for this particular bug, and it took me a bit of digging to understand why.

Here’s the bit I didn’t know, so I’m assuming some people reading this won’t either. Chromium runs its own language detection for accessibility over your page content, after it loads.

It makes its own assumptions about the language which is used for each individual node. Then, it decides what to expose to assistive technologies. The final output may be what you declared in your markup, or it may be what Chrome detected, or it may be a mashup of the two. So, your lang attribute is a part of that decision, but not an unbreakable rule.

Screen readers, like TalkBack, honour whatever language comes out of the merge, not just what you declared in your lang attributes, and this is what can cause it to switch voices on a particular node.

This is genuinely useful for screen reader users when a page really does mix languages, and they’re not very well defined in the markup. It papers over the cracks left by developers, and creates a better user experience for the person using the screen reader. But, it appears that automatic language detection is unreliable on short strings, and can default to American English when it is unsure. A label, like “Search this site”, doesn’t have any spelling cues, like “colour” rather than “color”, so it’s more likely the browser will override it.

This is why the bug is challenging to figure out. The page is English, the markup says English, and TalkBack still reads all the nodes in English. But, sometimes it uses its American voice, and sometimes it uses its British one, because the Chrome language detector took a best guess, and our generic lang="en" didn’t give it enough of a reason not to change it.

The fix

It’s probably clear by this point what the fix is. But, in case you’re still not sure, it’s literally adding three characters to the lang attribute. For example:

<html lang="en-GB">

<!-- Or -->

<html lang="en-US">

That’s literally it. Once I did this, the bug disappeared. By using a specific regional value instead of the generic en one, it then anchored every node on the page to a single accent and voice.

It appears Chrome’s language detector has much less wiggle room to make its own assumptions when you’ve already said precisely which version of English your page is using. So, when it detects English, it just parses it all as the same regional version.

This probably isn’t really a bug fix, though I realise I’ve been referring to it as that throughout this entire post. It’s probably just a side effect, and we’re now just being more accurate. Like most people, I’ve often just defaulted to using lang="en", but, as my content is written in British English, I should probably be using en-GB anyway. Though, arguably, as a Geordie who only managed a “B” in GCSE English, it’s debatable whether I use British English at all!

If you write in American English, the same logic applies. Use en-US, not just en. And, the same would apply for any other language with regional variants. For example, Brazilian Portuguese (pt-BR) versus European Portuguese (pt-PT), or Quebec French (fr-CA) versus European French (fr-FR).

Automated tools will likely never catch this

This is one of those quirky issues that lives outside the reach of automated testing tools. Using lang="en" is completely valid, well-formed, and complies with WCAG. Most tools, like axe-core, will not flag it, because there’s nothing wrong on a technical level. It’s a niche usability issue.

The only way you’ll find it is using a screen reader. Which is the point I seem to always end up circling back to in every post. WCAG compliance is a floor, not a ceiling. It cannot tell you what the true user experience is actually like.

If you want to hear it for yourself, grab an Android phone, turn on TalkBack, and listen to a few pages that declare bare lang="en". You may be surprised to hear how often the voice switches between a British and an American accent.

Final thoughts

Language keeps turning out to be one of those awkward areas where what is good, and what is great, are sometimes further apart than we think. I’ve written before about alt text that never gets translated, which is pretty much the same story from a different angle. The visible content gets all the care, and the accessible experience is quietly ignored.

So, three quick things I recommend we all do in future:

  1. Always use a regional subtag: Use en-GB or en-US, depending on what version of English you write in

  2. Always mark language changes in the page: 3.1.2 Language of Parts still applies, but I’d say if you’re putting an American quote on a British English website, this now deserves a lang="en-US" attribute, because TalkBack will actually use it

  3. Test with a real screen reader: This entire issue is invisible to automated tools, but it only takes about two minutes with TalkBack to find it

As always, I hope this was useful!

Thanks,
Craig