rubenv / angular-gettext

Gettext support for Angular.js
http://angular-gettext.rocketeer.be/
MIT License
650 stars 154 forks source link

Gettext Domains support #95

Open kevinmartin opened 10 years ago

kevinmartin commented 10 years ago

Would be nice to have support for domains. In a few languages, you can do something like:

__d('default', 'Hello World'); // (equivalent to __('Hello World')
__d('accounts', 'Billing Address');

So, something like the following would be nice, as well:

<span translate translate-domain="accounts">Billing Address</span>
rubenv commented 10 years ago

Do you have an example of where this is useful?

I've looked at them when designing angular-gettext and I haven't found a situation where really add value.

kevinmartin commented 10 years ago

I use this daily on two of my other non-Angular apps. I use them to separate language entries based on controllers, in this case probably modules.

In my experience, with larger applications, it make is more maintainable just like you would split up large controllers/modules/documents/views/etc into multiple files.

kevinmartin commented 10 years ago

There is also an example in the description of this issue.

But... <span translate>Save</span> would typically go into a default.po file. <span translate translate-domain="settings">Billing Address</span> would go into settings.po

I can imagine that this would be easy to integrate if you just assume there is always a domain and give it a default value of default.

kevinmartin commented 10 years ago

screen shot 2014-08-20 at 5 33 35 pm Screenshot for one of my Transifex projects

rubenv commented 10 years ago

Assuming that you split everything into modules, you'll have something like this:

src/accounts/
src/businesses/
src/capital/
...

Why don't you just generate a separate .po file for each of those folders? That'll get you the same result, without having to annotate each and every string.

I must admit that I'm inclined to just not support domains. It feels like a waste of time to annotate each string and it adds to the footprint of the application.

But worst of all: we can add this concept to the translate directive, but there's no way we can add this to the filter or the JS API. Consistency and simplicity matters more to me than supporting all possible features.

kevinmartin commented 10 years ago

Your suggestion is considerable, but honestly less than ideal. That would allow for duplicate strings across files. For example, I may want common words/phrases/actions in a default.po, but in your strategy, these strings would be duplicated across all the files.

The idea is to generate multiple .po files, but in the way they were intended to be created, and used.

As far as consistency, and with all due respect, your filter does not translate plurals. Now, both plurals and domains can be added as a filter. For example: Plural: {{ 'Singular Case' | translatePlural:'Plural Case':n }} Domain: {{ 'String' | translateDomain:'Domain' }} Domain/Plural: {{ 'Singular Case' | translateDomainPlural:'Domain':'Plural Case':n }}

In terms of the JS API, you simply add a gettextCatalog.getDomainString("Domain", "Hello"); and gettextCatalog.getDomainPlural("Domain", 3, "Bird", "Birds");

kevinmartin commented 10 years ago

Another suggestion is instead of using:

<span translate>Hello</span>
<span translate translate-domain="myDomain">World</span>

is:

<span translate>Hello</span>
<span translate="myDomain">World</span>

This could limit the footprint that you are worried about. I'm sure there is a way to implement this where it could benefit all parties. I hope you understand that this is a feature many big projects use.

adepretis commented 10 years ago

Use Case: we have an application that has some kind of export functionality, exporting part of the application as static/offline version. The part that's exported has significantly less strings to translate and significantly more languages to support (up to 15-20) - the rest of the application has more strings and needs lesser translations/language support.

1) we don't want to expose the strings of the whole platform in the offline version (covering only a small part of the application) 2) our customer could save a lot of money if they wouldn't need to translate the whole thing in 15-20 languages but just a small part of it

Textdomains would be a great feature for this :-)

rubenv commented 10 years ago

@adepretis That's also something that can be solved by a translation memory and simply limiting the files from which you extract strings.

I'm inclined to not support domains: they add complexity yet add little.

adepretis commented 10 years ago

@rubenv extracting strings into different catalogs is a requirement either way :-) ... having textdomains in the translate-filter and so on would be much clearer for developers, where they have to include which translation catalogs and in which context the string is to be seen.

kevinmartin commented 10 years ago

