Skip to content

Commit b981273

Browse files
committed
feat: add language selector component to homepage with dropdown functionality
1 parent 911ed99 commit b981273

File tree

3 files changed

+163
-1
lines changed

3 files changed

+163
-1
lines changed
Lines changed: 62 additions & 0 deletions
Loading
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* @flow strict
3+
* Copyright (C) 2025 MetaBrainz Foundation
4+
*
5+
* This file is part of MusicBrainz, the open internet music database,
6+
* and is licensed under the GPL version 2, or (at your option) any
7+
* later version: http://www.gnu.org/licenses/gpl-2.0.txt
8+
*/
9+
10+
11+
import * as React from "react";
12+
import languageIcon from '../../images/homepage/language-icon.svg';
13+
import { SanitizedCatalystContext } from '../../../context.mjs';
14+
import { returnToCurrentPage } from '../../../utility/returnUri.js';
15+
import { capitalize } from '../common/utility/strings.js';
16+
17+
function languageName(
18+
language: ?ServerLanguageT,
19+
selected: boolean,
20+
) {
21+
if (!language) {
22+
return '';
23+
}
24+
25+
const {
26+
id,
27+
native_language: nativeLanguage,
28+
native_territory: nativeTerritory,
29+
} = language;
30+
31+
let text = `[${id}]`;
32+
33+
if (nativeLanguage) {
34+
text = capitalize(nativeLanguage);
35+
36+
if (nativeTerritory) {
37+
text += ' (' + capitalize(nativeTerritory) + ')';
38+
}
39+
}
40+
41+
if (selected) {
42+
text += ' \u25be';
43+
}
44+
45+
return text;
46+
}
47+
48+
component LanguageSelector() {
49+
const $c = React.useContext(SanitizedCatalystContext);
50+
const serverLanguages = $c.stash.server_languages;
51+
const currentLanguage = $c.stash.current_language.replace('_', '-');
52+
53+
return (
54+
<>
55+
<a
56+
className="dropdown-toggle align-items-center dropdown-toggle-no-caret"
57+
href="#"
58+
role="button"
59+
data-bs-toggle="dropdown"
60+
aria-expanded="false"
61+
>
62+
<img src={languageIcon} alt="Language" width={40} height={40} />
63+
</a>
64+
<ul className="dropdown-menu">
65+
{serverLanguages?.map((language) => {
66+
const isSelected = language.name === currentLanguage;
67+
return (
68+
<li key={language.name}>
69+
<a
70+
href={`/set-language/${encodeURIComponent(language.name)}?${returnToCurrentPage($c)}`}
71+
className={`dropdown-item ${isSelected ? 'active' : ''}`}
72+
>
73+
{languageName(language, isSelected)}
74+
</a>
75+
</li>
76+
);
77+
})}
78+
<li>
79+
<a href={`/set-language/unset?${returnToCurrentPage($c)}`} className="dropdown-item">{l('(reset language)')}</a>
80+
</li>
81+
<li className="dropdown-divider" />
82+
<li>
83+
<a href="https://translations.metabrainz.org/projects/musicbrainz/" className="dropdown-item">{l('Help translate')}</a>
84+
</li>
85+
</ul>
86+
</>
87+
)
88+
}
89+
90+
export default (hydrate < React.PropsOf < LanguageSelector >> (
91+
'div',
92+
LanguageSelector,
93+
): component(...React.PropsOf < LanguageSelector >));

root/static/scripts/homepage/navbar.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import magnifyingGlass from '../../images/icons/magnifying-glass.svg';
1818
import magnifyingGlassTheme from '../../images/icons/magnifying-glass-theme.svg';
1919
import advancedSearchIcon from '../../images/homepage/advanced_search.svg';
2020
import MobileSearchPopup from './mobile-search-popup.js';
21+
import LanguageSelector from './language.js';
2122

2223
const aboutGroups = [
2324
[
@@ -106,7 +107,7 @@ component DropDownMenu(
106107
groups: DropdownMenuItem[][],
107108
) {
108109
return (
109-
<li className="nav-item dropdown">
110+
<li className="nav-item dropdown d-flex align-items-center">
110111
<a
111112
className="nav-link dropdown-toggle"
112113
href="#"
@@ -252,7 +253,13 @@ component Navbar() {
252253
{Object.keys(dropdownSections).map((section) => (
253254
<DropDownMenu key={section} label={section} groups={dropdownSections[section]} />
254255
))}
256+
257+
{/* Language Selector */}
258+
<li className="nav-item dropdown d-flex">
259+
<LanguageSelector />
260+
</li>
255261
</ul>
262+
256263
<form className="d-none d-lg-flex mt-3 mt-lg-0" role="search" action="/search" method="get">
257264
<div className="input-group">
258265
<input

0 commit comments

Comments
 (0)