mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
translation system
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"pages":{
|
||||
"settings":{
|
||||
"languages":{
|
||||
"en-EN": "English, UK",
|
||||
"en-US": "English, US",
|
||||
"fr-FR": "Français",
|
||||
"es-ES": "Español",
|
||||
"translated":{
|
||||
"en-EN": "English, United Kingdom",
|
||||
"en-US": "English, USA",
|
||||
"fr-FR": "French",
|
||||
"es-ES": "Spanish"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"pages":{
|
||||
"settings":{
|
||||
"languages":{
|
||||
"en-EN": "English, UK",
|
||||
"en-US": "English, US",
|
||||
"fr-FR": "Français",
|
||||
"es-ES": "Español",
|
||||
"translated":{
|
||||
"en-EN": "English, United Kingdom",
|
||||
"en-US": "English, United States",
|
||||
"fr-FR": "French",
|
||||
"es-ES": "Spanish"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"pages":{
|
||||
"settings":{
|
||||
"languages":{
|
||||
"en-EN": "English, UK",
|
||||
"en-US": "English, US",
|
||||
"fr-FR": "Français",
|
||||
"es-ES": "Español",
|
||||
"translated":{
|
||||
"en-EN": "Inglés, Reino Unido",
|
||||
"en-US": "Inglés, Estados Unidos",
|
||||
"fr-FR": "Francés",
|
||||
"es-ES": "Español"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"pages":{
|
||||
"settings":{
|
||||
"languages":{
|
||||
"en-EN": "English, UK",
|
||||
"en-US": "English, US",
|
||||
"fr-FR": "Français",
|
||||
"es-ES": "Español",
|
||||
"translated":{
|
||||
"en-EN": "Anglais, Royaume-Uni",
|
||||
"en-US": "Anglais, États-Unis",
|
||||
"fr-FR": "Français",
|
||||
"es-ES": "Espagnol"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+12
-4
@@ -4141,6 +4141,14 @@
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"dot-prop": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
|
||||
"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
|
||||
"requires": {
|
||||
"is-obj": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.7",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||
@@ -5011,11 +5019,11 @@
|
||||
}
|
||||
},
|
||||
"dot-prop": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
|
||||
"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz",
|
||||
"integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==",
|
||||
"requires": {
|
||||
"is-obj": "^2.0.0"
|
||||
"type-fest": "^2.11.2"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
"@node-steam/vdf": "^2.2.0",
|
||||
"@reduxjs/toolkit": "^1.8.3",
|
||||
"dateformat": "^5.0.3",
|
||||
"dot-prop": "^7.2.0",
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-log": "^4.4.7",
|
||||
"electron-store": "^8.0.2",
|
||||
|
||||
@@ -14,12 +14,10 @@ export function SettingRadioArray({items, selectedItem = items[0].id, onItemSele
|
||||
<h2 className="font-extrabold">{i.text}</h2>
|
||||
</div>
|
||||
{i.icon && (
|
||||
<>
|
||||
<div className="flex items-center">
|
||||
{i.textIcon && <span>{i.textIcon}</span>}
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
{i.textIcon && <span className="text-sm">{i.textIcon}</span>}
|
||||
<BsmIcon icon={i.icon}/>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)) }
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
export const defaultConfiguration: {[key in DefaultConfigKey]: any} = {
|
||||
"first-color": "#3b82ff",
|
||||
"second-color": "#ff4444",
|
||||
"theme": "os"
|
||||
"theme": "os",
|
||||
"language": window.navigator.language.length <= 2 ? `${window.navigator.language}-${window.navigator.language.toLocaleUpperCase()}` : window.navigator.language,
|
||||
"supported_languages": ["en-US", "en-EN", "fr-FR", "es-ES"],
|
||||
}
|
||||
|
||||
export type DefaultConfigKey = "first-color" | "second-color" | "theme";
|
||||
export type DefaultConfigKey = "first-color" | "second-color" | "theme" | "language" | "supported_languages";
|
||||
|
||||
export type ThemeConfig = "dark" | "light" | "os"
|
||||
@@ -0,0 +1,11 @@
|
||||
import { useMemo } from "react";
|
||||
import { I18nService } from "renderer/services/i18n.service"
|
||||
|
||||
export function useTranslation(): (translationKey: string) => string{
|
||||
|
||||
const i18nService = I18nService.getInstance();
|
||||
|
||||
return (key: string) => {
|
||||
return useMemo(() => i18nService.translate(key), [key, i18nService.currentLanguage]);
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,11 @@ import { RadioItem, SettingRadioArray } from "renderer/components/settings/setti
|
||||
import { BsmButton } from "renderer/components/shared/bsm-button.component";
|
||||
import { DefaultConfigKey, ThemeConfig } from "renderer/config/default-configuration.config";
|
||||
import { useObservable } from "renderer/hooks/use-observable.hook";
|
||||
import { useTranslation } from "renderer/hooks/use-translation.hook";
|
||||
import { AuthUserService } from "renderer/services/auth-user.service";
|
||||
import { BsDownloaderService } from "renderer/services/bs-downloader.service";
|
||||
import { ConfigurationService } from "renderer/services/configuration.service"
|
||||
import { I18nService } from "renderer/services/i18n.service";
|
||||
import { IpcService } from "renderer/services/ipc.service";
|
||||
import { ModalExitCode, ModalService, ModalType } from "renderer/services/modale.service";
|
||||
import { NotificationService } from "renderer/services/notification.service";
|
||||
@@ -24,6 +26,12 @@ export function SettingsPage() {
|
||||
const progressBarService: ProgressBarService = ProgressBarService.getInstance();
|
||||
const authService: AuthUserService = AuthUserService.getInstance();
|
||||
const notificationService: NotificationService = NotificationService.getInstance();
|
||||
const i18nService: I18nService = I18nService.getInstance();
|
||||
|
||||
const firstColor = useObservable(configService.watch<string>("first-color"));
|
||||
const secondColor = useObservable(configService.watch<string>("second-color"));
|
||||
const sessionExist = useObservable(authService.sessionExist$);
|
||||
const t = useTranslation();
|
||||
|
||||
const themeItem: RadioItem[] = [
|
||||
{id: 0, text: "Dark", value: "dark" as ThemeConfig},
|
||||
@@ -31,12 +39,16 @@ export function SettingsPage() {
|
||||
{id: 3, text: "Operating System", value: "os" as ThemeConfig}
|
||||
];
|
||||
|
||||
const firstColor = useObservable(configService.watch<string>("first-color"));
|
||||
const secondColor = useObservable(configService.watch<string>("second-color"));
|
||||
const sessionExist = useObservable(authService.sessionExist$);
|
||||
const languagesItems: RadioItem[] = i18nService.getSupportedLanguages().map((l, index) => {
|
||||
return {id: index, text: t(`pages.settings.languages.${l}`), value: l, textIcon:t(`pages.settings.languages.translated.${l}`), icon: "trash"};
|
||||
});
|
||||
|
||||
const[themeIdSelected, setThemeIdSelected]= useState(themeItem.find(e => e.value === themeService.getTheme()).id);
|
||||
const[languageSelected, setLanguageSelected]= useState(languagesItems.find(e => e.value === i18nService.currentLanguage).id);
|
||||
const [installationFolder, setInstallationFolder] = useState(null);
|
||||
|
||||
console.log(t("test"));
|
||||
|
||||
useEffect(() => {
|
||||
loadInstallationFolder();
|
||||
}, []);
|
||||
@@ -58,6 +70,12 @@ export function SettingsPage() {
|
||||
themeService.setTheme(themeItem.find(e => e.id === id).value);
|
||||
}
|
||||
|
||||
const handleChangeLanguage = (id: number) => {
|
||||
const selectedLanguage = languagesItems.find(l => l.id === id).value;
|
||||
i18nService.setLanguage(selectedLanguage);
|
||||
setLanguageSelected(languagesItems.find(l => l.value === i18nService.currentLanguage).id);
|
||||
}
|
||||
|
||||
const setDefaultInstallationFolder = () => {
|
||||
modalService.openModal(ModalType.INSTALLATION_FOLDER).then(async res => {
|
||||
if(res.exitCode !== ModalExitCode.COMPLETED){ return; }
|
||||
@@ -87,9 +105,9 @@ export function SettingsPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full flex justify-center px-40 pt-10 text-gray-800 dark:text-gray-200">
|
||||
<div className="w-full h-full flex justify-center overflow-y-scroll pb-12 scrollbar-thin scrollbar-thumb-neutral-900 text-gray-800 dark:text-gray-200">
|
||||
|
||||
<div className="w-fit max-w-full">
|
||||
<div className="w-fit max-w-full mt-10">
|
||||
|
||||
<SettingContainer title="Steam" description="If you logout of your Steam account, you must reconect for download a new BS instance">
|
||||
<BsmButton onClick={deleteSteamSession} className={`bg-red-500 w-fit px-3 py-[2px] text-white rounded-md`} withBar={false} text="Logout of Steam" disabled={!sessionExist}/>
|
||||
@@ -115,6 +133,12 @@ export function SettingsPage() {
|
||||
</div>
|
||||
</SettingContainer>
|
||||
|
||||
<SettingContainer title="Language" description="Select a language">
|
||||
<SettingRadioArray items={languagesItems} selectedItem={languageSelected} onItemSelected={handleChangeLanguage}/>
|
||||
</SettingContainer>
|
||||
|
||||
<div className="h-10"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -37,8 +37,6 @@ export function VersionViewer() {
|
||||
const bsDownloaderService = BsDownloaderService.getInstance();
|
||||
const progressService = ProgressBarService.getInstance();
|
||||
|
||||
const [launchRes, setLaunchRes] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
setOculusMode(!!configService.get<boolean>(LaunchMods.OCULUS_MOD));
|
||||
setDesktopMode(!!configService.get<boolean>(LaunchMods.DESKTOP_MOD));
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { DefaultConfigKey } from "renderer/config/default-configuration.config";
|
||||
import { distinctUntilChanged, filter, map, Observable } from "rxjs";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { getProperty } from "dot-prop";
|
||||
|
||||
export class I18nService {
|
||||
|
||||
private static instance: I18nService;
|
||||
|
||||
private readonly LANG_CONFIG_KEY: DefaultConfigKey = "language";
|
||||
private readonly LANG_FALLBACK = "en-EN";
|
||||
|
||||
private readonly configService: ConfigurationService;
|
||||
|
||||
private dictionary: Object;
|
||||
|
||||
public static getInstance(): I18nService{
|
||||
if(!I18nService.instance){ I18nService.instance = new I18nService(); }
|
||||
return I18nService.instance;
|
||||
}
|
||||
|
||||
private constructor(){
|
||||
this.configService = ConfigurationService.getInstance();
|
||||
|
||||
this.currentLanguage$.pipe(filter(l => !!l), distinctUntilChanged()).subscribe(lang => {
|
||||
this.dictionary = require(`../../../assets/jsons/translations/${lang}.json`);
|
||||
});
|
||||
}
|
||||
|
||||
public getSupportedLanguages(): string[]{ return this.configService.get("supported_languages" as DefaultConfigKey); }
|
||||
public getFallbackLanguage(): string{ return this.LANG_FALLBACK; }
|
||||
|
||||
public get currentLanguage(): string{
|
||||
return this.getSupportedLanguages().includes(this.configService.get(this.LANG_CONFIG_KEY)) ? this.configService.get(this.LANG_CONFIG_KEY) : this.LANG_FALLBACK;
|
||||
}
|
||||
public get currentLanguage$(): Observable<string>{
|
||||
return this.configService.watch<string>("language" as DefaultConfigKey).pipe(map(l => this.getSupportedLanguages().includes(l) ? l : this.LANG_FALLBACK));
|
||||
}
|
||||
|
||||
public setLanguage(lang: string){
|
||||
this.configService.set("language" as DefaultConfigKey, this.getSupportedLanguages().includes(lang) ? lang : this.LANG_FALLBACK);
|
||||
}
|
||||
|
||||
public translate(translationKey: string): string{
|
||||
return getProperty(this.dictionary, translationKey) || translationKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user