]> git.localhorst.tv Git - alttp.git/commitdiff
add language switcher
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 16 Mar 2022 16:38:43 +0000 (17:38 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 16 Mar 2022 16:38:43 +0000 (17:38 +0100)
app/Http/Controllers/UserController.php [new file with mode: 0644]
resources/js/components/common/Header.js
resources/js/components/common/Icon.js
resources/js/components/common/LanguageSwitcher.js [new file with mode: 0644]
resources/js/i18n/en.js [new file with mode: 0644]
resources/js/i18n/index.js
routes/api.php

diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php
new file mode 100644 (file)
index 0000000..58d725d
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+
+class UserController extends Controller
+{
+
+       public function setLanguage(Request $request) {
+               $user = $request->user();
+               if (!$user) return;
+
+               $validatedData = $request->validate([
+                       'language' => 'required|in:de,en',
+               ]);
+
+               $user->locale = $validatedData['language'];
+               $user->update();
+
+               return $user->toJson();
+       }
+
+}
index 6bab1a240fad9aa41008c21f0d215f26b70d208b..b1040f80bc5b187ea1fd538ff2f14558c511ce18 100644 (file)
@@ -5,6 +5,7 @@ import { LinkContainer } from 'react-router-bootstrap';
 import { withTranslation } from 'react-i18next';
 
 import Icon from './Icon';
+import LanguageSwitcher from './LanguageSwitcher';
 import { getAvatarUrl } from '../../helpers/User';
 import { withUser } from '../../helpers/UserContext';
 import i18n from '../../i18n';
@@ -17,7 +18,10 @@ const Header = ({ doLogout, user }) =>
                                        ALttP
                                </Navbar.Brand>
                        </LinkContainer>
-                       <Nav className="ms-auto">
+                       <Navbar.Text className="ms-auto me-2">
+                               <LanguageSwitcher />
+                       </Navbar.Text>
+                       <Nav>
                                {user ?
                                        <>
                                                <LinkContainer to={`/users/${user.id}`}>
index 2ad4e512036d873a6200f6cea98f139665d3395a..8b49c7e94b809984c682059966faaab9a0bfef3d 100644 (file)
@@ -62,6 +62,7 @@ Icon.EDIT = makePreset('EditIcon', 'edit');
 Icon.FINISHED = makePreset('FinishedIcon', 'square-check');
 Icon.FIRST_PLACE = makePreset('FirstPlaceIcon', 'trophy');
 Icon.FORFEIT = makePreset('ForfeitIcon', 'square-xmark');
+Icon.LANGUAGE = makePreset('LanguageIcon', 'language');
 Icon.LOGOUT = makePreset('LogoutIcon', 'sign-out-alt');
 Icon.PENDING = makePreset('PendingIcon', 'clock');
 Icon.PROTOCOL = makePreset('ProtocolIcon', 'file-alt');
diff --git a/resources/js/components/common/LanguageSwitcher.js b/resources/js/components/common/LanguageSwitcher.js
new file mode 100644 (file)
index 0000000..ff8b197
--- /dev/null
@@ -0,0 +1,34 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import Icon from './Icon';
+import { withUser } from '../../helpers/UserContext';
+import i18n from '../../i18n';
+
+const setLanguage = (user, language) => {
+       i18n.changeLanguage(language);
+       if (user) {
+               axios.post('/api/users/set-language', { language });
+       }
+};
+
+const LanguageSwitcher = ({ user }) =>
+<Button
+       onClick={() => { setLanguage(user, i18n.language === 'de' ? 'en' : 'de'); }}
+       title={i18n.language === 'de' ? 'Switch to english' : 'Auf deutsch wechseln'}
+       variant="outline-secondary"
+>
+       <Icon.LANGUAGE />
+       {' '}
+       {i18n.language === 'de' ? 'Deutsch' : 'English'}
+</Button>;
+
+LanguageSwitcher.propTypes = {
+       user: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(withUser(LanguageSwitcher));
diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js
new file mode 100644 (file)
index 0000000..80c091a
--- /dev/null
@@ -0,0 +1,135 @@
+/* eslint-disable max-len */
+export default {
+       translation: {
+               button: {
+                       add: 'Add',
+                       back: 'Back',
+                       cancel: 'Cancel',
+                       close: 'Close',
+                       edit: 'Edit',
+                       help: 'Help',
+                       login: 'Login',
+                       logout: 'Logout',
+                       new: 'New',
+                       protocol: 'Protocol',
+                       save: 'Save',
+                       search: 'Search',
+               },
+               general: {
+                       appName: 'ALttP',
+               },
+               icon: {
+                       DiscordIcon: 'Discord',
+                       EditIcon: 'Edit',
+                       FinishedIcon: 'Finished',
+                       FirstPlaceIcon: 'First Place',
+                       ForfeitIcon: 'Forfeit',
+                       LogoutIcon: 'Logout',
+                       PendingIcon: 'Pending',
+                       SecondPlaceIcon: 'Second Place',
+                       ThirdPlaceIcon: 'Third Place',
+                       zelda: {
+                               'big-key': 'Big Key',
+                               'blue-boomerang': 'Boomerang',
+                               'blue-mail': 'Blue Mail',
+                               'blue-pendant': 'Pendant of Power',
+                               'blue-potion': 'Blue Potion',
+                               bombos: 'Bombos',
+                               bomb: 'Bomb',
+                               book: 'Book',
+                               boots: 'Boots',
+                               'bottle-bee': 'Bee in a Bottle',
+                               bottle: 'Bottle',
+                               bow: 'Bow',
+                               bugnet: 'Bugnet',
+                               byrna: 'Cane of Byrna',
+                               cape: 'Cape',
+                               compass: 'Compass',
+                               crystal: 'Crystal',
+                               duck: 'Duck',
+                               ether: 'Ether',
+                               fairy: 'Fairy in a Bottle',
+                               'fighter-shield': 'Fighter Shield',
+                               'fire-rod': 'Fire Rod',
+                               'fire-shield': 'Fire Shield',
+                               flippers: 'Flippers',
+                               flute: 'Flute',
+                               glove: 'Power Glove',
+                               'green-mail': 'Green Mail',
+                               'green-pendant': 'Pendant of Courage',
+                               'green-potion': 'Green Potion',
+                               hammer: 'Hammer',
+                               'heart-container': 'Heart Container',
+                               'heart-piece': 'Heart Piece',
+                               hookshot: 'Hookshot',
+                               'ice-rod': 'Ice Rod',
+                               lamp: 'Lamp',
+                               map: 'Map',
+                               mirror: 'Mirror',
+                               'mirror-shield': 'Mirror Shield',
+                               mitts: 'Titan \'s Mitts',
+                               moonpearl: 'Moonpearl',
+                               mushroom: 'Mushroom',
+                               powder: 'Powder',
+                               quake: 'Quake',
+                               'red-bomb': 'Red Bomb',
+                               'red-boomerang': 'Red Boomerang',
+                               'red-mail': 'Red Mail',
+                               'red-pendant': 'Pendant of Wisdom',
+                               'red-potion': 'Red Potion',
+                               shovel: 'Shovel',
+                               silvers: 'Silvers',
+                               'small-key': 'Small Key',
+                               somaria: 'Cane of Somaria',
+                       },
+               },
+               participants: {
+                       empty: 'No participants on record',
+                       heading: 'Participants',
+                       participant: 'Participant',
+                       score: 'Score',
+               },
+               protocol: {
+                       description: {
+                               result: {
+                                       report: 'Result reported',
+                               },
+                               round: {
+                                       create: 'Round added',
+                               },
+                               unknown: 'Unknown protocol entry of type {{type}}.',
+                       },
+                       empty: 'Empty',
+                       heading: 'Protocol',
+               },
+               results: {
+                       edit: 'Change result',
+                       forfeit: 'Forfeit',
+                       report: 'Report result',
+                       reportError: 'Error saving result :(',
+                       reportPreview: 'Will be recorded as {{ time }}',
+                       reportSuccess: 'Result stored, thanks :)',
+                       reportTime: 'Time',
+                       time: 'Time: {{ time }}',
+               },
+               rounds: {
+                       date: '{{ date, L }}',
+                       empty: 'No rounds yet',
+                       heading: 'Rounds',
+                       new: 'New round',
+                       noSeed: 'No seed set',
+                       seed: 'Seed',
+                       setSeed: 'Set seed',
+               },
+               tournaments: {
+                       scoreboard: 'Scoreboard',
+               },
+               validation: {
+                       error: {
+                               required: 'Please tell me',
+                               time: 'Please enter as 1:23:45 (or 56:23 if you\'re fast ^^).',
+                               url: 'URL plz',
+                       },
+               }
+       },
+};
index ee366fe689cbc120fe84e584a0b9bb7339f7f4c8..63803cd4c31b7dd3f6570085951ca22f85aa1539 100644 (file)
@@ -5,11 +5,13 @@ import numeral from 'numeral';
 import { initReactI18next } from 'react-i18next';
 
 import de from './de';
+import en from './en';
 import 'numeral/locales/de';
 import 'moment/locale/de';
 
 const supportedLocales = [
        'de',
+       'en',
 ];
 
 const resolveLocale = (loc) => {
@@ -38,6 +40,7 @@ i18n
                },
                resources: {
                        de,
+                       en,
                },
                supportedLngs: supportedLocales,
        });
index 5b026e3b2b856c212ed3a19f2d617edc1fe415a4..4c55f75eb6a535013f837064ec66d649ea31133d 100644 (file)
@@ -26,3 +26,5 @@ Route::post('rounds', 'App\Http\Controllers\RoundController@create');
 Route::post('rounds/{round}/setSeed', 'App\Http\Controllers\RoundController@setSeed');
 
 Route::get('tournaments/{id}', 'App\Http\Controllers\TournamentController@single');
+
+Route::post('users/set-language', 'App\Http\Controllers\UserController@setLanguage');