Captions: add German and Portuguese, make them findable, and fix the dead "Add mine" button
Three things. GERMAN AND PORTUGUESE. Marty's call, and the right one: the translation cache only shows who is already here, not who Manson is bringing. Manson knows his audience, so Portuguese goes in even though site data ranks German above it. All five videos now carry English, Italian, French, Spanish, German and Portuguese. Disclaimers checked by hand in the two new languages: "Es wird kein Einkommen garantiert" and "Nenhuma renda e garantida". FINDABILITY. Marty went looking for the multilingual feature on his own training page and could not find it, because the first build leaned on the native CC control and nothing switches on for an English reader. A feature nobody can find is not shipped. Every captioned player now carries a visible row of subtitle chips underneath, named in their own language, with an Off option. Captions still stay off by default for an English reader and still turn themselves on for anyone who already picked a language with the globe button; the chips just make the choice visible instead of buried. THE DEAD BUTTON. The inbox banner's "Add mine" shipped with NO click handler, so it rendered and did absolutely nothing. That is why Marty could not add his address while connected to the right wallet: nothing was listening. It now opens the same optional profile dialog and re-renders when it completes. Tests: gate-e2e 38 (up from 33, and rendering that button is explicitly not the test any more, it has to actually open the dialog), captions-e2e 158 across six languages including the new chip behaviour, clicking one and turning them back off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+84
-27
@@ -1,33 +1,90 @@
|
||||
// Match video captions to the language the member already chose with the 🌐 button.
|
||||
// Video captions: match the language the member already chose with the 🌐 button, and
|
||||
// make the fact that captions EXIST visible without hunting for the player's CC button.
|
||||
//
|
||||
// Deliberately NOT on by default for English. Someone reading English does not want
|
||||
// captions forced over the picture; someone who switched the site to Italian almost
|
||||
// certainly does. So: if their chosen language has a track, show it. Otherwise show
|
||||
// nothing and leave the player's own CC button to do its job.
|
||||
// Marty, 2026-09-17: the first build relied on the native CC control. He could not find
|
||||
// it on his own page, which means members would not either, so every captioned player
|
||||
// now carries a visible row of language chips underneath.
|
||||
//
|
||||
// Marty + Manson, 2026-09-17. See tools/captions.mjs for how the tracks are built.
|
||||
// Still deliberately OFF by default for an English reader: someone reading English does
|
||||
// not want text over the picture. Someone who already switched the site to Italian
|
||||
// almost certainly does, so that one turns itself on.
|
||||
//
|
||||
// Tracks are built by tools/captions.mjs. See memory rm-circle-video-captions.
|
||||
(function () {
|
||||
function pick() {
|
||||
var lang = '';
|
||||
try { lang = String(localStorage.getItem('rmc.lang') || '').toLowerCase(); } catch (e) {}
|
||||
var vids = document.querySelectorAll('video');
|
||||
for (var i = 0; i < vids.length; i++) {
|
||||
var tt = vids[i].textTracks;
|
||||
if (!tt || !tt.length) continue;
|
||||
var wanted = null;
|
||||
for (var j = 0; j < tt.length; j++) {
|
||||
if (tt[j].kind !== 'captions' && tt[j].kind !== 'subtitles') continue;
|
||||
// never leave a stale track showing when the member switches language
|
||||
tt[j].mode = 'disabled';
|
||||
if (lang && lang !== 'en' && String(tt[j].language || '').toLowerCase() === lang) wanted = tt[j];
|
||||
}
|
||||
if (wanted) wanted.mode = 'showing';
|
||||
var NAMES = { en: 'English', it: 'Italiano', fr: 'Français', es: 'Español', de: 'Deutsch',
|
||||
pt: 'Português', nl: 'Nederlands', pl: 'Polski', ro: 'Română', ru: 'Русский', uk: 'Українська',
|
||||
tr: 'Türkçe', ar: 'العربية', hi: 'हिन्दी', vi: 'Tiếng Việt', id: 'Bahasa', th: 'ไทย',
|
||||
zh: '中文', ja: '日本語', ko: '한국어', sw: 'Kiswahili', fil: 'Filipino' };
|
||||
|
||||
function chosen() {
|
||||
try { return String(localStorage.getItem('rmc.lang') || '').toLowerCase(); } catch (e) { return ''; }
|
||||
}
|
||||
function tracksOf(v) {
|
||||
var out = [], tt = v.textTracks;
|
||||
for (var i = 0; tt && i < tt.length; i++) if (tt[i].kind === 'captions' || tt[i].kind === 'subtitles') out.push(tt[i]);
|
||||
return out;
|
||||
}
|
||||
function show(v, lang) {
|
||||
var list = tracksOf(v), hit = null;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
list[i].mode = 'disabled'; // never leave a stale track showing
|
||||
if (lang && String(list[i].language || '').toLowerCase() === lang) hit = list[i];
|
||||
}
|
||||
if (hit) hit.mode = 'showing';
|
||||
paint(v, lang);
|
||||
}
|
||||
function paint(v, active) {
|
||||
var bar = v.parentNode && v.parentNode.querySelector('.cap-bar');
|
||||
if (!bar) return;
|
||||
var btns = bar.querySelectorAll('button[data-lang]');
|
||||
for (var i = 0; i < btns.length; i++) {
|
||||
var on = btns[i].getAttribute('data-lang') === (active || '');
|
||||
btns[i].style.background = on ? 'rgba(240,197,109,.22)' : 'transparent';
|
||||
btns[i].style.borderColor = on ? 'rgba(240,197,109,.7)' : 'var(--line, #24425d)';
|
||||
btns[i].style.color = on ? 'var(--gold, #f0c56d)' : 'var(--muted, #8fa6bd)';
|
||||
btns[i].setAttribute('aria-pressed', on ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', pick);
|
||||
else pick();
|
||||
// translate.js writes rmc.lang when the member picks a language; re-run so the
|
||||
// captions follow without a reload, and cover players rendered later.
|
||||
window.addEventListener('storage', function (e) { if (!e || e.key === 'rmc.lang') pick(); });
|
||||
window.RMCCaptions = { refresh: pick };
|
||||
function build(v) {
|
||||
var list = tracksOf(v);
|
||||
if (!list.length || !v.parentNode) return;
|
||||
if (v.parentNode.querySelector('.cap-bar')) return; // already built
|
||||
var bar = document.createElement('div');
|
||||
bar.className = 'cap-bar';
|
||||
bar.style.cssText = 'display:flex;flex-wrap:wrap;gap:6px;align-items:center;padding:8px 6px 2px;font-size:12px';
|
||||
var lab = document.createElement('span');
|
||||
lab.textContent = 'Subtitles:';
|
||||
lab.style.cssText = 'color:var(--muted,#8fa6bd);text-transform:uppercase;letter-spacing:.07em;font-weight:700;margin-right:2px';
|
||||
bar.appendChild(lab);
|
||||
var mk = function (lang, text) {
|
||||
var b = document.createElement('button');
|
||||
b.type = 'button';
|
||||
b.setAttribute('data-lang', lang);
|
||||
b.textContent = text;
|
||||
b.style.cssText = 'cursor:pointer;border:1px solid var(--line,#24425d);background:transparent;color:var(--muted,#8fa6bd);' +
|
||||
'border-radius:999px;padding:4px 11px;font-size:12px;font-family:inherit;line-height:1.4';
|
||||
b.addEventListener('click', function () { show(v, lang); });
|
||||
return b;
|
||||
};
|
||||
bar.appendChild(mk('', 'Off'));
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var code = String(list[i].language || '').toLowerCase();
|
||||
bar.appendChild(mk(code, NAMES[code] || (list[i].label || code)));
|
||||
}
|
||||
v.parentNode.insertBefore(bar, v.nextSibling);
|
||||
}
|
||||
function init() {
|
||||
var vids = document.querySelectorAll('video');
|
||||
var lang = chosen();
|
||||
for (var i = 0; i < vids.length; i++) {
|
||||
if (!tracksOf(vids[i]).length) continue;
|
||||
build(vids[i]);
|
||||
// English readers get nothing over the picture; a chosen language turns itself on
|
||||
show(vids[i], lang && lang !== 'en' ? lang : '');
|
||||
}
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
||||
else init();
|
||||
window.addEventListener('storage', function (e) { if (!e || e.key === 'rmc.lang') init(); });
|
||||
window.RMCCaptions = { refresh: init };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user