feat: translations support

This commit is contained in:
Markos Gogoulos
2024-10-04 13:17:40 +03:00
committed by GitHub
parent ef4067cbdd
commit 4992cc425c
84 changed files with 2303 additions and 161 deletions

View File

@ -1,4 +1,5 @@
import React from 'react';
import { translateString } from '../utils/helpers/';
interface MediaListHeaderProps {
title?: string;
@ -9,7 +10,7 @@ interface MediaListHeaderProps {
}
export const MediaListHeader: React.FC<MediaListHeaderProps> = (props) => {
const viewAllText = props.viewAllText || 'VIEW ALL';
const viewAllText = props.viewAllText || translateString('VIEW ALL');
return (
<div className={(props.className ? props.className + ' ' : '') + 'media-list-header'} style={props.style}>
<h2>{props.title}</h2>

View File

@ -7,20 +7,22 @@ import { PageStore, MediaPageStore } from '../../utils/stores/';
import { PageActions, MediaPageActions } from '../../utils/actions/';
import { LinksContext, MemberContext, SiteContext } from '../../utils/contexts/';
import { PopupMain, UserThumbnail } from '../_shared';
import { replaceString } from '../../utils/helpers/';
import './videojs-markers.js';
import './videojs.markers.css';
import {enableMarkers, addMarker} from './videojs-markers_config.js'
import { translateString } from '../../utils/helpers/';
import './Comments.scss';
const commentsText = {
single: 'comment',
uppercaseSingle: 'COMMENT',
ucfirstSingle: 'Comment',
ucfirstPlural: 'Comments',
submitCommentText: 'SUBMIT',
disabledCommentsMsg: 'Comments are disabled',
single: translateString('comment'),
uppercaseSingle: translateString('COMMENT'),
ucfirstSingle: translateString('Comment'),
ucfirstPlural: translateString('Comments'),
submitCommentText: translateString('SUBMIT'),
disabledCommentsMsg: translateString('Comments are disabled'),
};
function CommentForm(props) {
@ -149,7 +151,7 @@ function CommentForm(props) {
inputRef={textareaRef}
className="form-textarea"
rows="1"
placeholder={'Add a ' + commentsText.single + '...'}
placeholder={translateString('Add a ') + commentsText.single + '...'}
value={value}
onChange={onChangeWithMention}
onFocus={onFocus}
@ -164,7 +166,7 @@ function CommentForm(props) {
ref={textareaRef}
className="form-textarea"
rows="1"
placeholder={'Add a ' + commentsText.single + '...'}
placeholder={translateString('Add a ') + commentsText.single + '...'}
value={value}
onChange={onChange}
onFocus={onFocus}
@ -189,9 +191,9 @@ function CommentForm(props) {
href={loginUrl}
rel="noffolow"
className="form-textarea-wrap"
title={'Add a ' + commentsText.single + '...'}
title={translateString('Add a ') + commentsText.single + '...'}
>
<span className="form-textarea">{'Add a ' + commentsText.single + '...'}</span>
<span className="form-textarea">{translateString('Add a ') + commentsText.single + '...'}</span>
</a>
<div className="form-buttons">
<a href={loginUrl} rel="noffolow" className="disabled">
@ -237,7 +239,7 @@ function CommentActions(props) {
{MemberContext._currentValue.can.deleteComment ? (
<div className="comment-action remove-comment">
<PopupTrigger contentRef={popupContentRef}>
<button>DELETE {commentsText.uppercaseSingle}</button>
<button>{translateString('DELETE')} {commentsText.uppercaseSingle}</button>
</PopupTrigger>
<PopupContent contentRef={popupContentRef}>
@ -310,7 +312,7 @@ function Comment(props) {
{props.author_name}
</a>
</div>
<div className="comment-date">{format(new Date(props.publish_date))}</div>
<div className="comment-date">{replaceString(format(new Date(props.publish_date)))}</div>
</div>
<div ref={commentTextRef} className={'comment-text' + (viewMoreContent ? ' show-all' : '')}>
<div
@ -411,7 +413,7 @@ const CommentsListHeader = ({ commentsLength }) => {
? commentsLength + ' ' + commentsText.ucfirstPlural
: commentsLength + ' ' + commentsText.ucfirstSingle
: MediaPageStore.get('media-data').enable_comments
? 'No ' + commentsText.single + ' yet'
? translateString('No') + commentsText.single + translateString('yet')
: ''}
</h2>
) : null}

View File

@ -2,6 +2,7 @@ import React from 'react';
import { format } from 'timeago.js';
import { formatViewsNumber, imageExtension } from '../../../../utils/helpers/';
import { VideoPlayerByPageLink } from '../../../video-player/VideoPlayerByPageLink';
import { translateString } from '../../../../utils/helpers/';
export function ItemDescription(props) {
return '' === props.description ? null : (
@ -73,8 +74,8 @@ export function MediaItemEditLink(props) {
}
return !link ? null : (
<a href={link} title="Edit media" className="item-edit-link">
EDIT MEDIA
<a href={link} title={translateString("Edit media")} className="item-edit-link">
{translateString("EDIT MEDIA")}
</a>
);
}
@ -135,7 +136,7 @@ export function MediaItemAuthorLink(props) {
export function MediaItemMetaViews(props) {
return (
<span className="item-views">{formatViewsNumber(props.views) + ' ' + (1 >= props.views ? 'view' : 'views')}</span>
<span className="item-views">{formatViewsNumber(props.views) + ' ' + (1 >= props.views ? translateString('view') : translateString('views'))}</span>
);
}

View File

@ -8,6 +8,7 @@ import { PendingItemsList } from '../../item-list/PendingItemsList.jsx';
import { renderManageItems } from './includes/functions';
import initManageItemsList from './includes/initManageItemsList';
import { ManageItemsListHandler } from './includes/ManageItemsListHandler';
import { translateString } from '../../../utils/helpers/';
import './ManageItemList.scss';
@ -102,7 +103,7 @@ function useManageItemListSync(props) {
return 1 > listHandler.totalPages() || listHandler.loadedAllItems() ? null : (
<button className="load-more" onClick={onClickLoadMore}>
SHOW MORE
{translateString("SHOW MORE")}
</button>
);
}

View File

@ -2,6 +2,7 @@ import React, { useState } from 'react';
import { usePopup } from '../../utils/hooks/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, PopupMain } from '../_shared/';
import { PlaylistsSelection } from '../playlists-selection/PlaylistsSelection';
import { translateString } from '../../utils/helpers/';
function mediaSavePopupPages(onTriggerPopupClose) {
return {
@ -39,7 +40,7 @@ export function MediaSaveButton(props) {
<CircleIconButton type="span">
<MaterialIcon type="playlist_add" />
</CircleIconButton>
<span>SAVE</span>
<span>{translateString("SAVE")}</span>
</button>
</PopupTrigger>

View File

@ -3,6 +3,7 @@ import { usePopup } from '../../utils/hooks/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, PopupMain } from '../_shared/';
import { MediaShareEmbed } from './MediaShareEmbed';
import { MediaShareOptions } from './MediaShareOptions';
import { translateString } from '../../utils/helpers/';
function mediaSharePopupPages() {
return {
@ -54,7 +55,7 @@ export function MediaShareButton(props) {
<CircleIconButton type="span">
<MaterialIcon type="share" />
</CircleIconButton>
<span>SHARE</span>
<span>{translateString("SHARE")}</span>
</button>
</PopupTrigger>

View File

@ -4,6 +4,7 @@ import { SiteContext } from '../../utils/contexts/';
import { MediaPageStore } from '../../utils/stores/';
import { formatInnerLink } from '../../utils/helpers/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, NavigationMenuList, PopupMain } from '../_shared/';
import { translateString } from '../../utils/helpers/';
function downloadOptionsList() {
const media_data = MediaPageStore.get('media-data');
@ -71,7 +72,7 @@ export function VideoMediaDownloadLink(props) {
<CircleIconButton type="span">
<MaterialIcon type="arrow_downward" />
</CircleIconButton>
<span>DOWNLOAD</span>
<span>{translateString("DOWNLOAD")}</span>
</button>
</PopupTrigger>

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
import { PageActions } from '../../utils/actions/';
import { PageStore, MediaPageStore } from '../../utils/stores/';
import { ItemList } from '../item-list/ItemList';
import { translateString } from '../../utils/helpers/';
function autoPlayMedia() {
const dt = MediaPageStore.get('media-data');
@ -38,10 +39,10 @@ export function AutoPlay(props) {
return !media ? null : (
<div className="auto-play">
<div className="auto-play-header">
<div className="next-label">Up next</div>
<div className="next-label">{translateString("Up next")}</div>
<div className="auto-play-option">
<label className="checkbox-label right-selectbox" tabIndex={0} onKeyPress={onKeyPress}>
AUTOPLAY
{translateString("AUTOPLAY")}
<span className="checkbox-switcher-wrap">
<span className="checkbox-switcher">
<input

View File

@ -6,6 +6,8 @@ import { PageActions, MediaPageActions } from '../../utils/actions/';
import { formatInnerLink, publishedOnDate } from '../../utils/helpers/';
import { PopupMain } from '../_shared/';
import CommentsList from '../comments/Comments';
import { replaceString } from '../../utils/helpers/';
import { translateString } from '../../utils/helpers/';
function metafield(arr) {
let i;
@ -48,7 +50,7 @@ function MediaAuthorBanner(props) {
</a>
</span>
{PageStore.get('config-media-item').displayPublishDate && props.published ? (
<span className="author-banner-date">Published on {publishedOnDate(new Date(props.published))}</span>
<span className="author-banner-date">{translateString("Published on")} {replaceString(publishedOnDate(new Date(props.published)))}</span>
) : null}
</div>
</div>
@ -76,8 +78,8 @@ function EditMediaButton(props) {
}
return (
<a href={link} rel="nofollow" title="Edit media" className="edit-media">
EDIT MEDIA
<a href={link} rel="nofollow" title={translateString("Edit media")} className="edit-media">
{translateString("EDIT MEDIA")}
</a>
);
}
@ -90,8 +92,8 @@ function EditSubtitleButton(props) {
}
return (
<a href={link} rel="nofollow" title="Edit subtitle" className="edit-subtitle">
EDIT SUBTITLE
<a href={link} rel="nofollow" title={translateString("Edit subtitle")} className="edit-subtitle">
{translateString("EDIT SUBTITLE")}
</a>
);
}
@ -195,12 +197,12 @@ export default function ViewerInfoContent(props) {
</button>
) : null}
{tagsContent.length ? (
<MediaMetaField value={tagsContent} title={1 < tagsContent.length ? 'Tags' : 'Tag'} id="tags" />
<MediaMetaField value={tagsContent} title={1 < tagsContent.length ? translateString('Tags') : translateString('Tag')} id="tags" />
) : null}
{categoriesContent.length ? (
<MediaMetaField
value={categoriesContent}
title={1 < categoriesContent.length ? 'Categories' : 'Category'}
title={1 < categoriesContent.length ? translateString('Categories') : translateString('Category')}
id="categories"
/>
) : null}
@ -215,7 +217,7 @@ export default function ViewerInfoContent(props) {
) : null}
<PopupTrigger contentRef={popupContentRef}>
<button className="remove-media">DELETE MEDIA</button>
<button className="remove-media">{translateString("DELETE MEDIA")}</button>
</PopupTrigger>
<PopupContent contentRef={popupContentRef}>

View File

@ -4,6 +4,7 @@ import { PageStore, MediaPageStore } from '../../utils/stores/';
import { MemberContext, PlaylistsContext } from '../../utils/contexts/';
import { MediaLikeIcon, MediaDislikeIcon, OtherMediaDownloadLink, VideoMediaDownloadLink, MediaSaveButton, MediaShareButton, MediaMoreOptionsIcon } from '../media-actions/';
import ViewerInfoTitleBanner from './ViewerInfoTitleBanner';
import { translateString } from '../../utils/helpers/';
export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
render() {
@ -56,7 +57,7 @@ export default class ViewerInfoVideoTitleBanner extends ViewerInfoTitleBanner {
{displayViews ? (
<div className="media-views">
{formatViewsNumber(this.props.views, true)} {1 >= this.props.views ? 'view' : 'views'}
{formatViewsNumber(this.props.views, true)} {1 >= this.props.views ? translateString('view') : translateString('views')}
</div>
) : null}

View File

@ -4,6 +4,7 @@ import { PageStore } from '../../../utils/stores/';
import { HeaderConsumer, MemberConsumer, LinksConsumer } from '../../../utils/contexts/';
import { CircleIconButton, MaterialIcon, NavigationContentApp, NavigationMenuList, PopupTop, PopupMain, UserThumbnail } from '../../_shared';
import { HeaderThemeSwitcher } from './HeaderThemeSwitcher';
import { translateString } from '../../../utils/helpers/';
function headerPopupPages(user, popupNavItems, hasHeaderThemeSwitcher) {
const pages = {
@ -95,9 +96,9 @@ function LoginButton({ user, link, hasHeaderThemeSwitcher }) {
className={
'button-link sign-in' + (hasHeaderThemeSwitcher ? ' hidden-only-in-small' : ' hidden-only-in-extra-small')
}
title="Sign in"
title={translateString('Sign in')}
>
Sign in
{translateString('Sign in')}
</a>
</div>
) : null;
@ -112,9 +113,9 @@ function RegisterButton({ user, link, hasHeaderThemeSwitcher }) {
'button-link register-link' +
(hasHeaderThemeSwitcher ? ' hidden-only-in-small' : ' hidden-only-in-extra-small')
}
title="Register"
title={translateString('Register')}
>
Register
{translateString('Register')}
</a>
</div>
) : null;

View File

@ -4,6 +4,7 @@ import { LinksContext } from '../../../utils/contexts/';
import { PageStore, SearchFieldStore } from '../../../utils/stores/';
import { SearchFieldActions } from '../../../utils/actions/';
import { MaterialIcon, PopupMain } from '../../_shared';
import { translateString } from '../../../utils/helpers/';
import './SearchField.scss';
@ -296,7 +297,7 @@ export function SearchField(props) {
<input
ref={searchInputRef}
type="text"
placeholder="Search"
placeholder={translateString("Search")}
aria-label="Search"
name="q"
value={queryVal}

View File

@ -4,6 +4,7 @@ import { useUser } from '../../../utils/hooks/';
import { PageStore } from '../../../utils/stores/';
import { LinksContext, SidebarContext } from '../../../utils/contexts/';
import { NavigationMenuList } from '../../_shared';
import { translateString } from '../../../utils/helpers/';
export function SidebarNavigationMenu() {
const { userCan, isAnonymous, pages: userPages } = useUser();
@ -40,7 +41,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.home,
icon: 'home',
text: 'Home',
text: translateString('Home'),
className: 'nav-item-home',
});
}
@ -49,7 +50,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.featured,
icon: 'star',
text: PageStore.get('config-enabled').pages.featured.title,
text: translateString('Featured'),
className: 'nav-item-featured',
});
}
@ -61,7 +62,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.recommended,
icon: 'done_outline',
text: PageStore.get('config-enabled').pages.recommended.title,
text: translateString("Recommended"),
className: 'nav-item-recommended',
});
}
@ -70,7 +71,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.latest,
icon: 'new_releases',
text: PageStore.get('config-enabled').pages.latest.title,
text: translateString("Latest"),
className: 'nav-item-latest',
});
}
@ -83,7 +84,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.archive.tags,
icon: 'local_offer',
text: PageStore.get('config-enabled').taxonomies.tags.title,
text: translateString("Tags"),
className: 'nav-item-tags',
});
}
@ -96,7 +97,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.archive.categories,
icon: 'list_alt',
text: PageStore.get('config-enabled').taxonomies.categories.title,
text: translateString("Categories"),
className: 'nav-item-categories',
});
}
@ -105,7 +106,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.members,
icon: 'people',
text: PageStore.get('config-enabled').pages.members.title,
text: translateString("Members"),
className: 'nav-item-members',
});
}
@ -132,7 +133,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.user.addMedia,
icon: 'video_call',
text: 'Upload media',
text: translateString("Upload"),
className: 'nav-item-upload-media',
});
@ -140,7 +141,7 @@ export function SidebarNavigationMenu() {
items.push({
link: userPages.media,
icon: 'video_library',
text: 'My media',
text: translateString("My media"),
className: 'nav-item-my-media',
});
}
@ -150,7 +151,7 @@ export function SidebarNavigationMenu() {
items.push({
link: userPages.playlists,
icon: 'playlist_play',
text: 'My playlists',
text: translateString("My playlists"),
className: 'nav-item-my-playlists',
});
}
@ -166,7 +167,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.user.history,
icon: 'history',
text: PageStore.get('config-enabled').pages.history.title,
text: translateString("History"),
className: 'nav-item-history',
});
}
@ -179,7 +180,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.user.liked,
icon: 'thumb_up',
text: PageStore.get('config-enabled').pages.liked.title,
text: translateString("Liked media"),
className: 'nav-item-liked',
});
}
@ -188,7 +189,35 @@ export function SidebarNavigationMenu() {
}
function CustomMenuSection() {
const items = PageStore.get('config-contents').sidebar.navMenu.items;
const items = [];
items.push({
link: '/about',
icon: 'contact_support',
text: translateString("About"),
className: 'nav-item-about',
});
items.push({
link: '/tos',
icon: 'description',
text: translateString("Terms"),
className: 'nav-item-terms',
});
items.push({
link: '/contact',
icon: 'alternate_email',
text: translateString("Contact"),
className: 'nav-item-contact',
});
items.push({
link: '/setlanguage',
icon: 'language',
text: translateString("Language"),
className: 'nav-item-language',
});
return items.length ? <NavigationMenuList key="custom" items={formatItems(items)} /> : null;
}
@ -200,7 +229,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.manage.media,
icon: 'miscellaneous_services',
text: 'Manage media',
text: translateString("Manage media"),
className: 'nav-item-manage-media',
});
}
@ -209,7 +238,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.manage.users,
icon: 'miscellaneous_services',
text: 'Manage users',
text: translateString("Manage users"),
className: 'nav-item-manage-users',
});
}
@ -218,7 +247,7 @@ export function SidebarNavigationMenu() {
items.push({
link: links.manage.comments,
icon: 'miscellaneous_services',
text: 'Manage comments',
text: translateString("Manage comments"),
className: 'nav-item-manage-comments',
});
}

