setup i18n with locale switcher in header

This commit is contained in:
Nuwan 2021-10-25 00:47:33 +05:30
parent 72092edf2b
commit e577d71d5d
23 changed files with 278 additions and 63 deletions

View File

@ -68,5 +68,22 @@ describe("Top Navigation", () => {
})
})
describe('locale switch', () => {
beforeEach(() => {
cy.stubAuthenticate()
cy.visit('/')
})
it("translate", () => {
cy.get('.card-header').contains('Home page')
cy.get('[data-testid=langSwitch]').contains('ES').click()
cy.get('.card-header').contains('Página de inicio')
cy.get('.card-header').should('not.contain', 'Home page')
cy.get('[data-testid=langSwitch]').contains('EN').click()
cy.get('.card-header').contains('Home page')
cy.get('.card-header').should('not.contain', 'Página de inicio')
})
})
});

View File

@ -9923,6 +9923,14 @@
}
}
},
"html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"requires": {
"void-elements": "3.1.0"
}
},
"html-webpack-plugin": {
"version": "4.0.0-beta.11",
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz",
@ -10067,6 +10075,14 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
"integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
},
"i18next": {
"version": "21.3.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-21.3.3.tgz",
"integrity": "sha512-Wv5arCT9pK35nfhOzTdS64T7JpPcoqnkOEidxc4zF0DZ8KetpvmnkO+uWkXy+DFz6zWzPX7U9bIemwBqpFRprw==",
"requires": {
"@babel/runtime": "^7.12.0"
}
},
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@ -15666,6 +15682,25 @@
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.11.1.tgz",
"integrity": "sha512-lBt428oU03dNUF5qZy5xqEdANaH3L/ilKWQS2t8wD6zF7FypOv46kEkZmg+oHf3n2xgeGYJgbMIGtYExsfKJ8A=="
},
"react-i18next": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.12.0.tgz",
"integrity": "sha512-M9BT+hqVG03ywrl+L7CK74ugK+4jIo7AeKJ17+g9BoqJz2+/aVbs8SIVXT4KMQ1rjIdcw+GcSRDy1CXjcz6tLQ==",
"requires": {
"@babel/runtime": "^7.14.5",
"html-parse-stringify": "^3.0.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.15.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz",
"integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
}
}
},
"react-image-lightbox": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/react-image-lightbox/-/react-image-lightbox-5.1.1.tgz",
@ -19342,6 +19377,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
},
"void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk="
},
"w3c-hr-time": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",

View File

@ -29,6 +29,7 @@
"emoji-mart": "^3.0.0",
"fuse.js": "^6.4.3",
"google-maps-react": "^2.0.6",
"i18next": "^21.3.3",
"is_js": "^0.9.0",
"leaflet": "^1.7.1",
"leaflet.markercluster": "^1.4.1",
@ -53,6 +54,7 @@
"react-es6-progressbar.js": "^1.1.0",
"react-flatpickr": "^3.10.6",
"react-hook-form": "^7.11.1",
"react-i18next": "^11.12.0",
"react-image-lightbox": "^5.1.1",
"react-image-video-lightbox": "^2.0.1",
"react-leaflet": "^2.7.0",

View File

@ -1,9 +1,12 @@
import React from 'react'
import React from 'react';
import { useTranslation } from 'react-i18next';
function JKDashboardLoadingIndicator() {
const {t} = useTranslation();
return (
<div className="spinner-border" role="status">
<span className="sr-only">Loading...</span>
<span className="sr-only">{t('loading', {ns: 'common'})}...</span>
</div>
)
}

View File

