From dda25c0b517654e05950570cde22f3755b4706d5 Mon Sep 17 00:00:00 2001 From: Pranav Date: Mon, 15 Jun 2026 14:34:52 -0700 Subject: [PATCH] fix(portal): emit valid BCP 47 html lang attribute (#14680) Locales are stored with underscores (e.g. pt_BR), but the HTML lang attribute requires hyphens (pt-BR). Convert via a helper in the public portal layouts. Co-authored-by: Claude Opus 4.8 (1M context) Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> --- app/helpers/portal_helper.rb | 4 ++++ .../layouts/portal.html+documentation.erb | 2 +- app/views/layouts/portal.html.erb | 2 +- spec/helpers/portal_helper_spec.rb | 22 +++++++++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/app/helpers/portal_helper.rb b/app/helpers/portal_helper.rb index 31bfe8632..76e286542 100644 --- a/app/helpers/portal_helper.rb +++ b/app/helpers/portal_helper.rb @@ -41,6 +41,10 @@ module PortalHelper language_map[locale] || locale end + def html_lang_attribute(locale) + locale.to_s.tr('_', '-') + end + def theme_query_string(theme) theme.present? && theme != 'system' ? "?theme=#{theme}" : '' end diff --git a/app/views/layouts/portal.html+documentation.erb b/app/views/layouts/portal.html+documentation.erb index 50374917f..aa26fce7e 100644 --- a/app/views/layouts/portal.html+documentation.erb +++ b/app/views/layouts/portal.html+documentation.erb @@ -1,5 +1,5 @@ - + <%= render 'layouts/portal_head' %> diff --git a/app/views/layouts/portal.html.erb b/app/views/layouts/portal.html.erb index a2b9033bf..ac3f7e574 100644 --- a/app/views/layouts/portal.html.erb +++ b/app/views/layouts/portal.html.erb @@ -1,5 +1,5 @@ - + <%= render 'layouts/portal_head' %> diff --git a/spec/helpers/portal_helper_spec.rb b/spec/helpers/portal_helper_spec.rb index 993399e74..37c7a927c 100644 --- a/spec/helpers/portal_helper_spec.rb +++ b/spec/helpers/portal_helper_spec.rb @@ -1,6 +1,28 @@ require 'rails_helper' describe PortalHelper do + describe '#html_lang_attribute' do + it 'returns the locale unchanged when it has no region suffix' do + expect(helper.html_lang_attribute('en')).to eq('en') + expect(helper.html_lang_attribute(:fr)).to eq('fr') + end + + it 'converts underscores to hyphens for BCP 47 compliance' do + expect(helper.html_lang_attribute('pt_BR')).to eq('pt-BR') + expect(helper.html_lang_attribute(:zh_CN)).to eq('zh-CN') + expect(helper.html_lang_attribute('zh_TW')).to eq('zh-TW') + end + + it 'produces a valid BCP 47 lang attribute for every language shown in the UI' do + bcp47 = /\A[a-z]{2,3}(-[A-Z]{2})?\z/ + + LANGUAGES_CONFIG.each_value do |lang| + locale = lang[:iso_639_1_code] + expect(helper.html_lang_attribute(locale)).to match(bcp47) + end + end + end + describe '#generate_portal_bg_color' do context 'when theme is dark' do it 'returns the correct color mix with black' do