Merge pull request #160 from intnick/i18n

i18n Support
This commit is contained in:
Jeremy Kauffman 2017-06-05 11:34:22 -04:00 committed by GitHub
commit 8d359629fb
48 changed files with 420 additions and 377 deletions

View file

@ -48,3 +48,7 @@ to create distributable packages, which is run by calling:
This project has currently only been worked on in Linux and macOS. If you are on Windows, you can This project has currently only been worked on in Linux and macOS. If you are on Windows, you can
checkout out the build steps in [appveyor.yml](https://github.com/lbryio/lbry-app/blob/master/.appveyor.yml) and probably figure out something from there. checkout out the build steps in [appveyor.yml](https://github.com/lbryio/lbry-app/blob/master/.appveyor.yml) and probably figure out something from there.
## Internationalization
If you want to help translating the lbry-app, you can copy the en.json file in /app/locales and modify the values while leaving the keys as their original English strings. An example for this would be: `"Skip": "Überspringen",` Translations should automatically show up in options.

View file

@ -1,12 +1,16 @@
import store from 'store.js'; import store from 'store.js';
import lbry from './lbry.js';
const env = ENV; const env = ENV;
const config = require(`./config/${env}`); const config = require(`./config/${env}`);
const language = lbry.getClientSetting('language') ? lbry.getClientSetting('language') : 'en';
const i18n = require('y18n')({directory: 'app/locales', updateFiles: false, locale: language});
const logs = []; const logs = [];
const app = { const app = {
env: env, env: env,
config: config, config: config,
store: store, store: store,
i18n: i18n,
logs: logs, logs: logs,
log: function(message) { log: function(message) {
console.log(message); console.log(message);
@ -14,5 +18,8 @@ const app = {
} }
} }
window.__ = i18n.__;
window.__n = i18n.__n;
global.app = app; global.app = app;
module.exports = app; module.exports = app;

View file

@ -41,7 +41,7 @@ class SubmitEmailStage extends React.Component {
lbryio.call('user_email', 'new', {email: this.state.email}, 'post').then(() => { lbryio.call('user_email', 'new', {email: this.state.email}, 'post').then(() => {
this.onEmailSaved(this.state.email); this.onEmailSaved(this.state.email);
}, (error) => { }, (error) => {
if (error.xhr && (error.xhr.status == 409 || error.message == "This email is already in use")) { if (error.xhr && (error.xhr.status == 409 || error.message == __("This email is already in use"))) {
this.onEmailSaved(this.state.email); this.onEmailSaved(this.state.email);
return; return;
} else if (this._emailRow) { } else if (this._emailRow) {
@ -55,11 +55,11 @@ class SubmitEmailStage extends React.Component {
return ( return (
<section> <section>
<form onSubmit={(event) => { this.handleSubmit(event) }}> <form onSubmit={(event) => { this.handleSubmit(event) }}>
<FormRow ref={(ref) => { this._emailRow = ref }} type="text" label="Email" placeholder="scrwvwls@lbry.io" <FormRow ref={(ref) => { this._emailRow = ref }} type="text" label={__("Email")} placeholder="scrwvwls@lbry.io"
name="email" value={this.state.email} name="email" value={this.state.email}
onChange={(event) => { this.handleEmailChanged(event) }} /> onChange={(event) => { this.handleEmailChanged(event) }} />
<div className="form-row-submit"> <div className="form-row-submit">
<Link button="primary" label="Next" disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event) }} /> <Link button="primary" label={__("Next")} disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event) }} />
</div> </div>
</form> </form>
</section> </section>
@ -102,7 +102,7 @@ class ConfirmEmailStage extends React.Component {
if (userEmail.is_verified) { if (userEmail.is_verified) {
this.props.setStage("welcome") this.props.setStage("welcome")
} else { } else {
onSubmitError(new Error("Your email is still not verified.")) //shouldn't happen? onSubmitError(new Error(__("Your email is still not verified."))) //shouldn't happen?
} }
}, onSubmitError); }, onSubmitError);
} }
@ -111,14 +111,14 @@ class ConfirmEmailStage extends React.Component {
return ( return (
<section> <section>
<form onSubmit={(event) => { this.handleSubmit(event) }}> <form onSubmit={(event) => { this.handleSubmit(event) }}>
<FormRow label="Verification Code" ref={(ref) => { this._codeRow = ref }} type="text" <FormRow label={__("Verification Code")} ref={(ref) => { this._codeRow = ref }} type="text"
name="code" placeholder="a94bXXXXXXXXXXXXXX" value={this.state.code} onChange={(event) => { this.handleCodeChanged(event) }} name="code" placeholder="a94bXXXXXXXXXXXXXX" value={this.state.code} onChange={(event) => { this.handleCodeChanged(event) }}
helper="A verification code is required to access this version."/> helper={__("A verification code is required to access this version.")}/>
<div className="form-row-submit form-row-submit--with-footer"> <div className="form-row-submit form-row-submit--with-footer">
<Link button="primary" label="Verify" disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event)}} /> <Link button="primary" label={__("Verify")} disabled={this.state.submitting} onClick={(event) => { this.handleSubmit(event)}} />
</div> </div>
<div className="form-field__helper"> <div className="form-field__helper">
No code? <Link onClick={() => { this.props.setStage("nocode")}} label="Click here" />. {__("No code?")} <Link onClick={() => { this.props.setStage("nocode")}} label={__("Click here")} />.
</div> </div>
</form> </form>
</section> </section>
@ -150,26 +150,26 @@ class WelcomeStage extends React.Component {
render() { render() {
return ( return (
!this.state.hasReward ? !this.state.hasReward ?
<Modal type="custom" isOpen={true} contentLabel="Welcome to LBRY" {...this.props}> <Modal type="custom" isOpen={true} contentLabel={__("Welcome to LBRY")} {...this.props}>
<section> <section>
<h3 className="modal__header">Welcome to LBRY.</h3> <h3 className="modal__header">{__("Welcome to LBRY.")}</h3>
<p>Using LBRY is like dating a centaur. Totally normal up top, and <em>way different</em> underneath.</p> <p>{__("Using LBRY is like dating a centaur. Totally normal up top, and way different underneath.")}</p>
<p>Up top, LBRY is similar to popular media sites.</p> <p>{__("Up top, LBRY is similar to popular media sites.")}</p>
<p>Below, LBRY is controlled by users -- you -- via blockchain and decentralization.</p> <p>{__("Below, LBRY is controlled by users -- you -- via blockchain and decentralization.")}</p>
<p>Thank you for making content freedom possible! Here's a nickel, kid.</p> <p>{__("Thank you for making content freedom possible! Here's a nickel, kid.")}</p>
<div style={{textAlign: "center", marginBottom: "12px"}}> <div style={{textAlign: "center", marginBottom: "12px"}}>
<RewardLink type="new_user" button="primary" onRewardClaim={(event) => { this.onRewardClaim(event) }} onRewardFailure={() => this.props.setStage(null)} onConfirmed={() => { this.props.setStage(null) }} /> <RewardLink type="new_user" button="primary" onRewardClaim={(event) => { this.onRewardClaim(event) }} onRewardFailure={() => this.props.setStage(null)} onConfirmed={() => { this.props.setStage(null) }} />
</div> </div>
</section> </section>
</Modal> : </Modal> :
<Modal type="alert" overlayClassName="modal-overlay modal-overlay--clear" isOpen={true} contentLabel="Welcome to LBRY" {...this.props} onConfirmed={() => { this.props.setStage(null) }}> <Modal type="alert" overlayClassName="modal-overlay modal-overlay--clear" isOpen={true} contentLabel={__("Welcome to LBRY")} {...this.props} onConfirmed={() => { this.props.setStage(null) }}>
<section> <section>
<h3 className="modal__header">About Your Reward</h3> <h3 className="modal__header">{__("About Your Reward")}</h3>
<p>You earned a reward of <CreditAmount amount={this.state.rewardAmount} label={false} /> LBRY credits, or <em>LBC</em>.</p> <p>{__("You earned a reward of ")} <CreditAmount amount={this.state.rewardAmount} label={false} /> {__("LBRY credits, or \"LBC\".")}</p>
<p>This reward will show in your Wallet momentarily, probably while you are reading this message.</p> <p>{__("This reward will show in your Wallet momentarily, probably while you are reading this message.")}</p>
<p>LBC is used to compensate creators, to publish, and to have say in how the network works.</p> <p>{__("LBC is used to compensate creators, to publish, and to have say in how the network works.")}</p>
<p>No need to understand it all just yet! Try watching or downloading something next.</p> <p>{__("No need to understand it all just yet! Try watching or downloading something next.")}</p>
<p>Finally, know that LBRY is an early beta and that it earns the name.</p> <p>{__("Finally, know that LBRY is an early beta and that it earns the name.")}</p>
</section> </section>
</Modal> </Modal>
); );
@ -178,16 +178,16 @@ class WelcomeStage extends React.Component {
const ErrorStage = (props) => { const ErrorStage = (props) => {
return <section> return <section>
<p>An error was encountered that we cannot continue from.</p> <p>{__("An error was encountered that we cannot continue from.")}</p>
<p>At least we're earning the name beta.</p> <p>{__("At least we're earning the name beta.")}</p>
{ props.errorText ? <p>Message: {props.errorText}</p> : '' } { props.errorText ? <p>{__("Message:")} {props.errorText}</p> : '' }
<Link button="alt" label="Try Reload" onClick={() => { window.location.reload() } } /> <Link button="alt" label={__("Try Reload")} onClick={() => { window.location.reload() } } />
</section> </section>
} }
const PendingStage = (props) => { const PendingStage = (props) => {
return <section> return <section>
<p>Preparing for first access <span className="busy-indicator"></span></p> <p>{__("Preparing for first access")} <span className="busy-indicator"></span></p>
</section> </section>
} }
@ -230,20 +230,20 @@ class CodeRequiredStage extends React.Component {
return ( return (
<div> <div>
<section className="section-spaced"> <section className="section-spaced">
<p>Access to LBRY is restricted as we build and scale the network.</p> <p>{__("Access to LBRY is restricted as we build and scale the network.")}</p>
<p>There are two ways in:</p> <p>{__("There are two ways in:")}</p>
<h3>Own LBRY Credits</h3> <h3>{__("Own LBRY Credits")}</h3>
<p>If you own at least 1 LBC, you can get in right now.</p> <p>{__("If you own at least 1 LBC, you can get in right now.")}</p>
<p style={{ textAlign: "center"}}><Link onClick={() => { setLocal('auth_bypassed', true); this.props.setStage(null); }} <p style={{ textAlign: "center"}}><Link onClick={() => { setLocal('auth_bypassed', true); this.props.setStage(null); }}
disabled={disabled} label="Let Me In" button={ disabled ? "alt" : "primary" } /></p> disabled={disabled} label={__("Let Me In")} button={ disabled ? "alt" : "primary" } /></p>
<p>Your balance is <CreditAmount amount={this.state.balance} />. To increase your balance, send credits to this address:</p> <p>{__("Your balance is ")}<CreditAmount amount={this.state.balance} />. {__("To increase your balance, send credits to this address:")}</p>
<p><Address address={ this.state.address ? this.state.address : "Generating Address..." } /></p> <p><Address address={ this.state.address ? this.state.address : __("Generating Address...") } /></p>
<p>If you don't understand how to send credits, then...</p> <p>{__("If you don't understand how to send credits, then...")}</p>
</section> </section>
<section> <section>
<h3>Wait For A Code</h3> <h3>{__("Wait For A Code")}</h3>
<p>If you provide your email, you'll automatically receive a notification when the system is open.</p> <p>{__("If you provide your email, you'll automatically receive a notification when the system is open.")}</p>
<p><Link onClick={() => { this.props.setStage("email"); }} label="Return" /></p> <p><Link onClick={() => { this.props.setStage("email"); }} label={__("Return")} /></p>
</section> </section>
</div> </div>
); );
@ -312,13 +312,13 @@ export class AuthOverlay extends React.Component {
const StageContent = this._stages[this.state.stage]; const StageContent = this._stages[this.state.stage];
if (!StageContent) { if (!StageContent) {
return <span className="empty">Unknown authentication step.</span> return <span className="empty">{__("Unknown authentication step.")}</span>
} }
return ( return (
this.state.stage != "welcome" ? this.state.stage != "welcome" ?
<ModalPage className="modal-page--full" isOpen={true} contentLabel="Authentication"> <ModalPage className="modal-page--full" isOpen={true} contentLabel={__("Authentication")}>
<h1>LBRY Early Access</h1> <h1>{__("LBRY Early Access")}</h1>
<StageContent {...this.state.stageProps} setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} /> <StageContent {...this.state.stageProps} setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} />
</ModalPage> : </ModalPage> :
<StageContent setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} {...this.state.stageProps} /> <StageContent setStage={(stage, stageProps) => { this.setStage(stage, stageProps) }} {...this.state.stageProps} />

View file

@ -68,9 +68,9 @@ export class CreditAmount extends React.Component {
const formattedAmount = lbry.formatCredits(this.props.amount, this.props.precision); const formattedAmount = lbry.formatCredits(this.props.amount, this.props.precision);
let amountText; let amountText;
if (this.props.showFree && parseFloat(formattedAmount) == 0) { if (this.props.showFree && parseFloat(formattedAmount) == 0) {
amountText = 'free'; amountText = __('free');
} else if (this.props.label) { } else if (this.props.label) {
amountText = formattedAmount + (parseFloat(formattedAmount) == 1 ? ' credit' : ' credits'); amountText = formattedAmount + ' ' + (parseFloat(formattedAmount) == 1 ? __('credit') : __('credits'));
} else { } else {
amountText = formattedAmount; amountText = formattedAmount;
} }
@ -80,7 +80,7 @@ export class CreditAmount extends React.Component {
<span> <span>
{amountText} {amountText}
</span> </span>
{ this.props.isEstimate ? <span className="credit-amount__estimate" title="This is an estimate and does not include data fees">*</span> : null } { this.props.isEstimate ? <span className="credit-amount__estimate" title={__("This is an estimate and does not include data fees")}>*</span> : null }
</span> </span>
); );
} }

View file

@ -15,22 +15,22 @@ class DownloadingModal extends React.Component {
} = this.props } = this.props
return ( return (
<Modal isOpen={true} contentLabel="Downloading Update" type="custom"> <Modal isOpen={true} contentLabel={__("Downloading Update")} type="custom">
Downloading Update{downloadProgress ? `: ${downloadProgress}%` : null} {__("Downloading Update")}{downloadProgress ? `: ${downloadProgress}%` : null}
<Line percent={downloadProgress ? downloadProgress : 0} strokeWidth="4"/> <Line percent={downloadProgress ? downloadProgress : 0} strokeWidth="4"/>
{downloadComplete ? ( {downloadComplete ? (
<div> <div>
<br /> <br />
<p>Click "Begin Upgrade" to start the upgrade process.</p> <p>{__("Click \"Begin Upgrade\" to start the upgrade process.")}</p>
<p>The app will close, and you will be prompted to install the latest version of LBRY.</p> <p>{__("The app will close, and you will be prompted to install the latest version of LBRY.")}</p>
<p>After the install is complete, please reopen the app.</p> <p>{__("After the install is complete, please reopen the app.")}</p>
</div> </div>
) : null } ) : null }
<div className="modal__buttons"> <div className="modal__buttons">
{downloadComplete {downloadComplete
? <Link button="primary" label="Begin Upgrade" className="modal__button" onClick={startUpgrade} /> ? <Link button="primary" label={__("Begin Upgrade")} className="modal__button" onClick={startUpgrade} />
: null} : null}
<Link button="alt" label="Cancel" className="modal__button" onClick={cancelUpgrade} /> <Link button="alt" label={__("Cancel")} className="modal__button" onClick={cancelUpgrade} />
</div> </div>
</Modal> </Modal>
) )

View file

@ -15,12 +15,12 @@ class ErrorModal extends React.Component {
const errorObj = typeof error === "string" ? { error: error } : error const errorObj = typeof error === "string" ? { error: error } : error
const error_key_labels = { const error_key_labels = {
connectionString: 'API connection string', connectionString: __('API connection string'),
method: 'Method', method: __('Method'),
params: 'Parameters', params: __('Parameters'),
code: 'Error code', code: __('Error code'),
message: 'Error message', message: __('Error message'),
data: 'Error data', data: __('Error data'),
} }
@ -35,16 +35,16 @@ class ErrorModal extends React.Component {
return( return(
<ExpandableModal <ExpandableModal
isOpen={modal == 'error'} isOpen={modal == 'error'}
contentLabel="Error" className="error-modal" contentLabel={__("Error")} className="error-modal"
overlayClassName="error-modal-overlay" overlayClassName="error-modal-overlay"
onConfirmed={closeModal} onConfirmed={closeModal}
extraContent={errorInfo} extraContent={errorInfo}
> >
<h3 className="modal__header">Error</h3> <h3 className="modal__header">{__("Error")}</h3>
<div className="error-modal__content"> <div className="error-modal__content">
<div><img className="error-modal__warning-symbol" src={lbry.imagePath('warning.png')} /></div> <div><img className="error-modal__warning-symbol" src={lbry.imagePath('warning.png')} /></div>
<p>We're sorry that LBRY has encountered an error. This has been reported and we will investigate the problem.</p> <p>{__("We're sorry that LBRY has encountered an error. This has been reported and we will investigate the problem.")}</p>
</div> </div>
</ExpandableModal> </ExpandableModal>
) )

View file

@ -41,14 +41,14 @@ class FileSelector extends React.Component {
<div className="file-selector"> <div className="file-selector">
<button type="button" className="file-selector__choose-button" onClick={() => this.handleButtonClick()}> <button type="button" className="file-selector__choose-button" onClick={() => this.handleButtonClick()}>
{this.props.type == 'file' ? {this.props.type == 'file' ?
'Choose File' : __('Choose File') :
'Choose Directory'} __('Choose Directory')}
</button> </button>
{' '} {' '}
<span className="file-selector__path"> <span className="file-selector__path">
{this.state.path ? {this.state.path ?
this.state.path : this.state.path :
'No File Chosen'} __('No File Chosen')}
</span> </span>
</div> </div>
); );

View file

@ -68,7 +68,7 @@ class FileActions extends React.Component {
const deleteChecked = this.state.deleteChecked, const deleteChecked = this.state.deleteChecked,
metadata = fileInfo ? fileInfo.metadata : null, metadata = fileInfo ? fileInfo.metadata : null,
openInFolderMessage = platform.startsWith('Mac') ? 'Open in Finder' : 'Open in Folder', openInFolderMessage = platform.startsWith('Mac') ? __('Open in Finder') : __('Open in Folder'),
showMenu = fileInfo && Object.keys(fileInfo).length > 0, showMenu = fileInfo && Object.keys(fileInfo).length > 0,
title = metadata ? metadata.title : uri; title = metadata ? metadata.title : uri;
@ -78,7 +78,7 @@ class FileActions extends React.Component {
const const
progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0, progress = (fileInfo && fileInfo.written_bytes) ? fileInfo.written_bytes / fileInfo.total_bytes * 100 : 0,
label = fileInfo ? progress.toFixed(0) + '% complete' : 'Connecting...', label = fileInfo ? progress.toFixed(0) + __('% complete') : __('Connecting...'),
labelWithIcon = <span className="button__content"><Icon icon="icon-download" /><span>{label}</span></span>; labelWithIcon = <span className="button__content"><Icon icon="icon-download" /><span>{label}</span></span>;
content = <div className="faux-button-block file-actions__download-status-bar button-set-item"> content = <div className="faux-button-block file-actions__download-status-bar button-set-item">
@ -88,27 +88,27 @@ class FileActions extends React.Component {
} else if (!fileInfo && isAvailable === undefined) { } else if (!fileInfo && isAvailable === undefined) {
content = <BusyMessage message="Checking availability" /> content = <BusyMessage message={__("Checking availability")} />
} else if (!fileInfo && !isAvailable && !this.state.forceShowActions) { } else if (!fileInfo && !isAvailable && !this.state.forceShowActions) {
content = <div> content = <div>
<div className="button-set-item empty">Content unavailable.</div> <div className="button-set-item empty">{__("Content unavailable.")}</div>
<ToolTip label="Why?" <ToolTip label={__("Why?")}
body="The content on LBRY is hosted by its users. It appears there are no users connected that have this file at the moment." body={__("The content on LBRY is hosted by its users. It appears there are no users connected that have this file at the moment.")}
className="button-set-item" /> className="button-set-item" />
<Link label="Try Anyway" onClick={this.onShowFileActionsRowClicked.bind(this)} className="button-text button-set-item" /> <Link label={__("Try Anyway")} onClick={this.onShowFileActionsRowClicked.bind(this)} className="button-text button-set-item" />
</div> </div>
} else if (fileInfo === null && !downloading) { } else if (fileInfo === null && !downloading) {
if (!costInfo) { if (!costInfo) {
content = <BusyMessage message="Fetching cost info" /> content = <BusyMessage message={__("Fetching cost info")} />
} else { } else {
content = <Link button="text" label="Download" icon="icon-download" onClick={() => { startDownload(uri) } } />; content = <Link button="text" label={__("Download")} icon="icon-download" onClick={() => { startDownload(uri) } } />;
} }
} else if (fileInfo && fileInfo.download_path) { } else if (fileInfo && fileInfo.download_path) {
content = <Link label="Open" button="text" icon="icon-folder-open" onClick={() => openInShell(fileInfo)} />; content = <Link label={__("Open")} button="text" icon="icon-folder-open" onClick={() => openInShell(fileInfo)} />;
} else { } else {
console.log('handle this case of file action props?'); console.log('handle this case of file action props?');
} }
@ -119,29 +119,29 @@ class FileActions extends React.Component {
{ showMenu ? { showMenu ?
<DropDownMenu> <DropDownMenu>
<DropDownMenuItem key={0} onClick={() => openInFolder(fileInfo)} label={openInFolderMessage} /> <DropDownMenuItem key={0} onClick={() => openInFolder(fileInfo)} label={openInFolderMessage} />
<DropDownMenuItem key={1} onClick={() => openModal('confirmRemove')} label="Remove..." /> <DropDownMenuItem key={1} onClick={() => openModal('confirmRemove')} label={__("Remove...")} />
</DropDownMenu> : '' } </DropDownMenu> : '' }
<Modal type="confirm" isOpen={modal == 'affirmPurchase'} <Modal type="confirm" isOpen={modal == 'affirmPurchase'}
contentLabel="Confirm Purchase" onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={closeModal}> contentLabel={__("Confirm Purchase")} onConfirmed={this.onAffirmPurchase.bind(this)} onAborted={closeModal}>
This will purchase <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits. {__("This will purchase")} <strong>{title}</strong> {__("for")} <strong><FilePrice uri={uri} look="plain" /></strong> {__("credits")}.
</Modal> </Modal>
<Modal isOpen={modal == 'notEnoughCredits'} contentLabel="Not enough credits" <Modal isOpen={modal == 'notEnoughCredits'} contentLabel={__("Not enough credits")}
onConfirmed={closeModal}> onConfirmed={closeModal}>
You don't have enough LBRY credits to pay for this stream. {__("You don't have enough LBRY credits to pay for this stream.")}
</Modal> </Modal>
<Modal isOpen={modal == 'timedOut'} contentLabel="Download failed" <Modal isOpen={modal == 'timedOut'} contentLabel={__("Download failed")}
onConfirmed={closeModal}> onConfirmed={closeModal}>
LBRY was unable to download the stream <strong>{uri}</strong>. {__("LBRY was unable to download the stream")} <strong>{uri}</strong>.
</Modal> </Modal>
<Modal isOpen={modal == 'confirmRemove'} <Modal isOpen={modal == 'confirmRemove'}
contentLabel="Not enough credits" contentLabel={__("Not enough credits")}
type="confirm" type="confirm"
confirmButtonLabel="Remove" confirmButtonLabel={__("Remove")}
onConfirmed={() => deleteFile(fileInfo.outpoint, deleteChecked)} onConfirmed={() => deleteFile(fileInfo.outpoint, deleteChecked)}
onAborted={closeModal}> onAborted={closeModal}>
<p>Are you sure you'd like to remove <cite>{title}</cite> from LBRY?</p> <p>{__("Are you sure you'd like to remove")} <cite>{title}</cite> {__("from LBRY?")}</p>
<label><FormField type="checkbox" checked={deleteChecked} onClick={this.handleDeleteCheckboxClicked.bind(this)} /> Delete this file from my computer</label> <label><FormField type="checkbox" checked={deleteChecked} onClick={this.handleDeleteCheckboxClicked.bind(this)} /> {__("Delete this file from my computer")}</label>
</Modal> </Modal>
</section> </section>
); );

View file

@ -68,11 +68,11 @@ class FileCard extends React.Component {
let description = "" let description = ""
if (isResolvingUri) { if (isResolvingUri) {
description = "Loading..." description = __("Loading...")
} else if (metadata && metadata.description) { } else if (metadata && metadata.description) {
description = metadata.description description = metadata.description
} else if (claim === null) { } else if (claim === null) {
description = 'This address contains no content.' description = __("This address contains no content.")
} }
return ( return (
@ -99,8 +99,7 @@ class FileCard extends React.Component {
{obscureNsfw && this.state.hovered {obscureNsfw && this.state.hovered
? <div className='card-overlay'> ? <div className='card-overlay'>
<p> <p>
This content is Not Safe For Work. {__("This content is Not Safe For Work. To view adult content, please change your")} <Link className="button-text" onClick={() => navigate('settings')} label={__("Settings")} />.
To view adult content, please change your <Link className="button-text" onClick={() => navigate('settings')} label="Settings" />.
</p> </p>
</div> </div>
: null} : null}

View file

@ -77,11 +77,11 @@ class FileList extends React.Component {
<section className="file-list__header"> <section className="file-list__header">
{ fetching && <span className="busy-indicator"/> } { fetching && <span className="busy-indicator"/> }
<span className='sort-section'> <span className='sort-section'>
Sort by { ' ' } {__("Sort by")} { ' ' }
<FormField type="select" onChange={this.handleSortChanged.bind(this)}> <FormField type="select" onChange={this.handleSortChanged.bind(this)}>
<option value="date">Date</option> <option value="date">{__("Date")}</option>
<option value="title">Title</option> <option value="title">{__("Title")}</option>
<option value="filename">File name</option> <option value="filename">{__("File name")}</option>
</FormField> </FormField>
</span> </span>
{content} {content}

View file

@ -16,8 +16,8 @@ const SearchNoResults = (props) => {
return <section> return <section>
<span className="empty"> <span className="empty">
No one has checked anything in for {query} yet. { ' ' } {__("No one has checked anything in for %s yet."), query} { ' ' }
<Link label="Be the first" onClick={() => navigate('/publish')} /> <Link label={__("Be the first")} onClick={() => navigate('/publish')} />
</span> </span>
</section>; </section>;
} }
@ -60,10 +60,10 @@ class FileListSearch extends React.Component{
return ( return (
<div> <div>
{isSearching && !results && {isSearching && !results &&
<BusyMessage message="Looking up the Dewey Decimals" />} <BusyMessage message={__("Looking up the Dewey Decimals")} />}
{isSearching && results && {isSearching && results &&
<BusyMessage message="Refreshing the Dewey Decimals" />} <BusyMessage message={__("Refreshing the Dewey Decimals")} />}
{(results && !!results.length) ? {(results && !!results.length) ?
<FileListSearchResults {...this.props} /> : <FileListSearchResults {...this.props} /> :

View file

@ -68,15 +68,15 @@ class FileTile extends React.Component {
if (isClaimed) { if (isClaimed) {
description = metadata && metadata.description description = metadata && metadata.description
} else if (isResolvingUri) { } else if (isResolvingUri) {
description = "Loading..." description = __("Loading...")
} else if (showEmpty === FileTile.SHOW_EMPTY_PUBLISH) { } else if (showEmpty === FileTile.SHOW_EMPTY_PUBLISH) {
onClick = () => navigate('/publish', { }) onClick = () => navigate('/publish', { })
description = <span className="empty"> description = <span className="empty">
This location is unused. { ' ' } {__("This location is unused.")} { ' ' }
{ isClaimable && <span className="button-text">Put something here!</span> } { isClaimable && <span className="button-text">{__("Put something here!")}</span> }
</span> </span>
} else if (showEmpty === FileTile.SHOW_EMPTY_PENDING) { } else if (showEmpty === FileTile.SHOW_EMPTY_PENDING) {
description = <span className="empty">This file is pending confirmation.</span> description = <span className="empty">{__("This file is pending confirmation.")}</span>
} }
return ( return (
@ -103,8 +103,7 @@ class FileTile extends React.Component {
{this.state.showNsfwHelp {this.state.showNsfwHelp
? <div className='card-overlay'> ? <div className='card-overlay'>
<p> <p>
This content is Not Safe For Work. {__("This content is Not Safe For Work. To view adult content, please change your")} <Link className="button-text" onClick={() => navigate('/settings')} label={__("Settings")} />.
To view adult content, please change your <Link className="button-text" onClick={() => navigate('/settings')} label="Settings" />.
</p> </p>
</div> </div>
: null} : null}

View file

@ -21,7 +21,7 @@ export class FormField extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this._fieldRequiredText = 'This field is required'; this._fieldRequiredText = __('This field is required');
this._type = null; this._type = null;
this._element = null; this._element = null;
@ -136,7 +136,7 @@ export class FormRow extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this._fieldRequiredText = 'This field is required'; this._fieldRequiredText = __('This field is required');
this.state = { this.state = {
isError: false, isError: false,

View file

@ -13,7 +13,8 @@ import {
import Header from './view' import Header from './view'
const select = (state) => ({ const select = (state) => ({
balance: lbry.formatCredits(selectBalance(state), 1) balance: lbry.formatCredits(selectBalance(state), 1),
publish: __("Publish"),
}) })
const perform = (dispatch) => ({ const perform = (dispatch) => ({

View file

@ -6,7 +6,8 @@ export const Header = (props) => {
const { const {
balance, balance,
back, back,
navigate navigate,
publish,
} = props } = props
return <header id="header"> return <header id="header">
@ -17,13 +18,13 @@ export const Header = (props) => {
<Link onClick={() => navigate('/discover')} button="alt button--flat" icon="icon-home" /> <Link onClick={() => navigate('/discover')} button="alt button--flat" icon="icon-home" />
</div> </div>
<div className="header__item header__item--wunderbar"> <div className="header__item header__item--wunderbar">
<WunderBar/> <WunderBar />
</div> </div>
<div className="header__item"> <div className="header__item">
<Link onClick={() => navigate('/wallet')} button="text" icon="icon-bank" label={balance} ></Link> <Link onClick={() => navigate('/wallet')} button="text" icon="icon-bank" label={balance} ></Link>
</div> </div>
<div className="header__item"> <div className="header__item">
<Link onClick={() => navigate('/publish')} button="primary button--flat" icon="icon-upload" label="Publish" /> <Link onClick={() => navigate('/publish')} button="primary button--flat" icon="icon-upload" label={publish} />
</div> </div>
<div className="header__item"> <div className="header__item">
<Link onClick={() => navigate('/downloaded')} button="alt button--flat" icon="icon-folder" /> <Link onClick={() => navigate('/downloaded')} button="alt button--flat" icon="icon-folder" />

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import ReactModal from 'react-modal'; import ReactModal from 'react-modal';
import Link from 'component/link'; import Link from 'component/link';
import app from '../app.js'
export class Modal extends React.Component { export class Modal extends React.Component {
static propTypes = { static propTypes = {
@ -18,8 +18,8 @@ export class Modal extends React.Component {
static defaultProps = { static defaultProps = {
type: 'alert', type: 'alert',
overlay: true, overlay: true,
confirmButtonLabel: 'OK', confirmButtonLabel: app.i18n.__('OK'),
abortButtonLabel: 'Cancel', abortButtonLabel: app.i18n.__('Cancel'),
confirmButtonDisabled: false, confirmButtonDisabled: false,
abortButtonDisabled: false, abortButtonDisabled: false,
} }
@ -52,9 +52,9 @@ export class ExpandableModal extends React.Component {
} }
static defaultProps = { static defaultProps = {
confirmButtonLabel: 'OK', confirmButtonLabel: app.i18n.__('OK'),
expandButtonLabel: 'Show More...', expandButtonLabel: app.i18n.__('Show More...'),
hideButtonLabel: 'Show Less', hideButtonLabel: app.i18n.__('Show Less'),
} }
constructor(props) { constructor(props) {

View file

@ -77,11 +77,11 @@ export class RewardLink extends React.Component {
return ( return (
<div className="reward-link"> <div className="reward-link">
{this.props.claimed {this.props.claimed
? <span><Icon icon="icon-check" /> Reward claimed.</span> ? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
: <Link button={this.props.button ? this.props.button : 'alt'} disabled={this.state.pending || !this.state.claimable } : <Link button={this.props.button ? this.props.button : 'alt'} disabled={this.state.pending || !this.state.claimable }
label={ this.state.pending ? "Claiming..." : "Claim Reward"} onClick={() => { this.claimReward() }} />} label={ this.state.pending ? __("Claiming...") : __("Claim Reward")} onClick={() => { this.claimReward() }} />}
{this.state.errorMessage ? {this.state.errorMessage ?
<Modal isOpen={true} contentLabel="Reward Claim Error" className="error-modal" onConfirmed={() => { this.clearError() }}> <Modal isOpen={true} contentLabel={__("Reward Claim Error")} className="error-modal" onConfirmed={() => { this.clearError() }}>
{this.state.errorMessage} {this.state.errorMessage}
</Modal> </Modal>
: ''} : ''}

View file

@ -12,8 +12,8 @@ export class SplashScreen extends React.Component {
super(props); super(props);
this.state = { this.state = {
details: 'Starting daemon', details: __('Starting daemon'),
message: "Connecting", message: __("Connecting"),
isLagging: false, isLagging: false,
}; };
} }
@ -30,8 +30,8 @@ export class SplashScreen extends React.Component {
// TODO: This is a hack, and the logic should live in the daemon // TODO: This is a hack, and the logic should live in the daemon
// to give us a better sense of when we are actually started // to give us a better sense of when we are actually started
this.setState({ this.setState({
message: "Testing Network", message: __("Testing Network"),
details: "Waiting for name resolution", details: __("Waiting for name resolution"),
isLagging: false isLagging: false
}); });
@ -55,8 +55,8 @@ export class SplashScreen extends React.Component {
.catch(() => { .catch(() => {
this.setState({ this.setState({
isLagging: true, isLagging: true,
message: "Connection Failure", message: __("Connection Failure"),
details: "Try closing all LBRY processes and starting again. If this still happpens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.io if you think this is a software bug." details: __("Try closing all LBRY processes and starting again. If this still happpens, your anti-virus software or firewall may be preventing LBRY from connecting. Contact hello@lbry.io if you think this is a software bug.")
}) })
}) })
} }

View file

@ -22,8 +22,8 @@ class TransactionList extends React.Component{
rows.push( rows.push(
<tr key={item.id}> <tr key={item.id}>
<td>{ (item.amount > 0 ? '+' : '' ) + item.amount }</td> <td>{ (item.amount > 0 ? '+' : '' ) + item.amount }</td>
<td>{ item.date ? item.date.toLocaleDateString() : <span className="empty">(Transaction pending)</span> }</td> <td>{ item.date ? item.date.toLocaleDateString() : <span className="empty">{__("(Transaction pending)")}</span> }</td>
<td>{ item.date ? item.date.toLocaleTimeString() : <span className="empty">(Transaction pending)</span> }</td> <td>{ item.date ? item.date.toLocaleTimeString() : <span className="empty">{__("(Transaction pending)")}</span> }</td>
<td> <td>
<a className="button-text" href={"https://explorer.lbry.io/#!/transaction?id="+item.id}>{item.id.substr(0, 7)}</a> <a className="button-text" href={"https://explorer.lbry.io/#!/transaction?id="+item.id}>{item.id.substr(0, 7)}</a>
</td> </td>
@ -35,19 +35,19 @@ class TransactionList extends React.Component{
return ( return (
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h3>Transaction History</h3> <h3>{__("Transaction History")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
{ fetchingTransactions && <BusyMessage message="Loading transactions" /> } { fetchingTransactions && <BusyMessage message={__("Loading transactions")} /> }
{ !fetchingTransactions && rows.length === 0 ? <div className="empty">You have no transactions.</div> : '' } { !fetchingTransactions && rows.length === 0 ? <div className="empty">{__("You have no transactions.")}</div> : '' }
{ rows.length > 0 ? { rows.length > 0 ?
<table className="table-standard table-stretch"> <table className="table-standard table-stretch">
<thead> <thead>
<tr> <tr>
<th>Amount</th> <th>{__("Amount")}</th>
<th>Date</th> <th>{__("Date")}</th>
<th>Time</th> <th>{__("Time")}</th>
<th>Transaction</th> <th>{__("Transaction")}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

View file

@ -17,13 +17,13 @@ class UpgradeModal extends React.Component {
return ( return (
<Modal <Modal
isOpen={true} isOpen={true}
contentLabel="Update available" contentLabel={__("Update available")}
type="confirm" type="confirm"
confirmButtonLabel="Upgrade" confirmButtonLabel={__("Upgrade")}
abortButtonLabel="Skip" abortButtonLabel={__("Skip")}
onConfirmed={downloadUpgrade} onConfirmed={downloadUpgrade}
onAborted={skipUpgrade}> onAborted={skipUpgrade}>
Your version of LBRY is out of date and may be unreliable or insecure. {__("Your version of LBRY is out of date and may be unreliable or insecure.")}
</Modal> </Modal>
) )
} }

View file

@ -58,20 +58,20 @@ class VideoPlayButton extends React.Component {
className="video__play-button" className="video__play-button"
icon={icon} icon={icon}
onClick={this.onWatchClick.bind(this)} /> onClick={this.onWatchClick.bind(this)} />
<Modal contentLabel="Not enough credits" isOpen={modal == 'notEnoughCredits'} onConfirmed={closeModal}> <Modal contentLabel={__("Not enough credits")} isOpen={modal == 'notEnoughCredits'} onConfirmed={closeModal}>
You don't have enough LBRY credits to pay for this stream. {__("You don't have enough LBRY credits to pay for this stream.")}
</Modal> </Modal>
<Modal <Modal
type="confirm" type="confirm"
isOpen={modal == 'affirmPurchaseAndPlay'} isOpen={modal == 'affirmPurchaseAndPlay'}
contentLabel="Confirm Purchase" contentLabel={__("Confirm Purchase")}
onConfirmed={this.onPurchaseConfirmed.bind(this)} onConfirmed={this.onPurchaseConfirmed.bind(this)}
onAborted={closeModal}> onAborted={closeModal}>
This will purchase <strong>{title}</strong> for <strong><FilePrice uri={uri} look="plain" /></strong> credits. {__("This will purchase")} <strong>{title}</strong> {__("for")} <strong><FilePrice uri={uri} look="plain" /></strong> {__("credits")}.
</Modal> </Modal>
<Modal <Modal
isOpen={modal == 'timedOut'} onConfirmed={closeModal} contentLabel="Timed Out"> isOpen={modal == 'timedOut'} onConfirmed={closeModal} contentLabel={__("Timed Out")}>
Sorry, your download timed out :( {__("Sorry, your download timed out :(")}
</Modal> </Modal>
</div>); </div>);
} }
@ -107,11 +107,11 @@ class Video extends React.Component {
let loadStatusMessage = '' let loadStatusMessage = ''
if(fileInfo && fileInfo.completed && !fileInfo.written_bytes) { if(fileInfo && fileInfo.completed && !fileInfo.written_bytes) {
loadStatusMessage = "It looks like you deleted or moved this file. We're rebuilding it now. It will only take a few seconds." loadStatusMessage = __("It looks like you deleted or moved this file. We're rebuilding it now. It will only take a few seconds.")
} else if (isLoading) { } else if (isLoading) {
loadStatusMessage = "Requesting stream... it may sit here for like 15-20 seconds in a really awkward way... we're working on it" loadStatusMessage = __("Requesting stream... it may sit here for like 15-20 seconds in a really awkward way... we're working on it")
} else if (isDownloading) { } else if (isDownloading) {
loadStatusMessage = "Downloading stream... not long left now!" loadStatusMessage = __("Downloading stream... not long left now!")
} }
let klassName = "" let klassName = ""
@ -128,7 +128,7 @@ class Video extends React.Component {
<div className={klassName}>{ <div className={klassName}>{
isPlaying ? isPlaying ?
(!isReadyToPlay ? (!isReadyToPlay ?
<span>this is the world's worst loading screen and we shipped our software with it anyway... <br /><br />{loadStatusMessage}</span> : <span>{__("this is the world's worst loading screen and we shipped our software with it anyway...")} <br /><br />{loadStatusMessage}</span> :
<VideoPlayer filename={fileInfo.file_name} poster={poster} downloadPath={fileInfo.download_path} mediaType={mediaType} poster={poster} />) : <VideoPlayer filename={fileInfo.file_name} poster={poster} downloadPath={fileInfo.download_path} mediaType={mediaType} poster={poster} />) :
<div className="video__cover" style={{backgroundImage: 'url("' + metadata.thumbnail + '")'}}> <div className="video__cover" style={{backgroundImage: 'url("' + metadata.thumbnail + '")'}}>
<VideoPlayButton startPlaying={this.startPlaying.bind(this)} {...this.props} mediaType={mediaType} /> <VideoPlayButton startPlaying={this.startPlaying.bind(this)} {...this.props} mediaType={mediaType} />

View file

@ -19,18 +19,18 @@ class WalletAddress extends React.Component {
return ( return (
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h3>Wallet Address</h3> <h3>{__("Wallet Address")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<Address address={receiveAddress} /> <Address address={receiveAddress} />
</div> </div>
<div className="card__actions"> <div className="card__actions">
<Link label="Get New Address" button="primary" icon='icon-refresh' onClick={getNewAddress} disabled={gettingNewAddress} /> <Link label={__("Get New Address")} button="primary" icon='icon-refresh' onClick={getNewAddress} disabled={gettingNewAddress} />
</div> </div>
<div className="card__content"> <div className="card__content">
<div className="help"> <div className="help">
<p>Other LBRY users may send credits to you by entering this address on the "Send" page.</p> <p>{__("Other LBRY users may send credits to you by entering this address on the \"Send\" page.")}</p>
<p>You can generate a new address at any time, and any previous addresses will continue to work. Using multiple addresses can be helpful for keeping track of incoming payments from multiple sources.</p> <p>{__("You can generate a new address at any time, and any previous addresses will continue to work. Using multiple addresses can be helpful for keeping track of incoming payments from multiple sources.")}</p>
</div> </div>
</div> </div>
</section> </section>

View file

@ -20,27 +20,27 @@ const WalletSend = (props) => {
<section className="card"> <section className="card">
<form onSubmit={sendToAddress}> <form onSubmit={sendToAddress}>
<div className="card__title-primary"> <div className="card__title-primary">
<h3>Send Credits</h3> <h3>{__("Send Credits")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow label="Amount" postfix="LBC" step="0.01" type="number" placeholder="1.23" size="10" onChange={setAmount} value={amount} /> <FormRow label={__("Amount")} postfix="LBC" step="0.01" type="number" placeholder="1.23" size="10" onChange={setAmount} value={amount} />
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow label="Recipient Address" placeholder="bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs" type="text" size="60" onChange={setAddress} value={address} /> <FormRow label={__("Recipient Address")} placeholder="bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs" type="text" size="60" onChange={setAddress} value={address} />
</div> </div>
<div className="card__actions card__actions--form-submit"> <div className="card__actions card__actions--form-submit">
<Link button="primary" label="Send" onClick={sendToAddress} disabled={!(parseFloat(amount) > 0.0) || !address} /> <Link button="primary" label={_("Send")} onClick={sendToAddress} disabled={!(parseFloat(amount) > 0.0) || !address} />
<input type='submit' className='hidden' /> <input type='submit' className='hidden' />
</div> </div>
</form> </form>
{modal == 'insufficientBalance' && <Modal isOpen={true} contentLabel="Insufficient balance" onConfirmed={closeModal}> {modal == 'insufficientBalance' && <Modal isOpen={true} contentLabel={__("Insufficient balance")} onConfirmed={closeModal}>
Insufficient balance: after this transaction you would have less than 1 LBC in your wallet. {__("Insufficient balance: after this transaction you would have less than 1 LBC in your wallet.")}
</Modal>} </Modal>}
{modal == 'transactionSuccessful' && <Modal isOpen={true} contentLabel="Transaction successful" onConfirmed={closeModal}> {modal == 'transactionSuccessful' && <Modal isOpen={true} contentLabel={__("Transaction successful")} onConfirmed={closeModal}>
Your transaction was successfully placed in the queue. {__("Your transaction was successfully placed in the queue.")}
</Modal>} </Modal>}
{modal == 'transactionFailed' && <Modal isOpen={true} contentLabel="Transaction failed" onConfirmed={closeModal}> {modal == 'transactionFailed' && <Modal isOpen={true} contentLabel={__("Transaction failed")} onConfirmed={closeModal}>
Something went wrong: {__("Something went wrong")}:
</Modal>} </Modal>}
</section> </section>
) )

View file

@ -151,7 +151,7 @@ class WunderBar extends React.PureComponent {
onChange={this.onChange} onChange={this.onChange}
onKeyPress={this.onKeyPress} onKeyPress={this.onKeyPress}
value={this.state.address} value={this.state.address}
placeholder="Find movies, music, games, and more" /> placeholder={__("Find movies, music, games, and more")} />
</div> </div>
); );
} }

View file

@ -11,7 +11,7 @@ jsonrpc.call = function (connectionString, method, params, callback, errorCallba
connectFailedCallback(e); connectFailedCallback(e);
}); });
xhr.addEventListener('timeout', function() { xhr.addEventListener('timeout', function() {
connectFailedCallback(new Error('XMLHttpRequest connection timed out')); connectFailedCallback(new Error(__('XMLHttpRequest connection timed out')));
}) })
} }
xhr.addEventListener('load', function() { xhr.addEventListener('load', function() {
@ -50,7 +50,7 @@ jsonrpc.call = function (connectionString, method, params, callback, errorCallba
method: method, method: method,
params: params, params: params,
code: xhr.status, code: xhr.status,
message: 'Connection to API server failed' message: __('Connection to API server failed')
} }
}); });
document.dispatchEvent(errorEvent); document.dispatchEvent(errorEvent);

View file

@ -18,6 +18,7 @@ let lbry = {
useCustomLighthouseServers: false, useCustomLighthouseServers: false,
customLighthouseServers: [], customLighthouseServers: [],
showDeveloperMenu: false, showDeveloperMenu: false,
language: 'en',
} }
}; };
@ -416,7 +417,7 @@ lbry._resolveXhrs = {}
lbry.resolve = function(params={}) { lbry.resolve = function(params={}) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!params.uri) { if (!params.uri) {
throw "Resolve has hacked cache on top of it that requires a URI" throw __("Resolve has hacked cache on top of it that requires a URI")
} }
if (params.uri && lbry._claimCache[params.uri] !== undefined) { if (params.uri && lbry._claimCache[params.uri] !== undefined) {
resolve(lbry._claimCache[params.uri]); resolve(lbry._claimCache[params.uri]);

View file

@ -34,20 +34,20 @@ lbryio.getExchangeRates = function() {
lbryio.call = function(resource, action, params={}, method='get', evenIfDisabled=false) { // evenIfDisabled is just for development, when we may have some calls working and some not lbryio.call = function(resource, action, params={}, method='get', evenIfDisabled=false) { // evenIfDisabled is just for development, when we may have some calls working and some not
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!lbryio.enabled && !evenIfDisabled && (resource != 'discover' || action != 'list')) { if (!lbryio.enabled && !evenIfDisabled && (resource != 'discover' || action != 'list')) {
console.log("Internal API disabled"); console.log(__("Internal API disabled"));
reject(new Error("LBRY internal API is disabled")) reject(new Error(__("LBRY internal API is disabled")))
return return
} }
const xhr = new XMLHttpRequest; const xhr = new XMLHttpRequest;
xhr.addEventListener('error', function (event) { xhr.addEventListener('error', function (event) {
reject(new Error("Something went wrong making an internal API call.")); reject(new Error(__("Something went wrong making an internal API call.")));
}); });
xhr.addEventListener('timeout', function() { xhr.addEventListener('timeout', function() {
reject(new Error('XMLHttpRequest connection timed out')); reject(new Error(__('XMLHttpRequest connection timed out')));
}); });
xhr.addEventListener('load', function() { xhr.addEventListener('load', function() {
@ -89,7 +89,7 @@ lbryio.call = function(resource, action, params={}, method='get', evenIfDisabled
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(querystring.stringify(fullParams)); xhr.send(querystring.stringify(fullParams));
} else { } else {
reject(new Error("Invalid method")); reject(new Error(__("Invalid method")));
} }
}); });
}; };
@ -139,7 +139,7 @@ lbryio.authenticate = function() {
app_id: installation_id, app_id: installation_id,
}, 'post').then(function(responseData) { }, 'post').then(function(responseData) {
if (!responseData.id) { if (!responseData.id) {
reject(new Error("Received invalid authentication response.")); reject(new Error(__("Received invalid authentication response.")));
} }
lbryio.setAccessToken(installation_id) lbryio.setAccessToken(installation_id)
setCurrentUser() setCurrentUser()

View file

@ -39,12 +39,12 @@ lbryuri.parse = function(uri, requireProto=false) {
// Validate protocol // Validate protocol
if (requireProto && !proto) { if (requireProto && !proto) {
throw new Error('LBRY URIs must include a protocol prefix (lbry://).'); throw new Error(__('LBRY URIs must include a protocol prefix (lbry://).'));
} }
// Validate and process name // Validate and process name
if (!name) { if (!name) {
throw new Error('URI does not include name.'); throw new Error(__('URI does not include name.'));
} }
const isChannel = name.startsWith('@'); const isChannel = name.startsWith('@');
@ -52,11 +52,11 @@ lbryuri.parse = function(uri, requireProto=false) {
if (isChannel) { if (isChannel) {
if (!channelName) { if (!channelName) {
throw new Error('No channel name after @.'); throw new Error(__('No channel name after @.'));
} }
if (channelName.length < CHANNEL_NAME_MIN_LEN) { if (channelName.length < CHANNEL_NAME_MIN_LEN) {
throw new Error(`Channel names must be at least ${CHANNEL_NAME_MIN_LEN} characters.`); throw new Error(__(`Channel names must be at least %s characters.`, CHANNEL_NAME_MIN_LEN));
} }
contentName = path; contentName = path;
@ -64,14 +64,14 @@ lbryuri.parse = function(uri, requireProto=false) {
const nameBadChars = (channelName || name).match(/[^A-Za-z0-9-]/g); const nameBadChars = (channelName || name).match(/[^A-Za-z0-9-]/g);
if (nameBadChars) { if (nameBadChars) {
throw new Error(`Invalid character${nameBadChars.length == 1 ? '' : 's'} in name: ${nameBadChars.join(', ')}.`); throw new Error(__(`Invalid character %s in name: %s.`, nameBadChars.length == 1 ? '' : 's', nameBadChars.join(', ') ));
} }
// Validate and process modifier (claim ID, bid position or claim sequence) // Validate and process modifier (claim ID, bid position or claim sequence)
let claimId, claimSequence, bidPosition; let claimId, claimSequence, bidPosition;
if (modSep) { if (modSep) {
if (!modVal) { if (!modVal) {
throw new Error(`No modifier provided after separator ${modSep}.`); throw new Error(__(`No modifier provided after separator %s.`, modSep));
} }
if (modSep == '#') { if (modSep == '#') {
@ -84,31 +84,31 @@ lbryuri.parse = function(uri, requireProto=false) {
} }
if (claimId && (claimId.length > CLAIM_ID_MAX_LEN || !claimId.match(/^[0-9a-f]+$/))) { if (claimId && (claimId.length > CLAIM_ID_MAX_LEN || !claimId.match(/^[0-9a-f]+$/))) {
throw new Error(`Invalid claim ID ${claimId}.`); throw new Error(__(`Invalid claim ID %s.`, claimId));
} }
if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) { if (claimSequence && !claimSequence.match(/^-?[1-9][0-9]*$/)) {
throw new Error('Claim sequence must be a number.'); throw new Error(__('Claim sequence must be a number.'));
} }
if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) { if (bidPosition && !bidPosition.match(/^-?[1-9][0-9]*$/)) {
throw new Error('Bid position must be a number.'); throw new Error(__('Bid position must be a number.'));
} }
// Validate and process path // Validate and process path
if (path) { if (path) {
if (!isChannel) { if (!isChannel) {
throw new Error('Only channel URIs may have a path.'); throw new Error(__('Only channel URIs may have a path.'));
} }
const pathBadChars = path.match(/[^A-Za-z0-9-]/g); const pathBadChars = path.match(/[^A-Za-z0-9-]/g);
if (pathBadChars) { if (pathBadChars) {
throw new Error(`Invalid character${count == 1 ? '' : 's'} in path: ${nameBadChars.join(', ')}`); throw new Error(__(`Invalid character %s in path: %s`,count == 1 ? '' : 's',nameBadChars.join(', ')));
} }
contentName = path; contentName = path;
} else if (pathSep) { } else if (pathSep) {
throw new Error('No path provided after /'); throw new Error(__('No path provided after /'));
} }
return { return {
@ -135,7 +135,7 @@ lbryuri.build = function(uriObj, includeProto=true, allowExtraProps=false) {
if (!name) { if (!name) {
name = channelNameFormatted; name = channelNameFormatted;
} else if (name !== channelNameFormatted) { } else if (name !== channelNameFormatted) {
throw new Error('Received a channel content URI, but name and channelName do not match. "name" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.'); throw new Error(__('Received a channel content URI, but name and channelName do not match. \"name\" represents the value in the name position of the URI (lbry://name...), which for channel content will be the channel name. In most cases, to construct a channel URI you should just pass channelName and contentName.'));
} }
} }
@ -146,7 +146,7 @@ lbryuri.build = function(uriObj, includeProto=true, allowExtraProps=false) {
path = contentName; path = contentName;
} }
if (path && path !== contentName) { if (path && path !== contentName) {
throw new Error('path and contentName do not match. Only one is required; most likely you wanted contentName.'); throw new Error(__('Path and contentName do not match. Only one is required; most likely you wanted contentName.'));
} }
} }

View file

@ -21,7 +21,7 @@ function getServers() {
function call(method, params, callback, errorCallback) { function call(method, params, callback, errorCallback) {
if (connectTryNum >= maxQueryTries) { if (connectTryNum >= maxQueryTries) {
errorCallback(new Error(`Could not connect to Lighthouse server. Last server attempted: ${server}`)); errorCallback(new Error(__(`Could not connect to Lighthouse server. Last server attempted: %s`, server)));
return; return;
} }

View file

@ -4,11 +4,11 @@ import lbry from './lbry.js';
import lbryio from './lbryio.js'; import lbryio from './lbryio.js';
import lighthouse from './lighthouse.js'; import lighthouse from './lighthouse.js';
import App from 'component/app/index.js'; import App from 'component/app/index.js';
import SplashScreen from 'component/splash.js';
import SnackBar from 'component/snackBar'; import SnackBar from 'component/snackBar';
import {AuthOverlay} from 'component/auth.js';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import store from 'store.js'; import store from 'store.js';
import SplashScreen from 'component/splash.js';
import {AuthOverlay} from 'component/auth.js';
import { import {
doChangePath, doChangePath,
doNavigate, doNavigate,
@ -28,6 +28,7 @@ const {remote, ipcRenderer, shell} = require('electron');
const contextMenu = remote.require('./menu/context-menu'); const contextMenu = remote.require('./menu/context-menu');
const app = require('./app') const app = require('./app')
lbry.showMenuIfNeeded(); lbry.showMenuIfNeeded();
window.addEventListener('contextmenu', (event) => { window.addEventListener('contextmenu', (event) => {

View file

@ -27,11 +27,11 @@ class ChannelPage extends React.Component{
let contentList let contentList
if (claimsInChannel === undefined) { if (claimsInChannel === undefined) {
contentList = <BusyMessage message="Fetching content" /> contentList = <BusyMessage message={__("Fetching content")} />
} else if (claimsInChannel) { } else if (claimsInChannel) {
contentList = claimsInChannel.length ? contentList = claimsInChannel.length ?
claimsInChannel.map((claim) => <FileTile key={claim.claim_id} uri={lbryuri.build({name: claim.name, claimId: claim.claim_id})} />) : claimsInChannel.map((claim) => <FileTile key={claim.claim_id} uri={lbryuri.build({name: claim.name, claimId: claim.claim_id})} />) :
<span className="empty">No content found.</span> <span className="empty">{__("No content found.")}</span>
} }
return <main className="main--single-column"> return <main className="main--single-column">
@ -41,11 +41,11 @@ class ChannelPage extends React.Component{
</div> </div>
<div className="card__content"> <div className="card__content">
<p> <p>
This channel page is a stub. {__("This channel page is a stub.")}
</p> </p>
</div> </div>
</section> </section>
<h3 className="card-row__header">Published Content</h3> <h3 className="card-row__header">{__("Published Content")}</h3>
{contentList} {contentList}
</main> </main>
} }

View file

@ -42,7 +42,7 @@ class DeveloperPage extends React.Component {
handleForceUpgradeClick() { handleForceUpgradeClick() {
let upgradeSent = false; let upgradeSent = false;
if (!this.state.upgradePath) { if (!this.state.upgradePath) {
alert('Please select a file to upgrade from'); alert(__('Please select a file to upgrade from'));
} else { } else {
try { try {
const stats = fs.lstatSync(this.state.upgradePath); const stats = fs.lstatSync(this.state.upgradePath);
@ -63,17 +63,17 @@ class DeveloperPage extends React.Component {
return ( return (
<main> <main>
<section className="card"> <section className="card">
<h3>Developer Settings</h3> <h3>{__("Developer Settings")}</h3>
<div className="form-row"> <div className="form-row">
<label><FormField type="checkbox" onChange={(event) => { this.handleShowDeveloperMenuChange() }} checked={this.state.showDeveloperMenu} /> Show developer menu</label> <label><FormField type="checkbox" onChange={(event) => { this.handleShowDeveloperMenuChange() }} checked={this.state.showDeveloperMenu} /> {__("Show developer menu")}</label>
</div> </div>
<div className="form-row"> <div className="form-row">
<label><FormField type="checkbox" onChange={(event) => { this.handleUseCustomLighthouseServersChange() }} checked={this.state.useCustomLighthouseServers} /> Use custom search servers</label> <label><FormField type="checkbox" onChange={(event) => { this.handleUseCustomLighthouseServersChange() }} checked={this.state.useCustomLighthouseServers} /> {__("Use custom search servers")}</label>
</div> </div>
{this.state.useCustomLighthouseServers {this.state.useCustomLighthouseServers
? <div className="form-row"> ? <div className="form-row">
<label> <label>
Custom search servers (one per line) {__("Custom search servers (one per line)")}
<div><FormField type="textarea" className="developer-page__custom-lighthouse-servers" value={this.state.customLighthouseServers} onChange={(event) => { this.handleCustomLighthouseServersChange() }} checked={this.state.debugMode} /></div> <div><FormField type="textarea" className="developer-page__custom-lighthouse-servers" value={this.state.customLighthouseServers} onChange={(event) => { this.handleCustomLighthouseServersChange() }} checked={this.state.debugMode} /></div>
</label> </label>
</div> </div>
@ -83,7 +83,7 @@ class DeveloperPage extends React.Component {
<div className="form-row"> <div className="form-row">
<FormField name="file" ref="file" type="file" onChange={(event) => { this.handleUpgradeFileChange() }}/> <FormField name="file" ref="file" type="file" onChange={(event) => { this.handleUpgradeFileChange() }}/>
&nbsp; &nbsp;
<Link label="Force Upgrade" button="alt" onClick={(event) => { this.handleForceUpgradeClick() }} /> <Link label={__("Force Upgrade")} button="alt" onClick={(event) => { this.handleForceUpgradeClick() }} />
</div> </div>
</section> </section>
</main> </main>

View file

@ -17,7 +17,7 @@ const FeaturedCategory = (props) => {
return <div className="card-row card-row--small"> return <div className="card-row card-row--small">
<h3 className="card-row__header">{category} <h3 className="card-row__header">{category}
{category && category.match(/^community/i) && <ToolTip label="What's this?" body={communityCategoryToolTipText} className="tooltip--header" />} {category && category.match(/^community/i) && <ToolTip label={__("What's this?")} body={__(communityCategoryToolTipText)} className="tooltip--header" />}
</h3> </h3>
{names && names.map(name => <FileCard key={name} displayStyle="card" uri={lbryuri.normalize(name)} />)} {names && names.map(name => <FileCard key={name} displayStyle="card" uri={lbryuri.normalize(name)} />)}
</div> </div>
@ -42,7 +42,7 @@ class DiscoverPage extends React.Component{
<main> <main>
{ {
fetchingFeaturedUris && fetchingFeaturedUris &&
<BusyMessage message="Fetching content" /> <BusyMessage message={__("Fetching content")} />
} }
{ {
typeof featuredUris === "object" && typeof featuredUris === "object" &&
@ -52,7 +52,7 @@ class DiscoverPage extends React.Component{
} }
{ {
failedToLoad && failedToLoad &&
<div className="empty">Failed to load landing content.</div> <div className="empty">{__("Failed to load landing content.")}</div>
} }
</main> </main>
) )

View file

@ -27,9 +27,9 @@ class FileListDownloaded extends React.Component {
content = <FileList fileInfos={fileInfos} fetching={isPending} /> content = <FileList fileInfos={fileInfos} fetching={isPending} />
} else { } else {
if (isPending) { if (isPending) {
content = <BusyMessage message="Loading" /> content = <BusyMessage message={__("Loading")} />
} else { } else {
content = <span>You haven't downloaded anything from LBRY yet. Go <Link onClick={() => navigate('/discover')} label="search for your first download" />!</span> content = <span>{__("You haven't downloaded anything from LBRY yet. Go")} <Link onClick={() => navigate('/discover')} label={__("search for your first download")} />!</span>
} }
} }

View file

@ -49,9 +49,9 @@ class FileListPublished extends React.Component {
content = <FileList fileInfos={fileInfos} fetching={isPending} fileTileShowEmpty={FileTile.SHOW_EMPTY_PENDING} /> content = <FileList fileInfos={fileInfos} fetching={isPending} fileTileShowEmpty={FileTile.SHOW_EMPTY_PENDING} />
} else { } else {
if (isPending) { if (isPending) {
content = <BusyMessage message="Loading" /> content = <BusyMessage message={__("Loading")} />
} else { } else {
content = <span>It looks like you haven't published anything to LBRY yet. Go <Link onClick={() => navigate('/publish')} label="share your beautiful cats with the world" />!</span> content = <span>{__("It looks like you haven't published anything to LBRY yet. Go")} <Link onClick={() => navigate('/publish')} label={__("share your beautiful cats with the world")} />!</span>
} }
} }

View file

@ -26,16 +26,16 @@ const FormatItem = (props) => {
<table className="table-standard"> <table className="table-standard">
<tbody> <tbody>
<tr> <tr>
<td>Content-Type</td><td>{mediaType}</td> <td>{__("Content-Type")}</td><td>{mediaType}</td>
</tr> </tr>
<tr> <tr>
<td>Author</td><td>{author}</td> <td>{__("Author")}</td><td>{author}</td>
</tr> </tr>
<tr> <tr>
<td>Language</td><td>{language}</td> <td>{__("Language")}</td><td>{language}</td>
</tr> </tr>
<tr> <tr>
<td>License</td><td>{license}</td> <td>{__("License")}</td><td>{license}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -75,7 +75,7 @@ class FilePage extends React.Component{
} = this.props } = this.props
if (!claim || !metadata) { if (!claim || !metadata) {
return <span className="empty">Empty claim or metadata info.</span> return <span className="empty">{__("Empty claim or metadata info.")}</span>
} }
const { const {
@ -125,7 +125,7 @@ class FilePage extends React.Component{
<FormatItem metadata={metadata} contentType={contentType} /> <FormatItem metadata={metadata} contentType={contentType} />
</div> : '' } </div> : '' }
<div className="card__content"> <div className="card__content">
<Link href="https://lbry.io/dmca" label="report" className="button-text-help" /> <Link href="https://lbry.io/dmca" label={__("report")} className="button-text-help" />
</div> </div>
</section> </section>
</main> </main>

View file

@ -66,70 +66,71 @@ class HelpPage extends React.Component {
<SubHeader /> <SubHeader />
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h3>Read the FAQ</h3> <h3>{__("Read the FAQ")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<p>Our FAQ answers many common questions.</p> <p>{__("Our FAQ answers many common questions.")}</p>
<p><Link href="https://lbry.io/faq" label="Read the FAQ" icon="icon-question" button="alt"/></p> <p><Link href="https://lbry.io/faq" label={__("Read the FAQ")} icon="icon-question" button="alt"/></p>
</div> </div>
</section> </section>
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h3>Get Live Help</h3> <h3>{__("Get Live Help")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<p> <p>
Live help is available most hours in the <strong>#help</strong> channel of our Slack chat room. {__("Live help is available most hours in the")} <strong>#help</strong> {__("channel of our Slack chat room.")}
</p> </p>
<p> <p>
<Link button="alt" label="Join Our Slack" icon="icon-slack" href="https://slack.lbry.io" /> <Link button="alt" label={__("Join Our Slack")} icon="icon-slack" href="https://slack.lbry.io" />
</p> </p>
</div> </div>
</section> </section>
<section className="card"> <section className="card">
<div className="card__title-primary"><h3>Report a Bug</h3></div> <div className="card__title-primary"><h3>{__("Report a Bug")}</h3></div>
<div className="card__content"> <div className="card__content">
<p>Did you find something wrong?</p> <p>{__("Did you find something wrong?")}</p>
<p><Link onClick={() => navigate('report')} label="Submit a Bug Report" icon="icon-bug" button="alt" /></p> <p><Link onClick={() => navigate('report')} label={__("Submit a Bug Report")} icon="icon-bug" button="alt" /></p>
<div className="meta">Thanks! LBRY is made by its users.</div> <div className="meta">{__("Thanks! LBRY is made by its users.")}</div>
</div> </div>
</section> </section>
<section className="card"> <section className="card">
<div className="card__title-primary"><h3>About</h3></div> <div className="card__title-primary"><h3>{__("About")}</h3></div>
<div className="card__content"> <div className="card__content">
{ this.state.upgradeAvailable === null ? '' : { this.state.upgradeAvailable === null ? '' :
( this.state.upgradeAvailable ? ( this.state.upgradeAvailable ?
<p>A newer version of LBRY is available. <Link href={newVerLink} label={`Download now!`} /></p> <p>{__("A newer version of LBRY is available.")} <Link href={newVerLink} label={__("Download now!")} /></p>
: <p>Your copy of LBRY is up to date.</p>)} : <p>{__("Your copy of LBRY is up to date.")}</p>)}
{ this.state.uiVersion && ver ? { this.state.uiVersion && ver ?
<table className="table-standard"> <table className="table-standard">
<tbody> <tbody>
<tr> <tr>
<th>daemon (lbrynet)</th> <th>{__("daemon (lbrynet)")}</th>
<td>{ver.lbrynet_version}</td> <td>{ver.lbrynet_version}</td>
</tr> </tr>
<tr> <tr>
<th>wallet (lbryum)</th> <th>{__("wallet (lbryum)")}</th>
<td>{ver.lbryum_version}</td> <td>{ver.lbryum_version}</td>
</tr> </tr>
<tr> <tr>
<th>interface</th> <th>{__("interface")}</th>
<td>{this.state.uiVersion}</td> <td>{this.state.uiVersion}</td>
</tr> </tr>
<tr> <tr>
<th>Platform</th> <th>{__("Platform")}</th>
<td>{platform}</td> <td>{platform}</td>
</tr> </tr>
<tr> <tr>
<th>Installation ID</th> <th>{__("Installation ID")}</th>
<td>{this.state.lbryId}</td> <td>{this.state.lbryId}</td>
</tr> </tr>
</tbody> </tbody>
</table> : </table> :
<BusyMessage message="Looking up version info" /> <BusyMessage message={__("Looking up version info")} />
} }
</div> </div>
</section> </section>
}
</main> </main>
); );
} }

View file

@ -179,7 +179,7 @@ class PublishPage extends React.Component {
} }
if (!lbryuri.isValidName(rawName, false)) { if (!lbryuri.isValidName(rawName, false)) {
this.refs.name.showError('LBRY names must contain only letters, numbers and dashes.'); this.refs.name.showError(__("LBRY names must contain only letters, numbers and dashes."));
return; return;
} }
@ -266,7 +266,7 @@ class PublishPage extends React.Component {
}; };
if (licenseType == 'copyright') { if (licenseType == 'copyright') {
newState.copyrightNotice = 'All rights reserved.' newState.copyrightNotice = __("All rights reserved.")
} }
this.setState(newState); this.setState(newState);
@ -302,7 +302,7 @@ class PublishPage extends React.Component {
const newChannelName = (event.target.value.startsWith('@') ? event.target.value : '@' + event.target.value); const newChannelName = (event.target.value.startsWith('@') ? event.target.value : '@' + event.target.value);
if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) { if (newChannelName.length > 1 && !lbryuri.isValidName(newChannelName.substr(1), false)) {
this.refs.newChannelName.showError('LBRY channel names must contain only letters, numbers and dashes.'); this.refs.newChannelName.showError(__("LBRY channel names must contain only letters, numbers and dashes."));
return; return;
} else { } else {
this.refs.newChannelName.clearError() this.refs.newChannelName.clearError()
@ -327,7 +327,7 @@ class PublishPage extends React.Component {
handleCreateChannelClick(event) { handleCreateChannelClick(event) {
if (this.state.newChannelName.length < 5) { if (this.state.newChannelName.length < 5) {
this.refs.newChannelName.showError('LBRY channel names must be at least 4 characters in length.'); this.refs.newChannelName.showError(__("LBRY channel names must be at least 4 characters in length."));
return; return;
} }
@ -346,7 +346,7 @@ class PublishPage extends React.Component {
}, 5000); }, 5000);
}, (error) => { }, (error) => {
// TODO: better error handling // TODO: better error handling
this.refs.newChannelName.showError('Unable to create channel due to an internal error.'); this.refs.newChannelName.showError(__("Unable to create channel due to an internal error."));
this.setState({ this.setState({
creatingChannel: false, creatingChannel: false,
}); });
@ -377,14 +377,17 @@ class PublishPage extends React.Component {
getNameBidHelpText() { getNameBidHelpText() {
if (!this.state.name) { if (!this.state.name) {
return "Select a URL for this publish."; return __("Select a URL for this publish.");
} else if (this.state.nameResolved === false) { } else if (this.state.nameResolved === false) {
return "This URL is unused."; return __("This URL is unused.");
} else if (this.state.myClaimExists) { } else if (this.state.myClaimExists) {
return "You have already used this URL. Publishing to it again will update your previous publish." return __("You have already used this URL. Publishing to it again will update your previous publish.")
} else if (this.state.topClaimValue) { } else if (this.state.topClaimValue) {
return <span>A deposit of at least <strong>{this.state.topClaimValue}</strong> {this.state.topClaimValue == 1 ? 'credit ' : 'credits '} return <span>{__n("A deposit of at least \"%s\" credit is required to win \"%s\". However, you can still get a permanent URL for any amount."
is required to win <strong>{this.state.name}</strong>. However, you can still get a permanent URL for any amount.</span> , "A deposit of at least \"%s\" credits is required to win \"%s\". However, you can still get a permanent URL for any amount."
, this.state.topClaimValue /*pluralization param*/
, this.state.topClaimValue, this.state.name /*regular params*/
)}</span>
} else { } else {
return ''; return '';
} }
@ -401,49 +404,49 @@ class PublishPage extends React.Component {
return null; return null;
} }
const lbcInputHelp = "This LBC remains yours and the deposit can be undone at any time." const lbcInputHelp = __("This LBC remains yours and the deposit can be undone at any time.");
return ( return (
<main className="main--single-column"> <main className="main--single-column">
<form onSubmit={(event) => { this.handleSubmit(event) }}> <form onSubmit={(event) => { this.handleSubmit(event) }}>
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h4>Content</h4> <h4>{__("Content")}</h4>
<div className="card__subtitle"> <div className="card__subtitle">
What are you publishing? {__("What are you publishing?")}
</div> </div>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow name="file" label="File" ref="file" type="file" onChange={(event) => { this.onFileChange(event) }} <FormRow name="file" label="File" ref="file" type="file" onChange={(event) => { this.onFileChange(event) }}
helper={this.state.myClaimExists ? "If you don't choose a file, the file from your existing claim will be used." : null}/> helper={this.state.myClaimExists ? __("If you don't choose a file, the file from your existing claim will be used.") : null}/>
</div> </div>
{ !this.state.hasFile ? '' : { !this.state.hasFile ? '' :
<div> <div>
<div className="card__content"> <div className="card__content">
<FormRow label="Title" type="text" ref="meta_title" name="title" placeholder="Titular Title" /> <FormRow label={__("Title")} type="text" ref="meta_title" name="title" placeholder={__("Title")} />
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="text" label="Thumbnail URL" ref="meta_thumbnail" name="thumbnail" placeholder="http://spee.ch/mylogo" /> <FormRow type="text" label={__("Thumbnail URL")} ref="meta_thumbnail" name="thumbnail" placeholder="http://spee.ch/mylogo" />
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow label="Description" type="textarea" ref="meta_description" name="description" placeholder="Description of your content" /> <FormRow label={__("Description")} type="textarea" ref="meta_description" name="description" placeholder={__("Description of your content")} />
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow label="Language" type="select" defaultValue="en" ref="meta_language" name="language"> <FormRow label={__("Language")} type="select" defaultValue="en" ref="meta_language" name="language">
<option value="en">English</option> <option value="en">{__("English")}</option>
<option value="zh">Chinese</option> <option value="zh">{__("Chinese")}</option>
<option value="fr">French</option> <option value="fr">{__("French")}</option>
<option value="de">German</option> <option value="de">{__("German")}</option>
<option value="jp">Japanese</option> <option value="jp">{__("Japanese")}</option>
<option value="ru">Russian</option> <option value="ru">{__("Russian")}</option>
<option value="es">Spanish</option> <option value="es">{__("Spanish")}</option>
</FormRow> </FormRow>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="select" label="Maturity" defaultValue="en" ref="meta_nsfw" name="nsfw"> <FormRow type="select" label={__("Maturity")} defaultValue="en" ref="meta_nsfw" name="nsfw">
{/* <option value=""></option> */} {/* <option value=""></option> */}
<option value="0">All Ages</option> <option value="0">{__("All Ages")}</option>
<option value="1">Adults Only</option> <option value="1">{__("Adults Only")}</option>
</FormRow> </FormRow>
</div> </div>
</div>} </div>}
@ -451,73 +454,73 @@ class PublishPage extends React.Component {
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h4>Access</h4> <h4>{__("Access")}</h4>
<div className="card__subtitle"> <div className="card__subtitle">
How much does this content cost? {__("How much does this content cost?")}
</div> </div>
</div> </div>
<div className="card__content"> <div className="card__content">
<div className="form-row__label-row"> <div className="form-row__label-row">
<label className="form-row__label">Price</label> <label className="form-row__label">{__("Price")}</label>
</div> </div>
<FormRow label="Free" type="radio" name="isFree" value="1" onChange={ () => { this.handleFeePrefChange(false) } } defaultChecked={!this.state.isFee} /> <FormRow label={__("Free")} type="radio" name="isFree" value="1" onChange={ () => { this.handleFeePrefChange(false) } } defaultChecked={!this.state.isFee} />
<FormField type="radio" name="isFree" label={!this.state.isFee ? 'Choose price...' : 'Price ' } <FormField type="radio" name="isFree" label={!this.state.isFee ? __('Choose price...') : __('Price ') }
onChange={ () => { this.handleFeePrefChange(true) } } defaultChecked={this.state.isFee} /> onChange={ () => { this.handleFeePrefChange(true) } } defaultChecked={this.state.isFee} />
<span className={!this.state.isFee ? 'hidden' : ''}> <span className={!this.state.isFee ? 'hidden' : ''}>
<FormField type="number" className="form-field__input--inline" step="0.01" placeholder="1.00" onChange={(event) => this.handleFeeAmountChange(event)} /> <FormField type="select" onChange={(event) => { this.handleFeeCurrencyChange(event) }}> <FormField type="number" className="form-field__input--inline" step="0.01" placeholder="1.00" onChange={(event) => this.handleFeeAmountChange(event)} /> <FormField type="select" onChange={(event) => { this.handleFeeCurrencyChange(event) }}>
<option value="USD">US Dollars</option> <option value="USD">{__("US Dollars")}</option>
<option value="LBC">LBRY credits</option> <option value="LBC">{__("LBRY credits")}</option>
</FormField> </FormField>
</span> </span>
{ this.state.isFee ? { this.state.isFee ?
<div className="form-field__helper"> <div className="form-field__helper">
If you choose to price this content in dollars, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase. {__("If you choose to price this content in dollars, the number of credits charged will be adjusted based on the value of LBRY credits at the time of purchase.")}
</div> : '' } </div> : '' }
<FormRow label="License" type="select" ref="meta_license" name="license" onChange={(event) => { this.handleLicenseChange(event) }}> <FormRow label="License" type="select" ref="meta_license" name="license" onChange={(event) => { this.handleLicenseChange(event) }}>
<option></option> <option></option>
<option>Public Domain</option> <option>{__("Public Domain")}</option>
<option data-url="https://creativecommons.org/licenses/by/4.0/legalcode">Creative Commons Attribution 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by/4.0/legalcode">{__("Creative Commons Attribution 4.0 International")}</option>
<option data-url="https://creativecommons.org/licenses/by-sa/4.0/legalcode">Creative Commons Attribution-ShareAlike 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by-sa/4.0/legalcode">{__("Creative Commons Attribution-ShareAlike 4.0 International")}</option>
<option data-url="https://creativecommons.org/licenses/by-nd/4.0/legalcode">Creative Commons Attribution-NoDerivatives 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by-nd/4.0/legalcode">{__("Creative Commons Attribution-NoDerivatives 4.0 International")}</option>
<option data-url="https://creativecommons.org/licenses/by-nc/4.0/legalcode">Creative Commons Attribution-NonCommercial 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by-nc/4.0/legalcode">{__("Creative Commons Attribution-NonCommercial 4.0 International")}</option>
<option data-url="https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode">{__("Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International")}</option>
<option data-url="https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International</option> <option data-url="https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode">{__("Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International")}</option>
<option data-license-type="copyright" {... this.state.copyrightChosen ? {value: this.state.copyrightNotice} : {}}>Copyrighted...</option> <option data-license-type="copyright" {... this.state.copyrightChosen ? {value: this.state.copyrightNotice} : {}}>{__("Copyrighted...")}</option>
<option data-license-type="other" {... this.state.otherLicenseChosen ? {value: this.state.otherLicenseDescription} : {}}>Other...</option> <option data-license-type="other" {... this.state.otherLicenseChosen ? {value: this.state.otherLicenseDescription} : {}}>{__("Other...")}</option>
</FormRow> </FormRow>
<FormField type="hidden" ref="meta_license_url" name="license_url" value={this.getLicenseUrl()} /> <FormField type="hidden" ref="meta_license_url" name="license_url" value={this.getLicenseUrl()} />
{this.state.copyrightChosen {this.state.copyrightChosen
? <FormRow label="Copyright notice" type="text" name="copyright-notice" ? <FormRow label={__("Copyright notice")} type="text" name="copyright-notice"
value={this.state.copyrightNotice} onChange={(event) => { this.handleCopyrightNoticeChange(event) }} /> value={this.state.copyrightNotice} onChange={(event) => { this.handleCopyrightNoticeChange(event) }} />
: null} : null}
{this.state.otherLicenseChosen ? {this.state.otherLicenseChosen ?
<FormRow label="License description" type="text" name="other-license-description" onChange={(event) => { this.handleOtherLicenseDescriptionChange() }} /> <FormRow label={__("License description")} type="text" name="other-license-description" onChange={(event) => { this.handleOtherLicenseDescriptionChange() }} />
: null} : null}
{this.state.otherLicenseChosen ? {this.state.otherLicenseChosen ?
<FormRow label="License URL" type="text" name="other-license-url" onChange={(event) => { this.handleOtherLicenseUrlChange(event) }} /> <FormRow label={__("License URL")} type="text" name="other-license-url" onChange={(event) => { this.handleOtherLicenseUrlChange(event) }} />
: null} : null}
</div> </div>
</section> </section>
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h4>Identity</h4> <h4>{__("Identity")}</h4>
<div className="card__subtitle"> <div className="card__subtitle">
Who created this content? {__("Who created this content?")}
</div> </div>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="select" tabIndex="1" onChange={(event) => { this.handleChannelChange(event) }} value={this.state.channel}> <FormRow type="select" tabIndex="1" onChange={(event) => { this.handleChannelChange(event) }} value={this.state.channel}>
<option key="anonymous" value="anonymous">Anonymous</option> <option key="anonymous" value="anonymous">{__("Anonymous")}</option>
{this.state.channels.map(({name}) => <option key={name} value={name}>{name}</option>)} {this.state.channels.map(({name}) => <option key={name} value={name}>{name}</option>)}
<option key="new" value="new">New identity...</option> <option key="new" value="new">{__("New identity...")}</option>
</FormRow> </FormRow>
</div> </div>
{this.state.channel == 'new' ? {this.state.channel == 'new' ?
<div className="card__content"> <div className="card__content">
<FormRow label="Name" type="text" onChange={(event) => { this.handleNewChannelNameChange(event) }} ref={newChannelName => { this.refs.newChannelName = newChannelName }} <FormRow label={__("Name")} type="text" onChange={(event) => { this.handleNewChannelNameChange(event) }} ref={newChannelName => { this.refs.newChannelName = newChannelName }}
value={this.state.newChannelName} /> value={this.state.newChannelName} />
<FormRow label="Deposit" <FormRow label={__("Deposit")}
postfix="LBC" postfix="LBC"
step="0.01" step="0.01"
type="number" type="number"
@ -525,7 +528,7 @@ class PublishPage extends React.Component {
onChange={(event) => { this.handleNewChannelBidChange(event) }} onChange={(event) => { this.handleNewChannelBidChange(event) }}
value={this.state.newChannelBid} /> value={this.state.newChannelBid} />
<div className="form-row-submit"> <div className="form-row-submit">
<Link button="primary" label={!this.state.creatingChannel ? 'Create identity' : 'Creating identity...'} onClick={(event) => { this.handleCreateChannelClick(event) }} disabled={this.state.creatingChannel} /> <Link button="primary" label={!this.state.creatingChannel ? __("Create identity") : __("Creating identity...")} onClick={(event) => { this.handleCreateChannelClick(event) }} disabled={this.state.creatingChannel} />
</div> </div>
</div> </div>
: null} : null}
@ -534,8 +537,8 @@ class PublishPage extends React.Component {
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h4>Address</h4> <h4>{__("Address")}</h4>
<div className="card__subtitle">Where should this content permanently reside? <Link label="Read more" href="https://lbry.io/faq/naming" />.</div> <div className="card__subtitle">{__("Where should this content permanently reside?")} <Link label={__("Read more")} href="https://lbry.io/faq/naming" />.</div>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow prefix="lbry://" type="text" ref="name" placeholder="myname" value={this.state.rawName} onChange={(event) => { this.handleNameChange(event) }} <FormRow prefix="lbry://" type="text" ref="name" placeholder="myname" value={this.state.rawName} onChange={(event) => { this.handleNameChange(event) }}
@ -546,7 +549,7 @@ class PublishPage extends React.Component {
<FormRow ref="bid" <FormRow ref="bid"
type="number" type="number"
step="0.01" step="0.01"
label="Deposit" label={__("Deposit")}
postfix="LBC" postfix="LBC"
onChange={(event) => { this.handleBidChange(event) }} onChange={(event) => { this.handleBidChange(event) }}
value={this.state.bid} value={this.state.bid}
@ -557,30 +560,30 @@ class PublishPage extends React.Component {
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h4>Terms of Service</h4> <h4>{__("Terms of Service")}</h4>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow label={ <FormRow label={
<span>I agree to the <Link href="https://www.lbry.io/termsofservice" label="LBRY terms of service" checked={this.state.TOSAgreed} /></span> <span>{__("I agree to the")} <Link href="https://www.lbry.io/termsofservice" label={__("LBRY terms of service")} checked={this.state.TOSAgreed} /></span>
} type="checkbox" name="tos_agree" ref={(field) => { this.refs.tos_agree = field }} onChange={(event) => { this.handleTOSChange(event)}} /> } type="checkbox" name="tos_agree" ref={(field) => { this.refs.tos_agree = field }} onChange={(event) => { this.handleTOSChange(event)}} />
</div> </div>
</section> </section>
<div className="card-series-submit"> <div className="card-series-submit">
<Link button="primary" label={!this.state.submitting ? 'Publish' : 'Publishing...'} onClick={(event) => { this.handleSubmit(event) }} disabled={this.state.submitting} /> <Link button="primary" label={!this.state.submitting ? __("Publish") : __("Publishing...")} onClick={(event) => { this.handleSubmit(event) }} disabled={this.state.submitting} />
<Link button="cancel" onClick={this.props.back} label="Cancel" /> <Link button="cancel" onClick={this.props.back} label={__("Cancel")} />
<input type="submit" className="hidden" /> <input type="submit" className="hidden" />
</div> </div>
</form> </form>
<Modal isOpen={this.state.modal == 'publishStarted'} contentLabel="File published" <Modal isOpen={this.state.modal == 'publishStarted'} contentLabel={__("File published")}
onConfirmed={(event) => { this.handlePublishStartedConfirmed(event) }}> onConfirmed={(event) => { this.handlePublishStartedConfirmed(event) }}>
<p>Your file has been published to LBRY at the address <code>lbry://{this.state.name}</code>!</p> <p>{__("Your file has been published to LBRY at the address")} <code>lbry://{this.state.name}</code>!</p>
<p>The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.</p> <p>{__('The file will take a few minutes to appear for other LBRY users. Until then it will be listed as "pending" under your published files.')}</p>
</Modal> </Modal>
<Modal isOpen={this.state.modal == 'error'} contentLabel="Error publishing file" <Modal isOpen={this.state.modal == 'error'} contentLabel={__("Error publishing file")}
onConfirmed={(event) => { this.closeModal(event) }}> onConfirmed={(event) => { this.closeModal(event) }}>
The following error occurred when attempting to publish your file: {this.state.errorMessage} {__("The following error occurred when attempting to publish your file")}: {this.state.errorMessage}
</Modal> </Modal>
</main> </main>
); );

View file

@ -40,25 +40,25 @@ class ReportPage extends React.Component {
<main className="main--single-column"> <main className="main--single-column">
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>Report an Issue</h3> <h3>{__("Report an Issue")}</h3>
<p>Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!</p> <p>{__("Please describe the problem you experienced and any information you think might be useful to us. Links to screenshots are great!")}</p>
<div className="form-row"> <div className="form-row">
<FormRow type="textarea" ref={(t) => this._messageArea = t} rows="10" name="message" placeholder="Description of your issue" /> <FormRow type="textarea" ref={(t) => this._messageArea = t} rows="10" name="message" placeholder={__("Description of your issue")} />
</div> </div>
<div className="form-row form-row-submit"> <div className="form-row form-row-submit">
<button onClick={(event) => { this.submitMessage(event) }} className={'button-block button-primary ' + (this.state.submitting ? 'disabled' : '')}>{this.state.submitting ? 'Submitting...' : 'Submit Report'}</button> <button onClick={(event) => { this.submitMessage(event) }} className={'button-block button-primary ' + (this.state.submitting ? 'disabled' : '')}>{this.state.submitting ? __('Submitting...') : __('Submit Report')}</button>
</div> </div>
</div> </div>
</section> </section>
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>Developer?</h3> <h3>{__("Developer?")}</h3>
You can also <Link href="https://github.com/lbryio/lbry/issues" label="submit an issue on GitHub"/>. {__("You can also")} <Link href="https://github.com/lbryio/lbry/issues" label={__("submit an issue on GitHub")}/>.
</div> </div>
</section> </section>
<Modal isOpen={this.state.modal == 'submitted'} contentLabel="Bug report submitted" <Modal isOpen={this.state.modal == 'submitted'} contentLabel={__("Bug report submitted")}
onConfirmed={(event) => { this.closeModal(event) }}> onConfirmed={(event) => { this.closeModal(event) }}>
Your bug report has been submitted! Thank you for your feedback. {__("Your bug report has been submitted! Thank you for your feedback.")}
</Modal> </Modal>
</main> </main>
); );

View file

@ -24,7 +24,7 @@ export class RewardTile extends React.Component {
</div> </div>
<div className="card__actions"> <div className="card__actions">
{this.props.claimed {this.props.claimed
? <span><Icon icon="icon-check" /> Reward claimed.</span> ? <span><Icon icon="icon-check" /> {__("Reward claimed.")}</span>
: <RewardLink {...this.props} />} : <RewardLink {...this.props} />}
</div> </div>
<div className="card__content">{this.props.description}</div> <div className="card__content">{this.props.description}</div>
@ -64,9 +64,9 @@ export class RewardsPage extends React.Component {
<SubHeader /> <SubHeader />
<div> <div>
{!this.state.userRewards {!this.state.userRewards
? (this.state.failed ? <div className="empty">Failed to load rewards.</div> : '') ? (this.state.failed ? <div className="empty">{__("Failed to load rewards.")}</div> : '')
: this.state.userRewards.map(({reward_type, reward_title, reward_description, transaction_id, reward_amount}) => { : this.state.userRewards.map(({reward_type, reward_title, reward_description, transaction_id, reward_amount}) => {
return <RewardTile key={reward_type} onRewardClaim={this.loadRewards} type={reward_type} title={reward_title} description={reward_description} claimed={!!transaction_id} value={reward_amount} />; return <RewardTile key={reward_type} onRewardClaim={this.loadRewards} type={reward_type} title={__(reward_title)} description={__(reward_description)} claimed={!!transaction_id} value={reward_amount} />;
})} })}
</div> </div>
</main> </main>

View file

@ -17,14 +17,14 @@ class SearchPage extends React.Component{
{ lbryuri.isValid(query) ? { lbryuri.isValid(query) ?
<section className="section-spaced"> <section className="section-spaced">
<h3 className="card-row__header"> <h3 className="card-row__header">
Exact URL <ToolTip label="?" body="This is the resolution of a LBRY URL and not controlled by LBRY Inc." {__("Exact URL")} <ToolTip label="?" body={__("This is the resolution of a LBRY URL and not controlled by LBRY Inc.")}
className="tooltip--header" /> className="tooltip--header" />
</h3> </h3>
<FileTile uri={lbryuri.normalize(query)} showEmpty={FileTile.SHOW_EMPTY_PUBLISH} /> <FileTile uri={lbryuri.normalize(query)} showEmpty={FileTile.SHOW_EMPTY_PUBLISH} />
</section> : '' } </section> : '' }
<section className="section-spaced"> <section className="section-spaced">
<h3 className="card-row__header"> <h3 className="card-row__header">
Search Results for {query} <ToolTip label="?" body="These search results are provided by LBRY, Inc." {__("Search Results for")} {query} <ToolTip label="?" body={__("These search results are provided by LBRY, Inc.")}
className="tooltip--header" /> className="tooltip--header" />
</h3> </h3>
<FileListSearch query={query} /> <FileListSearch query={query} />

View file

@ -3,6 +3,7 @@ import {FormField, FormRow} from 'component/form.js';
import SubHeader from 'component/subHeader' import SubHeader from 'component/subHeader'
import lbry from 'lbry.js'; import lbry from 'lbry.js';
class SettingsPage extends React.Component { class SettingsPage extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -14,6 +15,7 @@ class SettingsPage extends React.Component {
isMaxDownload: daemonSettings && daemonSettings.max_download != 0, isMaxDownload: daemonSettings && daemonSettings.max_download != 0,
showNsfw: lbry.getClientSetting('showNsfw'), showNsfw: lbry.getClientSetting('showNsfw'),
showUnavailable: lbry.getClientSetting('showUnavailable'), showUnavailable: lbry.getClientSetting('showUnavailable'),
language: lbry.getClientSetting('language'),
} }
} }
@ -68,6 +70,12 @@ class SettingsPage extends React.Component {
lbry.setClientSetting('showNsfw', event.target.checked); lbry.setClientSetting('showNsfw', event.target.checked);
} }
// onLanguageChange(language) {
// lbry.setClientSetting('language', language);
// i18n.setLocale(language);
// this.setState({language: language})
// }
onShowUnavailableChange(event) { onShowUnavailableChange(event) {
} }
@ -78,7 +86,7 @@ class SettingsPage extends React.Component {
} = this.props } = this.props
if (!daemonSettings) { if (!daemonSettings) {
return <main className="main--single-column"><span className="empty">Failed to load settings.</span></main>; return <main className="main--single-column"><span className="empty">{__("Failed to load settings.")}</span></main>;
} }
/* /*
<section className="card"> <section className="card">
@ -98,33 +106,33 @@ class SettingsPage extends React.Component {
<SubHeader /> <SubHeader />
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>Download Directory</h3> <h3>{__("Download Directory")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="directory" <FormRow type="directory"
name="download_directory" name="download_directory"
defaultValue={daemonSettings.download_directory} defaultValue={daemonSettings.download_directory}
helper="LBRY downloads will be saved here." helper={__("LBRY downloads will be saved here.")}
onChange={this.onDownloadDirChange.bind(this)} /> onChange={this.onDownloadDirChange.bind(this)} />
</div> </div>
</section> </section>
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>Bandwidth Limits</h3> <h3>{__("Bandwidth Limits")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<div className="form-row__label-row"><div className="form-field__label">Max Upload</div></div> <div className="form-row__label-row"><div className="form-field__label">{__("Max Upload")}</div></div>
<FormRow type="radio" <FormRow type="radio"
name="max_upload_pref" name="max_upload_pref"
onChange={() => { this.onMaxUploadPrefChange(false) }} onChange={() => { this.onMaxUploadPrefChange(false) }}
defaultChecked={!this.state.isMaxUpload} defaultChecked={!this.state.isMaxUpload}
label="Unlimited" /> label={__("Unlimited")} />
<div className="form-row"> <div className="form-row">
<FormField type="radio" <FormField type="radio"
name="max_upload_pref" name="max_upload_pref"
onChange={() => { this.onMaxUploadPrefChange(true) }} onChange={() => { this.onMaxUploadPrefChange(true) }}
defaultChecked={this.state.isMaxUpload} defaultChecked={this.state.isMaxUpload}
label={ this.state.isMaxUpload ? 'Up to' : 'Choose limit...' } /> label={ this.state.isMaxUpload ? __("Up to") : __("Choose limit...") } />
{ this.state.isMaxUpload ? { this.state.isMaxUpload ?
<FormField type="number" <FormField type="number"
min="0" min="0"
@ -141,8 +149,8 @@ class SettingsPage extends React.Component {
</div> </div>
</div> </div>
<div className="card__content"> <div className="card__content">
<div className="form-row__label-row"><div className="form-field__label">Max Download</div></div> <div className="form-row__label-row"><div className="form-field__label">{__("Max Download")}</div></div>
<FormRow label="Unlimited" <FormRow label={__("Unlimited")}
type="radio" type="radio"
name="max_download_pref" name="max_download_pref"
onChange={() => { this.onMaxDownloadPrefChange(false) }} onChange={() => { this.onMaxDownloadPrefChange(false) }}
@ -152,7 +160,7 @@ class SettingsPage extends React.Component {
name="max_download_pref" name="max_download_pref"
onChange={() => { this.onMaxDownloadPrefChange(true) }} onChange={() => { this.onMaxDownloadPrefChange(true) }}
defaultChecked={this.state.isMaxDownload} defaultChecked={this.state.isMaxDownload}
label={ this.state.isMaxDownload ? 'Up to' : 'Choose limit...' } /> label={ this.state.isMaxDownload ? __("Up to") : __("Choose limit...") } />
{ this.state.isMaxDownload ? { this.state.isMaxDownload ?
<FormField type="number" <FormField type="number"
min="0" min="0"
@ -171,29 +179,53 @@ class SettingsPage extends React.Component {
</section> </section>
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>Content</h3> <h3>{__("Content")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="checkbox" <FormRow type="checkbox"
onChange={this.onShowUnavailableChange.bind(this)} onChange={this.onShowUnavailableChange.bind(this)}
defaultChecked={this.state.showUnavailable} defaultChecked={this.state.showUnavailable}
label="Show unavailable content in search results" /> label={__("Show unavailable content in search results")} />
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow label="Show NSFW content" type="checkbox" <FormRow label={__("Show NSFW content")} type="checkbox"
onChange={this.onShowNsfwChange.bind(this)} defaultChecked={this.state.showNsfw} onChange={this.onShowNsfwChange.bind(this)} defaultChecked={this.state.showNsfw}
helper="NSFW content may include nudity, intense sexuality, profanity, or other adult content. By displaying NSFW content, you are affirming you are of legal age to view mature content in your country or jurisdiction. " /> helper={__("NSFW content may include nudity, intense sexuality, profanity, or other adult content. By displaying NSFW content, you are affirming you are of legal age to view mature content in your country or jurisdiction. ")} />
</div> </div>
</section> </section>
{/*}
<section className="card"> <section className="card">
<div className="card__content"> <div className="card__content">
<h3>Share Diagnostic Data</h3> <h3>{__("Language")}</h3>
</div>
<div className="card__content">
<div className="form-row">
<FormField type="radio"
name="language"
label={__("English")}
onChange={() => { this.onLanguageChange('en') }}
defaultChecked={this.state.language=='en'} />
</div>
<div className="form-row">
<FormField type="radio"
name="language"
label="Serbian"
onChange={() => { this.onLanguageChange('rs') }}
defaultChecked={this.state.language=='rs'} />
</div>
</div>
</section>*/}
<section className="card">
<div className="card__content">
<h3>{__("Share Diagnostic Data")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<FormRow type="checkbox" <FormRow type="checkbox"
onChange={this.onShareDataChange.bind(this)} onChange={this.onShareDataChange.bind(this)}
defaultChecked={daemonSettings.share_usage_data} defaultChecked={daemonSettings.share_usage_data}
label="Help make LBRY better by contributing diagnostic data about my usage" /> label={__("Help make LBRY better by contributing diagnostic data about my usage")} />
</div> </div>
</section> </section>
</main> </main>

View file

@ -43,8 +43,8 @@ class ShowPage extends React.Component{
<div className="card__title-identity"><h1>{uri}</h1></div> <div className="card__title-identity"><h1>{uri}</h1></div>
</div> </div>
<div className="card__content"> <div className="card__content">
{ isResolvingUri && <BusyMessage message="Loading magic decentralized data..." /> } { isResolvingUri && <BusyMessage message={__("Loading magic decentralized data...")} /> }
{ claim === null && <span className="empty">There's nothing at this location.</span> } { claim === null && <span className="empty">{__("There's nothing at this location.")}</span> }
</div> </div>
</section> </section>
} }

View file

@ -9,8 +9,8 @@ class StartPage extends React.Component {
render() { render() {
return ( return (
<main className="main--single-column"> <main className="main--single-column">
<h3>LBRY is Closed</h3> <h3>{__("LBRY is Closed")}</h3>
<Link href="lbry://lbry" label="Click here to start LBRY" /> <Link href="lbry://lbry" label={__("Click here to start LBRY")} />
</main> </main>
); );
} }

View file

@ -19,7 +19,7 @@ const WalletPage = (props) => {
<SubHeader /> <SubHeader />
<section className="card"> <section className="card">
<div className="card__title-primary"> <div className="card__title-primary">
<h3>Balance</h3> <h3>{__("Balance")}</h3>
</div> </div>
<div className="card__content"> <div className="card__content">
<CreditAmount amount={balance} precision={8} /> <CreditAmount amount={balance} precision={8} />

View file

@ -7,13 +7,13 @@ import {
function rewardMessage(type, amount) { function rewardMessage(type, amount) {
return { return {
new_developer: `You earned ${amount} for registering as a new developer.`, new_developer: __("You earned %s for registering as a new developer.", amount),
new_user: `You earned ${amount} LBC new user reward.`, new_user: __("You earned %s LBC new user reward.", amount),
confirm_email: `You earned ${amount} LBC for verifying your email address.`, confirm_email: __("You earned %s LBC for verifying your email address.", amount),
new_channel: `You earned ${amount} LBC for creating a publisher identity.`, new_channel: __("You earned %s LBC for creating a publisher identity.", amount),
first_stream: `You earned ${amount} LBC for streaming your first video.`, first_stream: __("You earned %s LBC for streaming your first video.", amount),
many_downloads: `You earned ${amount} LBC for downloading some of the things.`, many_downloads: __("You earned %s LBC for downloading some of the things.", amount),
first_publish: `You earned ${amount} LBC for making your first publication.`, first_publish: __("You earned %s LBC for making your first publication.", amount),
}[type]; }[type];
} }
@ -82,7 +82,7 @@ rewards.claimReward = function (type) {
function requestReward(resolve, reject, params) { function requestReward(resolve, reject, params) {
if (!lbryio.enabled) { if (!lbryio.enabled) {
reject(new Error("Rewards are not enabled.")) reject(new Error(__("Rewards are not enabled.")))
return; return;
} }
lbryio.call('reward', 'new', params, 'post').then(({reward_amount}) => { lbryio.call('reward', 'new', params, 'post').then(({reward_amount}) => {
@ -97,7 +97,7 @@ rewards.claimReward = function (type) {
// Display global notice // Display global notice
const action = doShowSnackBar({ const action = doShowSnackBar({
message, message,
linkText: "Show All", linkText: __("Show All"),
linkTarget: "/rewards", linkTarget: "/rewards",
isError: false, isError: false,
}) })
@ -126,7 +126,7 @@ rewards.claimReward = function (type) {
params.transaction_id = claim.txid; params.transaction_id = claim.txid;
requestReward(resolve, reject, params) requestReward(resolve, reject, params)
} else { } else {
reject(new Error("Please create a channel identity first.")) reject(new Error(__("Please create a channel identity first.")))
} }
}).catch(reject) }).catch(reject)
break; break;
@ -141,8 +141,8 @@ rewards.claimReward = function (type) {
requestReward(resolve, reject, params) requestReward(resolve, reject, params)
} else { } else {
reject(claims.length ? reject(claims.length ?
new Error("Please publish something and wait for confirmation by the network to claim this reward.") : new Error(__("Please publish something and wait for confirmation by the network to claim this reward.")) :
new Error("Please publish something to claim this reward.")) new Error(__("Please publish something to claim this reward.")))
} }
}).catch(reject) }).catch(reject)
break; break;

View file

@ -38,35 +38,28 @@ export const selectPageTitle = createSelector(
selectCurrentParams, selectCurrentParams,
(page, params) => { (page, params) => {
switch (page) { switch (page) {
case 'search':
return params.query ? `Search results for ${params.query}` : 'Search'
case 'settings': case 'settings':
return 'Settings'
case 'help': case 'help':
return 'Help'
case 'report': case 'report':
return 'Report'
case 'wallet': case 'wallet':
case 'send': case 'send':
case 'receive': case 'receive':
case 'rewards': case 'rewards':
return page.charAt(0).toUpperCase() + page.slice(1) case 'start':
case 'publish':
case 'help':
case 'developer':
return __(page.charAt(0).toUpperCase() + page.slice(1))
case 'search':
return params.query ? __("Search results for %s", params.query) : __('Search')
case 'show': case 'show':
return lbryuri.normalize(params.uri) return lbryuri.normalize(params.uri)
case 'downloaded': case 'downloaded':
return 'Downloads & Purchases' return __('Downloads & Purchases')
case 'published': case 'published':
return 'Publishes' return __('Publishes')
case 'start':
return 'Start'
case 'publish':
return 'Publish'
case 'help':
return 'Help'
case 'developer':
return 'Developer'
case 'discover': case 'discover':
return 'Home' return __('Home')
default: default:
return ''; return '';
} }
@ -142,22 +135,22 @@ export const selectHeaderLinks = createSelector(
case 'receive': case 'receive':
case 'rewards': case 'rewards':
return { return {
'wallet': 'Overview', 'wallet': __('Overview'),
'send': 'Send', 'send': __('Send'),
'receive': 'Receive', 'receive': __('Receive'),
'rewards': 'Rewards', 'rewards': __('Rewards'),
}; };
case 'downloaded': case 'downloaded':
case 'published': case 'published':
return { return {
'downloaded': 'Downloaded', 'downloaded': __('Downloaded'),
'published': 'Published', 'published': __('Published'),
}; };
case 'settings': case 'settings':
case 'help': case 'help':
return { return {
'settings': 'Settings', 'settings': __('Settings'),
'help': 'Help', 'help': __('Help'),
} }
default: default:
return null; return null;

View file

@ -34,7 +34,8 @@
"redux-logger": "^3.0.1", "redux-logger": "^3.0.1",
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"render-media": "^2.10.0", "render-media": "^2.10.0",
"reselect": "^3.0.0" "reselect": "^3.0.0",
"y18n": "^3.2.1"
}, },
"devDependencies": { "devDependencies": {
"babel": "^6.5.2", "babel": "^6.5.2",