Merge branch 'i18n'
This commit is contained in:
commit
3de3dd2544
22 changed files with 440 additions and 57 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
|
|
||||||
/app/dist
|
/app/dist
|
||||||
|
/app/locales
|
||||||
/app/node_modules
|
/app/node_modules
|
||||||
/build/venv
|
/build/venv
|
||||||
/build/daemon.ver
|
/build/daemon.ver
|
||||||
|
|
|
@ -231,14 +231,15 @@ export function doStartDownload(uri, outpoint) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
|
||||||
if (!outpoint) { throw new Error("outpoint is required to begin a download"); }
|
if (!outpoint) {
|
||||||
|
throw new Error("outpoint is required to begin a download");
|
||||||
|
}
|
||||||
|
|
||||||
const { downloadingByOutpoint = {} } = state.fileInfo;
|
const { downloadingByOutpoint = {} } = state.fileInfo;
|
||||||
|
|
||||||
if (downloadingByOutpoint[outpoint]) return;
|
if (downloadingByOutpoint[outpoint]) return;
|
||||||
|
|
||||||
lbry.file_list({ outpoint, full_status: true }).then(([fileInfo]) => {
|
lbry.file_list({ outpoint, full_status: true }).then(([fileInfo]) => {
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.DOWNLOADING_STARTED,
|
type: types.DOWNLOADING_STARTED,
|
||||||
data: {
|
data: {
|
||||||
|
@ -282,7 +283,9 @@ export function doLoadVideo(uri) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
lbry.get({ uri }).then(streamInfo => {
|
lbry
|
||||||
|
.get({ uri })
|
||||||
|
.then(streamInfo => {
|
||||||
const timeout =
|
const timeout =
|
||||||
streamInfo === null ||
|
streamInfo === null ||
|
||||||
typeof streamInfo !== "object" ||
|
typeof streamInfo !== "object" ||
|
||||||
|
@ -298,7 +301,8 @@ export function doLoadVideo(uri) {
|
||||||
} else {
|
} else {
|
||||||
dispatch(doDownloadFile(uri, streamInfo));
|
dispatch(doDownloadFile(uri, streamInfo));
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
})
|
||||||
|
.catch(error => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: types.LOADING_VIDEO_FAILED,
|
type: types.LOADING_VIDEO_FAILED,
|
||||||
data: { uri },
|
data: { uri },
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
|
import * as settings from "constants/settings";
|
||||||
|
import batchActions from "util/batchActions";
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
|
import fs from "fs";
|
||||||
|
import http from "http";
|
||||||
|
|
||||||
export function doFetchDaemonSettings() {
|
export function doFetchDaemonSettings() {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
|
@ -41,3 +45,96 @@ export function doSetClientSetting(key, value) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function doDownloadLanguage(langFile) {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
const destinationPath = `app/locales/${langFile}`;
|
||||||
|
const language = langFile.replace(".json", "");
|
||||||
|
const req = http.get(
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "text/html",
|
||||||
|
},
|
||||||
|
host: "i18n.lbry.io",
|
||||||
|
path: `/langs/${langFile}`,
|
||||||
|
},
|
||||||
|
response => {
|
||||||
|
if (response.statusCode === 200) {
|
||||||
|
const file = fs.createWriteStream(destinationPath);
|
||||||
|
|
||||||
|
file.on("error", errorHandler);
|
||||||
|
file.on("finish", () => {
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
// push to our local list
|
||||||
|
dispatch({
|
||||||
|
type: types.DOWNLOAD_LANGUAGE_SUCCEEDED,
|
||||||
|
data: { language: language },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
response.pipe(file);
|
||||||
|
} else {
|
||||||
|
errorHandler(new Error("Language request failed."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const errorHandler = err => {
|
||||||
|
fs.unlink(destinationPath, () => {}); // Delete the file async. (But we don't check the result)
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: types.DOWNLOAD_LANGUAGE_FAILED,
|
||||||
|
data: { language },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
req.setTimeout(30000, function() {
|
||||||
|
req.abort();
|
||||||
|
});
|
||||||
|
|
||||||
|
req.on("error", errorHandler);
|
||||||
|
|
||||||
|
req.end();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doDownloadLanguages() {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
if (!fs.existsSync(app.i18n.directory)) {
|
||||||
|
fs.mkdirSync(app.i18n.directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
try {
|
||||||
|
const files = JSON.parse(xhr.responseText);
|
||||||
|
const actions = [];
|
||||||
|
files.forEach(file => {
|
||||||
|
actions.push(doDownloadLanguage(file));
|
||||||
|
});
|
||||||
|
|
||||||
|
dispatch(batchActions(...actions));
|
||||||
|
} catch (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
__("The list of available languages could not be retrieved.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.open("get", "http://i18n.lbry.io");
|
||||||
|
xhr.send();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function doChangeLanguage(language) {
|
||||||
|
return function(dispatch, getState) {
|
||||||
|
lbry.setClientSetting(settings.LANGUAGE, language);
|
||||||
|
app.i18n.setLocale(language);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ class FileCard extends React.PureComponent {
|
||||||
? metadata.thumbnail
|
? metadata.thumbnail
|
||||||
: null;
|
: null;
|
||||||
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
|
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
|
||||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent =
|
||||||
|
claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||||
|
|
||||||
let description = "";
|
let description = "";
|
||||||
if (isResolvingUri && !claim) {
|
if (isResolvingUri && !claim) {
|
||||||
|
@ -96,7 +97,8 @@ class FileCard extends React.PureComponent {
|
||||||
<span style={{ float: "right" }}>
|
<span style={{ float: "right" }}>
|
||||||
<FilePrice uri={uri} />
|
<FilePrice uri={uri} />
|
||||||
{isRewardContent && <span>{" "}<IconFeatured /></span>}
|
{isRewardContent && <span>{" "}<IconFeatured /></span>}
|
||||||
{fileInfo && <span>{" "}<Icon fixed icon="icon-folder" /></span> }
|
{fileInfo &&
|
||||||
|
<span>{" "}<Icon fixed icon="icon-folder" /></span>}
|
||||||
</span>
|
</span>
|
||||||
<UriIndicator uri={uri} />
|
<UriIndicator uri={uri} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -71,7 +71,8 @@ class FileTile extends React.PureComponent {
|
||||||
? metadata.thumbnail
|
? metadata.thumbnail
|
||||||
: null;
|
: null;
|
||||||
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
|
const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
|
||||||
const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
|
const isRewardContent =
|
||||||
|
claim && rewardedContentClaimIds.includes(claim.claim_id);
|
||||||
|
|
||||||
let onClick = () => navigate("/show", { uri });
|
let onClick = () => navigate("/show", { uri });
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,11 @@ import { Icon } from "component/common.js";
|
||||||
|
|
||||||
const IconFeatured = props => {
|
const IconFeatured = props => {
|
||||||
return (
|
return (
|
||||||
<span className="icon-featured" title={ __("Watch content with this icon to earn weekly rewards.")}>
|
<span
|
||||||
<Icon icon="icon-rocket"
|
className="icon-featured"
|
||||||
fixed
|
title={__("Watch content with this icon to earn weekly rewards.")}
|
||||||
className="card__icon-featured-content" />
|
>
|
||||||
|
<Icon icon="icon-rocket" fixed className="card__icon-featured-content" />
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,7 @@ const select = (state, props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
navigate: (uri) => dispatch(doNavigate(uri)),
|
navigate: uri => dispatch(doNavigate(uri)),
|
||||||
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
|
verifyUserIdentity: token => dispatch(doUserIdentityVerify(token)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,20 +29,34 @@ class UserVerify extends React.PureComponent {
|
||||||
<p>
|
<p>
|
||||||
{__(
|
{__(
|
||||||
"To ensure you are a real person, we require a valid credit or debit card."
|
"To ensure you are a real person, we require a valid credit or debit card."
|
||||||
) + " " + __("There is no charge at all, now or in the future.") + " " }
|
) +
|
||||||
<Link href="https://lbry.io/faq/identity-requirements" label={__("Read More")} />
|
" " +
|
||||||
|
__("There is no charge at all, now or in the future.") +
|
||||||
|
" "}
|
||||||
|
<Link
|
||||||
|
href="https://lbry.io/faq/identity-requirements"
|
||||||
|
label={__("Read More")}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
{errorMessage && <p className="form-field__error">{errorMessage}</p>}
|
{errorMessage && <p className="form-field__error">{errorMessage}</p>}
|
||||||
<p><CardVerify
|
<p>
|
||||||
|
<CardVerify
|
||||||
label={__("Link Card and Finish")}
|
label={__("Link Card and Finish")}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
token={this.onToken.bind(this)}
|
token={this.onToken.bind(this)}
|
||||||
stripeKey="pk_live_e8M4dRNnCCbmpZzduEUZBgJO"
|
stripeKey="pk_live_e8M4dRNnCCbmpZzduEUZBgJO"
|
||||||
/></p>
|
/>
|
||||||
<p>
|
|
||||||
{__("You can continue without this step, but you will not be eligible to earn rewards.")}
|
|
||||||
</p>
|
</p>
|
||||||
<Link onClick={() => navigate("/discover")} button="alt" label={__("Skip Rewards")} />
|
<p>
|
||||||
|
{__(
|
||||||
|
"You can continue without this step, but you will not be eligible to earn rewards."
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<Link
|
||||||
|
onClick={() => navigate("/discover")}
|
||||||
|
button="alt"
|
||||||
|
label={__("Skip Rewards")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,11 @@ class Video extends React.PureComponent {
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
// reset playing state upon change path action
|
// reset playing state upon change path action
|
||||||
if (!this.isMediaSame(nextProps) && this.props.fileInfo && this.state.isPlaying) {
|
if (
|
||||||
|
!this.isMediaSame(nextProps) &&
|
||||||
|
this.props.fileInfo &&
|
||||||
|
this.state.isPlaying
|
||||||
|
) {
|
||||||
this.state.isPlaying = false;
|
this.state.isPlaying = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,3 +113,7 @@ export const CLAIM_REWARD_SUCCESS = "CLAIM_REWARD_SUCCESS";
|
||||||
export const CLAIM_REWARD_FAILURE = "CLAIM_REWARD_FAILURE";
|
export const CLAIM_REWARD_FAILURE = "CLAIM_REWARD_FAILURE";
|
||||||
export const CLAIM_REWARD_CLEAR_ERROR = "CLAIM_REWARD_CLEAR_ERROR";
|
export const CLAIM_REWARD_CLEAR_ERROR = "CLAIM_REWARD_CLEAR_ERROR";
|
||||||
export const FETCH_REWARD_CONTENT_COMPLETED = "FETCH_REWARD_CONTENT_COMPLETED";
|
export const FETCH_REWARD_CONTENT_COMPLETED = "FETCH_REWARD_CONTENT_COMPLETED";
|
||||||
|
|
||||||
|
//Language
|
||||||
|
export const DOWNLOAD_LANGUAGE_SUCCEEDED = "DOWNLOAD_LANGUAGE_SUCCEEDED";
|
||||||
|
export const DOWNLOAD_LANGUAGE_FAILED = "DOWNLOAD_LANGUAGE_FAILED";
|
||||||
|
|
187
ui/js/constants/languages.js
Normal file
187
ui/js/constants/languages.js
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
const LANGUAGES = {
|
||||||
|
aa: ["Afar", "Afar"],
|
||||||
|
ab: ["Abkhazian", "Аҧсуа"],
|
||||||
|
af: ["Afrikaans", "Afrikaans"],
|
||||||
|
ak: ["Akan", "Akana"],
|
||||||
|
am: ["Amharic", "አማርኛ"],
|
||||||
|
an: ["Aragonese", "Aragonés"],
|
||||||
|
ar: ["Arabic", "العربية"],
|
||||||
|
as: ["Assamese", "অসমীয়া"],
|
||||||
|
av: ["Avar", "Авар"],
|
||||||
|
ay: ["Aymara", "Aymar"],
|
||||||
|
az: ["Azerbaijani", "Azərbaycanca / آذربايجان"],
|
||||||
|
ba: ["Bashkir", "Башҡорт"],
|
||||||
|
be: ["Belarusian", "Беларуская"],
|
||||||
|
bg: ["Bulgarian", "Български"],
|
||||||
|
bh: ["Bihari", "भोजपुरी"],
|
||||||
|
bi: ["Bislama", "Bislama"],
|
||||||
|
bm: ["Bambara", "Bamanankan"],
|
||||||
|
bn: ["Bengali", "বাংলা"],
|
||||||
|
bo: ["Tibetan", "བོད་ཡིག / Bod skad"],
|
||||||
|
br: ["Breton", "Brezhoneg"],
|
||||||
|
bs: ["Bosnian", "Bosanski"],
|
||||||
|
ca: ["Catalan", "Català"],
|
||||||
|
ce: ["Chechen", "Нохчийн"],
|
||||||
|
ch: ["Chamorro", "Chamoru"],
|
||||||
|
co: ["Corsican", "Corsu"],
|
||||||
|
cr: ["Cree", "Nehiyaw"],
|
||||||
|
cs: ["Czech", "Česky"],
|
||||||
|
cu: ["Old Church Slavonic / Old Bulgarian", "словѣньскъ / slověnĭskŭ"],
|
||||||
|
cv: ["Chuvash", "Чăваш"],
|
||||||
|
cy: ["Welsh", "Cymraeg"],
|
||||||
|
da: ["Danish", "Dansk"],
|
||||||
|
de: ["German", "Deutsch"],
|
||||||
|
dv: ["Divehi", "ދިވެހިބަސް"],
|
||||||
|
dz: ["Dzongkha", "ཇོང་ཁ"],
|
||||||
|
ee: ["Ewe", "Ɛʋɛ"],
|
||||||
|
el: ["Greek", "Ελληνικά"],
|
||||||
|
en: ["English", "English"],
|
||||||
|
eo: ["Esperanto", "Esperanto"],
|
||||||
|
es: ["Spanish", "Español"],
|
||||||
|
et: ["Estonian", "Eesti"],
|
||||||
|
eu: ["Basque", "Euskara"],
|
||||||
|
fa: ["Persian", "فارسی"],
|
||||||
|
ff: ["Peul", "Fulfulde"],
|
||||||
|
fi: ["Finnish", "Suomi"],
|
||||||
|
fj: ["Fijian", "Na Vosa Vakaviti"],
|
||||||
|
fo: ["Faroese", "Føroyskt"],
|
||||||
|
fr: ["French", "Français"],
|
||||||
|
fy: ["West Frisian", "Frysk"],
|
||||||
|
ga: ["Irish", "Gaeilge"],
|
||||||
|
gd: ["Scottish Gaelic", "Gàidhlig"],
|
||||||
|
gl: ["Galician", "Galego"],
|
||||||
|
gn: ["Guarani", "Avañe'ẽ"],
|
||||||
|
gu: ["Gujarati", "ગુજરાતી"],
|
||||||
|
gv: ["Manx", "Gaelg"],
|
||||||
|
ha: ["Hausa", "هَوُسَ"],
|
||||||
|
he: ["Hebrew", "עברית"],
|
||||||
|
hi: ["Hindi", "हिन्दी"],
|
||||||
|
ho: ["Hiri Motu", "Hiri Motu"],
|
||||||
|
hr: ["Croatian", "Hrvatski"],
|
||||||
|
ht: ["Haitian", "Krèyol ayisyen"],
|
||||||
|
hu: ["Hungarian", "Magyar"],
|
||||||
|
hy: ["Armenian", "Հայերեն"],
|
||||||
|
hz: ["Herero", "Otsiherero"],
|
||||||
|
ia: ["Interlingua", "Interlingua"],
|
||||||
|
id: ["Indonesian", "Bahasa Indonesia"],
|
||||||
|
ie: ["Interlingue", "Interlingue"],
|
||||||
|
ig: ["Igbo", "Igbo"],
|
||||||
|
ii: ["Sichuan Yi", "ꆇꉙ / 四川彝语"],
|
||||||
|
ik: ["Inupiak", "Iñupiak"],
|
||||||
|
io: ["Ido", "Ido"],
|
||||||
|
is: ["Icelandic", "Íslenska"],
|
||||||
|
it: ["Italian", "Italiano"],
|
||||||
|
iu: ["Inuktitut", "ᐃᓄᒃᑎᑐᑦ"],
|
||||||
|
ja: ["Japanese", "日本語"],
|
||||||
|
jv: ["Javanese", "Basa Jawa"],
|
||||||
|
ka: ["Georgian", "ქართული"],
|
||||||
|
kg: ["Kongo", "KiKongo"],
|
||||||
|
ki: ["Kikuyu", "Gĩkũyũ"],
|
||||||
|
kj: ["Kuanyama", "Kuanyama"],
|
||||||
|
kk: ["Kazakh", "Қазақша"],
|
||||||
|
kl: ["Greenlandic", "Kalaallisut"],
|
||||||
|
km: ["Cambodian", "ភាសាខ្មែរ"],
|
||||||
|
kn: ["Kannada", "ಕನ್ನಡ"],
|
||||||
|
ko: ["Korean", "한국어"],
|
||||||
|
kr: ["Kanuri", "Kanuri"],
|
||||||
|
ks: ["Kashmiri", "कश्मीरी / كشميري"],
|
||||||
|
ku: ["Kurdish", "Kurdî / كوردی"],
|
||||||
|
kv: ["Komi", "Коми"],
|
||||||
|
kw: ["Cornish", "Kernewek"],
|
||||||
|
ky: ["Kirghiz", "Kırgızca / Кыргызча"],
|
||||||
|
la: ["Latin", "Latina"],
|
||||||
|
lb: ["Luxembourgish", "Lëtzebuergesch"],
|
||||||
|
lg: ["Ganda", "Luganda"],
|
||||||
|
li: ["Limburgian", "Limburgs"],
|
||||||
|
ln: ["Lingala", "Lingála"],
|
||||||
|
lo: ["Laotian", "ລາວ / Pha xa lao"],
|
||||||
|
lt: ["Lithuanian", "Lietuvių"],
|
||||||
|
lv: ["Latvian", "Latviešu"],
|
||||||
|
mg: ["Malagasy", "Malagasy"],
|
||||||
|
mh: ["Marshallese", "Kajin Majel / Ebon"],
|
||||||
|
mi: ["Maori", "Māori"],
|
||||||
|
mk: ["Macedonian", "Македонски"],
|
||||||
|
ml: ["Malayalam", "മലയാളം"],
|
||||||
|
mn: ["Mongolian", "Монгол"],
|
||||||
|
mo: ["Moldovan", "Moldovenească"],
|
||||||
|
mr: ["Marathi", "मराठी"],
|
||||||
|
ms: ["Malay", "Bahasa Melayu"],
|
||||||
|
mt: ["Maltese", "bil-Malti"],
|
||||||
|
my: ["Burmese", "Myanmasa"],
|
||||||
|
na: ["Nauruan", "Dorerin Naoero"],
|
||||||
|
nd: ["North Ndebele", "Sindebele"],
|
||||||
|
ne: ["Nepali", "नेपाली"],
|
||||||
|
ng: ["Ndonga", "Oshiwambo"],
|
||||||
|
nl: ["Dutch", "Nederlands"],
|
||||||
|
nn: ["Norwegian Nynorsk", "Norsk (nynorsk)"],
|
||||||
|
no: ["Norwegian", "Norsk (bokmål / riksmål)"],
|
||||||
|
nr: ["South Ndebele", "isiNdebele"],
|
||||||
|
nv: ["Navajo", "Diné bizaad"],
|
||||||
|
ny: ["Chichewa", "Chi-Chewa"],
|
||||||
|
oc: ["Occitan", "Occitan"],
|
||||||
|
oj: ["Ojibwa", "ᐊᓂᔑᓈᐯᒧᐎᓐ / Anishinaabemowin"],
|
||||||
|
om: ["Oromo", "Oromoo"],
|
||||||
|
or: ["Oriya", "ଓଡ଼ିଆ"],
|
||||||
|
os: ["Ossetian / Ossetic", "Иронау"],
|
||||||
|
pa: ["Panjabi / Punjabi", "ਪੰਜਾਬੀ / पंजाबी / پنجابي"],
|
||||||
|
pi: ["Pali", "Pāli / पाऴि"],
|
||||||
|
pl: ["Polish", "Polski"],
|
||||||
|
ps: ["Pashto", "پښتو"],
|
||||||
|
pt: ["Portuguese", "Português"],
|
||||||
|
qu: ["Quechua", "Runa Simi"],
|
||||||
|
rm: ["Raeto Romance", "Rumantsch"],
|
||||||
|
rn: ["Kirundi", "Kirundi"],
|
||||||
|
ro: ["Romanian", "Română"],
|
||||||
|
ru: ["Russian", "Русский"],
|
||||||
|
rw: ["Rwandi", "Kinyarwandi"],
|
||||||
|
sa: ["Sanskrit", "संस्कृतम्"],
|
||||||
|
sc: ["Sardinian", "Sardu"],
|
||||||
|
sd: ["Sindhi", "सिनधि"],
|
||||||
|
se: ["Northern Sami", "Sámegiella"],
|
||||||
|
sg: ["Sango", "Sängö"],
|
||||||
|
sh: ["Serbo-Croatian", "Srpskohrvatski / Српскохрватски"],
|
||||||
|
si: ["Sinhalese", "සිංහල"],
|
||||||
|
sk: ["Slovak", "Slovenčina"],
|
||||||
|
sl: ["Slovenian", "Slovenščina"],
|
||||||
|
sm: ["Samoan", "Gagana Samoa"],
|
||||||
|
sn: ["Shona", "chiShona"],
|
||||||
|
so: ["Somalia", "Soomaaliga"],
|
||||||
|
sq: ["Albanian", "Shqip"],
|
||||||
|
sr: ["Serbian", "Српски"],
|
||||||
|
ss: ["Swati", "SiSwati"],
|
||||||
|
st: ["Southern Sotho", "Sesotho"],
|
||||||
|
su: ["Sundanese", "Basa Sunda"],
|
||||||
|
sv: ["Swedish", "Svenska"],
|
||||||
|
sw: ["Swahili", "Kiswahili"],
|
||||||
|
ta: ["Tamil", "தமிழ்"],
|
||||||
|
te: ["Telugu", "తెలుగు"],
|
||||||
|
tg: ["Tajik", "Тоҷикӣ"],
|
||||||
|
th: ["Thai", "ไทย / Phasa Thai"],
|
||||||
|
ti: ["Tigrinya", "ትግርኛ"],
|
||||||
|
tk: ["Turkmen", "Туркмен / تركمن"],
|
||||||
|
tl: ["Tagalog / Filipino", "Tagalog"],
|
||||||
|
tn: ["Tswana", "Setswana"],
|
||||||
|
to: ["Tonga", "Lea Faka-Tonga"],
|
||||||
|
tr: ["Turkish", "Türkçe"],
|
||||||
|
ts: ["Tsonga", "Xitsonga"],
|
||||||
|
tt: ["Tatar", "Tatarça"],
|
||||||
|
tw: ["Twi", "Twi"],
|
||||||
|
ty: ["Tahitian", "Reo Mā`ohi"],
|
||||||
|
ug: ["Uyghur", "Uyƣurqə / ئۇيغۇرچە"],
|
||||||
|
uk: ["Ukrainian", "Українська"],
|
||||||
|
ur: ["Urdu", "اردو"],
|
||||||
|
uz: ["Uzbek", "Ўзбек"],
|
||||||
|
ve: ["Venda", "Tshivenḓa"],
|
||||||
|
vi: ["Vietnamese", "Tiếng Việt"],
|
||||||
|
vo: ["Volapük", "Volapük"],
|
||||||
|
wa: ["Walloon", "Walon"],
|
||||||
|
wo: ["Wolof", "Wollof"],
|
||||||
|
xh: ["Xhosa", "isiXhosa"],
|
||||||
|
yi: ["Yiddish", "ייִדיש"],
|
||||||
|
yo: ["Yoruba", "Yorùbá"],
|
||||||
|
za: ["Zhuang", "Cuengh / Tôô / 壮语"],
|
||||||
|
zh: ["Chinese", "中文"],
|
||||||
|
zu: ["Zulu", "isiZulu"],
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LANGUAGES;
|
|
@ -27,7 +27,7 @@ jsonrpc.call = function(
|
||||||
xhr.addEventListener("load", function() {
|
xhr.addEventListener("load", function() {
|
||||||
var response = JSON.parse(xhr.responseText);
|
var response = JSON.parse(xhr.responseText);
|
||||||
|
|
||||||
let error = response.error || response.result && response.result.error;
|
let error = response.error || (response.result && response.result.error);
|
||||||
if (error) {
|
if (error) {
|
||||||
if (errorCallback) {
|
if (errorCallback) {
|
||||||
errorCallback(error);
|
errorCallback(error);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Provider } from "react-redux";
|
||||||
import store from "store.js";
|
import store from "store.js";
|
||||||
import SplashScreen from "component/splash";
|
import SplashScreen from "component/splash";
|
||||||
import { doChangePath, doNavigate, doDaemonReady } from "actions/app";
|
import { doChangePath, doNavigate, doDaemonReady } from "actions/app";
|
||||||
|
import { doDownloadLanguages } from "actions/settings";
|
||||||
import { toQueryString } from "util/query_params";
|
import { toQueryString } from "util/query_params";
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
|
|
||||||
|
@ -96,6 +97,8 @@ const updateProgress = () => {
|
||||||
const initialState = app.store.getState();
|
const initialState = app.store.getState();
|
||||||
|
|
||||||
var init = function() {
|
var init = function() {
|
||||||
|
app.store.dispatch(doDownloadLanguages());
|
||||||
|
|
||||||
function onDaemonReady() {
|
function onDaemonReady() {
|
||||||
window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again
|
window.sessionStorage.setItem("loaded", "y"); //once we've made it here once per session, we don't need to show splash again
|
||||||
app.store.dispatch(doDaemonReady());
|
app.store.dispatch(doDaemonReady());
|
||||||
|
|
|
@ -127,7 +127,9 @@ class RewardsPage extends React.PureComponent {
|
||||||
<div>
|
<div>
|
||||||
<div className="card__content empty">
|
<div className="card__content empty">
|
||||||
<p>
|
<p>
|
||||||
{__("This application is unable to earn rewards due to an authentication failure.")}
|
{__(
|
||||||
|
"This application is unable to earn rewards due to an authentication failure."
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { doClearCache } from "actions/app";
|
import { doClearCache } from "actions/app";
|
||||||
import { doSetDaemonSetting, doSetClientSetting } from "actions/settings";
|
import {
|
||||||
import { selectDaemonSettings, selectShowNsfw } from "selectors/settings";
|
doSetDaemonSetting,
|
||||||
|
doSetClientSetting,
|
||||||
|
doChangeLanguage,
|
||||||
|
} from "actions/settings";
|
||||||
|
import {
|
||||||
|
selectDaemonSettings,
|
||||||
|
selectShowNsfw,
|
||||||
|
selectLanguages,
|
||||||
|
} from "selectors/settings";
|
||||||
|
import { selectCurrentLanguage } from "selectors/app";
|
||||||
import SettingsPage from "./view";
|
import SettingsPage from "./view";
|
||||||
|
|
||||||
const select = state => ({
|
const select = state => ({
|
||||||
daemonSettings: selectDaemonSettings(state),
|
daemonSettings: selectDaemonSettings(state),
|
||||||
showNsfw: selectShowNsfw(state),
|
showNsfw: selectShowNsfw(state),
|
||||||
|
language: selectCurrentLanguage(state),
|
||||||
|
languages: selectLanguages(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = dispatch => ({
|
const perform = dispatch => ({
|
||||||
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
|
setDaemonSetting: (key, value) => dispatch(doSetDaemonSetting(key, value)),
|
||||||
clearCache: () => dispatch(doClearCache()),
|
clearCache: () => dispatch(doClearCache()),
|
||||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||||
|
changeLanguage: newLanguage => dispatch(doChangeLanguage(newLanguage)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(SettingsPage);
|
export default connect(select, perform)(SettingsPage);
|
||||||
|
|
|
@ -96,16 +96,15 @@ class SettingsPage extends React.PureComponent {
|
||||||
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
this.props.setClientSetting(settings.SHOW_NSFW, event.target.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
// onLanguageChange(language) {
|
onLanguageChange(e) {
|
||||||
// lbry.setClientSetting('language', language);
|
this.props.changeLanguage(e.target.value);
|
||||||
// i18n.setLocale(language);
|
this.forceUpdate();
|
||||||
// this.setState({language: language})
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
onShowUnavailableChange(event) {}
|
onShowUnavailableChange(event) {}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { daemonSettings } = this.props;
|
const { daemonSettings, language, languages } = this.props;
|
||||||
|
|
||||||
if (!daemonSettings || Object.keys(daemonSettings).length === 0) {
|
if (!daemonSettings || Object.keys(daemonSettings).length === 0) {
|
||||||
return (
|
return (
|
||||||
|
@ -117,6 +116,28 @@ class SettingsPage extends React.PureComponent {
|
||||||
return (
|
return (
|
||||||
<main className="main--single-column">
|
<main className="main--single-column">
|
||||||
<SubHeader />
|
<SubHeader />
|
||||||
|
<section className="card">
|
||||||
|
<div className="card__content">
|
||||||
|
<h3>{__("Language")}</h3>
|
||||||
|
</div>
|
||||||
|
<div className="card__content">
|
||||||
|
<div className="form-row">
|
||||||
|
<FormField
|
||||||
|
type="select"
|
||||||
|
name="language"
|
||||||
|
defaultValue={language}
|
||||||
|
onChange={this.onLanguageChange.bind(this)}
|
||||||
|
>
|
||||||
|
<option value="en">{__("English")}</option>
|
||||||
|
{Object.keys(languages).map(dLang =>
|
||||||
|
<option key={dLang} value={dLang}>
|
||||||
|
{languages[dLang]}
|
||||||
|
</option>
|
||||||
|
)}
|
||||||
|
</FormField>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
<section className="card">
|
<section className="card">
|
||||||
<div className="card__content">
|
<div className="card__content">
|
||||||
<h3>{__("Download Directory")}</h3>
|
<h3>{__("Download Directory")}</h3>
|
||||||
|
|
|
@ -21,10 +21,7 @@ reducers[types.FETCH_FEATURED_CONTENT_COMPLETED] = function(state, action) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[types.FETCH_REWARD_CONTENT_COMPLETED] = function(
|
reducers[types.FETCH_REWARD_CONTENT_COMPLETED] = function(state, action) {
|
||||||
state,
|
|
||||||
action
|
|
||||||
) {
|
|
||||||
const { claimIds, success } = action.data;
|
const { claimIds, success } = action.data;
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import * as types from "constants/action_types";
|
import * as types from "constants/action_types";
|
||||||
|
import LANGUAGES from "constants/languages";
|
||||||
import lbry from "lbry";
|
import lbry from "lbry";
|
||||||
|
|
||||||
const reducers = {};
|
const reducers = {};
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
clientSettings: {
|
clientSettings: {
|
||||||
showNsfw: lbry.getClientSetting("showNsfw"),
|
showNsfw: lbry.getClientSetting("showNsfw"),
|
||||||
|
language: lbry.getClientSetting("language"),
|
||||||
},
|
},
|
||||||
|
languages: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
reducers[types.DAEMON_SETTINGS_RECEIVED] = function(state, action) {
|
reducers[types.DAEMON_SETTINGS_RECEIVED] = function(state, action) {
|
||||||
|
@ -25,6 +28,28 @@ reducers[types.CLIENT_SETTING_CHANGED] = function(state, action) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
reducers[types.DOWNLOAD_LANGUAGE_SUCCEEDED] = function(state, action) {
|
||||||
|
const languages = Object.assign({}, state.languages);
|
||||||
|
const language = action.data.language;
|
||||||
|
|
||||||
|
const langCode = language.substring(0, 2);
|
||||||
|
|
||||||
|
if (LANGUAGES[langCode]) {
|
||||||
|
languages[language] =
|
||||||
|
LANGUAGES[langCode][0] + " (" + LANGUAGES[langCode][1] + ")";
|
||||||
|
} else {
|
||||||
|
languages[langCode] = langCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.assign({}, state, { languages });
|
||||||
|
};
|
||||||
|
|
||||||
|
reducers[types.DOWNLOAD_LANGUAGE_FAILED] = function(state, action) {
|
||||||
|
const languages = Object.assign({}, state.languages);
|
||||||
|
delete languages[action.data.language];
|
||||||
|
return Object.assign({}, state, { languages });
|
||||||
|
};
|
||||||
|
|
||||||
export default function reducer(state = defaultState, action) {
|
export default function reducer(state = defaultState, action) {
|
||||||
const handler = reducers[action.type];
|
const handler = reducers[action.type];
|
||||||
if (handler) return handler(state, action);
|
if (handler) return handler(state, action);
|
||||||
|
|
|
@ -218,6 +218,11 @@ export const selectBadgeNumber = createSelector(
|
||||||
state => state.badgeNumber
|
state => state.badgeNumber
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectCurrentLanguage = createSelector(
|
||||||
|
_selectState,
|
||||||
|
() => app.i18n.getLocale() || "en"
|
||||||
|
);
|
||||||
|
|
||||||
export const selectPathAfterAuth = createSelector(
|
export const selectPathAfterAuth = createSelector(
|
||||||
_selectState,
|
_selectState,
|
||||||
state => state.pathAfterAuth
|
state => state.pathAfterAuth
|
||||||
|
|
|
@ -21,3 +21,8 @@ export const selectShowNsfw = createSelector(
|
||||||
selectClientSettings,
|
selectClientSettings,
|
||||||
clientSettings => !!clientSettings.showNsfw
|
clientSettings => !!clientSettings.showNsfw
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectLanguages = createSelector(
|
||||||
|
_selectState,
|
||||||
|
state => state.languages || {}
|
||||||
|
);
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
const { remote } = require("electron");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thin wrapper around localStorage.getItem(). Parses JSON and returns undefined if the value
|
* Thin wrapper around localStorage.getItem(). Parses JSON and returns undefined if the value
|
||||||
* is not set yet.
|
* is not set yet.
|
||||||
|
|
Loading…
Reference in a new issue