mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-28 15:27:43 +00:00
Fix bug tokenizing cheers in messages. Try to fix any bugs getting a user for a room. Strip apollo 404 messages from Sentry. Don't show the expansion arrows in the emote menu when using a filter. Fix emoji tab completion a bit. 🐝
should not match 🍺
. Start using crossorigin for script serving. Add a debug transformation for localization.
This commit is contained in:
parent
730e2129e9
commit
e581b50b08
13 changed files with 133 additions and 18 deletions
|
@ -1,3 +1,11 @@
|
|||
<div class="list-header">4.0.0-beta2.18<span>@c8636911fc387a9f5e0c</span> <time datetime="2018-04-15">(2018-04-15)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Added: Debugging setting for localization to help test UI issues, identify strings, and find strings that aren't localized.</li>
|
||||
<li>Fixed: Issue tokenizing cheers in messages.</li>
|
||||
<li>Fixed: Clean up tab-completion of emoji a bit more.</li>
|
||||
<li>Changed: Start using `crossorigin="anonymous"` when loading scripts from our CDN.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">4.0.0-beta2.17<span>@dce1b0c5268bdd3fe086</span> <time datetime="2018-04-13">(2018-04-13)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: An issue in automatic error reporting potentially swallowing errors when error reporting is disabled.</li>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
script = document.createElement('script');
|
||||
|
||||
script.id = 'ffz-script';
|
||||
script.crossOrigin = 'anonymous';
|
||||
script.src = `${SERVER}/script/${BABEL}${FLAVOR}.js?_=${Date.now()}`;
|
||||
document.head.appendChild(script);
|
||||
})();
|
81
src/i18n.js
81
src/i18n.js
|
@ -7,10 +7,59 @@
|
|||
// ============================================================================
|
||||
|
||||
import {SERVER} from 'utilities/constants';
|
||||
import {has} from 'utilities/object';
|
||||
import {pick_random, has} from 'utilities/object';
|
||||
import Module from 'utilities/module';
|
||||
|
||||
|
||||
const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'UwU', '>w<', '^w^'],
|
||||
|
||||
format_text = (phrase, token_regex, formatter) => {
|
||||
const out = [];
|
||||
|
||||
let i = 0, match;
|
||||
token_regex.lastIndex = 0;
|
||||
|
||||
while((match = token_regex.exec(phrase))) {
|
||||
if ( match.index !== i )
|
||||
out.push(formatter(phrase.slice(i, match.index)))
|
||||
|
||||
out.push(match[0]);
|
||||
i = match.index + match[0].length;
|
||||
}
|
||||
|
||||
if ( i < phrase.length )
|
||||
out.push(formatter(phrase.slice(i)));
|
||||
|
||||
return out.join('')
|
||||
},
|
||||
|
||||
owo = text => text
|
||||
.replace(/(?:r|l)/g, 'w')
|
||||
.replace(/(?:R|L)/g, 'W')
|
||||
.replace(/n([aeiou])/g, 'ny$1')
|
||||
.replace(/N([aeiou])/g, 'Ny$1')
|
||||
.replace(/N([AEIOU])/g, 'NY$1')
|
||||
.replace(/ove/g, 'uv')
|
||||
.replace(/!+/g, ` ${pick_random(FACES)} `),
|
||||
|
||||
|
||||
TRANSFORMATIONS = {
|
||||
double: (key, text) =>
|
||||
`${text} ${text}`,
|
||||
|
||||
upper: (key, text, opts, locale, token_regex) =>
|
||||
format_text(text, token_regex, t => t.toUpperCase()),
|
||||
|
||||
lower: (key, text, opts, locale, token_regex) =>
|
||||
format_text(text, token_regex, t => t.toLowerCase()),
|
||||
|
||||
append_key: (key, text) => `${text} (${key})`,
|
||||
|
||||
owo: (key, text, opts, locale, token_regex) =>
|
||||
format_text(text, token_regex, t => owo(t))
|
||||
};
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// TranslationManager
|
||||
// ============================================================================
|
||||
|
@ -28,6 +77,31 @@ export class TranslationManager extends Module {
|
|||
//ja: { name: '日本語' }
|
||||
}
|
||||
|
||||
|
||||
this.settings.add('i18n.debug.transform', {
|
||||
default: null,
|
||||
ui: {
|
||||
path: 'Debugging > Localization >> General',
|
||||
title: 'Transformation',
|
||||
description: 'Transform all localized strings to test string coverage as well as length.',
|
||||
component: 'setting-select-box',
|
||||
data: [
|
||||
{value: null, title: 'Disabled'},
|
||||
{value: 'upper', title: 'Upper Case'},
|
||||
{value: 'lower', title: 'Lower Case'},
|
||||
{value: 'append_key', title: 'Append Key'},
|
||||
{value: 'double', title: 'Double'},
|
||||
{value: 'owo', title: "owo what's this"}
|
||||
]
|
||||
},
|
||||
|
||||
changed: val => {
|
||||
this._.transformation = TRANSFORMATIONS[val];
|
||||
this.emit(':update')
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
this.settings.add('i18n.locale', {
|
||||
default: -1,
|
||||
process: (ctx, val) => {
|
||||
|
@ -65,6 +139,7 @@ export class TranslationManager extends Module {
|
|||
awarn: (...args) => this.log.info(...args)
|
||||
});*/
|
||||
|
||||
this._.transformation = TRANSFORMATIONS[this.settings.get('i18n.debug.transform')];
|
||||
this.locale = this.settings.get('i18n.locale');
|
||||
}
|
||||
|
||||
|
@ -311,6 +386,7 @@ export default class TranslationCore {
|
|||
this.extend(options.phrases);
|
||||
this.locale = options.locale || 'en';
|
||||
this.defaultLocale = options.defaultLocale || this.locale;
|
||||
this.transformation = null;
|
||||
|
||||
const allowMissing = options.allowMissing ? transformPhrase : null;
|
||||
this.onMissingKey = typeof options.onMissingKey === 'function' ? options.onMissingKey : allowMissing;
|
||||
|
@ -413,6 +489,9 @@ export default class TranslationCore {
|
|||
return key;
|
||||
}
|
||||
|
||||
if ( this.transformation )
|
||||
p = this.transformation(key, p, opts, locale, this.tokenRegex);
|
||||
|
||||
return this.transformPhrase(p, opts, locale, this.tokenRegex, this.formatters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ class FrankerFaceZ extends Module {
|
|||
FrankerFaceZ.Logger = Logger;
|
||||
|
||||
const VER = FrankerFaceZ.version_info = {
|
||||
major: 4, minor: 0, revision: 0, extra: '-beta2.17',
|
||||
major: 4, minor: 0, revision: 0, extra: '-beta2.18',
|
||||
build: __webpack_hash__,
|
||||
toString: () =>
|
||||
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
||||
|
|
|
@ -116,7 +116,7 @@ export default class Room {
|
|||
}
|
||||
|
||||
|
||||
getUser(id, login, no_create, no_login) {
|
||||
getUser(id, login, no_create, no_login, error = false) {
|
||||
if ( this.destroyed )
|
||||
return null;
|
||||
|
||||
|
@ -130,18 +130,29 @@ export default class Room {
|
|||
else if ( this.users[login] && ! no_login )
|
||||
user = this.users[login];
|
||||
|
||||
else if ( no_create )
|
||||
if ( user && user.destroyed )
|
||||
user = null;
|
||||
|
||||
if ( ! user ) {
|
||||
if ( no_create )
|
||||
return null;
|
||||
|
||||
else
|
||||
user = new User(this.manager, this, id, login);
|
||||
}
|
||||
|
||||
if ( id && id !== user.id ) {
|
||||
// If the ID isn't what we expected, something is very wrong here.
|
||||
// Blame name changes.
|
||||
if ( user.id )
|
||||
if ( user.id ) {
|
||||
this.manager.log.warn(`Data mismatch for user #${id} -- Stored ID: ${user.id} -- Login: ${login} -- Stored Login: ${user.login}`);
|
||||
if ( error )
|
||||
throw new Error('id mismatch');
|
||||
|
||||
// Remove the old reference if we're going with this.
|
||||
if ( this.user_ids[user.id] === user )
|
||||
this.user_ids[user.id] = null;
|
||||
}
|
||||
|
||||
// Otherwise, we're just here to set the ID.
|
||||
user._id = id;
|
||||
this.user_ids[id] = user;
|
||||
|
|
|
@ -389,6 +389,8 @@ export const CheerEmotes = {
|
|||
token.hidden = true;
|
||||
}
|
||||
|
||||
text.push('');
|
||||
|
||||
} else
|
||||
text.push(segment);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ export default class RavenLogger extends Module {
|
|||
}
|
||||
}));
|
||||
})
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
this.raven = Raven;
|
||||
|
|
|
@ -351,7 +351,7 @@ export default class EmoteMenu extends Module {
|
|||
}
|
||||
|
||||
clickHeading() {
|
||||
if ( this.props.filter )
|
||||
if ( this.props.filtered )
|
||||
return;
|
||||
|
||||
const collapsed = storage.get('emote-menu.collapsed') || [],
|
||||
|
@ -440,7 +440,7 @@ export default class EmoteMenu extends Module {
|
|||
</div>
|
||||
<div class="tw-flex-grow-1" />
|
||||
{data.source || 'FrankerFaceZ'}
|
||||
<figure class={`tw-pd-l-05 ffz-i-${collapsed ? 'left' : 'down'}-dir`} />
|
||||
{filtered ? '' : <figure class={`tw-pd-l-05 ffz-i-${collapsed ? 'left' : 'down'}-dir`} />}
|
||||
</heading>) : null}
|
||||
{collapsed || this.renderBody(show_heading)}
|
||||
</section>)
|
||||
|
|
|
@ -147,13 +147,14 @@ export default class TabCompletion extends Module {
|
|||
getEmojiSuggestions(input, inst) {
|
||||
let search = input.slice(1).toLowerCase();
|
||||
const style = this.chat.context.get('chat.emoji.style'),
|
||||
results = [];
|
||||
results = [],
|
||||
has_colon = search.endsWith(':');
|
||||
|
||||
if ( search.endsWith(':') )
|
||||
search = search.slice(0, -1);
|
||||
if ( has_colon )
|
||||
search = search.slice(0,-1);
|
||||
|
||||
for(const name in this.emoji.names)
|
||||
if ( name.startsWith(search) ) {
|
||||
if ( has_colon ? name === search : name.startsWith(search) ) {
|
||||
const emoji = this.emoji.emoji[this.emoji.names[name]];
|
||||
if ( emoji && (style === 0 || emoji.has[style]) )
|
||||
results.push({
|
||||
|
|
|
@ -14,6 +14,7 @@ const BAD_ERRORS = [
|
|||
'unable to load',
|
||||
'error internal',
|
||||
'context deadline exceeded',
|
||||
'404',
|
||||
'500',
|
||||
'501',
|
||||
'502',
|
||||
|
|
|
@ -235,6 +235,17 @@ export function split_chars(str) {
|
|||
}
|
||||
|
||||
|
||||
export function pick_random(obj) {
|
||||
if ( ! obj )
|
||||
return null;
|
||||
|
||||
if ( ! Array.isArray(obj) )
|
||||
return obj[pick_random(Object.keys(obj))]
|
||||
|
||||
return obj[Math.floor(Math.random() * obj.length)];
|
||||
}
|
||||
|
||||
|
||||
export class SourcedSet {
|
||||
constructor() {
|
||||
this._cache = [];
|
||||
|
|
|
@ -73,7 +73,7 @@ export class Tooltip {
|
|||
} else if ( this.live ) {
|
||||
this._onMouseOver = e => {
|
||||
const target = e.target;
|
||||
if ( target && target.classList.contains(this.cls) )
|
||||
if ( target && target.classList && target.classList.contains(this.cls) )
|
||||
this._enter(target);
|
||||
};
|
||||
|
||||
|
@ -296,8 +296,8 @@ export class Tooltip {
|
|||
|
||||
|
||||
// Add everything to the DOM and create the Popper instance.
|
||||
this.parent.appendChild(el);
|
||||
tip.popper = new Popper(target, el, pop_opts);
|
||||
this.parent.appendChild(el);
|
||||
tip.visible = true;
|
||||
|
||||
if ( opts.onShow )
|
||||
|
|
|
@ -27,7 +27,8 @@ module.exports = {
|
|||
output: {
|
||||
chunkFilename: '[name].[chunkhash].js',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
jsonpFunction: 'ffzWebpackJsonp'
|
||||
jsonpFunction: 'ffzWebpackJsonp',
|
||||
crossOriginLoading: 'anonymous'
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ExtendedAPIPlugin()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue