Exposing components for translation mapping; Queue and AAlbum views now moved to translation file

This commit is contained in:
James Barnsley
2020-07-06 20:22:39 +12:00
parent 1158fb7c2f
commit fca28ada88
9 changed files with 221 additions and 147 deletions

View File

@ -1,5 +1,6 @@
import { memo } from 'react';
import { content } from '../locale';
/**
* Format time duration
@ -50,21 +51,21 @@ const durationSentence = (milliseconds = null) => {
const totalMinutes = Math.floor(milliseconds / (1000 * 60));
const totalHours = Math.floor(milliseconds / (1000 * 60 * 60));
if (totalHours > 1) return `${totalHours}+ hrs`;
if (totalMinutes > 1) return `${totalMinutes} mins`;
if (totalSeconds) return `${totalSeconds} sec`;
return '0 mins';
if (totalHours > 1) return `${totalHours}+ ${content('time.hours.short')}`;
if (totalMinutes > 1) return `${totalMinutes} ${content('time.minutes.short')}`;
if (totalSeconds) return `${totalSeconds} ${content('time.seconds.short')}`;
return `0 ${content('time.minutes.short')}`;
};
export default memo((props) => {
if (props.data === undefined) {
const dater = (type, data) => {
if (data === undefined) {
return null;
}
switch (props.type) {
switch (type) {
case 'total-time':
var duration = 0;
var tracks = props.data;
var tracks = data;
for (let i = 0; i < tracks.length; i++) {
if (tracks[i].duration) {
duration += parseInt(tracks[i].duration);
@ -73,22 +74,22 @@ export default memo((props) => {
return durationSentence(duration);
case 'length':
return durationTime(props.data);
return durationTime(data);
case 'date':
// A four-character date indicates just a year (rather than a full date)
if (props.data.length == 4) {
return props.data;
if (data.length == 4) {
return data;
// Digest as a date string
}
var date = new Date(props.data);
var date = new Date(data);
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`;
case 'ago':
var date = new Date(props.data);
var date = new Date(data);
var diff = new Date() - date;
var seconds = Math.floor(diff / 1000);
var minutes = Math.floor(diff / (1000 * 60));
@ -98,18 +99,27 @@ export default memo((props) => {
var years = Math.floor(diff / (1000 * 60 * 60 * 24 * 7 * 52));
if (seconds < 60) {
return `${seconds} second${seconds > 1 ? 's' : ''}`;
return `${seconds} ${content(`time.seconds.${seconds > 1 ? 'singular' : 'plural'}`)}`;
} if (minutes < 60) {
return `${minutes} minute${minutes > 1 ? 's' : ''}`;
return `${minutes} ${content(`time.minutes.${minutes > 1 ? 'singular' : 'plural'}`)}`;
} if (hours < 24) {
return `${hours} hour${hours > 1 ? 's' : ''}`;
return `${hours} ${content(`time.hours.${hours > 1 ? 'singular' : 'plural'}`)}`;
} if (days < 7) {
return `${days} day${days > 1 ? 's' : ''}`;
return `${days} ${content(`time.days.${days > 1 ? 'singular' : 'plural'}`)}`;
} if (weeks < 54) {
return `${weeks} week${weeks > 1 ? 's' : ''}`;
return `${weeks} ${content(`time.weeks.${weeks > 1 ? 'singular' : 'plural'}`)}`;
}
return `${years} year${years > 1 ? 's' : ''}`;
return `${years} ${content(`time.years.${years > 1 ? 'singular' : 'plural'}`)}`;
default:
return null;
}
});
};
const Dater = memo(({ type, data }) => dater(type, data));
export {
Dater,
dater,
};
export default Dater;

View File

@ -1,8 +1,8 @@
import React, { memo } from 'react';
export default memo((props) => {
let formatted = parseInt(props.value);
const nice_number = (value) => {
let formatted = parseInt(value);
// > 1 million
if (formatted > 1000000) {
@ -14,10 +14,19 @@ export default memo((props) => {
} else if (formatted > 1000) {
formatted /= 1000;
formatted = Math.round(formatted * 10) / 10;
formatted = `${formatted}k`;
formatted = `${formatted}k`;
} else {
formatted = formatted.toLocaleString();
}
return formatted;
});
};
const NiceNumber = memo(({ value }) => nice_number(value));
export {
NiceNumber,
nice_number,
};
export default NiceNumber;

View File

@ -1,3 +1,41 @@
errors:
uri_not_found: Could not find anything with URI %{uri}
specs:
tracks: %{count} tracks
followers: %{count} followers
listeners: %{count} listeners
plays: %{count} plays
actions:
play: Play
pause: Pause
stop: Stop
add_to_library: Add to library
remove_from_library: Remove from library
time:
seconds:
short: secs
singular: second
plural: seconds
minutes:
short: mins
singular: minute
plural: minutes
hours:
short: hrs
singular: hour
plural: hours
days:
short: days
singular: day
plural: days
weeks:
short: wks
singular: week
plural: weeks
years:
short: yrs
singular: year
plural: years
sidebar:
now_playing: Now playing
search: Search
@ -20,9 +58,16 @@ now_playing:
history: History
add_uri: Add URI
current_track:
playing_from: Playling from
playing_from: Playing from
shuffle: Shuffle
clear: Clear
radio: Radio
album:
title: Album
title_window: %{name} by %{artist} (album)
wiki:
title: About
published: 'Published: %{date}'
search:
title: 'Search: %{term}'
context_actions:

View File

@ -8,7 +8,6 @@ const PARAMS_REG_EXP = '%{(.*?)}';
const paramsRegExp = new RegExp(PARAMS_REG_EXP, 'g');
const content = (path, params = {}, transform) => {
console.log(window.language);
const dictionary = dictionaries[window.language || 'en'] || dictionaries.en;
let value = get((dictionary), path, '');

View File

@ -3,18 +3,17 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import ErrorMessage from '../components/ErrorMessage';
import Header from '../components/Header';
import TrackList from '../components/TrackList';
import Thumbnail from '../components/Thumbnail';
import Parallax from '../components/Parallax';
import LinksSentence from '../components/LinksSentence';
import Loader from '../components/Loader';
import FollowButton from '../components/Fields/FollowButton';
import NiceNumber from '../components/NiceNumber';
import NiceNumber, { nice_number } from '../components/NiceNumber';
import Dater from '../components/Dater';
import LazyLoadListener from '../components/LazyLoadListener';
import ContextMenuTrigger from '../components/ContextMenuTrigger';
import Icon from '../components/Icon';
import { content } from '../locale';
import * as coreActions from '../services/core/actions';
import * as uiActions from '../services/ui/actions';
import * as mopidyActions from '../services/mopidy/actions';
@ -100,24 +99,21 @@ export class Album extends React.Component {
}
setWindowTitle = (album = this.props.album) => {
const { uiActions: { setWindowTitle } } = this.props;
const { uiActions: { setWindowTitle }, artists } = this.props;
if (album) {
let artists = '';
let artistNames = [];
if (album.artists_uris && artists) {
for (let i = 0; i < album.artists_uris.length; i++) {
const uri = album.artists_uris[i];
if (artists.hasOwnProperty(uri)) {
if (artists != '') {
artists += ', ';
}
artists += artists[uri].name;
artistNames.push(artists[uri].name);
}
}
}
setWindowTitle(`${album.name} by ${artists} (album)`);
setWindowTitle(content('album.title_window', { name: album.name, artist: artistNames.join() }));
} else {
setWindowTitle('Album');
setWindowTitle(content('album.title'));
}
}
@ -191,7 +187,7 @@ export class Album extends React.Component {
return (
<ErrorMessage type="not-found" title="Not found">
<p>
{`Could not find album with URI "${encodeURIComponent(uri)}"`}
{content('errors.uri_not_found', { uri: encodeURIComponent(uri) })}
</p>
</ErrorMessage>
);
@ -236,9 +232,10 @@ export class Album extends React.Component {
) : null}
{album.tracks ? (
<li>
{album.tracks_total || album.tracks.length}
{' '}
tracks
{content(
'specs.tracks',
{ count: album.tracks_total || album.tracks.length },
)}
</li>
) : null}
{!this.props.slim_mode && album.tracks ? (
@ -248,31 +245,33 @@ tracks
) : null}
{!this.props.slim_mode && album.play_count ? (
<li>
<NiceNumber value={album.play_count} />
{' '}
plays
{content(
'specs.plays',
{ count: nice_number(album.play_count) },
)}
</li>
) : null}
{!this.props.slim_mode && album.listeners ? (
<li>
<NiceNumber value={album.listeners} />
{' '}
listeners
{content(
'specs.plays',
{ count: nice_number(album.listeners) },
)}
</li>
) : null}
</ul>
</div>
<div className="actions">
<button className="button button--primary" onClick={(e) => this.play()}>
Play
<button type="button" className="button button--primary" onClick={(e) => this.play()}>
{content('actions.play')}
</button>
{uriSource(this.props.uri) == 'spotify' ? (
<FollowButton
className="secondary"
uri={this.props.uri}
addText="Add to library"
removeText="Remove from library"
addText={content('actions.add_to_library')}
removeText={content('actions.remove_from_library')}
is_following={this.inLibrary()}
/>
) : null}
@ -294,14 +293,15 @@ listeners
{album.wiki ? (
<section className="wiki">
<h4 className="wiki__title">About</h4>
<h4 className="wiki__title">{content('album.wiki.title')}</h4>
<div className="wiki__text">
<p>{album.wiki}</p>
<br />
<div className="mid_grey-text">
Published:
{' '}
{album.wiki_publish_date}
{content(
'album.wiki.published',
{ date: album.wiki_publish_date },
)}
</div>
</div>
</section>

View File

@ -201,7 +201,11 @@ class Queue extends React.Component {
<div className="current-track__added-from__text">
{'Playing from '}
<LinksSentence items={items} />
{uri_type === 'radio' && <span className="flag flag--blue">Radio</span>}
{uri_type === 'radio' && (
<span className="flag flag--blue">
{content('now_playing.current_track.radio')}
</span>
)}
</div>
</div>
);
@ -225,16 +229,16 @@ class Queue extends React.Component {
{this.props.spotify_enabled && (
<Link className="button button--no-hover" to="/queue/radio">
<Icon name="radio" />
Radio
{content('now_playing.context_actions.radio')}
</Link>
)}
<Link className="button button--no-hover" to="/queue/history">
<Icon name="history" />
History
{content('now_playing.context_actions.history')}
</Link>
<Link className="button button--no-hover" to="/queue/add-uri">
<Icon name="playlist_add" />
Add URI
{content('now_playing.context_actions.add_uri')}
</Link>
</span>
);
@ -279,7 +283,7 @@ class Queue extends React.Component {
<li>
<a onClick={this.props.mopidyActions.shuffleTracklist}>
<Icon name="shuffle" />
Shuffle
{content('now_playing.current_track.shuffle')}
</a>
</li>
)}
@ -287,7 +291,7 @@ class Queue extends React.Component {
<li>
<a onClick={this.props.mopidyActions.clearTracklist}>
<Icon name="delete_sweep" />
Clear
{content('now_playing.current_track.clear')}
</a>
</li>
)}