Skip to content

Commit 9c79bf2

Browse files
committed
fix(i18n): default interface language to english
1 parent fabdd0e commit 9c79bf2

File tree

5 files changed

+66
-44
lines changed

5 files changed

+66
-44
lines changed

src/components/settings-modal/interface-settings/__tests__/interface-settings.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
66
import packageJson from '../../../../../package.json';
77
import InterfaceSettings from '../interface-settings';
88
import useFeedViewSettingsStore from '../../../../stores/use-feed-view-settings-store';
9+
import { INTERFACE_LANGUAGE_STORAGE_KEY } from '../../../../lib/constants';
910

1011
(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
1112
const act = (React as { act?: (cb: () => void | Promise<void>) => void | Promise<void> }).act as (cb: () => void | Promise<void>) => void | Promise<void>;
@@ -155,6 +156,7 @@ describe('InterfaceSettings', () => {
155156
});
156157

157158
expect(testState.changeLanguageMock).toHaveBeenCalledWith('fr');
159+
expect(localStorage.getItem(INTERFACE_LANGUAGE_STORAGE_KEY)).toBe('fr');
158160
});
159161

160162
it('disables the update button while fetching and restores it afterward', async () => {

src/components/settings-modal/interface-settings/interface-settings.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import capitalize from 'lodash/capitalize';
66
import useExpandedMediaStore from '../../../stores/use-expanded-media-store';
77
import useFeedViewSettingsStore from '../../../stores/use-feed-view-settings-store';
88
import Version from '../../version';
9+
import { INTERFACE_LANGUAGE_STORAGE_KEY, SUPPORTED_INTERFACE_LANGUAGES } from '../../../lib/constants';
910

1011
const commitRef = process.env.VITE_COMMIT_REF;
1112
const isElectron = window.electronApi?.isElectron === true;
@@ -67,21 +68,20 @@ const CheckForUpdates = () => {
6768
);
6869
};
6970

70-
// prettier-ignore
71-
const availableLanguages = ['ar', 'bn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fil', 'fr', 'he', 'hi', 'hu', 'id', 'it', 'ja', 'ko', 'mr', 'nl', 'no', 'pl', 'pt', 'ro', 'ru', 'sq', 'sv', 'te', 'th', 'tr', 'uk', 'ur', 'vi', 'zh'];
72-
7371
const InterfaceLanguage = () => {
7472
const { i18n } = useTranslation();
7573
const { changeLanguage, language } = i18n;
7674

7775
const onSelectLanguage = (e: React.ChangeEvent<HTMLSelectElement>) => {
78-
changeLanguage(e.target.value);
76+
const selectedLanguage = e.target.value;
77+
localStorage.setItem(INTERFACE_LANGUAGE_STORAGE_KEY, selectedLanguage);
78+
changeLanguage(selectedLanguage);
7979
};
8080

8181
return (
8282
<div className={styles.languageSettings}>
8383
<select value={language} onChange={onSelectLanguage}>
84-
{availableLanguages.map((lang) => (
84+
{SUPPORTED_INTERFACE_LANGUAGES.map((lang) => (
8585
<option key={lang} value={lang}>
8686
{lang}
8787
</option>

src/lib/__tests__/init-translations.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { DEFAULT_INTERFACE_LANGUAGE, INTERFACE_LANGUAGE_STORAGE_KEY } from '../constants';
23

34
const testState = vi.hoisted(() => {
45
const i18next = {
@@ -47,10 +48,15 @@ describe('init-translations', () => {
4748
expect(testState.i18next.use).toHaveBeenNthCalledWith(3, testState.reactPlugin);
4849
expect(testState.i18next.init).toHaveBeenCalledWith(
4950
expect.objectContaining({
50-
fallbackLng: 'en',
51+
fallbackLng: DEFAULT_INTERFACE_LANGUAGE,
5152
ns: ['default'],
5253
defaultNS: 'default',
5354
backend: { loadPath: './translations/{{lng}}/{{ns}}.json' },
55+
detection: {
56+
order: ['localStorage'],
57+
caches: ['localStorage'],
58+
lookupLocalStorage: INTERFACE_LANGUAGE_STORAGE_KEY,
59+
},
5460
}),
5561
);
5662
expect(testState.i18next.init.mock.calls[0]?.[0]?.supportedLngs).toContain('en');

src/lib/constants.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,47 @@ export const BOARD_REPLIES_PREVIEW_VISIBLE_COUNT = 5;
66

77
/** Number of replies fetched for preview mode on board/listing views. */
88
export const BOARD_REPLIES_PREVIEW_FETCH_SIZE = 25;
9+
10+
/** 5chan ships in English by default; users must opt into other languages manually. */
11+
export const DEFAULT_INTERFACE_LANGUAGE = 'en';
12+
13+
/** Persist only deliberate in-app language selections, never OS/browser auto-detection. */
14+
export const INTERFACE_LANGUAGE_STORAGE_KEY = '5chan-interface-language';
15+
16+
export const SUPPORTED_INTERFACE_LANGUAGES = [
17+
'ar',
18+
'bn',
19+
'cs',
20+
'da',
21+
'de',
22+
'el',
23+
'en',
24+
'es',
25+
'fa',
26+
'fi',
27+
'fil',
28+
'fr',
29+
'he',
30+
'hi',
31+
'hu',
32+
'id',
33+
'it',
34+
'ja',
35+
'ko',
36+
'mr',
37+
'nl',
38+
'no',
39+
'pl',
40+
'pt',
41+
'ro',
42+
'ru',
43+
'sq',
44+
'sv',
45+
'te',
46+
'th',
47+
'tr',
48+
'uk',
49+
'ur',
50+
'vi',
51+
'zh',
52+
] as const;

src/lib/init-translations.ts

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import i18next from 'i18next';
22
import HttpBackend from 'i18next-http-backend';
33
import LanguageDetector from 'i18next-browser-languagedetector';
44
import { initReactI18next } from 'react-i18next';
5+
import { DEFAULT_INTERFACE_LANGUAGE, INTERFACE_LANGUAGE_STORAGE_KEY, SUPPORTED_INTERFACE_LANGUAGES } from './constants';
56

67
const loadPath = `./translations/{{lng}}/{{ns}}.json`;
78

@@ -10,44 +11,13 @@ i18next
1011
.use(LanguageDetector)
1112
.use(initReactI18next)
1213
.init({
13-
fallbackLng: 'en',
14-
supportedLngs: [
15-
'ar',
16-
'bn',
17-
'cs',
18-
'da',
19-
'de',
20-
'el',
21-
'en',
22-
'es',
23-
'fa',
24-
'fi',
25-
'fil',
26-
'fr',
27-
'he',
28-
'hi',
29-
'hu',
30-
'id',
31-
'it',
32-
'ja',
33-
'ko',
34-
'mr',
35-
'nl',
36-
'no',
37-
'pl',
38-
'pt',
39-
'ro',
40-
'ru',
41-
'sq',
42-
'sv',
43-
'te',
44-
'th',
45-
'tr',
46-
'uk',
47-
'ur',
48-
'vi',
49-
'zh',
50-
],
14+
fallbackLng: DEFAULT_INTERFACE_LANGUAGE,
15+
supportedLngs: [...SUPPORTED_INTERFACE_LANGUAGES],
16+
detection: {
17+
order: ['localStorage'],
18+
caches: ['localStorage'],
19+
lookupLocalStorage: INTERFACE_LANGUAGE_STORAGE_KEY,
20+
},
5121

5222
ns: ['default'],
5323
defaultNS: 'default',

0 commit comments

Comments
 (0)