Skip to content

Commit 09d85f2

Browse files
Hotfix/login translation (#62)
* update changelog and version * feat: set login page language from language header * feat: set client-error page language from language header * add ca templates * fix lang attribute in es templates * fix and add tests * fix(ClientErrorController): use the locale instead of the default language * remove logs * commit to retry deployment * remove unused import
1 parent fea1798 commit 09d85f2

File tree

13 files changed

+861
-31
lines changed

13 files changed

+861
-31
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [v2.0.0](https://github.com/in2workspace/in2-verifier-api/releases/tag/v2.0.0)
7+
## [v2.0.3](https://github.com/in2workspace/in2-verifier-api/releases/tag/v2.0.3)
8+
### Changed
9+
- For frontend pages, set language from Accept-Language header before using default language.
10+
11+
## [v2.0.2](https://github.com/in2workspace/in2-verifier-api/releases/tag/v2.0.2)
812
### Added
913
- Get default language from configuration, use it to translate HTML templates.
1014

15+
## [v2.0.1](https://github.com/in2workspace/in2-verifier-api/releases/tag/v2.0.1)
16+
- ### Added
17+
- Implement Authorization Code Flow with PKCE
18+
1119
## [v2.0.0](https://github.com/in2workspace/in2-verifier-api/releases/tag/v2.0.0)
1220
- New major version to align with the new major version of EUDIStack project.
1321

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ plugins {
1010
}
1111

1212
group = 'es.in2'
13-
version = '2.0.2'
13+
version = '2.0.3'
1414

1515
java {
1616
toolchain {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package es.in2.vcverifier.config;
2+
3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
6+
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
7+
8+
import java.util.List;
9+
import java.util.Locale;
10+
import org.springframework.web.servlet.LocaleResolver;
11+
12+
@Configuration
13+
public class I18nConfig implements WebMvcConfigurer {
14+
@Bean
15+
public LocaleResolver localeResolver(FrontendConfig frontendConfig) {
16+
AcceptHeaderLocaleResolver r = new AcceptHeaderLocaleResolver();
17+
r.setSupportedLocales(List.of(
18+
Locale.forLanguageTag("en"),
19+
Locale.forLanguageTag("es"),
20+
Locale.forLanguageTag("ca")
21+
));
22+
23+
r.setDefaultLocale(Locale.forLanguageTag(frontendConfig.getDefaultLang()));
24+
return r;
25+
}
26+
}

src/main/java/es/in2/vcverifier/controller/ClientErrorController.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import org.springframework.web.bind.annotation.ResponseStatus;
1010
import org.springframework.ui.Model;
1111

12+
import java.util.Locale;
13+
14+
1215
@Controller
1316
@RequiredArgsConstructor
1417
public class ClientErrorController {
@@ -21,6 +24,7 @@ public String showErrorPage(@RequestParam("errorCode") String errorCode,
2124
@RequestParam("errorMessage") String errorMessage,
2225
@RequestParam("clientUrl") String clientUrl,
2326
@RequestParam("originalRequestURL") String originalRequestURL,
27+
Locale locale,
2428
Model model) {
2529
// Add attributes to the model
2630
model.addAttribute("errorCode", errorCode);
@@ -34,8 +38,10 @@ public String showErrorPage(@RequestParam("errorCode") String errorCode,
3438
model.addAttribute("secondary", frontendConfig.getSecondaryColor());
3539
model.addAttribute("secondaryContrast", frontendConfig.getSecondaryContrastColor());
3640
model.addAttribute("faviconSrc", frontendConfig.getFaviconSrc());
41+
3742
// Return the view name
38-
return "client-authentication-error-" + frontendConfig.getDefaultLang();
43+
String language = locale.getLanguage().toLowerCase();
44+
return "client-authentication-error-" + language;
3945
}
4046

4147
}

src/main/java/es/in2/vcverifier/controller/LoginQrController.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import java.io.ByteArrayOutputStream;
1818
import java.util.Base64;
19+
import java.util.Locale;
1920

2021
@Controller
2122
@RequiredArgsConstructor
@@ -25,7 +26,7 @@ public class LoginQrController {
2526

2627
@GetMapping("/login")
2728
@ResponseStatus(HttpStatus.OK)
28-
public String showQrLogin(@RequestParam("authRequest") String authRequest, @RequestParam("state") String state, Model model, @RequestParam("homeUri") String homeUri) {
29+
public String showQrLogin(@RequestParam("authRequest") String authRequest, @RequestParam("state") String state, Model model, Locale locale, @RequestParam("homeUri") String homeUri) {
2930
try {
3031
// Generar la imagen QR en base64
3132
String qrImageBase64 = generateQRCodeImageBase64(authRequest);
@@ -46,10 +47,12 @@ public String showQrLogin(@RequestParam("authRequest") String authRequest, @Requ
4647
model.addAttribute("faviconSrc", frontendConfig.getFaviconSrc());
4748
model.addAttribute("expiration", LOGIN_TIMEOUT);
4849
model.addAttribute("cronUnit", LOGIN_TIMEOUT_CHRONO_UNIT);
50+
4951
} catch (Exception e) {
5052
throw new QRCodeGenerationException(e.getMessage());
5153
}
52-
return "login-" + frontendConfig.getDefaultLang();
54+
String language = locale.getLanguage().toLowerCase();
55+
return "login-" + language;
5356
}
5457

5558
private String generateQRCodeImageBase64(String barcodeText) {
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
<!DOCTYPE html>
2+
<html xmlns:th="http://www.thymeleaf.org" lang="ca">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Error d'autenticació</title>
6+
<link href="https://fonts.googleapis.com/css2?family=Blinker:wght@100;200;300;400;600;700;800;900&display=swap" rel="stylesheet">
7+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
8+
<link rel="icon" th:href="@{/img/{file}(file=${faviconSrc})}" type="image/png">
9+
<style>
10+
:root {
11+
--fore-color-primary: [[${primaryContrast}]];
12+
--bg-color-primary:[[${secondary}]];
13+
--highlight-color: [[${secondaryContrast}]];
14+
--error-box-background: #e0e0e0;
15+
}
16+
17+
html, body {
18+
height: 100%;
19+
margin: 0;
20+
padding: 0;
21+
}
22+
23+
body {
24+
font-family: 'Blinker', sans-serif;
25+
background-color: var(--bg-color-primary);
26+
color: var(--fore-color-primary);
27+
display: flex;
28+
justify-content: center;
29+
align-items: center;
30+
}
31+
32+
.container {
33+
text-align: center;
34+
padding: 3rem;
35+
border: 3px solid var(--highlight-color);
36+
border-radius: 8px;
37+
background-color: var(--bg-color-primary);
38+
max-width: 800px;
39+
}
40+
41+
.title {
42+
font-size: 4rem;
43+
font-weight: bold;
44+
color: var(--fore-color-primary);
45+
margin-bottom: 2rem;
46+
}
47+
48+
.error-message {
49+
font-size: 1.75rem;
50+
color: var(--fore-color-primary);
51+
margin-bottom: 2rem;
52+
text-align: justify;
53+
text-justify: inter-word;
54+
}
55+
56+
.info-box {
57+
position: relative;
58+
display: inline-flex;
59+
padding: 1.5rem;
60+
border: 2px solid #333;
61+
border-radius: 8px;
62+
background-color: var(--error-box-background);
63+
text-align: left;
64+
max-width: 90%;
65+
}
66+
67+
.info-box-content {
68+
flex-grow: 1;
69+
margin-right: 1.5rem;
70+
}
71+
72+
.info-box-item {
73+
font-size: 1.25rem;
74+
margin-bottom: 1rem;
75+
color: #333;
76+
}
77+
78+
.info-box-item:last-child {
79+
margin-bottom: 0;
80+
}
81+
82+
.shortened-url {
83+
display: inline-block;
84+
overflow: hidden;
85+
text-overflow: ellipsis;
86+
white-space: nowrap;
87+
max-width: 400px;
88+
vertical-align: middle;
89+
}
90+
91+
.copy-button {
92+
position: absolute;
93+
top: 5px;
94+
right: 5px;
95+
background-color: var(--error-box-background);
96+
color: #333;
97+
border: none;
98+
padding: 0.3rem;
99+
border-radius: 4px;
100+
cursor: pointer;
101+
font-size: 1.4rem;
102+
transition: background-color 0.3s, color 0.3s, border-color 0.3s;
103+
display: flex;
104+
align-items: center;
105+
justify-content: center;
106+
}
107+
108+
.copy-button:hover {
109+
background-color: #333;
110+
color: var(--error-box-background);
111+
}
112+
113+
.copy-icon {
114+
margin: 0;
115+
font-size: 1.3rem;
116+
}
117+
118+
.help {
119+
font-size: 1.25rem;
120+
color: var(--fore-color-primary);
121+
margin-top: 2rem;
122+
}
123+
124+
.help a {
125+
color: var(--highlight-color);
126+
text-decoration: none;
127+
}
128+
129+
.help a:hover {
130+
text-decoration: underline;
131+
}
132+
</style>
133+
</head>
134+
<body>
135+
<div class="container">
136+
<div class="title">Error d'autenticació</div>
137+
<div class="error-message" th:text="${errorMessage}">
138+
L'abast sol·licitat no conté 'learcredential'. Actualment només admetem aquest abast i 'email', 'profile' com a opcionals.
139+
</div>
140+
<div class="info-box">
141+
<div class="info-box-content">
142+
<div class="info-box-item">
143+
<p><strong>Codi d'error</strong>: <span th:text="${errorCode}">627d4af8-2ea8-4069-b3c2-b3fdaae3958d</span></p>
144+
</div>
145+
<div class="info-box-item">
146+
<p><strong>Client</strong>: <span th:text="${clientUrl}">a2ef4ab9-737d-485f-85bb-278764e7088b</span></p>
147+
</div>
148+
<div class="info-box-item">
149+
<p><strong>Sol·licitud original</strong>: <span class="shortened-url" th:utext="${originalRequestURL}">http://localhost:9000/oidc/authorize?...</span></p>
150+
</div>
151+
</div>
152+
<div class="copy-button" onclick="copyInfoBoxToClipboard()">
153+
<i class="fas fa-clipboard copy-icon"></i>
154+
</div>
155+
</div>
156+
<div class="help">
157+
Necessites ajuda? <a th:href="${supportUri}">Contacta'ns</a> i proporciona'ns la informació anterior perquè et puguem ajudar.
158+
</div>
159+
</div>
160+
161+
<script th:inline="javascript">
162+
/*<![CDATA[*/
163+
let originalUrl = /*[[${originalRequestURL}]]*/ "";
164+
/*]]>*/
165+
</script>
166+
167+
<script>
168+
function copyInfoBoxToClipboard() {
169+
// Select the text of each field
170+
const errorCode = document.querySelector('.info-box-item:nth-child(1) span').innerText;
171+
const clientUrl = document.querySelector('.info-box-item:nth-child(2) span').innerText;
172+
173+
// Concatenating all the information to copy
174+
const fullText = `Codi d'error: ${errorCode}\nClient: ${clientUrl}\nSol·licitud original: ${originalUrl}`;
175+
176+
// Copy to clipboard
177+
navigator.clipboard.writeText(fullText).then(() => {
178+
const copyButton = document.querySelector('.copy-button');
179+
copyButton.style.backgroundColor = 'var(--error-box-background)';
180+
copyButton.style.color = '#333';
181+
}).catch(err => {
182+
console.error('Failed to copy the info box: ', err);
183+
});
184+
}
185+
</script>
186+
187+
</body>
188+
</html>

src/main/resources/templates/client-authentication-error-es.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html xmlns:th="http://www.thymeleaf.org" lang="en">
2+
<html xmlns:th="http://www.thymeleaf.org" lang="es">
33
<head>
44
<meta charset="UTF-8">
55
<title>Error de autenticación</title>

0 commit comments

Comments
 (0)