Announcement
The Announcement module allows your app to show a message to everyone in the organization, in the header alert or on a glossary page. Crowdin requests the announcements each time it renders one of these placements and passes the reader’s context, so your app decides what to show per request.
Sample
Section titled “Sample”import crowdinModule from '@crowdin/app-project-module';
const configuration = { baseUrl: 'https://123.ngrok.io', clientId: 'clientId', clientSecret: 'clientSecret', name: 'Sample App', identifier: 'sample-app', description: 'Sample App description', port: 8080, dbFolder: import.meta.dirname, imagePath: import.meta.dirname + '/logo.png', announcement: [ { placement: 'header-alert', getAnnouncements: async () => [ { id: 'release-freeze-2024-05', text: 'Merges are frozen until Monday.', dismissible: false, expiresAt: '2024-05-27T08:00:00Z', actionLabel: 'Release schedule', actionUrl: 'https://wiki.example.com/release-schedule', } ] }, { placement: 'glossary', getAnnouncements: async ({ glossaryId }) => [ { id: 'glossary-guidelines-v3', text: `Follow the naming rules before adding terms to glossary ${glossaryId}.`, dismissible: true, } ] } ]};
crowdinModule.createApp(configuration);import crowdinModule from '@crowdin/app-project-module';import type { Config } from '@crowdin/app-project-module';
const configuration: Config = { baseUrl: 'https://123.ngrok.io', clientId: 'clientId', clientSecret: 'clientSecret', name: 'Sample App', identifier: 'sample-app', description: 'Sample App description', port: 8080, dbFolder: import.meta.dirname, imagePath: import.meta.dirname + '/logo.png', announcement: [ { placement: 'header-alert', getAnnouncements: async () => [ { id: 'release-freeze-2024-05', text: 'Merges are frozen until Monday.', dismissible: false, expiresAt: '2024-05-27T08:00:00Z', actionLabel: 'Release schedule', actionUrl: 'https://wiki.example.com/release-schedule', } ] }, { placement: 'glossary', getAnnouncements: async ({ glossaryId }) => [ { id: 'glossary-guidelines-v3', text: `Follow the naming rules before adding terms to glossary ${glossaryId}.`, dismissible: true, } ] } ]};
crowdinModule.createApp(configuration);Configuration
Section titled “Configuration”| Parameter | Description | Allowed values | Default value |
|---|---|---|---|
key | Raw module key, sent as jwt.module. Required when several modules share one placement. The derived key comes from the placement alone, so reordering the list never changes it. | String | <identifier>-announcement-<placement> |
name | Module name shown in the installation dialog. | String | derived from placement, e.g. Header announcements |
placement | Where Crowdin shows this module’s items. Declare one module per placement, because an admin grants the audience per module on install. | 'header-alert' | 'glossary' | – |
getAnnouncements | Async callback that returns what to show for the given context. | Function | – |
environments | Restrict the module to crowdin and/or crowdin-enterprise. | 'crowdin' | 'crowdin-enterprise' or array | both |
getAnnouncements Function
Section titled “getAnnouncements Function”This function is called each time Crowdin renders the declared placement, with the context of the user looking at the page.
Parameters
Section titled “Parameters”placement- The placement being rendered:'header-alert'or'glossary'.organizationId- Numeric Crowdin organization ID, read from the verified JWT. Safe to key your own storage by.userId- Numeric ID of the user looking at the page. The JWT is cached per organization and module, so it identifies the installing user rather than the viewer — which is why this one arrives in the request body instead. Use it to choose what to show, not to decide who may see it: Crowdin has already authorized the reader before calling.glossaryId- Numeric glossary ID. Only sent for theglossaryplacement.client- Crowdin API client.context- Context object.
Return Value
Section titled “Return Value”The function should return an array of announcements, most important first. An empty array means nothing to show, which is the normal case rather than an error.
| Field | Description | Required |
|---|---|---|
id | Keys the reader’s dismiss state. Changed text under a new id shows again to everyone who closed the old one. Up to 255 characters. | yes |
text | Plain text. Crowdin renders no markup; the browser links bare http/https addresses. | yes |
dismissible | Whether the reader can close it. A non-dismissible announcement stays until it expires. | yes |
expiresAt | ISO 8601 timestamp after which Crowdin stops showing it. | no |
actionLabel | Label of the call-to-action link. Up to 255 characters. | only with actionUrl |
actionUrl | Target of the call-to-action link. https:// only, up to 2048 characters. | only with actionLabel |
Omit an optional field you have no value for: null, '' and [] are rejected rather than read as “no value”, and the announcement carrying one is skipped.
Crowdin validates each announcement separately and takes at most 10 per module. An invalid announcement is skipped and the rest still show. If the app fails to answer, Crowdin skips the request silently and the page renders unchanged.
Multiple Announcement Modules
Section titled “Multiple Announcement Modules”You can register multiple announcement modules in a single app by providing an array. One keyless module per placement is enough, as in the sample above. Two modules on the same placement need an explicit key each, because the derived key comes from the placement alone:
const configuration = { // ... other configuration announcement: [ { key: 'release-notes', name: 'Release notes', placement: 'header-alert', getAnnouncements: async () => [] }, { key: 'incidents', name: 'Incidents', placement: 'header-alert', getAnnouncements: async () => [] } ]};