Skip to content

Commit faf5a70

Browse files
authored
chore: update the readme and changelog in preparation for release (#30)
1 parent 31ff399 commit faf5a70

2 files changed

Lines changed: 188 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8-
## 0.3.0 - TBD
8+
## 0.3.0 - 2021-12-16
99

1010
### Added
1111

@@ -24,6 +24,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2424
- Remove `$config` argument from `Format\ReaderInterface`
2525
- Remove `$localeResolved` argument from `Format\ReaderInterface`
2626
- Change type on `$options` argument in `Format\WriterInterface` from `MessageExtractorOptions` to a dedicated `WriterOptions` type
27+
- The `MessageLoader` constructor now accepts the following values for the `$formatReader` parameter:
28+
- Fully-qualified class name for a class that implements `FormatPHP\Format\ReaderInterface`
29+
- An already-instantiated instance object of `FormatPHP\Format\ReaderInterface`
30+
- A callable with the shape `callable(mixed[]): FormatPHP\MessageCollection`
31+
- The path to a script that returns a callable with this shape
2732

2833
### Deprecated
2934

README.md

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,66 @@ echo $formatphp->formatMessage([
8282
]);
8383
```
8484

85+
### Rich Text Formatting (Use of Tags in Messages)
86+
87+
While the ICU message syntax does not prohibit the use of HTML tags in formatted
88+
messages, HTML tags provide an added level of difficulty when it comes to parsing
89+
and validating ICU formatted messages. By default, FormatPHP does not support
90+
HTML tags in messages.
91+
92+
Instead, [like FormatJS](https://formatjs.io/docs/core-concepts/icu-syntax#rich-text-formatting),
93+
we support embedded rich text formatting using custom tags and callbacks. This
94+
allows developers to embed as much text as possible so sentences don't have to
95+
be broken up into chunks. These are not HTML or XML tags, and attributes are
96+
not supported.
97+
98+
```php
99+
$formatphp->formatMessage([
100+
'id' => 'priceMessage',
101+
'defaultMessage' => <<<'EOD'
102+
Our price is <boldThis>{price, number, ::currency/USD precision-integer}</boldThis>
103+
with <link>{pct, number, ::percent} discount</link>
104+
EOD,
105+
], [
106+
'price' => 29.99,
107+
'pct' => 2.5,
108+
'boldThis' => fn ($text) => "<strong>$text</strong>",
109+
'link' => fn ($text) => "<a href=\"/discounts/1234\">$text</a>",
110+
]);
111+
```
112+
113+
For an `en-US` locale, this will produce a string similar to the following:
114+
115+
Our price is <strong>$30</strong> with <a href="/discounts/1234">2.5% discount</a>
116+
117+
For rich text elements used throughout your application, you may provide a map
118+
of tag names to rich text formatting functions, when configuring FormatPHP.
119+
120+
```php
121+
$config = new Config(
122+
locale: new Intl\Locale('en-US'),
123+
defaultRichTextElements: [
124+
'em' => fn ($text) => "<em class=\"myClass\">$text</em>",
125+
'strong' => fn ($text) => "<strong class=\"myClass\">$text</strong>",
126+
],
127+
);
128+
```
129+
130+
Using this approach, consider the following formatted message:
131+
132+
```php
133+
$formatphp->formatMessage([
134+
'id' => 'welcome',
135+
'defaultMessage' => 'Welcome, <strong><em>{name}</em></strong>',
136+
], [
137+
'name' => 'Sam',
138+
]);
139+
```
140+
141+
It will produce a string similar to the following:
142+
143+
Welcome, <strong class="myClass"><em class="myClass">Sam</em></strong>
144+
85145
### Using MessageLoader to Load Messages
86146

87147
We also provide a message loader to load translation strings from locale files
@@ -134,7 +194,10 @@ application source code, saving them to JSON files that your translation
134194
management system can use.
135195

136196
```shell
137-
./vendor/bin/formatphp extract --out-file=locales/en.json 'src/**/*.php' 'src/**/*.phtml'
197+
./vendor/bin/formatphp extract \
198+
--out-file=locales/en.json \
199+
'src/**/*.php' \
200+
'src/**/*.phtml'
138201
```
139202

140203
In order for message extraction to function properly, we have a few rules that
@@ -167,6 +230,124 @@ At least one of `id` or `defaultMessage` must be present.
167230
> ```
168231
> --additional-function-names='formatMessage, myCustomFormattingFunction'
169232
> ```
233+
>
234+
> To see all available options, view the command help with `formatphp help extract`.
235+
236+
### Pseudo Locales
237+
238+
Pseudo locales provide a way to test an application with various types of
239+
characters and string widths. FormatPHP provides a tool to convert any locale
240+
file to a pseudo locale for testing purposes.
241+
242+
Given the English message `my name is {name}`, the following table shows how
243+
each supported pseudo locale will render this message.
244+
245+
| Locale | Message |
246+
|---------|----------------------------------------------|
247+
| `en-XA` | `ṁẏ ńâṁè íś {name}` |
248+
| `en-XB` | `[!! ṁẏ ńâṁṁṁè íííś !!]{name}` |
249+
| `xx-AC` | `MY NAME IS {name}` |
250+
| `xx-HA` | `[javascript]my name is {name}` |
251+
| `xx-LS` | `my name is {name}SSSSSSSSSSSSSSSSSSSSSSSSS` |
252+
253+
To convert a locale to a pseudo locale, use the `formatphp pseudo-locale` command.
254+
255+
```shell
256+
./vendor/bin/formatphp pseudo-locale \
257+
--out-file locales/en-XA.json \
258+
locales/en.json \
259+
en-XA
260+
```
261+
262+
> ℹ️ To see all available options, view the command help with
263+
> `formatphp help pseudo-locale`.
264+
265+
## TMS Support
266+
267+
A [translation management system](https://en.wikipedia.org/wiki/Translation_management_system),
268+
or TMS, allows translators to use your default locale file to create translations
269+
for all the other languages your application supports. To work with a TMS, you
270+
will extract the formatted strings from your application to send to the TMS.
271+
Often, a TMS will specify a particular document format they require.
272+
273+
Out of the box, FormatPHP supports the following formatters for integration with
274+
third-party TMSes. Supporting a TMS does not imply endorsement of that
275+
particular TMS.
276+
277+
| TMS | `--format` |
278+
|--------------------------------------------------------------------------------------|-------------|
279+
| [Crowdin Chrome JSON](https://support.crowdin.com/file-formats/chrome-json/) | `crowdin` |
280+
| [Lingohub](https://lingohub.com/developers/resource-files/json-localization/) | `simple` |
281+
| [locize](https://docs.locize.com/integration/supported-formats#json-flatten) | `simple` |
282+
| [Phrase](https://help.phrase.com/help/simple-json) | `simple` |
283+
| [SimpleLocalize](https://simplelocalize.io/docs/integrations/format-js-cli/) | `simple` |
284+
| [Smartling ICU JSON](https://help.smartling.com/hc/en-us/articles/360008000733-JSON) | `smartling` |
285+
286+
Our default formatter is `formatphp`, which mirrors the output of default
287+
formatter for FormatJS.
288+
289+
### Custom Formatters
290+
291+
You may provide your own formatter using our interfaces. You will need to
292+
create a writer for the format. Optionally, you may create a reader, if using
293+
our message loader or the `formatphp pseudo-locale` command with the
294+
`--in-format` option.
295+
296+
* The writer must implement `FormatPHP\Format\WriterInterface` or be a callable
297+
of the shape `callable(FormatPHP\DescriptorCollection, FormatPHP\Format\WriterOptions): mixed[]`.
298+
* The reader must implement `FormatPHP\Format\ReaderInterface` or be a
299+
callable of the shape `callable(mixed[]): FormatPHP\MessageCollection`.
300+
301+
To use your custom writer with `formatphp extract`, pass the fully-qualified
302+
class name to `--format`, or a path to a script that returns the callable.
303+
304+
For example, given the script `my-writer.php` with the contents:
305+
306+
```php
307+
<?php
308+
309+
use FormatPHP\DescriptorCollection;
310+
use FormatPHP\Format\WriterOptions;
311+
312+
require_once 'vendor/autoload.php';
313+
314+
/**
315+
* @return mixed[]
316+
*/
317+
return function(DescriptorCollection $descriptors, WriterOptions $options): array {
318+
// Custom writer logic to create an array of data we will write
319+
// as JSON to a file, which your TMS will be able to use.
320+
};
321+
```
322+
323+
You can call `formatphp extract` like this:
324+
325+
```shell
326+
./vendor/bin/formatphp extract \
327+
--format='path/to/my-writer.php' \
328+
--out-file=locales/en.json \
329+
'src/**/*.php'
330+
```
331+
332+
To use a custom reader with the message loader:
333+
334+
```php
335+
$messageLoader = new MessageLoader(
336+
// The path to your locale JSON files (i.e., en.json, es.json, etc.).
337+
messagesDirectory: '/path/to/app/locales',
338+
// The configuration object created earlier.
339+
config: $config,
340+
// Pass your custom reader through the formatReader parameter.
341+
formatReader: MyCustomReader::class,
342+
);
343+
```
344+
345+
The `formatReader` parameter accepts the following:
346+
347+
* Fully-qualified class name for a class that implements `FormatPHP\Format\ReaderInterface`
348+
* An already-instantiated instance object of `FormatPHP\Format\ReaderInterface`
349+
* A callable with the shape `callable(mixed[]): FormatPHP\MessageCollection`
350+
* The path to a script that returns a callable with this shape
170351

171352
## Contributing
172353

0 commit comments

Comments
 (0)