fix some i18n

closes #2726
pull/2728/head
Mikael Finstad 5 months ago
parent 2601288785
commit 260128e165
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -134,6 +134,10 @@ A videos rotation is just metadata stored in its file. A file can only have a
When you use the Tracks panel to extract a single track as a file, e.g. a subtitle, a default format will be automatically chosen. For example for subtitle, it will output an `.mks`. If you want a different output format, you can instead disable all tracks except the single track you want to extract, then close the Tracks panel, the choose the output format, (e.g. `srt`) and then perform an export. When you use the Tracks panel to extract a single track as a file, e.g. a subtitle, a default format will be automatically chosen. For example for subtitle, it will output an `.mks`. If you want a different output format, you can instead disable all tracks except the single track you want to extract, then close the Tracks panel, the choose the output format, (e.g. `srt`) and then perform an export.
## Translation is missing
If some text in the UI is in English even though you've selected a different language, please first check that it has actually been translated in [Weblate](translation.md). If not, you can help contribute. If it is not, you may create an issue.
# Still cannot find an answer? # Still cannot find an answer?
If any other problem please search for [existing issues](https://github.com/mifi/lossless-cut/issues) before you [ask a question](https://github.com/mifi/lossless-cut/discussions) here on GitHub. You can check the developer tools for any errors or clues. Menu: `Tools` -> `Toggle Developer Tools`. If any other problem please search for [existing issues](https://github.com/mifi/lossless-cut/issues) before you [ask a question](https://github.com/mifi/lossless-cut/discussions) here on GitHub. You can check the developer tools for any errors or clues. Menu: `Tools` -> `Toggle Developer Tools`.

@ -1,14 +1,16 @@
import { FaTimes } from 'react-icons/fa'; import { FaTimes } from 'react-icons/fa';
import type { DetailedHTMLProps, ButtonHTMLAttributes } from 'react'; import type { DetailedHTMLProps, ButtonHTMLAttributes } from 'react';
import { useTranslation } from 'react-i18next';
import styles from './CloseButton.module.css'; import styles from './CloseButton.module.css';
import i18n from '../i18n';
export default function CloseButton({ type = 'button', ...props }: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>) { export default function CloseButton({ type = 'button', ...props }: DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>) {
const { t } = useTranslation();
return ( return (
// eslint-disable-next-line react/jsx-props-no-spreading, react/button-has-type // eslint-disable-next-line react/jsx-props-no-spreading, react/button-has-type
<button type={type} className={styles['close-button']} title={i18n.t('Close')} aria-label={i18n.t('Close')} {...props}> <button type={type} className={styles['close-button']} title={t('Close')} aria-label={t('Close')} {...props}>
<FaTimes /> <FaTimes />
</button> </button>
); );

@ -228,7 +228,7 @@ function ConcatDialog({ isShown, onHide, paths, mergedFileTemplate, generateMerg
problemsByFile[path] ? ( problemsByFile[path] ? (
<Dialog.Root> <Dialog.Root>
<Dialog.Trigger asChild> <Dialog.Trigger asChild>
<Button title={i18n.t('Mismatches detected')} style={{ color: warningColor, marginLeft: '1em' }}><FaExclamationTriangle /></Button> <Button title={t('Mismatches detected')} style={{ color: warningColor, marginLeft: '1em' }}><FaExclamationTriangle /></Button>
</Dialog.Trigger> </Dialog.Trigger>
<Dialog.Portal> <Dialog.Portal>

@ -3,16 +3,18 @@ import { memo, useCallback } from 'react';
import { FaClipboard } from 'react-icons/fa'; import { FaClipboard } from 'react-icons/fa';
import type { MotionStyle } from 'motion/react'; import type { MotionStyle } from 'motion/react';
import { motion, useAnimation } from 'motion/react'; import { motion, useAnimation } from 'motion/react';
import i18n from '../i18n'; import { useTranslation } from 'react-i18next';
const electron = window.require('electron'); const electron = window.require('electron');
const { clipboard } = electron; const { clipboard } = electron;
function CopyClipboardButton({ text, style, children = ({ onClick }) => <FaClipboard title={i18n.t('Copy to clipboard')} onClick={onClick} /> }: { function CopyClipboardButton({ text, style, children }: {
text: string, text: string,
style?: MotionStyle, style?: MotionStyle,
children?: (p: { onClick: () => void }) => ReactNode, children?: (p: { onClick: () => void }) => ReactNode,
}) { }) {
const { t } = useTranslation();
const animation = useAnimation(); const animation = useAnimation();
const onClick = useCallback(() => { const onClick = useCallback(() => {
@ -25,7 +27,7 @@ function CopyClipboardButton({ text, style, children = ({ onClick }) => <FaClipb
return ( return (
<motion.span animate={animation} style={{ display: 'inline-block', cursor: 'pointer', ...style }}> <motion.span animate={animation} style={{ display: 'inline-block', cursor: 'pointer', ...style }}>
{children({ onClick })} {children != null ? children({ onClick }) : <FaClipboard title={t('Copy to clipboard')} onClick={onClick} />}
</motion.span> </motion.span>
); );
} }

@ -1,7 +1,6 @@
import type { ChangeEventHandler } from 'react'; import type { ChangeEventHandler } from 'react';
import { memo, useState, useEffect, useCallback, useRef, useMemo } from 'react'; import { memo, useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useDebounce } from 'use-debounce'; import { useDebounce } from 'use-debounce';
import i18n from 'i18next';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { IoIosHelpCircle } from 'react-icons/io'; import { IoIosHelpCircle } from 'react-icons/io';
import { motion, AnimatePresence } from 'motion/react'; import { motion, AnimatePresence } from 'motion/react';
@ -228,7 +227,7 @@ function FileNameTemplateEditor(opts: {
</div> </div>
<div style={{ fontSize: '.9em', color: 'var(--gray-11)', display: 'flex', gap: '.3em', flexWrap: 'wrap', alignItems: 'center', marginBottom: '.7em' }}> <div style={{ fontSize: '.9em', color: 'var(--gray-11)', display: 'flex', gap: '.3em', flexWrap: 'wrap', alignItems: 'center', marginBottom: '.7em' }}>
{`${i18n.t('Variables')}:`} {`${t('Variables')}:`}
<IoIosHelpCircle fontSize="1.3em" color="var(--gray-12)" role="button" cursor="pointer" onClick={() => electron.shell.openExternal(exportedFileNameTemplateHelpUrl)} /> <IoIosHelpCircle fontSize="1.3em" color="var(--gray-12)" role="button" cursor="pointer" onClick={() => electron.shell.openExternal(exportedFileNameTemplateHelpUrl)} />
{availableVariables.map((variable) => ( {availableVariables.map((variable) => (
@ -265,14 +264,14 @@ function FileNameTemplateEditor(opts: {
{generated.problems.sameAsInputFileNameWarning && ( {generated.problems.sameAsInputFileNameWarning && (
<div style={{ marginBottom: '1em' }}> <div style={{ marginBottom: '1em' }}>
<FaExclamationTriangle style={{ verticalAlign: 'middle', marginRight: '.3em' }} color={warningColor} /> <FaExclamationTriangle style={{ verticalAlign: 'middle', marginRight: '.3em' }} color={warningColor} />
{i18n.t('Output file name is the same as the source file name. This increases the risk of accidentally overwriting or deleting source files!')} {t('Output file name is the same as the source file name. This increases the risk of accidentally overwriting or deleting source files!')}
</div> </div>
)} )}
{!shouldIgnoreMissingExtension && isMissingExtension && ( {!shouldIgnoreMissingExtension && isMissingExtension && (
<div style={{ marginBottom: '1em' }}> <div style={{ marginBottom: '1em' }}>
<FaExclamationTriangle style={{ verticalAlign: 'middle', marginRight: '.3em' }} color={warningColor} /> <FaExclamationTriangle style={{ verticalAlign: 'middle', marginRight: '.3em' }} color={warningColor} />
{i18n.t('The file name template is missing {{ext}} and will result in a file without the suggested extension. This may result in an unplayable output file.', { ext: extVariableFormatted })} {t('The file name template is missing {{ext}} and will result in a file without the suggested extension. This may result in an unplayable output file.', { ext: extVariableFormatted })}
</div> </div>
)} )}
</> </>

@ -1,6 +1,6 @@
import type { CSSProperties } from 'react'; import type { CSSProperties } from 'react';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import i18n from 'i18next'; import { useTranslation } from 'react-i18next';
import type { FfmpegFormat } from '../outFormats'; import type { FfmpegFormat } from '../outFormats';
import allOutFormats from '../outFormats'; import allOutFormats from '../outFormats';
@ -24,6 +24,8 @@ function OutputFormatSelect({ style, disabled, detectedFileFormat, fileFormat, o
fileFormat?: string | undefined, fileFormat?: string | undefined,
onOutputFormatUserChange: (a: string) => void, onOutputFormatUserChange: (a: string) => void,
}) { }) {
const { t } = useTranslation();
const commonVideoAudioFormatsExceptDetectedFormat = useMemo(() => commonVideoAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]); const commonVideoAudioFormatsExceptDetectedFormat = useMemo(() => commonVideoAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
const commonAudioFormatsExceptDetectedFormat = useMemo(() => commonAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]); const commonAudioFormatsExceptDetectedFormat = useMemo(() => commonAudioFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
const commonSubtitleFormatsExceptDetectedFormat = useMemo(() => commonSubtitleFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]); const commonSubtitleFormatsExceptDetectedFormat = useMemo(() => commonSubtitleFormats.filter((f) => f !== detectedFileFormat), [detectedFileFormat]);
@ -33,25 +35,25 @@ function OutputFormatSelect({ style, disabled, detectedFileFormat, fileFormat, o
return ( return (
// eslint-disable-next-line react/jsx-props-no-spreading // eslint-disable-next-line react/jsx-props-no-spreading
<Select style={style} disabled={disabled} value={fileFormat || ''} title={i18n.t('Output container format:')} onChange={withBlur((e) => onOutputFormatUserChange(e.target.value))}> <Select style={style} disabled={disabled} value={fileFormat || ''} title={t('Output container format:')} onChange={withBlur((e) => onOutputFormatUserChange(e.target.value))}>
<option key="disabled1" value="" disabled>{i18n.t('Output container format:')}</option> <option key="disabled1" value="" disabled>{t('Output container format:')}</option>
{detectedFileFormat && ( {detectedFileFormat && (
<option key={detectedFileFormat} value={detectedFileFormat}> <option key={detectedFileFormat} value={detectedFileFormat}>
{detectedFileFormat} - {(allOutFormats as Record<string, string>)[detectedFileFormat]} {i18n.t('(detected)')} {detectedFileFormat} - {(allOutFormats as Record<string, string>)[detectedFileFormat]} {t('(detected)')}
</option> </option>
)} )}
<option key="disabled2" value="" disabled>--- {i18n.t('Common video/audio formats:')} ---</option> <option key="disabled2" value="" disabled>--- {t('Common video/audio formats:')} ---</option>
{renderFormatOptions(commonVideoAudioFormatsExceptDetectedFormat)} {renderFormatOptions(commonVideoAudioFormatsExceptDetectedFormat)}
<option key="disabled3" value="" disabled>--- {i18n.t('Common audio formats:')} ---</option> <option key="disabled3" value="" disabled>--- {t('Common audio formats:')} ---</option>
{renderFormatOptions(commonAudioFormatsExceptDetectedFormat)} {renderFormatOptions(commonAudioFormatsExceptDetectedFormat)}
<option key="disabled4" value="" disabled>--- {i18n.t('Common subtitle formats:')} ---</option> <option key="disabled4" value="" disabled>--- {t('Common subtitle formats:')} ---</option>
{renderFormatOptions(commonSubtitleFormatsExceptDetectedFormat)} {renderFormatOptions(commonSubtitleFormatsExceptDetectedFormat)}
<option key="disabled5" value="" disabled>--- {i18n.t('All other formats:')} ---</option> <option key="disabled5" value="" disabled>--- {t('All other formats:')} ---</option>
{renderFormatOptions(otherFormats)} {renderFormatOptions(otherFormats)}
</Select> </Select>
); );

Loading…
Cancel
Save