mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-21 06:20:05 -06:00
Migrate to zh-Hant / zh-Hans for Chinese language
Closes: #41239 Signed-off-by: 秉虎 <s96016641@gmail.com> Signed-off-by: Allen <s96016641@gmail.com> Signed-off-by: Alexander Schwartz <aschwart@redhat.com> Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
@@ -48,6 +48,16 @@ Starting with this release, {project_name} will cache by default only 10000 entr
|
||||
|
||||
Use the options `cache-embedded-offline-sessions-max-count` and `cache-embedded-offline-client-sessions-max-count` to change size of the offline session caches.
|
||||
|
||||
=== Translation resource bundle file names
|
||||
|
||||
The naming of resource bundles in classloader and folder based themes is now aligned with Java https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/ResourceBundle.html#getBundle(java.lang.String,java.util.Locale,java.lang.ClassLoader)[ResourceBunndle#getBundle] file names.
|
||||
For all included community languages like `de` or `pt-BR` a file is as before named `messages_de.properties` or `messages_pt_BR.properties`.
|
||||
If you added custom language code, you should check if your file names are still the same.
|
||||
|
||||
The languages "Chinese (traditional)" and "Chinese (simplified)" are named for historical reasons `zh-TW` and `zh-CN` in the community themes of {project_name}.
|
||||
As a start to migrate to the new language codes `zh-Hant` and `zh-Hans`, the classloader and folder based themes pick up for the old language codes `zh-TW` and `zh-CN` also the files `messages_zh_Hant.properties` and `messages_zh_Hant.properties`.
|
||||
Entries in `messages_zh_Hant.properties` take precedence over entries in `messages_zh_TW.properties`, and entries in `messages_zh_Hans.properties` take precedence over entries in `messages_zh_CN.properties`.
|
||||
|
||||
=== Supported Update Email Feature
|
||||
|
||||
The `Update Email` is now a supported feature so it is no longer needed to enable the feature during the server startup.
|
||||
|
||||
@@ -35,6 +35,7 @@ Texts of these message bundles can be overwritten by realm-specific values, whic
|
||||
.Procedure
|
||||
|
||||
. Create the file `<THEME TYPE>/messages/messages_<LOCALE>.properties` in the directory of your theme.
|
||||
The `<LOCALE>` follows the conventions of https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/ResourceBundle.html#getBundle(java.lang.String,java.util.Locale,java.lang.ClassLoader)[ResourceBunndle#getBundle].
|
||||
|
||||
. Add this file to the `locales` property in `<THEME TYPE>/theme.properties`.
|
||||
For a language to be available to users in a realm, the login, account, and email theme types must support the language, so you need to add your language for those theme types.
|
||||
@@ -72,8 +73,10 @@ locale_no=Norsk
|
||||
|
||||
By default, message properties files should be encoded using UTF-8.
|
||||
{project_name} falls back to ISO-8859-1 handling if it cannot read the contents as UTF-8.
|
||||
Unicode characters can be escaped as described in Java's documentation for https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/PropertyResourceBundle.html[PropertyResourceBundle].
|
||||
Previous versions of {project_name} had support for specifying the encoding in the first line with a comment such as `# encoding: UTF-8`, which is no longer supported.
|
||||
Unicode characters can be escaped as described in Java's documentation for https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/PropertyResourceBundle.html[PropertyResourceBundle].
|
||||
|
||||
To simplify migration to the new language codes `zh-Hant` and `zh-Hans`, the classloader and folder based themes pick up for the old language codes `zh-TW` and `zh-CN` also the files `messages_zh_Hant.properties` and `messages_zh_Hant.properties`.
|
||||
Entries in `messages_zh_Hant.properties` take precedence over entries in `messages_zh_TW.properties`, and entries in `messages_zh_Hans.properties` take precedence over entries in `messages_zh_CN.properties`.
|
||||
|
||||
[role="_additional-resources"]
|
||||
.Additional resources
|
||||
@@ -97,4 +100,4 @@ CAUTION: In most cases, using realm overrides is not the recommended way to achi
|
||||
. Create a key/value pair from the modal dialog.
|
||||
|
||||
Notice another subtab called *Effective message bundles*. This subtab provides a tool to query key/value pairs for a combination of theme, language, and theme type. You can use this tool to test and make sure your realm overrides took effect.
|
||||
</@tmpl.guide>
|
||||
</@tmpl.guide>
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.Properties;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class ClassLoaderTheme implements Theme {
|
||||
public class ClassLoaderTheme extends FileBasedTheme {
|
||||
|
||||
private String name;
|
||||
|
||||
@@ -116,19 +116,13 @@ public class ClassLoaderTheme implements Theme {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException {
|
||||
if(locale == null){
|
||||
return null;
|
||||
}
|
||||
Properties m = new Properties();
|
||||
|
||||
URL url = classLoader.getResource(this.messageRoot + baseBundlename + "_" + locale + ".properties");
|
||||
protected void loadBundle(String baseBundlename, Locale locale, Properties m) throws IOException {
|
||||
URL url = classLoader.getResource(this.messageRoot + toBundleName(baseBundlename, locale) + ".properties");
|
||||
if (url != null) {
|
||||
try (InputStream stream = url.openStream()) {
|
||||
PropertiesUtil.readCharsetAware(m, stream);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -311,9 +311,9 @@ public class DefaultThemeManager implements ThemeManager {
|
||||
// This is mapping old locale codes to the new locale codes for Simplified and Traditional Chinese.
|
||||
// Once the existing locales have been moved, this code can be removed.
|
||||
if (l.equals("zh-CN")) {
|
||||
rl = "zh-HANS";
|
||||
rl = "zh-Hans";
|
||||
} else if (l.equals("zh-TW")) {
|
||||
rl = "zh-HANT";
|
||||
rl = "zh-Hans";
|
||||
}
|
||||
Locale loc = Locale.forLanguageTag(rl);
|
||||
label = capitalize(loc.getDisplayName(locale), locale);
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
public abstract class FileBasedTheme implements Theme {
|
||||
abstract protected void loadBundle(String baseBundlename, Locale locale, Properties m) throws IOException;
|
||||
|
||||
@Override
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException {
|
||||
if(locale == null){
|
||||
return null;
|
||||
}
|
||||
Properties m = new Properties();
|
||||
|
||||
loadBundle(baseBundlename, locale, m);
|
||||
|
||||
// Chinese locales mapping
|
||||
if (locale.getLanguage().equals("zh") && !locale.getCountry().isEmpty()) {
|
||||
Locale l = switch (locale.getCountry()) {
|
||||
case "TW" -> Locale.forLanguageTag("zh-Hant");
|
||||
case "CN" -> Locale.forLanguageTag("zh-Hans");
|
||||
default -> null;
|
||||
};
|
||||
if (l != null) {
|
||||
loadBundle(baseBundlename, l, m);
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
// Logic as implemented by JDK's ResourceBundle
|
||||
public String toBundleName(String baseName, Locale locale) {
|
||||
if (locale == Locale.ROOT) {
|
||||
return baseName;
|
||||
}
|
||||
|
||||
String language = locale.getLanguage();
|
||||
String script = locale.getScript();
|
||||
String country = locale.getCountry();
|
||||
String variant = locale.getVariant();
|
||||
|
||||
if (language.isEmpty() && country.isEmpty() && variant.isEmpty()) {
|
||||
return baseName;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(baseName);
|
||||
sb.append('_');
|
||||
if (!script.isEmpty()) {
|
||||
if (!variant.isEmpty()) {
|
||||
sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
|
||||
} else if (!country.isEmpty()) {
|
||||
sb.append(language).append('_').append(script).append('_').append(country);
|
||||
} else {
|
||||
sb.append(language).append('_').append(script);
|
||||
}
|
||||
} else {
|
||||
if (!variant.isEmpty()) {
|
||||
sb.append(language).append('_').append(country).append('_').append(variant);
|
||||
} else if (!country.isEmpty()) {
|
||||
sb.append(language).append('_').append(country);
|
||||
} else {
|
||||
sb.append(language);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ import java.util.regex.Pattern;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class FolderTheme implements Theme {
|
||||
public class FolderTheme extends FileBasedTheme {
|
||||
|
||||
private String parentName;
|
||||
private String importName;
|
||||
@@ -101,14 +101,8 @@ public class FolderTheme implements Theme {
|
||||
private static final Pattern LEGAL_LOCALE = Pattern.compile("[a-zA-Z0-9-_#]*");
|
||||
|
||||
@Override
|
||||
public Properties getMessages(String baseBundlename, Locale locale) throws IOException {
|
||||
if (locale == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
Properties m = new Properties();
|
||||
|
||||
String filename = baseBundlename + "_" + locale;
|
||||
protected void loadBundle(String baseBundlename, Locale locale, Properties m) throws IOException {
|
||||
String filename = toBundleName(baseBundlename, locale);
|
||||
|
||||
if (!LEGAL_LOCALE.matcher(filename).matches()) {
|
||||
throw new RuntimeException("Found illegal characters in locale or bundle name: " + filename);
|
||||
@@ -120,7 +114,6 @@ public class FolderTheme implements Theme {
|
||||
PropertiesUtil.readCharsetAware(m, stream);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
public Properties getEnhancedMessages(RealmModel realm, Locale locale) throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user