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.

A module shows as module__myapp_thing on the administrator restrictions screen

Every module needs a language string named module__<app>_<module>. Leave it out and Invision prints the name of the missing string in place of the module's name — with no error, nothing in the logs, and nothing on the application's own screens to hint at it.

The symptom

Members > Staff > Administrators > Edit Restrictions lists your application's sections as raw keys:

module__myapp_backup
module__myapp_prompt

The restrictions themselves work correctly. Ticking and saving behaves exactly as it should — the only thing wrong is the label. On a site with a dozen applications installed, an administrator cannot even tell which application an unnamed row belongs to.

The cause

A module is a node, and its title comes from Module::get__title() in system/Application/Module.php:

protected function get__title(): string
{
    $key = "module__{$this->application}_{$this->key}";
    return Member::loggedIn()->language()->addToStack( $key );
}

The key is built from the application directory and the module directory — not from anything you declare. A module at applications/myapp/modules/admin/backup/ needs module__myapp_backup, whether or not you ever refer to that string yourself.

Why it is silent

This is the part worth remembering, because it generalises. addToStack() and get() fail in opposite ways:

$lang->addToStack( 'missing_key' );   // returns the string "missing_key"
$lang->get( 'missing_key' );          // throws UnderflowException

addToStack() is the safe one, so a missing key degrades to printing itself rather than breaking the page. That is usually what you want — but it also means nothing anywhere reports the fault. There is no exception, no log entry and no failed request. The only way to find it is to look at the screen.

The reverse case is worth knowing too: a core/Notifications extension missing its string is read with get(), and takes the entire ACP Notification Settings screen down for every application on the site. Same class of mistake, opposite volume.

Finding them

Every module in data/modules.json needs a matching key in dev/lang.php. Both areas count — admin and front:

'module__myapp_backup' => "Backup & Restore",
'module__myapp_prompt' => "Prompts",

To check a built application without installing it:

tar -xOf myapp-1.0.1.tar data/lang.xml | grep module__

Compare that against the module names in data/modules.json. Anything present there and absent from the language file will appear as a raw key.

If you are fixing it in a released application

Adding the string is the easy half. Getting it to people who already installed the application is the half that catches you out: correcting the file and re-uploading it under the same version number reaches nobody. Invision compares versions on upload and silently ignores one that is not newer, so the fix serves new downloads while every existing installation stays exactly as it was.

The fix has to ship as a version bump. Language strings need no upgrade step of their own — on upgrade Invision calls installLanguages(), which imports data/lang.xml in full, so a bumped version carries new keys automatically. The per-version setup/upg_<version>/lang.json is consulted only for strings you have removed.


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.