Better handling of "key" based messages in po files
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 5.9k
- Forks
- 457
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 16
Description
### Problem Description
Currently messages with explicitly defined id stored in PO files in very hacky way:
```po
#. js-lingui-explicit-id
msgctxt "my context"
msgid "custom.id"
msgstr ""
msgctxt "my context"
msgid "with generated id"
msgstr ""
```
The id is printed into the `msgid`, also we need to add a flag such `js-lingui-explicit-id` to tell formatter that on deserialize it should use this `msgid` as-is as id and not treat it as a source text.
The entry lacks the original message, and despite we can print this message into the translation as i did [here](https://github.com/lingui/js-lingui/pulls), it still not following the spec.
This brings a lot of hassle, because this is far from the original gettext spec and probably not working problem-free with any known TMS on the market.
### Proposed Solution
I dig into integration with translation.io [here](https://github.com/lingui/js-lingui/pull/2388) and took inspiration from how they approached it
Instead of writing `key` into the `msgid` we can write it into the context:
```po
msgctxt "custom.id"
msgid "Message with custom id"
msgstr ""
```
According to the gettext spec `msgid + msgctxt` creates a uniq pair, so adding `key` to context will do the trick, and will create a uniq entry only for that message.
This is fully following spec, no hacks, no tricks. All TMS should work with this approach.
## Opened questions?
### What should we do with the original context if provided?
By the spec, purpose of the context is to differentiate (creatte two separate entries) messages with the same source text. So it's exactly the same what `id` is doing. If the developer wants to leave a comment for the translator - better to use comment property.
So one solution is ignore originally passed context, and for example print a warning when both `id` and `context` provided.
Option number 2 - concatenate - (id + original context) - but honestly, i'm voting for more restricted approach and not giving a confusing options.
### How to identify during de-serialization that `context` is a custom key and not a real context?
I'm thinking of adding a special prefix to that context
```po
msgctxt "lingui-id:custom.id"
msgid "Message with custom id"
msgstr ""
```
So if the string started from the `lingui-id:` - it's a custom id, take it as-is. If it's not, use it as context for `generateMessageId(source, context)`
### How to migrate catalogs?
For a long time i advocated for not using `key-based` approach, but i admit that there still might be a group of developers using it.
We need a migrate comand, i know that `lingui-extract` already has some migrate functionality, but this is not enough. I'm thinkinh of creating an another command (or package) with it's own config just for migration.
The migration from code-perspective is straight forward, we need to load catalogs using old version with one parameters, and then save with a another one. I'm thinking of something like:
```ts
// migrator.config.js
import {defineConfig} from "@lingui/catalogs-migrator"
import {formatter as po} from "@lingui/format-po"
export default defineConfig({
from: po({...oldSettings}),
to: po({...newSettings}),
})
```
```sh
lingui-migrator --config migrator.config.js
```
### Alternatives Considered
Leave it as-is
### Additional Context
_No response_
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the existing PO formatter and the lingui-extract migration functionality mentioned in the issue, then compare the proposed context-prefix approach with current serialization and deserialization. Review the catalogs-migrator configuration and CLI examples, and consider the original-context and legacy-catalog cases. Done means key-based entries follow the gettext format and existing catalogs can be migrated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- localization, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100