Translating
There are two ways to translate phrases:
- Manually translate generated JSON file.
- Use the app editor Swiftyper Translations.
Command to generate missing translation hashes from collected source strings:
php ./vendor/bin/fbt generate-translations --src=./path/to/fbt/.source_strings.json --translation-input=./path/to/translation_input.json
# or
php ./vendor/bin/fbt generate-translations --src=./path/to/fbt/.source_strings.json --translations=./path/to/translations/*.json
Options:
| name | default | description |
|---|---|---|
| --src | ./.source_strings.json | Path to collected source strings file |
| --translation-input | ./translation_input.json | Path to translation input file |
--translations=[path] | none | The translation files containing translations. E.g. --translations=./path/to/translations/*.json |
| --sort-by-hash | no | Sort translation entries by hash key (both existing and new), for cleaner diffs of committed files |
Translation files have to be named by their locale (e.g. de_DE.json), other files are skipped.
Each file contains a translation group ({"fb-locale": "de_DE", "translations": {...}}), so it can be passed to translate --translations.
Without --translations, the missing translations are written to the --translation-input file.
The translations are merged with the collected strings like prepare-translations of fbtee:
new strings are added with their source text, their description and "status": "new", and translations of strings that are no longer collected are removed.
Entries marked as new are not translated yet, so translate skips them (remove the status once an entry is translated).
The translations by hash (--jenkins, --fbt-hash-module and translatedFbts.json) omit the strings without a translation, so the source string is used.
Command to convert provided translations to jenkins:
php ./vendor/bin/fbt translate --path=./path/to/fbt/ --stdin < translation_input.json
# or
php ./vendor/bin/fbt translate --path=./path/to/fbt/ --translations=./path/to/translations/*.json
Options:
| name | default | description |
|---|---|---|
| --path | none | Path to export translation output (Cache storage path - must be same as in configuration) |
| --pretty | no | Pretty print the translation output |
--translations=[path] | none | The translation files containing translations. E.g. --translations=/path/to/translations/*.json |
| --stdin < translation_input.json | none | Instead of reading translation files and source file separately, read monolithic JSON file from STDIN |
Writing to the standard output
Without --path, the translations are written as JSON to the standard output instead of
translatedFbts.json:
php ./vendor/bin/fbt translate --source-strings=./path/to/fbt/.source_strings.json --translations=./path/to/translations/*.json --jenkins
php ./vendor/bin/fbt translate --stdin --jenkins -o=./path/to/output/ < translation_input.json
| name | default | description |
|---|---|---|
--source-strings=[path] | .source_strings.json | The file containing source strings |
--translations=[paths] | none | The translation files (comma separated or globs), a translation group per file |
| --stdin | no | Read a monolithic JSON payload ({phrases, translationGroups}) from STDIN |
| --jenkins | no | Output the translations by locale and callsite hash ({"cs_CZ": {"<hash>": <payload>}}), like translatedFbts.json. Without it, the output is a list of translation groups ([{"fb-locale": ..., "translatedPhrases": [...]}]) |
--fbt-hash-module=[path] | none | Like --jenkins, with the hashes computed by a PHP file returning a callable |
--output-dir=[dir], -o=[dir] | none | Write one <locale>.json file per locale into the directory instead of the standard output |
--output-file=[file] | none | Write the combined output of all locales into a single file instead of the standard output |
| --strict | no | Stop on missing translations: every collected string needs a completed translation in each translation group (missing entries, entries marked as new and entries without translations fail). An explicit empty translation is valid |
| --pretty | no | Pretty print the translation output |
JSON schema:
In addition to the below example, the translation_input.json
provided in our tests
is a good reference on the "schema" used for the translations.
{
"phrases": [{
"hashToLeaf": {
<text_hash>: {"text": <text>, "desc": <description>},
...
},
"jsfbt": {"t": <leaf or table>, "m": <metadata>}
}],
...
"translationGroups": [{
"fb-locale": "xx_XX",
"translations": {
<translation_hash>: {
"tokens": [<token1>, ..., <tokenN>],
"types": [<variationType1>, ..., <variationTypeN>]
"translations": [{
"translation": <translation1>,
"variations": [variationValue1,...,variationValueN]
},
...,
]
}
}
}]
}
The <text_hash> and <translation_hash> correspond in the above example.
That is translations[<hash>] is the translation entry for
phrases.hashToLeaf[<hash>].
Translations of strings with inner strings (e.g. {=Learn more}) keep these tokens as they are.
Here tokens, types and variations are all associative arrays. That is, in
the above example, types[i] represents the variation type (or mask) of
tokens[i] and variations[i] is the variation value of token[i] for the
given translation entry.
Variation types
Variation types can be one of
IntlVariations::BITMASK_NUMBER: 28
IntlVariations::BITMASK_GENDER: 3
This signifies what the given token can variate on. Token types of type GENDER can be:
IntlVariations::GENDER_MALE: 1
IntlVariations::GENDER_FEMALE: 2
IntlVariations::GENDER_UNKNOWN: 3
while token types of NUMBER can be:
IntlVariations::NUMBER_ONE: 4
IntlVariations::NUMBER_TWO: 8
IntlVariations::NUMBER_MANY: 12
IntlVariations::NUMBER_ZERO: 16
IntlVariations::NUMBER_FEW: 20
IntlVariations::NUMBER_OTHER: 24