mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-13 03:30:43 -05:00
Fix issues around locales (!332)
- Remove locale check for give command (Now handled in the localeService itself) - Fix variable names/spelling/lowercase in LocaleService.getPlatformForServerLocale (should be no change in behaviour) - Rewrite LocaleService.getPlatformForClientLocale to not depend on serverSupportedLocales, and instead just use the tables for validity checking - Expand fallback of client locale handling to include the region code (Handles Czech and Korean locales) - Write tests for locales Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com> Reviewed-on: SPT-AKI/Server#332 Co-authored-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com> Co-committed-by: DrakiaXYZ <drakiaxyz@noreply.dev.sp-tarkov.com>
This commit is contained in:
parent
5254e9753e
commit
adab18e3fb
@ -129,15 +129,6 @@ export class GiveSptCommand implements ISptCommand
|
||||
try
|
||||
{
|
||||
locale = result[4] ? result[4] : this.localeService.getDesiredGameLocale() ?? "en";
|
||||
if (!this.localeService.getServerSupportedLocales().includes(locale))
|
||||
{
|
||||
this.mailSendService.sendUserMessageToPlayer(
|
||||
sessionId,
|
||||
commandHandler,
|
||||
`Unknown locale "${locale}". Use \"help\" for more information.`,
|
||||
);
|
||||
return request.dialogId;
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { ILocaleConfig } from "@spt-aki/models/spt/config/ILocaleConfig";
|
||||
import { ILocaleBase } from "@spt-aki/models/spt/server/ILocaleBase";
|
||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
@ -12,6 +13,7 @@ import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||
export class LocaleService
|
||||
{
|
||||
protected localeConfig: ILocaleConfig;
|
||||
protected localesTable: ILocaleBase;
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@ -20,6 +22,7 @@ export class LocaleService
|
||||
)
|
||||
{
|
||||
this.localeConfig = this.configServer.getConfig(ConfigTypes.LOCALE);
|
||||
this.localesTable = this.databaseServer.getTables().locales;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -28,7 +31,7 @@ export class LocaleService
|
||||
*/
|
||||
public getLocaleDb(): Record<string, string>
|
||||
{
|
||||
const desiredLocale = this.databaseServer.getTables().locales.global[this.getDesiredGameLocale()];
|
||||
const desiredLocale = this.localesTable.global[this.getDesiredGameLocale()];
|
||||
if (desiredLocale)
|
||||
{
|
||||
return desiredLocale;
|
||||
@ -38,7 +41,7 @@ export class LocaleService
|
||||
`Unable to find desired locale file using locale: ${this.getDesiredGameLocale()} from config/locale.json, falling back to 'en'`,
|
||||
);
|
||||
|
||||
return this.databaseServer.getTables().locales.global.en;
|
||||
return this.localesTable.global.en;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,29 +98,30 @@ export class LocaleService
|
||||
*/
|
||||
protected getPlatformForServerLocale(): string
|
||||
{
|
||||
const platformLocale = new Intl.Locale(Intl.DateTimeFormat().resolvedOptions().locale);
|
||||
const platformLocale = this.getPlatformLocale();
|
||||
if (!platformLocale)
|
||||
{
|
||||
this.logger.warning("System langauge could not be found, falling back to english");
|
||||
this.logger.warning("System language could not be found, falling back to english");
|
||||
|
||||
return "en";
|
||||
}
|
||||
|
||||
const localeCode = platformLocale.baseName.toLowerCase();
|
||||
if (!this.localeConfig.serverSupportedLocales.includes(localeCode))
|
||||
const baseNameCode = platformLocale.baseName.toLowerCase();
|
||||
if (!this.localeConfig.serverSupportedLocales.includes(baseNameCode))
|
||||
{
|
||||
// Chek if base language (e.g. CN / EN / DE) exists
|
||||
if (this.localeConfig.serverSupportedLocales.includes(platformLocale.language))
|
||||
const languageCode = platformLocale.language.toLocaleLowerCase();
|
||||
if (this.localeConfig.serverSupportedLocales.includes(languageCode))
|
||||
{
|
||||
return platformLocale.language;
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
this.logger.warning(`Unsupported system langauge found: ${localeCode}, falling back to english`);
|
||||
this.logger.warning(`Unsupported system language found: ${baseNameCode}, falling back to english`);
|
||||
|
||||
return "en";
|
||||
}
|
||||
|
||||
return localeCode;
|
||||
return baseNameCode;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -126,26 +130,29 @@ export class LocaleService
|
||||
*/
|
||||
protected getPlatformForClientLocale(): string
|
||||
{
|
||||
const platformLocale = new Intl.Locale(Intl.DateTimeFormat().resolvedOptions().locale);
|
||||
const platformLocale = this.getPlatformLocale();
|
||||
if (!platformLocale)
|
||||
{
|
||||
this.logger.warning("System langauge could not be found, falling back to english");
|
||||
|
||||
this.logger.warning("System language could not be found, falling back to english");
|
||||
return "en";
|
||||
}
|
||||
|
||||
const langaugeCode = platformLocale.language.toLowerCase();
|
||||
if (!this.localeConfig.serverSupportedLocales.includes(langaugeCode))
|
||||
const baseNameCode = platformLocale.baseName?.toLocaleLowerCase();
|
||||
if (baseNameCode && this.localesTable.global[baseNameCode])
|
||||
{
|
||||
this.logger.warning(`Unsupported system langauge found: ${langaugeCode}, falling back to english`);
|
||||
|
||||
return "en";
|
||||
return baseNameCode;
|
||||
}
|
||||
|
||||
// BSG map Czech to CZ for some reason
|
||||
if (platformLocale.language === "cs")
|
||||
const languageCode = platformLocale.language?.toLowerCase();
|
||||
if (languageCode && this.localesTable.global[languageCode])
|
||||
{
|
||||
return "cz";
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
const regionCode = platformLocale.region?.toLocaleLowerCase();
|
||||
if (regionCode && this.localesTable.global[regionCode])
|
||||
{
|
||||
return regionCode;
|
||||
}
|
||||
|
||||
// BSG map DE to GE some reason
|
||||
@ -154,6 +161,16 @@ export class LocaleService
|
||||
return "ge";
|
||||
}
|
||||
|
||||
return langaugeCode;
|
||||
this.logger.warning(`Unsupported system language found: ${languageCode}, falling back to english`);
|
||||
return "en";
|
||||
}
|
||||
|
||||
/**
|
||||
* This is in a function so we can overwrite it during testing
|
||||
* @returns The current platform locale
|
||||
*/
|
||||
protected getPlatformLocale(): Intl.Locale
|
||||
{
|
||||
return new Intl.Locale(Intl.DateTimeFormat().resolvedOptions().locale);
|
||||
}
|
||||
}
|
||||
|
124
project/tests/services/LocaleService.test.ts
Normal file
124
project/tests/services/LocaleService.test.ts
Normal file
@ -0,0 +1,124 @@
|
||||
import { container } from "tsyringe";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { LocaleService } from "@spt-aki/services/LocaleService";
|
||||
|
||||
describe("LocaleService", () =>
|
||||
{
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
let localeService: any; // Using "any" to access private/protected methods without type errors.
|
||||
|
||||
beforeEach(() =>
|
||||
{
|
||||
localeService = container.resolve<LocaleService>("LocaleService");
|
||||
});
|
||||
|
||||
afterEach(() =>
|
||||
{
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("ValidateServerLocale", () =>
|
||||
{
|
||||
it("should return 'en' for 'en-US'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("en-US");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForServerLocale()).toBe("en");
|
||||
});
|
||||
|
||||
it("should return 'ko' for 'ko-KR'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("ko-KR");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForServerLocale()).toBe("ko");
|
||||
});
|
||||
|
||||
it("should return 'pt-pt' for 'pt-PT'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("pt-PT");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForServerLocale()).toBe("pt-pt");
|
||||
});
|
||||
|
||||
it("should return 'pt-br' for 'pt-BR'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("pt-BR");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForServerLocale()).toBe("pt-br");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ValidateClientLocale", () =>
|
||||
{
|
||||
it("should return 'en' for 'en-US'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("en-US");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForClientLocale()).toBe("en");
|
||||
});
|
||||
|
||||
it("should return 'kr' for 'ko-KR'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("ko-KR");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForClientLocale()).toBe("kr");
|
||||
});
|
||||
|
||||
it("should return 'es-mx' for 'es-MX'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("es-MX");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForClientLocale()).toBe("es-mx");
|
||||
});
|
||||
|
||||
it("should return 'cz' for 'cs-CZ'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("cs-CZ");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForClientLocale()).toBe("cz");
|
||||
});
|
||||
|
||||
it("should return 'ge' for 'de-DE'", () =>
|
||||
{
|
||||
// Override the get locale so we control what the input is
|
||||
localeService.getPlatformLocale = () =>
|
||||
{
|
||||
return new Intl.Locale("de-DE");
|
||||
};
|
||||
|
||||
expect(localeService.getPlatformForClientLocale()).toBe("ge");
|
||||
});
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user