fix: suit i18n with mocha and optimize translation

- use `import * as i18next from 'i18next';` instead of `import i18next from 'i18next';` and add an specific env to bypass mocha test
- optimized several translations
This commit is contained in:
r-q 2022-07-22 21:35:25 +08:00 committed by Anton Belodedenko
parent eb5f5bbb9e
commit 0f10f2d483
19 changed files with 46 additions and 36 deletions

View File

@ -38,7 +38,7 @@ import * as osDialog from './os/dialog';
import * as windowProgress from './os/window-progress'; import * as windowProgress from './os/window-progress';
import MainPage from './pages/main/MainPage'; import MainPage from './pages/main/MainPage';
import './css/main.css'; import './css/main.css';
import i18next from 'i18next'; import * as i18next from 'i18next';
window.addEventListener( window.addEventListener(
'unhandledrejection', 'unhandledrejection',

View File

@ -44,7 +44,7 @@ import {
import { SourceMetadata } from '../source-selector/source-selector'; import { SourceMetadata } from '../source-selector/source-selector';
import { middleEllipsis } from '../../utils/middle-ellipsis'; import { middleEllipsis } from '../../utils/middle-ellipsis';
import i18next from 'i18next'; import * as i18next from 'i18next';
interface UsbbootDrive extends sourceDestination.UsbbootDrive { interface UsbbootDrive extends sourceDestination.UsbbootDrive {
progress: number; progress: number;

View File

@ -7,7 +7,7 @@ import { middleEllipsis } from '../../utils/middle-ellipsis';
import * as prettyBytes from 'pretty-bytes'; import * as prettyBytes from 'pretty-bytes';
import { DriveWithWarnings } from '../../pages/main/Flash'; import { DriveWithWarnings } from '../../pages/main/Flash';
import i18next from 'i18next'; import * as i18next from 'i18next';
const DriveStatusWarningModal = ({ const DriveStatusWarningModal = ({
done, done,

View File

@ -17,7 +17,7 @@
import * as React from 'react'; import * as React from 'react';
import { BaseButton } from '../../styled-components'; import { BaseButton } from '../../styled-components';
import i18next from 'i18next'; import * as i18next from 'i18next';
export interface FlashAnotherProps { export interface FlashAnotherProps {
onClick: () => void; onClick: () => void;

View File

@ -31,7 +31,7 @@ import { resetState } from '../../models/flash-state';
import * as selection from '../../models/selection-state'; import * as selection from '../../models/selection-state';
import { middleEllipsis } from '../../utils/middle-ellipsis'; import { middleEllipsis } from '../../utils/middle-ellipsis';
import { Modal, Table } from '../../styled-components'; import { Modal, Table } from '../../styled-components';
import i18next from 'i18next'; import * as i18next from 'i18next';
const ErrorsTable = styled((props) => <Table<FlashError> {...props} />)` const ErrorsTable = styled((props) => <Table<FlashError> {...props} />)`
&&& [data-display='table-head'], &&& [data-display='table-head'],

View File

@ -20,7 +20,7 @@ import { default as styled } from 'styled-components';
import { fromFlashState } from '../../modules/progress-status'; import { fromFlashState } from '../../modules/progress-status';
import { StepButton } from '../../styled-components'; import { StepButton } from '../../styled-components';
import i18next from 'i18next'; import * as i18next from 'i18next';
const FlashProgressBar = styled(ProgressBar)` const FlashProgressBar = styled(ProgressBar)`
> div { > div {

View File

@ -24,7 +24,7 @@ import * as settings from '../../models/settings';
import * as analytics from '../../modules/analytics'; import * as analytics from '../../modules/analytics';
import { open as openExternal } from '../../os/open-external/services/open-external'; import { open as openExternal } from '../../os/open-external/services/open-external';
import { Modal } from '../../styled-components'; import { Modal } from '../../styled-components';
import i18next from 'i18next'; import * as i18next from 'i18next';
interface Setting { interface Setting {
name: string; name: string;

View File

@ -66,7 +66,7 @@ import { DriveSelector } from '../drive-selector/drive-selector';
import { DrivelistDrive } from '../../../../shared/drive-constraints'; import { DrivelistDrive } from '../../../../shared/drive-constraints';
import axios, { AxiosRequestConfig } from 'axios'; import axios, { AxiosRequestConfig } from 'axios';
import { isJson } from '../../../../shared/utils'; import { isJson } from '../../../../shared/utils';
import i18next from 'i18next'; import * as i18next from 'i18next';
const recentUrlImagesKey = 'recentUrlImages'; const recentUrlImagesKey = 'recentUrlImages';

View File

@ -32,7 +32,7 @@ import {
StepNameButton, StepNameButton,
} from '../../styled-components'; } from '../../styled-components';
import { middleEllipsis } from '../../utils/middle-ellipsis'; import { middleEllipsis } from '../../utils/middle-ellipsis';
import i18next from 'i18next'; import * as i18next from 'i18next';
interface TargetSelectorProps { interface TargetSelectorProps {
targets: any[]; targets: any[];

View File

@ -37,7 +37,7 @@ import TgtSvg from '../../../assets/tgt.svg';
import DriveSvg from '../../../assets/drive.svg'; import DriveSvg from '../../../assets/drive.svg';
import { warning } from '../../../../shared/messages'; import { warning } from '../../../../shared/messages';
import { DrivelistDrive } from '../../../../shared/drive-constraints'; import { DrivelistDrive } from '../../../../shared/drive-constraints';
import i18next from 'i18next'; import * as i18next from 'i18next';
export const getDriveListLabel = () => { export const getDriveListLabel = () => {
return getSelectedDrives() return getSelectedDrives()

View File

@ -1,10 +1,15 @@
import i18next from 'i18next'; import * as i18next from 'i18next';
import { initReactI18next } from 'react-i18next'; import { initReactI18next } from 'react-i18next';
import zh_CN_translation from './i18n/zh-CN'; import zh_CN_translation from './i18n/zh-CN';
import zh_TW_translation from './i18n/zh-TW'; import zh_TW_translation from './i18n/zh-TW';
import en_translation from './i18n/en'; import en_translation from './i18n/en';
export function langParser() { export function langParser() {
if (process.env.LANG !== undefined) {
// Bypass mocha, where lang-detect don't works
return 'en';
}
const lang = Intl.DateTimeFormat().resolvedOptions().locale; const lang = Intl.DateTimeFormat().resolvedOptions().locale;
switch (lang.substr(0, 2)) { switch (lang.substr(0, 2)) {

View File

@ -17,7 +17,7 @@ const translation = {
decompressing: 'Decompressing...', decompressing: 'Decompressing...',
flashing: 'Flashing...', flashing: 'Flashing...',
finishing: 'Finishing...', finishing: 'Finishing...',
verifying: 'Verifying...', verifying: 'Validating...',
failing: 'Failed', failing: 'Failed',
}, },
message: { message: {
@ -32,15 +32,12 @@ const translation = {
flashSucceed_other: 'Successful targets', flashSucceed_other: 'Successful targets',
flashFail_one: 'Failed target', flashFail_one: 'Failed target',
flashFail_other: 'Failed targets', flashFail_other: 'Failed targets',
to: 'to ',
toDrive: 'to {{description}} ({{name}})', toDrive: 'to {{description}} ({{name}})',
toTarget_one: 'to {{num}} target', toTarget_one: 'to {{num}} target',
toTarget_other: 'to {{num}} targets', toTarget_other: 'to {{num}} targets',
andFailTarget_one: 'and failed to be flashed to {{num}} target', andFailTarget_one: 'and failed to be flashed to {{num}} target',
andFailTarget_other: 'and failed to be flashed to {{num}} targets', andFailTarget_other: 'and failed to be flashed to {{num}} targets',
target_one: ' target', succeedTo: '{{name}} was successfully flashed {{target}}',
target_other: ' targets',
succeedTo: '{{name}} was successfully flashed to {{target}}',
exitWhileFlashing: exitWhileFlashing:
'You are currently flashing a drive. Closing Etcher may leave your drive in an unusable state.', 'You are currently flashing a drive. Closing Etcher may leave your drive in an unusable state.',
looksLikeWindowsImage: looksLikeWindowsImage:
@ -62,8 +59,7 @@ const translation = {
'The write has been completed successfully but Etcher detected potential corruption issues when reading the image back from the drive. \n\nPlease consider writing the image to a different drive.', 'The write has been completed successfully but Etcher detected potential corruption issues when reading the image back from the drive. \n\nPlease consider writing the image to a different drive.',
openError: openError:
'Something went wrong while opening {{source}}.\n\nError: {{error}}', 'Something went wrong while opening {{source}}.\n\nError: {{error}}',
flashError: flashError: 'Something went wrong while writing {{image}} {{targets}}.',
'Something went wrong while writing {{image}} to {{targets}}.',
unplug: unplug:
"Looks like Etcher lost access to the drive. Did it get unplugged accidentally?\n\nSometimes this error is caused by faulty readers that don't provide stable access to the drive.", "Looks like Etcher lost access to the drive. Did it get unplugged accidentally?\n\nSometimes this error is caused by faulty readers that don't provide stable access to the drive.",
cannotWrite: cannotWrite:
@ -129,6 +125,8 @@ const translation = {
speedTip: speedTip:
'The speed is calculated by dividing the image size by the flashing time.\nDisk images with ext partitions flash faster as we are able to skip unused parts.', 'The speed is calculated by dividing the image size by the flashing time.\nDisk images with ext partitions flash faster as we are able to skip unused parts.',
speed: 'Effective speed: {{speed}} MB/s', speed: 'Effective speed: {{speed}} MB/s',
speedShort: '{{speed}} MB/s',
eta: 'ETA: {{eta}}',
failedTarget: 'Failed targets', failedTarget: 'Failed targets',
failedRetry: 'Retry failed targets', failedRetry: 'Retry failed targets',
flashFailed: 'Flash Failed.', flashFailed: 'Flash Failed.',

View File

@ -32,15 +32,12 @@ const translation = {
flashSucceed_other: '烧录成功', flashSucceed_other: '烧录成功',
flashFail_one: '烧录失败', flashFail_one: '烧录失败',
flashFail_other: '烧录失败', flashFail_other: '烧录失败',
to: '到 ',
toDrive: '到 {{description}} ({{name}})', toDrive: '到 {{description}} ({{name}})',
toTarget_one: '到 {{num}} 个目标', toTarget_one: '到 {{num}} 个目标',
toTarget_other: '到 {{num}} 个目标', toTarget_other: '到 {{num}} 个目标',
andFailTarget_one: '并烧录失败了 {{num}} 个目标', andFailTarget_one: '并烧录失败了 {{num}} 个目标',
andFailTarget_other: '并烧录失败了 {{num}} 个目标', andFailTarget_other: '并烧录失败了 {{num}} 个目标',
target_one: ' 个目标', succeedTo: '{{name}} 被成功烧录 {{target}}',
target_other: ' 个目标',
succeedTo: '{{name}} 被成功烧录到 {{target}}',
exitWhileFlashing: exitWhileFlashing:
'您当前正在刷机。 关闭 Etcher 可能会导致您的磁盘无法使用。', '您当前正在刷机。 关闭 Etcher 可能会导致您的磁盘无法使用。',
looksLikeWindowsImage: looksLikeWindowsImage:
@ -58,7 +55,7 @@ const translation = {
validation: validation:
'写入已成功完成,但 Etcher 在从磁盘读取镜像时检测到潜在的损坏问题。 \n\n请考虑将镜像写入其他磁盘。', '写入已成功完成,但 Etcher 在从磁盘读取镜像时检测到潜在的损坏问题。 \n\n请考虑将镜像写入其他磁盘。',
openError: '打开 {{source}} 时出错。\n\n错误信息 {{error}}', openError: '打开 {{source}} 时出错。\n\n错误信息 {{error}}',
flashError: '烧录 {{image}} {{targets}} 失败。', flashError: '烧录 {{image}} {{targets}} 失败。',
unplug: unplug:
'看起来 Etcher 失去了对磁盘的连接。 它是不是被意外拔掉了?\n\n有时这个错误是因为读卡器出了故障。', '看起来 Etcher 失去了对磁盘的连接。 它是不是被意外拔掉了?\n\n有时这个错误是因为读卡器出了故障。',
cannotWrite: cannotWrite:
@ -134,8 +131,10 @@ const translation = {
skip: '跳过了验证', skip: '跳过了验证',
moreInfo: '更多信息', moreInfo: '更多信息',
speedTip: speedTip:
'通过将像大小除以烧录时间来计算速度。\n由于我们能够跳过未使用的部分因此具有EXT分区的磁盘镜像烧录速度更快。', '通过将像大小除以烧录时间来计算速度。\n由于我们能够跳过未使用的部分因此具有EXT分区的磁盘镜像烧录速度更快。',
speed: '速度:{{speed}} MB/秒', speed: '速度:{{speed}} MB/秒',
speedShort: '{{speed}} MB/秒',
eta: '预计还需要:{{eta}}',
failedTarget: '失败的烧录目标', failedTarget: '失败的烧录目标',
failedRetry: '重试烧录失败目标', failedRetry: '重试烧录失败目标',
flashFailed: '烧录失败。', flashFailed: '烧录失败。',

View File

@ -32,15 +32,12 @@ const translation = {
flashSucceed_other: '燒錄成功', flashSucceed_other: '燒錄成功',
flashFail_one: '燒錄失敗', flashFail_one: '燒錄失敗',
flashFail_other: '燒錄失敗', flashFail_other: '燒錄失敗',
to: '到 ',
toDrive: '到 {{description}} ({{name}})', toDrive: '到 {{description}} ({{name}})',
toTarget_one: '到 {{num}} 個目標', toTarget_one: '到 {{num}} 個目標',
toTarget_other: '到 {{num}} 個目標', toTarget_other: '到 {{num}} 個目標',
andFailTarget_one: '並燒錄失敗了 {{num}} 個目標', andFailTarget_one: '並燒錄失敗了 {{num}} 個目標',
andFailTarget_other: '並燒錄失敗了 {{num}} 個目標', andFailTarget_other: '並燒錄失敗了 {{num}} 個目標',
target_one: ' 個目標', succeedTo: '{{name}} 被成功燒錄 {{target}}',
target_other: ' 個目標',
succeedTo: '{{name}} 被成功燒錄到 {{target}}',
exitWhileFlashing: exitWhileFlashing:
'您當前正在刷機。 關閉 Etcher 可能會導致您的磁盤無法使用。', '您當前正在刷機。 關閉 Etcher 可能會導致您的磁盤無法使用。',
looksLikeWindowsImage: looksLikeWindowsImage:
@ -58,7 +55,7 @@ const translation = {
validation: validation:
'寫入已成功完成,但 Etcher 在從磁盤讀取鏡像時檢測到潛在的損壞問題。 \n\n請考慮將鏡像寫入其他磁盤。', '寫入已成功完成,但 Etcher 在從磁盤讀取鏡像時檢測到潛在的損壞問題。 \n\n請考慮將鏡像寫入其他磁盤。',
openError: '打開 {{source}} 時出錯。\n\n錯誤信息 {{error}}', openError: '打開 {{source}} 時出錯。\n\n錯誤信息 {{error}}',
flashError: '燒錄 {{image}} {{targets}} 失敗。', flashError: '燒錄 {{image}} {{targets}} 失敗。',
unplug: unplug:
'看起來 Etcher 失去了對磁盤的連接。 它是不是被意外拔掉了?\n\n有時這個錯誤是因爲讀卡器出了故障。', '看起來 Etcher 失去了對磁盤的連接。 它是不是被意外拔掉了?\n\n有時這個錯誤是因爲讀卡器出了故障。',
cannotWrite: cannotWrite:
@ -134,8 +131,10 @@ const translation = {
skip: '跳過了驗證', skip: '跳過了驗證',
moreInfo: '更多信息', moreInfo: '更多信息',
speedTip: speedTip:
'通過將像大小除以燒錄時間來計算速度。\n由於我們能夠跳過未使用的部分因此具有EXT分區的磁盤鏡像燒錄速度更快。', '通過將像大小除以燒錄時間來計算速度。\n由於我們能夠跳過未使用的部分因此具有EXT分區的磁盤鏡像燒錄速度更快。',
speed: '速度:{{speed}} MB/秒', speed: '速度:{{speed}} MB/秒',
speedShort: '{{speed}} MB/秒',
eta: '預計還需要:{{eta}}',
failedTarget: '失敗的燒錄目標', failedTarget: '失敗的燒錄目標',
failedRetry: '重試燒錄失敗目標', failedRetry: '重試燒錄失敗目標',
flashFailed: '燒錄失敗。', flashFailed: '燒錄失敗。',

View File

@ -15,7 +15,7 @@
*/ */
import * as prettyBytes from 'pretty-bytes'; import * as prettyBytes from 'pretty-bytes';
import i18next from 'i18next'; import * as i18next from 'i18next';
export interface FlashState { export interface FlashState {
active: number; active: number;

View File

@ -20,7 +20,7 @@ import * as _ from 'lodash';
import * as errors from '../../../shared/errors'; import * as errors from '../../../shared/errors';
import * as settings from '../../../gui/app/models/settings'; import * as settings from '../../../gui/app/models/settings';
import { SUPPORTED_EXTENSIONS } from '../../../shared/supported-formats'; import { SUPPORTED_EXTENSIONS } from '../../../shared/supported-formats';
import i18next from 'i18next'; import * as i18next from 'i18next';
async function mountSourceDrive() { async function mountSourceDrive() {
// sourceDrivePath is the name of the link in /dev/disk/by-path // sourceDrivePath is the name of the link in /dev/disk/by-path

View File

@ -37,6 +37,7 @@ import {
import FlashSvg from '../../../assets/flash.svg'; import FlashSvg from '../../../assets/flash.svg';
import DriveStatusWarningModal from '../../components/drive-status-warning-modal/drive-status-warning-modal'; import DriveStatusWarningModal from '../../components/drive-status-warning-modal/drive-status-warning-modal';
import * as i18next from 'i18next';
const COMPLETED_PERCENTAGE = 100; const COMPLETED_PERCENTAGE = 100;
const SPEED_PRECISION = 2; const SPEED_PRECISION = 2;
@ -293,9 +294,17 @@ export class FlashStep extends React.PureComponent<
color="#7e8085" color="#7e8085"
width="100%" width="100%"
> >
<Txt>{this.props.speed.toFixed(SPEED_PRECISION)} MB/s</Txt> <Txt>
{i18next.t('flash.speedShort', {
speed: this.props.speed.toFixed(SPEED_PRECISION),
})}
</Txt>
{!_.isNil(this.props.eta) && ( {!_.isNil(this.props.eta) && (
<Txt>ETA: {formatSeconds(this.props.eta)}</Txt> <Txt>
{i18next.t('flash.eta', {
eta: formatSeconds(this.props.eta),
})}
</Txt>
)} )}
</Flex> </Flex>
)} )}

View File

@ -17,7 +17,7 @@
import * as electron from 'electron'; import * as electron from 'electron';
import { displayName } from '../../package.json'; import { displayName } from '../../package.json';
import i18next from 'i18next'; import * as i18next from 'i18next';
/** /**
* @summary Builds a native application menu for a given window * @summary Builds a native application menu for a given window

View File

@ -18,7 +18,7 @@ import { Dictionary } from 'lodash';
import { outdent } from 'outdent'; import { outdent } from 'outdent';
import * as prettyBytes from 'pretty-bytes'; import * as prettyBytes from 'pretty-bytes';
import '../gui/app/i18n'; import '../gui/app/i18n';
import i18next from 'i18next'; import * as i18next from 'i18next';
export const progress: Dictionary<(quantity: number) => string> = { export const progress: Dictionary<(quantity: number) => string> = {
successful: (quantity: number) => { successful: (quantity: number) => {