lingui / js-lingui

🌍 📖 A readable, automated, and optimized (3 kb) internationalization for JavaScript
https://lingui.dev
MIT License
4.38k stars 371 forks source link

Support additional + bespoke metadata on messages #1969

Closed AndrewIngram closed 3 days ago

AndrewIngram commented 1 month ago

(I imagine this would apply to all APIs where messages are defined).

We have need to provide additional structured data to our translators that don't really fit within the current context and comment properties. We're mainly thinking about some pre-defined tags that such as "Don't translate" (for when we went to instrumented strings early, but don't want translation work to begin yet), or feature name.

This would require that users make/derive their own catalog formats to actually take advantage of the data, but that seems reasonable enough.

didier-84 commented 1 month ago

For PO catalogs, these metadata could be stored as flags (like fuzzy and other pre-defined keywords), so your suggestion makes sense.

See https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html

But it's not certain that translation management tools (working with PO files) currently all handle custom flags (beside fuzzy).

andrii-bodnar commented 1 month ago

I'm afraid there isn't a common approach to handle this for most CMS. So the implementation on the Lingui side would most likely be different for each CMS.

I think it's convenient to use the comment configuration for this case. Translators will rely on the comments displayed in the translation editor. There is still a chance that the translator won't notice the comment.

In Crowdin, for example, you can automate the process of hiding such strings. It's possible to use the File Import Tweak application to detect some specific "markers" in the comment (this information is treated as Context) and hide strings based on them. In this case, there is no chance that translators will translate these strings by mistake.

AndrewIngram commented 3 weeks ago

I think it's reasonably to have the comment field be the output (we are in fact using CrowdIn), but having a way to augment the API so that developers can get the benefit of static typing, e.g. using an enum for possible tag values would be very helpful, even if ultimately we still have to provide a way to collapse all the config into a single comment string.

If static analysis weren't a concern, we'd just wrap the Lingui APIs to do this, but unfortunately that doesn't really seem like an option here.

thekip commented 3 weeks ago

Still even if we implement it on the analysis side, how you are going to extend signature of he lingui methods to benefit from static typings? This request sounds as something very specific to your use case.

One thing i see, we can change static analysis (extractor and macro) to extract any extra keys you passed to it, something like:

const descriptor: MacroMesageDescriptor  = {
  message: "Hello",
  values: {},
 // extra keys
  myKey: "myValue",
  myOtherKey: "MyValue"
}

So then you can extend MacroMesageDescriptor type using Module Augmentation + Declaration Merging

declare module "@lingui/macro" {
  type MacroMesageDescriptor {
      myKey: "myValue" | "MyValue2",
      myOtherKey: string
  }
}

It still will be bound to your specific use case, what if myKey would be not a string like? What if there would be something not analyzable statically?

BTW, using typescript's template literal types you can create really crazy typings, for example you can describe in types something like:

{
  comment: "tag: predefinedValue; Rest of comment"
} 

And tag: predefinedValue; would be statically typed.

AndrewIngram commented 3 weeks ago

One thing i see, we can change static analysis (extractor and macro) to extract any extra keys you passed to it, something like:

const descriptor: MacroMesageDescriptor  = {
  message: "Hello",
  values: {},
 // extra keys
  myKey: "myValue",
  myOtherKey: "MyValue"
}

So then you can extend MacroMesageDescriptor type using Module Augmentation + Declaration Merging

declare module "@lingui/macro" {
  type MacroMesageDescriptor {
      myKey: "myValue" | "MyValue2",
      myOtherKey: string
  }
}

It still will be bound to your specific use case, what if myKey would be not a string like? What if there would be something not analyzable statically?

This is more-or-less what I had in mind. We'd probably make a lint rule to prevent non-static args