mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-14 10:34:06 +02:00
Change default language to en-US and add US language (#6621)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en-GB">
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<base href="%BASE_URL%" />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -243,7 +243,7 @@ const LanguageSelector: React.FC<LanguageSelectorProps> = ({
|
||||
|
||||
const currentLanguage =
|
||||
supportedLanguages[i18n.language as keyof typeof supportedLanguages] ||
|
||||
supportedLanguages["en-GB"] ||
|
||||
supportedLanguages["en-US"] ||
|
||||
"English"; // Fallback if supportedLanguages lookup fails
|
||||
|
||||
// Hide the language selector if there's only one language option
|
||||
|
||||
@@ -5,7 +5,8 @@ import TomlBackend from "@app/i18n/tomlBackend";
|
||||
|
||||
// Define supported languages (based on your existing translations)
|
||||
export const supportedLanguages = {
|
||||
"en-GB": "English",
|
||||
"en-US": "English (US)",
|
||||
"en-GB": "English (UK)",
|
||||
"ar-AR": "العربية",
|
||||
"az-AZ": "Azərbaycan Dili",
|
||||
"bg-BG": "Български",
|
||||
@@ -72,7 +73,7 @@ i18n
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
fallbackLng: "en-GB",
|
||||
fallbackLng: "en-US",
|
||||
supportedLngs: Object.keys(supportedLanguages),
|
||||
load: "currentOnly",
|
||||
nonExplicitSupportedLngs: false,
|
||||
@@ -100,8 +101,8 @@ i18n
|
||||
order: ["localStorage", "navigator", "htmlTag"],
|
||||
caches: [], // Don't cache auto-detected language - only cache when user manually selects
|
||||
convertDetectedLanguage: (lng: string) => {
|
||||
// Map en and en-US to en-GB
|
||||
if (lng === "en" || lng === "en-US") return "en-GB";
|
||||
// Map bare en to en-US
|
||||
if (lng === "en") return "en-US";
|
||||
return lng;
|
||||
},
|
||||
},
|
||||
@@ -154,7 +155,7 @@ export function normalizeLanguageCode(languageCode: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert language codes to underscore format (e.g., en-GB → en_GB)
|
||||
* Convert language codes to underscore format (e.g., en-US → en_US)
|
||||
* Used for backend API communication which expects underscore format
|
||||
*/
|
||||
export function toUnderscoreFormat(languageCode: string): string {
|
||||
@@ -212,7 +213,7 @@ export function setUserLanguage(language: string): void {
|
||||
* Updates the supported languages list dynamically based on config
|
||||
* If configLanguages is null/empty, all languages remain available
|
||||
* Otherwise, only the specified languages are enabled with the first valid
|
||||
* option (preferring en-GB when present) used as the fallback language.
|
||||
* option (preferring en-US when present) used as the fallback language.
|
||||
*
|
||||
* @param configLanguages - Optional array of language codes from server config (ui.languages)
|
||||
* @param defaultLocale - Optional default language for new users (system.defaultLocale)
|
||||
@@ -248,12 +249,12 @@ export function updateSupportedLanguages(
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine fallback: prefer validDefault if in the list, then en-GB, then first valid language
|
||||
// Determine fallback: prefer validDefault if in the list, then en-US, then first valid language
|
||||
const fallback =
|
||||
validDefault && validLanguages.includes(validDefault)
|
||||
? validDefault
|
||||
: validLanguages.includes("en-GB")
|
||||
? "en-GB"
|
||||
: validLanguages.includes("en-US")
|
||||
? "en-US"
|
||||
: validLanguages[0];
|
||||
|
||||
i18n.options.supportedLngs = validLanguages;
|
||||
|
||||
@@ -154,8 +154,8 @@ export async function mockAppApis(
|
||||
email: "[email protected]",
|
||||
roles: ["ROLE_USER"],
|
||||
},
|
||||
languages = ["en-GB"],
|
||||
defaultLocale = "en-GB",
|
||||
languages = ["en-US"],
|
||||
defaultLocale = "en-US",
|
||||
endpointsAvailability = {},
|
||||
backendStatus = "UP",
|
||||
} = opts;
|
||||
|
||||
@@ -6,9 +6,9 @@ import { parse } from "smol-toml";
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, "../../../..");
|
||||
const SRC_ROOT = path.join(__dirname, "../..");
|
||||
const EN_GB_FILE = path.join(
|
||||
const EN_US_FILE = path.join(
|
||||
__dirname,
|
||||
"../../../public/locales/en-GB/translation.toml",
|
||||
"../../../public/locales/en-US/translation.toml",
|
||||
);
|
||||
|
||||
const IGNORED_DIRS = new Set(["tests", "__mocks__"]);
|
||||
@@ -174,14 +174,14 @@ const extractKeys = (file: string): FoundKey[] => {
|
||||
|
||||
describe("Missing translation coverage", () => {
|
||||
test(
|
||||
"fails if any en-GB translation key used in source is missing",
|
||||
"fails if any en-US translation key used in source is missing",
|
||||
{ timeout: 10000 },
|
||||
() => {
|
||||
expect(fs.existsSync(EN_GB_FILE)).toBe(true);
|
||||
expect(fs.existsSync(EN_US_FILE)).toBe(true);
|
||||
|
||||
const localeContent = fs.readFileSync(EN_GB_FILE, "utf8");
|
||||
const enGb = parse(localeContent);
|
||||
const availableKeys = flattenKeys(enGb);
|
||||
const localeContent = fs.readFileSync(EN_US_FILE, "utf8");
|
||||
const enUs = parse(localeContent);
|
||||
const availableKeys = flattenKeys(enUs);
|
||||
|
||||
const usedKeys = listSourceFiles()
|
||||
.flatMap(extractKeys)
|
||||
@@ -211,7 +211,7 @@ describe("Missing translation coverage", () => {
|
||||
// Output errors in GitHub Annotations format so they appear tagged in the code in CI
|
||||
for (const { key, fallback, file, line, column } of annotations) {
|
||||
process.stderr.write(
|
||||
`::error file=${file},line=${line},col=${column}::Missing en-GB translation for ${key} (${fallback})\n`,
|
||||
`::error file=${file},line=${line},col=${column}::Missing en-US translation for ${key} (${fallback})\n`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ test.describe("OAuth/SSO login buttons", () => {
|
||||
route.fulfill({
|
||||
json: {
|
||||
enableLogin: true,
|
||||
languages: ["en-GB"],
|
||||
defaultLocale: "en-GB",
|
||||
languages: ["en-US"],
|
||||
defaultLocale: "en-US",
|
||||
oauth2: {
|
||||
enabled: true,
|
||||
providers: [
|
||||
|
||||
@@ -6,9 +6,9 @@ import { parse } from "smol-toml";
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, "../../../..");
|
||||
const SRC_ROOT = path.join(__dirname, "../..");
|
||||
const EN_GB_FILE = path.join(
|
||||
const EN_US_FILE = path.join(
|
||||
__dirname,
|
||||
"../../../public/locales/en-GB/translation.toml",
|
||||
"../../../public/locales/en-US/translation.toml",
|
||||
);
|
||||
|
||||
const IGNORED_DIRS = new Set(["tests", "__mocks__"]);
|
||||
@@ -151,13 +151,13 @@ const isIgnored = (key: string): boolean => {
|
||||
|
||||
describe("Unused translation coverage", () => {
|
||||
test(
|
||||
"fails if any en-GB translation key has no source references",
|
||||
"fails if any en-US translation key has no source references",
|
||||
{ timeout: 30_000 },
|
||||
() => {
|
||||
expect(fs.existsSync(EN_GB_FILE)).toBe(true);
|
||||
expect(fs.existsSync(EN_US_FILE)).toBe(true);
|
||||
|
||||
const enGb = parse(fs.readFileSync(EN_GB_FILE, "utf8"));
|
||||
const availableKeys = Array.from(flattenKeys(enGb));
|
||||
const enUs = parse(fs.readFileSync(EN_US_FILE, "utf8"));
|
||||
const availableKeys = Array.from(flattenKeys(enUs));
|
||||
expect(availableKeys.length).toBeGreaterThan(100); // sanity check
|
||||
|
||||
const sourceFiles = listSourceFiles();
|
||||
@@ -184,20 +184,20 @@ describe("Unused translation coverage", () => {
|
||||
});
|
||||
|
||||
const localeRelative = path
|
||||
.relative(REPO_ROOT, EN_GB_FILE)
|
||||
.relative(REPO_ROOT, EN_US_FILE)
|
||||
.replace(/\\/g, "/");
|
||||
|
||||
// GitHub Annotations format so unused keys show up tagged on the
|
||||
// translation file in CI.
|
||||
for (const key of unused) {
|
||||
process.stderr.write(
|
||||
`::error file=${localeRelative}::Unused en-GB translation: ${key}\n`,
|
||||
`::error file=${localeRelative}::Unused en-US translation: ${key}\n`,
|
||||
);
|
||||
}
|
||||
|
||||
expect(
|
||||
unused,
|
||||
`Found ${unused.length} unused en-GB translation key(s). ` +
|
||||
`Found ${unused.length} unused en-US translation key(s). ` +
|
||||
`Remove them from ${localeRelative}, or (if the usage is too ` +
|
||||
`dynamic for the heuristic to spot) add to IGNORED_KEY_PATTERNS ` +
|
||||
`in this test.`,
|
||||
|
||||
@@ -13,7 +13,16 @@ const languageDefinitions: LanguageDefinition[] = [
|
||||
{
|
||||
ocrCode: "eng",
|
||||
displayName: "English",
|
||||
browserCodes: ["en", "en-GB", "en-AU", "en-CA", "en-IE", "en-NZ", "en-ZA"],
|
||||
browserCodes: [
|
||||
"en",
|
||||
"en-US",
|
||||
"en-GB",
|
||||
"en-AU",
|
||||
"en-CA",
|
||||
"en-IE",
|
||||
"en-NZ",
|
||||
"en-ZA",
|
||||
],
|
||||
},
|
||||
|
||||
// Spanish
|
||||
@@ -908,12 +917,12 @@ languageDefinitions.forEach((lang) => {
|
||||
* Maps a browser language code to an OCR language code
|
||||
* Handles exact matches and similar language fallbacks
|
||||
*
|
||||
* @param browserLanguage - The browser language code (e.g., 'en-GB', 'fr-FR')
|
||||
* @param browserLanguage - The browser language code (e.g., 'en-US', 'fr-FR')
|
||||
* @returns OCR language code if found, null if no match
|
||||
*
|
||||
* @example
|
||||
* mapBrowserLanguageToOcr('de-DE') // Returns 'deu'
|
||||
* mapBrowserLanguageToOcr('en-GB') // Returns 'eng'
|
||||
* mapBrowserLanguageToOcr('en-US') // Returns 'eng'
|
||||
* mapBrowserLanguageToOcr('zh-CN') // Returns 'chi_sim'
|
||||
*/
|
||||
export function mapBrowserLanguageToOcr(
|
||||
@@ -940,7 +949,7 @@ export function mapBrowserLanguageToOcr(
|
||||
if (match) return match;
|
||||
}
|
||||
|
||||
// Try base language code (e.g., 'en' from 'en-GB')
|
||||
// Try base language code (e.g., 'en' from 'en-US')
|
||||
const baseLanguage = normalizedInput.split("-")[0];
|
||||
const baseMatch = browserToOcrMap.get(baseLanguage);
|
||||
if (baseMatch) return baseMatch;
|
||||
@@ -1002,7 +1011,7 @@ export function getBrowserLanguagesForOcr(ocrCode: string): string[] {
|
||||
*
|
||||
* @example
|
||||
* getAutoOcrLanguage('de-DE') // Returns ['deu']
|
||||
* getAutoOcrLanguage('en-GB') // Returns ['eng']
|
||||
* getAutoOcrLanguage('en-US') // Returns ['eng']
|
||||
* getAutoOcrLanguage('unknown') // Returns []
|
||||
*/
|
||||
export function getAutoOcrLanguage(currentLanguage: string): string[] {
|
||||
|
||||
+1
-1
@@ -625,7 +625,7 @@ export default function AdminGeneralSection() {
|
||||
data={defaultLocaleOptions}
|
||||
searchable
|
||||
clearable
|
||||
placeholder="en_GB"
|
||||
placeholder="en_US"
|
||||
comboboxProps={{ zIndex: Z_INDEX_CONFIG_MODAL }}
|
||||
disabled={!loginEnabled}
|
||||
/>
|
||||
|
||||
@@ -26,10 +26,10 @@ vi.mock("react-i18next", () => ({
|
||||
// Mock i18n module to avoid initialization
|
||||
vi.mock("@app/i18n", () => ({
|
||||
updateSupportedLanguages: vi.fn(),
|
||||
supportedLanguages: { "en-GB": "English" },
|
||||
supportedLanguages: { "en-US": "English (US)" },
|
||||
rtlLanguages: [],
|
||||
default: {
|
||||
language: "en-GB",
|
||||
language: "en-US",
|
||||
changeLanguage: vi.fn(),
|
||||
options: {},
|
||||
},
|
||||
|
||||
@@ -50,7 +50,7 @@ export function TrialStatusBanner() {
|
||||
}
|
||||
|
||||
const trialEndDate = new Date(trialStatus.trialEnd).toLocaleDateString(
|
||||
"en-GB",
|
||||
"en-US",
|
||||
{
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en-GB">
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
Reference in New Issue
Block a user