diff --git a/src/common/MetaRow/MetaRow.js b/src/common/MetaRow/MetaRow.js index 298f7919b..48b5092fc 100644 --- a/src/common/MetaRow/MetaRow.js +++ b/src/common/MetaRow/MetaRow.js @@ -4,19 +4,18 @@ const React = require('react'); const ReactIs = require('react-is'); const PropTypes = require('prop-types'); const classnames = require('classnames'); -const { useTranslation } = require('react-i18next'); const { default: Icon } = require('@stremio/stremio-icons/react'); const Button = require('stremio/common/Button'); const CONSTANTS = require('stremio/common/CONSTANTS'); -const translateCatalog = require('stremio/common/translateCatalog'); +const useTranslate = require('stremio/common/useTranslate'); const MetaRowPlaceholder = require('./MetaRowPlaceholder'); const styles = require('./styles'); const MetaRow = ({ className, title, catalog, message, items, itemComponent, deepLinks }) => { - const { t } = useTranslation(); + const t = useTranslate(); const catalogTitle = React.useMemo(() => { - return title ?? translateCatalog(catalog); + return title ?? t.catalogTitle(catalog); }, [title, catalog]); return ( @@ -30,8 +29,8 @@ const MetaRow = ({ className, title, catalog, message, items, itemComponent, dee } { deepLinks && (typeof deepLinks.discover === 'string' || typeof deepLinks.library === 'string') ? - : diff --git a/src/common/index.js b/src/common/index.js index 0e8cf8c35..f2942bfb4 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -32,8 +32,6 @@ const getVisibleChildrenRange = require('./getVisibleChildrenRange'); const interfaceLanguages = require('./interfaceLanguages.json'); const languageNames = require('./languageNames.json'); const routesRegexp = require('./routesRegexp'); -const translateOption = require('./translateOption'); -const translateCatalog = require('./translateCatalog'); const useAnimationFrame = require('./useAnimationFrame'); const useBinaryState = require('./useBinaryState'); const useFullscreen = require('./useFullscreen'); @@ -44,6 +42,7 @@ const useOnScrollToBottom = require('./useOnScrollToBottom'); const useProfile = require('./useProfile'); const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); +const useTranslate = require('./useTranslate'); const platform = require('./platform'); const externalPlayerOptions = require('./externalPlayerOptions'); @@ -84,8 +83,6 @@ module.exports = { interfaceLanguages, languageNames, routesRegexp, - translateOption, - translateCatalog, useAnimationFrame, useBinaryState, useFullscreen, @@ -96,6 +93,7 @@ module.exports = { useProfile, useStreamingServer, useTorrent, + useTranslate, platform, externalPlayerOptions, }; diff --git a/src/common/translateCatalog.js b/src/common/translateCatalog.js deleted file mode 100644 index 86a4c70ad..000000000 --- a/src/common/translateCatalog.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const { t } = require('i18next'); - -const translateCatalog = ({ addon, id, name, type } = {}, withType = true) => { - if (addon && id && name) { - const label = `${addon.manifest.id}/${id}`; - const translatedName = t(`CATALOG_${label}`, { defaultValue: name }); - if (type && withType) { - const translatedType = t(`TYPE_${type}`, { defaultValue: type }); - return `${translatedName} - ${translatedType}`; - } - return translatedName; - } - return null; -}; - -module.exports = translateCatalog; diff --git a/src/common/translateOption.js b/src/common/translateOption.js deleted file mode 100644 index bbe0a9ebc..000000000 --- a/src/common/translateOption.js +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const { t } = require('i18next'); - -const translateOption = (option, translateKeyPrefix = '') => { - const translateKey = `${translateKeyPrefix}${option}`; - const translateValue = t(translateKey, { - defaultValue: t(translateKey.toUpperCase(), { - defaultValue: null - }) - }); - return translateValue ?? option.charAt(0).toUpperCase() + option.slice(1); -}; - -module.exports = translateOption; diff --git a/src/common/useTranslate.js b/src/common/useTranslate.js new file mode 100644 index 000000000..22f0443ea --- /dev/null +++ b/src/common/useTranslate.js @@ -0,0 +1,40 @@ +const { useTranslation } = require('react-i18next'); + +const useTranslate = () => { + const { t } = useTranslation(); + + const string = (key) => t(key); + + const stringWithPrefix = (value, prefix, fallback = null) => { + const key = `${prefix}${value}`; + const defaultValue = fallback ?? value.charAt(0).toUpperCase() + value.slice(1); + + return t(key, { + defaultValue, + }); + }; + + const catalogTitle = ({ addon, id, name, type } = {}, withType = true) => { + if (addon && id && name) { + const partialKey = `${addon.manifest.id}/${id}`; + const translatedName = stringWithPrefix(partialKey, 'CATALOG_', name); + + if (type && withType) { + const translatedType = stringWithPrefix(type, 'TYPE_'); + return `${translatedName} - ${translatedType}`; + } + + return translatedName; + } + + return null; + }; + + return { + string, + stringWithPrefix, + catalogTitle, + }; +}; + +module.exports = useTranslate; diff --git a/src/routes/Addons/useSelectableInputs.js b/src/routes/Addons/useSelectableInputs.js index a48cd2ac9..af0bb35fc 100644 --- a/src/routes/Addons/useSelectableInputs.js +++ b/src/routes/Addons/useSelectableInputs.js @@ -1,18 +1,17 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); -const { t } = require('i18next'); -const { translateOption } = require('stremio/common'); +const { useTranslate } = require('stremio/common'); -const mapSelectableInputs = (installedAddons, remoteAddons) => { +const mapSelectableInputs = (installedAddons, remoteAddons, t) => { const catalogSelect = { - title: t('SELECT_CATALOG'), + title: t.string('SELECT_CATALOG'), options: remoteAddons.selectable.catalogs .concat(installedAddons.selectable.catalogs) .map(({ name, deepLinks }) => ({ value: deepLinks.addons, - label: translateOption(name, 'ADDON_'), - title: translateOption(name, 'ADDON_'), + label: t.stringWithPrefix(name, 'ADDON_'), + title: t.stringWithPrefix(name, 'ADDON_'), })), selected: remoteAddons.selectable.catalogs .concat(installedAddons.selectable.catalogs) @@ -22,7 +21,7 @@ const mapSelectableInputs = (installedAddons, remoteAddons) => { () => { const selectableCatalog = remoteAddons.selectable.catalogs .find(({ id }) => id === remoteAddons.selected.request.path.id); - return selectableCatalog ? translateOption(selectableCatalog.name, 'ADDON_') : remoteAddons.selected.request.path.id; + return selectableCatalog ? t.stringWithPrefix(selectableCatalog.name, 'ADDON_') : remoteAddons.selected.request.path.id; } : null, @@ -31,16 +30,16 @@ const mapSelectableInputs = (installedAddons, remoteAddons) => { } }; const typeSelect = { - title: t('SELECT_TYPE'), + title: t.string('SELECT_TYPE'), options: installedAddons.selected !== null ? installedAddons.selectable.types.map(({ type, deepLinks }) => ({ value: deepLinks.addons, - label: type !== null ? translateOption(type, 'TYPE_') : t('TYPE_ALL') + label: type !== null ? t.stringWithPrefix(type, 'TYPE_') : t.string('TYPE_ALL') })) : remoteAddons.selectable.types.map(({ type, deepLinks }) => ({ value: deepLinks.addons, - label: translateOption(type, 'TYPE_') + label: t.stringWithPrefix(type, 'TYPE_') })), selected: installedAddons.selected !== null ? installedAddons.selectable.types @@ -53,12 +52,12 @@ const mapSelectableInputs = (installedAddons, remoteAddons) => { renderLabelText: () => { return installedAddons.selected !== null ? installedAddons.selected.request.type === null ? - t('TYPE_ALL') + t.string('TYPE_ALL') : - translateOption(installedAddons.selected.request.type, 'TYPE_') + t.stringWithPrefix(installedAddons.selected.request.type, 'TYPE_') : remoteAddons.selected !== null ? - translateOption(remoteAddons.selected.request.path.type, 'TYPE_') + t.stringWithPrefix(remoteAddons.selected.request.path.type, 'TYPE_') : typeSelect.title; }, @@ -70,8 +69,9 @@ const mapSelectableInputs = (installedAddons, remoteAddons) => { }; const useSelectableInputs = (installedAddons, remoteAddons) => { + const t = useTranslate(); const selectableInputs = React.useMemo(() => { - return mapSelectableInputs(installedAddons, remoteAddons); + return mapSelectableInputs(installedAddons, remoteAddons, t); }, [installedAddons, remoteAddons]); return selectableInputs; }; diff --git a/src/routes/Discover/useSelectableInputs.js b/src/routes/Discover/useSelectableInputs.js index a9f393537..18d317507 100644 --- a/src/routes/Discover/useSelectableInputs.js +++ b/src/routes/Discover/useSelectableInputs.js @@ -1,22 +1,21 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); -const { useTranslation } = require('react-i18next'); -const { translateOption, translateCatalog } = require('stremio/common'); +const { useTranslate } = require('stremio/common'); const mapSelectableInputs = (discover, t) => { const typeSelect = { - title: t('SELECT_TYPE'), + title: t.string('SELECT_TYPE'), options: discover.selectable.types .map(({ type, deepLinks }) => ({ value: deepLinks.discover, - label: translateOption(type, 'TYPE_') + label: t.stringWithPrefix(type, 'TYPE_') })), selected: discover.selectable.types .filter(({ selected }) => selected) .map(({ deepLinks }) => deepLinks.discover), renderLabelText: discover.selected !== null ? - () => translateOption(discover.selected.request.path.type, 'TYPE_') + () => t.stringWithPrefix(discover.selected.request.path.type, 'TYPE_') : null, onSelect: (event) => { @@ -24,11 +23,11 @@ const mapSelectableInputs = (discover, t) => { } }; const catalogSelect = { - title: t('SELECT_CATALOG'), + title: t.string('SELECT_CATALOG'), options: discover.selectable.catalogs .map(({ id, name, addon, deepLinks }) => ({ value: deepLinks.discover, - label: translateCatalog({ addon, id, name }), + label: t.catalogTitle({ addon, id, name }), title: `${name} (${addon.manifest.name})` })), selected: discover.selectable.catalogs @@ -38,7 +37,7 @@ const mapSelectableInputs = (discover, t) => { () => { const selectableCatalog = discover.selectable.catalogs .find(({ id }) => id === discover.selected.request.path.id); - return selectableCatalog ? translateCatalog(selectableCatalog, false) : discover.selected.request.path.id; + return selectableCatalog ? t.catalogTitle(selectableCatalog, false) : discover.selected.request.path.id; } : null, @@ -47,10 +46,10 @@ const mapSelectableInputs = (discover, t) => { } }; const extraSelects = discover.selectable.extra.map(({ name, isRequired, options }) => ({ - title: translateOption(name, 'SELECT_'), + title: t.stringWithPrefix(name, 'SELECT_'), isRequired: isRequired, options: options.map(({ value, deepLinks }) => ({ - label: typeof value === 'string' ? translateOption(value) : t('NONE'), + label: typeof value === 'string' ? t.stringWithPrefix(value) : t.string('NONE'), value: JSON.stringify({ href: deepLinks.discover, value @@ -63,7 +62,7 @@ const mapSelectableInputs = (discover, t) => { value })), renderLabelText: options.some(({ selected, value }) => selected && value === null) ? - () => translateOption(name, 'SELECT_') + () => t.stringWithPrefix(name, 'SELECT_') : null, onSelect: (event) => { @@ -75,7 +74,7 @@ const mapSelectableInputs = (discover, t) => { }; const useSelectableInputs = (discover) => { - const { t } = useTranslation(); + const t = useTranslate(); const selectableInputs = React.useMemo(() => { return mapSelectableInputs(discover, t); }, [discover.selected, discover.selectable]); diff --git a/src/routes/Library/useSelectableInputs.js b/src/routes/Library/useSelectableInputs.js index 49eb94a1f..ef956814b 100644 --- a/src/routes/Library/useSelectableInputs.js +++ b/src/routes/Library/useSelectableInputs.js @@ -1,16 +1,15 @@ // Copyright (C) 2017-2023 Smart code 203358507 const React = require('react'); -const { useTranslation } = require('react-i18next'); -const { translateOption } = require('stremio/common'); +const { useTranslate } = require('stremio/common'); const mapSelectableInputs = (library, t) => { const typeSelect = { - title: t('SELECT_TYPE'), + title: t.string('SELECT_TYPE'), options: library.selectable.types .map(({ type, deepLinks }) => ({ value: deepLinks.library, - label: type === null ? t('TYPE_ALL') : translateOption(type, 'TYPE_') + label: type === null ? t.string('TYPE_ALL') : t.stringWithPrefix(type, 'TYPE_') })), selected: library.selectable.types .filter(({ selected }) => selected) @@ -20,11 +19,11 @@ const mapSelectableInputs = (library, t) => { } }; const sortSelect = { - title: t('SELECT_SORT'), + title: t.string('SELECT_SORT'), options: library.selectable.sorts .map(({ sort, deepLinks }) => ({ value: deepLinks.library, - label: translateOption(sort, 'SORT_') + label: t.stringWithPrefix(sort, 'SORT_') })), selected: library.selectable.sorts .filter(({ selected }) => selected) @@ -51,7 +50,7 @@ const mapSelectableInputs = (library, t) => { }; const useSelectableInputs = (library) => { - const { t } = useTranslation(); + const t = useTranslate(); const selectableInputs = React.useMemo(() => { return mapSelectableInputs(library, t); }, [library]);