rubenv / angular-gettext-tools

Tools for extracting/compiling angular-gettext strings.
http://angular-gettext.rocketeer.be/
MIT License
39 stars 129 forks source link

Fixes rubenv/angular-gettext-tools#177 #178

Open matthieusieben opened 6 years ago

matthieusieben commented 6 years ago

Allow using markerNames to detect string literals. Simply add a leading comment to the string that contains the markerName (exactly) and that string will be added to the pot file.

Example:

const myString = /* gettext */ "This will be extracted"

or

var extractor = new Extractor({ markerNames: [ "@ngTranslate" ] })

Will extract the following string:

const myString = /* @ngTranslate */ "This will be extracted"
rubenv commented 6 years ago

Hi, thanks for writing this PR, but I wish you'd have checked with me first.

A big part of the design philosophy in angular-gettext was simplicity: one way to do things. Somewhat as a counter-reaction to angular-translate where there's a thousand options and equally much ways for doing things. Users get lost and hate it.

As such I'd rather not have two ways of doing the same thing, it'll just lead to confusion.

matthieusieben commented 6 years ago

The problem with your way is that it is utterly inefficient as it requires a useless function call in production code... Plus, it does not integrate properly with some code bundlers which sometimes rename functions (e.g. Rollup).

matthieusieben commented 6 years ago

This is the problem with the NPM community... You want to improve stuff, but you can't because the first guy who proposed an "ok" solution is now ruling on his own little kingdom without listening to its peers for improvements.

The alternative is for me to fork this project, meaning that there will be 2 ways of doing things out there (on NPM), defeating your purpose... There will then be 2 distinct code base which won't benefit from each other's fixes, leading to a decreased user experience for the community.

All because you wanted to impose your way. This is so absurd...

rubenv commented 6 years ago

Woah chill mate. There's a reason I didn't close this one yet: there's always room for talking about things.

The rollup case is pretty interesting and I hadn't considered that one. Though I do wonder if it's a good idea to extract strings from minified (as opposed to original) code. Is there no way to hook into this process before minification?

rubenv commented 6 years ago

Similarly, it's probably possible to add a build step (after extraction) that removes the calls to gettext(), as they are no-ops anyway.

But again, let's try to understand each other first before bursting into a fit of rage. I'm pretty sure we can come up with a solution that works for everybody.

matthieusieben commented 6 years ago

Rollup works as follows (roughly): 1) builds a tree of dependencies 2) applies transforms to individual files 3) resolves global naming conflicts (if some modules declares a gettext variable, even in a protected scope, the following global variables called gettext will be renamed into gettext$1...n) 4) merges all the files into one bundle

It also has a live watch functionality which only applies step 2 to the updated files and then applies step 3 and 4.

The most efficient way to apply the extractor.extractJs() is during step 2, as only updated files need to be parsed again. This would allow both to extract the gettext() strings, and remove the useless function call (btw, extractor.extractJs would need an option to transform the code, removing noops calls, to avoid having to re-build the AST in the rollup plugin).

However, doing this a a major inconvenient: with the live watch functionality on, new strings would only be added to the extractor instance, and, outdated strings, never be cleaned. I have run into several memory leak issues due to this.

Because of this memory leak issue, the proper way to integrate with the current version of angular-gettext-tools is to use the "on bundle hook" to parse the code (before minification of course).

Now the problem with this hook, is that it comes after the step 3) described before, during which RollupJs renames variables that may be in conflict, resulting in some gettext() function calls being renamed into gettext$1().

The way I see it, there are several solutions to this issue:

IMO the best solution is to always rely on special comments (which are never tempered with by code transformers), and to deprecate every other way of detecting strings.

rubenv commented 6 years ago

Note that we also extract strings from calls to gettextCatalog.getString() and gettextCatalog.getPlural(), so it's not purely gettext() that needs to be taken into account. This last one has more than one string in the definition.

matthieusieben commented 6 years ago

I know. I thought of it and have to admit that Javascript does not provide enough tools to handle this case.

gettextCatalog.getPlural(/* @gettextn */ "One", "Several")
gettextCatalog.getPlural(/* @gettext */ "One", /* @plural */ "Several")

Are all ugly!

matthieusieben commented 6 years ago

Another solution would be:

gettextCatalog.getPlural(/* @gettext */ [ "One", "Several" ])

But it would require an update of angular-gettext, which is probably not a good idea.

matthieusieben commented 6 years ago

Or one could write:

gettextCatalog.getPlural.apply(gettextCatalog, /* @gettext */ [ "One", "Several" ])

But my propositions are getting worse and worse 😆

rubenv commented 6 years ago

Yeah, that's not exactly ideal 😁

matthieusieben commented 6 years ago

I think that from the language point of view, the best would probably be:

// Singular only string
/* @gettext */ "My string"
/* @gettext */ [ "My string" ]

// String with plural
/* @gettext */ [ "One", "Some" ]

// String with multiple plural forms
/* @gettext */ [ "One", "Some", "A lot" ]

The array notation has the advantage of allowing to support defining more than one plural form, as some languages require, and is not currently supported by angular-gettext

rubenv commented 6 years ago

The array notation has the advantage of allowing to support defining more than one plural form, as some languages require.

Base language should always be English (if you do it right), so that's probably not a problem here :-)

Also keep in mind that we can't break compatibility. There are some pretty large codebases using this, they're not going to be happy if everything needs to be changed.

ngehlert commented 5 years ago

@matthieusieben is this issue still relevant? I still don't quite understand your problem. There is no reason that the extraction has to be after minification or transform (on a sidenote, you still can configure this step to force variable/function names to remain the same, e.g. ngInject does sth similar for angularjs services) even if this would be for some reason not possible you can set up a separate job only to extract the strings while developing and trigger you other watch to minify again.

Can you try to explain your use case a little bit more if this is still relevant?