Skip to content
View in the app

A better way to browse. Learn more.

ernestdefoe.online

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
ernestdefoe.online

Extensions, themes & support for Flarum and Invision Community

Vibe coding for the community web. Report a bug, request a feature, or dig into the source — this is where the tools you use get built, in the open.

We do custom Bespoke Invision Community apps. If you have an idea for something you want then use the contact form to get in touch with us.
Knowledge base

Things that cost me a day, so they cost you none

Working notes from building Invision Community and Flarum applications. Mostly the failures that give no error at all — the ones where everything installs cleanly and quietly does the wrong thing.

92 articles

Invision Community 5

86 articles

Extensions and contracts

39

What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.

Languages and text

5

The string table, translation, and the places where text does not appear where you expected it to.

Theming, templates and forms

9

Theme hooks, CSS that survives both colour schemes, and building forms that do not throw on render.

Background work and scheduled tasks

5

The queue system, work that has to happen after the response, and jobs that finish without doing anything.

Data, settings and storage

11

The database layer, settings, tags, file storage, and backing up a live site.

AI features and expectations

5

What these features do, what they cost, and what buyers reasonably but wrongly assume they do.

Application structure and releases

11

The JSON files an application is made of, versioning and upgrade steps, and testing from the command line.

Realtime, chat and calls

1

WebSocket gateways, relays and the server-side pieces live features depend on — where "it works when I test it" and "it works for your members" are different claims.

Nothing matches that.

Why your app shows menutab__content or module__myapp_thing to customers

Somewhere in your application a heading reads menutab__content, or a breadcrumb reads module__myapp_thing, or the administrator restrictions screen lists raw keys where names should be. The page works. Nothing is logged. It simply looks unfinished to whoever is paying you.

Invision Community renders a missing language key as the key itself. That is a sensible fallback and a poor advertisement, and there are two distinct ways to walk into it.

1. Keys you forgot to define

Every module in data/modules.json needs a module__<app>_<module> string. They appear on the administrator restrictions screen and in front-end breadcrumbs, so a missing one is customer-visible, not just staff-visible.

{
    "admin": { "settings": { ... } },
    "front": { "podcast":  { ... } }
}

/* needs BOTH */
'module__myapp_settings' => "My App",
'module__myapp_podcast'  => "My App",

Audit it in one line rather than trusting your memory:

python3 -c "
import json
m=json.load(open('applications/myapp/data/modules.json'))
lang=open('applications/myapp/dev/lang.php').read()
for area,mods in m.items():
    for mod in mods:
        k='module__myapp_%s' % mod
        print(k, 'present' if k in lang else 'MISSING')"

This was written up once here, then walked into twice more on later applications — including one that had already been published, where the restrictions screen used to decide which staff can touch what was listing internal keys. It is worth running on every app, not remembering.

2. Keys that were never yours to define

The second kind is subtler. You reference something that does not exist, and because the fallback is the key itself, it looks like a missing translation rather than a wrong value.

data/acpmenu.json puts your menu under a tab. There are exactly six, and content is not one of them:

grep -oE "menutab__[a-z]+" applications/core/dev/lang.php | sort -u
#   menutab__community
#   menutab__core
#   menutab__customization
#   menutab__members
#   menutab__stats
#   menutab__support

Use community for anything member-facing, members for member management, customization for appearance. Inventing content because it describes your app best produces a sidebar heading that reads menutab__content, and no error at all.

Related: addToStack returns a placeholder, not text

A third way to get a machine-readable string in front of a person, and the one most likely to end up in stored data rather than on a page. addToStack() returns a token for the language stack to substitute at render time. In a task, a queue, a CLI script or a feed generator, nothing renders — so the token is what gets saved:

/* wrong in a task: writes a 32-character hash as the topic title */
$topic->title = $lang->addToStack( 'my_title' );

/* right: returns the string, and throws if the key is missing */
$title = \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( 'my_title' );

See addToStack() often returns a placeholder, not translated text for the full version. Between them these three account for most raw strings a customer ever sees.

The reliable way to catch all of it

None of these throw, none fail a lint, and none fail a test that checks a page returns 200. Look at the rendered screen. Capturing screenshots of your own AdminCP and front-end pages as a matter of routine — not only when a listing needs images — is how every one of these was actually found.



User Feedback

Recommended Comments

There are no comments to display.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.