@ -1,13 +1,15 @@
import React from 'react';
import { Card, CardBody } from 'reactstrap';
import FalconCardHeader from '../common/FalconCardHeader';
import { useTranslation } from "react-i18next";
const JKHome = () => {
const {t} = useTranslation()
return (
<Card>
<FalconCardHeader title="Home page" titleClass="font-weight-bold" />
<FalconCardHeader title={t('page_title', {ns: 'home'})} titleClass="font-weight-semi-bold" />
<CardBody className="pt-0">
<h1>Dashboard - Home</h1>
</CardBody>
</Card>
);

View File

@ -2,19 +2,24 @@ import React from 'react';
import { Col, Row } from 'reactstrap';
import { version } from '../../config';
const JKFooter = () => (
<footer>
<Row noGutters className="justify-content-between text-center fs--1 mt-4 mb-3">
<Col sm="auto">
<p className="mb-0 text-600">
Copyright &copy; {new Date().getFullYear()} JamKazam, Inc. All Rights Reserved
</p>
</Col>
<Col sm="auto">
<p className="mb-0 text-600">v{version}</p>
</Col>
</Row>
</footer>
);
const JKFooter = () => {
return (
<footer>
<Row noGutters className="justify-content-between text-center fs--1 mt-4 mb-3">
<Col sm="auto">
<p className="mb-0 text-600">
Copyright &copy; {new Date().getFullYear()} JamKazam, Inc. All Rights Reserved
</p>
</Col>
<Col sm="auto">
<p className="mb-0 text-600">v{version}</p>
</Col>
</Row>
</footer>
);
};
export default JKFooter;

View File

@ -0,0 +1,25 @@
import React from 'react';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import { Button } from "reactstrap";
function JKLocaleSwitch() {
const { t, i18n } = useTranslation();
function changeLanguage(e) {
i18n.changeLanguage(e.target.value);
}
return (
<ul class="list-inline" data-testid="langSwitch">
<li class="list-inline-item">
<Button onClick={changeLanguage} value="en" color="link" size="sm" className={classNames('px-1 py-0', {'font-weight-semi-bold btn-outline-primary': i18n.language === 'en'})}>EN</Button>
</li>
<li class="list-inline-item">
<Button onClick={changeLanguage} value="es" color="link" size="sm" className={ classNames('px-1 py-0', {'font-weight-semi-bold btn-outline-primary': i18n.language === 'es'}) }>ES</Button>
</li>
</ul>
);
}
export default JKLocaleSwitch;

View File

@ -13,9 +13,10 @@ import NavbarTopDropDownMenus from './NavbarTopDropDownMenus';
import NavbarVerticalMenu from './NavbarVerticalMenu';
//import ToggleButton from './ToggleButton';
const JKNavbarVertical = ({ navbarStyle }) => {
const navBarRef = useRef(null);
const JKNavbarVertical = ({ navbarStyle }) => {
const navBarRef = useRef(null);
const {
showBurgerMenu,
isNavbarVerticalCollapsed,

View File

@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { Nav, NavItem, NavLink, UncontrolledTooltip, NavbarText } from 'reactstrap';
import ProfileDropdown from './JKProfileDropdown';
import NotificationDropdown from './JKNotificationDropdown';
import LangSwitch from './JKLangSwitch';
//import SettingsAnimatedIcon from './SettingsAnimatedIcon';
//import CartNotification from './CartNotification';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@ -10,11 +11,13 @@ import AppContext from '../../context/Context';
import classNames from 'classnames';
import { navbarBreakPoint } from '../../config';
//import { useSelector } from 'react-redux';
import { useTranslation } from "react-i18next";
const TopNavRightSideNavItem = () => {
//const notifications = useSelector(state => state.notification.notifications.slice(0, 5));
const {t} = useTranslation();
const { isTopNav, isCombo } = useContext(AppContext);
return (
@ -22,9 +25,9 @@ const TopNavRightSideNavItem = () => {
{/* <NavItem>
<SettingsAnimatedIcon />
</NavItem> */}
<NavbarText className="d-none d-md-inline">Keep JamKazam Improving:</NavbarText>
<NavbarText className="d-none d-md-inline">{t('keep_jamkazam_improving', {ns: 'common'})}:</NavbarText>
<NavItem className="d-none d-md-inline ml-1 mr-6">
<NavLink>Subscribe</NavLink>
<NavLink>{t('subscribe', {ns: 'common'})}</NavLink>
</NavItem>
{(isCombo || isTopNav) && (
<NavItem className={classNames(`p-2 px-lg-0 cursor-pointer`, { [`d-${navbarBreakPoint}-none`]: isCombo })}>
@ -37,7 +40,7 @@ const TopNavRightSideNavItem = () => {
</NavItem>
)}
{/* <CartNotification /> */}
<LangSwitch />
<NotificationDropdown />
<ProfileDropdown />

View File

@ -4,6 +4,7 @@ import { Alert, Card, CardBody, Col, Row, Button, Form } from 'reactstrap';
import Loader from '../common/Loader';
import FalconCardHeader from '../common/FalconCardHeader';
import { isIterableArray } from '../../helpers/utils';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { fetchPeople } from '../../store/features/peopleSlice';
@ -18,6 +19,7 @@ const JKPeople = ({ className }) => {
const [resetFilter, setResetFilter] = useState(false)
const peopleListRef = useRef();
const dispatch = useDispatch();
const {t} = useTranslation();
const people = useSelector(state => state.people.people);
const totalPages = useSelector(state => state.people.totalPages);
@ -77,15 +79,15 @@ const JKPeople = ({ className }) => {
<Card>
<JKPeopleSearch show={showSearch} setShow={setShowSearch} resetFilter={resetFilter} setResetFilter={setResetFilter} />
<FalconCardHeader
title={`Find New Friends`}
title={t('page_title', {ns: 'people'})}
titleClass="font-weight-bold"
>
<Form inline className="mt-md-0 mt-3">
<Button color="primary" className="me-2 mr-2 fs--1" onClick={() => setShowSearch(!showSearch)} data-testid="btnUpdateSearch">
Update Search
{t('update_search', {ns: 'people'})}
</Button>
<Button outline color="secondary" className="fs--1" data-testid="btnResetSearch" onClick={() => setResetFilter(true)}>
Reset Filters
{t('reset_filters', {ns: 'people'})}
</Button>
</Form>
</FalconCardHeader>

View File

@ -2,20 +2,22 @@ import React from 'react';
import { Table } from 'reactstrap';
import JKPerson from './JKPerson';
import PropTypes from 'prop-types';
import {useTranslation} from 'react-i18next'
const JKPeopleList = ({ people }) => {
const {t} = useTranslation()
return (
<>
<Table striped bordered className="fs--1" data-testid="peopleListTable">
<thead className="bg-200 text-900">
<tr>
<th scope="col">Name</th>
<th scope="col">{t('person_attributes.name', {ns: 'people'})}</th>
<th scope="col" style={{ minWidth: 250 }}>
About
{t('person_attributes.about', {ns: 'people'})}
</th>
<th scope="col">Instruments</th>
<th scope="col">{t('person_attributes.instruments', {ns: 'people'})}</th>
<th scope="col">Action</th>
<th scope="col">{t('actions', {ns: 'common'})}</th>
</tr>
</thead>
<tbody className="list">

View File

@ -6,6 +6,7 @@ import { useAuth } from '../../context/AuthContext';
import { truncate } from '../../helpers/utils';
import { fetchPerson } from '../../store/features/peopleSlice'
import { useDispatch, useSelector } from 'react-redux'
import { useTranslation } from "react-i18next";
import JKProfileSidePanel from '../profile/JKProfileSidePanel';
import JKProfileAvatar from '../profile/JKProfileAvatar';
@ -21,6 +22,7 @@ const JKPerson = props => {
const { currentUser } = useAuth();
const [showSidePanel, setShowSidePanel] = useState(false);
const dispatch = useDispatch()
const {t} = useTranslation()
const user = useSelector(state => state.people.people.find(p => p.id === id))
const toggleMoreDetails = async (e) => {
@ -48,18 +50,18 @@ const JKPerson = props => {
</div>
</a>
<div>
<strong>Latency To Me:</strong>
<strong>{t('person_attributes.latency_to_me', {ns: 'people'})}:</strong>
<JKLatencyBadge latencyData={latency_data} />
</div>
<div>
<strong>Last Active:</strong> <JKLastActiveAgo timestamp={last_active_timestamp} />
<strong>{t('person_attributes.last_active', {ns: 'people'})}:</strong> <JKLastActiveAgo timestamp={last_active_timestamp} />
</div>
</td>
<td>
{truncate(biography, 200)}
{biography && biography.length > 200 && (
<a href="/#" data-testid="linkMore" onClick={toggleMoreDetails}>
{' '} more »
{' '} {t('more', {ns: 'common'})} »
</a>
)}
</td>
@ -81,7 +83,7 @@ const JKPerson = props => {
</JKMessageButton>
<a href="/#" onClick={toggleMoreDetails} data-testid="btnMore">
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title="View Profile">
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title={t('view_profile', {ns: 'people'})}>
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
</span>
</a>
@ -92,20 +94,20 @@ const JKPerson = props => {
<Row>
<Col>
<div>
<strong>Latency To Me:</strong> <JKLatencyBadge latencyData={latency_data} />
<strong>{t('person_attributes.latency_to_me', {ns: 'people'})}:</strong> <JKLatencyBadge latencyData={latency_data} />
</div>
<div>
<strong>Last Active:</strong> <JKLastActiveAgo timestamp={last_active_timestamp} />
<strong>{t('person_attributes.last_active', {ns: 'people'})}:</strong> <JKLastActiveAgo timestamp={last_active_timestamp} />
</div>
</Col>
<Col className="d-none d-sm-block">
<h5>Instruments</h5>
<h5>{t('person_attributes.instruments', {ns: 'people'})}</h5>
<JKProfileInstrumentsList instruments={instruments} />
</Col>
</Row>
<Row className="d-block d-sm-none mt-3">
<Col>
<h5>Instruments</h5>
<h5>{t('person_attributes.instruments', {ns: 'people'})}</h5>
<JKProfileInstrumentsList instruments={instruments} />
</Col>
</Row>
@ -124,7 +126,7 @@ const JKPerson = props => {
</JKMessageButton>
<a href="/#" onClick={toggleMoreDetails} data-testid="btnMore">
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title="View Profile">
<span className="btn btn-primary fs--1 px-2 py-1" data-bs-toggle="tooltip" title={t('view_profile', {ns: 'people'})}>
<FontAwesomeIcon icon="user" transform="shrink-4 down-1" className="mr-1" />
</span>
</a>
@ -140,12 +142,4 @@ JKPerson.propTypes = {
viewMode: PropTypes.string
};
// const JKPersonAvator = ({ url }) => {
// if (url) {
// return <img className="avatar avatar-xl rounded-circle" src={url} />;
// } else {
// return <img className="avatar avatar-xl rounded-circle" src={avatar} />;
// }
// };
export default JKPerson;

View File

@ -8,6 +8,7 @@ import { Modal, ModalBody, ModalHeader } from 'reactstrap';
import ScrollBarCustom from '../common/ScrollBarCustom';
import { useAuth } from '../../context/AuthContext';
import { useTranslation } from "react-i18next";
import JKProfileAvatar from './JKProfileAvatar';
import JKProfileInstrumentsList from './JKProfileInstrumentsList';
@ -27,7 +28,8 @@ const JKProfileSidePanel = props => {
const { show, setShow, user, latencyData } = props;
const { currentUser } = useAuth();
const toggle = () => setShow(!show);
const {t} = useTranslation();
const joinedDate = () => {
return moment(new Date(user.created_at_timestamp * 1000)).format('MM-DD-YYYY');
};
@ -62,27 +64,27 @@ const JKProfileSidePanel = props => {
{user && (
<div>
<p>
<strong>Latency to Me:</strong> <JKLatencyBadge latencyData={latencyData} showAll={true} />
<strong>{t('person_attributes.latency_to_me', {ns: 'people'})}:</strong> <JKLatencyBadge latencyData={latencyData} showAll={true} />
<br />
<strong>Location:</strong> {`${user.city}, ${user.country}`}
<strong>{t('person_attributes.location', {ns: 'people'})}:</strong> {`${user.city}, ${user.country}`}
<br />
<strong>Skill Level:</strong> <JKProfileSkillLevel skillLevel={user.skill_level} />
<strong>{t('person_attributes.skill_level', {ns: 'people'})}:</strong> <JKProfileSkillLevel skillLevel={user.skill_level} />
<br />
<strong>Joined JamKazam:</strong> {joinedDate()}
<strong>{t('person_attributes.joined_jamkazam', {ns: 'people'})}:</strong> {joinedDate()}
<br />
<strong>Last Active:</strong> <JKLastActiveAgo timestamp={user.last_active_timestamp} />
<strong>{t('person_attributes.last_active', {ns: 'people'})}:</strong> <JKLastActiveAgo timestamp={user.last_active_timestamp} />
</p>
{user.biography && user.biography.length > 0 && (
<div data-testid="biography">
<h5>About</h5>
<h5>{t('person_attributes.about', {ns: 'people'})}</h5>
<p>{user.biography}</p>
</div>
)}
{user.instruments && user.instruments.length && (
<div data-testid="instruments">
<h5>Instruments</h5>
<h5>{t('person_attributes.instruments', {ns: 'people'})}</h5>
<JKProfileInstrumentsList instruments={user.instruments} />
</div>
)}
@ -90,7 +92,7 @@ const JKProfileSidePanel = props => {
{user.genres && user.genres.length > 0 && (
<div data-testid="genres">
<br />
<h5>Genres</h5>
<h5>{t('person_attributes.genres', {ns: 'people'})}</h5>
<JKProfileGenres genres={user.genres} />
</div>
)}
@ -98,7 +100,7 @@ const JKProfileSidePanel = props => {
{user.bands && user.bands.length > 0 && (
<div data-testid="bands">
<br />
<h5>Bands</h5>
<h5>{t('person_attributes.bands', {ns: 'people'})}</h5>
{user.bands.map(band => (
<p>
<a key={band.id} href="/#">
@ -111,7 +113,7 @@ const JKProfileSidePanel = props => {
{user.performance_samples && user.performance_samples.length > 0 && (
<div data-testid="performance_samples">
<h5>Performance Samples</h5>
<h5>{t('person_attributes.performance_samples', {ns: 'people'})}</h5>
<JKProfilePerformanceSamples samples={user.performance_samples} />
</div>
)}
@ -119,13 +121,13 @@ const JKProfileSidePanel = props => {
{user.online_presences && user.online_presences.length > 0 && (
<div data-testid="online_presences">
<br />
<h5>Online Presence</h5>
<h5>{t('person_attributes.online_presence', {ns: 'people'})}</h5>
<JKProfileOnlinePresence onlinePresences={user.online_presences} userId={user.id} />
</div>
)}
<br />
<h5>Interests</h5>
<h5>{t('person_attributes.interests', {ns: 'people'})}</h5>
<JKProfileInterests user={user} />
{currentUser && (
@ -135,17 +137,17 @@ const JKProfileSidePanel = props => {
user={user}
addContent={
<>
<FontAwesomeIcon icon="plus" transform="shrink-4 down-1" className="mr-1" /> Add Friend{' '}
<FontAwesomeIcon icon="plus" transform="shrink-4 down-1" className="mr-1" /> {t('add_friend', {ns: 'people'})}{' '}
</>
}
removeContent={
<>
<FontAwesomeIcon icon="minus" transform="shrink-4 down-1" className="mr-1" /> Disconnect
<FontAwesomeIcon icon="minus" transform="shrink-4 down-1" className="mr-1" /> {t('disconnect', {ns: 'people'})}
</>
}
/>{' '}
<JKMessageButton size="md" currentUser={currentUser} user={user}>
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" /> Send Message
<FontAwesomeIcon icon="comments" transform="shrink-4 down-1" className="mr-1" /> {t('send_message', {ns: 'people'})}
</JKMessageButton>
</div>
)}

35
jam-ui/src/i18n/config.js Normal file
View File

@ -0,0 +1,35 @@
import i18n from 'i18next';
import { initReactI18next } from "react-i18next";
import commonTranslationsEN from './locales/en/common.json'
import homeTranslationsEN from './locales/en/home.json'
import peopleTranslationsEN from './locales/en/people.json'
import commonTranslationsES from './locales/es/common.json'
import homeTranslationsES from './locales/es/home.json'
import peopleTranslationsES from './locales/es/people.json'
i18n.use(initReactI18next).init({
fallbackLng: 'en',
lng: 'en',
resources: {
en: {
//translations: require('./locales/en/translations.json')
common: commonTranslationsEN,
home: homeTranslationsEN,
people: peopleTranslationsEN
},
es: {
//translations: require('./locales/es/translations.json')
common: commonTranslationsES,
home: homeTranslationsES,
people: peopleTranslationsES
}
},
//ns: ['translations'],
defaultNS: 'common'
});
i18n.languages = ['en', 'es'];
export default i18n;

View File

@ -0,0 +1,12 @@
{
"keep_jamkazam_improving": "Keep JamKazam Improving",
"subscribe": "Subscribe",
"loading": "Loading",
"more": "More",
"actions": "Actions",
"navigation": {
"home": "Home",
"friends": "Friends",
"help": "Help"
}
}

View File

@ -0,0 +1,3 @@
{
"page_title": "Home page"
}

View File

@ -0,0 +1,24 @@
{
"page_title": "Find New Friends",
"update_search": "Update Search",
"reset_filters": "Reset Filters",
"view_profile": "View profile",
"add_friend": "Add Friends",
"disconnect": "Disconnect",
"send_message": "Send Message",
"person_attributes": {
"name": "Name",
"about": "About",
"instruments": "Instruments",
"latency_to_me": "Latency To Me",
"last_active": "Last Active",
"location": "Location",
"skill_level": "Skill Level",
"joined_jamkazam": "Joined JamKazam",
"genres": "Genres",
"bands": "Bands",
"performance_samples": "Performance Samples",
"online_presence": "Online Presence",
"interests": "Interests"
}
}

View File

@ -0,0 +1,4 @@
{
"keep_jamkazam_improving": "Keep Jamkazam Improving",
"subscribe": "Subscribe"
}

View File

@ -0,0 +1,7 @@
{
"keep_jamkazam_improving": "Mantenga JamKazam mejorando",
"subscribe": "Suscribir",
"loading": "Cargando",
"actions": "Comportamiento",
"more": "Más"
}

View File

@ -0,0 +1,3 @@
{
"page_title": "Página de inicio"
}

View File

@ -0,0 +1,24 @@
{
"page_title": "Encontrar nuevas amigas",
"update_search": "Actualizar búsqueda",
"reset_filters": "Restablecer filtros",
"view_profile": "Ver perfil",
"add_friend": "Agregar amiga",
"disconnect": "Desconectar",
"send_message": "Enviar mensaje",
"person_attributes": {
"name": "Nombre",
"about": "Sobre",
"instruments": "Instrumentos",
"latency_to_me": "Latencia para mí",
"last_active": "Último activo",
"location": "Localización",
"skill_level": "Nivel de habilidad",
"joined_jamkazam": "Se unió a JamKazam",
"genres": "Géneros",
"bands": "Bandas",
"performance_samples": "Muestras de rendimiento",
"online_presence": "Presencia en línea",
"interests": "Intereses"
}
}

View File

@ -0,0 +1,4 @@
{
"keep_jamkazam_improving": "Mantenga Jamkazam mejorando",
"subscribe": "Suscribir"
}

View File

@ -6,6 +6,7 @@ import ReactDOM from 'react-dom';
import App from './App';
import Main from './Main';
import './helpers/initFA';
import './i18n/config';
ReactDOM.render(
<Main>