View File

@ -6,6 +6,7 @@ import { PageStore, ProfilePageStore } from '../../utils/stores/';
import { PageActions, ProfilePageActions } from '../../utils/actions/';
import { CircleIconButton, PopupMain } from '../_shared';
import ItemsInlineSlider from '../item-list/includes/itemLists/ItemsInlineSlider';
import { translateString } from '../../utils/helpers/';
class ProfileSearchBar extends React.PureComponent {
constructor(props) {
@ -315,13 +316,13 @@ class NavMenuInlineTabs extends React.PureComponent {
<InlineTab
id="about"
isActive={'about' === this.props.type}
label={'About' + (this.userIsAuthor ? ' Me' : '')}
label={translateString('About')}
link={LinksContext._currentValue.profile.about}
/>
<InlineTab
id="media"
isActive={'media' === this.props.type}
label={(this.userIsAuthor ? 'My ' : '') + 'Media'}
label={translateString('Media')}
link={LinksContext._currentValue.profile.media}
/>
@ -329,7 +330,7 @@ class NavMenuInlineTabs extends React.PureComponent {
<InlineTab
id="playlists"
isActive={'playlists' === this.props.type}
label={(this.userIsAuthor ? 'My ' : '') + 'Playlists'}
label={translateString('Playlists')}
link={LinksContext._currentValue.profile.playlists}
/>
) : null}

View File

@ -3,13 +3,14 @@ import { ApiUrlConsumer } from '../utils/contexts/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface CategoriesPageProps {
id?: string;
title?: string;
}
export const CategoriesPage: React.FC<CategoriesPageProps> = ({ id = 'categories', title = 'Categories' }) => (
export const CategoriesPage: React.FC<CategoriesPageProps> = ({ id = 'categories', title = translateString('Categories') }) => (
<Page id={id}>
<ApiUrlConsumer>
{(apiUrl) => (

View File

@ -4,6 +4,7 @@ import { PageStore } from '../utils/stores/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface FeaturedMediaPageProps {
id?: string;
@ -12,7 +13,7 @@ interface FeaturedMediaPageProps {
export const FeaturedMediaPage: React.FC<FeaturedMediaPageProps> = ({
id = 'featured-media',
title = PageStore.get('config-enabled').pages.featured.title,
title = translateString('Featured'),
}) => (
<Page id={id}>
<ApiUrlConsumer>

View File

@ -7,6 +7,7 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { ProfileHistoryPage } from './ProfileHistoryPage';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
declare global {
interface Window {
@ -21,7 +22,7 @@ interface AnonymousHistoryPageProps {
export const AnonymousHistoryPage: React.FC<AnonymousHistoryPageProps> = ({
id = 'history-media',
title = PageStore.get('config-enabled').pages.history.title,
title = translateString('History'),
}) => {
const [resultsCount, setResultsCount] = useState<number | null>(null);

View File

@ -6,6 +6,7 @@ import { MediaMultiListWrapper } from '../components/MediaMultiListWrapper';
import { ItemListAsync } from '../components/item-list/ItemListAsync.jsx';
import { InlineSliderItemListAsync } from '../components/item-list/InlineSliderItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
const EmptyMedia: React.FC = ({}) => {
return (
@ -35,9 +36,12 @@ interface HomePageProps {
export const HomePage: React.FC<HomePageProps> = ({
id = 'home',
featured_title = PageStore.get('config-options').pages.home.sections.featured.title,
recommended_title = PageStore.get('config-options').pages.home.sections.recommended.title,
latest_title = PageStore.get('config-options').pages.home.sections.latest.title,
//featured_title = PageStore.get('config-options').pages.home.sections.featured.title,
//recommended_title = PageStore.get('config-options').pages.home.sections.recommended.title,
//latest_title = PageStore.get('config-options').pages.home.sections.latest.title,
featured_title = translateString('Featured'),
recommended_title = translateString('Recommended'),
latest_title = translateString('Latest'),
latest_view_all_link = false,
featured_view_all_link = true,
recommended_view_all_link = true,

View File

@ -4,6 +4,7 @@ import { PageStore } from '../utils/stores/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface LatestMediaPageProps {
id?: string;
@ -12,7 +13,7 @@ interface LatestMediaPageProps {
export const LatestMediaPage: React.FC<LatestMediaPageProps> = ({
id = 'latest-media',
title = PageStore.get('config-enabled').pages.latest.title,
title = translateString('Recent uploads'),
}) => (
<Page id={id}>
<ApiUrlConsumer>

View File

@ -7,6 +7,7 @@ import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync';
import { ProfileLikedPage } from './ProfileLikedPage';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
declare global {
interface Window {
@ -21,7 +22,7 @@ interface AnonymousLikedMediaPageProps {
export const AnonymousLikedMediaPage: React.FC<AnonymousLikedMediaPageProps> = ({
id = 'liked-media',
title = PageStore.get('config-enabled').pages.liked.title,
title = translateString('Liked media'),
}) => {
const [resultsCount, setResultsCount] = useState<number | null>(null);

View File

@ -4,6 +4,7 @@ import { PageStore } from '../utils/stores/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface RecommendedMediaPageProps {
id?: string;
@ -12,7 +13,7 @@ interface RecommendedMediaPageProps {
export const RecommendedMediaPage: React.FC<RecommendedMediaPageProps> = ({
id = 'recommended-media',
title = PageStore.get('config-enabled').pages.recommended.title,
title = translateString('Recommended'),
}) => (
<Page id={id}>
<ApiUrlConsumer>

View File

@ -7,6 +7,7 @@ import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListA
import { SearchMediaFiltersRow } from '../components/search-filters/SearchMediaFiltersRow';
import { SearchResultsFilters } from '../components/search-filters/SearchResultsFilters';
import { Page } from './_Page';
import { translateString } from '../utils/helpers/';
export class SearchPage extends Page {
constructor(props) {
@ -114,13 +115,13 @@ export class SearchPage extends Page {
} else {
if (this.state.searchCategories) {
title = null === this.state.resultsCount || 0 === this.state.resultsCount ? 'No' : this.state.resultsCount;
title += ' media in category "' + this.state.searchCategories + '"';
title += ' ' + translateString('media in category') + ' "' + this.state.searchCategories + '"';
} else if (this.state.searchTags) {
title = null === this.state.resultsCount || 0 === this.state.resultsCount ? 'No' : this.state.resultsCount;
title += ' media in tag "' + this.state.searchTags + '"';
title += ' ' + translateString('media in tag') + ' "' + this.state.searchTags + '"';
} else {
if (null === this.state.resultsCount || 0 === this.state.resultsCount) {
title = 'No results for "' + this.state.searchQuery + '"';
title = translateString('No results for') + ' "' + this.state.searchQuery + '"';
} else {
title =
this.state.resultsCount +

View File

@ -3,13 +3,14 @@ import { ApiUrlConsumer } from '../utils/contexts/';
import { MediaListWrapper } from '../components/MediaListWrapper';
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
import { Page } from './Page';
import { translateString } from '../utils/helpers/';
interface TagsPageProps {
id?: string;
title?: string;
}
export const TagsPage: React.FC<TagsPageProps> = ({ id = 'tags', title = 'Tags' }) => (
export const TagsPage: React.FC<TagsPageProps> = ({ id = 'tags', title = translateString('Tags') }) => (
<Page id={id}>
<ApiUrlConsumer>
{(apiUrl) => (

View File

@ -1,4 +1,5 @@
import { addClassname, removeClassname } from '../helpers/';
import { translateString } from '../../utils/helpers/';
export function UpNextLoaderView(nextItemData) {
var timerTimeout;
@ -39,7 +40,7 @@ export function UpNextLoaderView(nextItemData) {
domElems.nextMediaTitle.setAttribute('class', 'next-media-title');
domElems.nextMediaAuthor.setAttribute('class', 'next-media-author');
domElems.upNextLabel.innerHTML = 'Up Next';
domElems.upNextLabel.innerHTML = translateString('Up Next');
domElems.nextMediaTitle.innerHTML = nextItemData.title;
domElems.nextMediaAuthor.innerHTML = nextItemData.author_name;

View File

@ -1,5 +1,6 @@
import React, { createContext } from 'react';
import { config as mediacmsConfig } from '../settings/config.js';
import { translateString } from '../../utils/helpers/';
const config = mediacmsConfig(window.MediaCMS);
@ -17,7 +18,7 @@ function popupTopNavItems() {
items.push({
link: links.user.addMedia,
icon: 'video_call',
text: 'Upload media',
text: translateString('Upload media'),
itemAttr: {
className: 'visible-only-in-small',
},
@ -27,7 +28,7 @@ function popupTopNavItems() {
items.push({
link: user.pages.media,
icon: 'video_library',
text: 'My media',
text: translateString('My media'),
});
}
}
@ -35,7 +36,7 @@ function popupTopNavItems() {
items.push({
link: links.signout,
icon: 'exit_to_app',
text: 'Sign out',
text: translateString('Sign out'),
});
}
@ -64,7 +65,7 @@ function popupMiddleNavItems() {
itemType: 'link',
icon: 'login',
iconPos: 'left',
text: 'Sign in',
text: translateString('Sign in'),
link: links.signin,
linkAttr: {
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
@ -77,7 +78,7 @@ function popupMiddleNavItems() {
itemType: 'link',
icon: 'person_add',
iconPos: 'left',
text: 'Register',
text: translateString('Register'),
link: links.register,
linkAttr: {
className: hasThemeSwitcher ? 'visible-only-in-small' : 'visible-only-in-extra-small',
@ -88,14 +89,14 @@ function popupMiddleNavItems() {
items.push({
link: links.user.editProfile,
icon: 'brush',
text: 'Edit profile',
text: translateString('Edit profile'),
});
if (user.can.changePassword) {
items.push({
link: links.changePassword,
icon: 'lock',
text: 'Change password',
text: translateString('Change password'),
});
}
}

View File

@ -12,3 +12,5 @@ export * from './propTypeFilters';
export { default as publishedOnDate } from './publishedOnDate';
export * from './quickSort';
export * from './requests';
export { translateString } from './translate';
export { replaceString } from './replacementStrings';

View File

@ -0,0 +1,8 @@
// check templates/config/installation/translations.html for more
export function replaceString(string) {
for (const key in window.REPLACEMENTS) {
string = string.replace(key, window.REPLACEMENTS[key]);
}
return string;
}

View File

@ -0,0 +1,9 @@
// check templates/config/installation/translations.html for more
export function translateString(string) {
if (window.TRANSLATION && window.TRANSLATION[string]) {
return window.TRANSLATION[string];
} else {
return string;
}
}

View File

@ -1,5 +1,6 @@
import React, { useEffect, useRef } from 'react';
import { useItemList } from './useItemList';
import { translateString } from '../../utils/helpers/';
export function useItemListSync(props) {
const itemsListRef = useRef(null);
@ -32,7 +33,7 @@ export function useItemListSync(props) {
return 1 > listHandler.totalPages() || listHandler.loadedAllItems() ? null : (
<button className="load-more" onClick={onClickLoadMore}>
SHOW MORE
{translateString("SHOW MORE")}
</button>
);
}

View File

@ -10,6 +10,7 @@ import {
MediaItemEditLink,
} from '../../components/list-item/includes/items';
import { useItem } from './useItem';
import { replaceString } from '../../utils/helpers/';
export function itemClassname(defaultClassname, inheritedClassname, isActiveInPlaylistPlayback) {
let classname = defaultClassname;
@ -56,7 +57,7 @@ export function useMediaItem(props) {
return null;
}
const publishDate = format(new Date(props.publish_date));
const publishDate = replaceString(format(new Date(props.publish_date)));
const publishDateTime =
'string' === typeof props.publish_date
? Date.parse(props.publish_date)