angular-gettext
angular-gettext copied to clipboard
New "translate-attr" directive describing which attribute(s) value(s) must be translated
Hi,
I encountered a problem translating attribute values like title
and placeholder
. Currently we could convert
this:
<input type="password" placeholder="Password" .../>
to this:
<input type="password" placeholder="{{'Password' | translate}}" .../>
But this adds unnecessary obfuscation of the html attribute itself. My proposal is to create new directive say translate-attr
which will be used to point to the name of an attribute which should be translated so the above could look like this:
<input type="text" placeholder="Password" translate-attr="placeholder" ...>
It could greatly simplify elements which have more than one attribute for translation like this:
<img alt="{{'Tree' | translate}}" title="{{'An old tree' | translate}}" ... />
to this:
<img alt="Tree" title="An old tree" translate-attr="alt" translate-attr="title" ... />
or even combine all attribute names:
<img alt="Tree" title="An old tree" translate-attr="alt,title" ... />
It looks easier to read by a human, it removes "logic" from attribute values so non-programmer could easily find the text that will be translated reducing the number of possible errors, looks more "HTML-ish". And also I suppose it is easier for parser to extract text compared to filter approach.
:+1:
I found the following "custom annotations" ability of angular-gettext at https://angular-gettext.rocketeer.be/dev-guide/custom-annotations/ which could be used in this situation. But I also found that it only works for elements without content (so the sample with placeholder attribute of an input element is not good enough). If you for example try to do the same for title attribute of an label element that have some text content, grunt-angular-gettext will extract the label text, not the title attribute value. So if you have:
<label for="someId" title="Label tooltip">Label text content</label>
Extraction will extract only "Label text content".
So I have modified the node_modules\grunt-angular-gettext\node_modules\angular-gettext-tools\lib\extract.js
file in order to support extracting attribute values, not element content.
I have changed the following block in Extractor.prototype.extractHtml
method:
for (var attr in node.attr()) {
attr = attr.replace(/^data-/, '');
if (possibleAttributes.indexOf(attr) > -1) {
var attrValue = extracted[attr];
str = node.html(); // this shouldn't be necessary, but it is
self.addString(reference(n.startIndex), str || getAttr(attr) || '', attrValue.plural, attrValue.extractedComment, attrValue.context);
} else if (matches = noDelimRegex.exec(node.attr(attr))) {
str = matches[2].replace(/\\\'/g, '\'');
self.addString(reference(n.startIndex), str);
noDelimRegex.lastIndex = 0;
}
}
To:
var selfContentOnlyAttrs = self.options.selfContentOnlyAttributes;
for (var attr in node.attr()) {
attr = attr.replace(/^data-/, '');
if (possibleAttributes.indexOf(attr) > -1) {
var attrValue = extracted[attr];
if (selfContentOnlyAttrs && selfContentOnlyAttrs.indexOf(attr) > -1) {
// This attribute is found in selfContentOnlyAttrs array - so we should get only attribute's value, not its element html()
str = node.attr(attr);
} else {
// Not found in selfContentOnlyAttrs - get its element html
str = node.html(); // this shouldn't be necessary, but it is
}
//str = node.html(); // this shouldn't be necessary, but it is
self.addString(reference(n.startIndex), str || getAttr(attr) || '', attrValue.plural, attrValue.extractedComment, attrValue.context);
} else if (matches = noDelimRegex.exec(node.attr(attr))) {
str = matches[2].replace(/\\\'/g, '\'');
self.addString(reference(n.startIndex), str);
noDelimRegex.lastIndex = 0;
}
}
After that the usage in Gruntfile.js (for attributes title
and placeolder
) would be:
nggettext_extract: {
pot: {
options: {
attributes: ["placeholder", "title"],
selfContentOnlyAttributes: ["placeholder", "title"]
},
files: {
'po/template.pot': ['src/views/*.html']
}
},
},
It is obvious that including these specific attributes both in attributes
and selfContentOnlyAttributes
arrays is not good solution, so I could create pull request for review by the author and eventually change it to something more robust.
Note: I didn't started any tests after the change of extract.js
I must confirm issue posted by @varadero.
If you have
<foo bar="abc">
nggettext_extract output is:
msgid "abc"
same for:
<foo bar="abc"></foo>
but:
<foo bar="abc">xyz</foo>
produces:
msgid "xyz"
The only way here is to use translate filter like:
<foo bar="{{'abc'|translate}}">xyz</foo>