it's all about you and your native language!

- finally cleaned up localisation (now i18n)
- made localisation strings easier to read and understand
- removed static selected language in service modules
- added support for russian language (привет-привет)
- it's now extremely easy to add support for more languages. just copy en folder in i18n and start translating strings. pull requests for adding languages are more than welcome.
This commit is contained in:
wukko
2022-07-17 18:58:51 +06:00
parent 299fe6336b
commit d08af58b11
20 changed files with 139 additions and 62 deletions

View File

@@ -30,6 +30,6 @@ export async function getJSON(originalURL, ip, lang, format, quality) {
return apiJSON(0, { t: errorUnsupported(lang) } )
}
} catch (e) {
return apiJSON(0, { t: loc(lang, 'apiError', 'generic') + loc(lang, 'apiError', 'letMeKnow') });
return apiJSON(0, { t: loc(lang, 'apiError', 'generic') });
}
}

View File

@@ -34,7 +34,7 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit
lang: lang
});
return (!r.error) ? apiJSON(2, {
type: "render", urls: r.urls,
type: "render", urls: r.urls, lang: lang,
service: host, ip: ip,
filename: r.filename,
salt: process.env.streamSalt, time: r.time
@@ -73,7 +73,7 @@ export default async function (host, patternMatch, url, ip, lang, format, qualit
let r = await reddit({
sub: patternMatch["sub"],
id: patternMatch["id"],
title: patternMatch["title"]
title: patternMatch["title"], lang: lang,
});
return (!r.error) ? apiJSON(2, {
type: "render", urls: r.urls,

View File

@@ -17,7 +17,7 @@ let enabledServices = Object.keys(s).filter((p) => {
let donate = ``
for (let i in donations) {
donate += `<div class="subtitle">${i} (${loc("en", 'desc', 'clickToCopy').trim()})</div><div id="don-${i}" class="text-to-copy" onClick="copy('don-${i}')">${donations[i]}</div>`
donate += `<div class="subtitle">${i} (REPLACEME)</div><div id="don-${i}" class="text-to-copy" onClick="copy('don-${i}')">${donations[i]}</div>`
}
let com = getCommitInfo();
@@ -34,10 +34,10 @@ export default function(obj) {
<meta property="og:url" content="${process.env.selfURL}" />
<meta property="og:title" content="${appName}" />
<meta property="og:description" content="${loc(obj.lang, 'desc', 'embed')}" />
<meta property="og:description" content="${loc(obj.lang, 'strings', 'embed')}" />
<meta property="og:image" content="${process.env.selfURL}icons/generic.png" />
<meta name="title" content="${appName}" />
<meta name="description" content="${loc(obj.lang, 'desc', 'embed')}" />
<meta name="description" content="${loc(obj.lang, 'strings', 'embed')}" />
<meta name="theme-color" content="#000000" />
<meta name="twitter:card" content="summary" />
@@ -50,7 +50,7 @@ export default function(obj) {
<link rel="stylesheet" href="cobalt.css" />
<link rel="stylesheet" href="fonts/notosansmono/notosansmono.css" />
<noscript><div style="margin: 2rem;">${loc(obj.lang, 'desc', 'noScript')}</div></noscript>
<noscript><div style="margin: 2rem;">${loc(obj.lang, 'strings', 'noScript')}</div></noscript>
</head>
<body id="cobalt-body">
<div id="popup-download" class="popup center box" style="visibility: hidden;">
@@ -62,11 +62,11 @@ export default function(obj) {
<div id="theme-switcher" class="switch-container small-padding">
<div class="subtitle">${loc(obj.lang, 'title', 'pickDownload')}</div>
<div class="switches">
<a id="pd-download" class="switch full space-right" target="_blank"">${loc(obj.lang, 'desc', 'download')}</a>
<div id="pd-copy" class="switch full">${loc(obj.lang, 'desc', 'copy')}</div>
<a id="pd-download" class="switch full space-right" target="_blank"">${loc(obj.lang, 'strings', 'download')}</a>
<div id="pd-copy" class="switch full">${loc(obj.lang, 'strings', 'copy')}</div>
</div>
</div>
<div id="desc" class="explanation about-padding">${isIOS ? loc(obj.lang, 'desc', 'iosDownload') : loc(obj.lang, 'desc', 'normalDownload')}</div>
<div id="desc" class="explanation about-padding">${isIOS ? loc(obj.lang, 'strings', 'iosDownload') : loc(obj.lang, 'strings', 'normalDownload')}</div>
</div>
</div>
<div id="popup-about" class="popup center box" style="visibility: hidden;">
@@ -75,12 +75,12 @@ export default function(obj) {
<div id="title" class="popup-title">${loc(obj.lang, 'title', 'about')}</div>
</div>
<div id="content" class="popup-content with-footer">
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'desc', 'aboutSummary')}</div>
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'desc', 'supportedServices')} ${enabledServices}.</div>
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}">${loc(obj.lang, 'desc', 'sourceCode')}</a></div>
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'strings', 'aboutSummary')}</div>
<div id="desc" class="popup-desc about-padding">${loc(obj.lang, 'strings', 'supportedServices')} ${enabledServices}.</div>
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}">${loc(obj.lang, 'strings', 'sourceCode')}</a></div>
</div>
<div id="popup-footer" class="popup-footer">
<a id="popup-bottom" class="popup-footer-content" href="${authorInfo.link}">${loc(obj.lang, 'desc', 'popupBottom')}</a>
<a id="popup-bottom" class="popup-footer-content" href="${authorInfo.link}">${loc(obj.lang, 'strings', 'popupBottom')}</a>
</div>
</div>
<div id="popup-changelog" class="popup center box" style="visibility: hidden;">
@@ -91,19 +91,19 @@ export default function(obj) {
</div>
<div id="content" class="popup-content">
<div id="desc" class="popup-desc about-padding">${com[1]}</div>
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}/commits">${loc(obj.lang, 'desc', 'github')}</a></div>
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${repo}/commits">${loc(obj.lang, 'strings', 'github')}</a></div>
</div>
</div>
<div id="popup-donate" class="popup scrollable center box" style="visibility: hidden;">
<div id="popup-header" class="popup-header">
<button id="close" class="button mono" onclick="popup('donate', 0)" aria-label="${loc(obj.lang, 'accessibility', 'close')}">x</button>
<div id="title" class="popup-title">${loc(obj.lang, 'title', 'donate')}</div>
<div id="desc" class="little-subtitle">${loc(obj.lang, 'desc', 'donationsSub')}</div>
<div id="desc" class="little-subtitle">${loc(obj.lang, 'strings', 'donationsSub')}</div>
</div>
<div id="content" class="popup-content">
${donate}
<div id="desc" class="explanation about-padding">${loc(obj.lang, 'desc', 'donations')}</div>
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${authorInfo.contact}">${loc(obj.lang, 'desc', 'donateDm')}</a></div>
${donate.replace(/REPLACEME/g, loc(obj.lang, 'strings', 'clickToCopy').trim())}
<div id="desc" class="explanation about-padding">${loc(obj.lang, 'strings', 'donations')}</div>
<div id="desc" class="popup-desc"><a class="text-backdrop" href="${authorInfo.contact}">${loc(obj.lang, 'strings', 'donateDm')}</a></div>
</div>
</div>
<div id="popup-settings" class="popup scrollable center box" style="visibility: hidden;">
@@ -159,7 +159,7 @@ export default function(obj) {
<div class="switches">
<div id="youtubeFormat-mp4" class="switch full" onclick="changeSwitcher('youtubeFormat', 'mp4', 1)">mp4</div>
<div id="youtubeFormat-webm" class="switch" onclick="changeSwitcher('youtubeFormat', 'webm', 1)">webm</div>
<div id="youtubeFormat-audio" class="switch full" onclick="changeSwitcher('youtubeFormat', 'audio', 1)">audio only</div>
<div id="youtubeFormat-audio" class="switch full" onclick="changeSwitcher('youtubeFormat', 'audio', 1)">${loc(obj.lang, 'settings', 'audioOnly')}</div>
</div>
<div class="explanation">${loc(obj.lang, 'settings', 'formatInfo')}</div>
</div>
@@ -180,7 +180,7 @@ export default function(obj) {
<div id="cobalt-main-box" class="center box" style="visibility: hidden;">
<div id="logo-area">${appName}</div>
<div id="download-area" class="mobile-center">
<input id="url-input-area" class="mono" type="text" autocorrect="off" maxlength="110" autocapitalize="off" placeholder="${loc(obj.lang, 'desc', 'input')}" aria-label="${loc(obj.lang, 'accessibility', 'input')}" oninput="button()">
<input id="url-input-area" class="mono" type="text" autocorrect="off" maxlength="110" autocapitalize="off" placeholder="${loc(obj.lang, 'strings', 'input')}" aria-label="${loc(obj.lang, 'accessibility', 'input')}" oninput="button()">
<input id="download-button" class="mono dontRead" onclick="download(document.getElementById('url-input-area').value)" type="submit" value="" disabled=true aria-label="${loc(obj.lang, 'accessibility', 'download')}">
</div>
</div>
@@ -197,6 +197,6 @@ export default function(obj) {
<script type="text/javascript" src="cobalt.js"></script>
</html>`;
} catch (err) {
return `${loc('en', 'apiError', 'fatal', obj.hash)}`;
return `${loc('en', 'apiError', 'noRender', obj.hash)}`;
}
}

View File

@@ -8,7 +8,7 @@ export default async function(obj) {
headers: { "user-agent": genericUserAgent }
});
html.on('error', (err) => {
return { error: loc('en', 'apiError', 'youtubeFetch') };
return { error: loc(obj.lang, 'apiError', 'cantConnectToAPI', 'bilibili') };
});
html = html.body;
if (html.includes('<script>window.__playinfo__=') && html.includes('"video_codecid"')) {
@@ -22,13 +22,13 @@ export default async function(obj) {
}).sort((a, b) => Number(b.bandwidth) - Number(a.bandwidth));
return { urls: [video[0]["baseUrl"], audio[0]["baseUrl"]], time: streamData.data.timelength, filename: `bilibili_${obj.id}_${video[0]["width"]}x${video[0]["height"]}.mp4` };
} else {
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
return { error: loc(obj.lang, 'apiError', 'lengthLimit', maxVideoDuration / 60000) };
}
} else {
return { error: loc('en', 'apiError', 'youtubeFetch') };
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
}
} catch (e) {
return { error: loc('en', 'apiError', 'youtubeFetch') };
return { error: loc(obj.lang, 'apiError', 'noFetch') };
}
}

View File

@@ -9,9 +9,9 @@ export default async function(obj) {
if ("reddit_video" in data["secure_media"] && data["secure_media"]["reddit_video"]["duration"] * 1000 < maxVideoDuration) {
return { urls: [data["secure_media"]["reddit_video"]["fallback_url"].split('?')[0], `${data["secure_media"]["reddit_video"]["fallback_url"].split('_')[0]}_audio.mp4`], filename: `reddit_${data["secure_media"]["reddit_video"]["fallback_url"].split('/')[3]}.mp4` };
} else {
return { error: loc('en', 'apiError', 'nothingToDownload') };
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
}
} catch (err) {
return { error: loc("en", "apiError", "nothingToDownload") };
return { error: loc(obj.lang, 'apiError', 'noFetch') };
}
}

View File

@@ -52,6 +52,6 @@ export default async function (obj) {
}
} else return parsbod;
} catch (err) {
return { error: loc("en", "apiError", "youtubeBroke") };
return { error: loc("en", "apiError", "errorFetch") };
}
}

View File

@@ -30,18 +30,18 @@ export default async function(obj) {
if (selectedQuality in js["player"]["params"][0]) {
return { url: js["player"]["params"][0][selectedQuality].replace(`type=${maxQuality}`, `type=${services.vk.quality_match[userQuality]}`), filename: `vk_${js["player"]["params"][0][selectedQuality].split("id=")[1]}_${attr['width']}x${attr['height']}.mp4` };
} else {
return { error: loc('en', 'apiError', 'nothingToDownload') };
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
}
} else {
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
return { error: loc(obj.lang, 'apiError', 'lengthLimit', maxVideoDuration / 60000) };
}
} else {
return { error: loc('en', 'apiError', 'liveVideo') };
return { error: loc(obj.lang, 'apiError', 'liveVideo') };
}
} else {
return { error: loc('en', 'apiError', 'nothingToDownload') };
return { error: loc(obj.lang, 'apiError', 'nothingToDownload') };
}
} catch (err) {
return { error: loc('en', 'apiError', 'youtubeFetch') };
return { error: loc(obj.lang, 'apiError', 'errorFetch') };
}
}

View File

@@ -48,7 +48,7 @@ export default async function (obj) {
filename: `youtube_${obj.id}_${videoMatch[0]["width"]}x${videoMatch[0]["height"]}.${obj.format}` };
}
} else {
return { error: loc('en', 'apiError', 'youtubeBroke') };
return { error: loc('en', 'apiError', 'errorFetch') };
}
} else if (!obj.isAudioOnly) {
return { type: "render", urls: [video[0]["url"], audio[0]["url"]], time: video[0]["approxDurationMs"],
@@ -56,10 +56,10 @@ export default async function (obj) {
} else if (audio.length > 0) {
return { type: "render", isAudioOnly: true, urls: [audio[0]["url"]], filename: `youtube_${obj.id}_${audio[0]["audioBitrate"]}kbps.opus` };
} else {
return { error: loc('en', 'apiError', 'youtubeBroke') };
return { error: loc('en', 'apiError', 'errorFetch') };
}
} else {
return { error: loc('en', 'apiError', 'youtubeLimit', maxVideoDuration / 60000) };
return { error: loc('en', 'apiError', 'lengthLimit', maxVideoDuration / 60000) };
}
} else {
return { error: loc('en', 'apiError', 'liveVideo') };

View File

@@ -68,7 +68,7 @@ export async function streamLiveRender(streamInfo, res) {
ffmpegProcess.kill();
});
} else {
res.status(400).json({ status: "error", text: loc('en', 'apiError', 'corruptedVideo') });
res.status(400).json({ status: "error", text: loc('en', 'apiError', 'corruptedStream') });
}
} catch (e) {
internalError(res);

View File

@@ -4,8 +4,8 @@ export function internalError(res) {
res.status(501).json({ status: "error", text: "Internal Server Error" });
}
export function errorUnsupported(lang) {
return loc(lang, 'apiError', 'notSupported') + loc(lang, 'apiError', 'letMeKnow');
return loc(lang, 'apiError', 'notSupported');
}
export function genericError(lang, host) {
return loc(lang, 'apiError', 'brokenLink', host) + loc(lang, 'apiError', 'letMeKnow');
return loc(lang, 'apiError', 'brokenLink', host);
}