mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 04:53:49 +00:00
Add basic ICU message format support for translations (#1645)
## Description: This pull request adds support for ICU (Intl MessageFormat) syntax in the translation system. Existing translation files may need to be updated to fully leverage ICU features. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I have read and accepted the CLA agreement (only required once). ## Please put your Discord username so you can be contacted if a bug or regression is found: DISCORD_USERNAME
This commit is contained in:
@@ -34,8 +34,8 @@ import zh_CN from "../../resources/lang/zh-CN.json";
|
||||
@customElement("lang-selector")
|
||||
export class LangSelector extends LitElement {
|
||||
@state() public translations: Record<string, string> | undefined;
|
||||
@state() private defaultTranslations: Record<string, string> | undefined;
|
||||
@state() private currentLang: string = "en";
|
||||
@state() public defaultTranslations: Record<string, string> | undefined;
|
||||
@state() public currentLang: string = "en";
|
||||
@state() private languageList: any[] = [];
|
||||
@state() private showModal: boolean = false;
|
||||
@state() private debugMode: boolean = false;
|
||||
|
||||
+39
-3
@@ -1,3 +1,4 @@
|
||||
import IntlMessageFormat from "intl-messageformat";
|
||||
import { MessageType } from "../core/game/Game";
|
||||
import { LangSelector } from "./LangSelector";
|
||||
|
||||
@@ -78,18 +79,20 @@ export function generateCryptoRandomUUID(): string {
|
||||
);
|
||||
}
|
||||
|
||||
// Re-export translateText from LangSelector
|
||||
export const translateText = (
|
||||
key: string,
|
||||
params: Record<string, string | number> = {},
|
||||
): string => {
|
||||
const self = translateText as any;
|
||||
self.formatterCache ??= new Map();
|
||||
self.lastLang ??= null;
|
||||
|
||||
const langSelector = document.querySelector("lang-selector") as LangSelector;
|
||||
if (!langSelector) {
|
||||
console.warn("LangSelector not found in DOM");
|
||||
return key;
|
||||
}
|
||||
|
||||
// Wait for translations to be loaded
|
||||
if (
|
||||
!langSelector.translations ||
|
||||
Object.keys(langSelector.translations).length === 0
|
||||
@@ -97,7 +100,40 @@ export const translateText = (
|
||||
return key;
|
||||
}
|
||||
|
||||
return langSelector.translateText(key, params);
|
||||
if (self.lastLang !== langSelector.currentLang) {
|
||||
self.formatterCache.clear();
|
||||
self.lastLang = langSelector.currentLang;
|
||||
}
|
||||
|
||||
let message = langSelector.translations[key];
|
||||
|
||||
if (!message && langSelector.defaultTranslations) {
|
||||
const defaultTranslations = langSelector.defaultTranslations;
|
||||
if (defaultTranslations && defaultTranslations[key]) {
|
||||
message = defaultTranslations[key];
|
||||
}
|
||||
}
|
||||
|
||||
if (!message) return key;
|
||||
|
||||
try {
|
||||
const locale =
|
||||
!langSelector.translations[key] && langSelector.currentLang !== "en"
|
||||
? "en"
|
||||
: langSelector.currentLang;
|
||||
const cacheKey = `${key}:${locale}:${message}`;
|
||||
let formatter = self.formatterCache.get(cacheKey);
|
||||
|
||||
if (!formatter) {
|
||||
formatter = new IntlMessageFormat(message, locale);
|
||||
self.formatterCache.set(cacheKey, formatter);
|
||||
}
|
||||
|
||||
return formatter.format(params) as string;
|
||||
} catch (e) {
|
||||
console.warn("ICU format error", e);
|
||||
return message;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user