diff --git a/README.md b/README.md index 2bf6d4a..fc3475e 100644 --- a/README.md +++ b/README.md @@ -52,4 +52,7 @@ There is an Electron version available for local development. Some changes to th This exists mostly for debugging in Chromium. The release builds all use Tauri. Currently, the Electron version lacks the following features: - loading data (localization, emblems, colors) from Stellaris mods +- loading non-English Stellaris localization +- translator mode +- (temporarily) country emblems - production builds diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 9b083ca..11ed722 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -59,8 +59,8 @@ async fn get_stellaris_colors_cmd(path: String) -> Result, String> { } #[tauri::command] -async fn get_stellaris_loc_cmd(path: String) -> Result, String> { - return get_stellaris_loc(path).map_err(|err| err.to_string()); +async fn get_stellaris_loc_cmd(path: String, language: String) -> Result, String> { + return get_stellaris_loc(path, language).map_err(|err| err.to_string()); } #[tauri::command] @@ -359,7 +359,7 @@ fn get_stellaris_data_paths( .collect(); } -fn get_stellaris_loc(path: String) -> anyhow::Result> { +fn get_stellaris_loc(path: String, language: String) -> anyhow::Result> { let loc_file_paths = get_stellaris_data_paths( Path::new(&path).to_path_buf(), Path::new("localisation").to_path_buf(), @@ -384,7 +384,7 @@ fn get_stellaris_loc(path: String) -> anyhow::Result> { line_number += 1; let _ = buf_reader.read_line(&mut first_line)?; } - if first_line.contains("l_english") { + if first_line.contains(language.as_str()) { let re = Regex::new(r#"(?m)^\s*([\w\.\-]+)\s*:\d*\s*"(.*)".*$"#).unwrap(); let mut raw_content = String::new(); let _ = buf_reader.read_to_string(&mut raw_content)?; diff --git a/src/renderer/src/lib/loadStellarisData.ts b/src/renderer/src/lib/loadStellarisData.ts index 77f75ab..0a2c6f7 100644 --- a/src/renderer/src/lib/loadStellarisData.ts +++ b/src/renderer/src/lib/loadStellarisData.ts @@ -4,6 +4,7 @@ import { hsv } from 'd3-hsv'; import { get, writable } from 'svelte/store'; import { jsonify, tokenize } from '../../../shared/parseSave'; import { ADDITIONAL_COLORS } from './colors'; +import { appSettings } from './settings'; import stellarMapsApi from './stellarMapsApi'; import { timeItAsync } from './utils'; @@ -14,6 +15,14 @@ export const stellarisDataPromiseStore = writable( }), ); +// reload data if appStellarisLanguage setting changed +let loadedStellarisLanguage = get(appSettings).appStellarisLanguage; +appSettings.subscribe((value) => { + if (value.appStellarisLanguage !== loadedStellarisLanguage) { + loadStellarisData(); + } +}); + export function loadStellarisData() { const stellarisDataPromise = loadStellarisDataUnwrapped(); stellarisDataPromiseStore.set(stellarisDataPromise); @@ -23,12 +32,14 @@ export function loadStellarisData() { async function loadStellarisDataUnwrapped() { const path = get(stellarisPathStore) || (await stellarMapsApi.loadStellarisInstallDir()); stellarisPathStore.set(path); - const [colors, loc] = await Promise.all([loadColors(path), loadLoc(path)]); + const language = get(appSettings).appStellarisLanguage; + loadedStellarisLanguage = language; + const [colors, loc] = await Promise.all([loadColors(path), loadLoc(path, language)]); return { colors, loc }; } -function loadLoc(path: string) { - return timeItAsync('loadLoc', stellarMapsApi.loadLoc, path); +function loadLoc(path: string, language: string) { + return timeItAsync('loadLoc', stellarMapsApi.loadLoc, path, language); } async function loadColors(path: string): Promise> { diff --git a/src/renderer/src/lib/map/MapContainer.svelte b/src/renderer/src/lib/map/MapContainer.svelte index 6b79932..36d0eff 100644 --- a/src/renderer/src/lib/map/MapContainer.svelte +++ b/src/renderer/src/lib/map/MapContainer.svelte @@ -18,7 +18,7 @@ stellarisDataPromiseStore, stellarisPathStore, } from '../loadStellarisData'; - import { lastProcessedMapSettings, mapSettings } from '../settings'; + import { appStellarisLanguage, lastProcessedMapSettings, mapSettings } from '../settings'; import stellarMapsApi from '../stellarMapsApi'; import { debounce, timeItAsync, toastError } from '../utils'; import Map from './Map.svelte'; @@ -30,8 +30,9 @@ const modalStore = getModalStore(); $: mapDataPromise = - $gameStatePromise?.then((gs) => processMapData(gs, $lastProcessedMapSettings)) ?? - new Promise>>(() => {}); + $gameStatePromise?.then((gs) => + processMapData(gs, $lastProcessedMapSettings, $appStellarisLanguage), + ) ?? new Promise>>(() => {}); loadStellarisData(); const toastStore = getToastStore(); diff --git a/src/renderer/src/lib/map/data/processMapData.ts b/src/renderer/src/lib/map/data/processMapData.ts index 44f1558..01631a3 100644 --- a/src/renderer/src/lib/map/data/processMapData.ts +++ b/src/renderer/src/lib/map/data/processMapData.ts @@ -2,7 +2,7 @@ import * as R from 'rambda'; import { get } from 'svelte/store'; import type { GameState } from '../../GameState'; import debug from '../../debug'; -import type { MapSettings } from '../../settings'; +import { type MapSettings } from '../../settings'; import { timeIt, timeItAsync } from '../../utils'; import processBorders, { processBordersDeps } from './processBorders'; import processBypassLinks from './processBypassLinks'; @@ -24,7 +24,11 @@ import processTerraIncognitaPath, { import processVoronoi, { processVoronoiDeps } from './processVoronoi'; import { createHyperlanePaths } from './utils'; -export default async function processMapData(gameState: GameState, rawSettings: MapSettings) { +export default async function processMapData( + gameState: GameState, + rawSettings: MapSettings, + language: string, +) { console.time('TOTAL PROCESSING TIME'); const settings = { ...rawSettings }; if (settings.hyperlaneMetroStyle) settings.alignStarsToGrid = true; @@ -36,7 +40,7 @@ export default async function processMapData(gameState: GameState, rawSettings: cached(processEmblems), Object.values(gameState.country), ); - const countryNamesPromise = timeItAsync('names', cached(processNames), gameState); + const countryNamesPromise = timeItAsync('names', cached(processNames), gameState, language); const getSystemCoordinates = timeIt( 'system coordinates', diff --git a/src/renderer/src/lib/map/data/processNames.ts b/src/renderer/src/lib/map/data/processNames.ts index 4fee172..21e0512 100644 --- a/src/renderer/src/lib/map/data/processNames.ts +++ b/src/renderer/src/lib/map/data/processNames.ts @@ -3,7 +3,8 @@ import type { Country, GameState } from '../../GameState'; import { stellarisDataPromiseStore } from '../../loadStellarisData'; import { localizeTextSync } from './locUtils'; -export default async function processNames(gameState: GameState) { +// _language is just here to control caching +export default async function processNames(gameState: GameState, _language: string) { const countryNames = await localizeCountryNames(gameState.country); return countryNames; } diff --git a/src/renderer/src/lib/settings/appSettings.ts b/src/renderer/src/lib/settings/appSettings.ts index 60f5b84..1498c59 100644 --- a/src/renderer/src/lib/settings/appSettings.ts +++ b/src/renderer/src/lib/settings/appSettings.ts @@ -1,5 +1,5 @@ import { localStorageStore } from '@skeletonlabs/skeleton'; -import { get } from 'svelte/store'; +import { derived, get } from 'svelte/store'; import { locale } from '../../intl'; import stellarMapsApi from '../stellarMapsApi'; import { disableTranslatorMode, enableTranslatorMode } from '../translatorMode'; @@ -27,6 +27,7 @@ const defaultAppSettings: AppSettings = { }; export const appSettings = localStorageStore('appSettings', defaultAppSettings); +export const appStellarisLanguage = derived(appSettings, (value) => value.appStellarisLanguage); function loadSettings() { return getAppSettingsPath() @@ -39,10 +40,13 @@ function loadSettings() { .then((settings) => appSettings.set(settings)) .then(() => { appSettings.subscribe((settings) => { + // update locale locale.set(settings.appLocale as Parameters<(typeof locale)['set']>[0]); + // write to file createAppConfigDirIfNeeded() .then(getAppSettingsPath) .then((path) => stellarMapsApi.fs.writeFile(path, JSON.stringify(settings))); + // toggle translator mode if (settings.appTranslatorMode) { enableTranslatorMode(); } else { diff --git a/src/renderer/src/lib/stellarMapsApi.ts b/src/renderer/src/lib/stellarMapsApi.ts index 4851c5e..7529f53 100644 --- a/src/renderer/src/lib/stellarMapsApi.ts +++ b/src/renderer/src/lib/stellarMapsApi.ts @@ -27,8 +27,8 @@ if (stellarMapsApi == null) { loadColors(path) { return invoke('get_stellaris_colors_cmd', { path }); }, - loadLoc(path) { - return invoke('get_stellaris_loc_cmd', { path }); + loadLoc(path, language) { + return invoke('get_stellaris_loc_cmd', { path, language }); }, loadStellarisInstallDir() { return invoke('get_stellaris_install_dir_cmd'); diff --git a/src/shared/StellarMapsApi.ts b/src/shared/StellarMapsApi.ts index 4917502..5f35b41 100644 --- a/src/shared/StellarMapsApi.ts +++ b/src/shared/StellarMapsApi.ts @@ -7,7 +7,7 @@ interface StellarisSaveMetadata { export interface StellarMapsAPI { loadSaveMetadata(): Promise<[StellarisSaveMetadata, ...StellarisSaveMetadata[]][]>; - loadLoc(installPath: string): Promise>; + loadLoc(installPath: string, language: string): Promise>; loadColors(installPath: string): Promise; loadStellarisInstallDir(): Promise; loadSave(savePath: string): Promise;