1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-03 00:18:31 +00:00
* Added: Languages!

Not a native English speaker? We've got an option for that, too. FrankerFaceZ is translated with love by our community. Please [join our Discord](https://discord.gg/UrAkGhT) and ask about localization if you'd like to contribute. We're still new to localization, so there may be some growing pains.

If you notice any inaccuracies, confusing translations, or texts that are outright wrong or offensive, please be sure to report them. We accept reports via Discord, Twitter, or GitHub Issue.

* Fixed: The ability to disable Channel Hosting not functioning.
* Fixed: No background appearing behind channel metadata when in theater mode.
This commit is contained in:
SirStendec 2019-10-05 20:55:32 -04:00
parent 13ccc577f5
commit 7f0cad4bd4
6 changed files with 96 additions and 134 deletions

View file

@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
"version": "4.12.6",
"version": "4.13.0",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0",
"scripts": {

View file

@ -75,14 +75,14 @@ export class TranslationManager extends Module {
this._seen = new Set;
this.availableLocales = ['en']; //, 'de', 'ja'];
this.availableLocales = ['en'];
this.localeData = {
en: { name: 'English' }/*,
de: { name: 'Deutsch' },
ja: { name: '日本語' }*/
en: { name: 'English' }
}
this.loadLocales();
this.capturing = false;
this.captured = new Map;
@ -140,28 +140,59 @@ export class TranslationManager extends Module {
this.settings.add('i18n.locale', {
default: -1,
process: (ctx, val) => {
if ( val === -1 )
val = ctx.get('context.session.languageCode');
if ( val === -1 || typeof val !== 'string' )
val = ctx.get('context.session.languageCode') || 'en';
if ( this.availableLocales.includes(val) )
return val;
const idx = val.indexOf('-');
if ( idx === -1 )
return 'en';
val = val.slice(0, idx);
return this.availableLocales.includes(val) ? val : 'en'
},
_ui: {
ui: {
path: 'Appearance > Localization >> General',
title: 'Language',
// description: '',
description: `FrankerFaceZ is lovingly translated by volunteers from our community. Thank you. If you're interested in helping to translate FrankerFaceZ, please [join our Discord](https://discord.gg/UrAkGhT) and ask about localization.`,
component: 'setting-select-box',
data: (profile, val) => [{
selected: val === -1,
value: -1,
i18n_key: 'setting.appearance.localization.general.language.twitch',
title: "Use Twitch's Language"
}].concat(this.availableLocales.map(l => ({
selected: val === l,
value: l,
title: this.localeData[l].name
})))
data: (profile, val) => {
const out = this.availableLocales.map(l => {
const data = this.localeData[l];
let title = data?.native_name;
if ( ! title )
title = data?.name || l;
if ( data?.coverage != null && data?.coverage < 100 )
title = this.t('i18n.locale-coverage', '{name} ({coverage,number,percent} Complete)', {
name: title,
coverage: data.coverage / 100
});
return {
selected: val === l,
value: l,
title
};
});
out.sort((a, b) => {
return a.title.localeCompare(b.title)
});
out.unshift({
selected: val === -1,
value: -1,
i18n_key: 'setting.appearance.localization.general.language.twitch',
title: "Use Twitch's Language"
});
return out;
}
},
changed: val => this.locale = val
@ -361,122 +392,40 @@ export class TranslationManager extends Module {
}
async loadLocales() {
const resp = await fetch(`https://api-test.frankerfacez.com/v2/i18n/locales`);
if ( ! resp.ok ) {
this.log.warn(`Error Populating Locales -- Status: ${resp.status}`);
throw new Error(`http error ${resp.status} loading locales`)
}
let data = await resp.json();
if ( ! Array.isArray(data) || ! data.length )
data = [{
id: 'en',
name: 'English',
coverage: 100,
rtl: false
}];
this.localeData = {};
this.availableLocales = [];
for(const locale of data) {
const key = locale.id.toLowerCase();
this.localeData[key] = locale;
this.availableLocales.push(key);
}
this.emit(':locales-loaded');
}
async loadLocale(locale) {
if ( locale === 'en' )
return {};
/*if ( locale === 'de' )
return {
site: {
menu_button: 'FrankerFaceZ Leitstelle'
},
player: {
reset_button: 'Doppelklicken, um den Player zurückzusetzen'
},
setting: {
reset: 'Zurücksetzen',
appearance: {
_: 'Aussehen',
description: 'Personalisieren Sie das Aussehen von Twitch. Ändern Sie das Farbschema und die Schriften und stimmen Sie das Layout so ab, dass Sie ein optimales Erlebnis erleben.<br><br>(Yes, this is Google Translate still.)',
localization: {
_: 'Lokalisierung',
general: {
language: {
_: 'Sprache',
twitch: "Verwenden Sie Twitch's Sprache"
}
},
dates_and_times: {
_: 'Termine und Zeiten',
allow_relative_times: {
_: 'Relative Zeiten zulassen',
description: 'Wenn dies aktiviert ist, zeigt FrankerFaceZ einige Male in einem relativen Format an. <br>Beispiel: vor 3 Stunden'
}
}
},
layout: 'Layout',
theme: 'Thema'
},
profiles: {
_: 'Profile',
active: 'Dieses Profil ist aktiv.',
inactive: {
_: 'Dieses Profil ist nicht aktiv.',
description: 'Dieses Profil stimmt nicht mit dem aktuellen Kontext überein und ist momentan nicht aktiv, so dass Sie keine Änderungen sehen, die Sie hier bei Twitch vorgenommen haben.'
},
configure: 'Konfigurieren',
default: {
_: 'Standard Profil',
description: 'Einstellungen, die überall auf Twitch angewendet werden.'
},
moderation: {
_: 'Mäßigung',
description: 'Einstellungen, die gelten, wenn Sie ein Moderator des aktuellen Kanals sind.'
}
},
add_ons: {
_: 'Erweiterung'
},
'inherited-from': 'Vererbt von: {title}',
'overridden-by': 'Überschrieben von: {title}'
},
'main-menu': {
search: 'Sucheinstellungen',
about: {
_: 'Über',
news: 'Nachrichten',
support: 'Unterstützung'
}
}
}
if ( locale === 'ja' )
return {
greeting: 'こんにちは',
site: {
menu_button: 'FrankerFaceZコントロールセンター'
},
setting: {
appearance: {
_: '外観',
localization: '局地化',
layout: '設計',
theme: '題材'
}
},
'main-menu': {
search: '検索設定',
version: 'バージョン{version}',
about: {
_: '約',
news: '便り',
support: '対応'
}
}
}*/
const resp = await fetch(`${SERVER}/script/i18n/${locale}.json`);
const resp = await fetch(`https://api-test.frankerfacez.com/v2/i18n/locale/${locale}`);
if ( ! resp.ok ) {
if ( resp.status === 404 ) {
this.log.info(`Cannot Load Locale: ${locale}`);
@ -487,7 +436,8 @@ export class TranslationManager extends Module {
throw new Error(`http error ${resp.status} loading phrases`);
}
return resp.json();
const data = await resp.json();
return data?.phrases;
}
async setLocale(new_locale) {
@ -510,7 +460,8 @@ export class TranslationManager extends Module {
return [];
}
const phrases = await this.loadLocale(new_locale);
const data = this.localeData[new_locale];
const phrases = await this.loadLocale(data?.id || new_locale);
if ( this._.locale !== new_locale )
throw new Error('locale has changed since we started loading');

View file

@ -53,7 +53,7 @@ export default class Channel extends Module {
this.ChannelPage = this.fine.define(
'channel-page',
n => (n.updateRoute && n.updateChannel && n.state && has(n.state, 'hostedChannel')) || (n.getHostedChannelLogin && n.handleHostingChange) || (n.onChatHostingChange && n.state && has(n.state, 'hostMode')),
n => (n.updateHost && n.updateChannel && n.state && has(n.state, 'hostedChannel')) || (n.getHostedChannelLogin && n.handleHostingChange) || (n.onChatHostingChange && n.state && has(n.state, 'hostMode')),
['user', 'video', 'user-video', 'user-clip', 'user-videos', 'user-clips', 'user-collections', 'user-events', 'user-followers', 'user-following']
);

View file

@ -15,5 +15,6 @@
}
.channel-root__scroll-area--theatre-mode:hover .channel-info-bar {
background-color: var(--color-background-base);
opacity: 0.75;
}

View file

@ -30,6 +30,8 @@ export default class Player extends Module {
PLAYER_ROUTES
);
// TODO: Better way to reposition player on demand.
this.PersistentPlayer = this.fine.define(
'twitch-player-persistent',
n => n.renderMiniHoverControls && n.togglePause,

View file

@ -488,6 +488,7 @@ function listToString(list) {
const CARDINAL_TO_LANG = {
arabic: ['ar'],
czech: ['cs'],
danish: ['da'],
german: ['de', 'el', 'en', 'es', 'fi', 'hu', 'it', 'nl', 'no', 'nb', 'tr', 'sv'],
hebrew: ['he'],
@ -508,6 +509,13 @@ const CARDINAL_TYPES = {
return n1 >= 11 ? 4 : 5;
},
czech: (n,i,v) => {
if ( v !== 0 ) return 4;
if ( i === 1 ) return 1;
if ( i >= 2 && i <= 4 ) return 3;
return 5;
},
danish: (n,i,v,t) => (n === 1 || (t !== 0 && (i === 0 || i === 1))) ? 1 : 5,
french: (n, i) => (i === 0 || i === 1) ? 1 : 5,
german: n => n === 1 ? 1 : 5,