Merge branch 'master' into on-redis-expire
This commit is contained in:
commit
af3848586c
|
@ -1,2 +1,3 @@
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
|
.idea
|
||||||
|
|
|
@ -69,13 +69,13 @@ The server is configured with environment variables. See [server/config.js](serv
|
||||||
|
|
||||||
## Localization
|
## Localization
|
||||||
|
|
||||||
Firefox Send localization is managed via [Pontoon](https://pontoon.mozilla.org/projects/test-pilot-firefox-send/), not direct pull requests to the repository. If you want to fix a typo, add a new language, or simply know more about localization, please get in touch with the [existing localization team](https://pontoon.mozilla.org/teams/) for your language, or Mozilla’s [l10n-drivers](https://wiki.mozilla.org/L10n:Mozilla_Team#Mozilla_Corporation) for guidance.
|
Firefox Send localization is managed via [Pontoon](https://pontoon.mozilla.org/projects/test-pilot-firefox-send/), not direct pull requests to the repository. If you want to fix a typo, add a new language, or simply know more about localization, please get in touch with the [existing localization team](https://pontoon.mozilla.org/teams/) for your language or Mozilla’s [l10n-drivers](https://wiki.mozilla.org/L10n:Mozilla_Team#Mozilla_Corporation) for guidance.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Pull requests are always welcome! Feel free to check out the list of ["good first bugs"](https://github.com/mozilla/send/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+bug%22).
|
Pull requests are always welcome! Feel free to check out the list of ["good first issues"](https://github.com/mozilla/send/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
import { arrayToB64, b64ToArray } from './utils';
|
||||||
|
|
||||||
|
function post(obj) {
|
||||||
|
return {
|
||||||
|
method: 'POST',
|
||||||
|
headers: new Headers({
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}),
|
||||||
|
body: JSON.stringify(obj)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseNonce(header) {
|
||||||
|
header = header || '';
|
||||||
|
return header.split(' ')[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchWithAuth(url, params, keychain) {
|
||||||
|
const result = {};
|
||||||
|
params = params || {};
|
||||||
|
const h = await keychain.authHeader();
|
||||||
|
params.headers = new Headers({ Authorization: h });
|
||||||
|
const response = await fetch(url, params);
|
||||||
|
result.response = response;
|
||||||
|
result.ok = response.ok;
|
||||||
|
const nonce = parseNonce(response.headers.get('WWW-Authenticate'));
|
||||||
|
result.shouldRetry = response.status === 401 && nonce !== keychain.nonce;
|
||||||
|
keychain.nonce = nonce;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchWithAuthAndRetry(url, params, keychain) {
|
||||||
|
const result = await fetchWithAuth(url, params, keychain);
|
||||||
|
if (result.shouldRetry) {
|
||||||
|
return fetchWithAuth(url, params, keychain);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function del(id, owner_token) {
|
||||||
|
const response = await fetch(`/api/delete/${id}`, post({ owner_token }));
|
||||||
|
return response.ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setParams(id, owner_token, params) {
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/params/${id}`,
|
||||||
|
post({
|
||||||
|
owner_token,
|
||||||
|
dlimit: params.dlimit
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return response.ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fileInfo(id, owner_token) {
|
||||||
|
const response = await fetch(`/api/info/${id}`, post({ owner_token }));
|
||||||
|
if (response.ok) {
|
||||||
|
const obj = await response.json();
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
throw new Error(response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function metadata(id, keychain) {
|
||||||
|
const result = await fetchWithAuthAndRetry(
|
||||||
|
`/api/metadata/${id}`,
|
||||||
|
{ method: 'GET' },
|
||||||
|
keychain
|
||||||
|
);
|
||||||
|
if (result.ok) {
|
||||||
|
const data = await result.response.json();
|
||||||
|
const meta = await keychain.decryptMetadata(b64ToArray(data.metadata));
|
||||||
|
return {
|
||||||
|
size: data.size,
|
||||||
|
ttl: data.ttl,
|
||||||
|
iv: meta.iv,
|
||||||
|
name: meta.name,
|
||||||
|
type: meta.type
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(result.response.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setPassword(id, owner_token, keychain) {
|
||||||
|
const auth = await keychain.authKeyB64();
|
||||||
|
const response = await fetch(
|
||||||
|
`/api/password/${id}`,
|
||||||
|
post({ owner_token, auth })
|
||||||
|
);
|
||||||
|
return response.ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function uploadFile(encrypted, metadata, verifierB64, keychain) {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const upload = {
|
||||||
|
onprogress: function() {},
|
||||||
|
cancel: function() {
|
||||||
|
xhr.abort();
|
||||||
|
},
|
||||||
|
result: new Promise(function(resolve, reject) {
|
||||||
|
xhr.addEventListener('loadend', function() {
|
||||||
|
const authHeader = xhr.getResponseHeader('WWW-Authenticate');
|
||||||
|
if (authHeader) {
|
||||||
|
keychain.nonce = parseNonce(authHeader);
|
||||||
|
}
|
||||||
|
if (xhr.status === 200) {
|
||||||
|
const responseObj = JSON.parse(xhr.responseText);
|
||||||
|
return resolve({
|
||||||
|
url: responseObj.url,
|
||||||
|
id: responseObj.id,
|
||||||
|
ownerToken: responseObj.owner
|
||||||
|
});
|
||||||
|
}
|
||||||
|
reject(new Error(xhr.status));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
};
|
||||||
|
const dataView = new DataView(encrypted);
|
||||||
|
const blob = new Blob([dataView], { type: 'application/octet-stream' });
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('data', blob);
|
||||||
|
xhr.upload.addEventListener('progress', function(event) {
|
||||||
|
if (event.lengthComputable) {
|
||||||
|
upload.onprogress([event.loaded, event.total]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
xhr.open('post', '/api/upload', true);
|
||||||
|
xhr.setRequestHeader('X-File-Metadata', arrayToB64(new Uint8Array(metadata)));
|
||||||
|
xhr.setRequestHeader('Authorization', `send-v1 ${verifierB64}`);
|
||||||
|
xhr.send(fd);
|
||||||
|
return upload;
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(id, keychain) {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const download = {
|
||||||
|
onprogress: function() {},
|
||||||
|
cancel: function() {
|
||||||
|
xhr.abort();
|
||||||
|
},
|
||||||
|
result: new Promise(async function(resolve, reject) {
|
||||||
|
xhr.addEventListener('loadend', function() {
|
||||||
|
const authHeader = xhr.getResponseHeader('WWW-Authenticate');
|
||||||
|
if (authHeader) {
|
||||||
|
keychain.nonce = parseNonce(authHeader);
|
||||||
|
}
|
||||||
|
if (xhr.status === 404) {
|
||||||
|
return reject(new Error('notfound'));
|
||||||
|
}
|
||||||
|
if (xhr.status !== 200) {
|
||||||
|
return reject(new Error(xhr.status));
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = new Blob([xhr.response]);
|
||||||
|
const fileReader = new FileReader();
|
||||||
|
fileReader.readAsArrayBuffer(blob);
|
||||||
|
fileReader.onload = function() {
|
||||||
|
resolve(this.result);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
xhr.addEventListener('progress', function(event) {
|
||||||
|
if (event.lengthComputable && event.target.status === 200) {
|
||||||
|
download.onprogress([event.loaded, event.total]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const auth = await keychain.authHeader();
|
||||||
|
xhr.open('get', `/api/download/${id}`);
|
||||||
|
xhr.setRequestHeader('Authorization', auth);
|
||||||
|
xhr.responseType = 'blob';
|
||||||
|
xhr.send();
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
return download;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tryDownload(id, keychain, onprogress, tries = 1) {
|
||||||
|
const dl = download(id, keychain);
|
||||||
|
dl.onprogress = onprogress;
|
||||||
|
try {
|
||||||
|
const result = await dl.result;
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message === '401' && --tries > 0) {
|
||||||
|
return tryDownload(id, keychain, onprogress, tries);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function downloadFile(id, keychain) {
|
||||||
|
let cancelled = false;
|
||||||
|
function updateProgress(p) {
|
||||||
|
if (cancelled) {
|
||||||
|
// This is a bit of a hack
|
||||||
|
// We piggyback off of the progress event as a chance to cancel.
|
||||||
|
// Otherwise wiring the xhr abort up while allowing retries
|
||||||
|
// gets pretty nasty.
|
||||||
|
// 'this' here is the object returned by download(id, keychain)
|
||||||
|
return this.cancel();
|
||||||
|
}
|
||||||
|
dl.onprogress(p);
|
||||||
|
}
|
||||||
|
const dl = {
|
||||||
|
onprogress: function() {},
|
||||||
|
cancel: function() {
|
||||||
|
cancelled = true;
|
||||||
|
},
|
||||||
|
result: tryDownload(id, keychain, updateProgress, 2)
|
||||||
|
};
|
||||||
|
return dl;
|
||||||
|
}
|
|
@ -1,10 +1,19 @@
|
||||||
import hash from 'string-hash';
|
import hash from 'string-hash';
|
||||||
|
|
||||||
const experiments = {
|
const experiments = {
|
||||||
'SyI-hI7gT9agiH-f3f0BYg': {
|
S9wqVl2SQ4ab2yZtqDI3Dw: {
|
||||||
id: 'SyI-hI7gT9agiH-f3f0BYg',
|
id: 'S9wqVl2SQ4ab2yZtqDI3Dw',
|
||||||
run: function(variant, state, emitter) {
|
run: function(variant, state, emitter) {
|
||||||
state.promo = variant === 1 ? 'body' : 'header';
|
switch (variant) {
|
||||||
|
case 1:
|
||||||
|
state.promo = 'blue';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
state.promo = 'pink';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state.promo = 'grey';
|
||||||
|
}
|
||||||
emitter.emit('render');
|
emitter.emit('render');
|
||||||
},
|
},
|
||||||
eligible: function() {
|
eligible: function() {
|
||||||
|
@ -14,7 +23,11 @@ const experiments = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
variant: function(state) {
|
variant: function(state) {
|
||||||
return this.luckyNumber(state) > 0.5 ? 1 : 0;
|
const n = this.luckyNumber(state);
|
||||||
|
if (n < 0.33) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return n < 0.66 ? 1 : 2;
|
||||||
},
|
},
|
||||||
luckyNumber: function(state) {
|
luckyNumber: function(state) {
|
||||||
return luckyNumber(
|
return luckyNumber(
|
||||||
|
|
|
@ -1,57 +1,15 @@
|
||||||
/* global EXPIRE_SECONDS */
|
|
||||||
import FileSender from './fileSender';
|
import FileSender from './fileSender';
|
||||||
import FileReceiver from './fileReceiver';
|
import FileReceiver from './fileReceiver';
|
||||||
import { copyToClipboard, delay, fadeOut, percent } from './utils';
|
import {
|
||||||
|
copyToClipboard,
|
||||||
|
delay,
|
||||||
|
fadeOut,
|
||||||
|
openLinksInNewTab,
|
||||||
|
percent,
|
||||||
|
saveFile
|
||||||
|
} from './utils';
|
||||||
import * as metrics from './metrics';
|
import * as metrics from './metrics';
|
||||||
|
|
||||||
function saveFile(file) {
|
|
||||||
const dataView = new DataView(file.plaintext);
|
|
||||||
const blob = new Blob([dataView], { type: file.type });
|
|
||||||
const downloadUrl = URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
if (window.navigator.msSaveBlob) {
|
|
||||||
return window.navigator.msSaveBlob(blob, file.name);
|
|
||||||
}
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.href = downloadUrl;
|
|
||||||
a.download = file.name;
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
URL.revokeObjectURL(downloadUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
function openLinksInNewTab(links, should = true) {
|
|
||||||
links = links || Array.from(document.querySelectorAll('a:not([target])'));
|
|
||||||
if (should) {
|
|
||||||
links.forEach(l => {
|
|
||||||
l.setAttribute('target', '_blank');
|
|
||||||
l.setAttribute('rel', 'noopener noreferrer');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
links.forEach(l => {
|
|
||||||
l.removeAttribute('target');
|
|
||||||
l.removeAttribute('rel');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return links;
|
|
||||||
}
|
|
||||||
|
|
||||||
function exists(id) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
|
|
||||||
resolve(xhr.status === 200);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.onerror = () => resolve(false);
|
|
||||||
xhr.ontimeout = () => resolve(false);
|
|
||||||
xhr.open('get', '/api/exists/' + id);
|
|
||||||
xhr.timeout = 2000;
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function(state, emitter) {
|
export default function(state, emitter) {
|
||||||
let lastRender = 0;
|
let lastRender = 0;
|
||||||
let updateTitle = false;
|
let updateTitle = false;
|
||||||
|
@ -64,10 +22,14 @@ export default function(state, emitter) {
|
||||||
const files = state.storage.files;
|
const files = state.storage.files;
|
||||||
let rerender = false;
|
let rerender = false;
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const ok = await exists(file.id);
|
const oldLimit = file.dlimit;
|
||||||
if (!ok) {
|
const oldTotal = file.dtotal;
|
||||||
|
await file.updateDownloadCount();
|
||||||
|
if (file.dtotal === file.dlimit) {
|
||||||
state.storage.remove(file.id);
|
state.storage.remove(file.id);
|
||||||
rerender = true;
|
rerender = true;
|
||||||
|
} else if (oldLimit !== file.dlimit || oldTotal !== file.dtotal) {
|
||||||
|
rerender = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rerender) {
|
if (rerender) {
|
||||||
|
@ -91,12 +53,18 @@ export default function(state, emitter) {
|
||||||
checkFiles();
|
checkFiles();
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('navigate', checkFiles);
|
// emitter.on('navigate', checkFiles);
|
||||||
|
|
||||||
emitter.on('render', () => {
|
emitter.on('render', () => {
|
||||||
lastRender = Date.now();
|
lastRender = Date.now();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
emitter.on('changeLimit', async ({ file, value }) => {
|
||||||
|
await file.changeLimit(value);
|
||||||
|
state.storage.writeFile(file);
|
||||||
|
metrics.changedDownloadLimit(file);
|
||||||
|
});
|
||||||
|
|
||||||
emitter.on('delete', async ({ file, location }) => {
|
emitter.on('delete', async ({ file, location }) => {
|
||||||
try {
|
try {
|
||||||
metrics.deletedUpload({
|
metrics.deletedUpload({
|
||||||
|
@ -108,11 +76,10 @@ export default function(state, emitter) {
|
||||||
location
|
location
|
||||||
});
|
});
|
||||||
state.storage.remove(file.id);
|
state.storage.remove(file.id);
|
||||||
await FileSender.delete(file.id, file.deleteToken);
|
await file.del();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
state.raven.captureException(e);
|
state.raven.captureException(e);
|
||||||
}
|
}
|
||||||
state.fileInfo = null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('cancel', () => {
|
emitter.on('cancel', () => {
|
||||||
|
@ -126,32 +93,24 @@ export default function(state, emitter) {
|
||||||
sender.on('encrypting', render);
|
sender.on('encrypting', render);
|
||||||
state.transfer = sender;
|
state.transfer = sender;
|
||||||
render();
|
render();
|
||||||
|
|
||||||
const links = openLinksInNewTab();
|
const links = openLinksInNewTab();
|
||||||
await delay(200);
|
await delay(200);
|
||||||
try {
|
try {
|
||||||
const start = Date.now();
|
|
||||||
metrics.startedUpload({ size, type });
|
metrics.startedUpload({ size, type });
|
||||||
const info = await sender.upload();
|
const ownedFile = await sender.upload();
|
||||||
const time = Date.now() - start;
|
state.storage.totalUploads += 1;
|
||||||
const speed = size / (time / 1000);
|
metrics.completedUpload(ownedFile);
|
||||||
metrics.completedUpload({ size, time, speed, type });
|
|
||||||
|
state.storage.addFile(ownedFile);
|
||||||
|
|
||||||
document.getElementById('cancel-upload').hidden = 'hidden';
|
document.getElementById('cancel-upload').hidden = 'hidden';
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await fadeOut('upload-progress');
|
await fadeOut('upload-progress');
|
||||||
info.name = file.name;
|
|
||||||
info.size = size;
|
|
||||||
info.type = type;
|
|
||||||
info.time = time;
|
|
||||||
info.speed = speed;
|
|
||||||
info.createdAt = Date.now();
|
|
||||||
info.url = `${info.url}#${info.secretKey}`;
|
|
||||||
info.expiresAt = Date.now() + EXPIRE_SECONDS * 1000;
|
|
||||||
state.fileInfo = info;
|
|
||||||
state.storage.addFile(state.fileInfo);
|
|
||||||
openLinksInNewTab(links, false);
|
openLinksInNewTab(links, false);
|
||||||
state.transfer = null;
|
state.transfer = null;
|
||||||
state.storage.totalUploads += 1;
|
|
||||||
emitter.emit('pushState', `/share/${info.id}`);
|
emitter.emit('pushState', `/share/${ownedFile.id}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
state.transfer = null;
|
state.transfer = null;
|
||||||
|
@ -168,29 +127,27 @@ export default function(state, emitter) {
|
||||||
|
|
||||||
emitter.on('password', async ({ password, file }) => {
|
emitter.on('password', async ({ password, file }) => {
|
||||||
try {
|
try {
|
||||||
await FileSender.setPassword(password, file);
|
await file.setPassword(password);
|
||||||
|
state.storage.writeFile(file);
|
||||||
metrics.addedPassword({ size: file.size });
|
metrics.addedPassword({ size: file.size });
|
||||||
file.password = password;
|
} catch (err) {
|
||||||
state.storage.writeFiles();
|
console.error(err);
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('preview', async () => {
|
emitter.on('getMetadata', async () => {
|
||||||
const file = state.fileInfo;
|
const file = state.fileInfo;
|
||||||
const url = `/api/download/${file.id}`;
|
const receiver = new FileReceiver(file);
|
||||||
const receiver = new FileReceiver(url, file);
|
|
||||||
receiver.on('progress', updateProgress);
|
|
||||||
receiver.on('decrypting', render);
|
|
||||||
state.transfer = receiver;
|
|
||||||
try {
|
try {
|
||||||
await receiver.getMetadata(file.nonce);
|
await receiver.getMetadata();
|
||||||
|
receiver.on('progress', updateProgress);
|
||||||
|
receiver.on('decrypting', render);
|
||||||
|
state.transfer = receiver;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === '401') {
|
if (e.message === '401') {
|
||||||
file.password = null;
|
file.password = null;
|
||||||
if (!file.pwd) {
|
if (!file.requiresPassword) {
|
||||||
return emitter.emit('pushState', '/404');
|
return emitter.emit('pushState', '/404');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +163,7 @@ export default function(state, emitter) {
|
||||||
try {
|
try {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
metrics.startedDownload({ size: file.size, ttl: file.ttl });
|
metrics.startedDownload({ size: file.size, ttl: file.ttl });
|
||||||
const f = await state.transfer.download(file.nonce);
|
const f = await state.transfer.download();
|
||||||
const time = Date.now() - start;
|
const time = Date.now() - start;
|
||||||
const speed = size / (time / 1000);
|
const speed = size / (time / 1000);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
|
@ -217,8 +174,11 @@ export default function(state, emitter) {
|
||||||
metrics.completedDownload({ size, time, speed });
|
metrics.completedDownload({ size, time, speed });
|
||||||
emitter.emit('pushState', '/completed');
|
emitter.emit('pushState', '/completed');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (err.message === '0') {
|
||||||
|
// download cancelled
|
||||||
|
return render();
|
||||||
|
}
|
||||||
console.error(err);
|
console.error(err);
|
||||||
// TODO cancelled download
|
|
||||||
const location = err.message === 'notfound' ? '/404' : '/error';
|
const location = err.message === 'notfound' ? '/404' : '/error';
|
||||||
if (location === '/error') {
|
if (location === '/error') {
|
||||||
state.raven.captureException(err);
|
state.raven.captureException(err);
|
||||||
|
@ -236,6 +196,14 @@ export default function(state, emitter) {
|
||||||
metrics.copiedLink({ location });
|
metrics.copiedLink({ location });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
// poll for updates of the download counts
|
||||||
|
// TODO something for the share page: || state.route === '/share/:id'
|
||||||
|
if (state.route === '/') {
|
||||||
|
checkFiles();
|
||||||
|
}
|
||||||
|
}, 2 * 60 * 1000);
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// poll for rerendering the file list countdown timers
|
// poll for rerendering the file list countdown timers
|
||||||
if (
|
if (
|
||||||
|
|
|
@ -1,105 +1,21 @@
|
||||||
import Nanobus from 'nanobus';
|
import Nanobus from 'nanobus';
|
||||||
import { arrayToB64, b64ToArray, bytes } from './utils';
|
import Keychain from './keychain';
|
||||||
|
import { bytes } from './utils';
|
||||||
|
import { metadata, downloadFile } from './api';
|
||||||
|
|
||||||
export default class FileReceiver extends Nanobus {
|
export default class FileReceiver extends Nanobus {
|
||||||
constructor(url, file) {
|
constructor(fileInfo) {
|
||||||
super('FileReceiver');
|
super('FileReceiver');
|
||||||
this.secretKeyPromise = window.crypto.subtle.importKey(
|
this.keychain = new Keychain(fileInfo.secretKey, fileInfo.nonce);
|
||||||
'raw',
|
if (fileInfo.requiresPassword) {
|
||||||
b64ToArray(file.key),
|
this.keychain.setPassword(fileInfo.password, fileInfo.url);
|
||||||
'HKDF',
|
|
||||||
false,
|
|
||||||
['deriveKey']
|
|
||||||
);
|
|
||||||
this.encryptKeyPromise = this.secretKeyPromise.then(sk => {
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
return window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'HKDF',
|
|
||||||
salt: new Uint8Array(),
|
|
||||||
info: encoder.encode('encryption'),
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
sk,
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
length: 128
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['decrypt']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (file.pwd) {
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
console.log(file.password + file.url);
|
|
||||||
this.authKeyPromise = window.crypto.subtle
|
|
||||||
.importKey(
|
|
||||||
'raw',
|
|
||||||
encoder.encode(file.password),
|
|
||||||
{ name: 'PBKDF2' },
|
|
||||||
false,
|
|
||||||
['deriveKey']
|
|
||||||
)
|
|
||||||
.then(pwdKey =>
|
|
||||||
window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'PBKDF2',
|
|
||||||
salt: encoder.encode(file.url),
|
|
||||||
iterations: 100,
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
pwdKey,
|
|
||||||
{
|
|
||||||
name: 'HMAC',
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign']
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.authKeyPromise = this.secretKeyPromise.then(sk => {
|
|
||||||
const encoder = new TextEncoder();
|
|
||||||
return window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'HKDF',
|
|
||||||
salt: new Uint8Array(),
|
|
||||||
info: encoder.encode('authentication'),
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
sk,
|
|
||||||
{
|
|
||||||
name: 'HMAC',
|
|
||||||
hash: { name: 'SHA-256' }
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['sign']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
this.metaKeyPromise = this.secretKeyPromise.then(sk => {
|
this.fileInfo = fileInfo;
|
||||||
const encoder = new TextEncoder();
|
this.fileDownload = null;
|
||||||
return window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'HKDF',
|
|
||||||
salt: new Uint8Array(),
|
|
||||||
info: encoder.encode('metadata'),
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
sk,
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
length: 128
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['decrypt']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
this.file = file;
|
|
||||||
this.url = url;
|
|
||||||
this.msg = 'fileSizeProgress';
|
this.msg = 'fileSizeProgress';
|
||||||
this.state = 'initialized';
|
this.state = 'initialized';
|
||||||
this.progress = [0, 1];
|
this.progress = [0, 1];
|
||||||
|
this.cancelled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get progressRatio() {
|
get progressRatio() {
|
||||||
|
@ -114,135 +30,51 @@ export default class FileReceiver extends Nanobus {
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
// TODO
|
this.cancelled = true;
|
||||||
}
|
if (this.fileDownload) {
|
||||||
|
this.fileDownload.cancel();
|
||||||
fetchMetadata(sig) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
const nonce = xhr.getResponseHeader('WWW-Authenticate').split(' ')[1];
|
|
||||||
this.file.nonce = nonce;
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
return resolve(xhr.response);
|
|
||||||
}
|
|
||||||
reject(new Error(xhr.status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.onerror = () => reject(new Error(0));
|
|
||||||
xhr.ontimeout = () => reject(new Error(0));
|
|
||||||
xhr.open('get', `/api/metadata/${this.file.id}`);
|
|
||||||
xhr.setRequestHeader('Authorization', `send-v1 ${arrayToB64(sig)}`);
|
|
||||||
xhr.responseType = 'json';
|
|
||||||
xhr.timeout = 2000;
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getMetadata(nonce) {
|
|
||||||
try {
|
|
||||||
const authKey = await this.authKeyPromise;
|
|
||||||
const sig = await window.crypto.subtle.sign(
|
|
||||||
{
|
|
||||||
name: 'HMAC'
|
|
||||||
},
|
|
||||||
authKey,
|
|
||||||
b64ToArray(nonce)
|
|
||||||
);
|
|
||||||
const data = await this.fetchMetadata(new Uint8Array(sig));
|
|
||||||
const metaKey = await this.metaKeyPromise;
|
|
||||||
const json = await window.crypto.subtle.decrypt(
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
iv: new Uint8Array(12),
|
|
||||||
tagLength: 128
|
|
||||||
},
|
|
||||||
metaKey,
|
|
||||||
b64ToArray(data.metadata)
|
|
||||||
);
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
const meta = JSON.parse(decoder.decode(json));
|
|
||||||
this.file.name = meta.name;
|
|
||||||
this.file.type = meta.type;
|
|
||||||
this.file.iv = meta.iv;
|
|
||||||
this.file.size = data.size;
|
|
||||||
this.file.ttl = data.ttl;
|
|
||||||
this.state = 'ready';
|
|
||||||
} catch (e) {
|
|
||||||
this.state = 'invalid';
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadFile(sig) {
|
async getMetadata() {
|
||||||
return new Promise((resolve, reject) => {
|
const meta = await metadata(this.fileInfo.id, this.keychain);
|
||||||
const xhr = new XMLHttpRequest();
|
if (meta) {
|
||||||
|
this.keychain.setIV(meta.iv);
|
||||||
xhr.onprogress = event => {
|
this.fileInfo.name = meta.name;
|
||||||
if (event.lengthComputable && event.target.status !== 404) {
|
this.fileInfo.type = meta.type;
|
||||||
this.progress = [event.loaded, event.total];
|
this.fileInfo.iv = meta.iv;
|
||||||
this.emit('progress', this.progress);
|
this.fileInfo.size = meta.size;
|
||||||
}
|
this.state = 'ready';
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
xhr.onload = event => {
|
this.state = 'invalid';
|
||||||
if (xhr.status === 404) {
|
return;
|
||||||
reject(new Error('notfound'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xhr.status !== 200) {
|
|
||||||
return reject(new Error(xhr.status));
|
|
||||||
}
|
|
||||||
|
|
||||||
const blob = new Blob([xhr.response]);
|
|
||||||
const fileReader = new FileReader();
|
|
||||||
fileReader.onload = function() {
|
|
||||||
resolve(this.result);
|
|
||||||
};
|
|
||||||
|
|
||||||
fileReader.readAsArrayBuffer(blob);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open('get', this.url);
|
|
||||||
xhr.setRequestHeader('Authorization', `send-v1 ${arrayToB64(sig)}`);
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
xhr.send();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async download(nonce) {
|
async download() {
|
||||||
this.state = 'downloading';
|
this.state = 'downloading';
|
||||||
this.emit('progress', this.progress);
|
this.emit('progress', this.progress);
|
||||||
try {
|
try {
|
||||||
const encryptKey = await this.encryptKeyPromise;
|
const download = await downloadFile(this.fileInfo.id, this.keychain);
|
||||||
const authKey = await this.authKeyPromise;
|
download.onprogress = p => {
|
||||||
const sig = await window.crypto.subtle.sign(
|
this.progress = p;
|
||||||
{
|
this.emit('progress', p);
|
||||||
name: 'HMAC'
|
};
|
||||||
},
|
this.fileDownload = download;
|
||||||
authKey,
|
const ciphertext = await download.result;
|
||||||
b64ToArray(nonce)
|
this.fileDownload = null;
|
||||||
);
|
|
||||||
const ciphertext = await this.downloadFile(new Uint8Array(sig));
|
|
||||||
this.msg = 'decryptingFile';
|
this.msg = 'decryptingFile';
|
||||||
this.emit('decrypting');
|
this.emit('decrypting');
|
||||||
const plaintext = await window.crypto.subtle.decrypt(
|
const plaintext = await this.keychain.decryptFile(ciphertext);
|
||||||
{
|
if (this.cancelled) {
|
||||||
name: 'AES-GCM',
|
throw new Error(0);
|
||||||
iv: b64ToArray(this.file.iv),
|
}
|
||||||
tagLength: 128
|
|
||||||
},
|
|
||||||
encryptKey,
|
|
||||||
ciphertext
|
|
||||||
);
|
|
||||||
this.msg = 'downloadFinish';
|
this.msg = 'downloadFinish';
|
||||||
this.state = 'complete';
|
this.state = 'complete';
|
||||||
return {
|
return {
|
||||||
plaintext,
|
plaintext,
|
||||||
name: decodeURIComponent(this.file.name),
|
name: decodeURIComponent(this.fileInfo.name),
|
||||||
type: this.file.type
|
type: this.fileInfo.type
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.state = 'invalid';
|
this.state = 'invalid';
|
||||||
|
|
|
@ -1,42 +1,19 @@
|
||||||
|
/* global EXPIRE_SECONDS */
|
||||||
import Nanobus from 'nanobus';
|
import Nanobus from 'nanobus';
|
||||||
import { arrayToB64, b64ToArray, bytes } from './utils';
|
import OwnedFile from './ownedFile';
|
||||||
|
import Keychain from './keychain';
|
||||||
|
import { arrayToB64, bytes } from './utils';
|
||||||
|
import { uploadFile } from './api';
|
||||||
|
|
||||||
export default class FileSender extends Nanobus {
|
export default class FileSender extends Nanobus {
|
||||||
constructor(file) {
|
constructor(file) {
|
||||||
super('FileSender');
|
super('FileSender');
|
||||||
this.file = file;
|
this.file = file;
|
||||||
|
this.uploadRequest = null;
|
||||||
this.msg = 'importingFile';
|
this.msg = 'importingFile';
|
||||||
this.progress = [0, 1];
|
this.progress = [0, 1];
|
||||||
this.cancelled = false;
|
this.cancelled = false;
|
||||||
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
|
this.keychain = new Keychain();
|
||||||
this.uploadXHR = new XMLHttpRequest();
|
|
||||||
this.rawSecret = window.crypto.getRandomValues(new Uint8Array(16));
|
|
||||||
this.secretKey = window.crypto.subtle.importKey(
|
|
||||||
'raw',
|
|
||||||
this.rawSecret,
|
|
||||||
'HKDF',
|
|
||||||
false,
|
|
||||||
['deriveKey']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static delete(id, token) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!id || !token) {
|
|
||||||
return reject();
|
|
||||||
}
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open('POST', `/api/delete/${id}`);
|
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
||||||
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.send(JSON.stringify({ delete_token: token }));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get progressRatio() {
|
get progressRatio() {
|
||||||
|
@ -52,8 +29,8 @@ export default class FileSender extends Nanobus {
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.cancelled = true;
|
this.cancelled = true;
|
||||||
if (this.msg === 'fileSizeProgress') {
|
if (this.uploadRequest) {
|
||||||
this.uploadXHR.abort();
|
this.uploadRequest.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +38,7 @@ export default class FileSender extends Nanobus {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.readAsArrayBuffer(this.file);
|
reader.readAsArrayBuffer(this.file);
|
||||||
|
// TODO: progress?
|
||||||
reader.onload = function(event) {
|
reader.onload = function(event) {
|
||||||
const plaintext = new Uint8Array(this.result);
|
const plaintext = new Uint8Array(this.result);
|
||||||
resolve(plaintext);
|
resolve(plaintext);
|
||||||
|
@ -71,221 +49,57 @@ export default class FileSender extends Nanobus {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadFile(encrypted, metadata, rawAuth) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const dataView = new DataView(encrypted);
|
|
||||||
const blob = new Blob([dataView], { type: 'application/octet-stream' });
|
|
||||||
const fd = new FormData();
|
|
||||||
fd.append('data', blob);
|
|
||||||
|
|
||||||
const xhr = this.uploadXHR;
|
|
||||||
|
|
||||||
xhr.upload.addEventListener('progress', e => {
|
|
||||||
if (e.lengthComputable) {
|
|
||||||
this.progress = [e.loaded, e.total];
|
|
||||||
this.emit('progress', this.progress);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
const nonce = xhr
|
|
||||||
.getResponseHeader('WWW-Authenticate')
|
|
||||||
.split(' ')[1];
|
|
||||||
this.progress = [1, 1];
|
|
||||||
this.msg = 'notifyUploadDone';
|
|
||||||
const responseObj = JSON.parse(xhr.responseText);
|
|
||||||
return resolve({
|
|
||||||
url: responseObj.url,
|
|
||||||
id: responseObj.id,
|
|
||||||
secretKey: arrayToB64(this.rawSecret),
|
|
||||||
deleteToken: responseObj.delete,
|
|
||||||
nonce
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.msg = 'errorPageHeader';
|
|
||||||
reject(new Error(xhr.status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open('post', '/api/upload', true);
|
|
||||||
xhr.setRequestHeader(
|
|
||||||
'X-File-Metadata',
|
|
||||||
arrayToB64(new Uint8Array(metadata))
|
|
||||||
);
|
|
||||||
xhr.setRequestHeader('Authorization', `send-v1 ${arrayToB64(rawAuth)}`);
|
|
||||||
xhr.send(fd);
|
|
||||||
this.msg = 'fileSizeProgress';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async upload() {
|
async upload() {
|
||||||
const encoder = new TextEncoder();
|
const start = Date.now();
|
||||||
const secretKey = await this.secretKey;
|
|
||||||
const encryptKey = await window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'HKDF',
|
|
||||||
salt: new Uint8Array(),
|
|
||||||
info: encoder.encode('encryption'),
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
secretKey,
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
length: 128
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['encrypt']
|
|
||||||
);
|
|
||||||
const authKey = await window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'HKDF',
|
|
||||||
salt: new Uint8Array(),
|
|
||||||
info: encoder.encode('authentication'),
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
secretKey,
|
|
||||||
{
|
|
||||||
name: 'HMAC',
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign']
|
|
||||||
);
|
|
||||||
const metaKey = await window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'HKDF',
|
|
||||||
salt: new Uint8Array(),
|
|
||||||
info: encoder.encode('metadata'),
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
secretKey,
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
length: 128
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
['encrypt']
|
|
||||||
);
|
|
||||||
const plaintext = await this.readFile();
|
const plaintext = await this.readFile();
|
||||||
if (this.cancelled) {
|
if (this.cancelled) {
|
||||||
throw new Error(0);
|
throw new Error(0);
|
||||||
}
|
}
|
||||||
this.msg = 'encryptingFile';
|
this.msg = 'encryptingFile';
|
||||||
this.emit('encrypting');
|
this.emit('encrypting');
|
||||||
const encrypted = await window.crypto.subtle.encrypt(
|
const encrypted = await this.keychain.encryptFile(plaintext);
|
||||||
{
|
const metadata = await this.keychain.encryptMetadata(this.file);
|
||||||
name: 'AES-GCM',
|
const authKeyB64 = await this.keychain.authKeyB64();
|
||||||
iv: this.iv,
|
|
||||||
tagLength: 128
|
|
||||||
},
|
|
||||||
encryptKey,
|
|
||||||
plaintext
|
|
||||||
);
|
|
||||||
const metadata = await window.crypto.subtle.encrypt(
|
|
||||||
{
|
|
||||||
name: 'AES-GCM',
|
|
||||||
iv: new Uint8Array(12),
|
|
||||||
tagLength: 128
|
|
||||||
},
|
|
||||||
metaKey,
|
|
||||||
encoder.encode(
|
|
||||||
JSON.stringify({
|
|
||||||
iv: arrayToB64(this.iv),
|
|
||||||
name: this.file.name,
|
|
||||||
type: this.file.type || 'application/octet-stream'
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const rawAuth = await window.crypto.subtle.exportKey('raw', authKey);
|
|
||||||
if (this.cancelled) {
|
if (this.cancelled) {
|
||||||
throw new Error(0);
|
throw new Error(0);
|
||||||
}
|
}
|
||||||
return this.uploadFile(encrypted, metadata, new Uint8Array(rawAuth));
|
this.uploadRequest = uploadFile(
|
||||||
}
|
encrypted,
|
||||||
|
metadata,
|
||||||
static async setPassword(password, file) {
|
authKeyB64,
|
||||||
const encoder = new TextEncoder();
|
this.keychain
|
||||||
const secretKey = await window.crypto.subtle.importKey(
|
|
||||||
'raw',
|
|
||||||
b64ToArray(file.secretKey),
|
|
||||||
'HKDF',
|
|
||||||
false,
|
|
||||||
['deriveKey']
|
|
||||||
);
|
);
|
||||||
const authKey = await window.crypto.subtle.deriveKey(
|
this.msg = 'fileSizeProgress';
|
||||||
{
|
this.uploadRequest.onprogress = p => {
|
||||||
name: 'HKDF',
|
this.progress = p;
|
||||||
salt: new Uint8Array(),
|
this.emit('progress', p);
|
||||||
info: encoder.encode('authentication'),
|
};
|
||||||
hash: 'SHA-256'
|
try {
|
||||||
},
|
const result = await this.uploadRequest.result;
|
||||||
secretKey,
|
const time = Date.now() - start;
|
||||||
{
|
this.msg = 'notifyUploadDone';
|
||||||
name: 'HMAC',
|
this.uploadRequest = null;
|
||||||
hash: 'SHA-256'
|
this.progress = [1, 1];
|
||||||
},
|
const secretKey = arrayToB64(this.keychain.rawSecret);
|
||||||
true,
|
const ownedFile = new OwnedFile({
|
||||||
['sign']
|
id: result.id,
|
||||||
);
|
url: `${result.url}#${secretKey}`,
|
||||||
const sig = await window.crypto.subtle.sign(
|
name: this.file.name,
|
||||||
{
|
size: this.file.size,
|
||||||
name: 'HMAC'
|
type: this.file.type, //TODO 'click' ?
|
||||||
},
|
time: time,
|
||||||
authKey,
|
speed: this.file.size / (time / 1000),
|
||||||
b64ToArray(file.nonce)
|
createdAt: Date.now(),
|
||||||
);
|
expiresAt: Date.now() + EXPIRE_SECONDS * 1000,
|
||||||
const pwdKey = await window.crypto.subtle.importKey(
|
secretKey: secretKey,
|
||||||
'raw',
|
nonce: this.keychain.nonce,
|
||||||
encoder.encode(password),
|
ownerToken: result.ownerToken
|
||||||
{ name: 'PBKDF2' },
|
});
|
||||||
false,
|
return ownedFile;
|
||||||
['deriveKey']
|
} catch (e) {
|
||||||
);
|
this.msg = 'errorPageHeader';
|
||||||
const newAuthKey = await window.crypto.subtle.deriveKey(
|
this.uploadRequest = null;
|
||||||
{
|
throw e;
|
||||||
name: 'PBKDF2',
|
}
|
||||||
salt: encoder.encode(file.url),
|
|
||||||
iterations: 100,
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
pwdKey,
|
|
||||||
{
|
|
||||||
name: 'HMAC',
|
|
||||||
hash: 'SHA-256'
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
['sign']
|
|
||||||
);
|
|
||||||
const rawAuth = await window.crypto.subtle.exportKey('raw', newAuthKey);
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
return resolve(xhr.response);
|
|
||||||
}
|
|
||||||
if (xhr.status === 401) {
|
|
||||||
const nonce = xhr
|
|
||||||
.getResponseHeader('WWW-Authenticate')
|
|
||||||
.split(' ')[1];
|
|
||||||
file.nonce = nonce;
|
|
||||||
}
|
|
||||||
reject(new Error(xhr.status));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
xhr.onerror = () => reject(new Error(0));
|
|
||||||
xhr.ontimeout = () => reject(new Error(0));
|
|
||||||
xhr.open('post', `/api/password/${file.id}`);
|
|
||||||
xhr.setRequestHeader(
|
|
||||||
'Authorization',
|
|
||||||
`send-v1 ${arrayToB64(new Uint8Array(sig))}`
|
|
||||||
);
|
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
|
||||||
xhr.responseType = 'json';
|
|
||||||
xhr.timeout = 2000;
|
|
||||||
xhr.send(JSON.stringify({ auth: arrayToB64(new Uint8Array(rawAuth)) }));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
import { arrayToB64, b64ToArray } from './utils';
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
|
||||||
|
export default class Keychain {
|
||||||
|
constructor(secretKeyB64, nonce, ivB64) {
|
||||||
|
this._nonce = nonce || 'yRCdyQ1EMSA3mo4rqSkuNQ==';
|
||||||
|
if (ivB64) {
|
||||||
|
this.iv = b64ToArray(ivB64);
|
||||||
|
} else {
|
||||||
|
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
|
||||||
|
}
|
||||||
|
if (secretKeyB64) {
|
||||||
|
this.rawSecret = b64ToArray(secretKeyB64);
|
||||||
|
} else {
|
||||||
|
this.rawSecret = window.crypto.getRandomValues(new Uint8Array(16));
|
||||||
|
}
|
||||||
|
this.secretKeyPromise = window.crypto.subtle.importKey(
|
||||||
|
'raw',
|
||||||
|
this.rawSecret,
|
||||||
|
'HKDF',
|
||||||
|
false,
|
||||||
|
['deriveKey']
|
||||||
|
);
|
||||||
|
this.encryptKeyPromise = this.secretKeyPromise.then(function(secretKey) {
|
||||||
|
return window.crypto.subtle.deriveKey(
|
||||||
|
{
|
||||||
|
name: 'HKDF',
|
||||||
|
salt: new Uint8Array(),
|
||||||
|
info: encoder.encode('encryption'),
|
||||||
|
hash: 'SHA-256'
|
||||||
|
},
|
||||||
|
secretKey,
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
length: 128
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['encrypt', 'decrypt']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
this.metaKeyPromise = this.secretKeyPromise.then(function(secretKey) {
|
||||||
|
return window.crypto.subtle.deriveKey(
|
||||||
|
{
|
||||||
|
name: 'HKDF',
|
||||||
|
salt: new Uint8Array(),
|
||||||
|
info: encoder.encode('metadata'),
|
||||||
|
hash: 'SHA-256'
|
||||||
|
},
|
||||||
|
secretKey,
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
length: 128
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
['encrypt', 'decrypt']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
this.authKeyPromise = this.secretKeyPromise.then(function(secretKey) {
|
||||||
|
return window.crypto.subtle.deriveKey(
|
||||||
|
{
|
||||||
|
name: 'HKDF',
|
||||||
|
salt: new Uint8Array(),
|
||||||
|
info: encoder.encode('authentication'),
|
||||||
|
hash: 'SHA-256'
|
||||||
|
},
|
||||||
|
secretKey,
|
||||||
|
{
|
||||||
|
name: 'HMAC',
|
||||||
|
hash: { name: 'SHA-256' }
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get nonce() {
|
||||||
|
return this._nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
set nonce(n) {
|
||||||
|
if (n && n !== this._nonce) {
|
||||||
|
this._nonce = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setIV(ivB64) {
|
||||||
|
this.iv = b64ToArray(ivB64);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPassword(password, shareUrl) {
|
||||||
|
this.authKeyPromise = window.crypto.subtle
|
||||||
|
.importKey('raw', encoder.encode(password), { name: 'PBKDF2' }, false, [
|
||||||
|
'deriveKey'
|
||||||
|
])
|
||||||
|
.then(passwordKey =>
|
||||||
|
window.crypto.subtle.deriveKey(
|
||||||
|
{
|
||||||
|
name: 'PBKDF2',
|
||||||
|
salt: encoder.encode(shareUrl),
|
||||||
|
iterations: 100,
|
||||||
|
hash: 'SHA-256'
|
||||||
|
},
|
||||||
|
passwordKey,
|
||||||
|
{
|
||||||
|
name: 'HMAC',
|
||||||
|
hash: 'SHA-256'
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setAuthKey(authKeyB64) {
|
||||||
|
this.authKeyPromise = window.crypto.subtle.importKey(
|
||||||
|
'raw',
|
||||||
|
b64ToArray(authKeyB64),
|
||||||
|
{
|
||||||
|
name: 'HMAC',
|
||||||
|
hash: 'SHA-256'
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['sign']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async authKeyB64() {
|
||||||
|
const authKey = await this.authKeyPromise;
|
||||||
|
const rawAuth = await window.crypto.subtle.exportKey('raw', authKey);
|
||||||
|
return arrayToB64(new Uint8Array(rawAuth));
|
||||||
|
}
|
||||||
|
|
||||||
|
async authHeader() {
|
||||||
|
const authKey = await this.authKeyPromise;
|
||||||
|
const sig = await window.crypto.subtle.sign(
|
||||||
|
{
|
||||||
|
name: 'HMAC'
|
||||||
|
},
|
||||||
|
authKey,
|
||||||
|
b64ToArray(this.nonce)
|
||||||
|
);
|
||||||
|
return `send-v1 ${arrayToB64(new Uint8Array(sig))}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async encryptFile(plaintext) {
|
||||||
|
const encryptKey = await this.encryptKeyPromise;
|
||||||
|
const ciphertext = await window.crypto.subtle.encrypt(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
iv: this.iv,
|
||||||
|
tagLength: 128
|
||||||
|
},
|
||||||
|
encryptKey,
|
||||||
|
plaintext
|
||||||
|
);
|
||||||
|
return ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
async encryptMetadata(metadata) {
|
||||||
|
const metaKey = await this.metaKeyPromise;
|
||||||
|
const ciphertext = await window.crypto.subtle.encrypt(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
iv: new Uint8Array(12),
|
||||||
|
tagLength: 128
|
||||||
|
},
|
||||||
|
metaKey,
|
||||||
|
encoder.encode(
|
||||||
|
JSON.stringify({
|
||||||
|
iv: arrayToB64(this.iv),
|
||||||
|
name: metadata.name,
|
||||||
|
type: metadata.type || 'application/octet-stream'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return ciphertext;
|
||||||
|
}
|
||||||
|
|
||||||
|
async decryptFile(ciphertext) {
|
||||||
|
const encryptKey = await this.encryptKeyPromise;
|
||||||
|
const plaintext = await window.crypto.subtle.decrypt(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
iv: this.iv,
|
||||||
|
tagLength: 128
|
||||||
|
},
|
||||||
|
encryptKey,
|
||||||
|
ciphertext
|
||||||
|
);
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
async decryptMetadata(ciphertext) {
|
||||||
|
const metaKey = await this.metaKeyPromise;
|
||||||
|
const plaintext = await window.crypto.subtle.decrypt(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
iv: new Uint8Array(12),
|
||||||
|
tagLength: 128
|
||||||
|
},
|
||||||
|
metaKey,
|
||||||
|
ciphertext
|
||||||
|
);
|
||||||
|
return JSON.parse(decoder.decode(plaintext));
|
||||||
|
}
|
||||||
|
}
|
25
app/main.js
25
app/main.js
|
@ -1,3 +1,4 @@
|
||||||
|
import 'fluent-intl-polyfill';
|
||||||
import app from './routes';
|
import app from './routes';
|
||||||
import locale from '../common/locales';
|
import locale from '../common/locales';
|
||||||
import fileManager from './fileManager';
|
import fileManager from './fileManager';
|
||||||
|
@ -14,30 +15,34 @@ if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.use((state, emitter) => {
|
app.use((state, emitter) => {
|
||||||
// init state
|
|
||||||
state.transfer = null;
|
state.transfer = null;
|
||||||
state.fileInfo = null;
|
state.fileInfo = null;
|
||||||
state.translate = locale.getTranslator();
|
state.translate = locale.getTranslator();
|
||||||
state.storage = storage;
|
state.storage = storage;
|
||||||
state.raven = Raven;
|
state.raven = Raven;
|
||||||
emitter.on('DOMContentLoaded', async () => {
|
window.appState = state;
|
||||||
let reason = null;
|
emitter.on('DOMContentLoaded', async function checkSupport() {
|
||||||
|
let unsupportedReason = null;
|
||||||
if (
|
if (
|
||||||
|
// Firefox < 50
|
||||||
/firefox/i.test(navigator.userAgent) &&
|
/firefox/i.test(navigator.userAgent) &&
|
||||||
parseInt(navigator.userAgent.match(/firefox\/*([^\n\r]*)\./i)[1], 10) <=
|
parseInt(navigator.userAgent.match(/firefox\/*([^\n\r]*)\./i)[1], 10) < 50
|
||||||
49
|
|
||||||
) {
|
) {
|
||||||
reason = 'outdated';
|
unsupportedReason = 'outdated';
|
||||||
}
|
}
|
||||||
if (/edge\/\d+/i.test(navigator.userAgent)) {
|
if (/edge\/\d+/i.test(navigator.userAgent)) {
|
||||||
reason = 'edge';
|
unsupportedReason = 'edge';
|
||||||
}
|
}
|
||||||
const ok = await canHasSend(assets.get('cryptofill.js'));
|
const ok = await canHasSend(assets.get('cryptofill.js'));
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';
|
unsupportedReason = /firefox/i.test(navigator.userAgent)
|
||||||
|
? 'outdated'
|
||||||
|
: 'gcm';
|
||||||
}
|
}
|
||||||
if (reason) {
|
if (unsupportedReason) {
|
||||||
setTimeout(() => emitter.emit('replaceState', `/unsupported/${reason}`));
|
setTimeout(() =>
|
||||||
|
emitter.emit('replaceState', `/unsupported/${unsupportedReason}`)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,7 +20,7 @@ let experiment = null;
|
||||||
export default function initialize(state, emitter) {
|
export default function initialize(state, emitter) {
|
||||||
appState = state;
|
appState = state;
|
||||||
emitter.on('DOMContentLoaded', () => {
|
emitter.on('DOMContentLoaded', () => {
|
||||||
// addExitHandlers();
|
addExitHandlers();
|
||||||
experiment = storage.enrolled[0];
|
experiment = storage.enrolled[0];
|
||||||
sendEvent(category(), 'visit', {
|
sendEvent(category(), 'visit', {
|
||||||
cm5: storage.totalUploads,
|
cm5: storage.totalUploads,
|
||||||
|
@ -29,9 +29,8 @@ export default function initialize(state, emitter) {
|
||||||
});
|
});
|
||||||
//TODO restart handlers... somewhere
|
//TODO restart handlers... somewhere
|
||||||
});
|
});
|
||||||
emitter.on('exit', evt => {
|
emitter.on('exit', exitEvent);
|
||||||
exitEvent(evt);
|
emitter.on('experiment', experimentEvent);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function category() {
|
function category() {
|
||||||
|
@ -205,6 +204,16 @@ function stoppedUpload(params) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changedDownloadLimit(params) {
|
||||||
|
return sendEvent('sender', 'download-limit-changed', {
|
||||||
|
cm1: params.size,
|
||||||
|
cm5: storage.totalUploads,
|
||||||
|
cm6: storage.files.length,
|
||||||
|
cm7: storage.totalDownloads,
|
||||||
|
cm8: params.dlimit
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function completedDownload(params) {
|
function completedDownload(params) {
|
||||||
return sendEvent('recipient', 'download-stopped', {
|
return sendEvent('recipient', 'download-stopped', {
|
||||||
cm1: params.size,
|
cm1: params.size,
|
||||||
|
@ -249,6 +258,10 @@ function exitEvent(target) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function experimentEvent(params) {
|
||||||
|
return sendEvent(category(), 'experiment', params);
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function addExitHandlers() {
|
function addExitHandlers() {
|
||||||
const links = Array.from(document.querySelectorAll('a'));
|
const links = Array.from(document.querySelectorAll('a'));
|
||||||
|
@ -272,6 +285,7 @@ export {
|
||||||
cancelledUpload,
|
cancelledUpload,
|
||||||
stoppedUpload,
|
stoppedUpload,
|
||||||
completedUpload,
|
completedUpload,
|
||||||
|
changedDownloadLimit,
|
||||||
deletedUpload,
|
deletedUpload,
|
||||||
startedDownload,
|
startedDownload,
|
||||||
cancelledDownload,
|
cancelledDownload,
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
import Keychain from './keychain';
|
||||||
|
import { arrayToB64 } from './utils';
|
||||||
|
import { del, fileInfo, setParams, setPassword } from './api';
|
||||||
|
|
||||||
|
export default class OwnedFile {
|
||||||
|
constructor(obj) {
|
||||||
|
this.id = obj.id;
|
||||||
|
this.url = obj.url;
|
||||||
|
this.name = obj.name;
|
||||||
|
this.size = obj.size;
|
||||||
|
this.type = obj.type;
|
||||||
|
this.time = obj.time;
|
||||||
|
this.speed = obj.speed;
|
||||||
|
this.createdAt = obj.createdAt;
|
||||||
|
this.expiresAt = obj.expiresAt;
|
||||||
|
this.ownerToken = obj.ownerToken;
|
||||||
|
this.dlimit = obj.dlimit || 1;
|
||||||
|
this.dtotal = obj.dtotal || 0;
|
||||||
|
this.keychain = new Keychain(obj.secretKey);
|
||||||
|
this._hasPassword = !!obj.hasPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setPassword(password) {
|
||||||
|
this.password = password;
|
||||||
|
this._hasPassword = true;
|
||||||
|
this.keychain.setPassword(password, this.url);
|
||||||
|
const result = await setPassword(this.id, this.ownerToken, this.keychain);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
del() {
|
||||||
|
return del(this.id, this.ownerToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLimit(dlimit) {
|
||||||
|
if (this.dlimit !== dlimit) {
|
||||||
|
this.dlimit = dlimit;
|
||||||
|
return setParams(this.id, this.ownerToken, { dlimit });
|
||||||
|
}
|
||||||
|
return Promise.resolve(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasPassword() {
|
||||||
|
return !!this._hasPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDownloadCount() {
|
||||||
|
try {
|
||||||
|
const result = await fileInfo(this.id, this.ownerToken);
|
||||||
|
this.dtotal = result.dtotal;
|
||||||
|
this.dlimit = result.dlimit;
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message === '404') {
|
||||||
|
this.dtotal = this.dlimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
id: this.id,
|
||||||
|
url: this.url,
|
||||||
|
name: this.name,
|
||||||
|
size: this.size,
|
||||||
|
type: this.type,
|
||||||
|
time: this.time,
|
||||||
|
speed: this.speed,
|
||||||
|
createdAt: this.createdAt,
|
||||||
|
expiresAt: this.expiresAt,
|
||||||
|
secretKey: arrayToB64(this.keychain.rawSecret),
|
||||||
|
ownerToken: this.ownerToken,
|
||||||
|
dlimit: this.dlimit,
|
||||||
|
dtotal: this.dtotal,
|
||||||
|
hasPassword: this.hasPassword
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
|
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
const div = html`<div id="page-one"></div>`;
|
const div = html`<div></div>`;
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
|
@ -0,0 +1,34 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
const progress = require('../templates/progress');
|
||||||
|
const { fadeOut } = require('../utils');
|
||||||
|
|
||||||
|
module.exports = function(state, emit) {
|
||||||
|
const div = html`
|
||||||
|
<div id="page-one">
|
||||||
|
<div id="download" class="fadeIn">
|
||||||
|
<div id="download-progress">
|
||||||
|
<div id="dl-title" class="title">
|
||||||
|
${state.translate('downloadFinish')}
|
||||||
|
</div>
|
||||||
|
<div class="description"></div>
|
||||||
|
${progress(1)}
|
||||||
|
<div class="upload">
|
||||||
|
<div class="progress-text"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a class="send-new"
|
||||||
|
data-state="completed"
|
||||||
|
href="/"
|
||||||
|
onclick=${sendNew}>${state.translate('sendYourFilesLink')}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
async function sendNew(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
await fadeOut('download');
|
||||||
|
emit('pushState', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
return div;
|
||||||
|
};
|
|
@ -0,0 +1,43 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
const progress = require('../templates/progress');
|
||||||
|
const { bytes } = require('../utils');
|
||||||
|
|
||||||
|
module.exports = function(state, emit) {
|
||||||
|
const transfer = state.transfer;
|
||||||
|
const div = html`
|
||||||
|
<div id="page-one">
|
||||||
|
<div id="download">
|
||||||
|
<div id="download-progress" class="fadeIn">
|
||||||
|
<div id="dl-title" class="title">${state.translate(
|
||||||
|
'downloadingPageProgress',
|
||||||
|
{
|
||||||
|
filename: state.fileInfo.name,
|
||||||
|
size: bytes(state.fileInfo.size)
|
||||||
|
}
|
||||||
|
)}</div>
|
||||||
|
<div class="description">${state.translate(
|
||||||
|
'downloadingPageMessage'
|
||||||
|
)}</div>
|
||||||
|
${progress(transfer.progressRatio)}
|
||||||
|
<div class="upload">
|
||||||
|
<div class="progress-text">${state.translate(
|
||||||
|
transfer.msg,
|
||||||
|
transfer.sizes
|
||||||
|
)}</div>
|
||||||
|
<button
|
||||||
|
id="cancel-upload"
|
||||||
|
title="${state.translate('deletePopupCancel')}"
|
||||||
|
onclick=${cancel}>${state.translate('deletePopupCancel')}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
const btn = document.getElementById('cancel-upload');
|
||||||
|
btn.remove();
|
||||||
|
emit('cancel');
|
||||||
|
}
|
||||||
|
return div;
|
||||||
|
};
|
|
@ -9,12 +9,12 @@ module.exports = function(state) {
|
||||||
<div class="share-window">
|
<div class="share-window">
|
||||||
<img src="${assets.get('illustration_expired.svg')}" id="expired-img">
|
<img src="${assets.get('illustration_expired.svg')}" id="expired-img">
|
||||||
</div>
|
</div>
|
||||||
<div class="expired-description">${state.translate(
|
<div class="expired-description">
|
||||||
'uploadPageExplainer'
|
${state.translate('uploadPageExplainer')}
|
||||||
)}</div>
|
</div>
|
||||||
<a class="send-new" href="/" data-state="notfound">${state.translate(
|
<a class="send-new" href="/" data-state="notfound">
|
||||||
'sendYourFilesLink'
|
${state.translate('sendYourFilesLink')}
|
||||||
)}</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
return div;
|
return div;
|
|
@ -0,0 +1,37 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
const assets = require('../../common/assets');
|
||||||
|
const { bytes } = require('../utils');
|
||||||
|
|
||||||
|
module.exports = function(state, pageAction) {
|
||||||
|
const fileInfo = state.fileInfo;
|
||||||
|
const size = fileInfo.size
|
||||||
|
? state.translate('downloadFileSize', { size: bytes(fileInfo.size) })
|
||||||
|
: '';
|
||||||
|
|
||||||
|
const title = fileInfo.name
|
||||||
|
? state.translate('downloadFileName', { filename: fileInfo.name })
|
||||||
|
: state.translate('downloadFileTitle');
|
||||||
|
const div = html`
|
||||||
|
<div id="page-one">
|
||||||
|
<div id="download">
|
||||||
|
<div id="download-page-one">
|
||||||
|
<div class="title">
|
||||||
|
<span id="dl-file"
|
||||||
|
data-nonce="${fileInfo.nonce}"
|
||||||
|
data-requires-password="${fileInfo.requiresPassword}"
|
||||||
|
>${title}</span>
|
||||||
|
<span id="dl-filesize">${' ' + size}</span>
|
||||||
|
</div>
|
||||||
|
<div class="description">${state.translate('downloadMessage')}</div>
|
||||||
|
<img
|
||||||
|
src="${assets.get('illustration_download.svg')}"
|
||||||
|
id="download-img"
|
||||||
|
alt="${state.translate('downloadAltText')}"/>
|
||||||
|
${pageAction}
|
||||||
|
</div>
|
||||||
|
<a class="send-new" href="/">${state.translate('sendYourFilesLink')}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
return div;
|
||||||
|
};
|
|
@ -1,16 +1,28 @@
|
||||||
|
/* global EXPIRE_SECONDS */
|
||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
const notFound = require('./notFound');
|
const notFound = require('./notFound');
|
||||||
const uploadPassword = require('./uploadPassword');
|
const uploadPasswordSet = require('../templates/uploadPasswordSet');
|
||||||
|
const uploadPasswordUnset = require('../templates/uploadPasswordUnset');
|
||||||
|
const selectbox = require('../templates/selectbox');
|
||||||
const { allowedCopy, delay, fadeOut } = require('../utils');
|
const { allowedCopy, delay, fadeOut } = require('../utils');
|
||||||
|
|
||||||
function passwordComplete(state, password) {
|
function expireInfo(file, translate, emit) {
|
||||||
|
const hours = Math.floor(EXPIRE_SECONDS / 60 / 60);
|
||||||
const el = html([
|
const el = html([
|
||||||
`<div class="selectPassword">${state.translate('passwordResult', {
|
`<div>${translate('expireInfo', {
|
||||||
password: '<pre></pre>'
|
downloadCount: '<select></select>',
|
||||||
|
timespan: translate('timespanHours', { num: hours })
|
||||||
})}</div>`
|
})}</div>`
|
||||||
]);
|
]);
|
||||||
el.lastElementChild.textContent = password;
|
const select = el.querySelector('select');
|
||||||
|
const options = [1, 2, 3, 4, 5, 20].filter(i => i > (file.dtotal || 0));
|
||||||
|
const t = num => translate('downloadCount', { num });
|
||||||
|
const changed = value => emit('changeLimit', { file, value });
|
||||||
|
select.parentNode.replaceChild(
|
||||||
|
selectbox(file.dlimit || 1, options, t, changed),
|
||||||
|
select
|
||||||
|
);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,19 +32,16 @@ module.exports = function(state, emit) {
|
||||||
return notFound(state, emit);
|
return notFound(state, emit);
|
||||||
}
|
}
|
||||||
|
|
||||||
file.password = file.password || '';
|
const passwordSection = file.hasPassword
|
||||||
|
? uploadPasswordSet(state, emit)
|
||||||
const passwordSection = file.password
|
: uploadPasswordUnset(state, emit);
|
||||||
? passwordComplete(state, file.password)
|
|
||||||
: uploadPassword(state, emit);
|
|
||||||
const div = html`
|
const div = html`
|
||||||
<div id="share-link" class="fadeIn">
|
<div id="share-link" class="fadeIn">
|
||||||
<div class="title">${state.translate('uploadSuccessTimingHeader')}</div>
|
<div class="title">${expireInfo(file, state.translate, emit)}</div>
|
||||||
<div id="share-window">
|
<div id="share-window">
|
||||||
<div id="copy-text">
|
<div id="copy-text">
|
||||||
${state.translate('copyUrlFormLabelWithName', {
|
${state.translate('copyUrlFormLabelWithName', { filename: file.name })}
|
||||||
filename: file.name
|
</div>
|
||||||
})}</div>
|
|
||||||
<div id="copy">
|
<div id="copy">
|
||||||
<input id="link" type="url" value="${file.url}" readonly="true"/>
|
<input id="link" type="url" value="${file.url}" readonly="true"/>
|
||||||
<button id="copy-btn"
|
<button id="copy-btn"
|
||||||
|
@ -44,7 +53,22 @@ module.exports = function(state, emit) {
|
||||||
<button id="delete-file"
|
<button id="delete-file"
|
||||||
class="btn"
|
class="btn"
|
||||||
title="${state.translate('deleteFileButton')}"
|
title="${state.translate('deleteFileButton')}"
|
||||||
onclick=${deleteFile}>${state.translate('deleteFileButton')}</button>
|
onclick=${showPopup}>${state.translate('deleteFileButton')}
|
||||||
|
</button>
|
||||||
|
<div id="deletePopup" class="popup">
|
||||||
|
<div class="popuptext" onblur=${cancel} tabindex="-1">
|
||||||
|
<div class="popup-message">${state.translate('deletePopupText')}
|
||||||
|
</div>
|
||||||
|
<div class="popup-action">
|
||||||
|
<span class="popup-no" onclick=${cancel}>
|
||||||
|
${state.translate('deletePopupCancel')}
|
||||||
|
</span>
|
||||||
|
<span class="popup-yes" onclick=${deleteFile}>
|
||||||
|
${state.translate('deletePopupYes')}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<a class="send-new"
|
<a class="send-new"
|
||||||
data-state="completed"
|
data-state="completed"
|
||||||
href="/"
|
href="/"
|
||||||
|
@ -53,6 +77,18 @@ module.exports = function(state, emit) {
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
function showPopup() {
|
||||||
|
const popupText = document.querySelector('.popuptext');
|
||||||
|
popupText.classList.add('show');
|
||||||
|
popupText.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancel(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
const popupText = document.querySelector('.popuptext');
|
||||||
|
popupText.classList.remove('show');
|
||||||
|
}
|
||||||
|
|
||||||
async function sendNew(e) {
|
async function sendNew(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await fadeOut('share-link');
|
await fadeOut('share-link');
|
|
@ -0,0 +1,52 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
const assets = require('../../common/assets');
|
||||||
|
|
||||||
|
module.exports = function(state) {
|
||||||
|
const msg =
|
||||||
|
state.params.reason === 'outdated'
|
||||||
|
? html`
|
||||||
|
<div id="unsupported-browser">
|
||||||
|
<div class="title">${state.translate('notSupportedHeader')}</div>
|
||||||
|
<div class="description">
|
||||||
|
${state.translate('notSupportedOutdatedDetail')}
|
||||||
|
</div>
|
||||||
|
<a
|
||||||
|
id="update-firefox"
|
||||||
|
href="https://support.mozilla.org/kb/update-firefox-latest-version">
|
||||||
|
<img
|
||||||
|
src="${assets.get('firefox_logo-only.svg')}"
|
||||||
|
class="firefox-logo"
|
||||||
|
alt="Firefox"/>
|
||||||
|
<div class="unsupported-button-text">
|
||||||
|
${state.translate('updateFirefox')}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<div class="unsupported-description">
|
||||||
|
${state.translate('uploadPageExplainer')}
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
: html`
|
||||||
|
<div id="unsupported-browser">
|
||||||
|
<div class="title">${state.translate('notSupportedHeader')}</div>
|
||||||
|
<div class="description">${state.translate('notSupportedDetail')}</div>
|
||||||
|
<div class="description">
|
||||||
|
<a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported">
|
||||||
|
${state.translate('notSupportedLink')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com">
|
||||||
|
<img
|
||||||
|
src="${assets.get('firefox_logo-only.svg')}"
|
||||||
|
class="firefox-logo"
|
||||||
|
alt="Firefox"/>
|
||||||
|
<div class="unsupported-button-text">Firefox<br>
|
||||||
|
<span>${state.translate('downloadFirefoxButtonSub')}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<div class="unsupported-description">
|
||||||
|
${state.translate('uploadPageExplainer')}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
const div = html`<div id="page-one">${msg}</div>`;
|
||||||
|
return div;
|
||||||
|
};
|
|
@ -0,0 +1,41 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
const progress = require('../templates/progress');
|
||||||
|
const { bytes } = require('../utils');
|
||||||
|
|
||||||
|
module.exports = function(state, emit) {
|
||||||
|
const transfer = state.transfer;
|
||||||
|
|
||||||
|
const div = html`
|
||||||
|
<div id="download">
|
||||||
|
<div id="upload-progress" class="fadeIn">
|
||||||
|
<div class="title" id="upload-filename">
|
||||||
|
${state.translate('uploadingPageProgress', {
|
||||||
|
filename: transfer.file.name,
|
||||||
|
size: bytes(transfer.file.size)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div class="description"></div>
|
||||||
|
${progress(transfer.progressRatio)}
|
||||||
|
<div class="upload">
|
||||||
|
<div class="progress-text">
|
||||||
|
${state.translate(transfer.msg, transfer.sizes)}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
id="cancel-upload"
|
||||||
|
title="${state.translate('uploadingPageCancel')}"
|
||||||
|
onclick=${cancel}>
|
||||||
|
${state.translate('uploadingPageCancel')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
function cancel() {
|
||||||
|
const btn = document.getElementById('cancel-upload');
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = state.translate('uploadCancelNotification');
|
||||||
|
emit('cancel');
|
||||||
|
}
|
||||||
|
return div;
|
||||||
|
};
|
|
@ -1,8 +1,8 @@
|
||||||
|
/* global MAXFILESIZE */
|
||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
const fileList = require('./fileList');
|
const fileList = require('../templates/fileList');
|
||||||
const fxPromo = require('./fxPromo');
|
const { bytes, fadeOut } = require('../utils');
|
||||||
const { fadeOut } = require('../utils');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
const div = html`
|
const div = html`
|
||||||
|
@ -10,14 +10,18 @@ module.exports = function(state, emit) {
|
||||||
<div class="title">${state.translate('uploadPageHeader')}</div>
|
<div class="title">${state.translate('uploadPageHeader')}</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div>${state.translate('uploadPageExplainer')}</div>
|
<div>${state.translate('uploadPageExplainer')}</div>
|
||||||
<a href="https://testpilot.firefox.com/experiments/send"
|
<a
|
||||||
class="link">${state.translate('uploadPageLearnMore')}</a>
|
href="https://testpilot.firefox.com/experiments/send"
|
||||||
|
class="link">
|
||||||
|
${state.translate('uploadPageLearnMore')}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="upload-window"
|
<div class="upload-window"
|
||||||
ondragover=${dragover}
|
ondragover=${dragover}
|
||||||
ondragleave=${dragleave}>
|
ondragleave=${dragleave}>
|
||||||
<div id="upload-img">
|
<div id="upload-img">
|
||||||
<img src="${assets.get('upload.svg')}"
|
<img
|
||||||
|
src="${assets.get('upload.svg')}"
|
||||||
title="${state.translate('uploadSvgAlt')}"/>
|
title="${state.translate('uploadSvgAlt')}"/>
|
||||||
</div>
|
</div>
|
||||||
<div id="upload-text">${state.translate('uploadPageDropMessage')}</div>
|
<div id="upload-text">${state.translate('uploadPageDropMessage')}</div>
|
||||||
|
@ -34,9 +38,9 @@ module.exports = function(state, emit) {
|
||||||
id="browse"
|
id="browse"
|
||||||
class="btn browse"
|
class="btn browse"
|
||||||
title="${state.translate('uploadPageBrowseButton1')}">
|
title="${state.translate('uploadPageBrowseButton1')}">
|
||||||
${state.translate('uploadPageBrowseButton1')}</label>
|
${state.translate('uploadPageBrowseButton1')}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
|
||||||
${fileList(state, emit)}
|
${fileList(state, emit)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -66,6 +70,11 @@ module.exports = function(state, emit) {
|
||||||
if (file.size === 0) {
|
if (file.size === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (file.size > MAXFILESIZE) {
|
||||||
|
window.alert(state.translate('fileTooBig', { size: bytes(MAXFILESIZE) }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await fadeOut('page-one');
|
await fadeOut('page-one');
|
||||||
emit('upload', { file, type: 'click' });
|
emit('upload', { file, type: 'click' });
|
||||||
}
|
}
|
|
@ -1,12 +1,60 @@
|
||||||
const preview = require('../templates/preview');
|
const preview = require('../pages/preview');
|
||||||
const download = require('../templates/download');
|
const download = require('../pages/download');
|
||||||
|
const notFound = require('../pages/notFound');
|
||||||
|
const downloadPassword = require('../templates/downloadPassword');
|
||||||
|
const downloadButton = require('../templates/downloadButton');
|
||||||
|
|
||||||
|
function hasFileInfo() {
|
||||||
|
return !!document.getElementById('dl-file');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFileInfoFromDOM() {
|
||||||
|
const el = document.getElementById('dl-file');
|
||||||
|
if (!el) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
nonce: el.getAttribute('data-nonce'),
|
||||||
|
requiresPassword: !!+el.getAttribute('data-requires-password')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFileInfo(state) {
|
||||||
|
const metadata = getFileInfoFromDOM();
|
||||||
|
return {
|
||||||
|
id: state.params.id,
|
||||||
|
secretKey: state.params.key,
|
||||||
|
nonce: metadata.nonce,
|
||||||
|
requiresPassword: metadata.requiresPassword
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
|
if (!state.fileInfo) {
|
||||||
|
// This is a fresh page load
|
||||||
|
// We need to parse the file info from the server's html
|
||||||
|
if (!hasFileInfo()) {
|
||||||
|
return notFound(state, emit);
|
||||||
|
}
|
||||||
|
state.fileInfo = createFileInfo(state);
|
||||||
|
|
||||||
|
if (!state.fileInfo.requiresPassword) {
|
||||||
|
emit('getMetadata');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let pageAction = ''; //default state: we don't have file metadata
|
||||||
if (state.transfer) {
|
if (state.transfer) {
|
||||||
const s = state.transfer.state;
|
const s = state.transfer.state;
|
||||||
if (s === 'downloading' || s === 'complete') {
|
if (s === 'downloading' || s === 'complete') {
|
||||||
|
// Downloading is in progress
|
||||||
return download(state, emit);
|
return download(state, emit);
|
||||||
}
|
}
|
||||||
|
// we have file metadata
|
||||||
|
pageAction = downloadButton(state, emit);
|
||||||
|
} else if (state.fileInfo.requiresPassword && !state.fileInfo.password) {
|
||||||
|
// we're waiting on the user for a valid password
|
||||||
|
pageAction = downloadPassword(state, emit);
|
||||||
}
|
}
|
||||||
return preview(state, emit);
|
return preview(state, pageAction);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
const welcome = require('../templates/welcome');
|
const welcome = require('../pages/welcome');
|
||||||
const upload = require('../templates/upload');
|
const upload = require('../pages/upload');
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
if (state.transfer && state.transfer.iv) {
|
if (state.transfer) {
|
||||||
//TODO relying on 'iv' is gross
|
|
||||||
return upload(state, emit);
|
return upload(state, emit);
|
||||||
}
|
}
|
||||||
return welcome(state, emit);
|
return welcome(state, emit);
|
||||||
|
|
|
@ -7,22 +7,33 @@ const fxPromo = require('../templates/fxPromo');
|
||||||
|
|
||||||
const app = choo();
|
const app = choo();
|
||||||
|
|
||||||
|
function banner(state, emit) {
|
||||||
|
if (state.promo && !state.route.startsWith('/unsupported/')) {
|
||||||
|
return fxPromo(state, emit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function body(template) {
|
function body(template) {
|
||||||
return function(state, emit) {
|
return function(state, emit) {
|
||||||
const b = html`<body>
|
const b = html`<body>
|
||||||
${state.promo === 'header' ? fxPromo(state, emit) : ''}
|
${banner(state, emit)}
|
||||||
${header(state)}
|
${header(state)}
|
||||||
<div class="all">
|
<div class="all">
|
||||||
<noscript>
|
<noscript>
|
||||||
<h2>Firefox Send requires JavaScript</h2>
|
<h2>${state.translate('javascriptRequired')}</h2>
|
||||||
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
|
<p>
|
||||||
<p>Please enable JavaScript and try again.</p>
|
<a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">
|
||||||
|
${state.translate('whyJavascript')}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>${state.translate('enableJavascript')}</p>
|
||||||
</noscript>
|
</noscript>
|
||||||
${template(state, emit)}
|
${template(state, emit)}
|
||||||
</div>
|
</div>
|
||||||
${footer(state)}
|
${footer(state)}
|
||||||
</body>`;
|
</body>`;
|
||||||
if (state.layout) {
|
if (state.layout) {
|
||||||
|
// server side only
|
||||||
return state.layout(state, b);
|
return state.layout(state, b);
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
|
@ -30,14 +41,14 @@ function body(template) {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.route('/', body(require('./home')));
|
app.route('/', body(require('./home')));
|
||||||
app.route('/share/:id', body(require('../templates/share')));
|
app.route('/share/:id', body(require('../pages/share')));
|
||||||
app.route('/download/:id', body(download));
|
app.route('/download/:id', body(download));
|
||||||
app.route('/download/:id/:key', body(download));
|
app.route('/download/:id/:key', body(download));
|
||||||
app.route('/completed', body(require('../templates/completed')));
|
app.route('/completed', body(require('../pages/completed')));
|
||||||
app.route('/unsupported/:reason', body(require('../templates/unsupported')));
|
app.route('/unsupported/:reason', body(require('../pages/unsupported')));
|
||||||
app.route('/legal', body(require('../templates/legal')));
|
app.route('/legal', body(require('../pages/legal')));
|
||||||
app.route('/error', body(require('../templates/error')));
|
app.route('/error', body(require('../pages/error')));
|
||||||
app.route('/blank', body(require('../templates/blank')));
|
app.route('/blank', body(require('../pages/blank')));
|
||||||
app.route('*', body(require('../templates/notFound')));
|
app.route('*', body(require('../pages/notFound')));
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { isFile } from './utils';
|
import { isFile } from './utils';
|
||||||
|
import OwnedFile from './ownedFile';
|
||||||
|
|
||||||
class Mem {
|
class Mem {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -42,7 +43,7 @@ class Storage {
|
||||||
const k = this.engine.key(i);
|
const k = this.engine.key(i);
|
||||||
if (isFile(k)) {
|
if (isFile(k)) {
|
||||||
try {
|
try {
|
||||||
const f = JSON.parse(this.engine.getItem(k));
|
const f = new OwnedFile(JSON.parse(this.engine.getItem(k)));
|
||||||
if (!f.id) {
|
if (!f.id) {
|
||||||
f.id = f.fileId;
|
f.id = f.fileId;
|
||||||
}
|
}
|
||||||
|
@ -108,11 +109,15 @@ class Storage {
|
||||||
|
|
||||||
addFile(file) {
|
addFile(file) {
|
||||||
this._files.push(file);
|
this._files.push(file);
|
||||||
|
this.writeFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFile(file) {
|
||||||
this.engine.setItem(file.id, JSON.stringify(file));
|
this.engine.setItem(file.id, JSON.stringify(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFiles() {
|
writeFiles() {
|
||||||
this._files.forEach(f => this.engine.setItem(f.id, JSON.stringify(f)));
|
this._files.forEach(f => this.writeFile(f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const progress = require('./progress');
|
|
||||||
const { fadeOut } = require('../utils');
|
|
||||||
const fxPromo = require('./fxPromo');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const div = html`
|
|
||||||
<div id="page-one">
|
|
||||||
<div id="download" class="fadeIn">
|
|
||||||
<div id="download-progress">
|
|
||||||
<div id="dl-title" class="title">${state.translate(
|
|
||||||
'downloadFinish'
|
|
||||||
)}</div>
|
|
||||||
<div class="description"></div>
|
|
||||||
${progress(1)}
|
|
||||||
<div class="upload">
|
|
||||||
<div class="progress-text"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<a class="send-new" data-state="completed" href="/" onclick=${
|
|
||||||
sendNew
|
|
||||||
}>${state.translate('sendYourFilesLink')}</a>
|
|
||||||
</div>
|
|
||||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
async function sendNew(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
await fadeOut('download');
|
|
||||||
emit('pushState', '/');
|
|
||||||
}
|
|
||||||
|
|
||||||
return div;
|
|
||||||
};
|
|
|
@ -1,32 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const progress = require('./progress');
|
|
||||||
const { bytes } = require('../utils');
|
|
||||||
const fxPromo = require('./fxPromo');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const transfer = state.transfer;
|
|
||||||
const div = html`
|
|
||||||
<div id="page-one">
|
|
||||||
<div id="download-progress" class="fadeIn">
|
|
||||||
<div id="dl-title" class="title">${state.translate(
|
|
||||||
'downloadingPageProgress',
|
|
||||||
{
|
|
||||||
filename: state.fileInfo.name,
|
|
||||||
size: bytes(state.fileInfo.size)
|
|
||||||
}
|
|
||||||
)}</div>
|
|
||||||
<div class="description">${state.translate('downloadingPageMessage')}</div>
|
|
||||||
${progress(transfer.progressRatio)}
|
|
||||||
<div class="upload">
|
|
||||||
<div class="progress-text">${state.translate(
|
|
||||||
transfer.msg,
|
|
||||||
transfer.sizes
|
|
||||||
)}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
return div;
|
|
||||||
};
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
|
||||||
|
module.exports = function(state, emit) {
|
||||||
|
function download(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
emit('download', state.fileInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<button id="download-btn"
|
||||||
|
class="btn"
|
||||||
|
onclick=${download}>${state.translate('downloadButtonLabel')}
|
||||||
|
</button>
|
||||||
|
</div>`;
|
||||||
|
};
|
|
@ -5,8 +5,9 @@ module.exports = function(state, emit) {
|
||||||
const label =
|
const label =
|
||||||
fileInfo.password === null
|
fileInfo.password === null
|
||||||
? html`
|
? html`
|
||||||
<label class="red"
|
<label class="red" for="unlock-input">
|
||||||
for="unlock-input">${state.translate('passwordTryAgain')}</label>`
|
${state.translate('passwordTryAgain')}
|
||||||
|
</label>`
|
||||||
: html`
|
: html`
|
||||||
<label for="unlock-input">
|
<label for="unlock-input">
|
||||||
${state.translate('unlockInputLabel')}
|
${state.translate('unlockInputLabel')}
|
||||||
|
@ -48,7 +49,7 @@ module.exports = function(state, emit) {
|
||||||
document.getElementById('unlock-btn').disabled = true;
|
document.getElementById('unlock-btn').disabled = true;
|
||||||
state.fileInfo.url = window.location.href;
|
state.fileInfo.url = window.location.href;
|
||||||
state.fileInfo.password = password;
|
state.fileInfo.password = password;
|
||||||
emit('preview');
|
emit('getMetadata');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,62 @@
|
||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
|
|
||||||
function timeLeft(milliseconds) {
|
function timeLeft(milliseconds, state) {
|
||||||
const minutes = Math.floor(milliseconds / 1000 / 60);
|
const minutes = Math.floor(milliseconds / 1000 / 60);
|
||||||
const hours = Math.floor(minutes / 60);
|
const hours = Math.floor(minutes / 60);
|
||||||
const seconds = Math.floor((milliseconds / 1000) % 60);
|
|
||||||
if (hours >= 1) {
|
if (hours >= 1) {
|
||||||
return `${hours}h ${minutes % 60}m`;
|
return state.translate('expiresHoursMinutes', {
|
||||||
|
hours,
|
||||||
|
minutes: minutes % 60
|
||||||
|
});
|
||||||
} else if (hours === 0) {
|
} else if (hours === 0) {
|
||||||
return `${minutes}m ${seconds}s`;
|
if (minutes === 0) {
|
||||||
|
return state.translate('expiresMinutes', { minutes: '< 1' });
|
||||||
|
}
|
||||||
|
return state.translate('expiresMinutes', { minutes });
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(file, state, emit) {
|
module.exports = function(file, state, emit) {
|
||||||
const ttl = file.expiresAt - Date.now();
|
const ttl = file.expiresAt - Date.now();
|
||||||
const remaining = timeLeft(ttl) || state.translate('linkExpiredAlt');
|
const remainingTime =
|
||||||
|
timeLeft(ttl, state) || state.translate('linkExpiredAlt');
|
||||||
|
const downloadLimit = file.dlimit || 1;
|
||||||
|
const totalDownloads = file.dtotal || 0;
|
||||||
const row = html`
|
const row = html`
|
||||||
<tr id="${file.id}">
|
<tr id="${file.id}">
|
||||||
<td class="overflow-col" title="${file.name}">${file.name}</td>
|
<td class="overflow-col" title="${file.name}">
|
||||||
<td class="center-col">
|
<a class="link" href="/share/${file.id}">${file.name}</a>
|
||||||
<img onclick=${copyClick} src="${assets.get(
|
|
||||||
'copy-16.svg'
|
|
||||||
)}" class="icon-copy" title="${state.translate('copyUrlHover')}">
|
|
||||||
<span class="text-copied" hidden="true">${state.translate(
|
|
||||||
'copiedUrl'
|
|
||||||
)}</span>
|
|
||||||
</td>
|
</td>
|
||||||
<td>${remaining}</td>
|
|
||||||
<td class="center-col">
|
<td class="center-col">
|
||||||
<img onclick=${showPopup} src="${assets.get(
|
<img
|
||||||
'close-16.svg'
|
onclick=${copyClick}
|
||||||
)}" class="icon-delete" title="${state.translate('deleteButtonHover')}">
|
src="${assets.get('copy-16.svg')}"
|
||||||
|
class="icon-copy"
|
||||||
|
title="${state.translate('copyUrlHover')}">
|
||||||
|
<span class="text-copied" hidden="true">
|
||||||
|
${state.translate('copiedUrl')}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>${remainingTime}</td>
|
||||||
|
<td class="center-col">${totalDownloads} / ${downloadLimit}</td>
|
||||||
|
<td class="center-col">
|
||||||
|
<img
|
||||||
|
onclick=${showPopup}
|
||||||
|
src="${assets.get('close-16.svg')}"
|
||||||
|
class="icon-delete"
|
||||||
|
title="${state.translate('deleteButtonHover')}">
|
||||||
<div class="popup">
|
<div class="popup">
|
||||||
<div class="popuptext" onblur=${cancel} tabindex="-1">
|
<div class="popuptext" onblur=${cancel} tabindex="-1">
|
||||||
<div class="popup-message">${state.translate('deletePopupText')}</div>
|
<div class="popup-message">${state.translate('deletePopupText')}</div>
|
||||||
<div class="popup-action">
|
<div class="popup-action">
|
||||||
<span class="popup-no" onclick=${cancel}>${state.translate(
|
<span class="popup-no" onclick=${cancel}>
|
||||||
'deletePopupCancel'
|
${state.translate('deletePopupCancel')}
|
||||||
)}</span>
|
</span>
|
||||||
<span class="popup-yes" onclick=${deleteFile}>${state.translate(
|
<span class="popup-yes" onclick=${deleteFile}>
|
||||||
'deletePopupYes'
|
${state.translate('deletePopupYes')}
|
||||||
)}</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,13 +9,18 @@ module.exports = function(state, emit) {
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th id="uploaded-file">${state.translate('uploadedFile')}</th>
|
<th id="uploaded-file">${state.translate('uploadedFile')}</th>
|
||||||
<th id="copy-file-list" class="center-col">${state.translate(
|
<th id="copy-file-list" class="center-col">
|
||||||
'copyFileList'
|
${state.translate('copyFileList')}
|
||||||
)}</th>
|
</th>
|
||||||
<th id="expiry-file-list">${state.translate('expiryFileList')}</th>
|
<th id="expiry-time-file-list" >
|
||||||
<th id="delete-file-list" class="center-col">${state.translate(
|
${state.translate('timeFileList')}
|
||||||
'deleteFileList'
|
</th>
|
||||||
)}</th>
|
<th id="expiry-downloads-file-list" >
|
||||||
|
${state.translate('downloadsFileList')}
|
||||||
|
</th>
|
||||||
|
<th id="delete-file-list" class="center-col">
|
||||||
|
${state.translate('deleteFileList')}
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -4,28 +4,40 @@ const assets = require('../../common/assets');
|
||||||
module.exports = function(state) {
|
module.exports = function(state) {
|
||||||
return html`<div class="footer">
|
return html`<div class="footer">
|
||||||
<div class="legal-links">
|
<div class="legal-links">
|
||||||
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
|
<a href="https://www.mozilla.org" role="presentation">
|
||||||
'mozilla-logo.svg'
|
<img
|
||||||
)}" alt="mozilla"/></a>
|
class="mozilla-logo"
|
||||||
<a href="https://www.mozilla.org/about/legal">${state.translate(
|
src="${assets.get('mozilla-logo.svg')}"
|
||||||
'footerLinkLegal'
|
alt="mozilla"/>
|
||||||
)}</a>
|
</a>
|
||||||
<a href="https://testpilot.firefox.com/about">${state.translate(
|
<a href="https://www.mozilla.org/about/legal">
|
||||||
'footerLinkAbout'
|
${state.translate('footerLinkLegal')}
|
||||||
)}</a>
|
</a>
|
||||||
|
<a href="https://testpilot.firefox.com/about">
|
||||||
|
${state.translate('footerLinkAbout')}
|
||||||
|
</a>
|
||||||
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
|
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
|
||||||
<a href="/legal">${state.translate('footerLinkTerms')}</a>
|
<a href="/legal">${state.translate('footerLinkTerms')}</a>
|
||||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
|
<a href="https://www.mozilla.org/privacy/websites/#cookies">
|
||||||
'footerLinkCookies'
|
${state.translate('footerLinkCookies')}
|
||||||
)}</a>
|
</a>
|
||||||
|
<a href="https://www.mozilla.org/about/legal/report-infringement/">
|
||||||
|
${state.translate('reportIPInfringement')}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="social-links">
|
<div class="social-links">
|
||||||
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
|
<a href="https://github.com/mozilla/send" role="presentation">
|
||||||
'github-icon.svg'
|
<img
|
||||||
)}" alt="github"/></a>
|
class="github"
|
||||||
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
|
src="${assets.get('github-icon.svg')}"
|
||||||
'twitter-icon.svg'
|
alt="github"/>
|
||||||
)}" alt="twitter"/></a>
|
</a>
|
||||||
|
<a href="https://twitter.com/FxTestPilot" role="presentation">
|
||||||
|
<img
|
||||||
|
class="twitter"
|
||||||
|
src="${assets.get('twitter-icon.svg')}"
|
||||||
|
alt="twitter"/>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,26 +1,22 @@
|
||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
|
|
||||||
// function replaceLinks(str, urls) {
|
|
||||||
// let i = -1;
|
|
||||||
// const s = str.replace(/<a>([^<]+)<\/a>/g, (m, v) => {
|
|
||||||
// i++;
|
|
||||||
// return `<a class="link" href="${urls[i]}">${v}</a>`;
|
|
||||||
// });
|
|
||||||
// return [`<span>${s}</span>`];
|
|
||||||
// }
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
// function close() {
|
function clicked() {
|
||||||
// document.querySelector('.banner').remove();
|
emit('experiment', { cd3: 'promo' });
|
||||||
// }
|
}
|
||||||
|
let classes = 'banner';
|
||||||
function clicked(evt) {
|
switch (state.promo) {
|
||||||
emit('exit', evt);
|
case 'blue':
|
||||||
|
classes = 'banner banner-blue';
|
||||||
|
break;
|
||||||
|
case 'pink':
|
||||||
|
classes = 'banner banner-pink';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="banner">
|
<div class="${classes}">
|
||||||
<div>
|
<div>
|
||||||
<img
|
<img
|
||||||
src="${assets.get('firefox_logo-only.svg')}"
|
src="${assets.get('firefox_logo-only.svg')}"
|
||||||
|
@ -35,10 +31,3 @@ module.exports = function(state, emit) {
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
<img
|
|
||||||
src="${assets.get('close-16.svg')}"
|
|
||||||
class="icon-delete"
|
|
||||||
onclick=${close}>
|
|
||||||
*/
|
|
||||||
|
|
|
@ -1,21 +1,59 @@
|
||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
|
/*
|
||||||
|
The current weback config uses package.json to generate
|
||||||
|
version.json for /__version__ meaning `require` returns the
|
||||||
|
string 'version.json' in the frontend context but the json
|
||||||
|
on the server.
|
||||||
|
|
||||||
|
We want `version` to be constant at build time so this file
|
||||||
|
has a custom loader (/build/version_loader.js) just to replace
|
||||||
|
string with the value from package.json. 🤢
|
||||||
|
*/
|
||||||
|
const version = require('../../package.json').version || 'VERSION';
|
||||||
|
|
||||||
|
function browserName() {
|
||||||
|
try {
|
||||||
|
if (/firefox/i.test(navigator.userAgent)) {
|
||||||
|
return 'firefox';
|
||||||
|
}
|
||||||
|
if (/edge/i.test(navigator.userAgent)) {
|
||||||
|
return 'edge';
|
||||||
|
}
|
||||||
|
if (/trident/i.test(navigator.userAgent)) {
|
||||||
|
return 'ie';
|
||||||
|
}
|
||||||
|
if (/chrome/i.test(navigator.userAgent)) {
|
||||||
|
return 'chrome';
|
||||||
|
}
|
||||||
|
if (/safari/i.test(navigator.userAgent)) {
|
||||||
|
return 'safari';
|
||||||
|
}
|
||||||
|
return 'other';
|
||||||
|
} catch (e) {
|
||||||
|
return 'unknown';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const browser = browserName();
|
||||||
|
|
||||||
module.exports = function(state) {
|
module.exports = function(state) {
|
||||||
return html`<header class="header">
|
return html`<header class="header">
|
||||||
<div class="send-logo">
|
<div class="send-logo">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="${assets.get(
|
<img
|
||||||
'send_logo.svg'
|
src="${assets.get('send_logo.svg')}"
|
||||||
)}" alt="Send"/><h1 class="site-title">Send</h1>
|
alt="Send"/>
|
||||||
|
<h1 class="site-title">Send</h1>
|
||||||
</a>
|
</a>
|
||||||
<div class="site-subtitle">
|
<div class="site-subtitle">
|
||||||
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
||||||
<div>${state.translate('siteSubtitle')}</div>
|
<div>${state.translate('siteSubtitle')}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
|
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}"
|
||||||
'siteFeedback'
|
rel="noreferrer noopener"
|
||||||
)}</a>
|
class="feedback"
|
||||||
|
target="_blank">${state.translate('siteFeedback')}</a>
|
||||||
</header>`;
|
</header>`;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../common/assets');
|
|
||||||
const notFound = require('./notFound');
|
|
||||||
const downloadPassword = require('./downloadPassword');
|
|
||||||
const { bytes } = require('../utils');
|
|
||||||
const fxPromo = require('./fxPromo');
|
|
||||||
|
|
||||||
function getFileFromDOM() {
|
|
||||||
const el = document.getElementById('dl-file');
|
|
||||||
if (!el) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
nonce: el.getAttribute('data-nonce'),
|
|
||||||
pwd: !!+el.getAttribute('data-requires-password')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
state.fileInfo = state.fileInfo || getFileFromDOM();
|
|
||||||
if (!state.fileInfo) {
|
|
||||||
return notFound(state, emit);
|
|
||||||
}
|
|
||||||
state.fileInfo.id = state.params.id;
|
|
||||||
state.fileInfo.key = state.params.key;
|
|
||||||
const fileInfo = state.fileInfo;
|
|
||||||
const size = fileInfo.size
|
|
||||||
? state.translate('downloadFileSize', { size: bytes(fileInfo.size) })
|
|
||||||
: '';
|
|
||||||
let action = html`
|
|
||||||
<div>
|
|
||||||
<img src="${assets.get('illustration_download.svg')}"
|
|
||||||
id="download-img"
|
|
||||||
alt="${state.translate('downloadAltText')}"/>
|
|
||||||
<div>
|
|
||||||
<button id="download-btn"
|
|
||||||
class="btn"
|
|
||||||
onclick=${download}>${state.translate('downloadButtonLabel')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
if (fileInfo.pwd && !fileInfo.password) {
|
|
||||||
action = downloadPassword(state, emit);
|
|
||||||
} else if (!state.transfer) {
|
|
||||||
emit('preview');
|
|
||||||
}
|
|
||||||
const title = fileInfo.name
|
|
||||||
? state.translate('downloadFileName', { filename: fileInfo.name })
|
|
||||||
: state.translate('downloadFileTitle');
|
|
||||||
const div = html`
|
|
||||||
<div id="page-one">
|
|
||||||
<div id="download">
|
|
||||||
<div id="download-page-one">
|
|
||||||
<div class="title">
|
|
||||||
<span id="dl-file"
|
|
||||||
data-nonce="${fileInfo.nonce}"
|
|
||||||
data-requires-password="${fileInfo.pwd}">${title}</span>
|
|
||||||
<span id="dl-filesize">${' ' + size}</span>
|
|
||||||
</div>
|
|
||||||
<div class="description">${state.translate('downloadMessage')}</div>
|
|
||||||
${action}
|
|
||||||
</div>
|
|
||||||
<a class="send-new" href="/">${state.translate('sendYourFilesLink')}</a>
|
|
||||||
</div>
|
|
||||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
function download(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
emit('download', fileInfo);
|
|
||||||
}
|
|
||||||
return div;
|
|
||||||
};
|
|
|
@ -10,18 +10,30 @@ module.exports = function(progressRatio) {
|
||||||
const percent = Math.floor(progressRatio * 100);
|
const percent = Math.floor(progressRatio * 100);
|
||||||
const div = html`
|
const div = html`
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<svg id="progress" width="${oDiameter}" height="${
|
<svg
|
||||||
oDiameter
|
id="progress"
|
||||||
}" viewPort="0 0 ${oDiameter} ${oDiameter}" version="1.1">
|
width="${oDiameter}"
|
||||||
<circle r="${radius}" cx="${oRadius}" cy="${oRadius}" fill="transparent"/>
|
height="${oDiameter}"
|
||||||
<circle id="bar" r="${radius}" cx="${oRadius}" cy="${
|
viewPort="0 0 ${oDiameter} ${oDiameter}"
|
||||||
oRadius
|
version="1.1">
|
||||||
}" fill="transparent" transform="rotate(-90 ${oRadius} ${
|
<circle
|
||||||
oRadius
|
r="${radius}"
|
||||||
})" stroke-dasharray="${circumference}" stroke-dashoffset="${dashOffset}"/>
|
cx="${oRadius}"
|
||||||
<text class="percentage" text-anchor="middle" x="50%" y="98"><tspan class="percent-number">${
|
cy="${oRadius}"
|
||||||
percent
|
fill="transparent"/>
|
||||||
}</tspan><tspan class="percent-sign">%</tspan></text>
|
<circle
|
||||||
|
id="bar"
|
||||||
|
r="${radius}"
|
||||||
|
cx="${oRadius}"
|
||||||
|
cy="${oRadius}"
|
||||||
|
fill="transparent"
|
||||||
|
transform="rotate(-90 ${oRadius} ${oRadius})"
|
||||||
|
stroke-dasharray="${circumference}"
|
||||||
|
stroke-dashoffset="${dashOffset}"/>
|
||||||
|
<text class="percentage" text-anchor="middle" x="50%" y="98">
|
||||||
|
<tspan class="percent-number">${percent}</tspan>
|
||||||
|
<tspan class="percent-sign">%</tspan>
|
||||||
|
</text>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
|
||||||
|
module.exports = function(selected, options, translate, changed) {
|
||||||
|
const id = `select-${Math.random()}`;
|
||||||
|
let x = selected;
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
const ul = document.getElementById(id);
|
||||||
|
const body = document.querySelector('body');
|
||||||
|
ul.classList.remove('active');
|
||||||
|
body.removeEventListener('click', close);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const ul = document.getElementById(id);
|
||||||
|
if (ul.classList.contains('active')) {
|
||||||
|
close();
|
||||||
|
} else {
|
||||||
|
ul.classList.add('active');
|
||||||
|
const body = document.querySelector('body');
|
||||||
|
body.addEventListener('click', close);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function choose(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const target = event.target;
|
||||||
|
const value = +target.dataset.value;
|
||||||
|
target.parentNode.previousSibling.firstElementChild.textContent = translate(
|
||||||
|
value
|
||||||
|
);
|
||||||
|
if (x !== value) {
|
||||||
|
x = value;
|
||||||
|
changed(value);
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<div class="selectbox">
|
||||||
|
<div onclick=${toggle}>
|
||||||
|
<span class="link">${translate(selected)}</span>
|
||||||
|
<svg width="32" height="32">
|
||||||
|
<polygon points="8 18 17 28 26 18" fill="#0094fb"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<ul id="${id}" class="selectOptions">
|
||||||
|
${options.map(
|
||||||
|
i =>
|
||||||
|
html`<li class="selectOption" onclick=${choose} data-value="${i}">${i}</li>`
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</div>`;
|
||||||
|
};
|
|
@ -1,46 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const assets = require('../../common/assets');
|
|
||||||
|
|
||||||
module.exports = function(state) {
|
|
||||||
const msg =
|
|
||||||
state.params.reason === 'outdated'
|
|
||||||
? html`
|
|
||||||
<div id="unsupported-browser">
|
|
||||||
<div class="title">${state.translate('notSupportedHeader')}</div>
|
|
||||||
<div class="description">${state.translate(
|
|
||||||
'notSupportedOutdatedDetail'
|
|
||||||
)}</div>
|
|
||||||
<a id="update-firefox" href="https://support.mozilla.org/kb/update-firefox-latest-version">
|
|
||||||
<img src="${assets.get(
|
|
||||||
'firefox_logo-only.svg'
|
|
||||||
)}" class="firefox-logo" alt="Firefox"/>
|
|
||||||
<div class="unsupported-button-text">${state.translate(
|
|
||||||
'updateFirefox'
|
|
||||||
)}</div>
|
|
||||||
</a>
|
|
||||||
<div class="unsupported-description">${state.translate(
|
|
||||||
'uploadPageExplainer'
|
|
||||||
)}</div>
|
|
||||||
</div>`
|
|
||||||
: html`
|
|
||||||
<div id="unsupported-browser">
|
|
||||||
<div class="title">${state.translate('notSupportedHeader')}</div>
|
|
||||||
<div class="description">${state.translate('notSupportedDetail')}</div>
|
|
||||||
<div class="description"><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported">${state.translate(
|
|
||||||
'notSupportedLink'
|
|
||||||
)}</a></div>
|
|
||||||
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2">
|
|
||||||
<img src="${assets.get(
|
|
||||||
'firefox_logo-only.svg'
|
|
||||||
)}" class="firefox-logo" alt="Firefox"/>
|
|
||||||
<div class="unsupported-button-text">Firefox<br>
|
|
||||||
<span>${state.translate('downloadFirefoxButtonSub')}</span>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<div class="unsupported-description">${state.translate(
|
|
||||||
'uploadPageExplainer'
|
|
||||||
)}</div>
|
|
||||||
</div>`;
|
|
||||||
const div = html`<div id="page-one">${msg}</div>`;
|
|
||||||
return div;
|
|
||||||
};
|
|
|
@ -1,38 +0,0 @@
|
||||||
const html = require('choo/html');
|
|
||||||
const progress = require('./progress');
|
|
||||||
const { bytes } = require('../utils');
|
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
|
||||||
const transfer = state.transfer;
|
|
||||||
|
|
||||||
const div = html`
|
|
||||||
<div id="upload-progress" class="fadeIn">
|
|
||||||
<div class="title" id="upload-filename">${state.translate(
|
|
||||||
'uploadingPageProgress',
|
|
||||||
{
|
|
||||||
filename: transfer.file.name,
|
|
||||||
size: bytes(transfer.file.size)
|
|
||||||
}
|
|
||||||
)}</div>
|
|
||||||
<div class="description"></div>
|
|
||||||
${progress(transfer.progressRatio)}
|
|
||||||
<div class="upload">
|
|
||||||
<div class="progress-text">${state.translate(
|
|
||||||
transfer.msg,
|
|
||||||
transfer.sizes
|
|
||||||
)}</div>
|
|
||||||
<button id="cancel-upload" title="${state.translate(
|
|
||||||
'uploadingPageCancel'
|
|
||||||
)}" onclick=${cancel}>${state.translate('uploadingPageCancel')}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
function cancel() {
|
|
||||||
const btn = document.getElementById('cancel-upload');
|
|
||||||
btn.disabled = true;
|
|
||||||
btn.textContent = state.translate('uploadCancelNotification');
|
|
||||||
emit('cancel');
|
|
||||||
}
|
|
||||||
return div;
|
|
||||||
};
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
const html = require('choo/html');
|
||||||
|
|
||||||
|
module.exports = function(state, emit) {
|
||||||
|
const file = state.storage.getFileById(state.params.id);
|
||||||
|
|
||||||
|
return html`<div class="selectPassword">
|
||||||
|
${passwordSpan(file.password)}
|
||||||
|
<button
|
||||||
|
id="resetButton"
|
||||||
|
onclick=${toggleResetInput}
|
||||||
|
>${state.translate('changePasswordButton')}</button>
|
||||||
|
<form
|
||||||
|
id='reset-form'
|
||||||
|
class="setPassword hidden"
|
||||||
|
onsubmit=${resetPassword}
|
||||||
|
data-no-csrf>
|
||||||
|
<input id="unlock-reset-input"
|
||||||
|
class="unlock-input input-no-btn"
|
||||||
|
maxlength="32"
|
||||||
|
autocomplete="off"
|
||||||
|
type="password"
|
||||||
|
oninput=${inputChanged}
|
||||||
|
placeholder="${state.translate('unlockInputPlaceholder')}">
|
||||||
|
<input type="submit"
|
||||||
|
id="unlock-reset-btn"
|
||||||
|
class="btn btn-hidden"
|
||||||
|
value="${state.translate('changePasswordButton')}"/>
|
||||||
|
</form>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
function passwordSpan(password) {
|
||||||
|
password = password || '●●●●●';
|
||||||
|
const span = html([
|
||||||
|
`<span>${state.translate('passwordResult', {
|
||||||
|
password:
|
||||||
|
'<pre class="passwordOriginal"></pre><pre class="passwordMask"></pre>'
|
||||||
|
})}</span>`
|
||||||
|
]);
|
||||||
|
const og = span.querySelector('.passwordOriginal');
|
||||||
|
const masked = span.querySelector('.passwordMask');
|
||||||
|
og.textContent = password;
|
||||||
|
masked.textContent = password.replace(/./g, '●');
|
||||||
|
return span;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inputChanged() {
|
||||||
|
const resetInput = document.getElementById('unlock-reset-input');
|
||||||
|
const resetBtn = document.getElementById('unlock-reset-btn');
|
||||||
|
if (resetInput.value.length > 0) {
|
||||||
|
resetBtn.classList.remove('btn-hidden');
|
||||||
|
resetInput.classList.remove('input-no-btn');
|
||||||
|
} else {
|
||||||
|
resetBtn.classList.add('btn-hidden');
|
||||||
|
resetInput.classList.add('input-no-btn');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetPassword(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const password = document.querySelector('#unlock-reset-input').value;
|
||||||
|
if (password.length > 0) {
|
||||||
|
document.getElementById('copy').classList.remove('wait-password');
|
||||||
|
document.getElementById('copy-btn').disabled = false;
|
||||||
|
emit('password', { password, file });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleResetInput(event) {
|
||||||
|
const form = event.target.parentElement.querySelector('form');
|
||||||
|
const input = document.getElementById('unlock-reset-input');
|
||||||
|
if (form.style.visibility === 'hidden' || form.style.visibility === '') {
|
||||||
|
form.style.visibility = 'visible';
|
||||||
|
input.focus();
|
||||||
|
} else {
|
||||||
|
form.style.visibility = 'hidden';
|
||||||
|
}
|
||||||
|
inputChanged();
|
||||||
|
}
|
||||||
|
};
|
|
@ -5,18 +5,22 @@ module.exports = function(state, emit) {
|
||||||
const div = html`
|
const div = html`
|
||||||
<div class="selectPassword">
|
<div class="selectPassword">
|
||||||
<div id="addPasswordWrapper">
|
<div id="addPasswordWrapper">
|
||||||
<input id="addPassword" type="checkbox" autocomplete="off" onchange=${
|
<input
|
||||||
togglePasswordInput
|
id="addPassword"
|
||||||
}/>
|
type="checkbox"
|
||||||
|
autocomplete="off"
|
||||||
|
onchange=${togglePasswordInput}/>
|
||||||
<label for="addPassword">
|
<label for="addPassword">
|
||||||
${state.translate('requirePasswordCheckbox')}</label>
|
${state.translate('requirePasswordCheckbox')}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<form class="setPassword hidden" onsubmit=${setPassword} data-no-csrf>
|
<form class="setPassword hidden" onsubmit=${setPassword} data-no-csrf>
|
||||||
<input id="unlock-input"
|
<input id="unlock-input"
|
||||||
class="unlock-input input-no-btn"
|
class="unlock-input input-no-btn"
|
||||||
maxlength="64"
|
maxlength="32"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
placeholder="${state.translate('unlockInputPlaceholder')}"
|
placeholder="${state.translate('unlockInputPlaceholder')}"
|
||||||
|
type="password"
|
||||||
oninput=${inputChanged}/>
|
oninput=${inputChanged}/>
|
||||||
<input type="submit"
|
<input type="submit"
|
||||||
id="unlock-btn"
|
id="unlock-btn"
|
51
app/utils.js
51
app/utils.js
|
@ -15,21 +15,6 @@ function b64ToArray(str) {
|
||||||
return b64.toByteArray(str);
|
return b64.toByteArray(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
function notify(str) {
|
|
||||||
return str;
|
|
||||||
/* TODO: enable once we have an opt-in ui element
|
|
||||||
if (!('Notification' in window)) {
|
|
||||||
return;
|
|
||||||
} else if (Notification.permission === 'granted') {
|
|
||||||
new Notification(str);
|
|
||||||
} else if (Notification.permission !== 'denied') {
|
|
||||||
Notification.requestPermission(function(permission) {
|
|
||||||
if (permission === 'granted') new Notification(str);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadShim(polyfill) {
|
function loadShim(polyfill) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const shim = document.createElement('script');
|
const shim = document.createElement('script');
|
||||||
|
@ -148,7 +133,37 @@ function fadeOut(id) {
|
||||||
return delay(300);
|
return delay(300);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ONE_DAY_IN_MS = 86400000;
|
function saveFile(file) {
|
||||||
|
const dataView = new DataView(file.plaintext);
|
||||||
|
const blob = new Blob([dataView], { type: file.type });
|
||||||
|
const downloadUrl = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
if (window.navigator.msSaveBlob) {
|
||||||
|
return window.navigator.msSaveBlob(blob, file.name);
|
||||||
|
}
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = downloadUrl;
|
||||||
|
a.download = file.name;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(downloadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openLinksInNewTab(links, should = true) {
|
||||||
|
links = links || Array.from(document.querySelectorAll('a:not([target])'));
|
||||||
|
if (should) {
|
||||||
|
links.forEach(l => {
|
||||||
|
l.setAttribute('target', '_blank');
|
||||||
|
l.setAttribute('rel', 'noopener noreferrer');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
links.forEach(l => {
|
||||||
|
l.removeAttribute('target');
|
||||||
|
l.removeAttribute('rel');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fadeOut,
|
fadeOut,
|
||||||
|
@ -159,8 +174,8 @@ module.exports = {
|
||||||
copyToClipboard,
|
copyToClipboard,
|
||||||
arrayToB64,
|
arrayToB64,
|
||||||
b64ToArray,
|
b64ToArray,
|
||||||
notify,
|
|
||||||
canHasSend,
|
canHasSend,
|
||||||
isFile,
|
isFile,
|
||||||
ONE_DAY_IN_MS
|
saveFile,
|
||||||
|
openLinksInNewTab
|
||||||
};
|
};
|
||||||
|
|
159
assets/main.css
159
assets/main.css
|
@ -146,6 +146,8 @@ button {
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
@ -226,7 +228,6 @@ a {
|
||||||
|
|
||||||
.upload-window.ondrag {
|
.upload-window.ondrag {
|
||||||
border: 5px dashed rgba(0, 148, 251, 0.5);
|
border: 5px dashed rgba(0, 148, 251, 0.5);
|
||||||
margin: 0 auto;
|
|
||||||
height: 251px;
|
height: 251px;
|
||||||
transform: scale(1.04);
|
transform: scale(1.04);
|
||||||
border-radius: 4.2px;
|
border-radius: 4.2px;
|
||||||
|
@ -237,6 +238,10 @@ a {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.upload-window.ondrag * {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
color: #0094fb;
|
color: #0094fb;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
@ -337,10 +342,14 @@ tbody {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
#expiry-file-list {
|
#expiry-time-file-list {
|
||||||
width: 21%;
|
width: 21%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#expiry-downloads-file-list {
|
||||||
|
width: 8%;
|
||||||
|
}
|
||||||
|
|
||||||
#delete-file-list {
|
#delete-file-list {
|
||||||
width: 12%;
|
width: 12%;
|
||||||
}
|
}
|
||||||
|
@ -413,6 +422,8 @@ tbody {
|
||||||
border-radius: 0 0 5px;
|
border-radius: 0 0 5px;
|
||||||
border-right: 1px solid #d7d7db;
|
border-right: 1px solid #d7d7db;
|
||||||
border-bottom: 1px solid #d7d7db;
|
border-bottom: 1px solid #d7d7db;
|
||||||
|
border-left: 1px solid #fff;
|
||||||
|
border-top: 1px solid #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup .show {
|
.popup .show {
|
||||||
|
@ -601,6 +612,7 @@ tbody {
|
||||||
color: white;
|
color: white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
padding-bottom: 4px;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -632,10 +644,34 @@ tbody {
|
||||||
color: #313131;
|
color: #313131;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#deletePopup {
|
||||||
|
position: relative;
|
||||||
|
bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
#delete-file:hover {
|
#delete-file:hover {
|
||||||
background: #efeff1;
|
background: #efeff1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#resetButton {
|
||||||
|
width: 80px;
|
||||||
|
height: 30px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid rgba(12, 12, 13, 0.3);
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 15px;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-left: 15px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
line-height: 24px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #313131;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resetButton:hover {
|
||||||
|
background: #efeff1;
|
||||||
|
}
|
||||||
|
|
||||||
.send-new {
|
.send-new {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
@ -662,6 +698,18 @@ tbody {
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.passwordOriginal {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectPassword :hover .passwordOriginal {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectPassword :hover .passwordMask {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.setPassword {
|
.setPassword {
|
||||||
align-self: left;
|
align-self: left;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -721,7 +769,7 @@ tbody {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 0;
|
border: 0;
|
||||||
box-shadow: 0 5px 3px rgb(234, 234, 234);
|
box-shadow: 0 5px 3px rgb(234, 234, 234);
|
||||||
font-family: 'Fira Sans';
|
font-family: 'Fira Sans', 'segoe ui', sans-serif;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
|
@ -738,7 +786,7 @@ tbody {
|
||||||
}
|
}
|
||||||
|
|
||||||
.unsupported-button-text > span {
|
.unsupported-button-text > span {
|
||||||
font-family: 'Fira Sans';
|
font-family: 'Fira Sans', 'segoe ui', sans-serif;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
letter-spacing: -0.69px;
|
letter-spacing: -0.69px;
|
||||||
|
@ -833,20 +881,26 @@ tbody {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#unlock-btn {
|
#unlock-btn,
|
||||||
|
#unlock-reset-btn {
|
||||||
flex: 0 1 165px;
|
flex: 0 1 165px;
|
||||||
background: #0297f8;
|
background: #0297f8;
|
||||||
border-radius: 0 6px 6px 0;
|
border-radius: 0 6px 6px 0;
|
||||||
border: 1px solid #0297f8;
|
border: 1px solid #0297f8;
|
||||||
color: white;
|
color: white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
/* Force flat button look */
|
||||||
|
-webkit-appearance: none;
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
padding-bottom: 3px;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#unlock-btn:hover {
|
#unlock-btn:hover,
|
||||||
|
#unlock-reset-btn:hover {
|
||||||
background-color: #0287e8;
|
background-color: #0287e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,15 +985,18 @@ tbody {
|
||||||
visibility: collapse;
|
visibility: collapse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#addPasswordWrapper:hover label::before {
|
||||||
|
border: 1px solid #0297f8;
|
||||||
|
}
|
||||||
|
|
||||||
#addPasswordWrapper label {
|
#addPasswordWrapper label {
|
||||||
line-height: 20px;
|
line-height: 23px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
color: #737373;
|
||||||
opacity: 0.6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#addPassword:checked + label {
|
#addPassword:checked + label {
|
||||||
opacity: 1;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#addPasswordWrapper label::before {
|
#addPasswordWrapper label::before {
|
||||||
|
@ -981,6 +1038,77 @@ tbody {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.banner-blue {
|
||||||
|
background: linear-gradient(-180deg, #45a1ff 0%, #00feff 94%);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-blue a {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-blue a:hover {
|
||||||
|
color: #eee;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-pink {
|
||||||
|
background: linear-gradient(-180deg, #ff9400 0%, #ff1ad9 94%);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-pink a {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-pink a:hover {
|
||||||
|
color: #eee;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectbox {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectSelected {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectOptions {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectOptions.active {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 40px 0;
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid rgba(12, 12, 13, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 1px 2px 4px rgba(12, 12, 13, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectOption {
|
||||||
|
color: #737373;
|
||||||
|
font-size: 12pt;
|
||||||
|
list-style: none;
|
||||||
|
user-select: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 60px;
|
||||||
|
border-bottom: 1px solid rgba(12, 12, 13, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectOption:hover {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-device-width: 992px), (max-width: 992px) {
|
@media (max-device-width: 992px), (max-width: 992px) {
|
||||||
.popup .popuptext {
|
.popup .popuptext {
|
||||||
left: auto;
|
left: auto;
|
||||||
|
@ -1076,7 +1204,8 @@ tbody {
|
||||||
}
|
}
|
||||||
|
|
||||||
#copy-btn,
|
#copy-btn,
|
||||||
#unlock-btn {
|
#unlock-btn,
|
||||||
|
#unlock-reset-btn {
|
||||||
border-radius: 0 0 6px 6px;
|
border-radius: 0 0 6px 6px;
|
||||||
flex: 0 1 65px;
|
flex: 0 1 65px;
|
||||||
}
|
}
|
||||||
|
@ -1094,4 +1223,12 @@ tbody {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 17px 5px 0;
|
padding: 17px 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup .popuptext::after {
|
||||||
|
left: 125px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#deletePopup {
|
||||||
|
left: 83px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,45 @@
|
||||||
const { MessageContext } = require('fluent');
|
const { MessageContext } = require('fluent');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
function toJSON(map) {
|
function toJSON(map) {
|
||||||
return JSON.stringify(Array.from(map));
|
return JSON.stringify(Array.from(map));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function merge(m1, m2) {
|
||||||
|
const result = new Map(m1);
|
||||||
|
for (const [k, v] of m2) {
|
||||||
|
result.set(k, v);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = function(source) {
|
module.exports = function(source) {
|
||||||
const localeExp = this.options.locale || /([^/]+)\/[^/]+\.ftl$/;
|
const localeExp = this.options.locale || /([^/]+)\/[^/]+\.ftl$/;
|
||||||
const result = localeExp.exec(this.resourcePath);
|
const result = localeExp.exec(this.resourcePath);
|
||||||
const locale = result && result[1];
|
const locale = result && result[1];
|
||||||
// pre-parse the ftl
|
|
||||||
const context = new MessageContext(locale);
|
|
||||||
context.addMessages(source);
|
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
throw new Error(`couldn't find locale in: ${this.resourcePath}`);
|
throw new Error(`couldn't find locale in: ${this.resourcePath}`);
|
||||||
}
|
}
|
||||||
|
// load default language and "merge" contexts
|
||||||
|
// TODO: make this configurable
|
||||||
|
const en_ftl = fs.readFileSync(
|
||||||
|
require.resolve('../public/locales/en-US/send.ftl'),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
const en = new MessageContext('en-US');
|
||||||
|
en.addMessages(en_ftl);
|
||||||
|
// pre-parse the ftl
|
||||||
|
const context = new MessageContext(locale);
|
||||||
|
context.addMessages(source);
|
||||||
|
|
||||||
|
const merged = merge(en._messages, context._messages);
|
||||||
return `
|
return `
|
||||||
module.exports = \`
|
module.exports = \`
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
var fluent = require('fluent');
|
var fluent = require('fluent');
|
||||||
}
|
}
|
||||||
var ctx = new fluent.MessageContext('${locale}', {useIsolating: false});
|
var ctx = new fluent.MessageContext('${locale}', {useIsolating: false});
|
||||||
ctx._messages = new Map(${toJSON(context._messages)});
|
ctx._messages = new Map(${toJSON(merged)});
|
||||||
function translate(id, data) {
|
function translate(id, data) {
|
||||||
var msg = ctx.getMessage(id);
|
var msg = ctx.getMessage(id);
|
||||||
if (typeof(msg) !== 'string' && !msg.val && msg.attrs) {
|
if (typeof(msg) !== 'string' && !msg.val && msg.attrs) {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
const version = require('../package.json').version;
|
||||||
|
|
||||||
|
module.exports = function(source) {
|
||||||
|
return source.replace('VERSION', version);
|
||||||
|
};
|
|
@ -8,6 +8,5 @@ services:
|
||||||
- "1443:1443"
|
- "1443:1443"
|
||||||
environment:
|
environment:
|
||||||
- REDIS_HOST=redis
|
- REDIS_HOST=redis
|
||||||
- NODE_ENV=production
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
|
|
|
@ -27,6 +27,7 @@ Data will be collected with Google Analytics and follow [Test Pilot standards](h
|
||||||
- `cm5` - the number of files the user has ever uploaded.
|
- `cm5` - the number of files the user has ever uploaded.
|
||||||
- `cm6` - the number of unexpired files the user has uploaded.
|
- `cm6` - the number of unexpired files the user has uploaded.
|
||||||
- `cm7` - the number of files the user has ever downloaded.
|
- `cm7` - the number of files the user has ever downloaded.
|
||||||
|
- `cm8` - the number of downloads permitted by the uploader.
|
||||||
|
|
||||||
### Custom Dimensions
|
### Custom Dimensions
|
||||||
- `cd1` - the method by which the user initiated an upload. One of `drag`, `click`.
|
- `cd1` - the method by which the user initiated an upload. One of `drag`, `click`.
|
||||||
|
@ -67,6 +68,17 @@ Triggered whenever a user stops uploading a file. Includes:
|
||||||
- `cd2`
|
- `cd2`
|
||||||
- `cd6`
|
- `cd6`
|
||||||
|
|
||||||
|
#### `download-limit-changed`
|
||||||
|
Triggered whenever the sender changes the download limit. Includes:
|
||||||
|
|
||||||
|
- `ec` - `sender`
|
||||||
|
- `ea` - `download-limit-changed`
|
||||||
|
- `cm1`
|
||||||
|
- `cm5`
|
||||||
|
- `cm6`
|
||||||
|
- `cm7`
|
||||||
|
- `cm8`
|
||||||
|
|
||||||
#### `password-added`
|
#### `password-added`
|
||||||
Triggered whenever a password is added to a file. Includes:
|
Triggered whenever a password is added to a file. Includes:
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
## Take-down process
|
||||||
|
|
||||||
|
In cases of a DMCA notice, or other abuse yet to be determined, a file has to be removed from the service.
|
||||||
|
|
||||||
|
Files can be delisted and made inaccessible by removing their record from Redis.
|
||||||
|
|
||||||
|
Send share links contain the `id` of the file, for example `https://send.firefox.com/download/3d9d2bb9a1`
|
||||||
|
|
||||||
|
From a host with access to the Redis server run a `DEL` command with the file id.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
redis-cli DEL 3d9d2bb9a1
|
||||||
|
```
|
||||||
|
|
||||||
|
Other redis-cli parameters like `-h` may also be required. See [redis-cli docs](https://redis.io/topics/rediscli) for more info.
|
||||||
|
|
||||||
|
The encrypted file resides on S3 as the same `id` under the bucket that the app was configured with as `S3_BUCKET`. The file can be managed if it has not already expired with the [AWS cli](https://docs.aws.amazon.com/cli/latest/reference/s3/index.html) or AWS web console.
|
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "firefox-send",
|
"name": "firefox-send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"version": "2.0.0",
|
"version": "2.2.1",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"repository": "mozilla/send",
|
"repository": "mozilla/send",
|
||||||
"homepage": "https://github.com/mozilla/send/",
|
"homepage": "https://github.com/mozilla/send/",
|
||||||
|
@ -43,59 +43,60 @@
|
||||||
"node": ">=8.2.0"
|
"node": ">=8.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^7.1.6",
|
"autoprefixer": "^7.2.3",
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-loader": "^7.1.2",
|
"babel-loader": "^7.1.2",
|
||||||
"babel-plugin-yo-yoify": "^1.0.1",
|
"babel-plugin-yo-yoify": "^1.0.2",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
"babel-preset-env": "^1.6.1",
|
"babel-preset-env": "^1.6.1",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-stage-2": "^6.24.1",
|
"babel-preset-stage-2": "^6.24.1",
|
||||||
"base64-js": "^1.2.1",
|
"base64-js": "^1.2.1",
|
||||||
"copy-webpack-plugin": "^4.2.0",
|
"copy-webpack-plugin": "^4.3.0",
|
||||||
"cross-env": "^5.1.1",
|
"cross-env": "^5.1.1",
|
||||||
"css-loader": "^0.28.7",
|
"css-loader": "^0.28.7",
|
||||||
"css-mqpacker": "^6.0.1",
|
"css-mqpacker": "^6.0.1",
|
||||||
"cssnano": "^3.10.0",
|
"cssnano": "^3.10.0",
|
||||||
"eslint": "^4.10.0",
|
"eslint": "^4.13.1",
|
||||||
"eslint-plugin-mocha": "^4.11.0",
|
"eslint-plugin-mocha": "^4.11.0",
|
||||||
"eslint-plugin-node": "^5.2.1",
|
"eslint-plugin-node": "^5.2.1",
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
"expose-loader": "^0.7.3",
|
"expose-loader": "^0.7.4",
|
||||||
"extract-loader": "^1.0.1",
|
"extract-loader": "^1.0.1",
|
||||||
"file-loader": "^1.1.5",
|
"file-loader": "^1.1.6",
|
||||||
|
"fluent-intl-polyfill": "^0.1.0",
|
||||||
"git-rev-sync": "^1.9.1",
|
"git-rev-sync": "^1.9.1",
|
||||||
"github-changes": "^1.1.1",
|
"github-changes": "^1.1.1",
|
||||||
"html-loader": "^0.5.1",
|
"html-loader": "^0.5.1",
|
||||||
"husky": "^0.14.3",
|
"husky": "^0.14.3",
|
||||||
"lint-staged": "^4.3.0",
|
"lint-staged": "^4.3.0",
|
||||||
"mocha": "^3.5.3",
|
"mocha": "^3.5.3",
|
||||||
"nanobus": "^4.3.0",
|
"nanobus": "^4.3.1",
|
||||||
"npm-run-all": "^4.1.2",
|
"npm-run-all": "^4.1.2",
|
||||||
"postcss-loader": "^2.0.8",
|
"postcss-loader": "^2.0.9",
|
||||||
"prettier": "^1.8.2",
|
"prettier": "^1.9.2",
|
||||||
"proxyquire": "^1.8.0",
|
"proxyquire": "^1.8.0",
|
||||||
"raven-js": "^3.19.1",
|
"raven-js": "^3.21.0",
|
||||||
"redis-mock": "^0.20.0",
|
"redis-mock": "^0.20.0",
|
||||||
"require-from-string": "^2.0.1",
|
"require-from-string": "^2.0.1",
|
||||||
"rimraf": "^2.6.2",
|
"rimraf": "^2.6.2",
|
||||||
"selenium-webdriver": "^3.6.0",
|
"selenium-webdriver": "^3.6.0",
|
||||||
"sinon": "^4.1.2",
|
"sinon": "^4.1.3",
|
||||||
"string-hash": "^1.1.3",
|
"string-hash": "^1.1.3",
|
||||||
"stylelint-config-standard": "^17.0.0",
|
"stylelint-config-standard": "^17.0.0",
|
||||||
"stylelint-no-unsupported-browser-features": "^1.0.1",
|
"stylelint-no-unsupported-browser-features": "^1.0.1",
|
||||||
"supertest": "^3.0.0",
|
"supertest": "^3.0.0",
|
||||||
"testpilot-ga": "^0.3.0",
|
"testpilot-ga": "^0.3.0",
|
||||||
"val-loader": "^1.0.2",
|
"val-loader": "^1.1.0",
|
||||||
"webpack": "^3.8.1",
|
"webpack": "^3.10.0",
|
||||||
"webpack-dev-server": "2.9.1",
|
"webpack-dev-server": "2.9.1",
|
||||||
"webpack-manifest-plugin": "^1.3.2",
|
"webpack-manifest-plugin": "^1.3.2",
|
||||||
"webpack-unassert-loader": "^1.2.0"
|
"webpack-unassert-loader": "^1.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"aws-sdk": "^2.149.0",
|
"aws-sdk": "^2.171.0",
|
||||||
"body-parser": "^1.18.2",
|
"body-parser": "^1.18.2",
|
||||||
"choo": "^6.5.1",
|
"choo": "^6.6.0",
|
||||||
"cldr-core": "^32.0.0",
|
"cldr-core": "^32.0.0",
|
||||||
"connect-busboy": "0.0.2",
|
"connect-busboy": "0.0.2",
|
||||||
"convict": "^4.0.1",
|
"convict": "^4.0.1",
|
||||||
|
@ -104,8 +105,8 @@
|
||||||
"fluent-langneg": "^0.1.0",
|
"fluent-langneg": "^0.1.0",
|
||||||
"helmet": "^3.9.0",
|
"helmet": "^3.9.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mozlog": "^2.1.1",
|
"mozlog": "^2.2.0",
|
||||||
"raven": "^2.2.1",
|
"raven": "^2.3.0",
|
||||||
"redis": "^2.8.0"
|
"redis": "^2.8.0"
|
||||||
},
|
},
|
||||||
"availableLanguages": [
|
"availableLanguages": [
|
||||||
|
|
|
@ -11,7 +11,10 @@ uploadPageBrowseButton = اختر ملفّا على حاسوبك
|
||||||
.title = اختر ملفّا على حاسوبك
|
.title = اختر ملفّا على حاسوبك
|
||||||
uploadPageBrowseButton1 = اختر ملفّا لرفعه
|
uploadPageBrowseButton1 = اختر ملفّا لرفعه
|
||||||
uploadPageMultipleFilesAlert = رفع عدة ملفات (أو رفع مجلد) ليس مدعوما حاليا.
|
uploadPageMultipleFilesAlert = رفع عدة ملفات (أو رفع مجلد) ليس مدعوما حاليا.
|
||||||
|
uploadPageBrowseButtonTitle = ارفع ملفًا
|
||||||
|
uploadingPageProgress = يرفع { $filename } ({ $size })
|
||||||
importingFile = يستورد…
|
importingFile = يستورد…
|
||||||
|
verifyingFile = يتحقق…
|
||||||
encryptingFile = يعمّي…
|
encryptingFile = يعمّي…
|
||||||
decryptingFile = يفك التعمية…
|
decryptingFile = يفك التعمية…
|
||||||
notifyUploadDone = انتهى الرفع.
|
notifyUploadDone = انتهى الرفع.
|
||||||
|
@ -21,8 +24,27 @@ uploadingPageCancel = ألغِ الرفع
|
||||||
uploadCancelNotification = أُلغي الرفع.
|
uploadCancelNotification = أُلغي الرفع.
|
||||||
uploadingPageLargeFileMessage = هذا الملف كبير الحجم وسيأخذ رفعه وقتا. انتظر رجاءً.
|
uploadingPageLargeFileMessage = هذا الملف كبير الحجم وسيأخذ رفعه وقتا. انتظر رجاءً.
|
||||||
uploadingFileNotification = أعلِمني عندما يكتمل الرفع.
|
uploadingFileNotification = أعلِمني عندما يكتمل الرفع.
|
||||||
|
uploadSuccessConfirmHeader = جاهز للإرسال
|
||||||
uploadSvgAlt
|
uploadSvgAlt
|
||||||
.alt = ارفع
|
.alt = ارفع
|
||||||
|
uploadSuccessTimingHeader = ستنتهي صلاحية الرابط الذي يشير إلى الملف في حال: نُزِّل لأول مرة، أو مرّ ٢٤ ساعة على رفعه.
|
||||||
|
expireInfo = ستنتهي صلاحية رابط الملف بعد { $downloadCount } أو { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[zero] لا تنزيلات
|
||||||
|
[one] تنزيل واحد
|
||||||
|
[two] تنزيلين
|
||||||
|
[few] { $num } تنزيلات
|
||||||
|
[many] { $num } تنزيلًا
|
||||||
|
*[other] { $num } تنزيل
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[zero] أقل من ساعة
|
||||||
|
[one] ساعة
|
||||||
|
[two] ساعتين
|
||||||
|
[few] { $num } ساعات
|
||||||
|
[many] { $num } ساعة
|
||||||
|
*[other] { $num } ساعة
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = انسخ الرابط وشاركه لإرسال الملف: { $filename }
|
copyUrlFormLabelWithName = انسخ الرابط وشاركه لإرسال الملف: { $filename }
|
||||||
copyUrlFormButton = انسخ إلى الحافظة
|
copyUrlFormButton = انسخ إلى الحافظة
|
||||||
.title = انسخ إلى الحافظة
|
.title = انسخ إلى الحافظة
|
||||||
|
@ -34,9 +56,17 @@ sendAnotherFileLink = أرسل ملفّا آخر
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText
|
downloadAltText
|
||||||
.alt = نزّل
|
.alt = نزّل
|
||||||
|
downloadsFileList = التنزيلات
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = الوقت
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = نزّل { $filename }
|
downloadFileName = نزّل { $filename }
|
||||||
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = أدخل كلمة السر
|
unlockInputLabel = أدخل كلمة السر
|
||||||
unlockInputPlaceholder = كلمة السر
|
unlockInputPlaceholder = كلمة السر
|
||||||
|
unlockButtonLabel = افتح القفل
|
||||||
downloadFileTitle = نزِّل الملف المعمّى
|
downloadFileTitle = نزِّل الملف المعمّى
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
downloadMessage = يُرسل إليك صديقك ملفا عبر «فَيَرفُكس سِنْد»، وهي خدمة تتيح لك مشاركة الملفات عبر رابط آمن وخاص ومعمّى، حيث تنتهي صلاحياتها تلقائيا لتضمن عدم بقاء ما ترسله إلى الأبد.
|
downloadMessage = يُرسل إليك صديقك ملفا عبر «فَيَرفُكس سِنْد»، وهي خدمة تتيح لك مشاركة الملفات عبر رابط آمن وخاص ومعمّى، حيث تنتهي صلاحياتها تلقائيا لتضمن عدم بقاء ما ترسله إلى الأبد.
|
||||||
|
@ -49,6 +79,7 @@ downloadFinish = اكتمل التنزيل
|
||||||
fileSizeProgress = ({ $partialSize } من أصل { $totalSize })
|
fileSizeProgress = ({ $partialSize } من أصل { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
sendYourFilesLink = جرِّب «فَيَرفُكس سِنْد»
|
sendYourFilesLink = جرِّب «فَيَرفُكس سِنْد»
|
||||||
|
downloadingPageProgress = ينزّل { $filename } ({ $size })
|
||||||
downloadingPageMessage = رجاء أبقِ هذا اللسان مفتوحا حتى نجلب الملف ونفك تعميته.
|
downloadingPageMessage = رجاء أبقِ هذا اللسان مفتوحا حتى نجلب الملف ونفك تعميته.
|
||||||
errorAltText
|
errorAltText
|
||||||
.alt = خطأ أثناء الرفع
|
.alt = خطأ أثناء الرفع
|
||||||
|
@ -56,15 +87,24 @@ errorPageHeader = حدث خطب ما.
|
||||||
errorPageMessage = حدث خطب ما أثناء رفع الملف.
|
errorPageMessage = حدث خطب ما أثناء رفع الملف.
|
||||||
errorPageLink = أرسل ملفا آخر
|
errorPageLink = أرسل ملفا آخر
|
||||||
fileTooBig = حجم الملف كبير للغاية لرفعه. يجب أن يكون أصغر من { $size }.
|
fileTooBig = حجم الملف كبير للغاية لرفعه. يجب أن يكون أصغر من { $size }.
|
||||||
|
linkExpiredAlt = انتهت صلاحية الرابط
|
||||||
|
expiredPageHeader = انتهت صلاحية هذا الرابط أو لم يكن موجودا في المقام الأول!
|
||||||
notSupportedHeader = متصفحك غير مدعوم.
|
notSupportedHeader = متصفحك غير مدعوم.
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
notSupportedDetail = للأسف فإن متصفحك لا يدعم تقنية الوِب التي يعتمد عليها «فَيَرفُكس سِنْد». عليك تجربة متصفح آخر، ونحن ننصحك بِفَيَرفُكس!
|
notSupportedDetail = للأسف فإن متصفحك لا يدعم تقنية الوِب التي يعتمد عليها «فَيَرفُكس سِنْد». عليك تجربة متصفح آخر، ونحن ننصحك بِفَيَرفُكس!
|
||||||
notSupportedLink = لماذا متصفحي غير مدعوم؟
|
notSupportedLink = لماذا متصفحي غير مدعوم؟
|
||||||
notSupportedOutdatedDetail = للأسف فإن إصدارة فَيَرفُكس هذه لا تدعم تقنية الوِب التي يعتمد عليها «فَيَرفُكس سِنْد». عليك تحديث متصفحك.
|
notSupportedOutdatedDetail = للأسف فإن إصدارة فَيَرفُكس هذه لا تدعم تقنية الوِب التي يعتمد عليها «فَيَرفُكس سِنْد». عليك تحديث متصفحك.
|
||||||
updateFirefox = حدّث فَيَرفُكس
|
updateFirefox = حدّث فَيَرفُكس
|
||||||
|
downloadFirefoxButtonSub = تنزيل مجاني
|
||||||
|
uploadedFile = ملف
|
||||||
copyFileList = انسخ الرابط
|
copyFileList = انسخ الرابط
|
||||||
|
// expiryFileList is used as a column header
|
||||||
|
expiryFileList = ينتهي في
|
||||||
deleteFileList = احذف
|
deleteFileList = احذف
|
||||||
|
nevermindButton = لا بأس
|
||||||
legalHeader = الشروط والخصوصية
|
legalHeader = الشروط والخصوصية
|
||||||
|
legalNoticeTestPilot = «فَيَرفُكس سِنْد» جزء من اختبار تجريبي حاليًا و يخضع <a>لبنود خدمة</a> الاختبار التجريبي و <a>تنويه الخصوصية</a>. يمكنك التعرف على مزيد من المعلومات حول هذه التجربة وجمع البيانات<a>هنا</a>.
|
||||||
|
legalNoticeMozilla = يخضع استخدام موقع «فَيَرفُكس سِنْد» إلى<a>تنويه خصوصية المواقع</a> و <a>بنود خدمة المواقع</a>.
|
||||||
deletePopupText = أأحذف هذا الملف؟
|
deletePopupText = أأحذف هذا الملف؟
|
||||||
deletePopupYes = نعم
|
deletePopupYes = نعم
|
||||||
deletePopupCancel = ألغِ
|
deletePopupCancel = ألغِ
|
||||||
|
@ -72,9 +112,16 @@ deleteButtonHover
|
||||||
.title = احذف
|
.title = احذف
|
||||||
copyUrlHover
|
copyUrlHover
|
||||||
.title = انسخ الرابط
|
.title = انسخ الرابط
|
||||||
|
footerLinkLegal = القانونية
|
||||||
|
// Test Pilot is a proper name and should not be localized.
|
||||||
|
footerLinkAbout = حول الاختبار التجريبي
|
||||||
|
footerLinkPrivacy = الخصوصية
|
||||||
footerLinkTerms = الشروط
|
footerLinkTerms = الشروط
|
||||||
footerLinkCookies = الكعكات
|
footerLinkCookies = الكعكات
|
||||||
requirePasswordCheckbox = اطلب كلمة سر لتنزيل هذا الملف
|
requirePasswordCheckbox = اطلب كلمة سر لتنزيل هذا الملف
|
||||||
addPasswordButton = أضِف كلمة سر
|
addPasswordButton = أضِف كلمة سر
|
||||||
|
changePasswordButton = غيّر
|
||||||
|
passwordTryAgain = كلمة السر خاطئة. أعِد المحاولة.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = كلمة السر: { $password }
|
passwordResult = كلمة السر: { $password }
|
||||||
|
reportIPInfringement = أبلغ عن انتهاك للملكية الفكرية
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Yükləmə bitdiyində xəbər ver.
|
||||||
uploadSuccessConfirmHeader = Göndərməyə hazır
|
uploadSuccessConfirmHeader = Göndərməyə hazır
|
||||||
uploadSvgAlt = Yüklə
|
uploadSvgAlt = Yüklə
|
||||||
uploadSuccessTimingHeader = Faylınızın keçidinin 1 endirmədən və ya 24 saatdan sonra vaxtı çıxacaq.
|
uploadSuccessTimingHeader = Faylınızın keçidinin 1 endirmədən və ya 24 saatdan sonra vaxtı çıxacaq.
|
||||||
|
expireInfo = Faylınız üçün keçidin vaxtı { $downloadCount } sonra və ya { $timespan } tarixində keçəcək.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 endirmə
|
||||||
|
*[other] { $num } endirmə
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 saat
|
||||||
|
*[other] { $num } saat
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Faylınızı göndərmək üçün keçidi köçürün: { $filename }
|
copyUrlFormLabelWithName = Faylınızı göndərmək üçün keçidi köçürün: { $filename }
|
||||||
copyUrlFormButton = Buferə köçür
|
copyUrlFormButton = Buferə köçür
|
||||||
copiedUrl = Köçürüldü!
|
copiedUrl = Köçürüldü!
|
||||||
|
@ -86,4 +95,7 @@ footerLinkTerms = Şərtlər
|
||||||
footerLinkCookies = Çərəzlər
|
footerLinkCookies = Çərəzlər
|
||||||
requirePasswordCheckbox = Bu faylı endirmək üçün parol tələb et
|
requirePasswordCheckbox = Bu faylı endirmək üçün parol tələb et
|
||||||
addPasswordButton = Parol əlavə et
|
addPasswordButton = Parol əlavə et
|
||||||
incorrectPassword = Xətalı parol. Təkrar yoxlayın.
|
passwordTryAgain = Səhv parol. Təkrar yoxlayın.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Parol: { $password }
|
||||||
|
reportIPInfringement = Əqli-mülkiyyət pozuntusu bildir
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
title = Firefox Send
|
title = Firefox Send
|
||||||
siteSubtitle = ওয়েব গবেষণা
|
siteSubtitle = ওয়েব গবেষণা
|
||||||
siteFeedback = প্রতিক্রিয়া
|
siteFeedback = প্রতিক্রিয়া
|
||||||
|
uploadPageHeader = ব্যক্তিগত, এনক্রিপ্ট করা ফাইল শেয়ারিং
|
||||||
uploadPageLearnMore = আরও জানুন
|
uploadPageLearnMore = আরও জানুন
|
||||||
uploadPageBrowseButton = আপনার কম্পিউটারে ফাইল নির্বাচন করুন
|
uploadPageBrowseButton = আপনার কম্পিউটারে ফাইল নির্বাচন করুন
|
||||||
uploadPageBrowseButtonTitle = ফাইল আপলোড
|
uploadPageBrowseButtonTitle = ফাইল আপলোড
|
||||||
|
@ -14,14 +15,31 @@ uploadingPageCancel = আপলোড বাতিল করুন
|
||||||
uploadCancelNotification = আপনার অাপলোড বাতিল করা হয়েছে।
|
uploadCancelNotification = আপনার অাপলোড বাতিল করা হয়েছে।
|
||||||
uploadSuccessConfirmHeader = পাঠানোর জন্য প্রস্তুত
|
uploadSuccessConfirmHeader = পাঠানোর জন্য প্রস্তুত
|
||||||
uploadSvgAlt = আপলোড
|
uploadSvgAlt = আপলোড
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 ডাউনলোড
|
||||||
|
*[other] { $num } ডাউনলোডগুলো
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 ঘন্টা
|
||||||
|
*[other] { $num } ঘন্টা
|
||||||
|
}
|
||||||
copyUrlFormButton = ক্লিপবোর্ডে কপি করুন
|
copyUrlFormButton = ক্লিপবোর্ডে কপি করুন
|
||||||
copiedUrl = কপি করা হয়েছে!
|
copiedUrl = কপি করা হয়েছে!
|
||||||
deleteFileButton = ফাইল মুছুন
|
deleteFileButton = ফাইল মুছুন
|
||||||
sendAnotherFileLink = আরেকটি ফাইল পাঠান
|
sendAnotherFileLink = আরেকটি ফাইল পাঠান
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = ডাউনলোড
|
downloadAltText = ডাউনলোড
|
||||||
|
downloadsFileList = ডাউনলোডগুলো
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = সময়
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = ডাউনলোড { $filename }
|
downloadFileName = ডাউনলোড { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
|
unlockInputLabel = পাসওয়ার্ড লিখুন
|
||||||
|
unlockInputPlaceholder = পাসওয়ার্ড
|
||||||
|
unlockButtonLabel = আনলক করুন
|
||||||
// Text and title used on the download link/button (indicates an action).
|
// Text and title used on the download link/button (indicates an action).
|
||||||
downloadButtonLabel = ডাউনলোড
|
downloadButtonLabel = ডাউনলোড
|
||||||
downloadNotification = আপনার ডাউনলোড সম্পন্ন হয়েছে।
|
downloadNotification = আপনার ডাউনলোড সম্পন্ন হয়েছে।
|
||||||
|
@ -29,6 +47,8 @@ downloadFinish = ডাউনলোড সম্পন্ন
|
||||||
errorAltText = আপালোডে ত্রুটি
|
errorAltText = আপালোডে ত্রুটি
|
||||||
errorPageHeader = কোন সমস্যা হয়েছে!
|
errorPageHeader = কোন সমস্যা হয়েছে!
|
||||||
errorPageLink = আরেকটি ফাইল পাঠান
|
errorPageLink = আরেকটি ফাইল পাঠান
|
||||||
|
expiredPageHeader = এই লিঙ্কটির মেয়াদ শেষ হয়ে গেছে বা কখনই প্রথম স্থানে নেই!
|
||||||
|
notSupportedHeader = আপনার ব্রাউজার সমর্থিত নয়।
|
||||||
updateFirefox = Firefox হালনাগাদ করুন
|
updateFirefox = Firefox হালনাগাদ করুন
|
||||||
downloadFirefoxButtonSub = বিনামূল্যে ডাউনলোড
|
downloadFirefoxButtonSub = বিনামূল্যে ডাউনলোড
|
||||||
uploadedFile = ফাইল
|
uploadedFile = ফাইল
|
||||||
|
@ -49,3 +69,4 @@ footerLinkAbout = Test Pilot পরিচিতি
|
||||||
footerLinkPrivacy = গোপনীয়তা
|
footerLinkPrivacy = গোপনীয়তা
|
||||||
footerLinkTerms = শর্তাবলী
|
footerLinkTerms = শর্তাবলী
|
||||||
footerLinkCookies = কুকি
|
footerLinkCookies = কুকি
|
||||||
|
changePasswordButton = পরিবর্তন
|
||||||
|
|
|
@ -25,6 +25,17 @@ uploadingFileNotification = Obavijesti me kada otpremanje bude gotovo.
|
||||||
uploadSuccessConfirmHeader = Spremno za slanje
|
uploadSuccessConfirmHeader = Spremno za slanje
|
||||||
uploadSvgAlt = Otpremi
|
uploadSvgAlt = Otpremi
|
||||||
uploadSuccessTimingHeader = Veza prema vašoj datoteci će isteći nakon prvog preuzimanja ili za 24 sata.
|
uploadSuccessTimingHeader = Veza prema vašoj datoteci će isteći nakon prvog preuzimanja ili za 24 sata.
|
||||||
|
expireInfo = Link za vašu datoteku će isteći nakon { $downloadCount } ili { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 preuzimanja
|
||||||
|
[few] { $num } preuzimanja
|
||||||
|
*[other] { $num } preuzimanja
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 sat
|
||||||
|
[few] { $num } sata
|
||||||
|
*[other] { $num } sati
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Iskopirajte i podijelite vezu da biste poslali datoteku: { $filename }
|
copyUrlFormLabelWithName = Iskopirajte i podijelite vezu da biste poslali datoteku: { $filename }
|
||||||
copyUrlFormButton = Kopiraj u međuspremnik
|
copyUrlFormButton = Kopiraj u međuspremnik
|
||||||
copiedUrl = Kopirano!
|
copiedUrl = Kopirano!
|
||||||
|
@ -32,6 +43,12 @@ deleteFileButton = Izbriši datoteku
|
||||||
sendAnotherFileLink = Pošalji drugu datoteku
|
sendAnotherFileLink = Pošalji drugu datoteku
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Preuzmi
|
downloadAltText = Preuzmi
|
||||||
|
downloadsFileList = Preuzimanja
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Vrijeme
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Preuzmi { $filename }
|
downloadFileName = Preuzmi { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Unesite lozinku
|
unlockInputLabel = Unesite lozinku
|
||||||
|
@ -86,6 +103,15 @@ footerLinkTerms = Uslovi
|
||||||
footerLinkCookies = Kolačići
|
footerLinkCookies = Kolačići
|
||||||
requirePasswordCheckbox = Zahtjevaj lozinku za preuzimanje ove datoteke
|
requirePasswordCheckbox = Zahtjevaj lozinku za preuzimanje ove datoteke
|
||||||
addPasswordButton = Dodaj lozinku
|
addPasswordButton = Dodaj lozinku
|
||||||
|
changePasswordButton = Promijeni
|
||||||
passwordTryAgain = Netačna lozinka. Pokušajte ponovo.
|
passwordTryAgain = Netačna lozinka. Pokušajte ponovo.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Lozinka: { $password }
|
passwordResult = Lozinka: { $password }
|
||||||
|
reportIPInfringement = Prijavite IP prekršaj
|
||||||
|
javascriptRequired = Firefox Send zahtjeva JavaScript
|
||||||
|
whyJavascript = Zašto Firefox Send zahtjeva JavaScript?
|
||||||
|
enableJavascript = Molimo omogućite JavaScript i pokušajte ponovo.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Notifica'm quan s'acabi de pujar.
|
||||||
uploadSuccessConfirmHeader = Llest per enviar
|
uploadSuccessConfirmHeader = Llest per enviar
|
||||||
uploadSvgAlt = Puja
|
uploadSvgAlt = Puja
|
||||||
uploadSuccessTimingHeader = L'enllaç al fitxer caducarà quan es baixi una vegada o d'aquí 24 hores.
|
uploadSuccessTimingHeader = L'enllaç al fitxer caducarà quan es baixi una vegada o d'aquí 24 hores.
|
||||||
|
expireInfo = L'enllaç al fitxer caducarà en fer { $downloadCount } o d'aquí { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 baixada
|
||||||
|
*[other] { $num } baixades
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hora
|
||||||
|
*[other] { $num } hores
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copieu l'enllaç i compartiu-lo per enviar el fitxer: { $filename }
|
copyUrlFormLabelWithName = Copieu l'enllaç i compartiu-lo per enviar el fitxer: { $filename }
|
||||||
copyUrlFormButton = Copia al porta-retalls
|
copyUrlFormButton = Copia al porta-retalls
|
||||||
copiedUrl = Copiat!
|
copiedUrl = Copiat!
|
||||||
|
@ -34,6 +43,10 @@ sendAnotherFileLink = Envieu un altre fitxer
|
||||||
downloadAltText = Baixa
|
downloadAltText = Baixa
|
||||||
downloadFileName = Baixeu { $filename }
|
downloadFileName = Baixeu { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
|
unlockInputLabel = Introduïu la contrasenya
|
||||||
|
unlockInputPlaceholder = Contrasenya
|
||||||
|
unlockButtonLabel = Desbloca
|
||||||
|
downloadFileTitle = Baixa el fitxer xifrat
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
downloadMessage = Un amic us ha enviat un fitxer amb el Firefox Send, un servei que permet compartir fitxers mitjançant un enllaç segur, privat i xifrat que caduca automàticament per tal que les vostres dades no es conservin a Internet per sempre.
|
downloadMessage = Un amic us ha enviat un fitxer amb el Firefox Send, un servei que permet compartir fitxers mitjançant un enllaç segur, privat i xifrat que caduca automàticament per tal que les vostres dades no es conservin a Internet per sempre.
|
||||||
// Text and title used on the download link/button (indicates an action).
|
// Text and title used on the download link/button (indicates an action).
|
||||||
|
@ -80,3 +93,9 @@ footerLinkAbout = Quant al Test Pilot
|
||||||
footerLinkPrivacy = Privadesa
|
footerLinkPrivacy = Privadesa
|
||||||
footerLinkTerms = Condicions d'ús
|
footerLinkTerms = Condicions d'ús
|
||||||
footerLinkCookies = Galetes
|
footerLinkCookies = Galetes
|
||||||
|
requirePasswordCheckbox = Sol·licita una contrasenya per baixar aquest fitxer
|
||||||
|
addPasswordButton = Afegeix una contrasenya
|
||||||
|
passwordTryAgain = La contrasenya és incorrecta. Torneu-ho a provar.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Contrasenya: { $password }
|
||||||
|
reportIPInfringement = Denuncieu una infracció de propietat intel·lectual
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Tiya' pe rutzijol chwe toq xtitz'aqät rujotob'axik.
|
||||||
uploadSuccessConfirmHeader = Ütz chik richin Nitaq
|
uploadSuccessConfirmHeader = Ütz chik richin Nitaq
|
||||||
uploadSvgAlt = Tijotob'äx
|
uploadSvgAlt = Tijotob'äx
|
||||||
uploadSuccessTimingHeader = Ri ruximonel yakb'äl xtik'is ruq'ijul toq xtiqasäx jumul o pa 24 ramaj.
|
uploadSuccessTimingHeader = Ri ruximonel yakb'äl xtik'is ruq'ijul toq xtiqasäx jumul o pa 24 ramaj.
|
||||||
|
expireInfo = Ri ruximöy ayakb'al xtik'is ruq'ijul chi rij ri { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 qasanïk
|
||||||
|
*[other] { $num } taq qasanïk
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 ramaj
|
||||||
|
*[other] { $num } taq ramaj
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Tiwachib'ëx chuqa' tikomonïx ri ximonel richin nitaq ri ayakb'äl: { $filename }
|
copyUrlFormLabelWithName = Tiwachib'ëx chuqa' tikomonïx ri ximonel richin nitaq ri ayakb'äl: { $filename }
|
||||||
copyUrlFormButton = Tiwachib'ëx pa molwuj
|
copyUrlFormButton = Tiwachib'ëx pa molwuj
|
||||||
copiedUrl = ¡Xwachib'ëx!
|
copiedUrl = ¡Xwachib'ëx!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Tiyuj yakb'äl
|
||||||
sendAnotherFileLink = Titaq jun chik yakb'äl
|
sendAnotherFileLink = Titaq jun chik yakb'äl
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Tiqasäx
|
downloadAltText = Tiqasäx
|
||||||
|
downloadsFileList = Taq qasanïk
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Q'ijul
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Tiqasäx { $filename }
|
downloadFileName = Tiqasäx { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Titz'ib'äx Ewan Tzij
|
unlockInputLabel = Titz'ib'äx Ewan Tzij
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Taq ojqanem
|
||||||
footerLinkCookies = Taq kaxlanwey
|
footerLinkCookies = Taq kaxlanwey
|
||||||
requirePasswordCheckbox = Tik'utüx jun ewan tzij richin niqasäx re yakb'äl re'
|
requirePasswordCheckbox = Tik'utüx jun ewan tzij richin niqasäx re yakb'äl re'
|
||||||
addPasswordButton = Titz'aqatisäx Ewan Tzij
|
addPasswordButton = Titz'aqatisäx Ewan Tzij
|
||||||
|
changePasswordButton = Tijalwachïx
|
||||||
passwordTryAgain = Itzel ri ewan tzij. Tatojtob'ej chik.
|
passwordTryAgain = Itzel ri ewan tzij. Tatojtob'ej chik.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Ewan tzij: { $password }
|
passwordResult = Ewan tzij: { $password }
|
||||||
|
reportIPInfringement = Tiya' rutzijol ri Ritzelanik Ajna'oj Ichinil
|
||||||
|
javascriptRequired = K'atzinel JavaScript chi re ri Firefox Send
|
||||||
|
whyJavascript =
|
||||||
|
enableJavascript = Titz'ij JavaScript richin nitojtob'ëx chik.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }r { $minutes }ch
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }ch
|
||||||
|
|
|
@ -25,6 +25,17 @@ uploadingFileNotification = Upozornit, až bude nahrávání dokončeno.
|
||||||
uploadSuccessConfirmHeader = Připraveno k odeslání
|
uploadSuccessConfirmHeader = Připraveno k odeslání
|
||||||
uploadSvgAlt = Nahrát
|
uploadSvgAlt = Nahrát
|
||||||
uploadSuccessTimingHeader = Platnost odkazu na váš soubor vyprší po jeho prvním stažení, nebo po 24 hodinách.
|
uploadSuccessTimingHeader = Platnost odkazu na váš soubor vyprší po jeho prvním stažení, nebo po 24 hodinách.
|
||||||
|
expireInfo = Platnost odkazu na váš soubor vyprší po { $downloadCount } nebo { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] jednom stažení
|
||||||
|
[few] { $num } staženích
|
||||||
|
*[other] { $num } staženích
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] hodina
|
||||||
|
[few] hodiny
|
||||||
|
*[other] hodin
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Zkopírujte a sdílejte odkaz na váš soubor: { $filename }
|
copyUrlFormLabelWithName = Zkopírujte a sdílejte odkaz na váš soubor: { $filename }
|
||||||
copyUrlFormButton = Zkopírovat do schránky
|
copyUrlFormButton = Zkopírovat do schránky
|
||||||
copiedUrl = Zkopírováno!
|
copiedUrl = Zkopírováno!
|
||||||
|
@ -32,6 +43,8 @@ deleteFileButton = Smazat soubor
|
||||||
sendAnotherFileLink = Poslat další soubor
|
sendAnotherFileLink = Poslat další soubor
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Stáhnout
|
downloadAltText = Stáhnout
|
||||||
|
downloadsFileList = Stažení
|
||||||
|
timeFileList = Zbývá
|
||||||
downloadFileName = Stáhnout { $filename }
|
downloadFileName = Stáhnout { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Zadejte heslo
|
unlockInputLabel = Zadejte heslo
|
||||||
|
@ -86,6 +99,8 @@ footerLinkTerms = Podmínky
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Vyžadovat heslo pro stažení tohoto souboru
|
requirePasswordCheckbox = Vyžadovat heslo pro stažení tohoto souboru
|
||||||
addPasswordButton = Přidat heslo
|
addPasswordButton = Přidat heslo
|
||||||
|
changePasswordButton = Změnit
|
||||||
passwordTryAgain = Špatné heslo. Zkuste to znovu.
|
passwordTryAgain = Špatné heslo. Zkuste to znovu.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Heslo: { $password }
|
passwordResult = Heslo: { $password }
|
||||||
|
reportIPInfringement = Nahlásit porušení autorských práv
|
||||||
|
|
|
@ -25,6 +25,19 @@ uploadingFileNotification = Dweud pan fydd y llwytho wedi gorffen.
|
||||||
uploadSuccessConfirmHeader = Yn Barod i Anfon
|
uploadSuccessConfirmHeader = Yn Barod i Anfon
|
||||||
uploadSvgAlt = Llwytho i Fyny
|
uploadSvgAlt = Llwytho i Fyny
|
||||||
uploadSuccessTimingHeader = Bydd y ddolen i'ch ffeil y dod i ben ar ôl 1 llwytho neu o fewn 24 awr.
|
uploadSuccessTimingHeader = Bydd y ddolen i'ch ffeil y dod i ben ar ôl 1 llwytho neu o fewn 24 awr.
|
||||||
|
expireInfo = Bydd y ddolen i'ch ffeil yn dod i ben ym mhen { $downloadCount } neu { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] Llwyth i lawr
|
||||||
|
[two] Lwyth i lawr
|
||||||
|
[few] Llwyth i lawr
|
||||||
|
*[other] Llwyth i lawr
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] awr
|
||||||
|
[two] awr
|
||||||
|
[few] awr
|
||||||
|
*[other] awr
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copïo a rhannu'r ddolen i anfon eich ffeil: { $filename }
|
copyUrlFormLabelWithName = Copïo a rhannu'r ddolen i anfon eich ffeil: { $filename }
|
||||||
copyUrlFormButton = Copïo i'r clipfwrdd
|
copyUrlFormButton = Copïo i'r clipfwrdd
|
||||||
copiedUrl = Wedi eu copïo!
|
copiedUrl = Wedi eu copïo!
|
||||||
|
@ -32,6 +45,8 @@ deleteFileButton = Dileu ffeil
|
||||||
sendAnotherFileLink = Anfon ffeil arall
|
sendAnotherFileLink = Anfon ffeil arall
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Llwytho i lawr
|
downloadAltText = Llwytho i lawr
|
||||||
|
downloadsFileList = Llwythi
|
||||||
|
timeFileList = Amser
|
||||||
downloadFileName = Llwytho i lawr { $filename }
|
downloadFileName = Llwytho i lawr { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Rhowch Gyfrinair
|
unlockInputLabel = Rhowch Gyfrinair
|
||||||
|
@ -86,6 +101,8 @@ footerLinkTerms = Amodau
|
||||||
footerLinkCookies = Cwcis
|
footerLinkCookies = Cwcis
|
||||||
requirePasswordCheckbox = Gosod angen cyfrinair i lwytho'r ffeil hon i lawr
|
requirePasswordCheckbox = Gosod angen cyfrinair i lwytho'r ffeil hon i lawr
|
||||||
addPasswordButton = Ychwanegu Cyfrinair
|
addPasswordButton = Ychwanegu Cyfrinair
|
||||||
|
changePasswordButton = Newid
|
||||||
passwordTryAgain = Cyfrinair anghywir. Ceisiwch eto.
|
passwordTryAgain = Cyfrinair anghywir. Ceisiwch eto.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Cyfrinair: { $password }
|
passwordResult = Cyfrinair: { $password }
|
||||||
|
reportIPInfringement = Adrodd ar Gamddefnydd o'r IP
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Mich benachrichtigen, wenn der Upload abgeschlossen
|
||||||
uploadSuccessConfirmHeader = Bereit zum Senden
|
uploadSuccessConfirmHeader = Bereit zum Senden
|
||||||
uploadSvgAlt = Hochladen
|
uploadSvgAlt = Hochladen
|
||||||
uploadSuccessTimingHeader = Der Link zu Ihrer Datei läuft nach einem Download oder in 24 Stunden ab.
|
uploadSuccessTimingHeader = Der Link zu Ihrer Datei läuft nach einem Download oder in 24 Stunden ab.
|
||||||
|
expireInfo = Der Link zu Ihrer Datei läuft nach { $downloadCount } oder { $timespan } ab.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] einem Download
|
||||||
|
*[other] { $num } Downloads
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] einer Stunde
|
||||||
|
*[other] { $num } Stunden
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopieren und teilen Sie den Link, um Ihre Datei zu senden: { $filename }
|
copyUrlFormLabelWithName = Kopieren und teilen Sie den Link, um Ihre Datei zu senden: { $filename }
|
||||||
copyUrlFormButton = In Zwischenablage kopieren
|
copyUrlFormButton = In Zwischenablage kopieren
|
||||||
copiedUrl = Kopiert!
|
copiedUrl = Kopiert!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Datei löschen
|
||||||
sendAnotherFileLink = Eine weitere Datei senden
|
sendAnotherFileLink = Eine weitere Datei senden
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Herunterladen
|
downloadAltText = Herunterladen
|
||||||
|
downloadsFileList = Downloads
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Zeit
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } herunterladen
|
downloadFileName = { $filename } herunterladen
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Passwort eingeben
|
unlockInputLabel = Passwort eingeben
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Nutzungsbedingungen
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Zum Herunterladen dieser Datei soll ein Passwort erforderlich sein
|
requirePasswordCheckbox = Zum Herunterladen dieser Datei soll ein Passwort erforderlich sein
|
||||||
addPasswordButton = Passwort hinzufügen
|
addPasswordButton = Passwort hinzufügen
|
||||||
|
changePasswordButton = Ändern
|
||||||
passwordTryAgain = Falsches Passwort. Versuchen Sie es erneut.
|
passwordTryAgain = Falsches Passwort. Versuchen Sie es erneut.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Passwort: { $password }
|
passwordResult = Passwort: { $password }
|
||||||
|
reportIPInfringement = IP-Verletzung melden
|
||||||
|
javascriptRequired = Firefox Send benötigt JavaScript
|
||||||
|
whyJavascript = Warum benötigt Firefox Send JavaScript?
|
||||||
|
enableJavascript = Bitte akivieren Sie JavaScript und versuchen Sie es erneut.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,19 @@ uploadingFileNotification = K wěsći daś, gaž nagraśe jo dokóńcone.
|
||||||
uploadSuccessConfirmHeader = Gótowy za słanje
|
uploadSuccessConfirmHeader = Gótowy za słanje
|
||||||
uploadSvgAlt = Nagraś
|
uploadSvgAlt = Nagraś
|
||||||
uploadSuccessTimingHeader = Wótkaz k wašej dataji pó 1 ześěgnjenju abo 24 góźinach spadnjo.
|
uploadSuccessTimingHeader = Wótkaz k wašej dataji pó 1 ześěgnjenju abo 24 góźinach spadnjo.
|
||||||
|
expireInfo = Wótkaz k wašej dataji pó { $downloadCount } abo { $timespan } spadnjo.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 ześěgnjenje
|
||||||
|
[two] { $num } ześěgnjeni
|
||||||
|
[few] { $num } ześěgnjenja
|
||||||
|
*[other] { $num } ześěgnjenjow
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 góźina
|
||||||
|
[two] { $num } góźinje
|
||||||
|
[few] { $num } góźiny
|
||||||
|
*[other] { $num } góźin
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopěrujśo a źělśo wótkaz, aby swóju dataju pósłał: { $filename }
|
copyUrlFormLabelWithName = Kopěrujśo a źělśo wótkaz, aby swóju dataju pósłał: { $filename }
|
||||||
copyUrlFormButton = Do mjazywótkłada kopěrowaś
|
copyUrlFormButton = Do mjazywótkłada kopěrowaś
|
||||||
copiedUrl = Kopěrowany!
|
copiedUrl = Kopěrowany!
|
||||||
|
@ -32,6 +45,12 @@ deleteFileButton = Dataju wulašowaś
|
||||||
sendAnotherFileLink = Drugu dataju pósłaś
|
sendAnotherFileLink = Drugu dataju pósłaś
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Ześěgnuś
|
downloadAltText = Ześěgnuś
|
||||||
|
downloadsFileList = Ześěgnjenja
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Cas
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } ześěgnuś
|
downloadFileName = { $filename } ześěgnuś
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Gronidło zapódaś
|
unlockInputLabel = Gronidło zapódaś
|
||||||
|
@ -86,6 +105,15 @@ footerLinkTerms = Wuměnjenja
|
||||||
footerLinkCookies = Cookieje
|
footerLinkCookies = Cookieje
|
||||||
requirePasswordCheckbox = Gronidło za ześěgnjenje toś teje dataje pominaś
|
requirePasswordCheckbox = Gronidło za ześěgnjenje toś teje dataje pominaś
|
||||||
addPasswordButton = Gronidło pśidaś
|
addPasswordButton = Gronidło pśidaś
|
||||||
|
changePasswordButton = Změniś
|
||||||
passwordTryAgain = Wopacne gronidło. Wopytajśo hyšći raz.
|
passwordTryAgain = Wopacne gronidło. Wopytajśo hyšći raz.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Gronidło: { $password }
|
passwordResult = Gronidło: { $password }
|
||||||
|
reportIPInfringement = Pśekśiwjenje IP k wěsći daś
|
||||||
|
javascriptRequired = Firefox Send JavaScript trjeba
|
||||||
|
whyJavascript = Cogodla Firefox Send JavaScript trjeba?
|
||||||
|
enableJavascript = Pšosym zmóžniśo JavaScript a wopytajśo hyšći raz.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours } góź. { $minutes } min.
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } min.
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Ειδοποίηση όταν ολοκληρωθεί
|
||||||
uploadSuccessConfirmHeader = Έτοιμο για αποστολή
|
uploadSuccessConfirmHeader = Έτοιμο για αποστολή
|
||||||
uploadSvgAlt = Μεταφόρτωση
|
uploadSvgAlt = Μεταφόρτωση
|
||||||
uploadSuccessTimingHeader = Ο σύνδεσμος του αρχείου σας θα λήξει έπειτα από 1 λήψη ή 24 ώρες.
|
uploadSuccessTimingHeader = Ο σύνδεσμος του αρχείου σας θα λήξει έπειτα από 1 λήψη ή 24 ώρες.
|
||||||
|
expireInfo = Ο σύνδεσμος για το αρχείο σας θα λήξει μετά από { $downloadCount } ή { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 λήψη
|
||||||
|
*[other] { $num } λήψεις
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 ώρα
|
||||||
|
*[other] { $num } ώρες
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Αντιγράψτε και μοιραστείτε τον σύνδεσμο για αποστολή του αρχείου σας : { $filename }
|
copyUrlFormLabelWithName = Αντιγράψτε και μοιραστείτε τον σύνδεσμο για αποστολή του αρχείου σας : { $filename }
|
||||||
copyUrlFormButton = Αντιγραφή στο πρόχειρο
|
copyUrlFormButton = Αντιγραφή στο πρόχειρο
|
||||||
copiedUrl = Αντιγράφτηκε!
|
copiedUrl = Αντιγράφτηκε!
|
||||||
|
@ -86,4 +95,7 @@ footerLinkTerms = Όροι
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Απαίτηση κωδικού πρόσβασης για λήψη του αρχείου
|
requirePasswordCheckbox = Απαίτηση κωδικού πρόσβασης για λήψη του αρχείου
|
||||||
addPasswordButton = Προσθήκη κωδικού πρόσβασης
|
addPasswordButton = Προσθήκη κωδικού πρόσβασης
|
||||||
incorrectPassword = Λάθος κωδικός πρόσβασης. Προσπάθεια ξανά;
|
passwordTryAgain = Λάθος κωδικός πρόσβασης. Δοκιμάστε ξανά.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Κωδικός πρόσβασης: { $password }
|
||||||
|
reportIPInfringement = Αναφορά παραβίασης IP
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Notify me when the upload is complete.
|
||||||
uploadSuccessConfirmHeader = Ready to Send
|
uploadSuccessConfirmHeader = Ready to Send
|
||||||
uploadSvgAlt = Upload
|
uploadSvgAlt = Upload
|
||||||
uploadSuccessTimingHeader = The link to your file will expire after 1 download or in 24 hours.
|
uploadSuccessTimingHeader = The link to your file will expire after 1 download or in 24 hours.
|
||||||
|
expireInfo = The link to your file will expire after { $downloadCount } or { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 download
|
||||||
|
*[other] { $num } downloads
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hour
|
||||||
|
*[other] { $num } hours
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copy and share the link to send your file: { $filename }
|
copyUrlFormLabelWithName = Copy and share the link to send your file: { $filename }
|
||||||
copyUrlFormButton = Copy to clipboard
|
copyUrlFormButton = Copy to clipboard
|
||||||
copiedUrl = Copied!
|
copiedUrl = Copied!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Delete file
|
||||||
sendAnotherFileLink = Send another file
|
sendAnotherFileLink = Send another file
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Download
|
downloadAltText = Download
|
||||||
|
downloadsFileList = Downloads
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Time
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Download { $filename }
|
downloadFileName = Download { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Enter Password
|
unlockInputLabel = Enter Password
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Terms
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Require a password to download this file
|
requirePasswordCheckbox = Require a password to download this file
|
||||||
addPasswordButton = Add password
|
addPasswordButton = Add password
|
||||||
|
changePasswordButton = Change
|
||||||
passwordTryAgain = Incorrect password. Try again.
|
passwordTryAgain = Incorrect password. Try again.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Password: { $password }
|
passwordResult = Password: { $password }
|
||||||
|
reportIPInfringement = Report IP Infringement
|
||||||
|
javascriptRequired = Firefox Send requires JavaScript
|
||||||
|
whyJavascript = Why does Firefox Send require JavaScript?
|
||||||
|
enableJavascript = Please enable JavaScript and try again.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Notificarme cuando la subida se complete.
|
||||||
uploadSuccessConfirmHeader = Listo para enviar
|
uploadSuccessConfirmHeader = Listo para enviar
|
||||||
uploadSvgAlt = Subir
|
uploadSvgAlt = Subir
|
||||||
uploadSuccessTimingHeader = El enlace al archivo expirará después de 1 descarga o en 24 horas.
|
uploadSuccessTimingHeader = El enlace al archivo expirará después de 1 descarga o en 24 horas.
|
||||||
|
expireInfo = El enlace a tu archivo expirará después de { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 descarga
|
||||||
|
*[other] { $num } descargas
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hora
|
||||||
|
*[other] { $num } horas
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copiá y compartí el enlace para enviar tu archivo: { $filename }
|
copyUrlFormLabelWithName = Copiá y compartí el enlace para enviar tu archivo: { $filename }
|
||||||
copyUrlFormButton = Copiar al portapapeles
|
copyUrlFormButton = Copiar al portapapeles
|
||||||
copiedUrl = ¡Copiado!
|
copiedUrl = ¡Copiado!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Borrar archivo
|
||||||
sendAnotherFileLink = Enviar otro archivo
|
sendAnotherFileLink = Enviar otro archivo
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Descargar
|
downloadAltText = Descargar
|
||||||
|
downloadsFileList = Descargas
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tiempo
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Descargar { $filename }
|
downloadFileName = Descargar { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Ingresar contraseña
|
unlockInputLabel = Ingresar contraseña
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Términos
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Requerir contraseña para descargar este archivo
|
requirePasswordCheckbox = Requerir contraseña para descargar este archivo
|
||||||
addPasswordButton = Agregar contraseña
|
addPasswordButton = Agregar contraseña
|
||||||
|
changePasswordButton = Cambiar
|
||||||
passwordTryAgain = Contraseña incorrecta. Intentá nuevamente.
|
passwordTryAgain = Contraseña incorrecta. Intentá nuevamente.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Contraseña: { $password }
|
passwordResult = Contraseña: { $password }
|
||||||
|
reportIPInfringement = Informar violación de propiedad intelectual
|
||||||
|
javascriptRequired = Firefox Send requiere JavaScript
|
||||||
|
whyJavascript = ¿Por qué Firefox Send requiere Java Script?
|
||||||
|
enableJavascript = Por favor habilite JavaScript y pruebe de nuevo.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = h { $hours } m { $minutes }
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = m { $minutes }
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Notificarme cuando la subida sea completada.
|
||||||
uploadSuccessConfirmHeader = Listo para enviar
|
uploadSuccessConfirmHeader = Listo para enviar
|
||||||
uploadSvgAlt = Subir
|
uploadSvgAlt = Subir
|
||||||
uploadSuccessTimingHeader = El enlace a tu archivo expirará tras 1 descarga o en 24 horas.
|
uploadSuccessTimingHeader = El enlace a tu archivo expirará tras 1 descarga o en 24 horas.
|
||||||
|
expireInfo = El enlace a tu archivo expirará después de { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 descarga
|
||||||
|
*[other] { $num } descargas
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hora
|
||||||
|
*[other] { $num } horas
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copia y comparte el enlace para enviar tu archivo: { $filename }
|
copyUrlFormLabelWithName = Copia y comparte el enlace para enviar tu archivo: { $filename }
|
||||||
copyUrlFormButton = Copiar al portapapeles
|
copyUrlFormButton = Copiar al portapapeles
|
||||||
copiedUrl = ¡Copiado!
|
copiedUrl = ¡Copiado!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Eliminar archivo
|
||||||
sendAnotherFileLink = Enviar otro archivo
|
sendAnotherFileLink = Enviar otro archivo
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Descargar
|
downloadAltText = Descargar
|
||||||
|
downloadsFileList = Descargas
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tiempo
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Descargar { $filename }
|
downloadFileName = Descargar { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Ingresar contraseña
|
unlockInputLabel = Ingresar contraseña
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Términos
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
|
requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
|
||||||
addPasswordButton = Añadir contraseña
|
addPasswordButton = Añadir contraseña
|
||||||
|
changePasswordButton = Cambiar
|
||||||
passwordTryAgain = Contraseña incorrecta. Vuelve a intentarlo.
|
passwordTryAgain = Contraseña incorrecta. Vuelve a intentarlo.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Contraseña: { $password }
|
passwordResult = Contraseña: { $password }
|
||||||
|
reportIPInfringement = Reportar infracción de PI
|
||||||
|
javascriptRequired = Firefox Send requiere JavaScript.
|
||||||
|
whyJavascript = ¿Por qué Firefox Send requiere JavaScript?
|
||||||
|
enableJavascript = Por favor, activa JavaScript y vuelve a intentarlo.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Notificarme cuando se complete la subida.
|
||||||
uploadSuccessConfirmHeader = Listo para enviar
|
uploadSuccessConfirmHeader = Listo para enviar
|
||||||
uploadSvgAlt = Subir
|
uploadSvgAlt = Subir
|
||||||
uploadSuccessTimingHeader = El enlace al archivo caducará tras descargarlo una vez o en 24 horas.
|
uploadSuccessTimingHeader = El enlace al archivo caducará tras descargarlo una vez o en 24 horas.
|
||||||
|
expireInfo = El enlace al archivo expirará tras { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 descarga
|
||||||
|
*[other] { $num } descargas
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hora
|
||||||
|
*[other] { $num } horas
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copiar y compartir el enlace para enviar tu archivo: { $filename }
|
copyUrlFormLabelWithName = Copiar y compartir el enlace para enviar tu archivo: { $filename }
|
||||||
copyUrlFormButton = Copiar en el portapapeles
|
copyUrlFormButton = Copiar en el portapapeles
|
||||||
copiedUrl = ¡Copiado!
|
copiedUrl = ¡Copiado!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Eliminar archivo
|
||||||
sendAnotherFileLink = Enviar otro archivo
|
sendAnotherFileLink = Enviar otro archivo
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Descargar
|
downloadAltText = Descargar
|
||||||
|
downloadsFileList = Descargas
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Fecha
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Descargar { $filename }
|
downloadFileName = Descargar { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Introducir contraseña
|
unlockInputLabel = Introducir contraseña
|
||||||
|
@ -86,6 +101,8 @@ footerLinkTerms = Términos
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
|
requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
|
||||||
addPasswordButton = Añadir contraseña
|
addPasswordButton = Añadir contraseña
|
||||||
|
changePasswordButton = Cambiar
|
||||||
passwordTryAgain = Contraseña incorrecta. Inténtelo de nuevo.
|
passwordTryAgain = Contraseña incorrecta. Inténtelo de nuevo.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Contraseña: { $password }
|
passwordResult = Contraseña: { $password }
|
||||||
|
reportIPInfringement = Denunciar vulneración de propiedad intelectual
|
||||||
|
|
|
@ -25,6 +25,14 @@ uploadingFileNotification = Avísame cuando la subida del archivo esté completa
|
||||||
uploadSuccessConfirmHeader = Listo para enviar
|
uploadSuccessConfirmHeader = Listo para enviar
|
||||||
uploadSvgAlt = Subir
|
uploadSvgAlt = Subir
|
||||||
uploadSuccessTimingHeader = El enlace a tu archivo expirará después de una descarga o en 24 horas.
|
uploadSuccessTimingHeader = El enlace a tu archivo expirará después de una descarga o en 24 horas.
|
||||||
|
expireInfo = El enlace a tu archivo expirará después de { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[one] 1 descarga
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hora
|
||||||
|
*[other] { $num } horas
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copiar y compartir el enlace para enviar tu archivo: ($filename)
|
copyUrlFormLabelWithName = Copiar y compartir el enlace para enviar tu archivo: ($filename)
|
||||||
copyUrlFormButton = Copiar a portapapeles
|
copyUrlFormButton = Copiar a portapapeles
|
||||||
copiedUrl = ¡Copiado!
|
copiedUrl = ¡Copiado!
|
||||||
|
@ -32,6 +40,8 @@ deleteFileButton = Eliminar archivo
|
||||||
sendAnotherFileLink = Enviar otro archivo
|
sendAnotherFileLink = Enviar otro archivo
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Descargar
|
downloadAltText = Descargar
|
||||||
|
downloadsFileList = Descargas
|
||||||
|
timeFileList = Hora
|
||||||
downloadFileName = Descargar ($filename)
|
downloadFileName = Descargar ($filename)
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Ingresar contraseña
|
unlockInputLabel = Ingresar contraseña
|
||||||
|
@ -86,6 +96,8 @@ footerLinkTerms = Términos
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Se necesita una contraseña para descargar este archivo
|
requirePasswordCheckbox = Se necesita una contraseña para descargar este archivo
|
||||||
addPasswordButton = Agregar contraseña
|
addPasswordButton = Agregar contraseña
|
||||||
|
changePasswordButton = Cambiar
|
||||||
passwordTryAgain = Contraseña incorrecta. Intenta de nuevo.
|
passwordTryAgain = Contraseña incorrecta. Intenta de nuevo.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Contraseña: { $password }
|
passwordResult = Contraseña: { $password }
|
||||||
|
reportIPInfringement = Denunciar una infracción de PI
|
||||||
|
|
|
@ -25,6 +25,13 @@ uploadingFileNotification = هر وقت بارگذاری تمام شد به من
|
||||||
uploadSuccessConfirmHeader = آماده برای ارسال
|
uploadSuccessConfirmHeader = آماده برای ارسال
|
||||||
uploadSvgAlt = بارگذاری
|
uploadSvgAlt = بارگذاری
|
||||||
uploadSuccessTimingHeader = پیوند به پرونده شما بعد از ۱ بار دانلود یا ۲۴ ساعت حذف خواهد شد.
|
uploadSuccessTimingHeader = پیوند به پرونده شما بعد از ۱ بار دانلود یا ۲۴ ساعت حذف خواهد شد.
|
||||||
|
expireInfo = این پیوند به فایل شما پس از { $downloadCount } یا { $timespan } منقضی خواهد شد.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] ۱ بارگذاری
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] ۱ ساعت
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = برای ارسال پرونده پیوند آن را رونوشت و به اشتراک بگذارید: { $filename }
|
copyUrlFormLabelWithName = برای ارسال پرونده پیوند آن را رونوشت و به اشتراک بگذارید: { $filename }
|
||||||
copyUrlFormButton = رونوشت به کلیپبورد
|
copyUrlFormButton = رونوشت به کلیپبورد
|
||||||
copiedUrl = رونوشت شد!
|
copiedUrl = رونوشت شد!
|
||||||
|
@ -32,6 +39,12 @@ deleteFileButton = حذف پرونده
|
||||||
sendAnotherFileLink = ارسال پرونده دیگر
|
sendAnotherFileLink = ارسال پرونده دیگر
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = دریافت
|
downloadAltText = دریافت
|
||||||
|
downloadsFileList = دریافتها
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = زمان
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = بارگیری { $filename }
|
downloadFileName = بارگیری { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = گذرواژه را وارد کنید
|
unlockInputLabel = گذرواژه را وارد کنید
|
||||||
|
@ -86,4 +99,15 @@ footerLinkTerms = شرایط
|
||||||
footerLinkCookies = کوکیها
|
footerLinkCookies = کوکیها
|
||||||
requirePasswordCheckbox = دریافت این پرونده نیاز به گذرواژه دارد
|
requirePasswordCheckbox = دریافت این پرونده نیاز به گذرواژه دارد
|
||||||
addPasswordButton = افزودن گذرواژه
|
addPasswordButton = افزودن گذرواژه
|
||||||
|
changePasswordButton = تغییر
|
||||||
passwordTryAgain = کلمه عبور اشتباه است. مجدد تلاش کنید.
|
passwordTryAgain = کلمه عبور اشتباه است. مجدد تلاش کنید.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = گذرواژه: { $password }
|
||||||
|
reportIPInfringement = گزارش تخلف IP
|
||||||
|
javascriptRequired = Firefox Send نیازمند جاوااسکریپت است
|
||||||
|
whyJavascript = چراFirefox Send جاوااسکریپت لازم دارد؟
|
||||||
|
enableJavascript = لطفا جاوااسکریپت را فعال کنید و مجددا تلاش کنید.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }ساعت { $minutes }دقیقه
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } دقیقه
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = M’envoyer une notification lorsque l’envoi est t
|
||||||
uploadSuccessConfirmHeader = Paré à l’envoi
|
uploadSuccessConfirmHeader = Paré à l’envoi
|
||||||
uploadSvgAlt = Envoyer
|
uploadSvgAlt = Envoyer
|
||||||
uploadSuccessTimingHeader = Le lien vers votre fichier expirera après le premier téléchargement ou au bout de 24 heures.
|
uploadSuccessTimingHeader = Le lien vers votre fichier expirera après le premier téléchargement ou au bout de 24 heures.
|
||||||
|
expireInfo = Le lien vers votre fichier expirera après { $downloadCount } ou { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 téléchargement
|
||||||
|
*[other] { $num } téléchargements
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 heure
|
||||||
|
*[other] { $num } heures
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copiez et partagez le lien pour envoyer votre fichier : { $filename }
|
copyUrlFormLabelWithName = Copiez et partagez le lien pour envoyer votre fichier : { $filename }
|
||||||
copyUrlFormButton = Copier dans le presse-papiers
|
copyUrlFormButton = Copier dans le presse-papiers
|
||||||
copiedUrl = Lien copié !
|
copiedUrl = Lien copié !
|
||||||
|
@ -32,9 +41,15 @@ deleteFileButton = Supprimer le fichier
|
||||||
sendAnotherFileLink = Envoyer un autre fichier
|
sendAnotherFileLink = Envoyer un autre fichier
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Télécharger
|
downloadAltText = Télécharger
|
||||||
|
downloadsFileList = Téléchargements
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Heure
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Télécharger { $filename }
|
downloadFileName = Télécharger { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Saisissez un mot de passe
|
unlockInputLabel = Saisissez le mot de passe
|
||||||
unlockInputPlaceholder = Mot de passe
|
unlockInputPlaceholder = Mot de passe
|
||||||
unlockButtonLabel = Déverrouiller
|
unlockButtonLabel = Déverrouiller
|
||||||
downloadFileTitle = Télécharger le fichier chiffré
|
downloadFileTitle = Télécharger le fichier chiffré
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Conditions d’utilisation
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Exiger un mot de passe pour télécharger ce fichier
|
requirePasswordCheckbox = Exiger un mot de passe pour télécharger ce fichier
|
||||||
addPasswordButton = Ajouter un mot de passe
|
addPasswordButton = Ajouter un mot de passe
|
||||||
|
changePasswordButton = Changer
|
||||||
passwordTryAgain = Mot de passe incorrect. Veuillez réessayer.
|
passwordTryAgain = Mot de passe incorrect. Veuillez réessayer.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Mot de passe : { $password }
|
passwordResult = Mot de passe : { $password }
|
||||||
|
reportIPInfringement = Signaler une violation de la p.i.
|
||||||
|
javascriptRequired = Firefox Send nécessite JavaScript
|
||||||
|
whyJavascript = Pourquoi Firefox Send nécessite-t-il JavaScript ?
|
||||||
|
enableJavascript = Veuillez activer JavaScript puis réessayer.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours } h { $minutes } min
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } min
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Jou in melding as de oplaad foltôge is.
|
||||||
uploadSuccessConfirmHeader = Ree om te ferstjoeren
|
uploadSuccessConfirmHeader = Ree om te ferstjoeren
|
||||||
uploadSvgAlt = Oplaad
|
uploadSvgAlt = Oplaad
|
||||||
uploadSuccessTimingHeader = De keppeling nei jo bestân sil nei 1 download ferrinne of nei 24 oeren.
|
uploadSuccessTimingHeader = De keppeling nei jo bestân sil nei 1 download ferrinne of nei 24 oeren.
|
||||||
|
expireInfo = De keppeling nei jo bestân sil nei { $downloadCount } of { $timespan } ferrinne.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 download
|
||||||
|
*[other] { $num } downloads
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 oer
|
||||||
|
*[other] { $num } oeren
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopiearje en diel de keppeling om jo bestân te ferstjoeren: { $filename }
|
copyUrlFormLabelWithName = Kopiearje en diel de keppeling om jo bestân te ferstjoeren: { $filename }
|
||||||
copyUrlFormButton = Nei klamboerd kopiearje
|
copyUrlFormButton = Nei klamboerd kopiearje
|
||||||
copiedUrl = Kopiearre!
|
copiedUrl = Kopiearre!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Bestân fuortsmite
|
||||||
sendAnotherFileLink = Noch in bestân ferstjoere
|
sendAnotherFileLink = Noch in bestân ferstjoere
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Downloade
|
downloadAltText = Downloade
|
||||||
|
downloadsFileList = Downloads
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tiid
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } downloade
|
downloadFileName = { $filename } downloade
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Wachtwurd ynfiere
|
unlockInputLabel = Wachtwurd ynfiere
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Betingsten
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Om dit bestân te downloaden is in wachtwurd fereaske
|
requirePasswordCheckbox = Om dit bestân te downloaden is in wachtwurd fereaske
|
||||||
addPasswordButton = Wachtwurd tafoegje
|
addPasswordButton = Wachtwurd tafoegje
|
||||||
|
changePasswordButton = Wizigje
|
||||||
passwordTryAgain = Net krekt wachtwurd. Probearje it opnij.
|
passwordTryAgain = Net krekt wachtwurd. Probearje it opnij.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Wachtwurd: { $password }
|
passwordResult = Wachtwurd: { $password }
|
||||||
|
reportIPInfringement = IP-ynbrek melde
|
||||||
|
javascriptRequired = Firefox Send fereasket JavaScript.
|
||||||
|
whyJavascript = Werom hat Firefox Send JavaScript nedich?
|
||||||
|
enableJavascript = Skeakelje JavaScript yn en probearje nochris.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }o { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,19 @@ uploadingFileNotification = Zdźělić, hdyž nahraće je dokónčene.
|
||||||
uploadSuccessConfirmHeader = Hotowy za słanje
|
uploadSuccessConfirmHeader = Hotowy za słanje
|
||||||
uploadSvgAlt = Nahrać
|
uploadSvgAlt = Nahrać
|
||||||
uploadSuccessTimingHeader = Wotkaz k wašej dataji po 1 sćehnjenju abo 24 hodźinach spadnje.
|
uploadSuccessTimingHeader = Wotkaz k wašej dataji po 1 sćehnjenju abo 24 hodźinach spadnje.
|
||||||
|
expireInfo = Wotkaz k wašej dataji po { $downloadCount } abo { $timespan } spadnje.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 sćehnjenje
|
||||||
|
[two] { $num } sćehnjeni
|
||||||
|
[few] { $num } sćehnjenja
|
||||||
|
*[other] { $num } sćehnjenjow
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hodźina
|
||||||
|
[two] { $num } hodźinje
|
||||||
|
[few] { $num } hodźiny
|
||||||
|
*[other] { $num } hodźin
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopěrujće a dźělće wotkaz, zo byšće swoju dataju pósłał: { $filename }
|
copyUrlFormLabelWithName = Kopěrujće a dźělće wotkaz, zo byšće swoju dataju pósłał: { $filename }
|
||||||
copyUrlFormButton = Do mjezyskłada kopěrować
|
copyUrlFormButton = Do mjezyskłada kopěrować
|
||||||
copiedUrl = Kopěrowany!
|
copiedUrl = Kopěrowany!
|
||||||
|
@ -32,6 +45,12 @@ deleteFileButton = Dataju zhašeć
|
||||||
sendAnotherFileLink = Druhu dataju pósłać
|
sendAnotherFileLink = Druhu dataju pósłać
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Sćahnyć
|
downloadAltText = Sćahnyć
|
||||||
|
downloadsFileList = Sćehnjenja
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Čas
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } sćahnyć
|
downloadFileName = { $filename } sćahnyć
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Hesło zapodać
|
unlockInputLabel = Hesło zapodać
|
||||||
|
@ -86,6 +105,15 @@ footerLinkTerms = Wuměnjenja
|
||||||
footerLinkCookies = Placki
|
footerLinkCookies = Placki
|
||||||
requirePasswordCheckbox = Žadajće sej hesło za sćehnjenje tuteje dataje
|
requirePasswordCheckbox = Žadajće sej hesło za sćehnjenje tuteje dataje
|
||||||
addPasswordButton = Hesło přidać
|
addPasswordButton = Hesło přidać
|
||||||
|
changePasswordButton = Změnić
|
||||||
passwordTryAgain = Wopačne hesło. Prošu spytajće hišće raz.
|
passwordTryAgain = Wopačne hesło. Prošu spytajće hišće raz.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Hesło: { $password }
|
passwordResult = Hesło: { $password }
|
||||||
|
reportIPInfringement = Zranjenje IP zdźělić
|
||||||
|
javascriptRequired = Firefox Send JavaScript trjeba
|
||||||
|
whyJavascript = Čehodla Firefox Send JavaScript trjeba?
|
||||||
|
enableJavascript = Prošu zmóžńće JavaScript a spytajće hišće raz.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours } hodź. { $minutes } mjeń.
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } mjeń.
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Értesítsen, ha a feltöltés elkészült.
|
||||||
uploadSuccessConfirmHeader = Küldésre kész
|
uploadSuccessConfirmHeader = Küldésre kész
|
||||||
uploadSvgAlt = Feltöltés
|
uploadSvgAlt = Feltöltés
|
||||||
uploadSuccessTimingHeader = A fájl hivatkozása lejár 1 letöltés vagy 24 óra múlva.
|
uploadSuccessTimingHeader = A fájl hivatkozása lejár 1 letöltés vagy 24 óra múlva.
|
||||||
|
expireInfo = A fájlhoz tartozó hivatkozás { $downloadCount } vagy { $timespan } múlva lejár.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 letöltés
|
||||||
|
*[other] { $num } letöltés
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 óra
|
||||||
|
*[other] { $num } óra
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Másolja és ossza meg a hivatkozást a fájl küldéséhez: { $filename }
|
copyUrlFormLabelWithName = Másolja és ossza meg a hivatkozást a fájl küldéséhez: { $filename }
|
||||||
copyUrlFormButton = Vágólapra másolás
|
copyUrlFormButton = Vágólapra másolás
|
||||||
copiedUrl = Másolva!
|
copiedUrl = Másolva!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Fájl törlése
|
||||||
sendAnotherFileLink = Még egy fájl küldése
|
sendAnotherFileLink = Még egy fájl küldése
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Letöltés
|
downloadAltText = Letöltés
|
||||||
|
downloadsFileList = Letöltések
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Idő
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } letöltése
|
downloadFileName = { $filename } letöltése
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Adja meg a jelszót
|
unlockInputLabel = Adja meg a jelszót
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Feltételek
|
||||||
footerLinkCookies = Sütik
|
footerLinkCookies = Sütik
|
||||||
requirePasswordCheckbox = Jelszó megkövetelése a fájl letöltéséhez
|
requirePasswordCheckbox = Jelszó megkövetelése a fájl letöltéséhez
|
||||||
addPasswordButton = Jelszó hozzáadása
|
addPasswordButton = Jelszó hozzáadása
|
||||||
|
changePasswordButton = Módosítás
|
||||||
passwordTryAgain = Helytelen jelszó. Próbálja meg újra.
|
passwordTryAgain = Helytelen jelszó. Próbálja meg újra.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Jelszó: { $password }
|
passwordResult = Jelszó: { $password }
|
||||||
|
reportIPInfringement = Szellemi tulajdon megsértésének bejelentése
|
||||||
|
javascriptRequired = A Firefox Sendhez JavaScript szükséges
|
||||||
|
whyJavascript = Miért van szükség JavaScriptre a Firefox Sendhez?
|
||||||
|
enableJavascript = Kérjük engedélyezze a JavaScriptet, majd próbálkozzon újra.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }ó { $minutes }p
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }p
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
title = Firefox Send
|
||||||
|
siteSubtitle = un experimento web
|
||||||
|
siteFeedback = Reaction
|
||||||
|
uploadPageHeader = Compartimento de files private e cryptate
|
||||||
|
uploadPageExplainer = Invia files per un ligamine secur, private e cryptate que automaticamente expira pro assecurar que tu datos non resta in linea per sempre.
|
||||||
|
uploadPageLearnMore = Saper plus
|
||||||
|
uploadPageDropMessage = Depone ci tu file pro comenciar a lo cargar
|
||||||
|
uploadPageSizeMessage = Pro evitar problemas, mantene tu file sub 1GB
|
||||||
|
uploadPageBrowseButton = Elige un file sur tu computator
|
||||||
|
uploadPageBrowseButton1 = Elige un file a cargar
|
||||||
|
uploadPageMultipleFilesAlert = Le cargamento de plure files o de un plica actualmente non es supportate.
|
||||||
|
uploadPageBrowseButtonTitle = Cargar le file
|
||||||
|
uploadingPageProgress = Cargamento de { $filename } ({ $size })
|
||||||
|
importingFile = Importation…
|
||||||
|
verifyingFile = Verifica…
|
||||||
|
encryptingFile = Cryptation...
|
||||||
|
decryptingFile = Decryptation…
|
||||||
|
notifyUploadDone = Cargamento terminate
|
||||||
|
uploadingPageMessage = Post cargate tu file, tu potera definir le optiones de expiration.
|
||||||
|
uploadingPageCancel = Cancellar le cargamento
|
||||||
|
uploadCancelNotification = Cargamento cancellate.
|
||||||
|
uploadingPageLargeFileMessage = Iste file es grande e pote prender multe tempore pro le cargamento. Patientia!
|
||||||
|
uploadingFileNotification = Notificar me quando le cargamento es complete.
|
||||||
|
uploadSuccessConfirmHeader = Preste a inviar
|
||||||
|
uploadSvgAlt = Cargamento
|
||||||
|
uploadSuccessTimingHeader = Le ligamine a tu file expirara post un discargamento o in 24 horas.
|
||||||
|
expireInfo = Le ligamine a tu file expirara post { $downloadCount } o { $timespan }
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] discargamento
|
||||||
|
*[other] discargamentos
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] hora
|
||||||
|
*[other] horas
|
||||||
|
}
|
||||||
|
copyUrlFormLabelWithName = Copia e comparti le ligamine pro inviar tu file: { $filename }
|
||||||
|
copyUrlFormButton = Copiar al area de transferentia
|
||||||
|
copiedUrl = Copiate!
|
||||||
|
deleteFileButton = Deler le file
|
||||||
|
sendAnotherFileLink = Inviar un altere file
|
||||||
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
|
downloadAltText = Discargar
|
||||||
|
downloadsFileList = Discargamentos
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tempore
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
|
downloadFileName = Discargar { $filename }
|
||||||
|
downloadFileSize = ({ $size })
|
||||||
|
unlockInputLabel = Insere le contrasigno
|
||||||
|
unlockInputPlaceholder = Contrasigno
|
||||||
|
unlockButtonLabel = Disblocar
|
||||||
|
downloadFileTitle = Discargar le file cryptate
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
downloadMessage = Tu amico te invia un file per Firefox Send, un servicio que te permitte de compartir files per un ligamine secur, private e cryptate, que expira automaticamente pro te assecurar que tu datos non resta online per sempre.
|
||||||
|
// Text and title used on the download link/button (indicates an action).
|
||||||
|
downloadButtonLabel = Discargar
|
||||||
|
downloadNotification = Tu discargamento es completate.
|
||||||
|
downloadFinish = Discargamento completate
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
sendYourFilesLink = Proba Firefox Send
|
||||||
|
downloadingPageProgress = Discargamento de { $filename } ({ $size })
|
||||||
|
downloadingPageMessage = Per favor lassa iste scheda aperte durante que nos prende tu file e lo decifra.
|
||||||
|
errorAltText = Error de cargamento.
|
||||||
|
errorPageHeader = Un error occurreva!
|
||||||
|
errorPageMessage = Un error occurreva durante le cargamento del file.
|
||||||
|
errorPageLink = Inviar un altere file
|
||||||
|
fileTooBig = Iste file es troppo grande pro lo cargar. Illo debe ser inferior a { $size }.
|
||||||
|
linkExpiredAlt = Ligamine expirate
|
||||||
|
expiredPageHeader = Iste ligamine expirava o illo non existeva jammais!
|
||||||
|
notSupportedHeader = Tu navigator non es supportate
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
notSupportedDetail = Infelicemente iste navigator non supporta le nove technologias web que move Firefox Send. Tu besonia de probar un altere navigator. Nos recommenda Firefox!
|
||||||
|
notSupportedLink = Perque iste navigator non es supportate?
|
||||||
|
notSupportedOutdatedDetail = Infelicemente iste version de Firefox non supporta le nove technologias web que move Firefox Send. Tu besonia de actualisar tu navigator.
|
||||||
|
updateFirefox = Actualisar Firefox
|
||||||
|
downloadFirefoxButtonSub = Discargamento gratuite
|
||||||
|
uploadedFile = File
|
||||||
|
copyFileList = Copiar le URL
|
||||||
|
// expiryFileList is used as a column header
|
||||||
|
expiryFileList = Expira in
|
||||||
|
deleteFileList = Deler
|
||||||
|
nevermindButton = No, gratias
|
||||||
|
legalHeader = Terminos & confidentialitate
|
||||||
|
legalNoticeTestPilot = Firefox Send es actualmente un Experimento pilota, e subjecte a <a>Terminos de servicio</a> e <a>Notitia de confidentialitate</a> de Experimento pilota. Tu pote saper plus re iste experimento e su recolta de datos <a>hic</a>.
|
||||||
|
legalNoticeMozilla = Le uso del sito web de Firefox Send es anque subjecte a <a>Notitia de confidentialitate de sito web</a> e <a>Terminos de servicio sito web</a>.
|
||||||
|
deletePopupText = Deler iste file?
|
||||||
|
deletePopupYes =
|
||||||
|
deletePopupCancel = Cancellar
|
||||||
|
deleteButtonHover = Deler
|
||||||
|
copyUrlHover = Copiar le URL
|
||||||
|
footerLinkLegal = Legal
|
||||||
|
// Test Pilot is a proper name and should not be localized.
|
||||||
|
footerLinkAbout = Re Test Pilot
|
||||||
|
footerLinkPrivacy = Confidentialitate
|
||||||
|
footerLinkTerms = Terminos
|
||||||
|
footerLinkCookies = Cookies
|
||||||
|
requirePasswordCheckbox = Requirer un contrasigno pro discargar iste file
|
||||||
|
addPasswordButton = Adder contrasigno
|
||||||
|
changePasswordButton = Cambiar
|
||||||
|
passwordTryAgain = Contrasigno incorrecte. Retenta.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Contrasigno: { $password }
|
||||||
|
reportIPInfringement = Reportar un violation de proprietate intellectual
|
||||||
|
javascriptRequired = Firefox Send require JavaScript
|
||||||
|
whyJavascript = Proque Firefox Send require JavaScript?
|
||||||
|
enableJavascript = Por favor activa JavaScript e tenta novemente.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
|
@ -26,6 +26,13 @@ uploadingFileNotification = Beri tahu saya ketika unggahan telah selesai.
|
||||||
uploadSuccessConfirmHeader = Siap untuk Dikirim
|
uploadSuccessConfirmHeader = Siap untuk Dikirim
|
||||||
uploadSvgAlt = Unggah
|
uploadSvgAlt = Unggah
|
||||||
uploadSuccessTimingHeader = Tautan ke berkas Anda akan berakhir setelah 1 unduhan atau dalam 24 jam.
|
uploadSuccessTimingHeader = Tautan ke berkas Anda akan berakhir setelah 1 unduhan atau dalam 24 jam.
|
||||||
|
expireInfo = Tautan ke berkas Anda akan kedaluwarsa setelah { $downloadCount } atau { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] { $number } unduhan
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] { $number } jam
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Salin dan bagikan tautan untuk mengirim berkas Anda: { $filename }
|
copyUrlFormLabelWithName = Salin dan bagikan tautan untuk mengirim berkas Anda: { $filename }
|
||||||
copyUrlFormButton = Salin ke papan klip
|
copyUrlFormButton = Salin ke papan klip
|
||||||
copiedUrl = Tersalin!
|
copiedUrl = Tersalin!
|
||||||
|
@ -37,6 +44,7 @@ downloadFileName = Unduh { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Masukkan Sandi
|
unlockInputLabel = Masukkan Sandi
|
||||||
unlockInputPlaceholder = Sandi
|
unlockInputPlaceholder = Sandi
|
||||||
|
unlockButtonLabel = Buka
|
||||||
downloadFileTitle = Unduh Berkas Terenkripsi
|
downloadFileTitle = Unduh Berkas Terenkripsi
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
downloadMessage = Teman Anda mengirimkan berkas dengan Firefox Send, layanan yang memungkinkan Anda berbagi berkas dengan tautan yang aman, pribadi, dan terenkripsi yang secara otomatis berakhir untuk memastikan berkas Anda tidak daring selamanya.
|
downloadMessage = Teman Anda mengirimkan berkas dengan Firefox Send, layanan yang memungkinkan Anda berbagi berkas dengan tautan yang aman, pribadi, dan terenkripsi yang secara otomatis berakhir untuk memastikan berkas Anda tidak daring selamanya.
|
||||||
|
@ -86,4 +94,7 @@ footerLinkTerms = Ketentuan
|
||||||
footerLinkCookies = Kuki
|
footerLinkCookies = Kuki
|
||||||
requirePasswordCheckbox = Membutuhkan sandi untuk mengunduh berkas ini
|
requirePasswordCheckbox = Membutuhkan sandi untuk mengunduh berkas ini
|
||||||
addPasswordButton = Tambahkan Sandi
|
addPasswordButton = Tambahkan Sandi
|
||||||
incorrectPassword = Sandi salah. Coba lagi?
|
passwordTryAgain = Sandi salah. Silakan coba lagi.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Sandi: { $password }
|
||||||
|
reportIPInfringement = Laporkan Pelanggaran IP
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Invia una notifica quando il caricamento è completa
|
||||||
uploadSuccessConfirmHeader = Pronto per l’invio
|
uploadSuccessConfirmHeader = Pronto per l’invio
|
||||||
uploadSvgAlt = Carica
|
uploadSvgAlt = Carica
|
||||||
uploadSuccessTimingHeader = Il link al file scadrà dopo 1 download o in 24 ore.
|
uploadSuccessTimingHeader = Il link al file scadrà dopo 1 download o in 24 ore.
|
||||||
|
expireInfo = Il link a questo file scadrà dopo { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 download
|
||||||
|
*[other] { $num } download
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 ora
|
||||||
|
*[other] { $num } ore
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copia e condividi il link per inviare il tuo file: { $filename }
|
copyUrlFormLabelWithName = Copia e condividi il link per inviare il tuo file: { $filename }
|
||||||
copyUrlFormButton = Copia negli appunti
|
copyUrlFormButton = Copia negli appunti
|
||||||
copiedUrl = Copiato
|
copiedUrl = Copiato
|
||||||
|
@ -32,6 +41,8 @@ deleteFileButton = Elimina file
|
||||||
sendAnotherFileLink = Invia un altro file
|
sendAnotherFileLink = Invia un altro file
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Scarica
|
downloadAltText = Scarica
|
||||||
|
downloadsFileList = Download
|
||||||
|
timeFileList = Scadenza
|
||||||
downloadFileName = Scarica { $filename }
|
downloadFileName = Scarica { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Inserire la password
|
unlockInputLabel = Inserire la password
|
||||||
|
@ -86,6 +97,8 @@ footerLinkTerms = Condizioni di utilizzo
|
||||||
footerLinkCookies = Cookie
|
footerLinkCookies = Cookie
|
||||||
requirePasswordCheckbox = Richiedi una password per poter scaricare questo file
|
requirePasswordCheckbox = Richiedi una password per poter scaricare questo file
|
||||||
addPasswordButton = Aggiungi password
|
addPasswordButton = Aggiungi password
|
||||||
|
changePasswordButton = Modifica
|
||||||
passwordTryAgain = Password errata, riprovare.
|
passwordTryAgain = Password errata, riprovare.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Password: { $password }
|
passwordResult = Password: { $password }
|
||||||
|
reportIPInfringement = Segnala violazione della proprietà intellettuale
|
||||||
|
|
|
@ -25,6 +25,13 @@ uploadingFileNotification = アップロード完了時に通知を受け取る
|
||||||
uploadSuccessConfirmHeader = 送信準備完了
|
uploadSuccessConfirmHeader = 送信準備完了
|
||||||
uploadSvgAlt = アップロード
|
uploadSvgAlt = アップロード
|
||||||
uploadSuccessTimingHeader = ファイルへのリンクは、1 回ダウンロードされた後、もしくは 24 時間以内に期限切れとなります。
|
uploadSuccessTimingHeader = ファイルへのリンクは、1 回ダウンロードされた後、もしくは 24 時間以内に期限切れとなります。
|
||||||
|
expireInfo = このファイルへのリンクは { $downloadCount } あるいは { $timespan } 後に期限切れとなります。
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] { $num } 回のダウンロード
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] { $num } 時間
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = ファイルを送信するにはこのリンクをコピー、共有してください: { $filename }
|
copyUrlFormLabelWithName = ファイルを送信するにはこのリンクをコピー、共有してください: { $filename }
|
||||||
copyUrlFormButton = クリップボードへコピー
|
copyUrlFormButton = クリップボードへコピー
|
||||||
copiedUrl = コピー完了!
|
copiedUrl = コピー完了!
|
||||||
|
@ -32,6 +39,12 @@ deleteFileButton = ファイルを削除
|
||||||
sendAnotherFileLink = 他のファイルを送信
|
sendAnotherFileLink = 他のファイルを送信
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = ダウンロード
|
downloadAltText = ダウンロード
|
||||||
|
downloadsFileList = ダウンロード
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = 時間
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } をダウンロード
|
downloadFileName = { $filename } をダウンロード
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = パスワードを入力
|
unlockInputLabel = パスワードを入力
|
||||||
|
@ -86,6 +99,15 @@ footerLinkTerms = 利用規約
|
||||||
footerLinkCookies = Cookie
|
footerLinkCookies = Cookie
|
||||||
requirePasswordCheckbox = このファイルをダウンロードするにはパスワードが必要です
|
requirePasswordCheckbox = このファイルをダウンロードするにはパスワードが必要です
|
||||||
addPasswordButton = パスワードを追加
|
addPasswordButton = パスワードを追加
|
||||||
|
changePasswordButton = 変更
|
||||||
passwordTryAgain = パスワードが正しくありません。再度入力してください。
|
passwordTryAgain = パスワードが正しくありません。再度入力してください。
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = パスワード: { $password }
|
passwordResult = パスワード: { $password }
|
||||||
|
reportIPInfringement = 知的財産侵害報告
|
||||||
|
javascriptRequired = Firefox Send を使うには JavaScript が必要です
|
||||||
|
whyJavascript = Firefox Send が JavaScript を必要とする理由
|
||||||
|
enableJavascript = JavaScript を有効にして再度試してください。
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours } 時間 { $minutes } 分
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } 分
|
||||||
|
|
|
@ -25,6 +25,13 @@ uploadingFileNotification = შეტყობინება, ატვირ
|
||||||
uploadSuccessConfirmHeader = მზადაა გასაგზავნად
|
uploadSuccessConfirmHeader = მზადაა გასაგზავნად
|
||||||
uploadSvgAlt = ატვირთვა
|
uploadSvgAlt = ატვირთვა
|
||||||
uploadSuccessTimingHeader = ფაილს ვადა გაუვა 1 ჩამოტვირთვის, ან 24 საათის მერე.
|
uploadSuccessTimingHeader = ფაილს ვადა გაუვა 1 ჩამოტვირთვის, ან 24 საათის მერე.
|
||||||
|
expireInfo = ფაილის ბმულს, ვადა გაუვა { $downloadCount }, ან { $timespan } მერე.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] { $num } ჩამოტვირთვა
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] { $num } საათი
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = დააკოპირეთ და გააზიარეთ ბმული, ფაილის გასაგზავნად: { $filename }
|
copyUrlFormLabelWithName = დააკოპირეთ და გააზიარეთ ბმული, ფაილის გასაგზავნად: { $filename }
|
||||||
copyUrlFormButton = დაკოპირება
|
copyUrlFormButton = დაკოპირება
|
||||||
copiedUrl = დაკოპირდა!
|
copiedUrl = დაკოპირდა!
|
||||||
|
@ -32,6 +39,8 @@ deleteFileButton = ფაილის წაშლა
|
||||||
sendAnotherFileLink = სხვა ფაილის გაგზავნა
|
sendAnotherFileLink = სხვა ფაილის გაგზავნა
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = ჩამოტვირთვა
|
downloadAltText = ჩამოტვირთვა
|
||||||
|
downloadsFileList = ჩამოტვირთვები
|
||||||
|
timeFileList = დრო
|
||||||
downloadFileName = { $filename } ჩამოტვირთვა
|
downloadFileName = { $filename } ჩამოტვირთვა
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = შეიყვანეთ პაროლი
|
unlockInputLabel = შეიყვანეთ პაროლი
|
||||||
|
@ -86,6 +95,8 @@ footerLinkTerms = პირობები
|
||||||
footerLinkCookies = ფუნთუშები
|
footerLinkCookies = ფუნთუშები
|
||||||
requirePasswordCheckbox = პაროლის მოთხოვნა, ფაილის ჩამოტვირთვისას
|
requirePasswordCheckbox = პაროლის მოთხოვნა, ფაილის ჩამოტვირთვისას
|
||||||
addPasswordButton = პაროლის დამატება
|
addPasswordButton = პაროლის დამატება
|
||||||
|
changePasswordButton = შეცვლა
|
||||||
passwordTryAgain = პაროლი არასწორია. სცადეთ ხელახლა.
|
passwordTryAgain = პაროლი არასწორია. სცადეთ ხელახლა.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = პაროლი: { $password }
|
passwordResult = პაროლი: { $password }
|
||||||
|
reportIPInfringement = მოხსენება დარღვევაზე
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Lɣu-yid ticki yemmed usali.
|
||||||
uploadSuccessConfirmHeader = Ihegga i walluy
|
uploadSuccessConfirmHeader = Ihegga i walluy
|
||||||
uploadSvgAlt = Sali
|
uploadSvgAlt = Sali
|
||||||
uploadSuccessTimingHeader = Aseɣwen ar ufaylu-ik ad yemmet ticki yuder-d neɣ deffir n 24 n yisragen.
|
uploadSuccessTimingHeader = Aseɣwen ar ufaylu-ik ad yemmet ticki yuder-d neɣ deffir n 24 n yisragen.
|
||||||
|
expireInfo = Aseɣwen icudden ar ufaylu-inek ad yemmet send { $downloadCount } naɣ { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 usider
|
||||||
|
*[other] { $num } isidar
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 usrag
|
||||||
|
*[other] { $num } isragen
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Nɣel sakin Bḍu aseɣwen akken ad tazneḍ afaylu-ik: { $filename }
|
copyUrlFormLabelWithName = Nɣel sakin Bḍu aseɣwen akken ad tazneḍ afaylu-ik: { $filename }
|
||||||
copyUrlFormButton = Sers ɣef afus
|
copyUrlFormButton = Sers ɣef afus
|
||||||
copiedUrl = Yenɣel!
|
copiedUrl = Yenɣel!
|
||||||
|
@ -87,3 +96,6 @@ footerLinkCookies = Inagan n tuqqna
|
||||||
requirePasswordCheckbox = YEsra awal uffir akken ad isider afaylu-agi
|
requirePasswordCheckbox = YEsra awal uffir akken ad isider afaylu-agi
|
||||||
addPasswordButton = rnu awal uffir
|
addPasswordButton = rnu awal uffir
|
||||||
passwordTryAgain = Yir awal uffir. Ɛreḍ tikelt nniḍen.
|
passwordTryAgain = Yir awal uffir. Ɛreḍ tikelt nniḍen.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Awal uffir: { $password }
|
||||||
|
reportIPInfringement = Neqqes akukel n IP
|
||||||
|
|
|
@ -26,6 +26,9 @@ uploadingFileNotification = 업로드가 완료되면 알림을 표시해 주세
|
||||||
uploadSuccessConfirmHeader = 보낼 준비 완료
|
uploadSuccessConfirmHeader = 보낼 준비 완료
|
||||||
uploadSvgAlt = 업로드
|
uploadSvgAlt = 업로드
|
||||||
uploadSuccessTimingHeader = 이 파일의 링크는 한 번의 다운로드 후 또는 24시간이 지난 뒤에 만료됩니다.
|
uploadSuccessTimingHeader = 이 파일의 링크는 한 번의 다운로드 후 또는 24시간이 지난 뒤에 만료됩니다.
|
||||||
|
expireInfo = 이 파일의 링크는 { $downloadCount }나 { $timespan } 후에 만료됩니다.
|
||||||
|
downloadCount = 1 다운로드
|
||||||
|
timespanHours = 1 시간
|
||||||
copyUrlFormLabelWithName = 파일을 보내기 위해 이 링크를 복사하고 공유하세요: { $filename }
|
copyUrlFormLabelWithName = 파일을 보내기 위해 이 링크를 복사하고 공유하세요: { $filename }
|
||||||
copyUrlFormButton = 클립보드에 복사
|
copyUrlFormButton = 클립보드에 복사
|
||||||
copiedUrl = 복사 완료!
|
copiedUrl = 복사 완료!
|
||||||
|
@ -87,4 +90,7 @@ footerLinkTerms = 이용 약관
|
||||||
footerLinkCookies = 쿠키
|
footerLinkCookies = 쿠키
|
||||||
requirePasswordCheckbox = 이 파일을 다운로드하려면 비밀번호가 필요함
|
requirePasswordCheckbox = 이 파일을 다운로드하려면 비밀번호가 필요함
|
||||||
addPasswordButton = 비밀번호 추가
|
addPasswordButton = 비밀번호 추가
|
||||||
incorrectPassword = 비밀번호가 일치하지 않습니다. 다시 시도해주세요.
|
passwordTryAgain = 비밀번호가 맞지 않습니다. 다시 시도해 주세요.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = 비밀번호: { $password }
|
||||||
|
reportIPInfringement = 지적 재산권 침해 신고
|
||||||
|
|
|
@ -25,6 +25,13 @@ uploadingFileNotification = Maklumkan saya apabila muat naik selesai.
|
||||||
uploadSuccessConfirmHeader = Sedia untuk Hantar
|
uploadSuccessConfirmHeader = Sedia untuk Hantar
|
||||||
uploadSvgAlt = Muat naik
|
uploadSvgAlt = Muat naik
|
||||||
uploadSuccessTimingHeader = Pautan ke fail anda akan luput selepas 1 muat turun atau dalam 24 jam.
|
uploadSuccessTimingHeader = Pautan ke fail anda akan luput selepas 1 muat turun atau dalam 24 jam.
|
||||||
|
expireInfo = Pautan ke fail anda akan luput selepas { $downloadCount } atau { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] { $num } muat turun
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] { $num } jam
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Salin dan kongsi pautan untuk menghantar fail anda: { $filename }
|
copyUrlFormLabelWithName = Salin dan kongsi pautan untuk menghantar fail anda: { $filename }
|
||||||
copyUrlFormButton = Salin ke Klipbod
|
copyUrlFormButton = Salin ke Klipbod
|
||||||
copiedUrl = Disalin!
|
copiedUrl = Disalin!
|
||||||
|
@ -32,6 +39,12 @@ deleteFileButton = Buang Fail
|
||||||
sendAnotherFileLink = Hantar fail lain
|
sendAnotherFileLink = Hantar fail lain
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Muat turun
|
downloadAltText = Muat turun
|
||||||
|
downloadsFileList = Muat turun
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Masa
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Muat turun { $filename }
|
downloadFileName = Muat turun { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Masukkan Kata Laluan
|
unlockInputLabel = Masukkan Kata Laluan
|
||||||
|
@ -86,6 +99,15 @@ footerLinkTerms = Terma
|
||||||
footerLinkCookies = Kuki
|
footerLinkCookies = Kuki
|
||||||
requirePasswordCheckbox = Perlu kata laluan untuk memuat turun fail ini
|
requirePasswordCheckbox = Perlu kata laluan untuk memuat turun fail ini
|
||||||
addPasswordButton = Tambah Kata laluan
|
addPasswordButton = Tambah Kata laluan
|
||||||
|
changePasswordButton = Tukar
|
||||||
passwordTryAgain = Kata laluan tidak betul. Cuba lagi.
|
passwordTryAgain = Kata laluan tidak betul. Cuba lagi.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Kata laluan: { $password }
|
passwordResult = Kata laluan: { $password }
|
||||||
|
reportIPInfringement = Lapor Pencerobohan IP
|
||||||
|
javascriptRequired = Firefox Send perlukan JavaScript
|
||||||
|
whyJavascript = Kenapa Firefox Send perlukan JavaScript?
|
||||||
|
enableJavascript = Sila dayakan JavaScript dan cuba lagi.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Varsle meg når opplastingen er ferdig.
|
||||||
uploadSuccessConfirmHeader = Klar til å sende
|
uploadSuccessConfirmHeader = Klar til å sende
|
||||||
uploadSvgAlt = Last opp
|
uploadSvgAlt = Last opp
|
||||||
uploadSuccessTimingHeader = Lenken til filen din utløper etter 1 nedlasting eller om 24 timer.
|
uploadSuccessTimingHeader = Lenken til filen din utløper etter 1 nedlasting eller om 24 timer.
|
||||||
|
expireInfo = Lenken til filen din vil gå ut etter { $downloadCount } eller { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 nedlasting
|
||||||
|
*[other] { $num } nedlastinger
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 time
|
||||||
|
*[other] { $num } timer
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopier og del linken for å sende filen: { $filename }
|
copyUrlFormLabelWithName = Kopier og del linken for å sende filen: { $filename }
|
||||||
copyUrlFormButton = Kopier til utklippstavle
|
copyUrlFormButton = Kopier til utklippstavle
|
||||||
copiedUrl = Kopiert!
|
copiedUrl = Kopiert!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Slett fil
|
||||||
sendAnotherFileLink = Send en annen fil
|
sendAnotherFileLink = Send en annen fil
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Last ned
|
downloadAltText = Last ned
|
||||||
|
downloadsFileList = Nedlastinger
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tid
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Last ned { $filename }
|
downloadFileName = Last ned { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Skriv inn passord
|
unlockInputLabel = Skriv inn passord
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Vilkår
|
||||||
footerLinkCookies = Infokapsler
|
footerLinkCookies = Infokapsler
|
||||||
requirePasswordCheckbox = Krever et passord for å laste ned denne filen
|
requirePasswordCheckbox = Krever et passord for å laste ned denne filen
|
||||||
addPasswordButton = Legg til passord
|
addPasswordButton = Legg til passord
|
||||||
|
changePasswordButton = Endre
|
||||||
passwordTryAgain = Feil passord. Prøv igjen.
|
passwordTryAgain = Feil passord. Prøv igjen.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Passord: { $password }
|
passwordResult = Passord: { $password }
|
||||||
|
reportIPInfringement = Rapporter brudd på åndsverk
|
||||||
|
javascriptRequired = Firefox Send krever JavaScript.
|
||||||
|
whyJavascript = Hvorfor krever Firefox Send JavaScript?
|
||||||
|
enableJavascript = Slå på JavaScript og prøv igjen.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }t { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Mij waarschuwen zodra het uploaden is voltooid
|
||||||
uploadSuccessConfirmHeader = Gereed voor verzending
|
uploadSuccessConfirmHeader = Gereed voor verzending
|
||||||
uploadSvgAlt = Uploaden
|
uploadSvgAlt = Uploaden
|
||||||
uploadSuccessTimingHeader = De koppeling naar uw bestand zal na 1 download of 24 uur verlopen.
|
uploadSuccessTimingHeader = De koppeling naar uw bestand zal na 1 download of 24 uur verlopen.
|
||||||
|
expireInfo = De koppeling naar uw bestand zal na { $downloadCount } of { $timespan } verlopen.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 download
|
||||||
|
*[other] { $num } downloads
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 uur
|
||||||
|
*[other] { $num } uur
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopieer en deel de koppeling om uw bestand te verzenden: { $filename }
|
copyUrlFormLabelWithName = Kopieer en deel de koppeling om uw bestand te verzenden: { $filename }
|
||||||
copyUrlFormButton = Kopiëren naar klembord
|
copyUrlFormButton = Kopiëren naar klembord
|
||||||
copiedUrl = Gekopieerd!
|
copiedUrl = Gekopieerd!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Bestand verwijderen
|
||||||
sendAnotherFileLink = Nog een bestand verzenden
|
sendAnotherFileLink = Nog een bestand verzenden
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Downloaden
|
downloadAltText = Downloaden
|
||||||
|
downloadsFileList = Downloads
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tijd
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } downloaden
|
downloadFileName = { $filename } downloaden
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Voer wachtwoord in
|
unlockInputLabel = Voer wachtwoord in
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Voorwaarden
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Een wachtwoord vereisen om dit bestand te downloaden
|
requirePasswordCheckbox = Een wachtwoord vereisen om dit bestand te downloaden
|
||||||
addPasswordButton = Wachtwoord toevoegen
|
addPasswordButton = Wachtwoord toevoegen
|
||||||
|
changePasswordButton = Wijzigen
|
||||||
passwordTryAgain = Onjuist wachtwoord. Probeer het opnieuw.
|
passwordTryAgain = Onjuist wachtwoord. Probeer het opnieuw.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Wachtwoord: { $password }
|
passwordResult = Wachtwoord: { $password }
|
||||||
|
reportIPInfringement = IE-inbreuk melden
|
||||||
|
javascriptRequired = Firefox Send vereist JavaScript
|
||||||
|
whyJavascript = Waarom vereist Firefox Send JavaScript?
|
||||||
|
enableJavascript = Schakel JavaScript in en probeer het opnieuw.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }u { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Varsle meg når opplastinga er ferdig.
|
||||||
uploadSuccessConfirmHeader = Klår til å senda
|
uploadSuccessConfirmHeader = Klår til å senda
|
||||||
uploadSvgAlt = Last opp
|
uploadSvgAlt = Last opp
|
||||||
uploadSuccessTimingHeader = Lenka til fila di går ut etter 1 nedlasting eller om 24 timar.
|
uploadSuccessTimingHeader = Lenka til fila di går ut etter 1 nedlasting eller om 24 timar.
|
||||||
|
expireInfo = Lenka til fila di vil gå ut etter { $downloadCount } eller { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 nedlasting
|
||||||
|
*[other] { $num } nedlastingar
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 time
|
||||||
|
*[other] { $num } timar
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopier og del lenka for å sende fila: { $filename }
|
copyUrlFormLabelWithName = Kopier og del lenka for å sende fila: { $filename }
|
||||||
copyUrlFormButton = Kopier til utklippstavla
|
copyUrlFormButton = Kopier til utklippstavla
|
||||||
copiedUrl = Kopiert!
|
copiedUrl = Kopiert!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Slett fil
|
||||||
sendAnotherFileLink = Send ei anna fil
|
sendAnotherFileLink = Send ei anna fil
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Last ned
|
downloadAltText = Last ned
|
||||||
|
downloadsFileList = Nedlastingar
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tid
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Last ned { $filename }
|
downloadFileName = Last ned { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Skriv inn passord
|
unlockInputLabel = Skriv inn passord
|
||||||
|
@ -86,6 +101,8 @@ footerLinkTerms = Vilkår
|
||||||
footerLinkCookies = Infokapslar
|
footerLinkCookies = Infokapslar
|
||||||
requirePasswordCheckbox = Krev eit passord for å laste ned denne fila
|
requirePasswordCheckbox = Krev eit passord for å laste ned denne fila
|
||||||
addPasswordButton = Legg til passord
|
addPasswordButton = Legg til passord
|
||||||
|
changePasswordButton = Endre
|
||||||
passwordTryAgain = Feil passord. Prøv på nytt.
|
passwordTryAgain = Feil passord. Prøv på nytt.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Passord: { $password }
|
passwordResult = Passord: { $password }
|
||||||
|
reportIPInfringement = Rapporter brot på åndsverk
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Me avise quando completar o envio.
|
||||||
uploadSuccessConfirmHeader = Pronto para enviar
|
uploadSuccessConfirmHeader = Pronto para enviar
|
||||||
uploadSvgAlt = Enviado
|
uploadSvgAlt = Enviado
|
||||||
uploadSuccessTimingHeader = O link para o seu arquivo expirará após 1 download ou em 24 horas.
|
uploadSuccessTimingHeader = O link para o seu arquivo expirará após 1 download ou em 24 horas.
|
||||||
|
expireInfo = O link para o seu arquivo expirará após { $downloadCount } ou { $timepan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 download
|
||||||
|
*[other] { $num } downloads
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hora
|
||||||
|
*[other] { $num } horas
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Copie e compartilhe o link para enviar o seu arquivo: { $filename }
|
copyUrlFormLabelWithName = Copie e compartilhe o link para enviar o seu arquivo: { $filename }
|
||||||
copyUrlFormButton = Copiar para área de transferência
|
copyUrlFormButton = Copiar para área de transferência
|
||||||
copiedUrl = Copiado!
|
copiedUrl = Copiado!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Excluir arquivo
|
||||||
sendAnotherFileLink = Enviar outro arquivo
|
sendAnotherFileLink = Enviar outro arquivo
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Baixar
|
downloadAltText = Baixar
|
||||||
|
downloadsFileList = Downloads
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Hora
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Baixar { $filename }
|
downloadFileName = Baixar { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Insira a senha
|
unlockInputLabel = Insira a senha
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Termos
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Para baixar esse arquivo é necessário uma senha
|
requirePasswordCheckbox = Para baixar esse arquivo é necessário uma senha
|
||||||
addPasswordButton = Adicionar senha
|
addPasswordButton = Adicionar senha
|
||||||
|
changePasswordButton = Alterar
|
||||||
passwordTryAgain = Senha incorreta. Tente novamente.
|
passwordTryAgain = Senha incorreta. Tente novamente.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Senha: { $password }
|
passwordResult = Senha: { $password }
|
||||||
|
reportIPInfringement = Reportar violação de IP
|
||||||
|
javascriptRequired = O Firefox Send requer JavaScript
|
||||||
|
whyJavascript = Por que o Firefox Send precisa do JavaScript?
|
||||||
|
enableJavascript = Habilite o JavaScript e tente novamente.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -24,31 +24,43 @@ uploadingPageLargeFileMessage = Este ficheiro é grande e pode demorar um pouco
|
||||||
uploadingFileNotification = Notificar-me quando o carregamento estiver completo.
|
uploadingFileNotification = Notificar-me quando o carregamento estiver completo.
|
||||||
uploadSuccessConfirmHeader = Pronto para enviar
|
uploadSuccessConfirmHeader = Pronto para enviar
|
||||||
uploadSvgAlt = Carregar
|
uploadSvgAlt = Carregar
|
||||||
uploadSuccessTimingHeader = A ligação para o seu ficheiro irá expirar depois de 1 descarga ou em 24 horas.
|
uploadSuccessTimingHeader = A ligação para o seu ficheiro irá expirar depois de 1 transferência ou em 24 horas.
|
||||||
|
expireInfo = A ligação para o seu ficheiro irá expirar depois de { $downloadCount } or { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 transferência
|
||||||
|
*[other] { $num } transferências
|
||||||
|
}
|
||||||
|
timespanHours = 1 hora
|
||||||
copyUrlFormLabelWithName = Copie e partilhe a ligação para enviar o seu ficheiro: { $filename }
|
copyUrlFormLabelWithName = Copie e partilhe a ligação para enviar o seu ficheiro: { $filename }
|
||||||
copyUrlFormButton = Copiar para a área de transferência
|
copyUrlFormButton = Copiar para a área de transferência
|
||||||
copiedUrl = Copiado!
|
copiedUrl = Copiado!
|
||||||
deleteFileButton = Apagar ficheiro
|
deleteFileButton = Apagar ficheiro
|
||||||
sendAnotherFileLink = Enviar outro ficheiro
|
sendAnotherFileLink = Enviar outro ficheiro
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Descarregar
|
downloadAltText = Transferir
|
||||||
downloadFileName = Descarregar { $filename }
|
downloadsFileList = Transferências
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tempo
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
|
downloadFileName = Transferir { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Digitar palavra-passe
|
unlockInputLabel = Digitar palavra-passe
|
||||||
unlockInputPlaceholder = Palavra-passe
|
unlockInputPlaceholder = Palavra-passe
|
||||||
unlockButtonLabel = Desbloquear
|
unlockButtonLabel = Desbloquear
|
||||||
downloadFileTitle = Descarregar ficheiro encriptado
|
downloadFileTitle = Transferir ficheiro encriptado
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
downloadMessage = O seu amigo está a enviar-lhe um ficheiro com o Firefox Send, um serviço que lhe permite partilhar ficheiro com uma ligação segura, privada e encriptada que expira automaticamente para garantir que as suas coisas não fiquem online para sempre.
|
downloadMessage = O seu amigo está a enviar-lhe um ficheiro com o Firefox Send, um serviço que lhe permite partilhar ficheiro com uma ligação segura, privada e encriptada que expira automaticamente para garantir que as suas coisas não fiquem online para sempre.
|
||||||
// Text and title used on the download link/button (indicates an action).
|
// Text and title used on the download link/button (indicates an action).
|
||||||
downloadButtonLabel = Descarregar
|
downloadButtonLabel = Transferir
|
||||||
downloadNotification = A sua descarga foi completada.
|
downloadNotification = A sua transferência foi concluída.
|
||||||
downloadFinish = Descarga completada
|
downloadFinish = Transferência concluída
|
||||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
sendYourFilesLink = Tentar o Firefox Send
|
sendYourFilesLink = Experimentar o Firefox Send
|
||||||
downloadingPageProgress = A descarregar { $filename } ({ $size })
|
downloadingPageProgress = A transferir { $filename } ({ $size })
|
||||||
downloadingPageMessage = Por favor deixe este separador aberto enquanto obtemos o seu ficheiro e o desencriptamos.
|
downloadingPageMessage = Por favor deixe este separador aberto enquanto obtemos o seu ficheiro e o desencriptamos.
|
||||||
errorAltText = Erro ao carregar
|
errorAltText = Erro ao carregar
|
||||||
errorPageHeader = Algo correu mal.
|
errorPageHeader = Algo correu mal.
|
||||||
|
@ -63,7 +75,7 @@ notSupportedDetail = Infelizmente este navegador não suporta a tecnologia web q
|
||||||
notSupportedLink = Porque é que o meu navegador não é suportado?
|
notSupportedLink = Porque é que o meu navegador não é suportado?
|
||||||
notSupportedOutdatedDetail = Infelizmente esta versão do Firefox não suporta a tecnologia web que faz o Firefox Send funcionar. Precisa de atualizar o seu navegador.
|
notSupportedOutdatedDetail = Infelizmente esta versão do Firefox não suporta a tecnologia web que faz o Firefox Send funcionar. Precisa de atualizar o seu navegador.
|
||||||
updateFirefox = Atualizar o Firefox
|
updateFirefox = Atualizar o Firefox
|
||||||
downloadFirefoxButtonSub = Descarga gratuita
|
downloadFirefoxButtonSub = Transferência gratuita
|
||||||
uploadedFile = Ficheiro
|
uploadedFile = Ficheiro
|
||||||
copyFileList = Copiar URL
|
copyFileList = Copiar URL
|
||||||
// expiryFileList is used as a column header
|
// expiryFileList is used as a column header
|
||||||
|
@ -72,7 +84,7 @@ deleteFileList = Apagar
|
||||||
nevermindButton = Esquecer
|
nevermindButton = Esquecer
|
||||||
legalHeader = Termos e privacidade
|
legalHeader = Termos e privacidade
|
||||||
legalNoticeTestPilot = O Firefox Send é atualmente uma experiência do Test Pilot, e sujeita aos <a>Termos de serviço</a> e <a>Aviso de privacidade</a> do Test Pilot. Pode saber mais acerca desta experiência e a sua recolha de dados <a>aqui</a>.
|
legalNoticeTestPilot = O Firefox Send é atualmente uma experiência do Test Pilot, e sujeita aos <a>Termos de serviço</a> e <a>Aviso de privacidade</a> do Test Pilot. Pode saber mais acerca desta experiência e a sua recolha de dados <a>aqui</a>.
|
||||||
legalNoticeMozilla = A utilização do website do Firefox Send está também sujeita ao <a>Aviso de privacidade dos websites</a> e <a>Termos de serviço dos websites</a> da Mozilla.
|
legalNoticeMozilla = A utilização do website do Firefox Send está também sujeita ao <a>Aviso de privacidade dos websites</a> e <a>Termos de utilização dos websites</a> da Mozilla.
|
||||||
deletePopupText = Apagar este ficheiro?
|
deletePopupText = Apagar este ficheiro?
|
||||||
deletePopupYes = Sim
|
deletePopupYes = Sim
|
||||||
deletePopupCancel = Cancelar
|
deletePopupCancel = Cancelar
|
||||||
|
@ -84,8 +96,17 @@ footerLinkAbout = Acerca do Test Pilot
|
||||||
footerLinkPrivacy = Privacidade
|
footerLinkPrivacy = Privacidade
|
||||||
footerLinkTerms = Termos
|
footerLinkTerms = Termos
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Requerer uma palavra-passe para descarregar este ficheiro
|
requirePasswordCheckbox = Requerer uma palavra-passe para transferir este ficheiro
|
||||||
addPasswordButton = Adicionar palavra-passe
|
addPasswordButton = Adicionar palavra-passe
|
||||||
|
changePasswordButton = Alterar
|
||||||
passwordTryAgain = Palavra-passe incorreta. Tente novamente.
|
passwordTryAgain = Palavra-passe incorreta. Tente novamente.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Palavra-passe: { $password }
|
passwordResult = Palavra-passe: { $password }
|
||||||
|
reportIPInfringement = Reportar violação de PI
|
||||||
|
javascriptRequired = O Firefox Send requer JavaScript
|
||||||
|
whyJavascript = Porque é que o Firefox Send requer JavaScript?
|
||||||
|
enableJavascript = Por favor ative o JavaScript e tente novamente.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -3,8 +3,13 @@ title = Firefox Send
|
||||||
siteSubtitle = un experiment web
|
siteSubtitle = un experiment web
|
||||||
siteFeedback = Feedback
|
siteFeedback = Feedback
|
||||||
uploadPageHeader = Partajare de fișiere privată și criptată
|
uploadPageHeader = Partajare de fișiere privată și criptată
|
||||||
|
uploadPageExplainer = Trimite fișiere printr-un link sigur, privat și criptat care expiră automat pentru ca informațiile să rămână în siguranță.
|
||||||
uploadPageLearnMore = Află mai multe
|
uploadPageLearnMore = Află mai multe
|
||||||
|
uploadPageDropMessage = Aruncă fișierul aici pentru a începe încărcarea.
|
||||||
|
uploadPageSizeMessage = Pentru a lucra mai ușor, recomandăm să păstrezi fișierul sub 1GB
|
||||||
|
uploadPageBrowseButton = Alege un fișier din calculator.
|
||||||
uploadPageBrowseButton1 = Selectează un fișier pentru încărcare
|
uploadPageBrowseButton1 = Selectează un fișier pentru încărcare
|
||||||
|
uploadPageMultipleFilesAlert = Încărcarea mai multor fișiere deodată sau a dosarelor nu este suportată.
|
||||||
uploadPageBrowseButtonTitle = Încarcă fișier
|
uploadPageBrowseButtonTitle = Încarcă fișier
|
||||||
uploadingPageProgress = Se încarcă { $filename } ({ $size })
|
uploadingPageProgress = Se încarcă { $filename } ({ $size })
|
||||||
importingFile = Se importă…
|
importingFile = Se importă…
|
||||||
|
@ -15,20 +20,39 @@ notifyUploadDone = Încărcarea s-a finalizat.
|
||||||
uploadingPageMessage =
|
uploadingPageMessage =
|
||||||
uploadingPageCancel = Anulează încărcarea
|
uploadingPageCancel = Anulează încărcarea
|
||||||
uploadCancelNotification = Încărcarea a fost anulată.
|
uploadCancelNotification = Încărcarea a fost anulată.
|
||||||
|
uploadingPageLargeFileMessage = Stai calm! Acest fișier este mare. S-ar putea să dureze un timp încărcarea.
|
||||||
uploadingFileNotification = Notifică-mă când încărcarea este încheiată.
|
uploadingFileNotification = Notifică-mă când încărcarea este încheiată.
|
||||||
uploadSuccessConfirmHeader = Pregătit pentru trimitere
|
uploadSuccessConfirmHeader = Pregătit pentru trimitere
|
||||||
uploadSvgAlt = Încarcă
|
uploadSvgAlt = Încarcă
|
||||||
uploadSuccessTimingHeader = Linkul către fișierul tău va expira după 1 descărcare sau în 24 de ore.
|
uploadSuccessTimingHeader = Linkul către fișierul tău va expira după 1 descărcare sau în 24 de ore.
|
||||||
|
expireInfo = Linkul la fișier va expira după { $downloadCount } sau { $timespan }.
|
||||||
|
downloadCount =
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 oră
|
||||||
|
[few] ore
|
||||||
|
*[other] de ore
|
||||||
|
}
|
||||||
|
copyUrlFormLabelWithName = Copiază și împărtășește linkul de la fișierul de trimis: { $filename }
|
||||||
copyUrlFormButton = Copiază în clipboard
|
copyUrlFormButton = Copiază în clipboard
|
||||||
copiedUrl = Copiat!
|
copiedUrl = Copiat!
|
||||||
deleteFileButton = Șterge fișierul
|
deleteFileButton = Șterge fișierul
|
||||||
sendAnotherFileLink = Trimite un alt fișier
|
sendAnotherFileLink = Trimite un alt fișier
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Descarcă
|
downloadAltText = Descarcă
|
||||||
|
downloadsFileList = Descărcări
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Timp
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Descarcă { $filename }
|
downloadFileName = Descarcă { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
|
unlockInputLabel = Introdu parola
|
||||||
unlockInputPlaceholder = Parolă
|
unlockInputPlaceholder = Parolă
|
||||||
unlockButtonLabel = Deblochează
|
unlockButtonLabel = Deblochează
|
||||||
|
downloadFileTitle = Descarcă fișierul criptat
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
downloadMessage = Un prieten îți trimite un fișier prin Firefox Send, un serviciu care îți permite să împărtășești un fișier printr-un link sigur, privat și criptat care expiră automat pentru a păstra informațiile tale online doar temporar.
|
||||||
// Text and title used on the download link/button (indicates an action).
|
// Text and title used on the download link/button (indicates an action).
|
||||||
downloadButtonLabel = Descarcă
|
downloadButtonLabel = Descarcă
|
||||||
downloadNotification = Descărcarea s-a încheiat.
|
downloadNotification = Descărcarea s-a încheiat.
|
||||||
|
@ -38,13 +62,19 @@ fileSizeProgress = ({ $partialSize } din { $totalSize })
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
sendYourFilesLink = Încearcă Firefox Send
|
sendYourFilesLink = Încearcă Firefox Send
|
||||||
downloadingPageProgress = Se descarcă { $filename } ({ $size })
|
downloadingPageProgress = Se descarcă { $filename } ({ $size })
|
||||||
|
downloadingPageMessage = Te rugăm să păstrezi această file deschisă în timp ce preluăm fișierul și îl decriptăm.
|
||||||
errorAltText = Eroare la încărcare
|
errorAltText = Eroare la încărcare
|
||||||
errorPageHeader = Ceva a mers prost!
|
errorPageHeader = Ceva a mers prost!
|
||||||
|
errorPageMessage = A apărut o eroare la încărcarea fișierului.
|
||||||
errorPageLink = Trimite un alt fișier
|
errorPageLink = Trimite un alt fișier
|
||||||
|
fileTooBig = Acest fișier este prea mare. Trebuie să fie sub { $size }.
|
||||||
linkExpiredAlt = Link expirat
|
linkExpiredAlt = Link expirat
|
||||||
expiredPageHeader = Acest link a expirat sau nu a existat de la bun început!
|
expiredPageHeader = Acest link a expirat sau nu a existat de la bun început!
|
||||||
notSupportedHeader = Browserul tău nu este suportat.
|
notSupportedHeader = Browserul tău nu este suportat.
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
notSupportedDetail = Din păcate acest browser nu suportă tehnologii web precum Firefox Send. Trebuie să încerci alt browser. Îți recomandăm Firefox!
|
||||||
notSupportedLink = De ce browserul meu nu este suportat?
|
notSupportedLink = De ce browserul meu nu este suportat?
|
||||||
|
notSupportedOutdatedDetail = Din păcate această versiune de Firefox nu suportă tehnologiile web din spatele Firefox Sent. Îți recomandăm să actualizezi browserul.
|
||||||
updateFirefox = Actualizează Firefox
|
updateFirefox = Actualizează Firefox
|
||||||
downloadFirefoxButtonSub = Descărcare gratuită
|
downloadFirefoxButtonSub = Descărcare gratuită
|
||||||
uploadedFile = Fișier
|
uploadedFile = Fișier
|
||||||
|
@ -52,7 +82,10 @@ copyFileList = Copiază URL-ul
|
||||||
// expiryFileList is used as a column header
|
// expiryFileList is used as a column header
|
||||||
expiryFileList = Expiră în
|
expiryFileList = Expiră în
|
||||||
deleteFileList = Șterge
|
deleteFileList = Șterge
|
||||||
|
nevermindButton = Uită
|
||||||
legalHeader = Termeni de utilizare și politica de confidențialitate
|
legalHeader = Termeni de utilizare și politica de confidențialitate
|
||||||
|
legalNoticeTestPilot = Firefox Send este momentan un experiment Test Pilot și supus <a>Termenilor de utilizare</a> Test Pilot și a <a>Politicii de confidențialitate</a>. Poți afla mai multe despre acest experiment <a>aici</a>.
|
||||||
|
legalNoticeMozilla = Folosirea site-ului Firefox Send mai este supusă <a>Politicii de confidențialitate pentru site-uri web</a> și a <a>Termenilor de folosire a site-urilor web</a>.
|
||||||
deletePopupText = Ștergi aceast fișier?
|
deletePopupText = Ștergi aceast fișier?
|
||||||
deletePopupYes = Da
|
deletePopupYes = Da
|
||||||
deletePopupCancel = Renunță
|
deletePopupCancel = Renunță
|
||||||
|
@ -64,4 +97,10 @@ footerLinkAbout = Despre Test Pilot
|
||||||
footerLinkPrivacy = Confidențialitate
|
footerLinkPrivacy = Confidențialitate
|
||||||
footerLinkTerms = Termeni
|
footerLinkTerms = Termeni
|
||||||
footerLinkCookies = Cookie-uri
|
footerLinkCookies = Cookie-uri
|
||||||
|
requirePasswordCheckbox = Este necesară o parolă pentru a descărca acest fișier
|
||||||
addPasswordButton = Adaugă parolă
|
addPasswordButton = Adaugă parolă
|
||||||
|
changePasswordButton = Modifică
|
||||||
|
passwordTryAgain = Parola este incorectă. Încearcă din nou.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Parola: { $password }
|
||||||
|
reportIPInfringement = Raportează încălcarea proprietății intelectuale
|
||||||
|
|
|
@ -25,6 +25,17 @@ uploadingFileNotification = Оповестить меня, когда загру
|
||||||
uploadSuccessConfirmHeader = Готов к отправке
|
uploadSuccessConfirmHeader = Готов к отправке
|
||||||
uploadSvgAlt = Загрузить
|
uploadSvgAlt = Загрузить
|
||||||
uploadSuccessTimingHeader = Ссылка на ваш файл станет недоступна после 1 загрузки файла или через 24 часа.
|
uploadSuccessTimingHeader = Ссылка на ваш файл станет недоступна после 1 загрузки файла или через 24 часа.
|
||||||
|
expireInfo = Ссылка на ваш файл станет недоступна после { $downloadCount } файла или через { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] { $number } загрузки
|
||||||
|
[few] { $number } загрузок
|
||||||
|
*[other] { $number } загрузок
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] { $number } час
|
||||||
|
[few] { $number } часа
|
||||||
|
*[other] { $number } часов
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Скопировать и поделиться ссылкой на отправку вашего файла: { $filename }
|
copyUrlFormLabelWithName = Скопировать и поделиться ссылкой на отправку вашего файла: { $filename }
|
||||||
copyUrlFormButton = Скопировать в буфер обмена
|
copyUrlFormButton = Скопировать в буфер обмена
|
||||||
copiedUrl = Скопировано!
|
copiedUrl = Скопировано!
|
||||||
|
@ -32,6 +43,12 @@ deleteFileButton = Удалить файл
|
||||||
sendAnotherFileLink = Отправить другой файл
|
sendAnotherFileLink = Отправить другой файл
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Загрузить
|
downloadAltText = Загрузить
|
||||||
|
downloadsFileList = Загрузки
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Время
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Загрузить { $filename }
|
downloadFileName = Загрузить { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Введите пароль
|
unlockInputLabel = Введите пароль
|
||||||
|
@ -86,6 +103,8 @@ footerLinkTerms = Условия
|
||||||
footerLinkCookies = Куки
|
footerLinkCookies = Куки
|
||||||
requirePasswordCheckbox = Требовать пароль для загрузки этого файла
|
requirePasswordCheckbox = Требовать пароль для загрузки этого файла
|
||||||
addPasswordButton = Добавить пароль
|
addPasswordButton = Добавить пароль
|
||||||
|
changePasswordButton = Изменить
|
||||||
passwordTryAgain = Неверный пароль. Попробуйте снова.
|
passwordTryAgain = Неверный пароль. Попробуйте снова.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Пароль: { $password }
|
passwordResult = Пароль: { $password }
|
||||||
|
reportIPInfringement = Сообщить о нарушении прав на интеллектуальную собственность
|
||||||
|
|
|
@ -25,6 +25,17 @@ uploadingFileNotification = Upozorniť ma na ukončenie nahrávania
|
||||||
uploadSuccessConfirmHeader = Pripravené na odoslanie
|
uploadSuccessConfirmHeader = Pripravené na odoslanie
|
||||||
uploadSvgAlt = Nahrať
|
uploadSvgAlt = Nahrať
|
||||||
uploadSuccessTimingHeader = Platnosť odkazu vyprší po 1 prevzatí alebo po uplynutí 24 hodín.
|
uploadSuccessTimingHeader = Platnosť odkazu vyprší po 1 prevzatí alebo po uplynutí 24 hodín.
|
||||||
|
expireInfo = Platnosť odkazu na váš súbor vyprší po { $downloadCount } alebo po { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 prevzatí
|
||||||
|
[few] { $num } prevzatiach
|
||||||
|
*[other] { $num } prevzatiach
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 hodine
|
||||||
|
[few] { $num } hodinách
|
||||||
|
*[other] { $num } hodinách
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Skopírovaním a zdieľaním odkazu odošlete váš súbor: { $filename }
|
copyUrlFormLabelWithName = Skopírovaním a zdieľaním odkazu odošlete váš súbor: { $filename }
|
||||||
copyUrlFormButton = Kopírovať do schránky
|
copyUrlFormButton = Kopírovať do schránky
|
||||||
copiedUrl = Skopírované!
|
copiedUrl = Skopírované!
|
||||||
|
@ -32,6 +43,12 @@ deleteFileButton = Odstrániť súbor
|
||||||
sendAnotherFileLink = Odoslať ďalší súbor
|
sendAnotherFileLink = Odoslať ďalší súbor
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Prevziať
|
downloadAltText = Prevziať
|
||||||
|
downloadsFileList = Prevzatí
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Zostáva
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Prevziať { $filename }
|
downloadFileName = Prevziať { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Zadajte heslo
|
unlockInputLabel = Zadajte heslo
|
||||||
|
@ -86,6 +103,15 @@ footerLinkTerms = Podmienky používania
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
requirePasswordCheckbox = Pri preberaní súboru vyžadovať heslo
|
requirePasswordCheckbox = Pri preberaní súboru vyžadovať heslo
|
||||||
addPasswordButton = Pridať heslo
|
addPasswordButton = Pridať heslo
|
||||||
|
changePasswordButton = Zmeniť
|
||||||
passwordTryAgain = Nesprávne heslo. Skúste to znova.
|
passwordTryAgain = Nesprávne heslo. Skúste to znova.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Heslo: { $password }
|
passwordResult = Heslo: { $password }
|
||||||
|
reportIPInfringement = Nahlásiť porušenie práv duševného vlastníctva
|
||||||
|
javascriptRequired = Firefox Send vyžaduje JavaScript
|
||||||
|
whyJavascript = Prečo Firefox Send vyžaduje JavaScript?
|
||||||
|
enableJavascript = Prosím, povoľte JavaScript a skúste to znova.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours } hod. { $minutes } min.
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } min.
|
||||||
|
|
|
@ -25,6 +25,19 @@ uploadingFileNotification = Obvesti me, ko bo nalaganje končano.
|
||||||
uploadSuccessConfirmHeader = Pripravljeno za pošiljanje
|
uploadSuccessConfirmHeader = Pripravljeno za pošiljanje
|
||||||
uploadSvgAlt = Naloži
|
uploadSvgAlt = Naloži
|
||||||
uploadSuccessTimingHeader = Povezava do vaše datoteke bo potekla po enem prenosu ali v 24 urah.
|
uploadSuccessTimingHeader = Povezava do vaše datoteke bo potekla po enem prenosu ali v 24 urah.
|
||||||
|
expireInfo = Povezava do vaše datoteke bo potekla čez { $downloadCount } ali { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 prenos
|
||||||
|
[two] { $num } prenosa
|
||||||
|
[few] { $num } prenosi
|
||||||
|
*[other] { $num } prenosov
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 ura
|
||||||
|
[two] { $num } uri
|
||||||
|
[few] { $num } ure
|
||||||
|
*[other] { $num } ur
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopirajte in delite to povezavo, da pošljete datoteko: { $filename }
|
copyUrlFormLabelWithName = Kopirajte in delite to povezavo, da pošljete datoteko: { $filename }
|
||||||
copyUrlFormButton = Kopiraj v odložišče
|
copyUrlFormButton = Kopiraj v odložišče
|
||||||
copiedUrl = Kopirano!
|
copiedUrl = Kopirano!
|
||||||
|
@ -32,6 +45,12 @@ deleteFileButton = Izbriši datoteko
|
||||||
sendAnotherFileLink = Pošlji drugo datoteko
|
sendAnotherFileLink = Pošlji drugo datoteko
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Prenesi
|
downloadAltText = Prenesi
|
||||||
|
downloadsFileList = Prenosi
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Čas
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Prenesi { $filename }
|
downloadFileName = Prenesi { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Vnesite geslo
|
unlockInputLabel = Vnesite geslo
|
||||||
|
@ -86,6 +105,15 @@ footerLinkTerms = Pogoji
|
||||||
footerLinkCookies = Piškotki
|
footerLinkCookies = Piškotki
|
||||||
requirePasswordCheckbox = Zahtevaj geslo za prenos te datoteke
|
requirePasswordCheckbox = Zahtevaj geslo za prenos te datoteke
|
||||||
addPasswordButton = Dodaj geslo
|
addPasswordButton = Dodaj geslo
|
||||||
|
changePasswordButton = Spremeni
|
||||||
passwordTryAgain = Napačno geslo. Poskusite znova.
|
passwordTryAgain = Napačno geslo. Poskusite znova.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Geslo: { $password }
|
passwordResult = Geslo: { $password }
|
||||||
|
reportIPInfringement = Prijavite kršitev naslova IP
|
||||||
|
javascriptRequired = Firefox Send zahteva JavaScript
|
||||||
|
whyJavascript = Zakaj Firefox Send zahteva JavaScript?
|
||||||
|
enableJavascript = Omogočite JavaScript in poskusite znova.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
title = Firefox Send
|
||||||
|
siteSubtitle = eksperiment web
|
||||||
|
siteFeedback = Përshtypje
|
||||||
|
uploadPageHeader = Shkëmbim Privat, i Fshehtëzuar, Kartelash
|
||||||
|
uploadPageExplainer = Dërgoni kartela përmes një lidhjeje të parrezik, private dhe të fshehtëzuar, që skadon automatikisht për të garantuar që gjërat tuaja nuk mbesin në internet përgjithmonë.
|
||||||
|
uploadPageLearnMore = Mësoni më tepër
|
||||||
|
uploadPageDropMessage = Që të fillojë ngarkimi, hidheni kartelën tuaj këtu
|
||||||
|
uploadPageSizeMessage = Për ecurinë më të qëndrueshme, më e mira është t’i mbani kartelat tuaja nën 1GB
|
||||||
|
uploadPageBrowseButton = Përzgjidhni një kartelë nga kompjuteri juaj
|
||||||
|
uploadPageBrowseButton1 = Përzgjidhni një kartelë për ngarkim
|
||||||
|
uploadPageMultipleFilesAlert = Ngarkimi i shumë kartelave njëherësh, ose i një dosjeje, hëpërhë nuk mbulohen.
|
||||||
|
uploadPageBrowseButtonTitle = Ngarkoje kartelën
|
||||||
|
uploadingPageProgress = Po ngarkohet { $filename } ({ $size })
|
||||||
|
importingFile = Po importohet…
|
||||||
|
verifyingFile = Po verifikohet…
|
||||||
|
encryptingFile = Po fshehtëzohet…
|
||||||
|
decryptingFile = Po shfshehtëzohet…
|
||||||
|
notifyUploadDone = Ngarkimi juaj përfundoi.
|
||||||
|
uploadingPageMessage = Do të jeni në gjendje të caktoni parametra skadimi sapo kartela juaj të jetë ngarkuar.
|
||||||
|
uploadingPageCancel = Anuloje ngarkimin
|
||||||
|
uploadCancelNotification = Ngarkimi juaj u anulua.
|
||||||
|
uploadingPageLargeFileMessage = Kjo kartelë është e madhe dhe mund të dojë ca kohë të ngarkohet. Rrini këtu!
|
||||||
|
uploadingFileNotification = Njoftomë kur të jetë plotësuar ngarkimi .
|
||||||
|
uploadSuccessConfirmHeader = Gati për Dërgim
|
||||||
|
uploadSvgAlt = Ngarkoje
|
||||||
|
uploadSuccessTimingHeader = Lidhja për te kartela juaj do të skadojë pas 1 shkarkimi ose pas 24 orësh.
|
||||||
|
expireInfo = Lidhja për te kartela juaj do të skadojë pas { $downloadCount } ose { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 shkarkimi
|
||||||
|
*[other] { $num } shkarkimesh
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 ore
|
||||||
|
*[other] { $num } orësh
|
||||||
|
}
|
||||||
|
copyUrlFormLabelWithName = Kopjojeni dhe jepuani të tjerëve lidhje që të dërgoni kartelën tuaj: { $filename }
|
||||||
|
copyUrlFormButton = Kopjoje te e papastra
|
||||||
|
copiedUrl = U kopjua!
|
||||||
|
deleteFileButton = Fshije kartelën
|
||||||
|
sendAnotherFileLink = Dërgoni një kartelë tjetër
|
||||||
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
|
downloadAltText = Shkarkoje
|
||||||
|
downloadFileName = Shkarkoje { $filename }
|
||||||
|
downloadFileSize = ({ $size })
|
||||||
|
unlockInputLabel = Jepni Fjalëkalimin
|
||||||
|
unlockInputPlaceholder = Fjalëkalim
|
||||||
|
unlockButtonLabel = Zhbllokoje
|
||||||
|
downloadFileTitle = Shkarko Kartelën e Fshehtëzuar
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
downloadMessage = Shoku juaj po ju dërgon një kartelë me Firefox Send, një shërbim që ju lejon të shkëmbeni kartela përmes një lidhjeje të parrezik, private, dhe të fshehtëzuar, që skadon automatikisht, për të garantuar që gjërat tuaja të mos mbeten në internet përgjithmonë.
|
||||||
|
// Text and title used on the download link/button (indicates an action).
|
||||||
|
downloadButtonLabel = Shkarkoje
|
||||||
|
downloadNotification = Shkarkimi juaj u plotësua.
|
||||||
|
downloadFinish = Shkarkim i Plotësuar
|
||||||
|
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||||
|
fileSizeProgress = ({ $partialSize } nga { $totalSize }) gjithsej
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
sendYourFilesLink = Provoni Firefox Send
|
||||||
|
downloadingPageProgress = Po shkarkohet { $filename } ({ $size })
|
||||||
|
downloadingPageMessage = Ju lutemi, lëreni hapur këtë skedë ndërkohë që ne sjellim dhe shfshehtëzojmë kartelën tuaj.
|
||||||
|
errorAltText = Gabim ngarkimi
|
||||||
|
errorPageHeader = Diç shkoi ters!
|
||||||
|
errorPageMessage = Pati një gabim gjatë ngarkimit të kartelës.
|
||||||
|
errorPageLink = Dërgoni një kartelë tjetër
|
||||||
|
fileTooBig = Kjo kartelë është shumë e madhe për ngarkim. Do të duhej të ishte më pak se { $size }.
|
||||||
|
linkExpiredAlt = Lidhja skadoi
|
||||||
|
expiredPageHeader = Kjo lidhje ka skaduar ose s’ka ekzistuar kurrë!
|
||||||
|
notSupportedHeader = Shfletuesi juaj nuk mbulohet.
|
||||||
|
// Firefox Send is a brand name and should not be localized.
|
||||||
|
notSupportedDetail = Mjerisht, ky shfletues nuk mbulon teknologjinë web mbi të cilën bazohet Firefox Send.Do t’ju duhet të provoni një shfletues tjetër. Ju këshillojmë Firefox-in!
|
||||||
|
notSupportedLink = Pse nuk mbulohet ky shfletues?
|
||||||
|
notSupportedOutdatedDetail = Mjerisht, ky version i Firefox-it nuk e mbulon teknologjinë web mbi të cilën bazohet Firefox Send. Do t’ju duhet të përditësoni shfletuesin tuaj.
|
||||||
|
updateFirefox = Përditësojeni Firefox-in
|
||||||
|
downloadFirefoxButtonSub = Shkarkim Falas
|
||||||
|
uploadedFile = Kartelë
|
||||||
|
copyFileList = Kopjo URL-në
|
||||||
|
// expiryFileList is used as a column header
|
||||||
|
expiryFileList = Skadon Më
|
||||||
|
deleteFileList = Fshije
|
||||||
|
nevermindButton = S’prish punë
|
||||||
|
legalHeader = Kushte & Privatësi
|
||||||
|
legalNoticeTestPilot = Firefox Send është një eksperiment Pilot Testesh dhe subjekt i <a>Kushteve të Shërbimit</a> dhe <a>Shënim Privacësie</a> për Pilot Testesh. <a>Këtu</a> mund të mësoni më tepër mbi këtë eksperiment dhe grumbullimit të të dhënave që ai kryen.
|
||||||
|
legalNoticeMozilla = Përdorimi i sajtit Firefox Send është gjithashtu subjekt i <a>Shënimit Mbi Privatësi Sajtesh</a> të Mozilla-s dhe <a>Kushteve të Përdorimit të Sajtit</a>.
|
||||||
|
deletePopupText = Të fshihet kjo kartelë?
|
||||||
|
deletePopupYes = Po
|
||||||
|
deletePopupCancel = Anuloje
|
||||||
|
deleteButtonHover = Fshije
|
||||||
|
copyUrlHover = Kopjoji URL-në
|
||||||
|
footerLinkLegal = Ligjore
|
||||||
|
// Test Pilot is a proper name and should not be localized.
|
||||||
|
footerLinkAbout = Rreth Pilot Testesh
|
||||||
|
footerLinkPrivacy = Privatësi
|
||||||
|
footerLinkTerms = Kushte
|
||||||
|
footerLinkCookies = Cookies
|
||||||
|
requirePasswordCheckbox = Kërko doemos një fjalëkalim për shkarkim të kësaj kartele
|
||||||
|
addPasswordButton = Shtoni fjalëkalim
|
||||||
|
passwordTryAgain = Fjalëkalim i pasaktë. Riprovoni.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Fjalëkalim: { $password }
|
||||||
|
reportIPInfringement = Raportoni Cenim IP-je
|
|
@ -25,6 +25,17 @@ uploadingFileNotification = Обавести ме када се отпремањ
|
||||||
uploadSuccessConfirmHeader = Спреман за слање
|
uploadSuccessConfirmHeader = Спреман за слање
|
||||||
uploadSvgAlt = Отпреми
|
uploadSvgAlt = Отпреми
|
||||||
uploadSuccessTimingHeader = Веза ка вашој датотеци ће истећи након једног преузимања или након 24 сата.
|
uploadSuccessTimingHeader = Веза ка вашој датотеци ће истећи након једног преузимања или након 24 сата.
|
||||||
|
expireInfo = Веза ка вашој датотеци ће истећи након { $downloadCount } или { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] преузимања
|
||||||
|
[few] преузимања
|
||||||
|
*[other] преузимања
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] сата
|
||||||
|
[few] сата
|
||||||
|
*[other] сати
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Ископирајте и поделите везу да бисте послали вашу датотеку: { $filename }
|
copyUrlFormLabelWithName = Ископирајте и поделите везу да бисте послали вашу датотеку: { $filename }
|
||||||
copyUrlFormButton = Копирај у оставу
|
copyUrlFormButton = Копирај у оставу
|
||||||
copiedUrl = Ископирано!
|
copiedUrl = Ископирано!
|
||||||
|
@ -32,6 +43,12 @@ deleteFileButton = Обриши датотеку
|
||||||
sendAnotherFileLink = Пошаљи другу датотеку
|
sendAnotherFileLink = Пошаљи другу датотеку
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Преузми
|
downloadAltText = Преузми
|
||||||
|
downloadsFileList = Преузимања
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Време
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Преузимање датотеке { $filename }
|
downloadFileName = Преузимање датотеке { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Унесите лозинку
|
unlockInputLabel = Унесите лозинку
|
||||||
|
@ -86,6 +103,15 @@ footerLinkTerms = Услови
|
||||||
footerLinkCookies = Колачићи
|
footerLinkCookies = Колачићи
|
||||||
requirePasswordCheckbox = Захтевај лозинку да би преузео ову датотеку
|
requirePasswordCheckbox = Захтевај лозинку да би преузео ову датотеку
|
||||||
addPasswordButton = Додај лозинку
|
addPasswordButton = Додај лозинку
|
||||||
|
changePasswordButton = Промени
|
||||||
passwordTryAgain = Нетачна лозинка. Пробајте поново.
|
passwordTryAgain = Нетачна лозинка. Пробајте поново.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Лозинка: { $password }
|
passwordResult = Лозинка: { $password }
|
||||||
|
reportIPInfringement = Пријавите IP прекршај
|
||||||
|
javascriptRequired = За Firefox Send је потребан JavaScript
|
||||||
|
whyJavascript = Зашто је потребан JavaScript за Firefox Send?
|
||||||
|
enableJavascript = Омогућите JavaScript и пробајте поново.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }ч { $minutes }м
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }м
|
||||||
|
|
|
@ -25,6 +25,15 @@ uploadingFileNotification = Meddela mig när uppladdningen är klar.
|
||||||
uploadSuccessConfirmHeader = Klar för att skicka
|
uploadSuccessConfirmHeader = Klar för att skicka
|
||||||
uploadSvgAlt = Ladda upp
|
uploadSvgAlt = Ladda upp
|
||||||
uploadSuccessTimingHeader = Länken till din fil upphör att gälla efter 1 nedladdning eller om 24 timmar.
|
uploadSuccessTimingHeader = Länken till din fil upphör att gälla efter 1 nedladdning eller om 24 timmar.
|
||||||
|
expireInfo = Länken till din fil upphör att gälla efter { $downloadCount } eller { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 nedladdning
|
||||||
|
*[other] { $num } nedladdningar
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 timme
|
||||||
|
*[other] { $num } timmar
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopiera och dela länken för att skicka din fil: { $filename }
|
copyUrlFormLabelWithName = Kopiera och dela länken för att skicka din fil: { $filename }
|
||||||
copyUrlFormButton = Kopiera till urklipp
|
copyUrlFormButton = Kopiera till urklipp
|
||||||
copiedUrl = Kopierad!
|
copiedUrl = Kopierad!
|
||||||
|
@ -32,6 +41,12 @@ deleteFileButton = Ta bort fil
|
||||||
sendAnotherFileLink = Skicka en annan fil
|
sendAnotherFileLink = Skicka en annan fil
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = Ladda ner
|
downloadAltText = Ladda ner
|
||||||
|
downloadsFileList = Nedladdningar
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Tid
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = Ladda ner { $filename }
|
downloadFileName = Ladda ner { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Ange lösenord
|
unlockInputLabel = Ange lösenord
|
||||||
|
@ -86,6 +101,15 @@ footerLinkTerms = Villkor
|
||||||
footerLinkCookies = Kakor
|
footerLinkCookies = Kakor
|
||||||
requirePasswordCheckbox = Kräver ett lösenord för att ladda ner den här filen
|
requirePasswordCheckbox = Kräver ett lösenord för att ladda ner den här filen
|
||||||
addPasswordButton = Lägg till lösenord
|
addPasswordButton = Lägg till lösenord
|
||||||
|
changePasswordButton = Ändra
|
||||||
passwordTryAgain = Felaktigt lösenord. Försök igen.
|
passwordTryAgain = Felaktigt lösenord. Försök igen.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Lösenord: { $password }
|
passwordResult = Lösenord: { $password }
|
||||||
|
reportIPInfringement = Rapportera IP-överträdelse
|
||||||
|
javascriptRequired = Firefox Send kräver JavaScript
|
||||||
|
whyJavascript = Varför kräver Firefox Send JavaScript?
|
||||||
|
enableJavascript = Aktivera JavaScript och försök igen.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }t { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,14 @@ uploadingFileNotification = Abisuhan ako kapag nakumpleto na ang pag-upload.
|
||||||
uploadSuccessConfirmHeader = Handa nang Ipadala
|
uploadSuccessConfirmHeader = Handa nang Ipadala
|
||||||
uploadSvgAlt = I-upload
|
uploadSvgAlt = I-upload
|
||||||
uploadSuccessTimingHeader = Mag-e-expire ang link sa iyong file pagkatapos ng 1 pag-download o sa loob ng 24 na oras.
|
uploadSuccessTimingHeader = Mag-e-expire ang link sa iyong file pagkatapos ng 1 pag-download o sa loob ng 24 na oras.
|
||||||
|
expireInfo = Mag-e-expire ang link sa iyong file pagkatapos ng { $downloadCount } o { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 pag-download
|
||||||
|
*[other] { $num } na mga pag-download
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[one] 1 oras
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Kopyahin at ibahagi ang link upang ipadala ang iyong file: { $filename }
|
copyUrlFormLabelWithName = Kopyahin at ibahagi ang link upang ipadala ang iyong file: { $filename }
|
||||||
copyUrlFormButton = Kopyahin sa clipboard
|
copyUrlFormButton = Kopyahin sa clipboard
|
||||||
copiedUrl = Naikopya!
|
copiedUrl = Naikopya!
|
||||||
|
@ -32,6 +40,12 @@ deleteFileButton = Burahin ang file
|
||||||
sendAnotherFileLink = Magpadala ng isang file
|
sendAnotherFileLink = Magpadala ng isang file
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = I-download
|
downloadAltText = I-download
|
||||||
|
downloadsFileList = Mga Pag-download
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Oras
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = I-download { $filename }
|
downloadFileName = I-download { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Ilagay ang Password
|
unlockInputLabel = Ilagay ang Password
|
||||||
|
@ -86,6 +100,15 @@ footerLinkTerms = Mga term
|
||||||
footerLinkCookies = Mga cookie
|
footerLinkCookies = Mga cookie
|
||||||
requirePasswordCheckbox = Mangailangan ng isang password upang i-download ang file na ito
|
requirePasswordCheckbox = Mangailangan ng isang password upang i-download ang file na ito
|
||||||
addPasswordButton = Magdagdag ng password
|
addPasswordButton = Magdagdag ng password
|
||||||
|
changePasswordButton = Palitan
|
||||||
passwordTryAgain = Maling password. Subukan muli.
|
passwordTryAgain = Maling password. Subukan muli.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Password: { $password }
|
passwordResult = Password: { $password }
|
||||||
|
reportIPInfringement = Report IP Infringement
|
||||||
|
javascriptRequired = Nangangailangan ang JavaScript sa JavaScript
|
||||||
|
whyJavascript = Bakit ang JavaScript ay nangangailangan ng JavaScript?
|
||||||
|
enableJavascript = Mangyaring paganahin ang JavaScript at subukan muli.
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }m
|
||||||
|
|
|
@ -25,6 +25,11 @@ uploadingFileNotification = Yükleme bitince bana haber ver.
|
||||||
uploadSuccessConfirmHeader = Göndermeye hazır
|
uploadSuccessConfirmHeader = Göndermeye hazır
|
||||||
uploadSvgAlt = Yükle
|
uploadSvgAlt = Yükle
|
||||||
uploadSuccessTimingHeader = Dosyanız 1 kez indirildikten veya 24 saat geçtikten sonra linkiniz geçersiz olacaktır.
|
uploadSuccessTimingHeader = Dosyanız 1 kez indirildikten veya 24 saat geçtikten sonra linkiniz geçersiz olacaktır.
|
||||||
|
expireInfo = Dosyanızın bağlantısı { $downloadCount } sonra veya { $timespan } zaman aşımına uğrayacaktır.
|
||||||
|
downloadCount = { $num } indirme
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[one] { $num } saat
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = { $filename } dosyanızı başkasına göndermek için aşağıdaki linki kopyalayın.
|
copyUrlFormLabelWithName = { $filename } dosyanızı başkasına göndermek için aşağıdaki linki kopyalayın.
|
||||||
copyUrlFormButton = Panoya kopyala
|
copyUrlFormButton = Panoya kopyala
|
||||||
copiedUrl = Kopyalandı!
|
copiedUrl = Kopyalandı!
|
||||||
|
@ -32,6 +37,12 @@ deleteFileButton = Dosyayı sil
|
||||||
sendAnotherFileLink = Başka bir dosya daha gönder
|
sendAnotherFileLink = Başka bir dosya daha gönder
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = İndir
|
downloadAltText = İndir
|
||||||
|
downloadsFileList = İndirme
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = Süre
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = { $filename } dosyasını indir
|
downloadFileName = { $filename } dosyasını indir
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = Parolayı yazın
|
unlockInputLabel = Parolayı yazın
|
||||||
|
@ -86,6 +97,8 @@ footerLinkTerms = Şartlar
|
||||||
footerLinkCookies = Çerezler
|
footerLinkCookies = Çerezler
|
||||||
requirePasswordCheckbox = Bu dosyayı indirmek için parola iste
|
requirePasswordCheckbox = Bu dosyayı indirmek için parola iste
|
||||||
addPasswordButton = Parola ekle
|
addPasswordButton = Parola ekle
|
||||||
|
changePasswordButton = Değiştir
|
||||||
passwordTryAgain = Yanlış parola. Yeniden deneyin.
|
passwordTryAgain = Yanlış parola. Yeniden deneyin.
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = Parola: { $password }
|
passwordResult = Parola: { $password }
|
||||||
|
reportIPInfringement = Telif hakkı ihlali bildir
|
||||||
|
|
|
@ -25,6 +25,17 @@ uploadingFileNotification = Сповістити мене, коли вивант
|
||||||
uploadSuccessConfirmHeader = Готовий до надсилання
|
uploadSuccessConfirmHeader = Готовий до надсилання
|
||||||
uploadSvgAlt = Вивантажити
|
uploadSvgAlt = Вивантажити
|
||||||
uploadSuccessTimingHeader = Час дії цього посилання закінчиться після 1 завантаження, або через 24 години.
|
uploadSuccessTimingHeader = Час дії цього посилання закінчиться після 1 завантаження, або через 24 години.
|
||||||
|
expireInfo = Посилання на ваш файл стане недійсним після { $downloadCount } файла, або через { $timespan }.
|
||||||
|
downloadCount = { $num ->
|
||||||
|
[one] 1 завантаження
|
||||||
|
[few] { $num } завантаження
|
||||||
|
*[other] { $num } завантажень
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
[one] 1 година
|
||||||
|
[few] { $num } години
|
||||||
|
*[other] { $num } годин
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = Скопіювати і поділитися посиланням на ваш файл: { $filename }
|
copyUrlFormLabelWithName = Скопіювати і поділитися посиланням на ваш файл: { $filename }
|
||||||
copyUrlFormButton = Копіювати у буфер обміну
|
copyUrlFormButton = Копіювати у буфер обміну
|
||||||
copiedUrl = Скопійовано!
|
copiedUrl = Скопійовано!
|
||||||
|
@ -34,6 +45,10 @@ sendAnotherFileLink = Надіслати інший файл
|
||||||
downloadAltText = Завантаживи
|
downloadAltText = Завантаживи
|
||||||
downloadFileName = Завантажити { $filename }
|
downloadFileName = Завантажити { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
|
unlockInputLabel = Введіть пароль
|
||||||
|
unlockInputPlaceholder = Пароль
|
||||||
|
unlockButtonLabel = Розблокувати
|
||||||
|
downloadFileTitle = Завантажити зашифрований файл
|
||||||
// Firefox Send is a brand name and should not be localized.
|
// Firefox Send is a brand name and should not be localized.
|
||||||
downloadMessage = Ваш друг надіслав файл за допомогою Firefox Send, який дозволяє ділитися файлами, використовуючи безпечні, приватні та зашифровані посилання, термін дії яких автоматично закінчується, щоб ваші файли не лишилися в Інтернеті назавжди.
|
downloadMessage = Ваш друг надіслав файл за допомогою Firefox Send, який дозволяє ділитися файлами, використовуючи безпечні, приватні та зашифровані посилання, термін дії яких автоматично закінчується, щоб ваші файли не лишилися в Інтернеті назавжди.
|
||||||
// Text and title used on the download link/button (indicates an action).
|
// Text and title used on the download link/button (indicates an action).
|
||||||
|
@ -80,3 +95,9 @@ footerLinkAbout = Про Test Pilot
|
||||||
footerLinkPrivacy = Приватність
|
footerLinkPrivacy = Приватність
|
||||||
footerLinkTerms = Умови
|
footerLinkTerms = Умови
|
||||||
footerLinkCookies = Куки
|
footerLinkCookies = Куки
|
||||||
|
requirePasswordCheckbox = Вимагати пароль для завантаження цього файлу
|
||||||
|
addPasswordButton = Додати пароль
|
||||||
|
passwordTryAgain = Невірний пароль. Спробуйте знову.
|
||||||
|
// This label is followed by the password needed to download a file
|
||||||
|
passwordResult = Пароль: { $password }
|
||||||
|
reportIPInfringement = Повідомити про порушення прав на інтелектуальну власність
|
||||||
|
|
|
@ -25,6 +25,13 @@ uploadingFileNotification = 上传完成后通知我。
|
||||||
uploadSuccessConfirmHeader = 准备好发送
|
uploadSuccessConfirmHeader = 准备好发送
|
||||||
uploadSvgAlt = 上传
|
uploadSvgAlt = 上传
|
||||||
uploadSuccessTimingHeader = 您的文件的链接将在首次下载或 24 小时后过期。
|
uploadSuccessTimingHeader = 您的文件的链接将在首次下载或 24 小时后过期。
|
||||||
|
expireInfo = 指向该文件的链接将在 { $downloadCount } 或 { $timespan } 后过期。
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] { $num } 次下载
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] { $num } 小时
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = 复制并分享链接以发送您的文件:{ $filename }
|
copyUrlFormLabelWithName = 复制并分享链接以发送您的文件:{ $filename }
|
||||||
copyUrlFormButton = 复制到剪贴板
|
copyUrlFormButton = 复制到剪贴板
|
||||||
copiedUrl = 已复制!
|
copiedUrl = 已复制!
|
||||||
|
@ -32,6 +39,12 @@ deleteFileButton = 删除文件
|
||||||
sendAnotherFileLink = 发送其他文件
|
sendAnotherFileLink = 发送其他文件
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = 下载
|
downloadAltText = 下载
|
||||||
|
downloadsFileList = 下载次数
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = 时间
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = 下载 { $filename }
|
downloadFileName = 下载 { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = 请输入密码
|
unlockInputLabel = 请输入密码
|
||||||
|
@ -86,6 +99,15 @@ footerLinkTerms = 条款
|
||||||
footerLinkCookies = Cookie
|
footerLinkCookies = Cookie
|
||||||
requirePasswordCheckbox = 持有密码才能下载此文件
|
requirePasswordCheckbox = 持有密码才能下载此文件
|
||||||
addPasswordButton = 添加密码
|
addPasswordButton = 添加密码
|
||||||
|
changePasswordButton = 更改
|
||||||
passwordTryAgain = 密码不正确。请重试。
|
passwordTryAgain = 密码不正确。请重试。
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = 密码:{ $password }
|
passwordResult = 密码:{ $password }
|
||||||
|
reportIPInfringement = 举报知识产权侵权
|
||||||
|
javascriptRequired = Firefox Send 需要 JavaScript
|
||||||
|
whyJavascript = 为什么 Firefox Send 需要 JavaScript?
|
||||||
|
enableJavascript = 请启用 JavaScript 并重试。
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours }时 { $minutes }分
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes }分
|
||||||
|
|
|
@ -25,6 +25,13 @@ uploadingFileNotification = 上傳完成時通知我。
|
||||||
uploadSuccessConfirmHeader = 準備好傳送
|
uploadSuccessConfirmHeader = 準備好傳送
|
||||||
uploadSvgAlt = 上傳
|
uploadSvgAlt = 上傳
|
||||||
uploadSuccessTimingHeader = 您的檔案鏈結將會在首次下載,或 24 小時後失效。
|
uploadSuccessTimingHeader = 您的檔案鏈結將會在首次下載,或 24 小時後失效。
|
||||||
|
expireInfo = 檔案鏈結將在 { $downloadCount }或 { $timespan }後失效。
|
||||||
|
downloadCount = { $num ->
|
||||||
|
*[other] { $num } 次下載
|
||||||
|
}
|
||||||
|
timespanHours = { $num ->
|
||||||
|
*[other] { $num } 小時
|
||||||
|
}
|
||||||
copyUrlFormLabelWithName = 複製並分享鏈結來傳送您的檔案: { $filename }
|
copyUrlFormLabelWithName = 複製並分享鏈結來傳送您的檔案: { $filename }
|
||||||
copyUrlFormButton = 複製到剪貼簿
|
copyUrlFormButton = 複製到剪貼簿
|
||||||
copiedUrl = 已複製!
|
copiedUrl = 已複製!
|
||||||
|
@ -32,6 +39,12 @@ deleteFileButton = 刪除檔案
|
||||||
sendAnotherFileLink = 傳送另一個檔案
|
sendAnotherFileLink = 傳送另一個檔案
|
||||||
// Alternative text used on the download link/button (indicates an action).
|
// Alternative text used on the download link/button (indicates an action).
|
||||||
downloadAltText = 下載
|
downloadAltText = 下載
|
||||||
|
downloadsFileList = 下載次數
|
||||||
|
// Used as header in a column indicating the amount of time left before a
|
||||||
|
// download link expires (e.g. "10h 5m")
|
||||||
|
timeFileList = 剩餘時間
|
||||||
|
// Used as header in a column indicating the number of times a file has been
|
||||||
|
// downloaded
|
||||||
downloadFileName = 下載 { $filename }
|
downloadFileName = 下載 { $filename }
|
||||||
downloadFileSize = ({ $size })
|
downloadFileSize = ({ $size })
|
||||||
unlockInputLabel = 輸入密碼
|
unlockInputLabel = 輸入密碼
|
||||||
|
@ -86,6 +99,15 @@ footerLinkTerms = 使用條款
|
||||||
footerLinkCookies = Cookie
|
footerLinkCookies = Cookie
|
||||||
requirePasswordCheckbox = 需要密碼才能下載此檔案
|
requirePasswordCheckbox = 需要密碼才能下載此檔案
|
||||||
addPasswordButton = 新增密碼
|
addPasswordButton = 新增密碼
|
||||||
|
changePasswordButton = 變更
|
||||||
passwordTryAgain = 密碼不正確,請再試一次。
|
passwordTryAgain = 密碼不正確,請再試一次。
|
||||||
// This label is followed by the password needed to download a file
|
// This label is followed by the password needed to download a file
|
||||||
passwordResult = 密碼: { $password }
|
passwordResult = 密碼: { $password }
|
||||||
|
reportIPInfringement = 回報智慧財產權濫用情況
|
||||||
|
javascriptRequired = Firefox Send 需要開啟 JavaScript 功能
|
||||||
|
whyJavascript = 為什麼 Firefox Send 需要 JavaScript 才能使用?
|
||||||
|
enableJavascript = 請開啟 JavaScript 功能後再試一次。
|
||||||
|
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
|
expiresHoursMinutes = { $hours } 時 { $minutes } 分
|
||||||
|
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
|
||||||
|
expiresMinutes = { $minutes } 分鐘
|
||||||
|
|
|
@ -19,6 +19,11 @@ const conf = convict({
|
||||||
default: false,
|
default: false,
|
||||||
env: 'REDIS_EVENT_EXPIRE'
|
env: 'REDIS_EVENT_EXPIRE'
|
||||||
},
|
},
|
||||||
|
listen_address: {
|
||||||
|
format: 'ipaddress',
|
||||||
|
default: '0.0.0.0',
|
||||||
|
env: 'IP_ADDRESS'
|
||||||
|
},
|
||||||
listen_port: {
|
listen_port: {
|
||||||
format: 'port',
|
format: 'port',
|
||||||
default: 1443,
|
default: 1443,
|
||||||
|
|
|
@ -24,4 +24,4 @@ app.use(
|
||||||
|
|
||||||
app.use(pages.notfound);
|
app.use(pages.notfound);
|
||||||
|
|
||||||
app.listen(config.listen_port);
|
app.listen(config.listen_port, config.listen_address);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue