mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-22 19:16:09 -05:00
Fix leaderboards crash for season 0
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import clsx from "clsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { countryCodeToTranslatedName } from "~/utils/i18n";
|
||||
|
||||
export function Flag({
|
||||
countryCode,
|
||||
@@ -9,15 +10,17 @@ export function Flag({
|
||||
tiny?: boolean;
|
||||
}) {
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(`twf twf-${countryCode.toLowerCase()}`, {
|
||||
"twf-s": tiny,
|
||||
})}
|
||||
data-testid={`flag-${countryCode}`}
|
||||
title={new Intl.DisplayNames([i18n.language], { type: "region" }).of(
|
||||
title={countryCodeToTranslatedName({
|
||||
countryCode,
|
||||
)}
|
||||
language: i18n.language,
|
||||
})}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { BADGE } from "~/features/badges/badges-constants";
|
||||
import { BadgesSelector } from "~/features/badges/components/BadgesSelector";
|
||||
import { useIsMounted } from "~/hooks/useIsMounted";
|
||||
import { useHasRole } from "~/modules/permissions/hooks";
|
||||
import { countryCodeToTranslatedName } from "~/utils/i18n";
|
||||
import invariant from "~/utils/invariant";
|
||||
import { rawSensToString } from "~/utils/strings";
|
||||
import { FAQ_PAGE } from "~/utils/urls";
|
||||
@@ -215,12 +216,13 @@ function CountrySelect() {
|
||||
const isMounted = useIsMounted();
|
||||
const [value, setValue] = React.useState(data.user.country ?? null);
|
||||
|
||||
const displayName = new Intl.DisplayNames(i18n.language, { type: "region" });
|
||||
|
||||
// TODO: if react-aria-components start supporting "suppressHydrationWarning" it would likely be a better solution here
|
||||
const items = COUNTRY_CODES.map((countryCode) => ({
|
||||
name: isMounted
|
||||
? (displayName.of(countryCode) ?? countryCode)
|
||||
? countryCodeToTranslatedName({
|
||||
countryCode,
|
||||
language: i18n.language,
|
||||
})
|
||||
: countryCode,
|
||||
id: countryCode,
|
||||
key: countryCode,
|
||||
|
||||
38
app/utils/i18n.test.ts
Normal file
38
app/utils/i18n.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { countryCodeToTranslatedName } from "./i18n";
|
||||
|
||||
describe("countryCodeToTranslatedName()", () => {
|
||||
it("returns the translated country name for a valid code", () => {
|
||||
const result = countryCodeToTranslatedName({
|
||||
countryCode: "FI",
|
||||
language: "fi",
|
||||
});
|
||||
expect(result).toBe("Suomi");
|
||||
});
|
||||
|
||||
it("returns the country code if it contains a dash (Intl.DisplayNames throws)", () => {
|
||||
const result = countryCodeToTranslatedName({
|
||||
countryCode: "GB-WLS",
|
||||
language: "en",
|
||||
});
|
||||
expect(result).toBe("GB-WLS");
|
||||
});
|
||||
|
||||
it("returns the country code as is for unknown country", () => {
|
||||
const result = countryCodeToTranslatedName({
|
||||
countryCode: "UNKNOWN",
|
||||
language: "en",
|
||||
});
|
||||
|
||||
expect(result).toBe("UNKNOWN");
|
||||
});
|
||||
|
||||
it("defaults to english for unknown language", () => {
|
||||
const result = countryCodeToTranslatedName({
|
||||
countryCode: "FI",
|
||||
language: "unknown",
|
||||
});
|
||||
|
||||
expect(result).toBe("Finland");
|
||||
});
|
||||
});
|
||||
41
app/utils/i18n.ts
Normal file
41
app/utils/i18n.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { logger } from "./logger";
|
||||
|
||||
/**
|
||||
* Returns the localized display name for a given ISO country code using the specified language. If the country code is unknown or the function fails for othe reason, returns the country code itself as a fallback.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* function CountryNameComponent() {
|
||||
* const { i18n } = useTranslation();
|
||||
* const countryName = countryCodeToTranslatedName({
|
||||
* countryCode: "FI",
|
||||
* language: i18n.language,
|
||||
* }); // "Suomi" in Finnish
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function countryCodeToTranslatedName({
|
||||
countryCode,
|
||||
language,
|
||||
}: {
|
||||
countryCode: string;
|
||||
language: string;
|
||||
}) {
|
||||
// known limitation, function cannot handle e.g. GB-WLS (Wales)
|
||||
if (countryCode.includes("-")) {
|
||||
return countryCode;
|
||||
}
|
||||
|
||||
try {
|
||||
return (
|
||||
new Intl.DisplayNames([language], { type: "region" }).of(countryCode) ??
|
||||
countryCode
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`Error getting display name for country code "${countryCode}":`,
|
||||
e,
|
||||
);
|
||||
return countryCode; // fallback to the code itself if display name fails
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user