More translation strings

pull/943/head
Piero Toffanin 2020-12-16 14:37:35 -05:00
rodzic ba3fd861b8
commit 28f35de733
14 zmienionych plików z 91 dodań i 86 usunięć

Wyświetl plik

@ -2,6 +2,7 @@ import React from 'react';
import '../css/AssetDownloadButtons.scss'; import '../css/AssetDownloadButtons.scss';
import AssetDownloads from '../classes/AssetDownloads'; import AssetDownloads from '../classes/AssetDownloads';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { _ } from '../classes/gettext';
class AssetDownloadButtons extends React.Component { class AssetDownloadButtons extends React.Component {
static defaultProps = { static defaultProps = {
@ -29,7 +30,7 @@ class AssetDownloadButtons extends React.Component {
return (<div className={"asset-download-buttons " + (this.props.showLabel ? "btn-group" : "") + " " + (this.props.direction === "up" ? "dropup" : "")}> return (<div className={"asset-download-buttons " + (this.props.showLabel ? "btn-group" : "") + " " + (this.props.direction === "up" ? "dropup" : "")}>
<button type="button" className={"btn btn-sm " + this.props.buttonClass} disabled={this.props.disabled} data-toggle="dropdown"> <button type="button" className={"btn btn-sm " + this.props.buttonClass} disabled={this.props.disabled} data-toggle="dropdown">
<i className="glyphicon glyphicon-download"></i>{this.props.showLabel ? " Download Assets" : ""} <i className="glyphicon glyphicon-download"></i>{this.props.showLabel ? " " + _("Download Assets") : ""}
</button> </button>
{this.props.showLabel ? {this.props.showLabel ?
<button type="button" className={"btn btn-sm dropdown-toggle " + this.props.buttonClass} data-toggle="dropdown" disabled={this.props.disabled}> <button type="button" className={"btn btn-sm dropdown-toggle " + this.props.buttonClass} data-toggle="dropdown" disabled={this.props.disabled}>

Wyświetl plik

@ -4,8 +4,8 @@ import FormDialog from './FormDialog';
import ProcessingNodeOption from './ProcessingNodeOption'; import ProcessingNodeOption from './ProcessingNodeOption';
import PresetUtils from '../classes/PresetUtils'; import PresetUtils from '../classes/PresetUtils';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import $ from 'jquery';
import values from 'object.values'; import values from 'object.values';
import { _ } from '../classes/gettext';
if (!Object.values) { if (!Object.values) {
values.shim(); values.shim();
@ -92,13 +92,13 @@ class EditPresetDialog extends React.Component {
show={true} show={true}
onShow={this.onShow} onShow={this.onShow}
saveIcon="far fa-edit" saveIcon="far fa-edit"
title="Edit Task Options" title={_("Edit Task Options")}
saveAction={this.props.saveAction} saveAction={this.props.saveAction}
deleteWarning={false} deleteWarning={false}
deleteAction={(this.props.preset.id !== -1 && !this.props.preset.system) ? this.props.deleteAction : undefined}> deleteAction={(this.props.preset.id !== -1 && !this.props.preset.system) ? this.props.deleteAction : undefined}>
{!this.isCustomPreset() ? {!this.isCustomPreset() ?
<div className="row preset-name"> <div className="row preset-name">
<label className="col-sm-2 control-label">Name</label> <label className="col-sm-2 control-label">{_("Name")}</label>
<div className="col-sm-10"> <div className="col-sm-10">
<input type="text" className="form-control" ref={(domNode) => { this.nameInput = domNode; }} value={this.state.name} onChange={this.handleChange('name')} /> <input type="text" className="form-control" ref={(domNode) => { this.nameInput = domNode; }} value={this.state.name} onChange={this.handleChange('name')} />
</div> </div>

Wyświetl plik

@ -6,6 +6,7 @@ import ErrorMessage from './ErrorMessage';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Storage from '../classes/Storage'; import Storage from '../classes/Storage';
import $ from 'jquery'; import $ from 'jquery';
import { _, interpolate } from '../classes/gettext';
class EditTaskForm extends React.Component { class EditTaskForm extends React.Component {
@ -85,7 +86,7 @@ class EditTaskForm extends React.Component {
loadProcessingNodes(){ loadProcessingNodes(){
const failed = () => { const failed = () => {
this.setState({error: "Could not load list of processing nodes. Are you connected to the internet?"}); this.setState({error: _("Could not load list of processing nodes. Are you connected to the internet?")});
} }
this.nodesRequest = this.nodesRequest =
@ -93,11 +94,8 @@ class EditTaskForm extends React.Component {
if (Array.isArray(json)){ if (Array.isArray(json)){
// No nodes with options? // No nodes with options?
const noProcessingNodesError = (nodes) => { const noProcessingNodesError = (nodes) => {
var extra = nodes ? "We tried to reach:<ul>" + nodes.map(n => Utils.html`<li><a href="${n.url}">${n.label}</a></li>`).join("") + "</ul>" : ""; var extra = nodes ? _("We tried to reach:") + "<ul>" + nodes.map(n => Utils.html`<li><a href="${n.url}">${n.label}</a></li>`).join("") + "</ul>" : "";
this.setState({error: `There are no usable processing nodes. ${extra}Make sure that at least one processing node is reachable and this.setState({error: _("There are no usable processing nodes.") + extra + _("Make sure that at least one processing node is reachable and that you have granted the current user sufficient permissions to view the processing node (by going to Administration -- Processing Nodes -- Select Node -- Object Permissions -- Add User/Group and check CAN VIEW PROCESSING NODE). If you are bringing a node back online, it will take about 30 seconds for WebODM to recognize it.")});
that you have granted the current user sufficient permissions to view
the processing node (by going to Administration -- Processing Nodes -- Select Node -- Object Permissions -- Add User/Group and check CAN VIEW PROCESSING NODE).
If you are bringing a node back online, it will take about 30 seconds for WebODM to recognize it.`});
}; };
if (json.length === 0){ if (json.length === 0){
@ -215,7 +213,7 @@ class EditTaskForm extends React.Component {
loadPresets(){ loadPresets(){
const failed = () => { const failed = () => {
this.setState({error: "Could not load list of presets. Are you connected to the internet?"}); this.setState({error: _("Could not load list of presets. Are you connected to the internet?")});
} }
this.presetsRequest = this.presetsRequest =
@ -224,13 +222,14 @@ class EditTaskForm extends React.Component {
// Add custom preset // Add custom preset
const customPreset = { const customPreset = {
id: -1, id: -1,
name: "(Custom)", name: "(" + _("Custom") + ")",
options: [], options: [],
system: true system: true
}; };
presets.unshift(customPreset); presets.unshift(customPreset);
// Choose preset // Choose preset
_("Default"); // Add translation
let selectedPreset = presets[0], let selectedPreset = presets[0],
defaultPreset = presets.find(p => p.name === "Default"); // Do not translate Default defaultPreset = presets.find(p => p.name === "Default"); // Do not translate Default
if (defaultPreset) selectedPreset = defaultPreset; if (defaultPreset) selectedPreset = defaultPreset;
@ -351,7 +350,7 @@ class EditTaskForm extends React.Component {
getAvailableOptionsOnlyText(options, availableOptions){ getAvailableOptionsOnlyText(options, availableOptions){
const opts = this.getAvailableOptionsOnly(options, availableOptions); const opts = this.getAvailableOptionsOnly(options, availableOptions);
let res = opts.map(opt => `${opt.name}:${opt.value}`).join(", "); let res = opts.map(opt => `${opt.name}:${opt.value}`).join(", ");
if (!res) res = "Default"; if (!res) res = _("Default");
return res; return res;
} }
@ -382,7 +381,7 @@ class EditTaskForm extends React.Component {
if (!customPreset){ if (!customPreset){
customPreset = { customPreset = {
id: -1, id: -1,
name: "(Custom)", name: "(" + _("Custom") + ")",
options: [], options: [],
system: true system: true
}; };
@ -435,7 +434,7 @@ class EditTaskForm extends React.Component {
this.setState({presetActionPerforming: true}); this.setState({presetActionPerforming: true});
const isCustom = selectedPreset.id === -1, const isCustom = selectedPreset.id === -1,
name = isCustom ? "My Preset" : "Copy of " + selectedPreset.name; name = isCustom ? _("My Preset") : interpolate(_("Copy of %(preset)s"), {preset: selectedPreset.name});
$.ajax({ $.ajax({
url: `/api/presets/`, url: `/api/presets/`,
@ -458,7 +457,7 @@ class EditTaskForm extends React.Component {
this.setState({presets, selectedPreset: preset}); this.setState({presets, selectedPreset: preset});
this.handleEditPreset(); this.handleEditPreset();
}).fail(() => { }).fail(() => {
this.setState({presetError: "Could not duplicate the preset. Please try to refresh the page."}); this.setState({presetError: _("Could not duplicate the preset. Please try to refresh the page.")});
}).always(() => { }).always(() => {
this.setState({presetActionPerforming: false}); this.setState({presetActionPerforming: false});
}); });
@ -467,11 +466,11 @@ class EditTaskForm extends React.Component {
handleDeletePreset(){ handleDeletePreset(){
const { selectedPreset, presets } = this.state; const { selectedPreset, presets } = this.state;
if (selectedPreset.system){ if (selectedPreset.system){
this.setState({presetError: "System presets can only be removed by a staff member from the Administration panel."}); this.setState({presetError: _("System presets can only be removed by a staff member from the Administration panel.")});
return; return;
} }
if (window.confirm(`Are you sure you want to delete "${selectedPreset.name}"?`)){ if (window.confirm(interpolate(_('Are you sure you want to delete "%(preset)s"?'), { preset: selectedPreset.name}))){
this.setState({presetActionPerforming: true}); this.setState({presetActionPerforming: true});
return $.ajax({ return $.ajax({
@ -484,7 +483,7 @@ class EditTaskForm extends React.Component {
// Select first by default // Select first by default
this.setState({presets, selectedPreset: presets[0], editingPreset: false}); this.setState({presets, selectedPreset: presets[0], editingPreset: false});
}).fail(() => { }).fail(() => {
this.setState({presetError: "Could not delete the preset. Please try to refresh the page."}); this.setState({presetError: _("Could not delete the preset. Please try to refresh the page.")});
}).always(() => { }).always(() => {
this.setState({presetActionPerforming: false}); this.setState({presetActionPerforming: false});
}); });
@ -499,7 +498,7 @@ class EditTaskForm extends React.Component {
<div className="alert alert-warning"> <div className="alert alert-warning">
<div dangerouslySetInnerHTML={{__html:this.state.error}}></div> <div dangerouslySetInnerHTML={{__html:this.state.error}}></div>
<button className="btn btn-sm btn-primary" onClick={this.retryLoad}> <button className="btn btn-sm btn-primary" onClick={this.retryLoad}>
<i className="fa fa-rotate-left"></i> Retry <i className="fa fa-rotate-left"></i> {_("Retry")}
</button> </button>
</div> </div>
</div>); </div>);
@ -515,35 +514,35 @@ class EditTaskForm extends React.Component {
value={this.state.selectedPreset.id} value={this.state.selectedPreset.id}
onChange={this.handleSelectPreset}> onChange={this.handleSelectPreset}>
{this.state.presets.map(preset => {this.state.presets.map(preset =>
<option value={preset.id} key={preset.id} className={preset.system ? "system-preset" : ""}>{preset.name}</option> <option value={preset.id} key={preset.id} className={preset.system ? "system-preset" : ""}>{preset.name === "Default" ? _(preset.name) : preset.name}</option>
)} )}
</select> </select>
{!this.state.presetActionPerforming ? {!this.state.presetActionPerforming ?
<div className="btn-group presets-dropdown"> <div className="btn-group presets-dropdown">
<button type="button" className="btn btn-default" title="Edit Task Options" onClick={this.handleEditPreset}> <button type="button" className="btn btn-default" title={_("Edit Task Options")} onClick={this.handleEditPreset}>
<i className="fa fa-sliders-h"></i> Edit <i className="fa fa-sliders-h"></i> {_("Edit")}
</button> </button>
<button type="button" className="btn btn-default dropdown-toggle" data-toggle="dropdown"> <button type="button" className="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span className="caret"></span> <span className="caret"></span>
</button> </button>
<ul className="dropdown-menu"> <ul className="dropdown-menu">
<li> <li>
<a href="javascript:void(0);" onClick={this.handleEditPreset}><i className="fa fa-sliders-h"></i> Edit</a> <a href="javascript:void(0);" onClick={this.handleEditPreset}><i className="fa fa-sliders-h"></i> {_("Edit")}</a>
</li> </li>
<li className="divider"></li> <li className="divider"></li>
{this.state.selectedPreset.id !== -1 ? {this.state.selectedPreset.id !== -1 ?
<li> <li>
<a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-copy"></i> Duplicate</a> <a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-copy"></i> {_("Duplicate")}</a>
</li> </li>
: :
<li> <li>
<a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-save"></i> Save</a> <a href="javascript:void(0);" onClick={this.handleDuplicateSavePreset}><i className="fa fa-save"></i> {_("Save")}</a>
</li> </li>
} }
<li className={this.state.selectedPreset.system ? "disabled" : ""}> <li className={this.state.selectedPreset.system ? "disabled" : ""}>
<a href="javascript:void(0);" onClick={this.handleDeletePreset}><i className="fa fa-trash"></i> Delete</a> <a href="javascript:void(0);" onClick={this.handleDeletePreset}><i className="fa fa-trash"></i> {_("Delete")}</a>
</li> </li>
</ul> </ul>
</div> </div>
@ -554,7 +553,7 @@ class EditTaskForm extends React.Component {
taskOptions = ( taskOptions = (
<div> <div>
<div className="form-group"> <div className="form-group">
<label className="col-sm-2 control-label">Processing Node</label> <label className="col-sm-2 control-label">{_("Processing Node")}</label>
<div className="col-sm-10"> <div className="col-sm-10">
<select className="form-control" value={this.state.selectedNode.key} onChange={this.handleSelectNode}> <select className="form-control" value={this.state.selectedNode.key} onChange={this.handleSelectNode}>
{this.state.processingNodes.map(node => {this.state.processingNodes.map(node =>
@ -564,7 +563,7 @@ class EditTaskForm extends React.Component {
</div> </div>
</div> </div>
<div className="form-group form-inline"> <div className="form-group form-inline">
<label className="col-sm-2 control-label">Options</label> <label className="col-sm-2 control-label">{_("Options")}</label>
<div className="col-sm-10"> <div className="col-sm-10">
{!this.props.inReview ? optionsSelector : {!this.props.inReview ? optionsSelector :
<div className="review-options"> <div className="review-options">
@ -588,14 +587,14 @@ class EditTaskForm extends React.Component {
); );
}else{ }else{
taskOptions = (<div className="form-group"> taskOptions = (<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">Loading processing nodes and presets... <i className="fa fa-sync fa-spin fa-fw"></i></div> <div className="col-sm-offset-2 col-sm-10">{_("Loading processing nodes and presets...")} <i className="fa fa-sync fa-spin fa-fw"></i></div>
</div>); </div>);
} }
return ( return (
<div className="edit-task-form"> <div className="edit-task-form">
<div className="form-group"> <div className="form-group">
<label className="col-sm-2 control-label">Name</label> <label className="col-sm-2 control-label">{_("Name")}</label>
<div className="col-sm-10"> <div className="col-sm-10">
{this.state.loadingTaskName ? {this.state.loadingTaskName ?
<i className="fa fa-circle-notch fa-spin fa-fw name-loading"></i> <i className="fa fa-circle-notch fa-spin fa-fw name-loading"></i>

Wyświetl plik

@ -25,7 +25,7 @@ class ErrorMessage extends React.Component {
if (parent.state[prop]){ if (parent.state[prop]){
return ( return (
<div className={"alert alert-warning alert-dismissible " + (this.props.className ? this.props.className : "")}> <div className={"alert alert-warning alert-dismissible " + (this.props.className ? this.props.className : "")}>
<button type="button" className="close" aria-label="Close" onClick={this.close}><span aria-hidden="true">&times;</span></button> <button type="button" className="close" title={_("Close")} onClick={this.close}><span aria-hidden="true">&times;</span></button>
{parent.state[prop]} {parent.state[prop]}
</div> </div>
); );

Wyświetl plik

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import '../css/Histogram.scss'; import '../css/Histogram.scss';
import d3 from 'd3'; import d3 from 'd3';
import { _ } from '../classes/gettext';
export default class Histogram extends React.Component { export default class Histogram extends React.Component {
static defaultProps = { static defaultProps = {
@ -289,8 +290,8 @@ export default class Histogram extends React.Component {
return (<div className={"histogram " + (this.props.loading ? "disabled" : "")}> return (<div className={"histogram " + (this.props.loading ? "disabled" : "")}>
<div ref={(domNode) => { this.hgContainer = domNode; }}> <div ref={(domNode) => { this.hgContainer = domNode; }}>
</div> </div>
<label>Min:</label> <input onChange={this.handleChangeMin} type="number" className="form-control min-max" size={5} value={this.state.min} /> <label>{_("Min:")}</label> <input onChange={this.handleChangeMin} type="number" className="form-control min-max" size={5} value={this.state.min} />
<label>Max:</label> <input onChange={this.handleChangeMax} type="number" className="form-control min-max" size={5} value={this.state.max} /> <label>{_("Max:")}</label> <input onChange={this.handleChangeMax} type="number" className="form-control min-max" size={5} value={this.state.max} />
</div>); </div>);
} }
} }

Wyświetl plik

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import AssetDownloads from '../classes/AssetDownloads'; import AssetDownloads from '../classes/AssetDownloads';
import '../css/ImagePopup.scss'; import '../css/ImagePopup.scss';
import { _ } from '../classes/gettext';
class ImagePopup extends React.Component { class ImagePopup extends React.Component {
static propTypes = { static propTypes = {
@ -43,7 +44,7 @@ class ImagePopup extends React.Component {
} }
imageOnError = () => { imageOnError = () => {
this.setState({error: "Image is missing", loading: false}); this.setState({error: _("Image is missing"), loading: false});
} }
imageOnLoad = () => { imageOnLoad = () => {
@ -82,7 +83,7 @@ class ImagePopup extends React.Component {
<a onClick={this.onImgClick} href="javascript:void(0);" title={feature.properties.filename}><img style={{borderRadius: "4px"}} src={imageUrl} onLoad={this.imageOnLoad} onError={this.imageOnError} /></a> <a onClick={this.onImgClick} href="javascript:void(0);" title={feature.properties.filename}><img style={{borderRadius: "4px"}} src={imageUrl} onLoad={this.imageOnLoad} onError={this.imageOnError} /></a>
</div>, </div>,
<div key="download-image"> <div key="download-image">
<a href={downloadImageLink}><i className="fa fa-image"></i> Download Image</a> <a href={downloadImageLink}><i className="fa fa-image"></i> {_("Download Image")}</a>
</div> </div>
]} ]}
<div> <div>

Wyświetl plik

@ -5,6 +5,8 @@ import Dropzone from '../vendor/dropzone';
import csrf from '../django/csrf'; import csrf from '../django/csrf';
import ErrorMessage from './ErrorMessage'; import ErrorMessage from './ErrorMessage';
import UploadProgressBar from './UploadProgressBar'; import UploadProgressBar from './UploadProgressBar';
import { _, interpolate } from '../classes/gettext';
import Trans from './Trans';
class ImportTaskPanel extends React.Component { class ImportTaskPanel extends React.Component {
static defaultProps = { static defaultProps = {
@ -58,7 +60,7 @@ class ImportTaskPanel extends React.Component {
}); });
this.dz.on("error", (file) => { this.dz.on("error", (file) => {
if (this.state.uploading) this.setState({error: "Cannot upload file. Check your internet connection and try again."}); if (this.state.uploading) this.setState({error: _("Cannot upload file. Check your internet connection and try again.")});
}) })
.on("sending", () => { .on("sending", () => {
this.setState({typeUrl: false, uploading: true, totalCount: 1}); this.setState({typeUrl: false, uploading: true, totalCount: 1});
@ -86,10 +88,10 @@ class ImportTaskPanel extends React.Component {
if (!response.id) throw new Error(`Expected id field, but none given (${response})`); if (!response.id) throw new Error(`Expected id field, but none given (${response})`);
this.props.onImported(); this.props.onImported();
}catch(e){ }catch(e){
this.setState({error: `Invalid response from server: ${e.message}`}); this.setState({error: interpolate(_('Invalid response from server: %(error)s'), { error: e.message})});
} }
}else if (this.state.uploading){ }else if (this.state.uploading){
this.setState({uploading: false, error: "An error occured while uploading the file. Please try again."}); this.setState({uploading: false, error: _("An error occured while uploading the file. Please try again.")});
} }
}); });
} }
@ -133,11 +135,11 @@ class ImportTaskPanel extends React.Component {
if (json.id){ if (json.id){
this.props.onImported(); this.props.onImported();
}else{ }else{
this.setState({error: json.error || `Cannot import from URL, server responded: ${JSON.stringify(json)}`}); this.setState({error: json.error || interpolate(_("Invalid JSON response: %(error)s"), {error: JSON.stringify(json)})});
} }
}) })
.fail(() => { .fail(() => {
this.setState({importingFromUrl: false, error: "Cannot import from URL. Check your internet connection."}); this.setState({importingFromUrl: false, error: _("Cannot import from URL. Check your internet connection.")});
}); });
} }
@ -153,16 +155,16 @@ class ImportTaskPanel extends React.Component {
<div className="form-horizontal"> <div className="form-horizontal">
<ErrorMessage bind={[this, 'error']} /> <ErrorMessage bind={[this, 'error']} />
<button type="button" className="close theme-color-primary" aria-label="Close" onClick={this.cancel}><span aria-hidden="true">&times;</span></button> <button type="button" className="close theme-color-primary" title="Close" onClick={this.cancel}><span aria-hidden="true">&times;</span></button>
<h4>Import Existing Assets</h4> <h4>{_("Import Existing Assets")}</h4>
<p>You can import .zip files that have been exported from existing tasks via Download Assets <i className="glyphicon glyphicon-arrow-right"></i> All Assets.</p> <p><Trans params={{arrow: '<i class="glyphicon glyphicon-arrow-right"></i>'}}>{_("You can import .zip files that have been exported from existing tasks via Download Assets %(arrow)s All Assets.")}</Trans></p>
<button disabled={this.state.uploading} <button disabled={this.state.uploading}
type="button" type="button"
className="btn btn-primary" className="btn btn-primary"
ref={this.setRef("uploadButton")}> ref={this.setRef("uploadButton")}>
<i className="glyphicon glyphicon-upload"></i> <i className="glyphicon glyphicon-upload"></i>
Upload a File {_("Upload a File")}
</button> </button>
<button disabled={this.state.uploading} <button disabled={this.state.uploading}
type="button" type="button"
@ -170,7 +172,7 @@ class ImportTaskPanel extends React.Component {
onClick={this.handleImportFromUrl} onClick={this.handleImportFromUrl}
ref={this.setRef("importFromUrlButton")}> ref={this.setRef("importFromUrlButton")}>
<i className="glyphicon glyphicon-cloud-download"></i> <i className="glyphicon glyphicon-cloud-download"></i>
Import From URL {_("Import From URL")}
</button> </button>
{this.state.typeUrl ? {this.state.typeUrl ?
@ -179,7 +181,7 @@ class ImportTaskPanel extends React.Component {
<input disabled={this.state.importingFromUrl} onChange={this.handleChangeImportUrl} size="45" type="text" className="form-control" placeholder="http://" value={this.state.importUrl} /> <input disabled={this.state.importingFromUrl} onChange={this.handleChangeImportUrl} size="45" type="text" className="form-control" placeholder="http://" value={this.state.importUrl} />
<button onClick={this.handleConfirmImportUrl} <button onClick={this.handleConfirmImportUrl}
disabled={this.state.importUrl.length < 4 || this.state.importingFromUrl} disabled={this.state.importUrl.length < 4 || this.state.importingFromUrl}
className="btn-import btn btn-primary"><i className="glyphicon glyphicon-cloud-download"></i> Import</button> className="btn-import btn btn-primary"><i className="glyphicon glyphicon-cloud-download"></i> {_("Import")}</button>
</div> </div>
</div> : ""} </div> : ""}
@ -189,7 +191,7 @@ class ImportTaskPanel extends React.Component {
className="btn btn-danger btn-sm" className="btn btn-danger btn-sm"
onClick={this.cancelUpload}> onClick={this.cancelUpload}>
<i className="glyphicon glyphicon-remove-circle"></i> <i className="glyphicon glyphicon-remove-circle"></i>
Cancel Upload {_("Cancel Upload")}
</button> </button>
</div> : ""} </div> : ""}
</div> </div>

Wyświetl plik

@ -7,6 +7,7 @@ import Utils from '../classes/Utils';
import Workers from '../classes/Workers'; import Workers from '../classes/Workers';
import ErrorMessage from './ErrorMessage'; import ErrorMessage from './ErrorMessage';
import $ from 'jquery'; import $ from 'jquery';
import { _, interpolate } from '../classes/gettext';
export default class LayersControlLayer extends React.Component { export default class LayersControlLayer extends React.Component {
static defaultProps = { static defaultProps = {
@ -245,7 +246,7 @@ export default class LayersControlLayer extends React.Component {
}else if (result.error){ }else if (result.error){
this.setState({exportLoading: false, error: result.error}); this.setState({exportLoading: false, error: result.error});
}else{ }else{
this.setState({exportLoading: false, error: "Invalid response: " + result}); this.setState({exportLoading: false, error: interpolate(_("Invalid JSON response: %(error)s"), {error: JSON.stringify(result)})});
} }
}).fail(error => { }).fail(error => {
this.setState({exportLoading: false, error: JSON.stringify(error)}); this.setState({exportLoading: false, error: JSON.stringify(error)});
@ -283,7 +284,7 @@ export default class LayersControlLayer extends React.Component {
{formula !== "" && algorithms ? {formula !== "" && algorithms ?
<div className="row form-group form-inline"> <div className="row form-group form-inline">
<label className="col-sm-3 control-label">Algorithm:</label> <label className="col-sm-3 control-label">{_("Algorithm:")}</label>
<div className="col-sm-9 "> <div className="col-sm-9 ">
{histogramLoading ? {histogramLoading ?
<i className="fa fa-circle-notch fa-spin fa-fw" /> : <i className="fa fa-circle-notch fa-spin fa-fw" /> :
@ -295,7 +296,7 @@ export default class LayersControlLayer extends React.Component {
{bands !== "" && algo ? {bands !== "" && algo ?
<div className="row form-group form-inline"> <div className="row form-group form-inline">
<label className="col-sm-3 control-label">Filter:</label> <label className="col-sm-3 control-label">{_("Filter:")}</label>
<div className="col-sm-9 "> <div className="col-sm-9 ">
{histogramLoading ? {histogramLoading ?
<i className="fa fa-circle-notch fa-spin fa-fw" /> : <i className="fa fa-circle-notch fa-spin fa-fw" /> :
@ -307,7 +308,7 @@ export default class LayersControlLayer extends React.Component {
{colorMap && color_maps.length ? {colorMap && color_maps.length ?
<div className="row form-group form-inline"> <div className="row form-group form-inline">
<label className="col-sm-3 control-label">Color:</label> <label className="col-sm-3 control-label">{_("Color:")}</label>
<div className="col-sm-9 "> <div className="col-sm-9 ">
{histogramLoading ? {histogramLoading ?
<i className="fa fa-circle-notch fa-spin fa-fw" /> : <i className="fa fa-circle-notch fa-spin fa-fw" /> :
@ -319,18 +320,18 @@ export default class LayersControlLayer extends React.Component {
{hillshade !== "" ? {hillshade !== "" ?
<div className="row form-group form-inline"> <div className="row form-group form-inline">
<label className="col-sm-3 control-label">Shading:</label> <label className="col-sm-3 control-label">{_("Shading:")}</label>
<div className="col-sm-9 "> <div className="col-sm-9 ">
<select className="form-control" value={hillshade} onChange={this.handleSelectHillshade}> <select className="form-control" value={hillshade} onChange={this.handleSelectHillshade}>
<option value="0">None</option> <option value="0">{_("None")}</option>
<option value="6">Normal</option> <option value="6">{_("Normal")}</option>
<option value="18">Extruded</option> <option value="18">{_("Extruded")}</option>
</select> </select>
</div> </div>
</div> : ""} </div> : ""}
<div className="row form-group form-inline"> <div className="row form-group form-inline">
<label className="col-sm-3 control-label">Export: </label> <label className="col-sm-3 control-label">{_("Export:")} </label>
<div className="col-sm-9"> <div className="col-sm-9">
<button onClick={this.handleExport} disabled={exportLoading} type="button" className="btn btn-sm btn-default"> <button onClick={this.handleExport} disabled={exportLoading} type="button" className="btn btn-sm btn-default">
{exportLoading ? <i className="fa fa-spin fa-circle-notch"/> : <i className="far fa-image fa-fw" />} GeoTIFF {exportLoading ? <i className="fa fa-spin fa-circle-notch"/> : <i className="far fa-image fa-fw" />} GeoTIFF

Wyświetl plik

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import '../css/LayersControlPanel.scss'; import '../css/LayersControlPanel.scss';
import LayersControlLayer from './LayersControlLayer'; import LayersControlLayer from './LayersControlLayer';
import { _ } from '../classes/gettext';
export default class LayersControlPanel extends React.Component { export default class LayersControlPanel extends React.Component {
static defaultProps = { static defaultProps = {
@ -22,7 +23,7 @@ export default class LayersControlPanel extends React.Component {
render(){ render(){
let content = ""; let content = "";
if (!this.props.layers.length) content = (<span><i className="loading fa fa-circle-notch fa-spin"></i> Loading...</span>); if (!this.props.layers.length) content = (<span><i className="loading fa fa-circle-notch fa-spin"></i> {_("Loading...")}</span>);
else{ else{
content = (<div> content = (<div>
{this.props.overlays.length ? {this.props.overlays.length ?
@ -40,7 +41,7 @@ export default class LayersControlPanel extends React.Component {
return (<div className="layers-control-panel"> return (<div className="layers-control-panel">
<span className="close-button" onClick={this.props.onClose}/> <span className="close-button" onClick={this.props.onClose}/>
<div className="title">Layers</div> <div className="title">{_("Layers")}</div>
<hr/> <hr/>
{content} {content}
</div>); </div>);

Wyświetl plik

@ -26,6 +26,7 @@ import update from 'immutability-helper';
import Utils from '../classes/Utils'; import Utils from '../classes/Utils';
import '../vendor/leaflet/Leaflet.Ajax'; import '../vendor/leaflet/Leaflet.Ajax';
import '../vendor/leaflet/Leaflet.Awesome-markers'; import '../vendor/leaflet/Leaflet.Awesome-markers';
import { _ } from '../classes/gettext';
class Map extends React.Component { class Map extends React.Component {
static defaultProps = { static defaultProps = {
@ -78,13 +79,13 @@ class Map extends React.Component {
typeToHuman = (type) => { typeToHuman = (type) => {
switch(type){ switch(type){
case "orthophoto": case "orthophoto":
return "Orthophoto"; return _("Orthophoto");
case "plant": case "plant":
return "Plant Health"; return _("Plant Health");
case "dsm": case "dsm":
return "DSM"; return _("DSM");
case "dtm": case "dtm":
return "DTM"; return _("DTM");
} }
return ""; return "";
} }
@ -255,7 +256,7 @@ class Map extends React.Component {
} }
} }
}); });
shotsLayer[Symbol.for("meta")] = {name: name + " (Cameras)", icon: "fa fa-camera fa-fw"}; shotsLayer[Symbol.for("meta")] = {name: name + " " + _("(Cameras)"), icon: "fa fa-camera fa-fw"};
this.setState(update(this.state, { this.setState(update(this.state, {
overlays: {$push: [shotsLayer]} overlays: {$push: [shotsLayer]}
@ -327,13 +328,12 @@ class Map extends React.Component {
const customLayer = L.layerGroup(); const customLayer = L.layerGroup();
customLayer.on("add", a => { customLayer.on("add", a => {
let url = window.prompt(`Enter a tile URL template. Valid tokens are: let url = window.prompt([_('Enter a tile URL template. Valid coordinates are:'),
{z}, {x}, {y} for Z/X/Y tile scheme _('{z}, {x}, {y} for Z/X/Y tile scheme'),
{-y} for flipped TMS-style Y coordinates _('{-y} for flipped TMS-style Y coordinates'),
'',
Example: _('Example:'),
https://a.tile.openstreetmap.org/{z}/{x}/{y}.png 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png'].join("\n"), 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png');
`, 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png');
if (url){ if (url){
customLayer.clearLayers(); customLayer.clearLayers();
@ -346,8 +346,8 @@ https://a.tile.openstreetmap.org/{z}/{x}/{y}.png
l.bringToBack(); l.bringToBack();
} }
}); });
this.basemaps["Custom"] = customLayer; this.basemaps[_("Custom")] = customLayer;
this.basemaps["None"] = L.layerGroup(); this.basemaps[_("None")] = L.layerGroup();
} }
this.layersControl = new LayersControl({ this.layersControl = new LayersControl({
@ -398,7 +398,7 @@ https://a.tile.openstreetmap.org/{z}/{x}/{y}.png
this.container = Leaflet.DomUtil.create('div', 'leaflet-control-add-overlay leaflet-bar leaflet-control'); this.container = Leaflet.DomUtil.create('div', 'leaflet-control-add-overlay leaflet-bar leaflet-control');
Leaflet.DomEvent.disableClickPropagation(this.container); Leaflet.DomEvent.disableClickPropagation(this.container);
const btn = Leaflet.DomUtil.create('a', 'leaflet-control-add-overlay-button'); const btn = Leaflet.DomUtil.create('a', 'leaflet-control-add-overlay-button');
btn.setAttribute("title", "Add a temporary GeoJSON (.json) or ShapeFile (.zip) overlay"); btn.setAttribute("title", _("Add a temporary GeoJSON (.json) or ShapeFile (.zip) overlay"));
this.container.append(btn); this.container.append(btn);
addDnDZone(btn, {url: "/", clickable: true}); addDnDZone(btn, {url: "/", clickable: true});
@ -447,7 +447,7 @@ https://a.tile.openstreetmap.org/{z}/{x}/{y}.png
$assetLinks.append($(linksHtml)); $assetLinks.append($(linksHtml));
}) })
.fail(() => { .fail(() => {
$assetLinks.append($("<li>Error: cannot load assets list. </li>")); $assetLinks.append($("<li>" + _("Error: cannot load assets list.") + "</li>"));
}) })
.always(() => { .always(() => {
$assetLinks.removeClass('loading'); $assetLinks.removeClass('loading');

Wyświetl plik

@ -540,7 +540,7 @@ class ProjectListItem extends React.Component {
{this.state.upload.error !== "" ? {this.state.upload.error !== "" ?
<div className="alert alert-warning alert-dismissible"> <div className="alert alert-warning alert-dismissible">
<button type="button" className="close" aria-label={_("Close")} onClick={this.closeUploadError}><span aria-hidden="true">&times;</span></button> <button type="button" className="close" title={_("Close")} onClick={this.closeUploadError}><span aria-hidden="true">&times;</span></button>
{this.state.upload.error} {this.state.upload.error}
</div> </div>
: ""} : ""}

Wyświetl plik

@ -222,7 +222,7 @@ class TaskListItem extends React.Component {
optionsToList(options){ optionsToList(options){
if (!Array.isArray(options)) return ""; if (!Array.isArray(options)) return "";
else if (options.length === 0) return _("Default"); else if (options.length === 0) return "Default";
else { else {
return options.map(opt => `${opt.name}: ${opt.value}`).join(", "); return options.map(opt => `${opt.name}: ${opt.value}`).join(", ");
} }
@ -531,9 +531,7 @@ class TaskListItem extends React.Component {
{showExitedWithCodeOneHints ? {showExitedWithCodeOneHints ?
<div className="task-warning"><i className="fa fa-info-circle"></i> <div className="inline"> <div className="task-warning"><i className="fa fa-info-circle"></i> <div className="inline">
"Process exited with code 1" means that part of the processing failed. Sometimes it's a problem with the dataset, sometimes it can be solved by tweaking the Task Options and sometimes it might be a bug! <Trans params={{link1: `<a href="https://www.dronedb.app/" target="_blank">DroneDB</a>`, link2: `<a href="https://drive.google.com/drive/u/0/" target="_blank">Google Drive</a>`, open_a_topic: `<a href="http://community.opendronemap.org/c/webodm" target="_blank">${_("open a topic")}</a>`, }}>{_("\"Process exited with code 1\" means that part of the processing failed. Sometimes it's a problem with the dataset, sometimes it can be solved by tweaking the Task Options and sometimes it might be a bug! If you need help, upload your images somewhere like %(link1)s or %(link2)s and %(open_a_topic)s on our community forum, making sure to include a copy of your task's output. Our awesome contributors will try to help you!")}</Trans> <i className="far fa-smile"></i>
If you need help, upload your images somewhere like <a href="https://www.dronedb.app/" target="_blank">DroneDB</a> or <a href="https://drive.google.com/drive/u/0/" target="_blank">Google Drive</a> and <a href="http://community.opendronemap.org/c/webodm" target="_blank">open a topic</a> on our community forum, making
sure to include a <a href="javascript:void(0);" onClick={this.setView("console")}>copy of your task's output</a>. Our awesome contributors will try to help you! <i className="far fa-smile"></i>
</div> </div>
</div> </div>
: ""} : ""}
@ -579,12 +577,12 @@ class TaskListItem extends React.Component {
if (task.last_error){ if (task.last_error){
statusLabel = getStatusLabel(task.last_error, 'error'); statusLabel = getStatusLabel(task.last_error, 'error');
}else if (!task.processing_node && !imported){ }else if (!task.processing_node && !imported){
statusLabel = getStatusLabel("Set a processing node"); statusLabel = getStatusLabel(_("Set a processing node"));
statusIcon = "fa fa-hourglass-3"; statusIcon = "fa fa-hourglass-3";
showEditLink = true; showEditLink = true;
}else if (task.partial && !task.pending_action){ }else if (task.partial && !task.pending_action){
statusIcon = "fa fa-hourglass-3"; statusIcon = "fa fa-hourglass-3";
statusLabel = getStatusLabel("Waiting for image upload..."); statusLabel = getStatusLabel(_("Waiting for image upload..."));
}else{ }else{
let progress = 100; let progress = 100;
let type = 'done'; let type = 'done';

Wyświetl plik

@ -15,7 +15,8 @@ class Trans extends React.Component {
if (!this.props.children) return (<span/>); if (!this.props.children) return (<span/>);
let content = ""; let content = "";
console.log(this.props.children);
console.log(interpolate(this.props.children, this.props.params));
if (typeof this.props.children === "string"){ if (typeof this.props.children === "string"){
content = (<span dangerouslySetInnerHTML={{__html: interpolate(this.props.children, this.props.params)}}></span>); content = (<span dangerouslySetInnerHTML={{__html: interpolate(this.props.children, this.props.params)}}></span>);
}else{ }else{
@ -31,7 +32,7 @@ class Trans extends React.Component {
i++; i++;
}); });
} }
console.log(content);
return content; return content;
} }
} }

Wyświetl plik

@ -33,8 +33,8 @@
<ul> <ul>
<li>{% trans 'You need at least 5 images' %}</li> <li>{% trans 'You need at least 5 images' %}</li>
<li>{% trans 'Images must overlap by 65% or more' %}</li> <li>{% trans 'Images must overlap by 65% or more' %}</li>
<li>{% trans 'For great 3D, images must overlap by 83%' %}</li> <li>{% trans 'For great 3D, images must overlap by 83%' %}</li>
<li>{% trans 'A <a href="https://github.com/OpenDroneMap/OpenDroneMap/wiki/Running-OpenDroneMap#running-odm-with-ground-control" target="_blank">GCP file</a> is optional, but can increase georeferencing accuracy' %}</li> <li>{% blocktrans with link_start='<a href="https://github.com/OpenDroneMap/OpenDroneMap/wiki/Running-OpenDroneMap#running-odm-with-ground-control" target="_blank">' link_end='</a>' %}A {{link_start}}GCP File{{link_end}} is optional, but can increase georeferencing accuracy{% endblocktrans %}</li>
</ul> </ul>
</p> </p>
{% endif %} {% endif %}