Skip to content

Commit 23e336c

Browse files
committed
Language: lang attribute compliant with WCAG 2.0 #5679
1 parent ab6f49c commit 23e336c

File tree

10 files changed

+61
-25
lines changed

10 files changed

+61
-25
lines changed

assets/js/legacy/app.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ global.$ = global.jQuery = $
99

1010
//Routing.setRoutingData(routes);
1111

12-
const locale = document.querySelector("html").lang
12+
const locale = document.documentElement.dataset.lang
1313
// moment
1414
const { DateTime } = require("luxon")
1515
window.luxon = global.luxon = DateTime

assets/js/legacy/free-jqgrid.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'free-jqgrid';
22
import 'free-jqgrid/css/ui.jqgrid.bootstrap4.css';
33

4-
let locale = document.querySelector('html').lang;
4+
let locale = document.documentElement.dataset.lang.split("-")[0]
55

66
const langs = [
77
'ar', 'bg', 'bs', 'ca', 'cn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fr', 'gl', 'he', 'hr', 'hu', 'id',

assets/vue/composables/locale.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export function useLocale() {
1414
const cidReqStore = useCidReqStore()
1515
const courseSettingsStore = useCourseSettings()
1616

17-
const appLocale = ref(document.querySelector("html").lang)
17+
const appLocale = ref(document.documentElement.dataset.lang)
1818

1919
const localeList = computed(() => {
2020
const list = {}
@@ -68,7 +68,7 @@ export function useLocale() {
6868
* @type {{originalName: string, isocode: string}}
6969
*/
7070
const currentLanguageFromList =
71-
languageList.find((language) => document.querySelector("html").lang === language.isocode) || defaultLanguage
71+
languageList.find((language) => document.documentElement.dataset.lang === language.isocode) || defaultLanguage
7272

7373
/**
7474
* @param {string} isoCode
@@ -99,9 +99,9 @@ export function useLocale() {
9999
if (!iso) return { db: "", bcp47: "", parent: "" }
100100
const u = String(iso).trim()
101101
return {
102-
db: u.replace("-", "_"), // pt-BR -> pt_BR (DB)
103-
bcp47: u.replace("_", "-"), // pt_BR -> pt-BR (BCP-47)
104-
parent: u.split(/[-_]/)[0], // pt_BR -> pt
102+
db: u.replace("-", "_"), // pt-BR -> pt_BR (DB)
103+
bcp47: u.replace("_", "-"), // pt_BR -> pt-BR (BCP-47)
104+
parent: u.split(/[-_]/)[0], // pt_BR -> pt
105105
}
106106
}
107107

@@ -112,7 +112,7 @@ export function useLocale() {
112112
function getLanguageName(iso, displayLocale = null) {
113113
if (!iso) return "-"
114114
const tag = String(iso).replace("_", "-")
115-
const ui = displayLocale || appLocale.value || document.documentElement.lang || "en"
115+
const ui = displayLocale || appLocale.value || document.documentElement.dataset.lang || "en"
116116
try {
117117
const dn = new Intl.DisplayNames([ui], { type: "language" })
118118
return dn.of(tag) || iso.toUpperCase()
@@ -144,12 +144,7 @@ export function useLocale() {
144144
if (!row && bcp47 !== db) row = await hit(bcp47)
145145
if (!row && parent && parent !== db) row = await hit(parent)
146146

147-
const name =
148-
row?.originalName ||
149-
row?.original_name ||
150-
row?.englishName ||
151-
row?.english_name ||
152-
iso.toUpperCase()
147+
const name = row?.originalName || row?.original_name || row?.englishName || row?.english_name || iso.toUpperCase()
153148

154149
__apiLangCache.set(iso, name)
155150
return name

assets/vue/i18n.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ const messages = loadLocaleMessages()
6060

6161
// Prefer previously chosen locale, otherwise <html lang>, otherwise "en"
6262
const stored = typeof localStorage !== "undefined" ? localStorage.getItem("app_locale") : null
63-
const initialHtmlLocale = stored || document.documentElement?.lang || "en"
63+
const initialHtmlLocale = stored || document.documentElement.dataset?.lang || "en"
6464
const initial = resolveBestLocale(initialHtmlLocale, messages)
6565

6666
// NOTE: do NOT create runtime aliases; use the resolved bundle directly
@@ -81,7 +81,7 @@ export function setLocale(code) {
8181
i18n.global.locale.value = target.resolved // switch to an existing bundle
8282

8383
if (typeof document !== "undefined") {
84-
document.documentElement.lang = target.resolved
84+
document.documentElement.dataset.lang = target.resolved
8585
}
8686
if (typeof localStorage !== "undefined") {
8787
localStorage.setItem("app_locale", target.resolved)

src/CoreBundle/EventListener/TwigListener.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Chamilo\CoreBundle\EventListener;
88

99
use Chamilo\CoreBundle\Helpers\AccessUrlHelper;
10+
use Chamilo\CoreBundle\Helpers\LanguageHelper;
1011
use Chamilo\CoreBundle\Helpers\UserHelper;
1112
use Chamilo\CoreBundle\Repository\LanguageRepository;
1213
use Symfony\Component\HttpKernel\Event\ControllerEvent;
@@ -24,6 +25,7 @@ public function __construct(
2425
private readonly LanguageRepository $languageRepository,
2526
private readonly UserHelper $userHelper,
2627
private readonly AccessUrlHelper $accessUrlHelper,
28+
private readonly LanguageHelper $languageHelper,
2729
) {}
2830

2931
public function __invoke(ControllerEvent $event): void
@@ -54,5 +56,6 @@ public function __invoke(ControllerEvent $event): void
5456
$this->twig->addGlobal('access_url_id', 1);
5557
}
5658
$this->twig->addGlobal('languages_json', json_encode($languages));
59+
$this->twig->addGlobal('wcag_locale', $this->languageHelper->getWcagIso());
5760
}
5861
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
/* For licensing terms, see /license.txt */
4+
5+
declare(strict_types=1);
6+
7+
namespace Chamilo\CoreBundle\Helpers;
8+
9+
use Chamilo\CoreBundle\Repository\LanguageRepository;
10+
use Symfony\Component\HttpFoundation\RequestStack;
11+
12+
final readonly class LanguageHelper
13+
{
14+
public function __construct(
15+
private LanguageRepository $languageRepository,
16+
private RequestStack $requestStack,
17+
) {}
18+
19+
public function getWcagIso(): string
20+
{
21+
$locale = $this->requestStack->getMainRequest()?->getLocale();
22+
23+
if ($locale) {
24+
$language = $this->languageRepository->findByIsoCode($locale);
25+
26+
if ($language->getParent()) {
27+
$language = $language->getParent();
28+
}
29+
30+
return str_replace('_', '-', $language->getIsocode());
31+
}
32+
33+
return 'en-US';
34+
}
35+
}

src/CoreBundle/Repository/LanguageRepository.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use Doctrine\Persistence\ManagerRegistry;
1515
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
1616

17+
/**
18+
* @extends ServiceEntityRepository<Language>
19+
*/
1720
class LanguageRepository extends ServiceEntityRepository
1821
{
1922
public function __construct(

src/CoreBundle/Resources/views/Layout/base-layout.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
{% import '@ChamiloCore/Macros/modals.html.twig' as macro_modals %}
77
{% set modals_block = macro_modals.global_modal('') %}
88
<!DOCTYPE html>
9-
<html lang="{{ app.request.locale }}" class="no-js h-100">
9+
<html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js h-100">
1010
{% block chamilo_head %}
1111
{%- include "@ChamiloCore/Layout/head.html.twig" %}
1212
{% endblock %}

src/CoreBundle/Resources/views/Layout/blank.html.twig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<!DOCTYPE html>
2-
<!--[if lt IE 7]> <html lang="{{app.request.locale}}" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3-
<!--[if IE 7]> <html lang="{{app.request.locale}}" class="no-js lt-ie9 lt-ie8"> <![endif]-->
4-
<!--[if IE 8]> <html lang="{{app.request.locale}}" class="no-js lt-ie9"> <![endif]-->
5-
<!--[if gt IE 8]><!--><html lang="{{app.request.locale}}" class="no-js"> <!--<![endif]-->
2+
<!--[if lt IE 7]> <html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3+
<!--[if IE 7]> <html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js lt-ie9 lt-ie8"> <![endif]-->
4+
<!--[if IE 8]> <html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js lt-ie9"> <![endif]-->
5+
<!--[if gt IE 8]><!--><html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js"> <!--<![endif]-->
66

77
{% include "@ChamiloCore/Layout/head.html.twig" %}
88

src/CoreBundle/Resources/views/Layout/blank_no_header.html.twig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<!DOCTYPE html>
2-
<!--[if lt IE 7]> <html lang="{{app.request.locale}}" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3-
<!--[if IE 7]> <html lang="{{app.request.locale}}" class="no-js lt-ie9 lt-ie8"> <![endif]-->
4-
<!--[if IE 8]> <html lang="{{app.request.locale}}" class="no-js lt-ie9"> <![endif]-->
5-
<!--[if gt IE 8]><!--><html lang="{{app.request.locale}}" class="no-js"> <!--<![endif]-->
2+
<!--[if lt IE 7]> <html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
3+
<!--[if IE 7]> <html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js lt-ie9 lt-ie8"> <![endif]-->
4+
<!--[if IE 8]> <html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js lt-ie9"> <![endif]-->
5+
<!--[if gt IE 8]><!--><html lang="{{ wcag_locale }}" data-lang="{{ app.request.locale }}" class="no-js"> <!--<![endif]-->
66
<head>
77
</head>
88
{% autoescape false %}

0 commit comments

Comments
 (0)