Ygg01 / Linguini

C# Port of fluent.rs zero-copy parser
Apache License 2.0
28 stars 8 forks source link

Too many bundles #52

Closed eXplowar closed 10 months ago

eXplowar commented 10 months ago

Good afternoon. There are about fifty enumerations in my ASP.NET Core Web API project. For each such enumeration, I have allocated ten language ftl files. Plus separate ftl contexts for general translations, separate ftl's for Exceptions. Everything is neatly arranged in folders. This ensures ease of translation management.

How to use Linguini correctly with this project structure?

Ygg01 commented 10 months ago

Perhaps it needs clarifying, but it's one FluentBundle per language. If languages are similar, they can be handled by a single bundle, but I've yet to implement fallback languages.

Edit: also, what do you mean by enumerations? Could you please provide a sketch of what you want to do? Like basic folder structure, and how enumerations related to .ftl files?

Ygg01 commented 10 months ago

@eXplowar I hope you haven't missed my reply. I would love to help you, but I need a bit more clarification.

eXplowar commented 10 months ago

@Ygg01, thank you for your attention to my issue. I creating an example. Later put his her.

what do you mean by enumerations Enum's

Basic folder structure for translations:

image

Ygg01 commented 10 months ago

thank you for your attention to my issue.

No worries, I'm here to try to help!

That's a very peculiar pattern you have chosen for your project. Usually, translations are divided per language. For example, SS14 uses it for localization, and they have an entirely different structure.

This has the benefits that you can see what languages are available by scanning children folders of Translation (i.e. en-US, ru-RU in below example), and just adding all subfolders of said translation to a bundle.

E.g. their structure goes something like this

Translations
 |
 +-- en-US
 |  |
 |  +-- cities.ftl
 |  |
 |  +-- common.ftl
 |  |
 |  +-- invoiceException.ftl
 |  |
 |  +-- Enum
 |       |
 |       +-- invoice.ftl
 |       |
 |       +-- payment.ftl
 |     
 +-- ru-RU
      |
      ... // mirrored structure

At the end of the day, files are just a logical separator, for ease of organization, all resources for a given language are dumped into the same Dictionary. You could theoretically have a big all in one translation file. E.g.

Translations
 |
 +-- en-US
 |  |
 |  +-- all_translations.ftl
 |     
 +-- ru-RU
    |
    +-- all_translations.ftl  

But it might be too challenging to navigate. Again, it depends on how you want to structure it.

Another thing to note if you find yourself with following pattern:

Entity = My entity
Entity-description = My entity description

Perhaps the better option would be to use fluent attributes

Entity = My Entity
   .description = My Entity description

EDIT: I think I see what you mean. Having translations side by side would ease translation effort.

However, I'm not sure how could I help you? What would make your life easier?

eXplowar commented 10 months ago

@Ygg01, thanks for cool and detailed answer.

That's a very peculiar pattern you have chosen for your project. Usually, translations are divided per language. For example, SS14 uses it for localization, and they have an entirely different structure.

Perhaps. I will try take solusion from SS14. Thanks for alternative example.

At the end of the day, files are just a logical separator, for ease of organization, all resources for a given language are dumped into the same Dictionary.

I see that this is exactly how Linguini is designed. But tell me, won’t there be a problem if I have, say, both Invoice and Payment enums with similar "Paid" values? E.g. Invoice.Paid and Payment.Paid. The fact is that in the ftl-file that I write for them, the key has a value that matches the value of the enum, in our case Paid. I need this so that my extension method can find the translation by enum value. It seems to me that I will have to make a prefix to the key that corresponds to the name Enum... Perhaps this is not a big problem, and I will still make the prefix, it’s just that without it the ftl-file, which relates to some enum, is served a little more conveniently.

Perhaps the better option would be to use fluent attributes

Thanks for the information about fluent attributes.

Ygg01 commented 10 months ago

But tell me, won’t there be a problem if I have, say, both Invoice and Payment enums with similar "Paid" values?

Yes. They would collide, and depending on how you insert a resource, it would either error out or just overwrite.

Keep in mind Fluent is a way to replace .properties like translation resources. Each translation key is expected to be unique in application. I.e. Invoiced.Paid and Payment.Paid would become keys like Invoice-Paid and Payment-Paid. You could use reflection or some other convention to transform a call to Invoice for Paid string into an Invoice-Paid id.

// assume this is a field in some internal helper class 
public LinguiniBundle bundle;

public bool TryGetLocalization(string? classPrefix, string loc, IDictionary<string, IFluentType>? args, out string? message)
{

     var id = classPrefix == null ? loc : $"{classPrefix}-{loc}";
     // Note: `out _` is ignoring all errors, don't do this in actual code.
     bundle.TryGetMessage(id, args, out _, out message)
}

EDIT: However, it would still require your translations to be written as Invoice-Paid