feat: unify language handling across the application

- Updated the language configuration to use a single source of truth from `DEFAULT_LANGUAGE` for the bot, API, and Mini App, eliminating auto-detection from user settings.
- Refactored the `get_lang` function to always return `DEFAULT_LANGUAGE`, ensuring consistent language usage throughout the application.
- Modified the handling of language in various components, including API responses and UI elements, to reflect the new language management approach.
- Enhanced documentation and comments to clarify the changes in language handling.
- Added unit tests to verify the new language handling behavior and ensure coverage for the updated functionality.
This commit is contained in:
2026-03-02 23:05:28 +03:00
parent 54446d7b0f
commit 67ba9826c7
21 changed files with 446 additions and 205 deletions

View File

@@ -1,50 +1,76 @@
/**
* Unit tests for i18n: getLang, t (fallback, params), monthName.
* Unit tests for i18n: getLang (window.__DT_LANG), normalizeLang, t (fallback, params), monthName.
*/
import { describe, it, expect, vi, beforeEach } from "vitest";
import { describe, it, expect, beforeEach, afterEach } from "vitest";
const mockGetInitData = vi.fn();
vi.mock("./auth.js", () => ({ getInitData: () => mockGetInitData() }));
import { getLang, t, monthName, MESSAGES } from "./i18n.js";
import { getLang, normalizeLang, t, monthName, MESSAGES } from "./i18n.js";
describe("getLang", () => {
const origNavigator = globalThis.navigator;
const orig__DT_LANG = globalThis.window?.__DT_LANG;
beforeEach(() => {
mockGetInitData.mockReset();
afterEach(() => {
if (typeof globalThis.window !== "undefined") {
if (orig__DT_LANG !== undefined) {
globalThis.window.__DT_LANG = orig__DT_LANG;
} else {
delete globalThis.window.__DT_LANG;
}
}
});
it("returns lang from initData user when present", () => {
mockGetInitData.mockReturnValue(
"user=" + encodeURIComponent(JSON.stringify({ language_code: "en" }))
);
expect(getLang()).toBe("en");
});
it("normalizes ru from initData", () => {
mockGetInitData.mockReturnValue(
"user=" + encodeURIComponent(JSON.stringify({ language_code: "ru" }))
);
it("returns ru when window.__DT_LANG is ru", () => {
globalThis.window.__DT_LANG = "ru";
expect(getLang()).toBe("ru");
});
it("falls back to navigator.language when initData empty", () => {
mockGetInitData.mockReturnValue("");
Object.defineProperty(globalThis, "navigator", {
value: { ...origNavigator, language: "en-US", languages: ["en-US", "en"] },
configurable: true,
});
it("returns en when window.__DT_LANG is en", () => {
globalThis.window.__DT_LANG = "en";
expect(getLang()).toBe("en");
});
it("normalizes to en for unknown language code", () => {
mockGetInitData.mockReturnValue(
"user=" + encodeURIComponent(JSON.stringify({ language_code: "uk" }))
);
it("returns en when window.__DT_LANG is missing", () => {
delete globalThis.window.__DT_LANG;
expect(getLang()).toBe("en");
});
it("returns en when window.__DT_LANG is invalid (unknown code)", () => {
globalThis.window.__DT_LANG = "uk";
expect(getLang()).toBe("en");
});
it("returns ru when window.__DT_LANG is ru-RU (normalized)", () => {
globalThis.window.__DT_LANG = "ru-RU";
expect(getLang()).toBe("ru");
});
it("returns en when window.__DT_LANG is empty string", () => {
globalThis.window.__DT_LANG = "";
expect(getLang()).toBe("en");
});
it("returns en when window.__DT_LANG is null", () => {
globalThis.window.__DT_LANG = null;
expect(getLang()).toBe("en");
});
});
describe("normalizeLang", () => {
it("returns ru for ru-like codes", () => {
expect(normalizeLang("ru")).toBe("ru");
expect(normalizeLang("ru-RU")).toBe("ru");
});
it("returns en for en and others", () => {
expect(normalizeLang("en")).toBe("en");
expect(normalizeLang("en-US")).toBe("en");
expect(normalizeLang("uk")).toBe("en");
});
it("returns en for empty or invalid", () => {
expect(normalizeLang("")).toBe("en");
expect(normalizeLang(null)).toBe("en");
});
});
describe("t", () => {