Accessibility proposal: add 'lang' attribute to generated views

Hi,

I’d like to propose a small change that could make a big difference for the accessibility of Rails apps - setting a default language for all generated HTML.

Under the Web Content Accessibility Guidelines it’s better to have something set as a default language than nothing at all. This could be set to lang="en" by default, and it would be up to developers to change that if necessary.

Adding the lang attribute to your page has lots of benefits, which you can read about here.

There are a few templates that already have the lang attribute, but application.html.erb and a good few other templates don’t.

3 Likes

It could be set up in the template to default to I18n.locale

1 Like

In order to fix this problem you have fix two tags for your tool to stop pointing accessibility error. You have to set both “lang” as well as “xml:lang” tag. One way to achieve this through pure Javascript is below. I am proposing this solution as it is independent of any platform.

(function() {
       document.getElementsByTagName('html')[0].setAttribute('lang', 'en-US');
       document.getElementsByTagName('html')[0].setAttribute('xml:lang','en-US');
})(); 

You may replace ‘en’ with language of your choice to correctly point the correct language in place.

This looks like it would be an easy fix, indeed. However, there are already a few templates that define lang and a few that don’t, so it would be nice to keep it consistent.

I agree that JavaScript could help easily target all lang attributes in your code, however this is an attribute that belongs in the HTML world. Meaning if I wanted to change the lang in my code, I’d go straight to my HTML rather than thinking to dig through JavaScript to find where it’s set. And personally, I would prefer not to introduce JavaScript unless I had to.

1 Like

@metamoni Great suggestion, do you have an idea in mind where we could add the lang attribute? Would you be interested in working on a patch?

@zzak the lang attribute would need to be added to every tag. As far as I know, in a newly generated app, this means: application.html.erb, 404.html, 422.html and 500.html. At least they’re the files I’m seeing in one of my recently created projects. It would also need to be added to any templates that get generated automatically, and there are a good few of them in the code base. I think the change could look like:

<html lang=<%= I18n.default_locale %>>

This is set to :en by default, and if you want to set it to something else I believe it’s recommended to do that in the environment.rb file, like so:

I18n.default_locale = :de

I’d be happy to work on it, yes :slightly_smiling_face:, if the community feels like it’s a useful addition and it gets approved.

From what I can tell, these places would have to change:

railties/lib/rails/generators/erb/mailer/templates/layout.html.erb.tt:2:<html>
railties/lib/rails/generators/rails/app/templates/app/views/layouts/application.html.erb.tt:2:<html>
railties/lib/rails/generators/rails/app/templates/app/views/layouts/mailer.html.erb.tt:2:<html>
railties/lib/rails/generators/rails/app/templates/public/404.html:2:<html>
railties/lib/rails/generators/rails/app/templates/public/422.html:2:<html>
railties/lib/rails/generators/rails/app/templates/public/500.html:2:<html>
railties/lib/rails/generators/rails/plugin/templates/app/views/layouts/%namespaced_name%/application.html.erb.tt:2:<html>
railties/lib/rails/templates/layouts/application.html.erb:2:<html lang="en">
railties/lib/rails/templates/rails/mailers/email.html.erb:2:<html><head>
railties/lib/rails/templates/rails/welcome/index.html.erb:2:<html>

It seems other parts are already using lang=“en” default. So I wonder if we just use that, because i18n is optional right? I guess we could detect it and use I18n.default_locale if it’s available…

Since I18n ships with Rails, there will always be a default locale. I’m not sure whether you can remove it, to be honest :thinking:I just tried to delete it from a freshly created Rails app and got this error:

The i18n gem is not available. Please add it to your Gemfile and run bundle install
/Users/monicamateiu/.asdf/installs/ruby/3.0.0/lib/ruby/gems/3.0.0/gems/bootsnap-1.7.2/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:23:in `require': cannot load such file -- i18n (LoadError)

I’ll investigate to find out if there’s a way to turn it off, however one thing I wouldn’t want to have is a mix of both. The solution needs to be consistent, all lang attributes need to be set either to I18n.default_locale, or to another default_locale attribute we’d set somewhere in the app, if I18n isn’t available.

Yup, it looks like i18n is a dependency of activesupport, so it can’t be turned off. This means I18n.default_locale should always be available. Unless configured to a different language, it’ll be set to :en :slight_smile:

Ok, so if we’re assuming i18n is available everywhere then it makes sense to bake that into the templates.

One side-effect of using default_locale is what if the user changes their locale? The <html> tag would still have the same locale. Is that a problem?

Hmm that’s a great question, @zzak!

From an accessibility point of view, we’d have lang set to something, which is already an improvement. However, we want this lang to reflect the correct language choice, and you’re right, you can have default_locale and locale set to different languages (I didn’t know this until just now, as I don’t have a lot of experience in this area).

It would probably be safer to set lang = I18n.locale, as @soulcutter rightly suggested. Is there anyone we could ask to confirm whether this is a good solution? It sounds right to me, but as I said I’m a bit of a novice and it would be great to make sure before I start working on this.

@metamoni I think using I18n.locale is perfectly fine, sorry I missed this earlier.

The I18n.locale defaults to I18n.default_locale which defaults to : en .

I’m feeling pretty confident about this change, as we already discovered lang="en" already exists in railties app. One thing I’m wondering is what is the difference between that template and this one. I think we could test it like here.

That said, each of the places I mentioned before are somewhat unique. For example, the 404 page is not generated but just copied (so we don’t have access to ERB) afaict.

So I think it would be best to start small, maybe this one: (railties/lib/rails/templates/layouts/application.html.erb:2:) and not the static files or “generators” files yet until you get some feedback on that first PR.

1 Like

That sounds great, thanks for your help @zzak

Np! Let me know when you pick this up if you have any questions or concerns.

1 Like