I know that @rubenv knows about the PR, but just in case for others: https://github.com/rubenv/angular-gettext/pull/115

rubenv commented 10 years ago

@adepretis Don't confuse contexts with domains. See #103.

mtr commented 10 years ago

+1 for this feature, and great work, @KevinMartin!

generalov commented 10 years ago

+1

gabegorelick commented 10 years ago

The only usecase I can come up with for domains (that can't be solved with separate modules) is when you want to split the strings from a single file into multiple catalogs. Is that something that people are trying to do?

mtr commented 10 years ago

I can tell you how I use it and why, @gabegorelick:

In the web application I develop, each user participates in one or more activities of different kinds. Each activity's contents can be localized, and only users that participate in an activity should be able to see the contents.

Because the per-activity contents should not be shared with outside, non-participating users, the translations cannot be served in one, general gettext catalog (that would just be obfuscation, not real security/privacy). Another reason is that the number of such localized activities are in the thousands, and serving every possible translation to all users (where each user only participates in at most a few percent of the activities) would be a huge waste of bandwidth.

A natural solution is therefore to use gettext's support for domains and let each activity be served along with a gettext domain-specific catalog that is incorporated into angular-gettext's shared catalog as a separate domain (one domain per activity) when it is received from the server. That way, relevant parts (domains) of the angular-gettext catalog can be updated, if needed, when activities are refreshed from the server (new translations can have become available). This is how we use this feature today (and it works great with @KevinMartin's solution). Hence, I've created my own fork for the time being and made a pull request for @KevinMartin, keeping up with upstream changes while hoping that this feature will be incorporated into the main project.

gabegorelick commented 10 years ago

@mtr Thanks for the info. I don't have any control over what gets added to angular-gettext, but I do want to understand this issue.

Because the per-activity contents should not be shared with outside, non-participating users, the translations cannot be served in one, general gettext catalog (that would just be obfuscation, not real security/privacy).

I understand domains would fit nicely into your workflow, but do you have to have them to accomplish this? Or can you, like @rubenv has suggested, simply structure your project around the separate catalogs? No one is saying that multiple catalogs isn't a valid usecase. The issue is whether domains are necessary to manage multiple catalogs, given that there are already other ways to do it.

Another reason is that the number of such localized activities are in the thousands, and serving every possible translation to all users (where each user only participates in at most a few percent of the activities) would be a huge waste of bandwidth.

This is perhaps a compelling reason to support domains: that it makes it easier to manage a large number of catalogs. But again, could you accomplish the same thing with separate modules?

kevinmartin commented 10 years ago

@gabegorelick, at the end of the day, a project's structure should not be changed because of a or revolve around a dependency.

If I have to modify my existing structure or working process completely around a dependency, then that is a poor design on the dependency. The project should not suffer for it.

This is why it is such good practice to fork the code, make your modifications, and submit them up the chain. There's a difference between creating a lean module that fully serves it's duty (not the current case) and creating an empty module (based on a much bigger concept) with only a third of the features that should be in it (which is the current case).

This is why I, nor the other commenters on this issue and on pull request #115, understand why @rubenv would like to make a half-assed module with only some of the features intended by the greater concept of GNU Gettext.

rubenv commented 10 years ago

why @rubenv would like to make a half-assed module with only some of the features intended by the greater concept of GNU Gettext.

Let's keep things constructive and positive.

I'm not opposed to adding features that fix problems, but I've always felt that domains is one of those features that doesn't really solve anything new in the context of a web app.

We shouldn't blindly follow what gettext does, just because gettext does it. Gettext is 20 years old and things have changed quite a lot in the last two decades. Angular-gettext deviates in other areas as well: look at how interpolation is handled in gettext: that would be totally unsuitable for an Angular.JS app, instead we use the Angular.JS interpolation, which fits us much better.

But if there's a real problem that cannot be fixed, I'm all for adding it. Case in point: contexts.

Now as for structuring your project differently based on a dependency: I'm not convinced you should. Grunt has such an amazing wealth of file matching power built-in that you can structure your catalogs pretty much any way you want.

But let's continue that discussion in #115, where there's a concrete example. It's quite annoying to talk about this feature in two places.