Skip to content

Commit f5040cc

Browse files
committed
Add language selection to web-eid.eu
WE2-1100 Signed-off-by: Sven Mitt <[email protected]>
1 parent c8b70bb commit f5040cc

File tree

3 files changed

+178
-4
lines changed

3 files changed

+178
-4
lines changed

example/src/main/resources/static/css/main.css

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,84 @@ body {
6767
.eu-logo-fixed img {
6868
height: 86px;
6969
}
70+
71+
.language-dropdown {
72+
position: relative;
73+
display: inline-block;
74+
}
75+
76+
.language-btn {
77+
background-color: #f8f9fa;
78+
color: #212529;
79+
border: 1px solid #e9ecef;
80+
padding: 8px 12px;
81+
border-radius: 4px;
82+
cursor: pointer;
83+
display: flex;
84+
align-items: center;
85+
gap: 8px;
86+
font-size: 14px;
87+
font-weight: 500;
88+
min-width: 60px;
89+
justify-content: space-between;
90+
transition: background-color 0.2s, border-color 0.2s;
91+
}
92+
93+
.language-btn:hover {
94+
background-color: #e9ecef;
95+
}
96+
97+
.dropdown-arrow {
98+
font-size: 10px;
99+
transition: transform 0.2s;
100+
}
101+
102+
.language-btn.active .dropdown-arrow {
103+
transform: rotate(180deg);
104+
}
105+
106+
.language-menu {
107+
position: absolute;
108+
top: 100%;
109+
left: 0;
110+
background-color: #f8f9fa;
111+
border: 1px solid #e9ecef;
112+
border-radius: 4px;
113+
padding: 8px;
114+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.15);
115+
z-index: 1000;
116+
display: none;
117+
min-width: 200px;
118+
margin-top: 2px;
119+
}
120+
121+
.language-menu.show {
122+
display: block;
123+
}
124+
125+
.language-grid {
126+
display: grid;
127+
grid-template-columns: 1fr 1fr;
128+
gap: 4px;
129+
}
130+
131+
.language-option {
132+
background: none;
133+
border: none;
134+
color: #212529;
135+
padding: 8px 12px;
136+
text-align: left;
137+
cursor: pointer;
138+
border-radius: 2px;
139+
font-size: 14px;
140+
white-space: nowrap;
141+
transition: background-color 0.2s;
142+
}
143+
144+
.language-option:hover {
145+
background-color: #e9ecef;
146+
}
147+
148+
.language-option.selected {
149+
font-weight: bold;
150+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2020-2025 Estonian Information System Authority
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
"use strict";
24+
25+
const languageUi = {
26+
selectedLang: document.querySelector("#selected-lang"),
27+
languageButton: document.querySelector("#language-button"),
28+
languageMenu: document.querySelector("#language-menu"),
29+
languageOptions: document.querySelectorAll(".language-option")
30+
};
31+
32+
export function setupLanguageSelection(currentLang, onLangChange) {
33+
const selectedOption = Array.from(languageUi.languageOptions)
34+
.find(option => option.dataset.lang === currentLang);
35+
36+
languageUi.selectedLang.textContent = selectedOption ? selectedOption.dataset.display : "EN";
37+
38+
languageUi.languageOptions.forEach(option =>
39+
option.classList.toggle('selected', option.dataset.lang === currentLang)
40+
);
41+
42+
languageUi.languageButton.onclick = e => {
43+
e.stopPropagation();
44+
languageUi.languageMenu.classList.toggle('show');
45+
e.target.classList.toggle('active');
46+
};
47+
48+
document.onclick = () => {
49+
languageUi.languageMenu.classList.remove('show');
50+
languageUi.languageButton.classList.remove('active');
51+
};
52+
53+
languageUi.languageMenu.onclick = e => e.stopPropagation();
54+
55+
languageUi.languageOptions.forEach(option => {
56+
option.onclick = () => {
57+
onLangChange(option.dataset.lang);
58+
languageUi.selectedLang.textContent = option.dataset.display;
59+
languageUi.languageOptions.forEach(o => o.classList.remove('selected'));
60+
option.classList.add('selected');
61+
languageUi.languageMenu.classList.remove('show');
62+
languageUi.languageButton.classList.remove('active');
63+
};
64+
});
65+
}

example/src/main/resources/templates/index.html

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,15 +87,41 @@ <h3><a id="usage"></a>Usage</h3>
8787
Attach a smart card reader to the computer and insert the eID card into the reader.
8888
</li>
8989
<li>Click <i>Authenticate</i> below.</li>
90+
<li>
91+
Select the Web eID application language from the dropdown menu.
92+
If you have previously configured a language preference within the Web eID application dialog, that setting will take precedence over the language selection made here.
93+
Please note that this language setting does not affect the website interface.
94+
</li>
9095
</ol>
9196

9297
<div id="error-message" class="alert alert-danger" style="display: none;" role="alert">
9398
<div class="message"></div>
9499
<pre class="details"></pre>
95100
</div>
96-
<p class="text-center p-4">
101+
102+
<div class="d-flex justify-content-center align-items-center p-4">
97103
<button id="webeid-auth-button" class="btn btn-info">Authenticate</button>
98-
</p>
104+
<div class="language-dropdown ml-1">
105+
<button id="language-button" class="language-btn" type="button">
106+
<span id="selected-lang">EN</span>
107+
<span class="dropdown-arrow"></span>
108+
</button>
109+
<div id="language-menu" class="language-menu">
110+
<div class="language-grid">
111+
<button class="language-option" data-lang="et" data-display="ET">Eesti</button>
112+
<button class="language-option" data-lang="en" data-display="EN">English</button>
113+
<button class="language-option" data-lang="ru" data-display="RU">Русский</button>
114+
<button class="language-option" data-lang="fi" data-display="FI">Suomi</button>
115+
<button class="language-option" data-lang="hr" data-display="HR">Hrvatska</button>
116+
<button class="language-option" data-lang="de" data-display="DE">Deutsch</button>
117+
<button class="language-option" data-lang="fr" data-display="FR">Française</button>
118+
<button class="language-option" data-lang="nl" data-display="NL">Nederlands</button>
119+
<button class="language-option" data-lang="cs" data-display="CS">Čeština</button>
120+
<button class="language-option" data-lang="sk" data-display="SK">Slovenština</button>
121+
</div>
122+
</div>
123+
</div>
124+
</div>
99125

100126
<p>The privacy policy of the test service is available <a href="/files/Web eID privacy policy.pdf">here</a>.
101127
</p>
@@ -250,6 +276,7 @@ <h3><a id="for-developers"></a>For developers</h3>
250276
"use strict";
251277
import * as webeid from "/js/web-eid.js";
252278
import {hideErrorMessage, showErrorMessage, checkHttpError} from "/js/errors.js";
279+
import {setupLanguageSelection} from "/js/index.js";
253280

254281
hideErrorMessage();
255282

@@ -258,7 +285,8 @@ <h3><a id="for-developers"></a>For developers</h3>
258285
const csrfToken = document.querySelector('#csrftoken').content;
259286
const csrfHeaderName = document.querySelector('#csrfheadername').content;
260287

261-
const lang = new URLSearchParams(window.location.search).get("lang") || "en";
288+
let lang = new URLSearchParams(window.location.search).get("lang") || "en";
289+
setupLanguageSelection(lang, changedLang => lang = changedLang);
262290

263291
authButton.addEventListener("click", async () => {
264292
hideErrorMessage();
@@ -289,7 +317,7 @@ <h3><a id="for-developers"></a>For developers</h3>
289317

290318
console.log("Authentication successful! Result:", authTokenResult);
291319

292-
window.location.href = "/welcome";
320+
window.location.href = "/welcome?lang=" + lang;
293321

294322
} catch (error) {
295323
showErrorMessage(error);

0 commit comments

Comments
 (0)