Skip to content

Commit 2b93e3d

Browse files
Merge pull request #4302 from opral/add-icu-message-format
Add-icu-message-format
2 parents 22517d7 + b0afb2b commit 2b93e3d

File tree

27 files changed

+1788
-1273
lines changed

27 files changed

+1788
-1273
lines changed

.changeset/bright-grapes-rule.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@inlang/plugin-icu1": major
3+
---
4+
5+
Initial release
Lines changed: 92 additions & 0 deletions
Loading
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
og:title: "ICU MessageFormat v1 Plugin Now Available"
3+
og:description: "Full support for ICU MessageFormat v1 in inlang. Drop-in compatibility for plurals, selects, and formatters with your existing JSON files."
4+
og:image: ./assets/og-image.svg
5+
og:type: article
6+
---
7+
8+
![ICU MessageFormat v1 Plugin for Inlang](./assets/og-image.svg)
9+
10+
The ICU MessageFormat v1 plugin is now available for inlang. If your project uses ICU MessageFormat (the format behind `react-intl`, `@formatjs`, and many other i18n libraries), you can now use inlang's full tooling ecosystem.
11+
12+
## What's Supported
13+
14+
The plugin parses and exports ICU1 strings with full fidelity:
15+
16+
- **Plurals and selectordinal** including `offset` and exact matches (`=0`, `=1`)
17+
- **Select expressions** for gender and other categorical choices
18+
- **Formatter functions** like `number`, `date`, `time` with style parameters
19+
- **Octothorpe `#`** substitution inside plural/selectordinal cases
20+
21+
```json
22+
{
23+
"items": "{count, plural, offset:1 =0 {no items} one {# item} other {# items}}",
24+
"rank": "{place, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}"
25+
}
26+
```
27+
28+
## Get Started
29+
30+
Add the plugin to your `project.inlang/settings.json`:
31+
32+
```json
33+
{
34+
"modules": [
35+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-icu1@latest/dist/index.js"
36+
],
37+
"plugin.inlang.icu-messageformat-1": {
38+
"pathPattern": "./messages/{locale}.json"
39+
}
40+
}
41+
```
42+
43+
That's it. Your existing JSON files work immediately. No migration required.
44+
45+
[Read the full documentation](https://inlang.com/m/p7c8m1d2)

blog/table_of_contents.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
[
2+
{
3+
"path": "./icu-messageformat-v1-plugin/index.md",
4+
"slug": "icu-messageformat-v1-plugin",
5+
"date": "2026-02-09",
6+
"authors": ["samuelstroschein"]
7+
},
28
{
39
"path": "./human-readable-message-ids/index.md",
410
"slug": "human-readable-message-ids",

packages/cli/marketplace-manifest.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@
3333
"pricing": "free",
3434
"publisherName": "inlang",
3535
"publisherIcon": "https://inlang.com/favicon/safari-pinned-tab.svg",
36+
"website": "https://www.npmjs.com/package/@inlang/cli",
37+
"repository": "https://github.com/opral/inlang/tree/main/packages/cli",
3638
"license": "Apache-2.0"
3739
}

packages/marketplace-registry/registry.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"632iow21": "https://raw.githubusercontent.com/opral/inlang/refs/heads/main/packages/plugins/m-function-matcher/marketplace-manifest.json",
1515
"698iow33": "https://raw.githubusercontent.com/opral/inlang/refs/heads/main/packages/plugins/t-function-matcher/marketplace-manifest.json",
1616
"193hsyds": "https://raw.githubusercontent.com/opral/inlang/refs/heads/main/packages/plugins/next-intl/marketplace-manifest.json",
17+
"p7c8m1d2": "https://raw.githubusercontent.com/opral/inlang/refs/heads/main/packages/plugins/icu1/marketplace-manifest.json",
1718
"neh2d6w7": "https://cdn.jsdelivr.net/npm/inlang-plugin-xcstrings@latest/marketplace-manifest.json",
1819
"3gk8n4n4": "https://raw.githubusercontent.com/opral/inlang/refs/heads/inlang-v1/inlang/source-code/github-lint-action/marketplace-manifest.json",
1920
"y0eo8f66": "https://raw.githubusercontent.com/opral/inlang/refs/heads/inlang-v1/inlang/source-code/message-lint-rules/emptyPattern/marketplace-manifest.json",

packages/plugins/i18next/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
},
1616
"repository": {
1717
"type": "git",
18-
"url": "https://github.com/opral/inlang"
18+
"url": "https://github.com/opral/inlang",
19+
"directory": "packages/plugins/i18next"
1920
},
2021
"scripts": {
2122
"dev": "node ./build.js",

packages/plugins/icu1/README.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
og:title: ICU MessageFormat v1 Plugin
3+
og:description: Storage plugin for inlang that reads and writes ICU MessageFormat v1 JSON files. Supports selects, plurals, selectordinal, offsets, and formatter styles.
4+
---
5+
6+
# ICU MessageFormat v1 Plugin
7+
8+
The ICU MessageFormat v1 plugin is a storage plugin for inlang. It reads and writes ICU1 strings in JSON files per locale.
9+
It targets ICU MessageFormat v1 (a.k.a. ICU MessageFormat) and maps it onto inlang's data model so selectors and variants are preserved.
10+
11+
## Features
12+
13+
- Parses ICU1 messages using `@messageformat/parser`.
14+
- Supports `select`, `plural`, and `selectordinal`, including exact matches (`=n`) and `offset`.
15+
- Supports `#` (octothorpe) inside plural/selectordinal cases.
16+
- Supports formatter functions (e.g. `number`, `date`, `time`, `spellout`, `ordinal`, `duration`) with style parameters.
17+
- Exports ICU1 strings back from inlang data.
18+
19+
## Installation
20+
21+
Install the plugin in your Inlang Project by adding it to your `modules` in `project.inlang/settings.json` and configure `pathPattern`.
22+
23+
```diff
24+
// project.inlang/settings.json
25+
{
26+
"modules": [
27+
+ "https://cdn.jsdelivr.net/npm/@inlang/plugin-icu1@latest/dist/index.js"
28+
],
29+
+ "plugin.inlang.icu-messageformat-1": {
30+
+ "pathPattern": "./messages/{locale}.json"
31+
+ }
32+
}
33+
```
34+
35+
## Configuration
36+
37+
Configuration happens in `project.inlang/settings.json` under `"plugin.inlang.icu-messageformat-1"`.
38+
39+
### `pathPattern`
40+
41+
You can define a single `pathPattern` or provide an array of patterns. The placeholder should be `{locale}`.
42+
43+
#### Single path pattern example
44+
45+
```json
46+
{
47+
"plugin.inlang.icu-messageformat-1": {
48+
"pathPattern": "./messages/{locale}.json"
49+
}
50+
}
51+
```
52+
53+
#### Multiple path patterns example
54+
55+
```json
56+
{
57+
"plugin.inlang.icu-messageformat-1": {
58+
"pathPattern": ["./defaults/{locale}.json", "./product/{locale}.json"]
59+
}
60+
}
61+
```
62+
63+
> [!NOTE]
64+
> When exporting, all messages are written to every path pattern in the array (one file per pattern and locale). Multiple patterns are a one-way merge for import.
65+
66+
## Messages
67+
68+
ICU1 files contain key-value pairs with ICU MessageFormat strings.
69+
70+
```json
71+
// messages/en.json
72+
{
73+
"hello_world": "Hello World!",
74+
"greeting": "Good morning {name}!",
75+
"likes": "You have {count, plural, one {# like} other {# likes}}"
76+
}
77+
```
78+
79+
### Plurals and selectordinal
80+
81+
```json
82+
{
83+
"items": "{count, plural, offset:1 =0 {no items} one {# item} other {# items}}",
84+
"rank": "{place, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}"
85+
}
86+
```
87+
88+
### Select
89+
90+
```json
91+
{
92+
"gender": "{gender, select, male {He} female {She} other {They}}"
93+
}
94+
```
95+
96+
### Escaping
97+
98+
ICU1 uses apostrophes to escape literals. To include literal braces, wrap them in apostrophes:
99+
100+
- `'{'
101+
- `'}'`
102+
103+
If you need a literal apostrophe, use `''` (two single quotes).
104+
105+
## Caveats
106+
107+
- Export is canonicalized. Output is semantically equivalent, but whitespace and formatting may differ from the original source.
108+
- Tags/markup are treated as plain text by the parser.
Lines changed: 12 additions & 0 deletions
Loading
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "https://inlang.com/schema/marketplace-manifest",
3+
"id": "plugin.inlang.icu-messageformat-1",
4+
"icon": "./assets/icon.svg",
5+
"displayName": {
6+
"en": "ICU MessageFormat v1"
7+
},
8+
"description": {
9+
"en": "Storage plugin for inlang that reads and writes ICU MessageFormat v1 JSON files with support for selects, plurals, selectordinal, offsets, and formatter styles."
10+
},
11+
"pages": {
12+
"/": "./README.md"
13+
},
14+
"keywords": [
15+
"icu",
16+
"messageformat",
17+
"json",
18+
"storage",
19+
"messages",
20+
"plugin",
21+
"javascript",
22+
"website"
23+
],
24+
"publisherName": "inlang",
25+
"publisherIcon": "https://inlang.com/favicon/safari-pinned-tab.svg",
26+
"license": "Apache-2.0",
27+
"module": "https://cdn.jsdelivr.net/npm/@inlang/plugin-icu1@latest/dist/index.js"
28+
}

0 commit comments

Comments
 (0)