Replace RTL_LANGUAGE_CODE implementation to Bidi

Fixes #33833.

Signed-off-by: akbarhusainpatel <apatel@intermiles.com>
Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Co-authored-by: akbarhusainpatel <apatel@intermiles.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
akbar1214 2025-01-27 14:51:30 +05:30 committed by GitHub
parent 4036357b1d
commit 4965f40994
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 12 deletions

View File

@ -21,10 +21,11 @@ import org.keycloak.models.RealmModel;
import jakarta.ws.rs.core.UriBuilder;
import java.text.Bidi;
import java.text.Collator;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
@ -32,18 +33,16 @@ import java.util.stream.Collectors;
*/
public class LocaleBean {
private static final Set<String> RTL_LANGUAGE_CODES =
Set.of("ar", "dv", "fa", "ha", "he", "iw", "ji", "ps", "sd", "ug", "ur", "yi");
private String current;
private String currentLanguageTag;
private boolean rtl; // right-to-left language
private List<Locale> supported;
private final String current;
private final String currentLanguageTag;
private final boolean rtl; // right-to-left language
private final List<Locale> supported;
private static final ConcurrentHashMap<java.util.Locale, Boolean> bidiMap = new ConcurrentHashMap<>();
public LocaleBean(RealmModel realm, java.util.Locale current, UriBuilder uriBuilder, Properties messages) {
this.currentLanguageTag = current.toLanguageTag();
this.current = messages.getProperty("locale_" + this.currentLanguageTag, this.currentLanguageTag);
this.rtl = RTL_LANGUAGE_CODES.contains(current.getLanguage());
this.rtl = isLeftToRight(current);
Collator collator = Collator.getInstance(current);
collator.setStrength(Collator.PRIMARY); // ignore case and accents
@ -58,6 +57,18 @@ public class LocaleBean {
.collect(Collectors.toList());
}
protected static boolean isLeftToRight(java.util.Locale current) {
// Some languages that are RTL have an English name in Java locales, like 'dv' aka Divehi as stated in
// https://github.com/keycloak/keycloak/issues/33833#issuecomment-2446965307.
// Still, this solution seems to be good enough for now. Any exceptions would be added when those translations arise.
// Adding the ICU library was discarded at the time to avoid an additional dependency and due to its special license.
// This might be reconsidered in the future if there are more scenarios.
//
// As the most likely alternative, a translation could in the future define RTL, its language name, and then this can be used instead.
return bidiMap.computeIfAbsent(current, l -> new Bidi(l.getLanguage(), Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT).isLeftToRight());
}
public String getCurrent() {
return current;
}
@ -79,9 +90,9 @@ public class LocaleBean {
public static class Locale {
private String languageTag;
private String label;
private String url;
private final String languageTag;
private final String label;
private final String url;
public Locale(String languageTag, String label, String url) {
this.languageTag = languageTag;

View File

@ -0,0 +1,52 @@
/*
* Copyright 2025 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.theme.beans;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Test;
import java.util.Locale;
import java.util.Set;
/**
* @author Alexander Schwartz
*/
public class LocaleBeanTest {
private static final Set<String> RTL_LANGUAGE_CODES =
Set.of("ar", "dv", "fa", "ha", "he", "iw", "ji", "ps", "sd", "ug", "ur", "yi");
private static final Set<String> LTR_LANGUAGE_CODES =
Set.of("en", "de");
@Test
public void verifyRtl() {
for (String rtlLanguageCode : RTL_LANGUAGE_CODES) {
MatcherAssert.assertThat(LocaleBean.isLeftToRight(Locale.forLanguageTag(rtlLanguageCode)), Matchers.is(true));
}
}
@Test
public void verifyLtr() {
for (String rtlLanguageCode : LTR_LANGUAGE_CODES) {
MatcherAssert.assertThat(LocaleBean.isLeftToRight(Locale.forLanguageTag(rtlLanguageCode)), Matchers.is(true));
}
}
}