mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-06 22:20:55 +03:00
Compare commits
136 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b88d3f5e4 | ||
|
|
cd4df5f6d8 | ||
|
|
7c461eab52 | ||
|
|
1b7e94c2d8 | ||
|
|
dcd3c0b3ff | ||
|
|
bfe16a5300 | ||
|
|
8a1f905831 | ||
|
|
e5b4165eff | ||
|
|
be596e91ef | ||
|
|
f20c995d1a | ||
|
|
5f97c130bd | ||
|
|
13bf765be0 | ||
|
|
443de49db8 | ||
|
|
3d82ce0909 | ||
|
|
b259cba882 | ||
|
|
a138586dd7 | ||
|
|
e427203a45 | ||
|
|
8882024e8f | ||
|
|
581ae224e7 | ||
|
|
dccf3329ca | ||
|
|
1450322585 | ||
|
|
5d1639851b | ||
|
|
77939cc280 | ||
|
|
7fd8fb4914 | ||
|
|
91ede1bdec | ||
|
|
29698a55c4 | ||
|
|
abfc07b1e3 | ||
|
|
a0401b24e8 | ||
|
|
dbf39efd35 | ||
|
|
fe7d71d165 | ||
|
|
977fe65dce | ||
|
|
4e79925c7b | ||
|
|
416e8d81f9 | ||
|
|
215f0f74ad | ||
|
|
93930b91a2 | ||
|
|
65c24990cd | ||
|
|
424eb2c37a | ||
|
|
d10cbcba3e | ||
|
|
553f0958ba | ||
|
|
ae2bae88cf | ||
|
|
313b145297 | ||
|
|
faf5fd17d3 | ||
|
|
dd0ab710de | ||
|
|
c2bcac76e9 | ||
|
|
bf7024c6d9 | ||
|
|
992cdcc70e | ||
|
|
10e446bb41 | ||
|
|
15ac0e1d49 | ||
|
|
4946e9c382 | ||
|
|
ece302342e | ||
|
|
721aa48d53 | ||
|
|
0761fcf902 | ||
|
|
33602f1432 | ||
|
|
74b305442c | ||
|
|
f30393cf33 | ||
|
|
e7688a62c6 | ||
|
|
109617d817 | ||
|
|
8f66db2295 | ||
|
|
57e0d17cbc | ||
|
|
93138773ca | ||
|
|
1bfa6321b1 | ||
|
|
10d489f766 | ||
|
|
4065bbcfd7 | ||
|
|
330da9b258 | ||
|
|
3febcfe1ea | ||
|
|
0cdae11456 | ||
|
|
5996bceef7 | ||
|
|
ba277b9382 | ||
|
|
5046b5022a | ||
|
|
74334433cd | ||
|
|
33bf82e963 | ||
|
|
c72896aeb7 | ||
|
|
b306ffec8d | ||
|
|
e1c21dd9b0 | ||
|
|
9f8cedc0db | ||
|
|
12c02ef6af | ||
|
|
5a564e2c37 | ||
|
|
4b8445191b | ||
|
|
12033edda5 | ||
|
|
8e6d8eaddd | ||
|
|
faaa8afe17 | ||
|
|
84e8abf2c5 | ||
|
|
5db8a20b9d | ||
|
|
117c6ea12d | ||
|
|
83880d97e6 | ||
|
|
c3be5228cb | ||
|
|
ade214c69c | ||
|
|
4cb040d70d | ||
|
|
73ccce627c | ||
|
|
4043d35c8b | ||
|
|
a576cc0198 | ||
|
|
fa1f0208a4 | ||
|
|
193d3b1aef | ||
|
|
3b28ce88bf | ||
|
|
c77983d902 | ||
|
|
6ef9f8fa43 | ||
|
|
1eabc1a11e | ||
|
|
9136694d29 | ||
|
|
ec7f058afc | ||
|
|
62989ee2c9 | ||
|
|
85068e97ae | ||
|
|
eb73dbfe78 | ||
|
|
dde2c4d5a9 | ||
|
|
20cf8d0a15 | ||
|
|
b2bd623a49 | ||
|
|
fc3001978c | ||
|
|
d6823f492d | ||
|
|
c3751c2efc | ||
|
|
70396e2f36 | ||
|
|
b557665d04 | ||
|
|
6393d70a33 | ||
|
|
834df8526f | ||
|
|
f5bd332ff8 | ||
|
|
0d5fb1740d | ||
|
|
5ed4db9689 | ||
|
|
31b810eb7d | ||
|
|
168a711c05 | ||
|
|
7243a10340 | ||
|
|
b18bcd3b6e | ||
|
|
09a6192bf5 | ||
|
|
9585850d6d | ||
|
|
14f3d837f9 | ||
|
|
d660eda64c | ||
|
|
b123b736e9 | ||
|
|
28e496fe05 | ||
|
|
8ebfaf9ad9 | ||
|
|
47fd387799 | ||
|
|
463393552b | ||
|
|
cb0d69c5cd | ||
|
|
2c77d94af7 | ||
|
|
b9eb653f1f | ||
|
|
37bb6fd982 | ||
|
|
e5d1e8f028 | ||
|
|
99477774cf | ||
|
|
76a6f02eb7 | ||
|
|
744dbb3a6f |
@@ -5,3 +5,4 @@ static
|
||||
test
|
||||
scripts
|
||||
docs
|
||||
firefox
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
public/bundle.js
|
||||
public/webcrypto-shim.js
|
||||
public
|
||||
test/frontend/bundle.js
|
||||
firefox
|
||||
firefox
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,7 +1,9 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
public/bundle.js
|
||||
public/upload.js
|
||||
public/download.js
|
||||
public/version.json
|
||||
public/l20n.min.js
|
||||
static/*
|
||||
!static/info.txt
|
||||
test/frontend/bundle.js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extends: stylelint-config-standard
|
||||
|
||||
rules:
|
||||
color-hex-case: upper
|
||||
color-hex-case: lower
|
||||
declaration-colon-newline-after: null
|
||||
selector-list-comma-newline-after: null
|
||||
|
||||
@@ -16,7 +16,7 @@ deployment:
|
||||
latest:
|
||||
branch: master
|
||||
commands:
|
||||
- npm run predocker
|
||||
- npm run build
|
||||
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||
- docker build -t mozilla/send:latest .
|
||||
- docker push mozilla/send:latest
|
||||
@@ -24,7 +24,7 @@ deployment:
|
||||
tag: /.*/
|
||||
owner: mozilla
|
||||
commands:
|
||||
- npm run predocker
|
||||
- npm run build
|
||||
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||
- docker build -t mozilla/send:$CIRCLE_TAG .
|
||||
- docker push mozilla/send:$CIRCLE_TAG
|
||||
|
||||
@@ -7,6 +7,6 @@ services:
|
||||
ports:
|
||||
- "1443:1443"
|
||||
environment:
|
||||
- P2P_REDIS_HOST=redis
|
||||
- REDIS_HOST=redis
|
||||
redis:
|
||||
image: redis:alpine
|
||||
|
||||
@@ -3,12 +3,22 @@
|
||||
| Name | Description
|
||||
|------------------|-------------|
|
||||
| `PORT` | Port the server will listen on (defaults to 1443).
|
||||
| `P2P_S3_BUCKET` | The S3 bucket name.
|
||||
| `P2P_REDIS_HOST` | Host name of the Redis server.
|
||||
| `S3_BUCKET` | The S3 bucket name.
|
||||
| `REDIS_HOST` | Host name of the Redis server.
|
||||
| `GOOGLE_ANALYTICS_ID` | Google Analytics ID
|
||||
| `SENTRY_CLIENT` | Sentry Client ID
|
||||
| `SENTRY_DSN` | Sentry DSN
|
||||
| `MAX_FILE_SIZE` | in bytes (defaults to 2147483648)
|
||||
| `NODE_ENV` | "production"
|
||||
|
||||
## Example:
|
||||
|
||||
```sh
|
||||
$ docker run --net=host -e 'NODE_ENV=production' -e 'P2P_S3_BUCKET=testpilot-p2p-dev' -e 'P2P_REDIS_HOST=dyf9s2r4vo3.bolxr4.0001.usw2.cache.amazonaws.com' mozilla/send:latest
|
||||
$ docker run --net=host -e 'NODE_ENV=production' \
|
||||
-e 'S3_BUCKET=testpilot-p2p-dev' \
|
||||
-e 'REDIS_HOST=dyf9s2r4vo3.bolxr4.0001.usw2.cache.amazonaws.com' \
|
||||
-e 'GOOGLE_ANALYTICS_ID=UA-35433268-78' \
|
||||
-e 'SENTRY_CLIENT=https://51e23d7263e348a7a3b90a5357c61cb2@sentry.prod.mozaws.net/168' \
|
||||
-e 'SENTRY_DSN=https://51e23d7263e348a7a3b90a5357c61cb2:65e23d7263e348a7a3b90a5357c61c44@sentry.prod.mozaws.net/168' \
|
||||
mozilla/send:latest
|
||||
```
|
||||
|
||||
@@ -112,6 +112,7 @@ Fired whenever a user deletes a file they’ve uploaded.
|
||||
- `cm6`
|
||||
- `cm7`
|
||||
- `cd1`
|
||||
- `cd4`
|
||||
|
||||
#### `copied`
|
||||
Fired whenever a user copies the URL of an upload file.
|
||||
|
||||
10
frontend/src/common.js
Normal file
10
frontend/src/common.js
Normal file
@@ -0,0 +1,10 @@
|
||||
window.Raven = require('raven-js');
|
||||
window.Raven.config(window.dsn).install();
|
||||
window.dsn = undefined;
|
||||
|
||||
const testPilotGA = require('testpilot-ga');
|
||||
window.analytics = new testPilotGA({
|
||||
an: 'Firefox Send',
|
||||
ds: 'web',
|
||||
tid: window.trackerId
|
||||
});
|
||||
@@ -1,78 +1,178 @@
|
||||
require('./common');
|
||||
const FileReceiver = require('./fileReceiver');
|
||||
const { notify } = require('./utils');
|
||||
const { notify, findMetric, gcmCompliant, sendEvent } = require('./utils');
|
||||
const bytes = require('bytes');
|
||||
const Storage = require('./storage');
|
||||
const storage = new Storage(localStorage);
|
||||
|
||||
const $ = require('jquery');
|
||||
require('jquery-circle-progress');
|
||||
|
||||
const Raven = window.Raven;
|
||||
|
||||
$(document).ready(function() {
|
||||
gcmCompliant().catch(err => {
|
||||
$('#download').attr('hidden', true);
|
||||
sendEvent('recipient', 'unsupported', {
|
||||
cd6: err
|
||||
}).then(() => {
|
||||
location.replace('/unsupported');
|
||||
});
|
||||
});
|
||||
//link back to homepage
|
||||
$('.send-new').attr('href', window.location.origin);
|
||||
|
||||
const filename = $('#dl-filename').html();
|
||||
$('.send-new').click(function(target) {
|
||||
target.preventDefault();
|
||||
sendEvent('recipient', 'restarted', {
|
||||
cd2: 'completed'
|
||||
}).then(() => {
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('.legal-links a, .social-links a, #dl-firefox').click(function(target) {
|
||||
target.preventDefault();
|
||||
const metric = findMetric(target.currentTarget.href);
|
||||
// record exited event by recipient
|
||||
sendEvent('recipient', 'exited', {
|
||||
cd3: metric
|
||||
}).then(() => {
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
const filename = $('#dl-filename').text();
|
||||
const bytelength = Number($('#dl-bytelength').text());
|
||||
const timeToExpiry = Number($('#dl-ttl').text());
|
||||
|
||||
//initiate progress bar
|
||||
$('#dl-progress').circleProgress({
|
||||
value: 0.0,
|
||||
startAngle: -Math.PI / 2,
|
||||
fill: '#00C8D7',
|
||||
fill: '#3B9DFF',
|
||||
size: 158,
|
||||
animation: { duration: 300 }
|
||||
});
|
||||
$('#download-btn').click(download);
|
||||
function download() {
|
||||
storage.totalDownloads += 1;
|
||||
|
||||
const fileReceiver = new FileReceiver();
|
||||
const unexpiredFiles = storage.numFiles;
|
||||
|
||||
fileReceiver.on('progress', progress => {
|
||||
window.onunload = function() {
|
||||
storage.referrer = 'cancelled-download';
|
||||
// record download-stopped (cancelled by tab close or reload)
|
||||
sendEvent('recipient', 'download-stopped', {
|
||||
cm1: bytelength,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd2: 'cancelled'
|
||||
});
|
||||
};
|
||||
|
||||
$('#download-page-one').attr('hidden', true);
|
||||
$('#download-progress').removeAttr('hidden');
|
||||
const percent = progress[0] / progress[1];
|
||||
// update progress bar
|
||||
$('#dl-progress').circleProgress('value', percent);
|
||||
$('.percent-number').html(`${Math.floor(percent * 100)}`);
|
||||
$('.progress-text').text(`${filename} (${bytes(progress[0], {decimalPlaces: 1, fixedDecimals: true})} of ${bytes(progress[1], {decimalPlaces: 1})})`);
|
||||
//on complete
|
||||
if (percent === 1) {
|
||||
fileReceiver.removeAllListeners('progress');
|
||||
document.l10n.formatValues('downloadNotification', 'downloadFinish')
|
||||
.then(translated => {
|
||||
notify(translated[0]);
|
||||
$('.title').html(translated[1]);
|
||||
});
|
||||
}
|
||||
$('.percent-number').text(`${Math.floor(percent * 100)}`);
|
||||
$('.progress-text').text(
|
||||
`${filename} (${bytes(progress[0], {
|
||||
decimalPlaces: 1,
|
||||
fixedDecimals: true
|
||||
})} of ${bytes(progress[1], { decimalPlaces: 1 })})`
|
||||
);
|
||||
});
|
||||
|
||||
let downloadEnd;
|
||||
fileReceiver.on('decrypting', isStillDecrypting => {
|
||||
// The file is being decrypted
|
||||
if (isStillDecrypting) {
|
||||
console.log('Decrypting');
|
||||
fileReceiver.removeAllListeners('progress');
|
||||
window.onunload = null;
|
||||
document.l10n.formatValue('decryptingFile').then(decryptingFile => {
|
||||
$('.progress-text').text(decryptingFile);
|
||||
});
|
||||
} else {
|
||||
console.log('Done decrypting');
|
||||
downloadEnd = Date.now();
|
||||
}
|
||||
});
|
||||
|
||||
fileReceiver.on('hashing', isStillHashing => {
|
||||
// The file is being hashed to make sure a malicious user hasn't tampered with it
|
||||
if (isStillHashing) {
|
||||
console.log('Checking file integrity');
|
||||
document.l10n.formatValue('verifyingFile').then(verifyingFile => {
|
||||
$('.progress-text').text(verifyingFile);
|
||||
});
|
||||
} else {
|
||||
console.log('Integrity check done');
|
||||
$('.progress-text').text(' ');
|
||||
document.l10n
|
||||
.formatValues('downloadNotification', 'downloadFinish')
|
||||
.then(translated => {
|
||||
notify(translated[0]);
|
||||
$('.title').text(translated[1]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
// record download-started by recipient
|
||||
sendEvent('recipient', 'download-started', {
|
||||
cm1: bytelength,
|
||||
cm4: timeToExpiry,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads
|
||||
});
|
||||
|
||||
fileReceiver
|
||||
.download()
|
||||
.catch(() => {
|
||||
document.l10n.formatValue('expiredPageHeader')
|
||||
.then(translated => {
|
||||
$('.title').text(translated);
|
||||
});
|
||||
$('#download-btn').attr('hidden', true);
|
||||
$('#expired-img').removeAttr('hidden');
|
||||
console.log('The file has expired, or has already been deleted.');
|
||||
.catch(err => {
|
||||
// record download-stopped (errored) by recipient
|
||||
sendEvent('recipient', 'download-stopped', {
|
||||
cm1: bytelength,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd2: 'errored',
|
||||
cd6: err
|
||||
});
|
||||
|
||||
if (err.message === 'notfound') {
|
||||
location.reload();
|
||||
} else {
|
||||
document.l10n.formatValue('errorPageHeader').then(translated => {
|
||||
$('.title').text(translated);
|
||||
});
|
||||
$('#download-btn').attr('hidden', true);
|
||||
$('#expired-img').removeAttr('hidden');
|
||||
}
|
||||
return;
|
||||
})
|
||||
.then(([decrypted, fname]) => {
|
||||
const endTime = Date.now();
|
||||
const totalTime = endTime - startTime;
|
||||
const downloadTime = endTime - downloadEnd;
|
||||
const downloadSpeed = bytelength / (downloadTime / 1000);
|
||||
|
||||
storage.referrer = 'completed-download';
|
||||
// record download-stopped (completed) by recipient
|
||||
sendEvent('recipient', 'download-stopped', {
|
||||
cm1: bytelength,
|
||||
cm2: totalTime,
|
||||
cm3: downloadSpeed,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd2: 'completed'
|
||||
});
|
||||
|
||||
const dataView = new DataView(decrypted);
|
||||
const blob = new Blob([dataView]);
|
||||
const downloadUrl = URL.createObjectURL(blob);
|
||||
|
||||
@@ -19,9 +19,7 @@ class FileReceiver extends EventEmitter {
|
||||
|
||||
xhr.onload = function(event) {
|
||||
if (xhr.status === 404) {
|
||||
reject(
|
||||
new Error('The file has expired, or has already been deleted.')
|
||||
);
|
||||
reject(new Error('notfound'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,41 +56,47 @@ class FileReceiver extends EventEmitter {
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
)
|
||||
]).then(([fdata, key]) => {
|
||||
this.emit('decrypting', true);
|
||||
return Promise.all([
|
||||
window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(fdata.iv),
|
||||
additionalData: hexToArray(fdata.aad)
|
||||
},
|
||||
key,
|
||||
fdata.data
|
||||
).then(decrypted => {
|
||||
this.emit('decrypting', false);
|
||||
return Promise.resolve(decrypted)
|
||||
}),
|
||||
fdata.filename,
|
||||
hexToArray(fdata.aad)
|
||||
]);
|
||||
}).then(([decrypted, fname, proposedHash]) => {
|
||||
this.emit('hashing', true);
|
||||
return window.crypto.subtle.digest('SHA-256', decrypted).then(calculatedHash => {
|
||||
this.emit('hashing', false);
|
||||
const integrity = new Uint8Array(calculatedHash).toString() === proposedHash.toString();
|
||||
if (!integrity) {
|
||||
this.emit('unsafe', true)
|
||||
return Promise.reject();
|
||||
} else {
|
||||
this.emit('safe', true);
|
||||
return Promise.all([
|
||||
decrypted,
|
||||
decodeURIComponent(fname)
|
||||
]);
|
||||
}
|
||||
])
|
||||
.then(([fdata, key]) => {
|
||||
this.emit('decrypting', true);
|
||||
return Promise.all([
|
||||
window.crypto.subtle
|
||||
.decrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(fdata.iv),
|
||||
additionalData: hexToArray(fdata.aad),
|
||||
tagLength: 128
|
||||
},
|
||||
key,
|
||||
fdata.data
|
||||
)
|
||||
.then(decrypted => {
|
||||
this.emit('decrypting', false);
|
||||
return Promise.resolve(decrypted);
|
||||
}),
|
||||
fdata.filename,
|
||||
hexToArray(fdata.aad)
|
||||
]);
|
||||
})
|
||||
})
|
||||
.then(([decrypted, fname, proposedHash]) => {
|
||||
this.emit('hashing', true);
|
||||
return window.crypto.subtle
|
||||
.digest('SHA-256', decrypted)
|
||||
.then(calculatedHash => {
|
||||
this.emit('hashing', false);
|
||||
const integrity =
|
||||
new Uint8Array(calculatedHash).toString() ===
|
||||
proposedHash.toString();
|
||||
if (!integrity) {
|
||||
this.emit('unsafe', true);
|
||||
return Promise.reject();
|
||||
} else {
|
||||
this.emit('safe', true);
|
||||
return Promise.all([decrypted, decodeURIComponent(fname)]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
window.Raven = require('raven-js');
|
||||
window.Raven.config(window.dsn).install();
|
||||
window.dsn = undefined;
|
||||
require('./upload');
|
||||
require('./download');
|
||||
66
frontend/src/storage.js
Normal file
66
frontend/src/storage.js
Normal file
@@ -0,0 +1,66 @@
|
||||
const { isFile } = require('./utils');
|
||||
|
||||
class Storage {
|
||||
constructor(engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
get totalDownloads() {
|
||||
return Number(this.engine.getItem('totalDownloads'));
|
||||
}
|
||||
set totalDownloads(n) {
|
||||
this.engine.setItem('totalDownloads', n);
|
||||
}
|
||||
get totalUploads() {
|
||||
return Number(this.engine.getItem('totalUploads'));
|
||||
}
|
||||
set totalUploads(n) {
|
||||
this.engine.setItem('totalUploads', n);
|
||||
}
|
||||
get referrer() {
|
||||
return this.engine.getItem('referrer');
|
||||
}
|
||||
set referrer(str) {
|
||||
this.engine.setItem('referrer', str);
|
||||
}
|
||||
|
||||
get files() {
|
||||
const fs = [];
|
||||
for (let i = 0; i < this.engine.length; i++) {
|
||||
const k = this.engine.key(i);
|
||||
if (isFile(k)) {
|
||||
fs.push(JSON.parse(this.engine.getItem(k))); // parse or whatever else
|
||||
}
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
get numFiles() {
|
||||
let length = 0;
|
||||
for (let i = 0; i < this.engine.length; i++) {
|
||||
const k = this.engine.key(i);
|
||||
if (isFile(k)) {
|
||||
length += 1;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
getFileById(id) {
|
||||
return this.engine.getItem(id);
|
||||
}
|
||||
|
||||
has(property) {
|
||||
return this.engine.hasOwnProperty(property);
|
||||
}
|
||||
|
||||
remove(property) {
|
||||
this.engine.removeItem(property);
|
||||
}
|
||||
|
||||
addFile(id, file) {
|
||||
this.engine.setItem(id, JSON.stringify(file));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Storage;
|
||||
@@ -1,19 +1,74 @@
|
||||
/* global MAXFILESIZE */
|
||||
/* global MAXFILESIZE EXPIRE_SECONDS */
|
||||
require('./common');
|
||||
const FileSender = require('./fileSender');
|
||||
const { notify, gcmCompliant } = require('./utils');
|
||||
const {
|
||||
notify,
|
||||
gcmCompliant,
|
||||
findMetric,
|
||||
sendEvent,
|
||||
ONE_DAY_IN_MS
|
||||
} = require('./utils');
|
||||
const bytes = require('bytes');
|
||||
const Storage = require('./storage');
|
||||
const storage = new Storage(localStorage);
|
||||
|
||||
const $ = require('jquery');
|
||||
require('jquery-circle-progress');
|
||||
|
||||
const Raven = window.Raven;
|
||||
|
||||
if (storage.has('referrer')) {
|
||||
window.referrer = storage.referrer;
|
||||
storage.remove('referrer');
|
||||
} else {
|
||||
window.referrer = 'external';
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
gcmCompliant().catch(err => {
|
||||
$('#page-one').attr('hidden', true);
|
||||
$('#unsupported-browser').removeAttr('hidden');
|
||||
sendEvent('sender', 'unsupported', {
|
||||
cd6: err
|
||||
}).then(() => {
|
||||
location.replace('/unsupported');
|
||||
});
|
||||
});
|
||||
|
||||
$('#file-upload').change(onUpload);
|
||||
|
||||
$('.legal-links a, .social-links a, #dl-firefox').click(function(target) {
|
||||
target.preventDefault();
|
||||
const metric = findMetric(target.currentTarget.href);
|
||||
// record exited event by recipient
|
||||
sendEvent('sender', 'exited', {
|
||||
cd3: metric
|
||||
}).then(() => {
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('#send-new-completed').click(function(target) {
|
||||
target.preventDefault();
|
||||
// record restarted event
|
||||
sendEvent('sender', 'restarted', {
|
||||
cd2: 'completed'
|
||||
}).then(() => {
|
||||
storage.referrer = 'completed-upload';
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('#send-new-error').click(function(target) {
|
||||
target.preventDefault();
|
||||
// record restarted event
|
||||
sendEvent('sender', 'restarted', {
|
||||
cd2: 'errored'
|
||||
}).then(() => {
|
||||
storage.referrer = 'errored-upload';
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('body').on('dragover', allowDrop).on('drop', onUpload);
|
||||
// reset copy button
|
||||
const $copyBtn = $('#copy-btn');
|
||||
@@ -21,18 +76,23 @@ $(document).ready(function() {
|
||||
$('#link').attr('disabled', false);
|
||||
$copyBtn.attr('data-l10n-id', 'copyUrlFormButton');
|
||||
|
||||
if (localStorage.length === 0) {
|
||||
const files = storage.files;
|
||||
if (files.length === 0) {
|
||||
toggleHeader();
|
||||
} else {
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const id = localStorage.key(i);
|
||||
//check if file exists before adding to list
|
||||
checkExistence(id, true);
|
||||
for (const index in files) {
|
||||
const id = files[index].fileId;
|
||||
//check if file still exists before adding to list
|
||||
checkExistence(id, files[index], true);
|
||||
}
|
||||
}
|
||||
|
||||
// copy link to clipboard
|
||||
$copyBtn.click(() => {
|
||||
// record copied event from success screen
|
||||
sendEvent('sender', 'copied', {
|
||||
cd4: 'success-screen'
|
||||
});
|
||||
const aux = document.createElement('input');
|
||||
aux.setAttribute('value', $('#link').attr('value'));
|
||||
document.body.appendChild(aux);
|
||||
@@ -42,7 +102,9 @@ $(document).ready(function() {
|
||||
//disable button for 3s
|
||||
$copyBtn.attr('disabled', true);
|
||||
$('#link').attr('disabled', true);
|
||||
$copyBtn.html('<img src="/resources/check-16.svg" class="icon-check"></img>');
|
||||
$copyBtn.html(
|
||||
'<img src="/resources/check-16.svg" class="icon-check"></img>'
|
||||
);
|
||||
window.setTimeout(() => {
|
||||
$copyBtn.attr('disabled', false);
|
||||
$('#link').attr('disabled', false);
|
||||
@@ -71,14 +133,28 @@ $(document).ready(function() {
|
||||
// on file upload by browse or drag & drop
|
||||
function onUpload(event) {
|
||||
event.preventDefault();
|
||||
|
||||
// don't allow upload if not on upload page
|
||||
if ($('#page-one').attr('hidden')) {
|
||||
return;
|
||||
}
|
||||
|
||||
storage.totalUploads += 1;
|
||||
|
||||
let file = '';
|
||||
if (event.type === 'drop') {
|
||||
if (event.originalEvent.dataTransfer.files.length > 1 || event.originalEvent.dataTransfer.files[0].size === 0){
|
||||
if (!event.originalEvent.dataTransfer.files[0]) {
|
||||
$('.upload-window').removeClass('ondrag');
|
||||
document.l10n.formatValue('uploadPageMultipleFilesAlert')
|
||||
.then(str => {
|
||||
alert(str);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
event.originalEvent.dataTransfer.files.length > 1 ||
|
||||
event.originalEvent.dataTransfer.files[0].size === 0
|
||||
) {
|
||||
$('.upload-window').removeClass('ondrag');
|
||||
document.l10n.formatValue('uploadPageMultipleFilesAlert').then(str => {
|
||||
alert(str);
|
||||
});
|
||||
return;
|
||||
}
|
||||
file = event.originalEvent.dataTransfer.files[0];
|
||||
@@ -87,24 +163,38 @@ $(document).ready(function() {
|
||||
}
|
||||
|
||||
if (file.size > MAXFILESIZE) {
|
||||
return document.l10n.formatValue('fileTooBig', {size: bytes(MAXFILESIZE)}).then(alert);
|
||||
return document.l10n
|
||||
.formatValue('fileTooBig', { size: bytes(MAXFILESIZE) })
|
||||
.then(alert);
|
||||
}
|
||||
|
||||
$('#page-one').attr('hidden', true);
|
||||
$('#upload-error').attr('hidden', true);
|
||||
$('#upload-progress').removeAttr('hidden');
|
||||
document.l10n.formatValue('importingFile').then(importingFile => {
|
||||
$('.progress-text').text(importingFile);
|
||||
});
|
||||
//don't allow drag and drop when not on page-one
|
||||
$('body').off('drop', onUpload);
|
||||
const expiration = 24 * 60 * 60 * 1000; //will eventually come from a field
|
||||
|
||||
const fileSender = new FileSender(file);
|
||||
$('#cancel-upload').click(() => {
|
||||
fileSender.cancel();
|
||||
location.reload();
|
||||
document.l10n.formatValue('uploadCancelNotification')
|
||||
.then(str => {
|
||||
notify(str);
|
||||
});
|
||||
document.l10n.formatValue('uploadCancelNotification').then(str => {
|
||||
notify(str);
|
||||
});
|
||||
storage.referrer = 'cancelled-upload';
|
||||
|
||||
// record upload-stopped (cancelled) by sender
|
||||
sendEvent('sender', 'upload-stopped', {
|
||||
cm1: file.size,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
||||
cd2: 'cancelled'
|
||||
});
|
||||
});
|
||||
|
||||
fileSender.on('progress', progress => {
|
||||
@@ -112,89 +202,152 @@ $(document).ready(function() {
|
||||
// update progress bar
|
||||
$('#ul-progress').circleProgress('value', percent);
|
||||
$('#ul-progress').circleProgress().on('circle-animation-end', function() {
|
||||
$('.percent-number').html(`${Math.floor(percent * 100)}`);
|
||||
$('.percent-number').text(`${Math.floor(percent * 100)}`);
|
||||
});
|
||||
$('.progress-text').text(`${file.name} (${bytes(progress[0], {decimalPlaces: 1, fixedDecimals: true})} of ${bytes(progress[1], {decimalPlaces: 1})})`);
|
||||
});
|
||||
|
||||
fileSender.on('loading', isStillLoading => {
|
||||
// The file is loading into Firefox at this stage
|
||||
if (isStillLoading) {
|
||||
console.log('Processing');
|
||||
} else {
|
||||
console.log('Finished processing');
|
||||
}
|
||||
$('.progress-text').text(
|
||||
`${file.name} (${bytes(progress[0], {
|
||||
decimalPlaces: 1,
|
||||
fixedDecimals: true
|
||||
})} of ${bytes(progress[1], { decimalPlaces: 1 })})`
|
||||
);
|
||||
});
|
||||
|
||||
fileSender.on('hashing', isStillHashing => {
|
||||
// The file is being hashed
|
||||
if (isStillHashing) {
|
||||
console.log('Hashing');
|
||||
document.l10n.formatValue('verifyingFile').then(verifyingFile => {
|
||||
$('.progress-text').text(verifyingFile);
|
||||
});
|
||||
} else {
|
||||
console.log('Finished hashing');
|
||||
}
|
||||
});
|
||||
|
||||
let uploadStart;
|
||||
fileSender.on('encrypting', isStillEncrypting => {
|
||||
// The file is being encrypted
|
||||
if (isStillEncrypting) {
|
||||
console.log('Encrypting');
|
||||
document.l10n.formatValue('encryptingFile').then(encryptingFile => {
|
||||
$('.progress-text').text(encryptingFile);
|
||||
});
|
||||
} else {
|
||||
console.log('Finished encrypting');
|
||||
uploadStart = Date.now();
|
||||
}
|
||||
});
|
||||
let t = '';
|
||||
fileSender
|
||||
.upload()
|
||||
.then(info => {
|
||||
const fileData = {
|
||||
name: file.name,
|
||||
fileId: info.fileId,
|
||||
url: info.url,
|
||||
secretKey: info.secretKey,
|
||||
deleteToken: info.deleteToken,
|
||||
creationDate: new Date(),
|
||||
expiry: expiration
|
||||
};
|
||||
localStorage.setItem(info.fileId, JSON.stringify(fileData));
|
||||
$('#upload-filename').attr('data-l10n-id', 'uploadSuccessConfirmHeader');
|
||||
t = window.setTimeout(() => {
|
||||
|
||||
let t;
|
||||
const startTime = Date.now();
|
||||
const unexpiredFiles = storage.numFiles + 1;
|
||||
|
||||
// record upload-started event by sender
|
||||
sendEvent('sender', 'upload-started', {
|
||||
cm1: file.size,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
||||
cd5: window.referrer
|
||||
});
|
||||
|
||||
// For large files we need to give the ui a tick to breathe and update
|
||||
// before we kick off the FileSender
|
||||
setTimeout(() => {
|
||||
fileSender
|
||||
.upload()
|
||||
.then(info => {
|
||||
const endTime = Date.now();
|
||||
const totalTime = endTime - startTime;
|
||||
const uploadTime = endTime - uploadStart;
|
||||
const uploadSpeed = file.size / (uploadTime / 1000);
|
||||
const expiration = EXPIRE_SECONDS * 1000;
|
||||
|
||||
// record upload-stopped (completed) by sender
|
||||
sendEvent('sender', 'upload-stopped', {
|
||||
cm1: file.size,
|
||||
cm2: totalTime,
|
||||
cm3: uploadSpeed,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
||||
cd2: 'completed'
|
||||
});
|
||||
|
||||
const fileData = {
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
fileId: info.fileId,
|
||||
url: info.url,
|
||||
secretKey: info.secretKey,
|
||||
deleteToken: info.deleteToken,
|
||||
creationDate: new Date(),
|
||||
expiry: expiration,
|
||||
totalTime: totalTime,
|
||||
typeOfUpload: event.type === 'drop' ? 'drop' : 'click',
|
||||
uploadSpeed: uploadSpeed
|
||||
};
|
||||
|
||||
storage.addFile(info.fileId, fileData);
|
||||
$('#upload-filename').attr(
|
||||
'data-l10n-id',
|
||||
'uploadSuccessConfirmHeader'
|
||||
);
|
||||
t = window.setTimeout(() => {
|
||||
$('#page-one').attr('hidden', true);
|
||||
$('#upload-progress').attr('hidden', true);
|
||||
$('#upload-error').attr('hidden', true);
|
||||
$('#share-link').removeAttr('hidden');
|
||||
}, 1000);
|
||||
|
||||
populateFileList(fileData);
|
||||
document.l10n.formatValue('notifyUploadDone').then(str => {
|
||||
notify(str);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
// err is 0 when coming from a cancel upload event
|
||||
if (err === 0) {
|
||||
return;
|
||||
}
|
||||
// only show error page when the error is anything other than user cancelling the upload
|
||||
Raven.captureException(err);
|
||||
$('#page-one').attr('hidden', true);
|
||||
$('#upload-progress').attr('hidden', true);
|
||||
$('#upload-error').attr('hidden', true);
|
||||
$('#share-link').removeAttr('hidden');
|
||||
}, 1000);
|
||||
$('#upload-error').removeAttr('hidden');
|
||||
window.clearTimeout(t);
|
||||
|
||||
populateFileList(JSON.stringify(fileData));
|
||||
document.l10n.formatValue('notifyUploadDone')
|
||||
.then(str => {
|
||||
notify(str);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
Raven.captureException(err);
|
||||
console.log(err);
|
||||
$('#page-one').attr('hidden', true);
|
||||
$('#upload-progress').attr('hidden', true);
|
||||
$('#upload-error').removeAttr('hidden');
|
||||
window.clearTimeout(t);
|
||||
});
|
||||
// record upload-stopped (errored) by sender
|
||||
sendEvent('sender', 'upload-stopped', {
|
||||
cm1: file.size,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd1: event.type === 'drop' ? 'drop' : 'click',
|
||||
cd2: 'errored',
|
||||
cd6: err
|
||||
});
|
||||
});
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function allowDrop(ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
function checkExistence(id, populate) {
|
||||
function checkExistence(id, file, populate) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
if (populate) {
|
||||
populateFileList(localStorage.getItem(id));
|
||||
populateFileList(file);
|
||||
}
|
||||
} else if (xhr.status === 404) {
|
||||
localStorage.removeItem(id);
|
||||
storage.remove(id);
|
||||
if (storage.numFiles === 0) {
|
||||
toggleHeader();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -202,21 +355,23 @@ $(document).ready(function() {
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
//update file table with current files in localStorage
|
||||
//update file table with current files in storage
|
||||
function populateFileList(file) {
|
||||
try {
|
||||
file = JSON.parse(file);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
const row = document.createElement('tr');
|
||||
const name = document.createElement('td');
|
||||
const link = document.createElement('td');
|
||||
const $copyIcon = $('<img>', { src: '/resources/copy-16.svg', class: 'icon-copy', 'data-l10n-id': 'copyUrlHover'});
|
||||
const $copyIcon = $('<img>', {
|
||||
src: '/resources/copy-16.svg',
|
||||
class: 'icon-copy',
|
||||
'data-l10n-id': 'copyUrlHover'
|
||||
});
|
||||
const expiry = document.createElement('td');
|
||||
const del = document.createElement('td');
|
||||
const $delIcon = $('<img>', { src: '/resources/close-16.svg', class: 'icon-delete', 'data-l10n-id': 'deleteButtonHover' });
|
||||
const $delIcon = $('<img>', {
|
||||
src: '/resources/close-16.svg',
|
||||
class: 'icon-delete',
|
||||
'data-l10n-id': 'deleteButtonHover'
|
||||
});
|
||||
const popupDiv = document.createElement('div');
|
||||
const $popupText = $('<div>', { class: 'popuptext' });
|
||||
const cellText = document.createTextNode(file.name);
|
||||
@@ -224,14 +379,8 @@ $(document).ready(function() {
|
||||
const url = file.url.trim() + `#${file.secretKey}`.trim();
|
||||
|
||||
$('#link').attr('value', url);
|
||||
$('#copy-text').attr(
|
||||
'data-l10n-args',
|
||||
'{"filename": "' + file.name + '"}'
|
||||
);
|
||||
$('#copy-text').attr(
|
||||
'data-l10n-id',
|
||||
'copyUrlFormLabelWithName'
|
||||
);
|
||||
$('#copy-text').attr('data-l10n-args', '{"filename": "' + file.name + '"}');
|
||||
$('#copy-text').attr('data-l10n-id', 'copyUrlFormLabelWithName');
|
||||
$popupText.attr('tabindex', '-1');
|
||||
|
||||
name.appendChild(cellText);
|
||||
@@ -252,16 +401,19 @@ $(document).ready(function() {
|
||||
|
||||
//copy link to clipboard when icon clicked
|
||||
$copyIcon.click(function() {
|
||||
// record copied event from upload list
|
||||
sendEvent('sender', 'copied', {
|
||||
cd4: 'upload-list'
|
||||
});
|
||||
const aux = document.createElement('input');
|
||||
aux.setAttribute('value', url);
|
||||
document.body.appendChild(aux);
|
||||
aux.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(aux);
|
||||
document.l10n.formatValue('copiedUrl')
|
||||
.then(translated => {
|
||||
link.innerHTML = translated;
|
||||
});
|
||||
document.l10n.formatValue('copiedUrl').then(translated => {
|
||||
link.innerHTML = translated;
|
||||
});
|
||||
window.setTimeout(() => {
|
||||
const linkImg = document.createElement('img');
|
||||
$(linkImg).addClass('icon-copy');
|
||||
@@ -277,7 +429,7 @@ $(document).ready(function() {
|
||||
future.setTime(file.creationDate.getTime() + file.expiry);
|
||||
|
||||
let countdown = 0;
|
||||
countdown = future.getTime() - new Date().getTime();
|
||||
countdown = future.getTime() - Date.now();
|
||||
let minutes = Math.floor(countdown / 1000 / 60);
|
||||
let hours = Math.floor(minutes / 60);
|
||||
let seconds = Math.floor(countdown / 1000 % 60);
|
||||
@@ -285,7 +437,7 @@ $(document).ready(function() {
|
||||
poll();
|
||||
|
||||
function poll() {
|
||||
countdown = future.getTime() - new Date().getTime();
|
||||
countdown = future.getTime() - Date.now();
|
||||
minutes = Math.floor(countdown / 1000 / 60);
|
||||
hours = Math.floor(minutes / 60);
|
||||
seconds = Math.floor(countdown / 1000 % 60);
|
||||
@@ -304,7 +456,7 @@ $(document).ready(function() {
|
||||
}
|
||||
//remove from list when expired
|
||||
if (countdown <= 0) {
|
||||
localStorage.removeItem(file.fileId);
|
||||
storage.remove(file.fileId);
|
||||
$(expiry).parents('tr').remove();
|
||||
window.clearTimeout(t);
|
||||
toggleHeader();
|
||||
@@ -313,21 +465,14 @@ $(document).ready(function() {
|
||||
|
||||
// create popup
|
||||
popupDiv.classList.add('popup');
|
||||
const popupDelSpan = document.createElement('span');
|
||||
$(popupDelSpan).addClass('del-file');
|
||||
$(popupDelSpan).attr('data-l10n-id', 'sentFilesTitle4');
|
||||
|
||||
const popupNvmSpan = document.createElement('span');
|
||||
$(popupNvmSpan).addClass('nvm');
|
||||
$(popupNvmSpan).attr('data-l10n-id', 'nevermindButton');
|
||||
|
||||
$popupText.html([
|
||||
popupDelSpan,
|
||||
' ',
|
||||
' ',
|
||||
popupNvmSpan
|
||||
]);
|
||||
const $popupMessage = $('<div>', { class: 'popup-message' });
|
||||
$popupMessage.attr('data-l10n-id', 'deletePopupText');
|
||||
const $popupDelSpan = $('<span>', { class: 'popup-yes' });
|
||||
$popupDelSpan.attr('data-l10n-id', 'deletePopupYes');
|
||||
const $popupNvmSpan = $('<span>', { class: 'popup-no' });
|
||||
$popupNvmSpan.attr('data-l10n-id', 'deletePopupCancel');
|
||||
|
||||
$popupText.html([$popupMessage, $popupDelSpan, $popupNvmSpan]);
|
||||
|
||||
// add data cells to table row
|
||||
row.appendChild(name);
|
||||
@@ -340,18 +485,51 @@ $(document).ready(function() {
|
||||
row.appendChild(del);
|
||||
$('tbody').append(row); //add row to table
|
||||
|
||||
const unexpiredFiles = storage.numFiles;
|
||||
|
||||
// delete file
|
||||
$popupText.find('.del-file').click(e => {
|
||||
$popupText.find('.popup-yes').click(e => {
|
||||
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
||||
$(e.target).parents('tr').remove();
|
||||
localStorage.removeItem(file.fileId);
|
||||
const timeToExpiry =
|
||||
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
||||
// record upload-deleted from file list
|
||||
sendEvent('sender', 'upload-deleted', {
|
||||
cm1: file.size,
|
||||
cm2: file.totalTime,
|
||||
cm3: file.uploadSpeed,
|
||||
cm4: timeToExpiry,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd1: file.typeOfUpload,
|
||||
cd4: 'upload-list'
|
||||
}).then(() => {
|
||||
storage.remove(file.fileId);
|
||||
});
|
||||
toggleHeader();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('delete-file').onclick = () => {
|
||||
FileSender.delete(file.fileId, file.deleteToken).then(() => {
|
||||
localStorage.removeItem(file.fileId);
|
||||
location.reload();
|
||||
const timeToExpiry =
|
||||
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
|
||||
// record upload-deleted from success screen
|
||||
sendEvent('sender', 'upload-deleted', {
|
||||
cm1: file.size,
|
||||
cm2: file.totalTime,
|
||||
cm3: file.uploadSpeed,
|
||||
cm4: timeToExpiry,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: unexpiredFiles,
|
||||
cm7: storage.totalDownloads,
|
||||
cd1: file.typeOfUpload,
|
||||
cd4: 'success-screen'
|
||||
}).then(() => {
|
||||
storage.remove(file.fileId);
|
||||
location.reload();
|
||||
});
|
||||
});
|
||||
};
|
||||
// show popup
|
||||
@@ -360,7 +538,7 @@ $(document).ready(function() {
|
||||
$popupText.focus();
|
||||
});
|
||||
// hide popup
|
||||
$popupText.find('.nvm').click(function(e) {
|
||||
$popupText.find('.popup-no').click(function(e) {
|
||||
e.stopPropagation();
|
||||
$popupText.removeClass('show');
|
||||
});
|
||||
@@ -372,7 +550,6 @@ $(document).ready(function() {
|
||||
$popupText.removeClass('show');
|
||||
});
|
||||
|
||||
|
||||
toggleHeader();
|
||||
}
|
||||
function toggleHeader() {
|
||||
|
||||
@@ -69,9 +69,55 @@ function gcmCompliant() {
|
||||
}
|
||||
}
|
||||
|
||||
function findMetric(href) {
|
||||
switch (href) {
|
||||
case 'https://www.mozilla.org/':
|
||||
return 'mozilla';
|
||||
case 'https://www.mozilla.org/about/legal':
|
||||
return 'legal';
|
||||
case 'https://testpilot.firefox.com/about':
|
||||
return 'about';
|
||||
case 'https://testpilot.firefox.com/privacy':
|
||||
return 'privacy';
|
||||
case 'https://testpilot.firefox.com/terms':
|
||||
return 'terms';
|
||||
case 'https://www.mozilla.org/en-US/privacy/websites/#cookies':
|
||||
return 'cookies';
|
||||
case 'https://github.com/mozilla/send':
|
||||
return 'github';
|
||||
case 'https://twitter.com/FxTestPilot':
|
||||
return 'twitter';
|
||||
case 'https://www.mozilla.org/firefox/new/?scene=2':
|
||||
return 'download-firefox';
|
||||
default:
|
||||
return 'other';
|
||||
}
|
||||
}
|
||||
|
||||
function isFile(id) {
|
||||
return ![
|
||||
'referrer',
|
||||
'totalDownloads',
|
||||
'totalUploads',
|
||||
'testpilot_ga__cid'
|
||||
].includes(id);
|
||||
}
|
||||
|
||||
function sendEvent() {
|
||||
return window.analytics.sendEvent
|
||||
.apply(window.analytics, arguments)
|
||||
.catch(() => 0);
|
||||
}
|
||||
|
||||
const ONE_DAY_IN_MS = 86400000;
|
||||
|
||||
module.exports = {
|
||||
arrayToHex,
|
||||
hexToArray,
|
||||
notify,
|
||||
gcmCompliant
|
||||
gcmCompliant,
|
||||
findMetric,
|
||||
isFile,
|
||||
sendEvent,
|
||||
ONE_DAY_IN_MS
|
||||
};
|
||||
|
||||
12
l10n.toml
Normal file
12
l10n.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
basepath = "."
|
||||
|
||||
[env]
|
||||
l = "{l10n_base}/public/locales/{locale}/"
|
||||
|
||||
[[paths]]
|
||||
reference = "public/locales/en-US/**"
|
||||
l10n = "{l}**"
|
||||
3959
package-lock.json
generated
3959
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
53
package.json
53
package.json
@@ -1,44 +1,43 @@
|
||||
{
|
||||
"name": "firefox-send",
|
||||
"description": "File Sharing Experiment",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"author": "Mozilla (https://mozilla.org)",
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.62.0",
|
||||
"aws-sdk": "^2.89.0",
|
||||
"body-parser": "^1.17.2",
|
||||
"bytes": "^2.5.0",
|
||||
"connect-busboy": "0.0.2",
|
||||
"convict": "^3.0.0",
|
||||
"cross-env": "^5.0.1",
|
||||
"express": "^4.15.3",
|
||||
"express-handlebars": "^3.0.0",
|
||||
"helmet": "^3.6.1",
|
||||
"jquery": "^3.2.1",
|
||||
"jquery-circle-progress": "^1.2.2",
|
||||
"l20n": "^5.0.0",
|
||||
"helmet": "^3.8.0",
|
||||
"mozlog": "^2.1.1",
|
||||
"raven": "^2.1.0",
|
||||
"raven-js": "^3.16.0",
|
||||
"redis": "^2.7.1",
|
||||
"selenium-webdriver": "^3.4.0",
|
||||
"supertest": "^3.0.0",
|
||||
"uglify-es": "3.0.19"
|
||||
"redis": "^2.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"browserify": "^14.4.0",
|
||||
"eslint": "^4.0.0",
|
||||
"eslint": "^4.3.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
"eslint-plugin-node": "^5.0.0",
|
||||
"eslint-plugin-node": "^5.1.1",
|
||||
"eslint-plugin-security": "^1.4.0",
|
||||
"git-rev-sync": "^1.9.1",
|
||||
"jquery": "^3.2.1",
|
||||
"jquery-circle-progress": "^1.2.2",
|
||||
"l20n": "^5.0.0",
|
||||
"mocha": "^3.4.2",
|
||||
"npm-run-all": "^4.0.2",
|
||||
"prettier": "^1.4.4",
|
||||
"prettier": "^1.5.3",
|
||||
"proxyquire": "^1.8.0",
|
||||
"sinon": "^2.3.5",
|
||||
"stylelint": "^7.11.0",
|
||||
"raven-js": "^3.17.0",
|
||||
"selenium-webdriver": "^3.5.0",
|
||||
"sinon": "^2.3.8",
|
||||
"stylelint": "^7.13.0",
|
||||
"stylelint-config-standard": "^16.0.0",
|
||||
"watchify": "^3.9.0"
|
||||
"supertest": "^3.0.0",
|
||||
"testpilot-ga": "^0.3.0",
|
||||
"uglifyify": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
@@ -46,16 +45,22 @@
|
||||
"homepage": "https://github.com/mozilla/send/",
|
||||
"license": "MPL-2.0",
|
||||
"repository": "mozilla/send",
|
||||
"availableLanguages": ["en-US"],
|
||||
"scripts": {
|
||||
"predocker": "browserify frontend/src/main.js | uglifyjs > public/bundle.js && npm run version",
|
||||
"dev": "npm run version && watchify frontend/src/main.js -o public/bundle.js -d | node server/server",
|
||||
"format": "prettier '{frontend/src/,scripts/,server/,test/}*.js' 'public/*.css' --single-quote --write",
|
||||
"build": "npm-run-all build:*",
|
||||
"build:upload": "browserify frontend/src/upload.js -g uglifyify -o public/upload.js",
|
||||
"build:download": "browserify frontend/src/download.js -g uglifyify -o public/download.js",
|
||||
"build:version": "node scripts/version",
|
||||
"build:l10n": "cp node_modules/l20n/dist/web/l20n.min.js public",
|
||||
"dev": "npm run build && npm start",
|
||||
"format": "prettier '{frontend/src/,scripts/,server/,test/**/}*.js' 'public/*.css' --single-quote --write",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:css": "stylelint 'public/*.css'",
|
||||
"lint:js": "eslint .",
|
||||
"start": "node server/server",
|
||||
"test": "mocha test/unit && mocha test/server && npm run test-browser && node test/frontend/driver.js",
|
||||
"test-browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d",
|
||||
"version": "node scripts/version"
|
||||
"test": "npm-run-all test:*",
|
||||
"test:unit": "mocha test/unit",
|
||||
"test:server": "mocha test/server",
|
||||
"test:browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d && node test/frontend/driver.js"
|
||||
}
|
||||
}
|
||||
|
||||
95
public/locales/de/send.ftl
Normal file
95
public/locales/de/send.ftl
Normal file
@@ -0,0 +1,95 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = Web-Experiment
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Privates, verschlüsseltes Austauschen von Dateien
|
||||
uploadPageExplainer = Senden Sie Dateien über einen sicheren, privaten und verschlüsselten Link, der automatisch abläuft, damit Ihre Daten nicht für immer im Internet bleiben.
|
||||
uploadPageLearnMore = Mehr erfahren
|
||||
uploadPageDropMessage = Ziehen Sie eine Datei zum Hochladen hierher
|
||||
uploadPageSizeMessage = Dateien unter 1 GB sorgen für erhöhte Zuverlässigkeit des Betriebs
|
||||
uploadPageBrowseButton = Wählen Sie eine Datei auf Ihrem Computer aus
|
||||
.title = Wählen Sie eine Datei auf Ihrem Computer aus
|
||||
uploadPageMultipleFilesAlert = Hochladen mehrerer Dateien oder eines Ordners wird derzeit nicht unterstützt.
|
||||
uploadPageBrowseButtonTitle = Datei hochladen
|
||||
uploadingPageHeader = Ihre Datei wird hochgeladen
|
||||
importingFile = Wird importiert…
|
||||
verifyingFile = Wird überprüft…
|
||||
encryptingFile = Wird verschlüsselt
|
||||
decryptingFile = Wird entschlüsselt...
|
||||
notifyUploadDone = Ihr Upload ist abgeschlossen.
|
||||
uploadingPageMessage = Sobald Ihre Datei hochgeladen wird, können Sie die Optionen zum Ablaufdatum auswählen.
|
||||
uploadingPageCancel = Hochladen abbrechen
|
||||
.title = Hochladen abbrechen
|
||||
uploadCancelNotification = Ihr Upload wurde abgebrochen.
|
||||
uploadingPageLargeFileMessage = Diese Datei ist groß, sodass das hochladen einige Zeit dauern könnte. Haben Sie Geduld!
|
||||
uploadingFileNotification = Mich benachrichtigen, wenn der Upload abgeschlossen ist.
|
||||
uploadSuccessConfirmHeader = Bereit zum Senden
|
||||
uploadSvgAlt
|
||||
.alt = Hochladen
|
||||
uploadSuccessTimingHeader = Der Link zu Ihrer Datei läuft nach einem Download oder in 24 Stunden ab.
|
||||
copyUrlFormLabelWithName = Kopieren und teilen Sie den Link, um Ihre Datei zu senden: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = In Zwischenablage kopieren
|
||||
.title = In Zwischenablage kopieren
|
||||
copiedUrl = Kopiert!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Datei löschen
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Eine weitere Datei senden
|
||||
.title = Eine weitere Datei senden
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Herunterladen
|
||||
downloadFileName = { $filename } herunterladen
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ihr Freund schickt Ihnen eine Datei mit Firefox Send, einem Dienst, mit dem Sie Dateien über einen sicheren, privaten und verschlüsselten Link teilen können, der automatisch abläuft, damit Ihre Daten nicht für immer im Internet bleiben.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Herunterladen
|
||||
.title = Herunterladen
|
||||
downloadNotification = Der Download wurde abgeschlossen.
|
||||
downloadFinish = Download abgeschlossen
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Firefox Send ausprobieren
|
||||
.title = Firefox Send ausprobieren
|
||||
downloadingPageProgress = { $filename } ({ $size }) wird heruntergeladen
|
||||
downloadingPageMessage = Bitte lassen Sie diesen Tab geöffnet, während Ihre Datei heruntergeladen und entschlüsselt wird.
|
||||
errorAltText
|
||||
.alt = Fehler beim Hochladen
|
||||
errorPageHeader = Ein Fehler ist aufgetreten!
|
||||
errorPageMessage = Beim Hochladen der Datei ist ein Fehler aufgetreten.
|
||||
errorPageLink = Eine weitere Datei senden
|
||||
fileTooBig = Die Datei ist zu groß zum Hochladen. Sie sollte maximal { $size } groß sein.
|
||||
linkExpiredAlt
|
||||
.alt = Link abgelaufen
|
||||
expiredPageHeader = Dieser Link ist abgelaufen oder hat nie existiert!
|
||||
notSupportedHeader = Ihr Browser wird nicht unterstützt.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Leider unterstützt dieser Browser die Web-Technologie nicht, auf der Firefox Send basiert. Sie benötigen einen anderen Browser. Wir empfehlen Firefox!
|
||||
downloadFirefoxButtonSub = Kostenloser Download
|
||||
uploadedFile = Datei
|
||||
copyFileList = Adresse kopieren
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Läuft ab in
|
||||
deleteFileList = Löschen
|
||||
nevermindButton = Egal
|
||||
deleteButtonHover
|
||||
.title = Löschen
|
||||
copyUrlHover
|
||||
.title = Adresse kopieren
|
||||
legalHeader = Nutzungsbedingungen und Datenschutz
|
||||
legalNoticeTestPilot = Firefox Send ist aktuell ein Test-Pilot-Experiment und unterliegt den <a>Nutzungsbedingungen</a> und dem <a>Datenschutzhinweis</a> von Test Pilot. Mehr über diese Experiment und die Daten, die es sammelt, erfahren Sie <a>hier</a>.
|
||||
legalNoticeMozilla = Die Nutzung der Website von Firefox Send unterliegt außerdem Mozillas <a>Datenschutzhinweis für Websites</a> und <a>Nutzungsbedingungen für Websites</a>.
|
||||
deletePopupText = Diese Datei löschen?
|
||||
deletePopupYes = Ja
|
||||
deletePopupCancel = Abbrechen
|
||||
deleteButtonHover
|
||||
.title = Löschen
|
||||
copyUrlHover
|
||||
.title = Adresse kopieren
|
||||
footerLinkLegal = Rechtliches
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Über Test Pilot
|
||||
footerLinkPrivacy = Datenschutz
|
||||
footerLinkTerms = Nutzungsbedingungen
|
||||
footerLinkCookies = Cookies
|
||||
@@ -1,87 +1,95 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
|
||||
siteSubtitle = web experiment
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Private, Encrypted File Sharing
|
||||
uploadPageExplainer = Send files through a safe, private, and encrypted link that automatically expires to ensure your stuff does not remain online forever.
|
||||
|
||||
uploadPageLearnMore = Learn more
|
||||
uploadPageDropMessage = Drop your file here to start uploading
|
||||
uploadPageSizeMessage = For the most reliable operation, it’s best to keep your file under 1GB
|
||||
uploadPageBrowseButton = Select a file on your computer
|
||||
.title = {uploadPageBrowseButtonTitle}
|
||||
.title = Select a file on your computer
|
||||
uploadPageMultipleFilesAlert = Uploading multiple files or a folder is currently not supported.
|
||||
|
||||
uploadPageBrowseButtonTitle = Upload file
|
||||
|
||||
uploadingPageHeader = Uploading Your File
|
||||
|
||||
importingFile = Importing…
|
||||
verifyingFile = Verifying…
|
||||
encryptingFile = Encrypting…
|
||||
decryptingFile = Decrypting…
|
||||
notifyUploadDone = Your upload has finished.
|
||||
|
||||
|
||||
uploadingPageMessage = Once your file uploads you will be able to set expiry options.
|
||||
uploadingPageCancel = Cancel upload
|
||||
.title = {uploadingPageCancel}
|
||||
.title = Cancel upload
|
||||
uploadCancelNotification = Your upload was cancelled.
|
||||
|
||||
uploadingPageLargeFileMessage = This file is large and may take awhile to upload. Sit tight!
|
||||
uploadingPageLargeFileMessage = This file is large and may take a while to upload. Sit tight!
|
||||
uploadingFileNotification = Notify me when the upload is complete.
|
||||
uploadSuccessConfirmHeader = Ready to Send
|
||||
|
||||
uploadSvgAlt.alt = Upload
|
||||
|
||||
|
||||
//Note the spec suggests that this string is editable. That feature will not appear at Launch
|
||||
uploadSvgAlt
|
||||
.alt = Upload
|
||||
uploadSuccessTimingHeader = The link to your file will expire after 1 download or in 24 hours.
|
||||
copyUrlFormLabel = Copy and share the link to send your file:
|
||||
copyUrlFormLabelWithName = Copy and share the link to send your file: { $filename }
|
||||
// Note: Title text for button should be the same
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Copy to clipboard
|
||||
.title = {copyUrlFormButton}
|
||||
|
||||
.title = Copy to clipboard
|
||||
copiedUrl = Copied!
|
||||
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Delete file
|
||||
.title = {deleteFileButton}
|
||||
.title = Delete file
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Send another file
|
||||
.title = {sendAnotherFileLink}
|
||||
|
||||
downloadAltText.alt = Download
|
||||
downloadFileName = Download { $filename }
|
||||
.title = Send another file
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Download
|
||||
downloadFileName = Download { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Your friend is sending you a file with Firefox Send, a service that allows you to share files with a safe, private, and encrypted link that automatically expires to ensure your stuff does not remain online forever.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Download
|
||||
.title = {downloadButtonLabel}
|
||||
.title = Download
|
||||
downloadNotification = Your download has completed.
|
||||
downloadFinish = Download Complete
|
||||
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Try Firefox Send
|
||||
.title = {sendYourFilesLink}
|
||||
.title = Try Firefox Send
|
||||
downloadingPageProgress = Downloading { $filename } ({ $size })
|
||||
downloadingPageMessage = Please leave this tab open while we fetch your file and decrypt it.
|
||||
|
||||
errorAltText.alt = Upload error
|
||||
errorAltText
|
||||
.alt = Upload error
|
||||
errorPageHeader = Something went wrong!
|
||||
errorPageMessage = There has been an error uploading the file.
|
||||
errorPageLink = Send another file
|
||||
|
||||
fileTooBig = That file is too big to upload. It should be less than { $size }.
|
||||
|
||||
linkExpiredAlt.alt = Link expired
|
||||
linkExpiredAlt
|
||||
.alt = Link expired
|
||||
expiredPageHeader = This link has expired or never existed in the first place!
|
||||
notSupportedHeader = Your browser is not supported.
|
||||
notSupportedDetail = Unfortunately this browser does not support the web technology that powers Firefox Send. You'll need to try another browser. We recommend Firefox!
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Unfortunately this browser does not support the web technology that powers Firefox Send. You’ll need to try another browser. We recommend Firefox!
|
||||
downloadFirefoxButtonSub = Free Download
|
||||
|
||||
|
||||
sentFilesTitle1 = File
|
||||
sentFilesTitle2 = Copy URL
|
||||
sentFilesTitle3 = Expires In
|
||||
sentFilesTitle4 = Delete
|
||||
|
||||
nevermindButton = Nevermind
|
||||
deleteButtonHover.title = {sentFilesTitle4}
|
||||
copyUrlHover.title = {sentFilesTitle2}
|
||||
|
||||
uploadedFile = File
|
||||
copyFileList = Copy URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Expires In
|
||||
deleteFileList = Delete
|
||||
nevermindButton = Never mind
|
||||
deleteButtonHover
|
||||
.title = Delete
|
||||
copyUrlHover
|
||||
.title = Copy URL
|
||||
legalHeader = Terms & Privacy
|
||||
legalNoticeTestPilot = Firefox Send is currently a Test Pilot experiment, and subject to the Test Pilot <a>Terms of Service</a> and <a>Privacy Notice</a>. You can learn more about this experiment and its data collection <a>here</a>.
|
||||
legalNoticeMozilla = Use of the Firefox Send website is also subject to Mozilla’s <a>Websites Privacy Notice</a> and <a>Websites Terms of Use</a>.
|
||||
deletePopupText = Delete this file?
|
||||
deletePopupYes = Yes
|
||||
deletePopupCancel = Cancel
|
||||
deleteButtonHover
|
||||
.title = Delete
|
||||
copyUrlHover
|
||||
.title = Copy URL
|
||||
footerLinkLegal = Legal
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = About Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Terms
|
||||
88
public/locales/hsb/send.ftl
Normal file
88
public/locales/hsb/send.ftl
Normal file
@@ -0,0 +1,88 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = webeksperiment
|
||||
siteFeedback = Komentar
|
||||
uploadPageHeader = Priwatne, zaklučowane dźělenje datajow
|
||||
uploadPageExplainer = Pósćelće dataje přez wěstny, priwatny a zaklučowany wotkaz, kotryž awtomatisće spadnje, zo njebychu waše daty na přeco online wostali.
|
||||
uploadPageLearnMore = Dalše informacije
|
||||
uploadPageDropMessage = Ćehńće swoju dataju sem, zo byšće ju nahrał
|
||||
uploadPageSizeMessage = Wužiwajće najlěpje dataje, kotrež su mjeńše hač 1 GB za lěpšu spušćomnosć.
|
||||
uploadPageBrowseButton = Wubjerće dataju na swojim ličaku
|
||||
.title = Wubjerće dataju na swojim ličaku
|
||||
uploadPageMultipleFilesAlert = Nahrawanje wjacorych datajow abo rjadowaka so tuchwilu njepodpěruje.
|
||||
uploadPageBrowseButtonTitle = Dataju nahrać
|
||||
uploadingPageHeader = Waša dataja so nahrawa
|
||||
importingFile = Importuje so...
|
||||
verifyingFile = Přepruwuje so...
|
||||
encryptingFile = Zaklučuje so...
|
||||
decryptingFile = Dešifruje so...
|
||||
notifyUploadDone = Waše nahraće je dokónčene.
|
||||
uploadingPageMessage = Hdyž do waša dataja nahrawa, móžeće nastajenja spadnjenja postajić.
|
||||
uploadingPageCancel = Nahraće přetorhnyć
|
||||
.title = Nahraće přetorhnyć
|
||||
uploadCancelNotification = Waše nahraće je so přetorhnyło.
|
||||
uploadingFileNotification = Zdźělić, hdyž nahraće je dokónčene.
|
||||
uploadSuccessConfirmHeader = Hotowy za słanje
|
||||
uploadSvgAlt
|
||||
.alt = Nahrać
|
||||
uploadSuccessTimingHeader = Wotkaz k wašej dataji po 1 sćehnjenju abo 24 hodźinach spadnje.
|
||||
copyUrlFormLabelWithName = Kopěrujće a dźělće wotkaz, zo byšće swoju dataju pósłał: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Do mjezyskłada kopěrować
|
||||
.title = Do mjezyskłada kopěrować
|
||||
copiedUrl = Kopěrowany!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Dataju zhašeć
|
||||
.title = Dataju zhašeć
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Druhu dataju pósłać
|
||||
.title = Druhu dataju pósłać
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Sćahnyć
|
||||
downloadFileName = { $filename } sćahnyć
|
||||
downloadFileSize = ({ $size })
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Sćahnyć
|
||||
.title = Sćahnyć
|
||||
downloadNotification = Waše sćehnjenje je dokónčene.
|
||||
downloadFinish = Sćehnjenje dokónčene
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Firefox Send wupruwować
|
||||
.title = Firefox Send wupruwować
|
||||
downloadingPageProgress = { $filename } ({ $size }) so sćahuje
|
||||
errorAltText
|
||||
.alt = Nahrawanski zmylk
|
||||
errorPageHeader = Něšto je so nimokuliło!
|
||||
errorPageMessage = Při nahrawanju dataje je zmylk wustupił.
|
||||
errorPageLink = Druhu dataju pósłać
|
||||
fileTooBig = Tuta dataja je přewulka za nahraće. Měła mjeńša hač { $size } być.
|
||||
linkExpiredAlt
|
||||
.alt = Wotkaz je spadnjeny
|
||||
expiredPageHeader = Tutón wotkaz je spadnjeny abo njeje ženje eksistował.
|
||||
notSupportedHeader = Waš wobhladowak so njepodpěruje.
|
||||
downloadFirefoxButtonSub = Darmotne sćehnjenje
|
||||
uploadedFile = Dataja
|
||||
copyFileList = URL kopěrować
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Spadnje za
|
||||
deleteFileList = Zhašeć
|
||||
nevermindButton = Wšojedne
|
||||
deleteButtonHover
|
||||
.title = Zhašeć
|
||||
copyUrlHover
|
||||
.title = URL kopěrować
|
||||
legalHeader = Wuměnjenja a priwatnosć
|
||||
deletePopupText = Tutu dataju zhašeć?
|
||||
deletePopupYes = Haj
|
||||
deletePopupCancel = Přetorhnyć
|
||||
deleteButtonHover
|
||||
.title = Zhašeć
|
||||
copyUrlHover
|
||||
.title = URL kopěrować
|
||||
footerLinkLegal = Prawniske
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Wo Test Pilot
|
||||
footerLinkPrivacy = Priwatnosć
|
||||
footerLinkTerms = Wuměnjenja
|
||||
footerLinkCookies = Placki
|
||||
96
public/locales/it/send.ftl
Normal file
96
public/locales/it/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = esperimento web
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Condivisione di file riservata e cifrata
|
||||
uploadPageExplainer = Invia file in modo sicuro, riservato e crittato, con un link che scade automaticamente per garantire che i tuoi dati non rimangano online per sempre.
|
||||
uploadPageLearnMore = Ulteriori informazioni
|
||||
uploadPageDropMessage = Trascina qui i tuoi file per caricarli
|
||||
uploadPageSizeMessage = Per un risultato affidabile è consigliabile mantenere il file al di sotto di 1 GB
|
||||
uploadPageBrowseButton = Seleziona un file sul computer
|
||||
.title = Seleziona un file sul computer
|
||||
uploadPageMultipleFilesAlert = Il caricamento di più file o cartelle non è attualmente supportato.
|
||||
uploadPageBrowseButtonTitle = Carica file
|
||||
uploadingPageHeader = Caricamento file
|
||||
importingFile = Importazione in corso…
|
||||
verifyingFile = Verifica in corso…
|
||||
encryptingFile = Crittografia in corso...
|
||||
decryptingFile = Decrittografia in corso...
|
||||
notifyUploadDone = Il caricamento è stato completato.
|
||||
uploadingPageMessage = È possibile impostare le opzioni di scadenza una volta caricato il file.
|
||||
uploadingPageCancel = Annulla caricamento
|
||||
.title = Annulla caricamento
|
||||
uploadCancelNotification = Il caricamento è stato annullato.
|
||||
uploadingPageLargeFileMessage = Si tratta di un file di grandi dimensioni e potrebbe volerci un po' di tempo.
|
||||
uploadingFileNotification = Invia una notifica quando il caricamento è completato.
|
||||
uploadSuccessConfirmHeader = Pronto per l'invio
|
||||
uploadSvgAlt
|
||||
.alt = Carica
|
||||
uploadSuccessTimingHeader = Il link al file scadrà dopo 1 download o in 24 ore.
|
||||
copyUrlFormLabelWithName = Copia e condividi il link per inviare il tuo file: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Copia negli appunti
|
||||
.title = Copia negli appunti
|
||||
copiedUrl = Copiato
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Elimina file
|
||||
.title = Elimina file
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Invia un altro file
|
||||
.title = Invia un altro file
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Scarica
|
||||
downloadFileName = Scarica { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Qualcuno ti ha inviato un file con Firefox Send: è un servizio che permette di condividere file in modo sicuro, riservato e crittato, attraverso un link che scade automaticamente, garantendo che i tuoi dati non rimangano online per sempre.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Scarica
|
||||
.title = Scarica
|
||||
downloadNotification = Download completato.
|
||||
downloadFinish = Download completato
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Prova Firefox Send
|
||||
.title = Prova Firefox Send
|
||||
downloadingPageProgress = Download in corso di { $filename } ({ $size })
|
||||
downloadingPageMessage = Mantieni aperta questa scheda mentre il file viene scaricato e decrittato.
|
||||
errorAltText
|
||||
.alt = Errore durante il caricamento
|
||||
errorPageHeader = Si è verificato un errore.
|
||||
errorPageMessage = Si è verificato un errore durante il caricamento del file.
|
||||
errorPageLink = Invia un altro file
|
||||
fileTooBig = Le dimensioni di questo file sono eccessive. Dovrebbe essere inferiore a { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Link scaduto
|
||||
expiredPageHeader = Questo link è scaduto oppure non è mai esistito.
|
||||
notSupportedHeader = Il browser in uso non è supportato.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Sfortunatamente questo browser non supporta le tecnologie web alla base di Firefox Send. Devi utilizzare un altro browser. Ti consigliamo Firefox!
|
||||
downloadFirefoxButtonSub = Download gratuito
|
||||
uploadedFile = File
|
||||
copyFileList = Copia indirizzo
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Scade in
|
||||
deleteFileList = Elimina
|
||||
nevermindButton = No, grazie
|
||||
deleteButtonHover
|
||||
.title = Elimina
|
||||
copyUrlHover
|
||||
.title = Copia indirizzo
|
||||
legalHeader = Termini di utilizzo e privacy
|
||||
legalNoticeTestPilot = Firefox Send è attualmente un esperimento di Test Pilot ed è soggetto alle <a>Condizioni di utilizzo</a> e all’<a>Informativa sulla privacy</a> di Test Pilot. Per ulteriori informazioni su questo esperimento e i dati raccolti, consulta <a>questa pagina<a>.
|
||||
legalNoticeMozilla = L’utilizzo del sito di Firefox Send è soggetto all’<a>Informativa sulla privacy</a> e le <a>Condizioni di utilizzo</a> dei siti web Mozilla.
|
||||
deletePopupText = Eliminare questo file?
|
||||
deletePopupYes = Sì
|
||||
deletePopupCancel = Annulla
|
||||
deleteButtonHover
|
||||
.title = Elimina
|
||||
copyUrlHover
|
||||
.title = Copia indirizzo
|
||||
footerLinkLegal = Note legali
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Informazioni su Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Condizioni di utilizzo
|
||||
footerLinkCookies = Cookie
|
||||
96
public/locales/ja/send.ftl
Normal file
96
public/locales/ja/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = ウェブ実験
|
||||
siteFeedback = フィードバック
|
||||
uploadPageHeader = プライベートな暗号化されたファイル共有
|
||||
uploadPageExplainer = 安全で、プライベートで、暗号化されたリンクを通じてファイルを送信。あなたのものがずっとオンラインに残らないよう、リンクは自動的に期限切れとなります。
|
||||
uploadPageLearnMore = 詳しくはこちら
|
||||
uploadPageDropMessage = ここにファイルをドロップしてアップロードを開始
|
||||
uploadPageSizeMessage = 確実に処理できるよう、ファイルサイズは 1 GB 以下にすることを推奨します。
|
||||
uploadPageBrowseButton = コンピューター上のファイルを選択
|
||||
.title = コンピューター上のファイルを選択
|
||||
uploadPageMultipleFilesAlert = 今のところ複数ファイルやフォルダーのアップロードには対応していません。
|
||||
uploadPageBrowseButtonTitle = ファイルをアップロード
|
||||
uploadingPageHeader = ファイルをアップロードしています
|
||||
importingFile = インポート中...
|
||||
verifyingFile = 検証中...
|
||||
encryptingFile = 暗号化中...
|
||||
decryptingFile = 復号化中...
|
||||
notifyUploadDone = アップロードが完了しました。
|
||||
uploadingPageMessage = ファイルのアップロード完了後に期限を設定できます。
|
||||
uploadingPageCancel = アップロードを中止
|
||||
.title = アップロードを中止
|
||||
uploadCancelNotification = アップロードは中止されました。
|
||||
uploadingPageLargeFileMessage = このファイルは大きいのでアップロードに多少時間が掛かるかもしれません。しばらくお待ちください。
|
||||
uploadingFileNotification = アップロード完了時に通知を受け取る
|
||||
uploadSuccessConfirmHeader = 送信準備完了
|
||||
uploadSvgAlt
|
||||
.alt = アップロード
|
||||
uploadSuccessTimingHeader = ファイルへのリンクは、1 回ダウンロードされた後、もしくは 24 時間以内に期限切れとなります。
|
||||
copyUrlFormLabelWithName = ファイルを送信するにはこのリンクをコピー、共有してください: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = クリップボードへコピー
|
||||
.title = クリップボードへコピー
|
||||
copiedUrl = コピー完了!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = ファイルを削除
|
||||
.title = ファイルを削除
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = 他のファイルを送信
|
||||
.title = 他のファイルを送信
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = ダウンロード
|
||||
downloadFileName = { $filename } をダウンロード
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = あなたの友人が Firefox Send を通じてファイルを送ってきています。これは、安全で、プライベートで、暗号化されたリンクを通じてファイルを共有できるサービスです。あなたのものがずっとオンラインに残らないよう、リンクは自動的に期限切れとなります。
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = ダウンロード
|
||||
.title = ダウンロード
|
||||
downloadNotification = ダウンロードが完了しました。
|
||||
downloadFinish = ダウンロード完了
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Firefox Send を試す
|
||||
.title = Firefox Send を試す
|
||||
downloadingPageProgress = { $filename } ({ $size }) をダウンロードしています
|
||||
downloadingPageMessage = ファイルの取得と暗号化が完了するまでこのタブを開いたままにしておいてください。
|
||||
errorAltText
|
||||
.alt = アップロードエラー
|
||||
errorPageHeader = 何か問題が発生しました。
|
||||
errorPageMessage = ファイルのアップロード中に問題が発生しました。
|
||||
errorPageLink = 他のファイルを送信
|
||||
fileTooBig = このファイルは大きすぎるためアップロードできません。上限は { $size } です。
|
||||
linkExpiredAlt
|
||||
.alt = リンク期限切れ
|
||||
expiredPageHeader = このリンクは期限切れとなったか元々存在していません。
|
||||
notSupportedHeader = お使いのブラウザーには対応していません。
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = 残念ながらこのブラウザーは Firefox Send が活用しているウェブ技術に対応していません。他のブラウザーで試してください。私たちは Firefox をお勧めします!
|
||||
downloadFirefoxButtonSub = 無料ダウンロード
|
||||
uploadedFile = ファイル
|
||||
copyFileList = URL をコピー
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = 有効期限:
|
||||
deleteFileList = 削除
|
||||
nevermindButton = 気にしないでください
|
||||
deleteButtonHover
|
||||
.title = 削除
|
||||
copyUrlHover
|
||||
.title = URL をコピー
|
||||
legalHeader = 利用規約とプライバシー
|
||||
legalNoticeTestPilot = Firefox Send は今のところ Test Pilot 実験のひとつであり、Test Pilot <a>利用規約</a> と <a>プライバシー通知</a> が適用されます。この実験とそのデータ収集に関する詳細は <a>こちら</a> をご覧ください。
|
||||
legalNoticeMozilla = Firefox Send のサイトの利用には、Mozilla の <a>ウェブサイトプライバシー通知</a> と <a>ウェブサイト利用規約</a> も適用されます。
|
||||
deletePopupText = このファイルを削除しますか?
|
||||
deletePopupYes = はい
|
||||
deletePopupCancel = キャンセル
|
||||
deleteButtonHover
|
||||
.title = 削除
|
||||
copyUrlHover
|
||||
.title = URL をコピー
|
||||
footerLinkLegal = 法的情報
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Test Pilot について
|
||||
footerLinkPrivacy = プライバシー
|
||||
footerLinkTerms = 利用規約
|
||||
footerLinkCookies = Cookie
|
||||
11
public/locales/ms/send.ftl
Normal file
11
public/locales/ms/send.ftl
Normal file
@@ -0,0 +1,11 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = experimen web
|
||||
siteFeedback = Maklum balas
|
||||
uploadPageHeader = Peribadi, Perkongsian Fail Dienkrip
|
||||
uploadPageExplainer = Hantar fail melalui pautan yang selamat, peribadi dan dienkrip, yang akan luput secara automatik untuk memastikan fail anda itu tidak terus berada dalam talian selama-lamanya.
|
||||
uploadPageLearnMore = Ketahui selanjutnya
|
||||
uploadPageDropMessage = Letakkan fail anda di sini untuk mulakan memuat naik
|
||||
uploadPageSizeMessage = Untuk operasi yang paling selamat, lebih baik pastikan fail anda itu kurang 1GB
|
||||
uploadPageBrowseButton = Pilih fail dalam komputer anda
|
||||
.title = Pilih fail dalam komputer anda
|
||||
81
public/locales/nb-NO/send.ftl
Normal file
81
public/locales/nb-NO/send.ftl
Normal file
@@ -0,0 +1,81 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = netteksperiment
|
||||
siteFeedback = Tilbakemelding
|
||||
uploadPageHeader = Privat, kryptert fildeling
|
||||
uploadPageLearnMore = Les mer
|
||||
uploadPageDropMessage = Slipp din fil her for å starte opplastingen
|
||||
uploadPageSizeMessage = For den mest problemfrie bruken, er det best å holde filen under 1 GB
|
||||
uploadPageBrowseButton = Velg en fil på din datamaskin
|
||||
.title = Velg en fil på din datamaskin
|
||||
uploadPageBrowseButtonTitle = Last opp fil
|
||||
uploadingPageHeader = Laster opp din fil
|
||||
importingFile = Importerer…
|
||||
verifyingFile = Verifiserer...
|
||||
encryptingFile = Krypterer...
|
||||
decryptingFile = Dekrypterer...
|
||||
uploadingPageCancel = Avbryt opplasting
|
||||
.title = Avbryt opplasting
|
||||
uploadCancelNotification = Din opplasting ble avbrutt
|
||||
uploadSuccessConfirmHeader = Klar til å sende
|
||||
uploadSvgAlt
|
||||
.alt = Last opp
|
||||
uploadSuccessTimingHeader = Lenken til filen din utløper etter 1 nedlasting eller om 24 timer.
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Kopier til utklippstavle
|
||||
.title = Kopier til utklippstavle
|
||||
copiedUrl = Kopiert!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Slett fil
|
||||
.title = Slett fil
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Send en annen fil
|
||||
.title = Send en annen fil
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Last ned
|
||||
downloadFileName = Last ned { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Last ned
|
||||
.title = Last ned
|
||||
downloadNotification = Nedlastingen er fullført.
|
||||
downloadFinish = Nedlastingen er fullført.
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Prøv Firefox Send
|
||||
.title = Prøv Firefox Send
|
||||
downloadingPageProgress = Laster ned { $filename } ({ $size })
|
||||
errorAltText
|
||||
.alt = Opplastingsfeil
|
||||
errorPageHeader = Det oppstod en feil.
|
||||
errorPageLink = Send en annen fil
|
||||
linkExpiredAlt
|
||||
.alt = Lenke utløpt
|
||||
notSupportedHeader = Din nettleser er ikke støttet.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Dessverre støtter denne nettleseren ikke webteknologien som driver Firefox Send. Du må prøve en annen nettleser. Vi anbefaler Firefox!
|
||||
downloadFirefoxButtonSub = Gratis nedlasting
|
||||
uploadedFile = Fil
|
||||
copyFileList = Kopier URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Utløper om
|
||||
deleteFileList = Slett
|
||||
nevermindButton = Glem det
|
||||
deleteButtonHover
|
||||
.title = Slett
|
||||
copyUrlHover
|
||||
.title = Kopier URL
|
||||
legalHeader = Vilkår og personvern
|
||||
deletePopupText = Slett denne filen?
|
||||
deletePopupYes = Ja
|
||||
deletePopupCancel = Avbryt
|
||||
deleteButtonHover
|
||||
.title = Slett
|
||||
copyUrlHover
|
||||
.title = Kopier URL
|
||||
footerLinkLegal = Juridisk informasjon
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Om Test Pilot
|
||||
footerLinkPrivacy = Personvern
|
||||
footerLinkTerms = Vilkår
|
||||
footerLinkCookies = Infokapsler
|
||||
35
public/locales/pt-BR/send.ftl
Normal file
35
public/locales/pt-BR/send.ftl
Normal file
@@ -0,0 +1,35 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = experimento web
|
||||
siteFeedback = Opinião
|
||||
uploadPageHeader = Compartilhamento de arquivos privados e criptografados
|
||||
uploadPageExplainer = Envie arquivos por meio de um link seguro, privado e criptografado que expira automaticamente para garantir que as suas coisas não permaneçam on-line para sempre.
|
||||
uploadPageLearnMore = Saiba mais
|
||||
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter seu arquivo menor que 1GB
|
||||
uploadPageBrowseButton = Selecione um arquivo em seu computador
|
||||
.title = Selecione um arquivo em seu computador
|
||||
importingFile = Importando…
|
||||
verifyingFile = Verificando…
|
||||
encryptingFile = Criptografando...
|
||||
decryptingFile = Descriptografando...
|
||||
uploadSuccessConfirmHeader = Pronto para enviar
|
||||
uploadSuccessTimingHeader = O link para o seu arquivo expirará após 1 download ou em 24 horas.
|
||||
copyUrlFormLabelWithName = Copie e compartilhe o link para enviar o seu arquivo: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Copiar para área de transferência
|
||||
.title = Copiar para área de transferência
|
||||
copiedUrl = Copiado!
|
||||
uploadedFile = Arquivo
|
||||
copyFileList = Copiar URL
|
||||
deleteFileList = Excluir
|
||||
deleteButtonHover
|
||||
.title = Excluir
|
||||
legalHeader = Termos e privacidade
|
||||
deletePopupText = Excluir este arquivo
|
||||
deletePopupYes = Sim
|
||||
deletePopupCancel = Cancelar
|
||||
deleteButtonHover
|
||||
.title = Excluir
|
||||
footerLinkPrivacy = Privacidade
|
||||
footerLinkTerms = Termos
|
||||
footerLinkCookies = Cookies
|
||||
96
public/locales/pt-PT/send.ftl
Normal file
96
public/locales/pt-PT/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = experiência web
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Partilha de ficheiros privada e encriptada
|
||||
uploadPageExplainer = Envie ficheiros através de uma ligação segura, privada e encriptada que automaticamente expira para garantir que as suas coisas não fiquem online para sempre.
|
||||
uploadPageLearnMore = Saber mais
|
||||
uploadPageDropMessage = Largue o seu ficheiro aqui para começar a carregar
|
||||
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter o seu ficheiro abaixo de 1GB
|
||||
uploadPageBrowseButton = Selecione um ficheiro no seu computador
|
||||
.title = Selecione um ficheiro no seu computador
|
||||
uploadPageMultipleFilesAlert = Carregar múltiplos ficheiros ou uma pasta não é atualmente suportado.
|
||||
uploadPageBrowseButtonTitle = Carregar ficheiro
|
||||
uploadingPageHeader = A carregar o seu ficheiro
|
||||
importingFile = A importar...
|
||||
verifyingFile = A verificar...
|
||||
encryptingFile = A encriptar...
|
||||
decryptingFile = A desencriptar...
|
||||
notifyUploadDone = O seu carregamento terminou.
|
||||
uploadingPageMessage = Assim que o seu ficheiro carregar irá poder definir as opções de expiração.
|
||||
uploadingPageCancel = Cancelar carregamento
|
||||
.title = Cancelar carregamento
|
||||
uploadCancelNotification = O seu carregamento foi cancelado.
|
||||
uploadingPageLargeFileMessage = Este ficheiro é grande e pode demorar um pouco a carregar. Fique onde está!
|
||||
uploadingFileNotification = Notificar-me quando o carregamento estiver completo.
|
||||
uploadSuccessConfirmHeader = Pronto para enviar
|
||||
uploadSvgAlt
|
||||
.alt = Carregar
|
||||
uploadSuccessTimingHeader = A ligação para o seu ficheiro irá expirar depois de 1 descarga ou em 24 horas.
|
||||
copyUrlFormLabelWithName = Copie e partilhe a ligação para enviar o seu ficheiro: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Copiar para a área de transferência
|
||||
.title = Copiar para a área de transferência
|
||||
copiedUrl = Copiado!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Apagar ficheiro
|
||||
.title = Apagar ficheiro
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Enviar outro ficheiro
|
||||
.title = Enviar outro ficheiro
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Descarregar
|
||||
downloadFileName = Descarregar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// 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 automaticamente expira para garantir que as suas coisas não fiquem online para sempre.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Descarregar
|
||||
.title = Descarregar
|
||||
downloadNotification = A sua descarga foi completada.
|
||||
downloadFinish = Descarga completada
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Tentar o Firefox Send
|
||||
.title = Tentar o Firefox Send
|
||||
downloadingPageProgress = A descarregar { $filename } ({ $size })
|
||||
downloadingPageMessage = Por favor deixe este separador aberto enquanto obtemos o seu ficheiro e o desencriptamos.
|
||||
errorAltText
|
||||
.alt = Erro ao carregar
|
||||
errorPageHeader = Algo correu mal.
|
||||
errorPageMessage = Houve um erro ao carregar o ficheiro.
|
||||
errorPageLink = Enviar outro ficheiro
|
||||
fileTooBig = Esse ficheiro é muito grande para carregar. Deve ser menor do que { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Ligação expirada
|
||||
expiredPageHeader = Esta ligação expirou ou nunca existiu em primeiro lugar!
|
||||
notSupportedHeader = O seu navegador não é suportado.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Infelizmente este navegador não suporta a tecnologia web que faz o Firefox Send funcionar. Irá precisar de tentar outro navegador. Nós recomendamos o Firefox!
|
||||
downloadFirefoxButtonSub = Descarga gratuita
|
||||
uploadedFile = Ficheiro
|
||||
copyFileList = Copiar URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Expira em
|
||||
deleteFileList = Apagar
|
||||
nevermindButton = Esquecer
|
||||
deleteButtonHover
|
||||
.title = Apagar
|
||||
copyUrlHover
|
||||
.title = Copiar URL
|
||||
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>.
|
||||
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.
|
||||
deletePopupText = Apagar este ficheiro?
|
||||
deletePopupYes = Sim
|
||||
deletePopupCancel = Cancelar
|
||||
deleteButtonHover
|
||||
.title = Apagar
|
||||
copyUrlHover
|
||||
.title = Copiar URL
|
||||
footerLinkLegal = Legal
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Acerca do Test Pilot
|
||||
footerLinkPrivacy = Privacidade
|
||||
footerLinkTerms = Termos
|
||||
footerLinkCookies = Cookies
|
||||
96
public/locales/sk/send.ftl
Normal file
96
public/locales/sk/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = webový experiment
|
||||
siteFeedback = Spätná väzba
|
||||
uploadPageHeader = Súkromné, šifrované zdieľanie súborov
|
||||
uploadPageExplainer = Odosielajte súbory pomocou bezpečného, súkromného a šifrovaného odkazu, ktorého platnosť automaticky vyprší. Vďaka tomu máte istotu, že vaše súbory nezostanú na internete naveky.
|
||||
uploadPageLearnMore = Ďalšie informácie
|
||||
uploadPageDropMessage = Presunutím súboru sem začnete nahrávanie
|
||||
uploadPageSizeMessage = Pre zaistenie čo najväčšej spoľahlivosti vám odporúčame nahrávať súbory menšie než 1GB.
|
||||
uploadPageBrowseButton = Vyberte súbor vo vašom počítači
|
||||
.title = Vyberte súbor vo vašom počítači
|
||||
uploadPageMultipleFilesAlert = Nahrávanie viacerých súborov alebo priečinkov momentálne nie je podporované.
|
||||
uploadPageBrowseButtonTitle = Nahrať súbor
|
||||
uploadingPageHeader = Nahrávanie vášho súboru
|
||||
importingFile = Importuje sa…
|
||||
verifyingFile = Overuje sa…
|
||||
encryptingFile = Šifruje sa...
|
||||
decryptingFile = Dešifruje sa...
|
||||
notifyUploadDone = Vaše nahrávanie sa dokončilo.
|
||||
uploadingPageMessage = Po nahratí súboru budete môcť nastaviť vypršanie platnosti.
|
||||
uploadingPageCancel = Zrušiť nahrávanie
|
||||
.title = Zrušiť nahrávanie
|
||||
uploadCancelNotification = Vaše nahrávanie bolo zrušené.
|
||||
uploadingPageLargeFileMessage = Tento súbor je veľký. Nahrávanie tak môže chvíľu trvať.
|
||||
uploadingFileNotification = Upozorniť ma na ukončenie nahrávania
|
||||
uploadSuccessConfirmHeader = Pripravené na odoslanie
|
||||
uploadSvgAlt
|
||||
.alt = Nahrať
|
||||
uploadSuccessTimingHeader = Platnosť odkazu vyprší po 1 prevzatí alebo po uplynutí 24 hodín.
|
||||
copyUrlFormLabelWithName = Skopírovaním a zdieľaním odkazu odošlete váš súbor: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Kopírovať do schránky
|
||||
.title = Kopírovať do schránky
|
||||
copiedUrl = Skopírované!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Odstrániť súbor
|
||||
.title = Odstrániť súbor
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Odoslať ďalší súbor
|
||||
.title = Odoslať ďalší súbor
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Prevziať
|
||||
downloadFileName = Prevziať { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Váš priateľ vám odoslal súbor pomocou služby Firefox Sync - táto vám umožňuje zdieľať súbory pomocou bezpečného, súkromného a zašifrovaného odkazu, ktorého platnosť automaticky vyprší. Vďaka tomu máte istotu, že vaše súbory neostanú na internete naveky.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Prevziať
|
||||
.title = Prevziať
|
||||
downloadNotification = Vaše preberanie bolo dokončené.
|
||||
downloadFinish = Preberanie bolo dokončené
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Vyskúšajte Firefox Send
|
||||
.title = Vyskúšajte Firefox Send
|
||||
downloadingPageProgress = Preberá sa { $filename } ({ $size })
|
||||
downloadingPageMessage = Prosím, ponechajte túto kartu otvorenú zatiaľ čo váš súbor prevezmeme a dešifrujeme.
|
||||
errorAltText
|
||||
.alt = Pri nahrávaní sa vyskytla chyba
|
||||
errorPageHeader = Vyskytol sa problém.
|
||||
errorPageMessage = Pri nahrávaní súboru nastala chyba.
|
||||
errorPageLink = Odošlite ďalší súbor
|
||||
fileTooBig = Súbor je príliš veľký. Mal by byť menší než { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Platnosť odkazu vypršala
|
||||
expiredPageHeader = Platnosť tohto odkazu vypršala alebo daný odkaz nikdy neexistoval.
|
||||
notSupportedHeader = Váš prehliadač nie je podporovaný.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Žiaľ, tento prehliadač nepodporuje webovú technológiu, ktorá poháňa službu Firefox Send. Budete musieť vyskúšať iný prehliadač. My vám odporúčame Firefox!
|
||||
downloadFirefoxButtonSub = Prevziať zadarmo
|
||||
uploadedFile = Súbor
|
||||
copyFileList = Kopírovať adresu URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Platnosť vyprší
|
||||
deleteFileList = Odstrániť
|
||||
nevermindButton = Zrušiť
|
||||
deleteButtonHover
|
||||
.title = Odstrániť
|
||||
copyUrlHover
|
||||
.title = Skopírovať adresu URL
|
||||
legalHeader = Podmienky používania a súkromie
|
||||
legalNoticeTestPilot = Firefox Send je v súčasnosti experimentom projektu Test Pilot a vzťahujú sa naň <a>podmienky používania</a> a <a>zásady ochrany súkromia</a> Test Pilotu. Viac sa o zbieraní údajov experimentami dozviete <a>tu</a>.
|
||||
legalNoticeMozilla = Na použitie webovej stránky služby Firefox Send sa vzťahujú <a>zásady ochrany súkromia na webových stránkach</a> a <a>podmienky použitia webových stránok</a> Mozilly.
|
||||
deletePopupText = Naozaj chcete odstrániť tento súbor?
|
||||
deletePopupYes = Áno
|
||||
deletePopupCancel = Zrušiť
|
||||
deleteButtonHover
|
||||
.title = Odstrániť
|
||||
copyUrlHover
|
||||
.title = Skopírovať adresu URL
|
||||
footerLinkLegal = Právne informácie
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = O projekte Test Pilot
|
||||
footerLinkPrivacy = Súkromie
|
||||
footerLinkTerms = Podmienky používania
|
||||
footerLinkCookies = Cookies
|
||||
77
public/locales/sl/send.ftl
Normal file
77
public/locales/sl/send.ftl
Normal file
@@ -0,0 +1,77 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = poskus za splet
|
||||
siteFeedback = Povratne informacije
|
||||
uploadPageHeader = Zasebno, šifrirano deljenje datotek
|
||||
uploadPageLearnMore = Več o tem
|
||||
uploadPageBrowseButton = Izberite datoteko na računalniku
|
||||
.title = Izberite datoteko na računalniku
|
||||
uploadPageMultipleFilesAlert = Nalaganje več datotek ali map trenutno ni podprto.
|
||||
uploadPageBrowseButtonTitle = Prenesi datoteko
|
||||
importingFile = Uvažanje …
|
||||
verifyingFile = Preverjanje …
|
||||
encryptingFile = Šifriranje ...
|
||||
decryptingFile = Dešifriranje ...
|
||||
uploadingPageCancel = Prekliči prenos
|
||||
.title = Prekliči prenos
|
||||
uploadCancelNotification = Vaš prenos je preklican.
|
||||
uploadingFileNotification = Obvesti me, ko bo prenos končan.
|
||||
uploadSvgAlt
|
||||
.alt = Prenesi
|
||||
uploadSuccessTimingHeader = Povezava do vaše datoteke bo potekla po enem prenosu ali v 24 urah.
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Kopiraj v odložišče
|
||||
.title = Kopiraj v odložišče
|
||||
copiedUrl = Kopirano!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Izbriši datoteko
|
||||
.title = Izbriši datoteko
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Pošlji drugo datoteko
|
||||
.title = Pošlji drugo datoteko
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Prenesi
|
||||
downloadFileName = Prenesi { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Prenesi
|
||||
.title = Prenesi
|
||||
downloadFinish = Prenos končan
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Preskusite Firefox Send
|
||||
.title = Preskusite Firefox Send
|
||||
downloadingPageProgress = Prenašanje { $filename } ({ $size })
|
||||
errorAltText
|
||||
.alt = Napaka pri prenosu
|
||||
errorPageHeader = Prišlo je do težave!
|
||||
errorPageLink = Pošlji drugo datoteko
|
||||
fileTooBig = Ta datoteka je prevelika za prenos. Morala bi biti manjša od { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Povezava je potekla
|
||||
notSupportedHeader = Vaš brskalnik ni podprt.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Ta brskalnik na žalost ne podpira tehnologije, ki poganja Firefox Send. Uporabiti boste morali drug brskalnik. Priporočamo Firefox!
|
||||
downloadFirefoxButtonSub = Brezplačen prenos
|
||||
uploadedFile = Datoteka
|
||||
copyFileList = Kopiraj URL
|
||||
deleteFileList = Izbriši
|
||||
nevermindButton = Pozabi
|
||||
deleteButtonHover
|
||||
.title = Izbriši
|
||||
copyUrlHover
|
||||
.title = Kopiraj URL
|
||||
legalHeader = Pogoji in zasebnost
|
||||
deletePopupText = Izbrišem to datoteko?
|
||||
deletePopupYes = Da
|
||||
deletePopupCancel = Prekliči
|
||||
deleteButtonHover
|
||||
.title = Izbriši
|
||||
copyUrlHover
|
||||
.title = Kopiraj URL
|
||||
footerLinkLegal = Pravno obvestilo
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = O Test Pilotu
|
||||
footerLinkPrivacy = Zasebnost
|
||||
footerLinkTerms = Pogoji
|
||||
footerLinkCookies = Piškotki
|
||||
96
public/locales/sv-SE/send.ftl
Normal file
96
public/locales/sv-SE/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = webbexperiment
|
||||
siteFeedback = Återkoppling
|
||||
uploadPageHeader = Privat, krypterad fildelning
|
||||
uploadPageExplainer = Skicka filer via en säker, privat och krypterad länk som automatiskt upphör för att säkerställa att dina saker inte förblir på nätet för alltid.
|
||||
uploadPageLearnMore = Läs mer
|
||||
uploadPageDropMessage = Släpp filen här för att börja ladda upp
|
||||
uploadPageSizeMessage = För den mest tillförlitliga driften är det bäst att hålla din fil under 1 GB
|
||||
uploadPageBrowseButton = Välj en fil på din dator
|
||||
.title = Välj en fil på din dator
|
||||
uploadPageMultipleFilesAlert = Överföring av flera filer eller en mapp stöds för närvarande inte.
|
||||
uploadPageBrowseButtonTitle = Ladda upp fil
|
||||
uploadingPageHeader = Överför din fil
|
||||
importingFile = Importerar…
|
||||
verifyingFile = Verifierar…
|
||||
encryptingFile = Krypterar…
|
||||
decryptingFile = Avkodar…
|
||||
notifyUploadDone = Din uppladdning har slutförts.
|
||||
uploadingPageMessage = När din filuppladdning är klar kommer du att kunna ange alternativ för upphörande.
|
||||
uploadingPageCancel = Avbryt uppladdning
|
||||
.title = Avbryt uppladdning
|
||||
uploadCancelNotification = Din uppladdning avbröts.
|
||||
uploadingPageLargeFileMessage = Den här filen är stor och kan ta ett tag att ladda upp. Ha tålamod!
|
||||
uploadingFileNotification = Meddela mig när uppladdningen är klar.
|
||||
uploadSuccessConfirmHeader = Klar för att skicka
|
||||
uploadSvgAlt
|
||||
.alt = Ladda upp
|
||||
uploadSuccessTimingHeader = Länken till din fil upphör att gälla efter 1 nedladdning eller om 24 timmar.
|
||||
copyUrlFormLabelWithName = Kopiera och dela länken för att skicka din fil: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Kopiera till urklipp
|
||||
.title = Kopiera till urklipp
|
||||
copiedUrl = Kopierad!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Ta bort fil
|
||||
.title = Ta bort fil
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Skicka en annan fil
|
||||
.title = Skicka en annan fil
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Ladda ner
|
||||
downloadFileName = Ladda ner { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Din vän skickar dig en fil med Firefox Send, en tjänst som låter dig dela filer med en säker, privat och krypterad länk som automatiskt upphör för att säkerställa att dina saker inte förblir på nätet för alltid.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Ladda ner
|
||||
.title = Ladda ner
|
||||
downloadNotification = Din nedladdning har slutförts.
|
||||
downloadFinish = Nedladdning klar
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Testa Firefox Send
|
||||
.title = Testa Firefox Send
|
||||
downloadingPageProgress = Laddar ner { $filename } ({ $size })
|
||||
downloadingPageMessage = Lämna den här fliken öppen medan vi laddar ner din fil och dekrypterar den.
|
||||
errorAltText
|
||||
.alt = Uppladdningsfel
|
||||
errorPageHeader = Något gick fel!
|
||||
errorPageMessage = Det har uppstått ett fel vid uppladdning av filen.
|
||||
errorPageLink = Skicka en annan fil
|
||||
fileTooBig = Den filen är för stor för att ladda upp. Det ska vara mindre än { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Länk upphörd
|
||||
expiredPageHeader = Den här länken har upphört eller har aldrig existerat i första hand!
|
||||
notSupportedHeader = Din webbläsare stöds inte.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Tyvärr stöder inte webbläsaren den webbteknologi som används av Firefox Send. Du måste försöka med en annan webbläsare. Vi rekommenderar Firefox!
|
||||
downloadFirefoxButtonSub = Gratis nedladdning
|
||||
uploadedFile = Fil
|
||||
copyFileList = Kopiera URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Upphör
|
||||
deleteFileList = Ta bort
|
||||
nevermindButton = Glöm det
|
||||
deleteButtonHover
|
||||
.title = Ta bort
|
||||
copyUrlHover
|
||||
.title = Kopiera URL
|
||||
legalHeader = Villkor och sekretess
|
||||
legalNoticeTestPilot = Firefox Send är för närvarande ett Test Pilot experiment och omfattas av Test Pilots <a>användarvillkor</a> och <a>sekretesspolicy</a>. Du kan läsa dig mer om detta experiment och dess datainsamling <a>här</a>.
|
||||
legalNoticeMozilla = Användning av webbplatsen för Firefox Send är också föremål för Mozillas <a>sekretesspolicy för webbplatser</a> och <a>användarvillkor för webbplatser</a>.
|
||||
deletePopupText = Ta bort den här filen?
|
||||
deletePopupYes = Ja
|
||||
deletePopupCancel = Avbryt
|
||||
deleteButtonHover
|
||||
.title = Ta bort
|
||||
copyUrlHover
|
||||
.title = Kopiera URL
|
||||
footerLinkLegal = Juridisk information
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Om Test Pilot
|
||||
footerLinkPrivacy = Sekretess
|
||||
footerLinkTerms = Villkor
|
||||
footerLinkCookies = Kakor
|
||||
96
public/locales/zh-CN/send.ftl
Normal file
96
public/locales/zh-CN/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = Web 实验
|
||||
siteFeedback = 反馈
|
||||
uploadPageHeader = 私密、安全的文件分享
|
||||
uploadPageExplainer = 通过一个安全、私密且已加密的链接发送文件,文件将在有效期后自动清除。
|
||||
uploadPageLearnMore = 详细了解
|
||||
uploadPageDropMessage = 拖放您的文件到此处以开始上传
|
||||
uploadPageSizeMessage = 为保证运行稳定,建议文件大小不超过 1GB
|
||||
uploadPageBrowseButton = 选择一个在您的计算机上的文件
|
||||
.title = 选择一个在您的计算机上的文件
|
||||
uploadPageMultipleFilesAlert = 目前不支持上传多个文件或上传文件夹。
|
||||
uploadPageBrowseButtonTitle = 上传文件
|
||||
uploadingPageHeader = 正在上传您的文件
|
||||
importingFile = 正在导入…
|
||||
verifyingFile = 正在验证…
|
||||
encryptingFile = 正在加密…
|
||||
decryptingFile = 正在解密…
|
||||
notifyUploadDone = 您的上传已完成。
|
||||
uploadingPageMessage = 在文件上传后,您可以设定过期选项。
|
||||
uploadingPageCancel = 取消上传
|
||||
.title = 取消上传
|
||||
uploadCancelNotification = 您的上传已取消。
|
||||
uploadingPageLargeFileMessage = 此文件较大,可能要花费一些时间。请稍候。
|
||||
uploadingFileNotification = 上传完成后通知我。
|
||||
uploadSuccessConfirmHeader = 准备好发送
|
||||
uploadSvgAlt
|
||||
.alt = 上传
|
||||
uploadSuccessTimingHeader = 您的文件的链接将在第一次下载的 24 小时后过期。
|
||||
copyUrlFormLabelWithName = 复制并分享链接以发送您的文件:{ $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = 复制到剪贴板
|
||||
.title = 复制到剪贴板
|
||||
copiedUrl = 已复制!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = 删除文件
|
||||
.title = 删除文件
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = 发送其他文件
|
||||
.title = 发送其他文件
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = 下载
|
||||
downloadFileName = 下载 { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = 您的朋友使用 Firefox Send 向您发送一个文件。该服务允许用户安全、私密、加密的以链接分享一个文件,链接将会自动过期失效。
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = 下载
|
||||
.title = 下载
|
||||
downloadNotification = 您的下载已完成。
|
||||
downloadFinish = 下载完成
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = 尝试 Firefox Send
|
||||
.title = 尝试 Firefox Send
|
||||
downloadingPageProgress = 正在下载 { $filename } ({ $size })
|
||||
downloadingPageMessage = 在我们获取您的文件并解密的期间,请不要关闭此网页。
|
||||
errorAltText
|
||||
.alt = 上传出错
|
||||
errorPageHeader = 我们遇到错误。
|
||||
errorPageMessage = 上传文件时发生错误。
|
||||
errorPageLink = 发送其他文件
|
||||
fileTooBig = 此文件太大,它应该小于 { $size }。
|
||||
linkExpiredAlt
|
||||
.alt = 链接已过期
|
||||
expiredPageHeader = 此链接已过期或者从未生效。
|
||||
notSupportedHeader = 不支持您的浏览器。
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = 很遗憾,您的浏览器不支持 Firefox Send 所使用的技术。您需要尝试其他浏览器。我们推荐使用 Firefox。
|
||||
downloadFirefoxButtonSub = 免费下载
|
||||
uploadedFile = 文件
|
||||
copyFileList = 复制网址
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = 过期时间
|
||||
deleteFileList = 删除
|
||||
nevermindButton = 没关系
|
||||
deleteButtonHover
|
||||
.title = 删除
|
||||
copyUrlHover
|
||||
.title = 复制网址
|
||||
legalHeader = 条款和隐私
|
||||
legalNoticeTestPilot = Firefox Send 目前是一个 Test Pilot 实验,并遵守 Test Pilot <a>服务条款</a>和<a>隐私声明</a>。您可以在<a>这里</a>了解此实验及数据收集的有关信息。
|
||||
legalNoticeMozilla = 使用 Firefox Send 网站亦受到 Mozilla <a>网站隐私声明</a>和<a>网站使用条款</a>的约束。
|
||||
deletePopupText = 删除此文件?
|
||||
deletePopupYes = 是
|
||||
deletePopupCancel = 取消
|
||||
deleteButtonHover
|
||||
.title = 删除
|
||||
copyUrlHover
|
||||
.title = 复制网址
|
||||
footerLinkLegal = 法律
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = 关于 Test Pilot
|
||||
footerLinkPrivacy = 隐私
|
||||
footerLinkTerms = 条款
|
||||
footerLinkCookies = Cookie
|
||||
96
public/locales/zh-TW/send.ftl
Normal file
96
public/locales/zh-TW/send.ftl
Normal file
@@ -0,0 +1,96 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = 網頁實驗
|
||||
siteFeedback = 意見回饋
|
||||
uploadPageHeader = 私密、有加密的檔案分享服務
|
||||
uploadPageExplainer = 透過安全、隱私、加密過的管道來傳送檔案,而且鏈結會自動過期,可確保您的東西不會在網路上無限停留。
|
||||
uploadPageLearnMore = 了解更多
|
||||
uploadPageDropMessage = 將檔案放到此處開始上傳
|
||||
uploadPageSizeMessage = 為了讓系統能最穩定地執行,請盡量將檔案控制在 1GB 以下。
|
||||
uploadPageBrowseButton = 選擇您電腦上的檔案
|
||||
.title = 選擇您電腦上的檔案
|
||||
uploadPageMultipleFilesAlert = 目前暫不支援上傳多個檔案或資料夾。
|
||||
uploadPageBrowseButtonTitle = 上傳檔案
|
||||
uploadingPageHeader = 正在上傳檔案
|
||||
importingFile = 匯入中…
|
||||
verifyingFile = 驗證中…
|
||||
encryptingFile = 加密中…
|
||||
decryptingFile = 解密中…
|
||||
notifyUploadDone = 已完成上傳。
|
||||
uploadingPageMessage = 檔案上傳後,即可設定過期時間。
|
||||
uploadingPageCancel = 取消上傳
|
||||
.title = 取消上傳
|
||||
uploadCancelNotification = 已取消上傳。
|
||||
uploadingPageLargeFileMessage = 這個檔案有點大,可能需要花點時間上傳,再等會兒!
|
||||
uploadingFileNotification = 上傳完成時通知我。
|
||||
uploadSuccessConfirmHeader = 準備好傳送
|
||||
uploadSvgAlt
|
||||
.alt = 上傳
|
||||
uploadSuccessTimingHeader = 您的檔案鏈結將會在首次下載,或 24 小時後失效。
|
||||
copyUrlFormLabelWithName = 複製並分享鏈結來傳送您的檔案: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = 複製到剪貼簿
|
||||
.title = 複製到剪貼簿
|
||||
copiedUrl = 已複製!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = 刪除檔案
|
||||
.title = 刪除檔案
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = 傳送另一個檔案
|
||||
.title = 傳送另一個檔案
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = 下載
|
||||
downloadFileName = 下載 { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = 您的朋友正透過 Firefox Send 傳送檔案給您。這是一個可讓您透過安全、隱密、並且會將鏈結加密過,自動失效以確保檔案不會在網路上無限停留的檔案分享服務。
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = 下載
|
||||
.title = 下載
|
||||
downloadNotification = 下載完成。
|
||||
downloadFinish = 下載完成
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = 試用 Firefox Send
|
||||
.title = 試用 Firefox Send
|
||||
downloadingPageProgress = 正在下載 { $filename }({ $size })
|
||||
downloadingPageMessage = 請保留此分頁開啟,我們將取回這個檔案並進行解密。
|
||||
errorAltText
|
||||
.alt = 上傳錯誤
|
||||
errorPageHeader = 有些東西不對勁!
|
||||
errorPageMessage = 上傳檔案時發生錯誤。
|
||||
errorPageLink = 傳送另一個檔案
|
||||
fileTooBig = 檔案太大無法上傳。檔案大小限制為 { $size }。
|
||||
linkExpiredAlt
|
||||
.alt = 鏈結已過期
|
||||
expiredPageHeader = 鏈結已失效,或根本不存在!
|
||||
notSupportedHeader = 不支援您的瀏覽器。
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = 很可惜,您使用的瀏覽器並不支援 Firefox Send 所需的 Web 技術。請改用其他瀏覽器,我們推薦使用 Firefox!
|
||||
downloadFirefoxButtonSub = 免費下載
|
||||
uploadedFile = 檔案
|
||||
copyFileList = 複製網址
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = 失效於
|
||||
deleteFileList = 刪除
|
||||
nevermindButton = 沒關係
|
||||
deleteButtonHover
|
||||
.title = 刪除
|
||||
copyUrlHover
|
||||
.title = 複製網址
|
||||
legalHeader = 使用條款及隱私權
|
||||
legalNoticeTestPilot = Firefox Send 目前是一個 Test Pilot 實驗,依照 Test Pilot 的<a>服務條款</a>及<a>隱私權公告</a>提供服務。您可以在<a>此處</a>了解實驗內容,以及所收集資料的詳細資訊。
|
||||
legalNoticeMozilla = 使用 Firefox Send 網站時,亦受到 Mozilla 的<a>網站隱私權公告</a>以及<a>網站使用條款</a>約束。
|
||||
deletePopupText = 真的要刪除這個檔案嗎?
|
||||
deletePopupYes = 好的,刪除
|
||||
deletePopupCancel = 不要刪除
|
||||
deleteButtonHover
|
||||
.title = 刪除
|
||||
copyUrlHover
|
||||
.title = 複製網址
|
||||
footerLinkLegal = 法律資訊
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = 關於 Test Pilot
|
||||
footerLinkPrivacy = 隱私權
|
||||
footerLinkTerms = 使用條款
|
||||
footerLinkCookies = Cookie
|
||||
392
public/main.css
392
public/main.css
@@ -1,33 +1,128 @@
|
||||
/*** index.html ***/
|
||||
html {
|
||||
background: url('resources/send_bg.svg');
|
||||
font-family: 'SF Pro Text', sans-serif;
|
||||
font-family: -apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'SF Pro Text',
|
||||
Helvetica,
|
||||
Arial,
|
||||
sans-serif;
|
||||
font-weight: 200;
|
||||
background-size: 100%;
|
||||
background-size: 110%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center top;
|
||||
height: 100%;
|
||||
max-width: 1440px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header {
|
||||
align-items: flex-start;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 31px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.send-logo {
|
||||
display: flex;
|
||||
position: relative;
|
||||
top: 31px;
|
||||
left: 31px;
|
||||
display: inline-block;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.send-logo > a {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
color: #3e3d40;
|
||||
font-size: 32px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
letter-spacing: 1px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.site-subtitle {
|
||||
color: #3e3d40;
|
||||
font-size: 12px;
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
.site-subtitle a {
|
||||
font-weight: bold;
|
||||
color: #3e3d40;
|
||||
transition: color 50ms;
|
||||
}
|
||||
|
||||
.send-logo:hover a {
|
||||
color: #0297f8;
|
||||
}
|
||||
|
||||
.feedback {
|
||||
background-color: #0297f8;
|
||||
background-image: url('resources/feedback.svg');
|
||||
background-position: 2px 4px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 18px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #0297f8;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
line-height: 12px;
|
||||
opacity: 0.9;
|
||||
padding: 5px;
|
||||
overflow: hidden;
|
||||
width: 12px;
|
||||
text-indent: 17px;
|
||||
transition: all 150ms ease-in-out;
|
||||
}
|
||||
|
||||
.feedback:hover,
|
||||
.feedback:focus {
|
||||
width: 57px;
|
||||
text-indent: 2px;
|
||||
padding: 5px 5px 5px 20px;
|
||||
background-color: #0287e8;
|
||||
transition: all 150ms ease-in-out;
|
||||
}
|
||||
|
||||
.feedback:active {
|
||||
background-color: #0277d8;
|
||||
}
|
||||
|
||||
.all {
|
||||
padding-top: 10%;
|
||||
padding-bottom: 51px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
max-width: 630px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
input, select, textarea, button {
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
button {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
@@ -36,26 +131,29 @@ a {
|
||||
}
|
||||
|
||||
/** page-one **/
|
||||
|
||||
.title {
|
||||
font-size: 33px;
|
||||
line-height: 40px;
|
||||
margin: 20px auto;
|
||||
text-align: center;
|
||||
max-width: 520px;
|
||||
font-family: 'SF Pro Display', sans-serif;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 15px;
|
||||
line-height: 23px;
|
||||
width: 630px;
|
||||
max-width: 630px;
|
||||
text-align: center;
|
||||
margin: 0 auto 60px;
|
||||
color: #0C0C0D;
|
||||
color: #0c0c0d;
|
||||
width: 92%;
|
||||
}
|
||||
|
||||
.upload-window {
|
||||
border: 1px dashed rgba(0, 148, 251, 0.5);
|
||||
margin: 0 auto;
|
||||
width: 640px;
|
||||
height: 255px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
@@ -63,14 +161,15 @@ a {
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
transition: transform 150ms;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.upload-window.ondrag {
|
||||
border: 3px dashed rgba(0, 148, 251, 0.5);
|
||||
margin: 0 auto;
|
||||
width: 636px;
|
||||
height: 251px;
|
||||
transform: scale(1.05);
|
||||
transform: scale(1.04);
|
||||
border-radius: 4.2px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -80,10 +179,14 @@ a {
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0094FB;
|
||||
color: #0094fb;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link:hover {
|
||||
color: #0287e8;
|
||||
}
|
||||
|
||||
#upload-text {
|
||||
font-size: 22px;
|
||||
color: #737373;
|
||||
@@ -92,10 +195,10 @@ a {
|
||||
}
|
||||
|
||||
#browse {
|
||||
background: #0297F8;
|
||||
background: #0297f8;
|
||||
border-radius: 5px;
|
||||
font-size: 15px;
|
||||
color: #FFF;
|
||||
color: #fff;
|
||||
width: 240px;
|
||||
height: 44px;
|
||||
display: flex;
|
||||
@@ -104,12 +207,17 @@ a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#browse:hover {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
input[type="file"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#file-size-msg {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: #737373;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
@@ -129,9 +237,10 @@ th {
|
||||
td {
|
||||
font-size: 15px;
|
||||
vertical-align: top;
|
||||
color: #4A4A4A;
|
||||
color: #4a4a4a;
|
||||
padding: 17px 19px 0;
|
||||
line-height: 23px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
table {
|
||||
@@ -141,42 +250,44 @@ table {
|
||||
|
||||
tbody {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
#uploaded-files {
|
||||
width: 640px;
|
||||
margin: 45.3px auto;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.icon-delete, .icon-copy, .icon-check {
|
||||
.icon-delete,
|
||||
.icon-copy,
|
||||
.icon-check {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Popup container */
|
||||
.popup {
|
||||
position: relative;
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* The actual popup (appears on top) */
|
||||
.popup .popuptext {
|
||||
visibility: hidden;
|
||||
width: 160px;
|
||||
background-color: #555;
|
||||
color: #FFF;
|
||||
min-width: 115px;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #0297f8;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 8px 0;
|
||||
border-radius: 5px;
|
||||
padding: 7px 8px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
margin-left: -88px;
|
||||
bottom: 8px;
|
||||
right: -28px;
|
||||
transition: opacity 0.5s;
|
||||
opacity: 0;
|
||||
outline: 0;
|
||||
box-shadow: 3px 3px 7px #888;
|
||||
}
|
||||
|
||||
/* Popup arrow */
|
||||
@@ -184,11 +295,11 @@ tbody {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
right: 30px;
|
||||
margin-left: -5px;
|
||||
border-width: 5px;
|
||||
border-style: solid;
|
||||
border-color: #555 transparent transparent;
|
||||
border-color: #0297f8 transparent transparent;
|
||||
}
|
||||
|
||||
.popup .show {
|
||||
@@ -196,6 +307,29 @@ tbody {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.popup-message {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.popup-yes {
|
||||
color: #fff;
|
||||
background-color: #0297f8;
|
||||
border-radius: 5px;
|
||||
padding: 2px 11px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.popup-yes:hover {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
.popup-no {
|
||||
color: #4a4a4a;
|
||||
border-radius: 6px;
|
||||
padding: 3px 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/** upload-progress **/
|
||||
.progress-bar {
|
||||
margin-top: 3px;
|
||||
@@ -239,14 +373,13 @@ tbody {
|
||||
}
|
||||
|
||||
#cancel-upload {
|
||||
color: #D70022;
|
||||
color: #d70022;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/** share-link **/
|
||||
#share-window {
|
||||
width: 645px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -262,53 +395,64 @@ tbody {
|
||||
#copy {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
width: 640px;
|
||||
}
|
||||
|
||||
#copy-text {
|
||||
align-self: flex-start;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 10px;
|
||||
color: #0C0C0D;
|
||||
color: #0c0c0d;
|
||||
}
|
||||
|
||||
#link {
|
||||
width: 480px;
|
||||
flex: 1;
|
||||
height: 56px;
|
||||
border: 1px solid #0297F8;
|
||||
border: 1px solid #0297f8;
|
||||
border-radius: 6px 0 0 6px;
|
||||
font-size: 24px;
|
||||
color: #737373;
|
||||
font-family: 'SF Pro Display', sans-serif;
|
||||
letter-spacing: 0;
|
||||
line-height: 23px;
|
||||
font-weight: 300;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#link:disabled {
|
||||
border: 1px solid #05A700;
|
||||
background: #FFF;
|
||||
border: 1px solid #05a700;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#copy-btn {
|
||||
width: 165px;
|
||||
height: 60px;
|
||||
background: #0297F8;
|
||||
border: 1px solid #0297F8;
|
||||
flex: 0 1 165px;
|
||||
background: #0297f8;
|
||||
border-radius: 0 6px 6px 0;
|
||||
border: 1px solid #0297f8;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
height: 60px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#copy-btn:hover {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
#copy-btn:disabled {
|
||||
background: #05A700;
|
||||
border: 1px solid #05A700;
|
||||
background: #05a700;
|
||||
border: 1px solid #05a700;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
#delete-file {
|
||||
width: 176px;
|
||||
height: 44px;
|
||||
background: #FFF;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(12, 12, 13, 0.3);
|
||||
border-radius: 5px;
|
||||
font-size: 15px;
|
||||
@@ -318,15 +462,25 @@ tbody {
|
||||
color: #313131;
|
||||
}
|
||||
|
||||
#delete-file:hover {
|
||||
background: #efeff1;
|
||||
}
|
||||
|
||||
.send-new {
|
||||
font-size: 15px;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
color: #0094FB;
|
||||
color: #0094fb;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.send-new:hover,
|
||||
.send-new:focus,
|
||||
.send-new:active {
|
||||
color: #0287e8;
|
||||
}
|
||||
|
||||
/* upload-error */
|
||||
#upload-error {
|
||||
display: flex;
|
||||
@@ -336,13 +490,13 @@ tbody {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#upload-error[hidden], #unsupported-browser[hidden] {
|
||||
#upload-error[hidden],
|
||||
#unsupported-browser[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#upload-error-img {
|
||||
margin-bottom: 90px;
|
||||
margin-top: 5px;
|
||||
margin: 51px 0 71px;
|
||||
}
|
||||
|
||||
/* unsupported-browser */
|
||||
@@ -356,9 +510,8 @@ tbody {
|
||||
.unsupported-description {
|
||||
font-size: 13px;
|
||||
line-height: 23px;
|
||||
width: 630px;
|
||||
text-align: center;
|
||||
color: #7D7D7D;
|
||||
color: #7d7d7d;
|
||||
margin: 0 auto 23px;
|
||||
}
|
||||
|
||||
@@ -370,14 +523,14 @@ tbody {
|
||||
margin-bottom: 181px;
|
||||
width: 260px;
|
||||
height: 80px;
|
||||
background: #12BC00;
|
||||
background: #12bc00;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
border: 0;
|
||||
box-shadow: 0 5px 3px rgb(234, 234, 234);
|
||||
font-family: 'Fira Sans';
|
||||
font-weight: 500;
|
||||
color: #FFF;
|
||||
color: #fff;
|
||||
font-size: 26px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -406,15 +559,19 @@ tbody {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
background: #0297F8;
|
||||
border: 1px solid #0297F8;
|
||||
background: #0297f8;
|
||||
border: 1px solid #0297f8;
|
||||
border-radius: 5px;
|
||||
font-weight: 300;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#download-btn:hover {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
#download-btn:disabled {
|
||||
background: #47B04B;
|
||||
background: #47b04b;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
@@ -434,9 +591,8 @@ tbody {
|
||||
.expired-description {
|
||||
font-size: 15px;
|
||||
line-height: 23px;
|
||||
width: 630px;
|
||||
text-align: center;
|
||||
color: #7D7D7D;
|
||||
color: #7d7d7d;
|
||||
margin: 0 auto 23px;
|
||||
}
|
||||
|
||||
@@ -460,14 +616,17 @@ tbody {
|
||||
|
||||
/* footer */
|
||||
.footer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
padding: 10px;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 50px 31px 41px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.mozilla-logo {
|
||||
@@ -476,9 +635,22 @@ tbody {
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.legal-links {
|
||||
max-width: 600px;
|
||||
width: 80vw;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.legal-links > a {
|
||||
margin-right: 30px;
|
||||
color: #858585;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.legal-links > a:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.legal-links > a:visited {
|
||||
@@ -487,16 +659,102 @@ tbody {
|
||||
|
||||
.social-links {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
justify-content: space-between;
|
||||
width: 94px;
|
||||
}
|
||||
|
||||
.social-links > a {
|
||||
margin-left: 30px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.github, .twitter {
|
||||
.social-links > a:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.github,
|
||||
.twitter {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
@media (max-device-width: 768px), (max-width: 768px) {
|
||||
.description {
|
||||
margin: 0 auto 25px;
|
||||
}
|
||||
|
||||
#copy {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#link {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
max-width: 630px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.mozilla-logo {
|
||||
margin-left: -7px;
|
||||
}
|
||||
|
||||
.legal-links {
|
||||
flex-direction: column;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.legal-links > * {
|
||||
display: block;
|
||||
padding: 10px 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
margin-top: 20px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-device-width: 520px), (max-width: 520px) {
|
||||
.header {
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.feedback {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
#copy {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#link {
|
||||
font-size: 22px;
|
||||
padding: 15px 10px;
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
#copy-btn {
|
||||
border-radius: 0 0 6px 6px;
|
||||
flex: 0 1 65px;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: 14px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 13px;
|
||||
padding: 17px 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/resources/favicon-32x32.png
Executable file
BIN
public/resources/favicon-32x32.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
1
public/resources/feedback.svg
Normal file
1
public/resources/feedback.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="15" height="13" viewBox="0 0 15 13" xmlns="http://www.w3.org/2000/svg"><title>Combined Shape</title><path d="M10.274 9.193a5.957 5.957 0 0 1-2.98.778C4.37 9.97 2 7.963 2 5.485 2 3.008 4.37 1 7.294 1c2.924 0 5.294 2.008 5.294 4.485 0 .843-.274 1.632-.751 2.305l.577 2.21-2.14-.807zm-5.983-2.96a.756.756 0 0 0 .763-.748.756.756 0 0 0-.763-.747.756.756 0 0 0-.764.747c0 .413.342.748.764.748zm3.054 0a.756.756 0 0 0 .764-.748.756.756 0 0 0-.764-.747.756.756 0 0 0-.764.747c0 .413.342.748.764.748zm3.054 0a.756.756 0 0 0 .764-.748.756.756 0 0 0-.764-.747.756.756 0 0 0-.763.747c0 .413.342.748.763.748z" fill="#FFF" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 649 B |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.4 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 14 KiB |
@@ -14,7 +14,7 @@ const filename = path.join(__dirname, '..', 'public', 'version.json');
|
||||
const filedata = {
|
||||
commit,
|
||||
source: pkg.homepage,
|
||||
version: pkg.version
|
||||
version: process.env.CIRCLE_TAG || pkg.version
|
||||
};
|
||||
|
||||
fs.writeFileSync(filename, JSON.stringify(filedata, null, 2) + '\n');
|
||||
|
||||
@@ -4,12 +4,12 @@ const conf = convict({
|
||||
s3_bucket: {
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'P2P_S3_BUCKET'
|
||||
env: 'S3_BUCKET'
|
||||
},
|
||||
redis_host: {
|
||||
format: String,
|
||||
default: 'localhost',
|
||||
env: 'P2P_REDIS_HOST'
|
||||
env: 'REDIS_HOST'
|
||||
},
|
||||
listen_port: {
|
||||
format: 'port',
|
||||
@@ -25,12 +25,12 @@ const conf = convict({
|
||||
sentry_id: {
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'P2P_SENTRY_CLIENT'
|
||||
env: 'SENTRY_CLIENT'
|
||||
},
|
||||
sentry_dsn: {
|
||||
format: String,
|
||||
default: '',
|
||||
env: 'P2P_SENTRY_DSN'
|
||||
env: 'SENTRY_DSN'
|
||||
},
|
||||
env: {
|
||||
format: ['production', 'development', 'test'],
|
||||
@@ -39,8 +39,18 @@ const conf = convict({
|
||||
},
|
||||
max_file_size: {
|
||||
format: Number,
|
||||
default: (1024 * 1024 * 1024) * 2,
|
||||
env: 'P2P_MAX_FILE_SIZE'
|
||||
default: 1024 * 1024 * 1024 * 2,
|
||||
env: 'MAX_FILE_SIZE'
|
||||
},
|
||||
expire_seconds: {
|
||||
format: Number,
|
||||
default: 86400,
|
||||
env: 'EXPIRE_SECONDS'
|
||||
},
|
||||
l10n_dev: {
|
||||
format: Boolean,
|
||||
default: false,
|
||||
env: 'L10N_DEV'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
135
server/server.js
135
server/server.js
@@ -9,6 +9,7 @@ const conf = require('./config.js');
|
||||
const storage = require('./storage.js');
|
||||
const Raven = require('raven');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
|
||||
if (conf.sentry_dsn) {
|
||||
Raven.config(conf.sentry_dsn).install();
|
||||
@@ -19,25 +20,48 @@ const mozlog = require('./log.js');
|
||||
const log = mozlog('send.server');
|
||||
|
||||
const STATIC_PATH = path.join(__dirname, '../public');
|
||||
const L20N = path.join(__dirname, '../node_modules/l20n');
|
||||
const LOCALES = path.join(__dirname, '../public/locales');
|
||||
|
||||
const app = express();
|
||||
|
||||
function allLangs() {
|
||||
return fs
|
||||
.readdirSync(path.join(STATIC_PATH, 'locales'))
|
||||
.map(function(f) {
|
||||
return f.split('.')[0];
|
||||
})
|
||||
.join(',');
|
||||
}
|
||||
|
||||
function prodLangs() {
|
||||
return require(path.join(
|
||||
__dirname,
|
||||
'..',
|
||||
'package.json'
|
||||
)).availableLanguages.join(',');
|
||||
}
|
||||
|
||||
const availableLanguages = conf.l10n_dev ? allLangs() : prodLangs();
|
||||
|
||||
app.engine(
|
||||
'handlebars',
|
||||
exphbs({
|
||||
defaultLayout: 'main',
|
||||
partialsDir: 'views/partials/'
|
||||
partialsDir: 'views/partials/',
|
||||
helpers: {
|
||||
availableLanguages,
|
||||
l10nDev: conf.l10n_dev
|
||||
}
|
||||
})
|
||||
);
|
||||
app.set('view engine', 'handlebars');
|
||||
|
||||
app.use(helmet());
|
||||
app.use(helmet.hsts({
|
||||
maxAge: 31536000,
|
||||
force: conf.env === 'production'
|
||||
}));
|
||||
app.use(
|
||||
helmet.hsts({
|
||||
maxAge: 31536000,
|
||||
force: conf.env === 'production'
|
||||
})
|
||||
);
|
||||
app.use(
|
||||
helmet.contentSecurityPolicy({
|
||||
directives: {
|
||||
@@ -45,43 +69,48 @@ app.use(
|
||||
connectSrc: [
|
||||
"'self'",
|
||||
'https://sentry.prod.mozaws.net',
|
||||
'https://www.google-analytics.com',
|
||||
'https://ssl.google-analytics.com'
|
||||
'https://www.google-analytics.com'
|
||||
],
|
||||
imgSrc: [
|
||||
"'self'",
|
||||
'https://www.google-analytics.com',
|
||||
'https://ssl.google-analytics.com'
|
||||
],
|
||||
scriptSrc: ["'self'", 'https://ssl.google-analytics.com'],
|
||||
imgSrc: ["'self'", 'https://www.google-analytics.com'],
|
||||
scriptSrc: ["'self'"],
|
||||
styleSrc: ["'self'", 'https://code.cdn.mozilla.net'],
|
||||
fontSrc: ["'self'", 'https://code.cdn.mozilla.net'],
|
||||
formAction: ["'none'"],
|
||||
frameAncestors: ["'none'"],
|
||||
objectSrc: ["'none'"]
|
||||
objectSrc: ["'none'"],
|
||||
reportUri: '/__cspreport__'
|
||||
}
|
||||
})
|
||||
);
|
||||
app.use(
|
||||
busboy({
|
||||
limits: {
|
||||
fileSize: conf.max_file_size
|
||||
}
|
||||
})
|
||||
);
|
||||
app.use(busboy({
|
||||
limits: {
|
||||
fileSize: conf.max_file_size
|
||||
}
|
||||
}));
|
||||
app.use(bodyParser.json());
|
||||
app.use(express.static(STATIC_PATH));
|
||||
app.use('/l20n', express.static(L20N));
|
||||
app.use('/locales', express.static(LOCALES));
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
res.render('index');
|
||||
});
|
||||
|
||||
app.get('/unsupported', (req, res) => {
|
||||
res.render('unsupported');
|
||||
});
|
||||
|
||||
app.get('/legal', (req, res) => {
|
||||
res.render('legal');
|
||||
});
|
||||
|
||||
app.get('/jsconfig.js', (req, res) => {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
res.render('jsconfig', {
|
||||
trackerId: conf.analytics_id,
|
||||
dsn: conf.sentry_id,
|
||||
maxFileSize: conf.max_file_size,
|
||||
expireSeconds: conf.expire_seconds,
|
||||
layout: false
|
||||
});
|
||||
});
|
||||
@@ -108,21 +137,23 @@ app.get('/download/:id', (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
storage.filename(id).then(filename => {
|
||||
storage
|
||||
.length(id)
|
||||
.then(contentLength => {
|
||||
res.render('download', {
|
||||
filename: decodeURIComponent(filename),
|
||||
filesize: bytes(contentLength),
|
||||
trackerId: conf.analytics_id,
|
||||
dsn: conf.sentry_id
|
||||
storage
|
||||
.filename(id)
|
||||
.then(filename => {
|
||||
return storage.length(id).then(contentLength => {
|
||||
storage.ttl(id).then(timeToExpiry => {
|
||||
res.render('download', {
|
||||
filename: decodeURIComponent(filename),
|
||||
filesize: bytes(contentLength),
|
||||
sizeInBytes: contentLength,
|
||||
timeToExpiry: timeToExpiry
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
res.render('download');
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
res.status(404).render('notfound');
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/assets/download/:id', (req, res) => {
|
||||
@@ -224,21 +255,23 @@ app.post('/upload', (req, res, next) => {
|
||||
req.busboy.on('file', (fieldname, file, filename) => {
|
||||
log.info('Uploading:', newId);
|
||||
|
||||
storage.set(newId, file, filename, meta).then(() => {
|
||||
const protocol = conf.env === 'production' ? 'https' : req.protocol;
|
||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
||||
res.json({
|
||||
url,
|
||||
delete: meta.delete,
|
||||
id: newId
|
||||
});
|
||||
},
|
||||
err => {
|
||||
if (err.message === 'limit') {
|
||||
return res.sendStatus(413);
|
||||
storage.set(newId, file, filename, meta).then(
|
||||
() => {
|
||||
const protocol = conf.env === 'production' ? 'https' : req.protocol;
|
||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
||||
res.json({
|
||||
url,
|
||||
delete: meta.delete,
|
||||
id: newId
|
||||
});
|
||||
},
|
||||
err => {
|
||||
if (err.message === 'limit') {
|
||||
return res.sendStatus(413);
|
||||
}
|
||||
res.sendStatus(500);
|
||||
}
|
||||
res.sendStatus(500);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
req.on('close', err => {
|
||||
@@ -252,7 +285,7 @@ app.post('/upload', (req, res, next) => {
|
||||
.catch(err => {
|
||||
log.info('DeleteError:', newId);
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/__lbheartbeat__', (req, res) => {
|
||||
|
||||
@@ -23,10 +23,10 @@ if (conf.s3_bucket) {
|
||||
module.exports = {
|
||||
filename: filename,
|
||||
exists: exists,
|
||||
ttl: ttl,
|
||||
length: awsLength,
|
||||
get: awsGet,
|
||||
set: awsSet,
|
||||
aad: aad,
|
||||
setField: setField,
|
||||
delete: awsDelete,
|
||||
forceDelete: awsForceDelete,
|
||||
@@ -39,10 +39,10 @@ if (conf.s3_bucket) {
|
||||
module.exports = {
|
||||
filename: filename,
|
||||
exists: exists,
|
||||
ttl: ttl,
|
||||
length: localLength,
|
||||
get: localGet,
|
||||
set: localSet,
|
||||
aad: aad,
|
||||
setField: setField,
|
||||
delete: localDelete,
|
||||
forceDelete: localForceDelete,
|
||||
@@ -64,11 +64,21 @@ function quit() {
|
||||
function metadata(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
redis_client.hgetall(id, (err, reply) => {
|
||||
if (!err) {
|
||||
resolve(reply);
|
||||
} else {
|
||||
reject(err);
|
||||
if (err || !reply) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(reply);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function ttl(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
redis_client.ttl(id, (err, reply) => {
|
||||
if (err || !reply) {
|
||||
return reject(err);
|
||||
}
|
||||
resolve(reply * 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -76,11 +86,10 @@ function metadata(id) {
|
||||
function filename(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
redis_client.hget(id, 'filename', (err, reply) => {
|
||||
if (!err) {
|
||||
resolve(reply);
|
||||
} else {
|
||||
reject(err);
|
||||
if (err || !reply) {
|
||||
return reject();
|
||||
}
|
||||
resolve(reply);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -101,18 +110,6 @@ function setField(id, key, value) {
|
||||
redis_client.hset(id, key, value);
|
||||
}
|
||||
|
||||
function aad(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
redis_client.hget(id, 'aad', (err, reply) => {
|
||||
if (!err) {
|
||||
resolve(reply);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function localLength(id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
@@ -138,7 +135,7 @@ function localSet(newId, file, filename, meta) {
|
||||
});
|
||||
fstream.on('finish', () => {
|
||||
redis_client.hmset(newId, meta);
|
||||
redis_client.expire(newId, 86400000);
|
||||
redis_client.expire(newId, conf.expire_seconds);
|
||||
log.info('localSet:', 'Upload Finished of ' + newId);
|
||||
resolve(meta.delete);
|
||||
});
|
||||
@@ -221,10 +218,10 @@ function awsSet(newId, file, filename, meta) {
|
||||
hitLimit = true;
|
||||
upload.abort();
|
||||
});
|
||||
return upload.promise()
|
||||
.then(() => {
|
||||
return upload.promise().then(
|
||||
() => {
|
||||
redis_client.hmset(newId, meta);
|
||||
redis_client.expire(newId, 86400000);
|
||||
redis_client.expire(newId, conf.expire_seconds);
|
||||
log.info('awsUploadFinish', 'Upload Finished of ' + filename);
|
||||
},
|
||||
err => {
|
||||
@@ -233,7 +230,8 @@ function awsSet(newId, file, filename, meta) {
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function awsDelete(id, delete_token) {
|
||||
|
||||
@@ -19,3 +19,5 @@ rules:
|
||||
mocha/no-pending-tests: error
|
||||
mocha/no-return-and-callback: warn
|
||||
mocha/no-skipped-tests: error
|
||||
|
||||
no-console: off # ¯\_(ツ)_/¯
|
||||
|
||||
@@ -7,8 +7,8 @@ const driver = new webdriver.Builder()
|
||||
.build();
|
||||
|
||||
driver.get(path.join('file:///', __dirname, '/frontend.test.html'));
|
||||
driver.wait(until.titleIs('Mocha Tests'), 10000);
|
||||
driver.wait(until.titleMatches(/^[0-1]$/), 10000);
|
||||
driver.wait(until.titleIs('Mocha Tests'));
|
||||
driver.wait(until.titleMatches(/^[0-1]$/));
|
||||
|
||||
driver.getTitle().then(title => {
|
||||
driver.quit().then(() => {
|
||||
|
||||
@@ -115,7 +115,7 @@ describe('Testing Set using aws', function() {
|
||||
.set('123', {on: sinon.stub()}, 'Filename.moz', {})
|
||||
.then(() => {
|
||||
assert(expire.calledOnce);
|
||||
assert(expire.calledWith('123', 86400000));
|
||||
assert(expire.calledWith('123', 86400));
|
||||
})
|
||||
.catch(err => assert.fail());
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div id="download">
|
||||
{{#if filename}}
|
||||
<script src="/download.js"></script>
|
||||
<div id="download-page-one">
|
||||
<div class="title">
|
||||
<span id="dl-filename"
|
||||
@@ -7,6 +7,8 @@
|
||||
data-l10n-args='{"filename": "{{filename}}"}'></span>
|
||||
<span data-l10n-id="downloadFileSize"
|
||||
data-l10n-args='{"size": "{{filesize}}"}'></span>
|
||||
<span id="dl-bytelength" hidden="true">{{sizeInBytes}}</span>
|
||||
<span id="dl-ttl" hidden="true">{{timeToExpiry}}</span>
|
||||
</div>
|
||||
<div class="description" data-l10n-id="downloadMessage"></div>
|
||||
<img src="/resources/illustration_download.svg" id="download-img" data-l10n-id="downloadAltText"/>
|
||||
@@ -34,13 +36,4 @@
|
||||
</div>
|
||||
|
||||
<a class="send-new" data-l10n-id="sendYourFilesLink"></a>
|
||||
{{else}}
|
||||
<div class="title" data-l10n-id="expiredPageHeader"></div>
|
||||
|
||||
<div class="share-window">
|
||||
<img src="/resources/illustration_expired.svg" id="expired-img" data-l10n-id="linkExpiredAlt"/>
|
||||
</div>
|
||||
<div class="expired-description" data-l10n-id="uploadPageExplainer"></div>
|
||||
<a class="send-new" data-l10n-id="sendYourFilesLink"></a>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<div id="page-one">
|
||||
<script src="/upload.js"></script>
|
||||
<div class="title" data-l10n-id="uploadPageHeader"></div>
|
||||
<div class="description">
|
||||
<div data-l10n-id="uploadPageExplainer"></div>
|
||||
@@ -20,10 +21,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- htmllint attr-bans="false" -->
|
||||
<th width="35%" data-l10n-id="sentFilesTitle1"></th>
|
||||
<th width="25%" data-l10n-id="sentFilesTitle2"></th>
|
||||
<th width="21%" data-l10n-id="sentFilesTitle3"></th>
|
||||
<th width="12%" data-l10n-id="sentFilesTitle4"></th>
|
||||
<th width="35%" data-l10n-id="uploadedFile"></th>
|
||||
<th width="25%" data-l10n-id="copyFileList"></th>
|
||||
<th width="21%" data-l10n-id="expiryFileList"></th>
|
||||
<th width="12%" data-l10n-id="deleteFileList"></th>
|
||||
<!-- htmllint tag-bans="$previous" -->
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -54,13 +55,13 @@
|
||||
<div id="share-link" hidden="true">
|
||||
<div class="title" data-l10n-id="uploadSuccessTimingHeader"></div>
|
||||
<div id="share-window">
|
||||
<div id="copy-text" data-l10n-id="copyUrlFormLabel"></div>
|
||||
<div id="copy-text"></div>
|
||||
<div id="copy">
|
||||
<input id="link" type="url" value="" readonly/>
|
||||
<button id="copy-btn" data-l10n-id="copyUrlFormButton"></button>
|
||||
</div>
|
||||
<button id="delete-file" data-l10n-id="deleteFileButton"></button>
|
||||
<a class="send-new" data-l10n-id="sendAnotherFileLink"></a>
|
||||
<a class="send-new" id="send-new-completed" data-l10n-id="sendAnotherFileLink"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -68,17 +69,5 @@
|
||||
<div class="title" data-l10n-id="errorPageHeader"></div>
|
||||
<div class="expired-description" data-l10n-id="errorPageMessage"></div>
|
||||
<img id="upload-error-img" data-l10n-id="errorAltText" src="/resources/illustration_error.svg"/>
|
||||
<a class="send-new" data-l10n-id="sendAnotherFileLink"></a>
|
||||
</div>
|
||||
|
||||
<div id="unsupported-browser" hidden="true">
|
||||
<div class="title" data-l10n-id="notSupportedHeader"></div>
|
||||
<div class="description" data-l10n-id="notSupportedDetail"></div>
|
||||
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2" target="_blank">
|
||||
<img src="/resources/firefox_logo-only.svg" id="firefox-logo" alt="Firefox"/>
|
||||
<div id="dl-firefox-text">Firefox<br>
|
||||
<span data-l10n-id="downloadFirefoxButtonSub"></span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="unsupported-description" data-l10n-id="uploadPageExplainer"></div>
|
||||
<a class="send-new" id="send-new-error" data-l10n-id="sendAnotherFileLink"></a>
|
||||
</div>
|
||||
|
||||
@@ -5,3 +5,4 @@ window.dsn = '{{{dsn}}}';
|
||||
window.trackerId = '{{{trackerId}}}';
|
||||
{{/if}}
|
||||
const MAXFILESIZE = {{{maxFileSize}}};
|
||||
const EXPIRE_SECONDS = {{{expireSeconds}}};
|
||||
|
||||
@@ -3,30 +3,40 @@
|
||||
<head>
|
||||
<title>Firefox Send</title>
|
||||
<script src="/jsconfig.js"></script>
|
||||
<script src="/bundle.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/main.css" />
|
||||
<link rel="stylesheet" href="https://code.cdn.mozilla.net/fonts/fira.css">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="en-US">
|
||||
<link rel="localization" href="/locales/send.{locale}.ftl">
|
||||
<script defer src="/l20n/dist/web/l20n.js"></script>
|
||||
<meta name="availableLanguages" content="{{availableLanguages}}">
|
||||
|
||||
<link rel="icon" type="image/png" href="/resources/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="localization" href="/locales/{locale}/send.ftl">
|
||||
<script defer src="/l20n.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="send-logo">
|
||||
<img src="/resources/send_logo.svg"/>
|
||||
<img src="/resources/send_logo_type.svg"/>
|
||||
</div>
|
||||
<header class="header">
|
||||
<div class="send-logo">
|
||||
<a href="/">
|
||||
<img src="/resources/send_logo.svg" alt="Send"/><h1 class="site-title">Send</h1>
|
||||
</a>
|
||||
<div class="site-subtitle">
|
||||
<a href="https://testpilot.firefox.com" target="_blank">Firefox Test Pilot</a>
|
||||
<div data-l10n-id="siteSubtitle">web experiment</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank" data-l10n-id="siteFeedback">Feedback</a>
|
||||
</header>
|
||||
<div class="all">
|
||||
{{{body}}}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="legal-links">
|
||||
<a href="https://www.mozilla.org"><img class="mozilla-logo" src="/resources/mozilla-logo.svg"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal/" data-l10n-id="footerLinkLegal"></a>
|
||||
<a href="https://www.mozilla.org"><img class="mozilla-logo" src="/resources/mozilla-logo.svg"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal" data-l10n-id="footerLinkLegal"></a>
|
||||
<a href="https://testpilot.firefox.com/about" data-l10n-id="footerLinkAbout"></a>
|
||||
<a href="https://testpilot.firefox.com/privacy" data-l10n-id="footerLinkPrivacy"></a>
|
||||
<a href="https://testpilot.firefox.com/terms" data-l10n-id="footerLinkTerms"></a>
|
||||
<a href="/legal" data-l10n-id="footerLinkPrivacy"></a>
|
||||
<a href="/legal" data-l10n-id="footerLinkTerms"></a>
|
||||
<a href="https://www.mozilla.org/en-US/privacy/websites/#cookies" data-l10n-id="footerLinkCookies"></a>
|
||||
</div>
|
||||
<div class="social-links">
|
||||
|
||||
12
views/legal.handlebars
Normal file
12
views/legal.handlebars
Normal file
@@ -0,0 +1,12 @@
|
||||
<div id="legal">
|
||||
<div class="title" data-l10n-id="legalHeader"></div>
|
||||
<div class="description" data-l10n-id="legalNoticeTestPilot">
|
||||
<a href="https://testpilot.firefox.com/terms"></a>
|
||||
<a href="https://testpilot.firefox.com/privacy"></a>
|
||||
<a href="https://testpilot.firefox.com/experiments/send"></a>
|
||||
</div>
|
||||
<div class="description" data-l10n-id="legalNoticeMozilla">
|
||||
<a href="https://www.mozilla.org/privacy/websites/"></a>
|
||||
<a href="https://www.mozilla.org/about/legal/terms/mozilla/"></a>
|
||||
</div>
|
||||
</div>
|
||||
8
views/notfound.handlebars
Normal file
8
views/notfound.handlebars
Normal file
@@ -0,0 +1,8 @@
|
||||
<div id="download">
|
||||
<div class="title" data-l10n-id="expiredPageHeader"></div>
|
||||
<div class="share-window">
|
||||
<img src="/resources/illustration_expired.svg" id="expired-img" data-l10n-id="linkExpiredAlt"/>
|
||||
</div>
|
||||
<div class="expired-description" data-l10n-id="uploadPageExplainer"></div>
|
||||
<a class="send-new" href="/" id="expired-send-new" data-l10n-id="sendYourFilesLink"></a>
|
||||
</div>
|
||||
11
views/unsupported.handlebars
Normal file
11
views/unsupported.handlebars
Normal file
@@ -0,0 +1,11 @@
|
||||
<div id="unsupported-browser">
|
||||
<div class="title" data-l10n-id="notSupportedHeader"></div>
|
||||
<div class="description" data-l10n-id="notSupportedDetail"></div>
|
||||
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2" target="_blank">
|
||||
<img src="/resources/firefox_logo-only.svg" id="firefox-logo" alt="Firefox"/>
|
||||
<div id="dl-firefox-text">Firefox<br>
|
||||
<span data-l10n-id="downloadFirefoxButtonSub"></span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="unsupported-description" data-l10n-id="uploadPageExplainer"></div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user