pybabel-angularjs 1.3.5__tar.gz → 1.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: pybabel-angularjs
3
+ Version: 1.5.0
4
+ Summary: An AngularJS extractor for Babel
5
+ Author-email: Jaromír Pufler <jaromir.pufler@gmail.com>
6
+ License: Apache Software License
7
+ Project-URL: Homepage, https://github.com/chuckyblack/pybabel-angularjs
8
+ Keywords: angularjs,gettext,babel,i18n,translate
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Software Development :: Internationalization
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: babel
24
+ Dynamic: license-file
25
+
26
+ # pybabel-angularjs
27
+
28
+ [![CI](https://github.com/chuckyblack/pybabel-angularjs/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/chuckyblack/pybabel-angularjs/actions/workflows/release.yml)
29
+ [![PyPI](https://img.shields.io/pypi/v/pybabel-angularjs.svg)](https://pypi.org/project/pybabel-angularjs/)
30
+
31
+ A [Babel](https://babel.pocoo.org/) message extractor for AngularJS HTML
32
+ templates. It extracts element content and attributes marked for translation,
33
+ including strings containing AngularJS expressions such as `{{ name }}`.
34
+
35
+ Requires Python 3.12 or newer.
36
+
37
+ ## Installation
38
+
39
+ ```console
40
+ python -m pip install pybabel-angularjs
41
+ ```
42
+
43
+ The package installs the `angularjs` Babel extractor entry point. Add it to a
44
+ Babel mapping file such as `babel.cfg`:
45
+
46
+ ```ini
47
+ [angularjs: **/*.html]
48
+ encoding = utf-8
49
+ ```
50
+
51
+ Then extract messages in the usual way:
52
+
53
+ ```console
54
+ pybabel extract -F babel.cfg -o messages.pot .
55
+ ```
56
+
57
+ ## Marking messages
58
+
59
+ Mark an element's content with `i18n`:
60
+
61
+ ```html
62
+ <div i18n>Hello world!</div>
63
+ <p i18n>Hello {{ name }}!</p>
64
+ ```
65
+
66
+ The value of `i18n`, when present, is included as a comment for translators:
67
+
68
+ ```html
69
+ <h1 i18n="Page heading">Welcome</h1>
70
+ ```
71
+
72
+ Mark an individual attribute by adding the `i18n-` prefix:
73
+
74
+ ```html
75
+ <input placeholder="Your name" i18n-placeholder>
76
+ ```
77
+
78
+ ## Configuration
79
+
80
+ Options are set in the extractor section of the Babel mapping file. Lists can
81
+ be separated by commas or whitespace.
82
+
83
+ ```ini
84
+ [angularjs: **/*.html]
85
+ encoding = utf-8
86
+ include_tags = h1, h2, p
87
+ include_attributes = title, alt, placeholder
88
+ allowed_tags = a, strong, br, i
89
+ allowed_attributes_a = href, target
90
+ include_format_flags = false
91
+ ```
92
+
93
+ - `extract_attribute` changes the marker from the default `i18n`, for example
94
+ to `data-translate`.
95
+ - `include_tags` extracts all content from the listed tags without requiring an
96
+ explicit marker.
97
+ - `include_attributes` extracts the listed attributes wherever they occur.
98
+ - `allowed_tags` controls which nested HTML tags may appear inside a translated
99
+ message. The default is `strong, br, i`.
100
+ - `allowed_attributes_<tag>` controls attributes allowed on a nested tag, for
101
+ example `allowed_attributes_a = href, target`.
102
+ - `encoding` controls template decoding and defaults to `utf-8`.
103
+ - `include_format_flags` makes the extractor return an extended five-value
104
+ result and marks messages containing AngularJS interpolation with
105
+ `angularjs-format`. It defaults to `false` because official Babel releases
106
+ accept only the standard four-value extractor result. Enable it only with a
107
+ Babel build that explicitly supports extractor-provided flags.
108
+
109
+ Use `no-i18n` to exclude an automatically included tag. A `<div no-i18n>`
110
+ excludes its entire subtree. For automatically included attributes, use the
111
+ corresponding marker such as `no-i18n-title`.
112
+
113
+ ## License
114
+
115
+ Apache License 2.0. The project was heavily inspired by the original
116
+ [shoreware/pybabel-angularjs](https://bitbucket.org/shoreware/pybabel-angularjs).
@@ -0,0 +1,91 @@
1
+ # pybabel-angularjs
2
+
3
+ [![CI](https://github.com/chuckyblack/pybabel-angularjs/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/chuckyblack/pybabel-angularjs/actions/workflows/release.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/pybabel-angularjs.svg)](https://pypi.org/project/pybabel-angularjs/)
5
+
6
+ A [Babel](https://babel.pocoo.org/) message extractor for AngularJS HTML
7
+ templates. It extracts element content and attributes marked for translation,
8
+ including strings containing AngularJS expressions such as `{{ name }}`.
9
+
10
+ Requires Python 3.12 or newer.
11
+
12
+ ## Installation
13
+
14
+ ```console
15
+ python -m pip install pybabel-angularjs
16
+ ```
17
+
18
+ The package installs the `angularjs` Babel extractor entry point. Add it to a
19
+ Babel mapping file such as `babel.cfg`:
20
+
21
+ ```ini
22
+ [angularjs: **/*.html]
23
+ encoding = utf-8
24
+ ```
25
+
26
+ Then extract messages in the usual way:
27
+
28
+ ```console
29
+ pybabel extract -F babel.cfg -o messages.pot .
30
+ ```
31
+
32
+ ## Marking messages
33
+
34
+ Mark an element's content with `i18n`:
35
+
36
+ ```html
37
+ <div i18n>Hello world!</div>
38
+ <p i18n>Hello {{ name }}!</p>
39
+ ```
40
+
41
+ The value of `i18n`, when present, is included as a comment for translators:
42
+
43
+ ```html
44
+ <h1 i18n="Page heading">Welcome</h1>
45
+ ```
46
+
47
+ Mark an individual attribute by adding the `i18n-` prefix:
48
+
49
+ ```html
50
+ <input placeholder="Your name" i18n-placeholder>
51
+ ```
52
+
53
+ ## Configuration
54
+
55
+ Options are set in the extractor section of the Babel mapping file. Lists can
56
+ be separated by commas or whitespace.
57
+
58
+ ```ini
59
+ [angularjs: **/*.html]
60
+ encoding = utf-8
61
+ include_tags = h1, h2, p
62
+ include_attributes = title, alt, placeholder
63
+ allowed_tags = a, strong, br, i
64
+ allowed_attributes_a = href, target
65
+ include_format_flags = false
66
+ ```
67
+
68
+ - `extract_attribute` changes the marker from the default `i18n`, for example
69
+ to `data-translate`.
70
+ - `include_tags` extracts all content from the listed tags without requiring an
71
+ explicit marker.
72
+ - `include_attributes` extracts the listed attributes wherever they occur.
73
+ - `allowed_tags` controls which nested HTML tags may appear inside a translated
74
+ message. The default is `strong, br, i`.
75
+ - `allowed_attributes_<tag>` controls attributes allowed on a nested tag, for
76
+ example `allowed_attributes_a = href, target`.
77
+ - `encoding` controls template decoding and defaults to `utf-8`.
78
+ - `include_format_flags` makes the extractor return an extended five-value
79
+ result and marks messages containing AngularJS interpolation with
80
+ `angularjs-format`. It defaults to `false` because official Babel releases
81
+ accept only the standard four-value extractor result. Enable it only with a
82
+ Babel build that explicitly supports extractor-provided flags.
83
+
84
+ Use `no-i18n` to exclude an automatically included tag. A `<div no-i18n>`
85
+ excludes its entire subtree. For automatically included attributes, use the
86
+ corresponding marker such as `no-i18n-title`.
87
+
88
+ ## License
89
+
90
+ Apache License 2.0. The project was heavily inspired by the original
91
+ [shoreware/pybabel-angularjs](https://bitbucket.org/shoreware/pybabel-angularjs).
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pybabel-angularjs"
7
+ version = "1.5.0"
8
+ description = "An AngularJS extractor for Babel"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ authors = [
12
+ { name = "Jaromír Pufler", email = "jaromir.pufler@gmail.com" },
13
+ ]
14
+ license = { text = "Apache Software License" }
15
+ keywords = ["angularjs", "gettext", "babel", "i18n", "translate"]
16
+ dependencies = [
17
+ "babel",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 5 - Production/Stable",
21
+ "Intended Audience :: Developers",
22
+ "Topic :: Software Development :: Internationalization",
23
+ "License :: OSI Approved :: Apache Software License",
24
+ "Operating System :: OS Independent",
25
+ "Programming Language :: Python",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3 :: Only",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Programming Language :: Python :: 3.13",
30
+ "Programming Language :: Python :: 3.14",
31
+ ]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/chuckyblack/pybabel-angularjs"
35
+
36
+ [project.entry-points."babel.extractors"]
37
+ angularjs = "pybabel_angularjs.extractor:extract_angularjs"
38
+
39
+ [tool.setuptools]
40
+ package-dir = { "" = "src" }
41
+
42
+ [tool.setuptools.packages.find]
43
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,270 @@
1
+ from html.parser import HTMLParser
2
+ from typing import Any, Iterable, Iterator, Mapping, Sequence
3
+
4
+ import re
5
+
6
+ type StandardExtractorEntry = tuple[int, str, str, list[str]]
7
+ type FlaggedExtractorEntry = tuple[int, str, str, list[str], tuple[str, ...]]
8
+ type ExtractorEntry = StandardExtractorEntry | FlaggedExtractorEntry
9
+ type AllowedAttributesByTag = dict[str, list[str]]
10
+ type HtmlAttributes = list[tuple[str, str | None]]
11
+
12
+
13
+ class TagNotAllowedException(Exception):
14
+ pass
15
+
16
+
17
+ class TagAttributeNotAllowedException(Exception):
18
+ pass
19
+
20
+
21
+ class ExtractAttributeNotAllowedException(Exception):
22
+ pass
23
+
24
+
25
+ class MissingAttributeException(Exception):
26
+ pass
27
+
28
+
29
+ class AngularJSGettextHTMLParser(HTMLParser):
30
+ """Parse HTML to find translate directives.
31
+
32
+ Currently this parses for these forms of translation:
33
+
34
+ <p data-translate>content</p>
35
+ The content will be translated. Angular value templating will be
36
+ recognised and transformed into gettext-familiar translation
37
+ entries (i.e. "{$ expression $}" becomes "%(expression)")
38
+ """
39
+
40
+ VOID_TAGS = ("br", "input", "img")
41
+
42
+ def __init__(
43
+ self,
44
+ include_tags: list[str],
45
+ include_attributes: list[str],
46
+ extract_attribute: str,
47
+ allowed_attributes_by_tag: AllowedAttributesByTag,
48
+ include_format_flags: bool = False,
49
+ ) -> None:
50
+ super().__init__()
51
+
52
+ self.include_tags: list[str] = include_tags
53
+ self.include_attributes: list[str] = include_attributes
54
+ self.extract_attribute: str = extract_attribute
55
+ self.allowed_attributes_by_tag: AllowedAttributesByTag = allowed_attributes_by_tag
56
+ self.include_format_flags = include_format_flags
57
+
58
+ self.in_translate: bool = False
59
+ self.inner_tags: list[str] = []
60
+ self.data: list[str] = []
61
+ self.entries: list[ExtractorEntry] = []
62
+ self.start_lineno: int = 0
63
+ self.comments: list[str] = []
64
+ self.re_collapse_whitespaces: re.Pattern[str] = re.compile(r"\s+")
65
+ self.in_do_not_translate: bool = False
66
+
67
+ @property
68
+ def do_not_extract_attribute(self) -> str:
69
+ return "no-" + self.extract_attribute
70
+
71
+ def normalize_string(self, string: str, replace_whitespace: str = " ") -> str:
72
+ """
73
+ :type string: str
74
+ :type replace_whitespace: str
75
+ """
76
+ string = (
77
+ string
78
+ .replace("\n", " ")
79
+ .replace("\t", " ")
80
+ .replace(" ", "&nbsp;")
81
+ )
82
+ return self.re_collapse_whitespaces.sub(replace_whitespace, string).strip()
83
+
84
+ def add_entry(self, message: str, comments: Sequence[str] | None = None, lineno: int | None = None) -> None:
85
+ comments = comments or []
86
+ entry: StandardExtractorEntry = (
87
+ lineno or self.start_lineno,
88
+ "gettext",
89
+ self.normalize_string(message),
90
+ [self.normalize_string(comment) for comment in comments],
91
+ )
92
+ if self.include_format_flags:
93
+ flags = ("angularjs-format",) if "{{" in message else ()
94
+ self.entries.append((*entry, flags))
95
+ else:
96
+ self.entries.append(entry)
97
+
98
+ def append_inner_tag(self, tag: str) -> None:
99
+ if tag not in self.VOID_TAGS:
100
+ self.inner_tags.append(tag)
101
+
102
+ def handle_startendtag(self, tag: str, attrs: HtmlAttributes) -> None:
103
+ self.handle_starttag(tag, attrs)
104
+ if tag not in self.VOID_TAGS:
105
+ self.handle_endtag(tag)
106
+
107
+ def attrdict_contains(self, attrdict: Mapping[str, str | None], search: Sequence[str] | None = None) -> bool:
108
+ search = search or [self.extract_attribute, self.do_not_extract_attribute]
109
+ for attr in attrdict:
110
+ for prefix in search:
111
+ if attr.startswith(prefix):
112
+ return True
113
+ return False
114
+
115
+ def handle_starttag(self, tag: str, attrs: HtmlAttributes) -> None:
116
+ attrdict = dict(attrs)
117
+ lineno = self.getpos()[0]
118
+
119
+ if self.in_do_not_translate:
120
+ if self.attrdict_contains(attrdict):
121
+ raise ExtractAttributeNotAllowedException((lineno, tag, attrdict))
122
+ self.append_inner_tag(tag)
123
+ return
124
+
125
+ if self.in_translate and (
126
+ self.extract_attribute in attrdict or self.do_not_extract_attribute in attrdict
127
+ ):
128
+ raise ExtractAttributeNotAllowedException((lineno, tag, attrdict))
129
+
130
+ if tag == "div" and self.do_not_extract_attribute in attrdict:
131
+ self.in_do_not_translate = True
132
+ if self.attrdict_contains(attrdict, [self.extract_attribute]):
133
+ raise ExtractAttributeNotAllowedException((lineno, tag, attrdict))
134
+ return
135
+
136
+ # handle data-translate attribute for translating content
137
+ if self.in_translate:
138
+ if tag not in self.allowed_attributes_by_tag:
139
+ raise TagNotAllowedException((lineno, tag))
140
+
141
+ allowed_attributes = self.allowed_attributes_by_tag[tag]
142
+ diff_attributes = set(attrdict.keys()) - set(allowed_attributes)
143
+ for attr in diff_attributes:
144
+ if attr.startswith(self.extract_attribute + "-"): # i18n-
145
+ pair_attr = attr.removeprefix(self.extract_attribute + "-")
146
+ else:
147
+ pair_attr = f"{self.extract_attribute}-{attr}"
148
+ if pair_attr not in attrdict:
149
+ raise TagAttributeNotAllowedException((lineno, tag, attrdict))
150
+
151
+ if attrs:
152
+ rendered_attrs = " ".join(f'{name}="{value or ""}"' for name, value in attrs)
153
+ self.data.append(f"<{tag} {rendered_attrs}>")
154
+ else:
155
+ self.data.append(f"<{tag}>")
156
+
157
+ self.append_inner_tag(tag)
158
+ elif self.extract_attribute in attrdict or (tag in self.include_tags and self.do_not_extract_attribute not in attrdict):
159
+ self.start_lineno = lineno
160
+ self.in_translate = True
161
+ comment = attrdict.get(self.extract_attribute)
162
+ if comment:
163
+ self.comments.append(comment)
164
+
165
+ already_added_attrs = []
166
+ # auto-add attributes
167
+ for attr in self.include_attributes:
168
+ exclude_attribute = f"{self.do_not_extract_attribute}-{attr}"
169
+ value = attrdict.get(attr)
170
+ if value is not None and exclude_attribute not in attrdict:
171
+ self.add_entry(value, [attr], lineno)
172
+ already_added_attrs.append(attr)
173
+
174
+ # i18n-marked attributes
175
+ for attr in attrdict:
176
+ if attr.startswith(self.extract_attribute + "-"):
177
+ name = attr.removeprefix(self.extract_attribute + "-")
178
+ if name not in attrdict:
179
+ raise MissingAttributeException((lineno, tag, name))
180
+
181
+ value = attrdict[name]
182
+ if value is not None and name not in already_added_attrs:
183
+ self.add_entry(value, [name], lineno)
184
+
185
+ def handle_data(self, data: str) -> None:
186
+ if self.in_translate:
187
+ self.data.append(data)
188
+
189
+ def handle_endtag(self, tag: str) -> None:
190
+ if self.in_do_not_translate:
191
+ if len(self.inner_tags) > 0:
192
+ self.inner_tags.pop()
193
+ return
194
+
195
+ self.in_do_not_translate = False
196
+
197
+ if self.in_translate:
198
+ if len(self.inner_tags) > 0:
199
+ tag = self.inner_tags.pop()
200
+ self.data.append(f"</{tag}>")
201
+ return
202
+
203
+ self.add_entry("".join(self.data), self.comments)
204
+ self.in_translate = False
205
+ self.data.clear()
206
+ self.comments = []
207
+
208
+
209
+ def get_option_list(options: Mapping[str, str], name: str, default: list[str] | None = None) -> list[str]:
210
+ if default is None:
211
+ default = []
212
+ value = options.get(name)
213
+ return value.replace(",", " ").split() if value else default
214
+
215
+
216
+ def get_option_bool(options: Mapping[str, str], name: str, default: bool = False) -> bool:
217
+ value = options.get(name)
218
+ if value is None:
219
+ return default
220
+ if isinstance(value, bool):
221
+ return value
222
+ normalized_value = value.strip().lower()
223
+ if normalized_value in {"1", "true", "yes", "on"}:
224
+ return True
225
+ if normalized_value in {"0", "false", "no", "off"}:
226
+ return False
227
+ raise ValueError(f"Invalid boolean value for {name}: {value!r}")
228
+
229
+
230
+ def extract_angularjs(
231
+ fileobj: Iterable[str | bytes],
232
+ keywords: Any,
233
+ comment_tags: Any,
234
+ options: Mapping[str, str],
235
+ ) -> Iterator[ExtractorEntry]:
236
+ """Extract messages from AngularJS template (HTML) files that use the
237
+ data-translate directive as per.
238
+
239
+ :param fileobj: the file-like object the messages should be extracted from
240
+ :param keywords: This is a standard parameter so it isaccepted but ignored.
241
+ :param comment_tags: This is a standard parameter so it is accepted but ignored.
242
+ :param options: Extractor configuration options.
243
+ :return: an iterator over ``(lineno, funcname, message, comments)`` tuples,
244
+ optionally extended by a fifth ``flags`` value
245
+ :rtype: ``iterator``
246
+ """
247
+ include_tags = get_option_list(options, "include_tags")
248
+ include_attributes = get_option_list(options, "include_attributes")
249
+ allowed_tags = get_option_list(options, "allowed_tags", ["strong", "br", "i"])
250
+ extract_attribute = options.get("extract_attribute") or "i18n"
251
+ include_format_flags = get_option_bool(options, "include_format_flags")
252
+ allowed_attributes_by_tag = {tag: get_option_list(options, "allowed_attributes_" + tag) for tag in allowed_tags}
253
+ encoding = options.get('encoding', 'utf-8')
254
+
255
+ parser = AngularJSGettextHTMLParser(
256
+ include_tags,
257
+ include_attributes,
258
+ extract_attribute,
259
+ allowed_attributes_by_tag,
260
+ include_format_flags,
261
+ )
262
+
263
+ for line in fileobj:
264
+ if isinstance(line, bytes):
265
+ line = line.decode(encoding)
266
+ line = line.replace("&#xa;", "<br>")
267
+ line = line.replace("&nbsp;", " ")
268
+ parser.feed(line)
269
+
270
+ yield from parser.entries
@@ -0,0 +1,116 @@
1
+ Metadata-Version: 2.4
2
+ Name: pybabel-angularjs
3
+ Version: 1.5.0
4
+ Summary: An AngularJS extractor for Babel
5
+ Author-email: Jaromír Pufler <jaromir.pufler@gmail.com>
6
+ License: Apache Software License
7
+ Project-URL: Homepage, https://github.com/chuckyblack/pybabel-angularjs
8
+ Keywords: angularjs,gettext,babel,i18n,translate
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Software Development :: Internationalization
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: babel
24
+ Dynamic: license-file
25
+
26
+ # pybabel-angularjs
27
+
28
+ [![CI](https://github.com/chuckyblack/pybabel-angularjs/actions/workflows/release.yml/badge.svg?branch=master)](https://github.com/chuckyblack/pybabel-angularjs/actions/workflows/release.yml)
29
+ [![PyPI](https://img.shields.io/pypi/v/pybabel-angularjs.svg)](https://pypi.org/project/pybabel-angularjs/)
30
+
31
+ A [Babel](https://babel.pocoo.org/) message extractor for AngularJS HTML
32
+ templates. It extracts element content and attributes marked for translation,
33
+ including strings containing AngularJS expressions such as `{{ name }}`.
34
+
35
+ Requires Python 3.12 or newer.
36
+
37
+ ## Installation
38
+
39
+ ```console
40
+ python -m pip install pybabel-angularjs
41
+ ```
42
+
43
+ The package installs the `angularjs` Babel extractor entry point. Add it to a
44
+ Babel mapping file such as `babel.cfg`:
45
+
46
+ ```ini
47
+ [angularjs: **/*.html]
48
+ encoding = utf-8
49
+ ```
50
+
51
+ Then extract messages in the usual way:
52
+
53
+ ```console
54
+ pybabel extract -F babel.cfg -o messages.pot .
55
+ ```
56
+
57
+ ## Marking messages
58
+
59
+ Mark an element's content with `i18n`:
60
+
61
+ ```html
62
+ <div i18n>Hello world!</div>
63
+ <p i18n>Hello {{ name }}!</p>
64
+ ```
65
+
66
+ The value of `i18n`, when present, is included as a comment for translators:
67
+
68
+ ```html
69
+ <h1 i18n="Page heading">Welcome</h1>
70
+ ```
71
+
72
+ Mark an individual attribute by adding the `i18n-` prefix:
73
+
74
+ ```html
75
+ <input placeholder="Your name" i18n-placeholder>
76
+ ```
77
+
78
+ ## Configuration
79
+
80
+ Options are set in the extractor section of the Babel mapping file. Lists can
81
+ be separated by commas or whitespace.
82
+
83
+ ```ini
84
+ [angularjs: **/*.html]
85
+ encoding = utf-8
86
+ include_tags = h1, h2, p
87
+ include_attributes = title, alt, placeholder
88
+ allowed_tags = a, strong, br, i
89
+ allowed_attributes_a = href, target
90
+ include_format_flags = false
91
+ ```
92
+
93
+ - `extract_attribute` changes the marker from the default `i18n`, for example
94
+ to `data-translate`.
95
+ - `include_tags` extracts all content from the listed tags without requiring an
96
+ explicit marker.
97
+ - `include_attributes` extracts the listed attributes wherever they occur.
98
+ - `allowed_tags` controls which nested HTML tags may appear inside a translated
99
+ message. The default is `strong, br, i`.
100
+ - `allowed_attributes_<tag>` controls attributes allowed on a nested tag, for
101
+ example `allowed_attributes_a = href, target`.
102
+ - `encoding` controls template decoding and defaults to `utf-8`.
103
+ - `include_format_flags` makes the extractor return an extended five-value
104
+ result and marks messages containing AngularJS interpolation with
105
+ `angularjs-format`. It defaults to `false` because official Babel releases
106
+ accept only the standard four-value extractor result. Enable it only with a
107
+ Babel build that explicitly supports extractor-provided flags.
108
+
109
+ Use `no-i18n` to exclude an automatically included tag. A `<div no-i18n>`
110
+ excludes its entire subtree. For automatically included attributes, use the
111
+ corresponding marker such as `no-i18n-title`.
112
+
113
+ ## License
114
+
115
+ Apache License 2.0. The project was heavily inspired by the original
116
+ [shoreware/pybabel-angularjs](https://bitbucket.org/shoreware/pybabel-angularjs).
@@ -1,8 +1,7 @@
1
1
  LICENSE
2
2
  MANIFEST.in
3
3
  README.md
4
- setup.cfg
5
- setup.py
4
+ pyproject.toml
6
5
  src/pybabel_angularjs/__init__.py
7
6
  src/pybabel_angularjs/extractor.py
8
7
  src/pybabel_angularjs.egg-info/PKG-INFO
@@ -1,3 +1,2 @@
1
1
  [babel.extractors]
2
2
  angularjs = pybabel_angularjs.extractor:extract_angularjs
3
-
@@ -1,95 +0,0 @@
1
- Metadata-Version: 1.1
2
- Name: pybabel-angularjs
3
- Version: 1.3.5
4
- Summary: An AngularJS extractor for Babel
5
- Home-page: https://github.com/chuckyblack/pybabel-angularjs
6
- Author: Jaromír Pufler
7
- Author-email: jaromir.pufler@gmail.com
8
- License: Apache Software License
9
- Description: pybabel-angularjs
10
- =================
11
-
12
- [![Build Status](https://travis-ci.org/chuckyblack/pybabel-angularjs.svg?branch=master)](https://travis-ci.org/chuckyblack/pybabel-angularjs.svg?branch=master)
13
-
14
- A Babel extractor for AngularJS templates.
15
-
16
- To translate the content of an HTML element use the `i18n`
17
- attribute:
18
-
19
- <div i18n>hello world!</div>
20
-
21
- To give somme context to your translators add value to the attribute:
22
-
23
- <div i18n="page title">hello world!</div>
24
-
25
- ## Babel configuration
26
-
27
- ### extract_attribute
28
-
29
- To change default `i18n` attribute use `extract_attribute` options:
30
-
31
- [angularjs: **/*.html]
32
- encoding = utf-8
33
- extract_attribute = translate
34
-
35
- Then use in template:
36
-
37
- <div translate="page title">hello world!</div>
38
-
39
- ### include_attributes
40
-
41
- To translate attributes of HTML nodes use `include_attributes` options:
42
-
43
- [angularjs: **/*.html]
44
- encoding = utf-8
45
- include_attributes = title, alt
46
-
47
- Then use in template:
48
-
49
- <div title="some title">hello world!</div>
50
- <img src="..." alt="some image description">
51
-
52
-
53
- ### allowed_tags
54
-
55
- Content of every translated tag is checked for tags it contains. You have to define sub-tags that can occur.
56
- Tags allowed by default are: strong, br, i
57
-
58
- [angularjs: **/*.html]
59
- encoding = utf-8
60
- allowed_tags = a, strong, br
61
-
62
-
63
- ### allowed_attributes_x
64
-
65
- Sub-tags (described in 'allowed_tags') may by default contain NO attributes at all.
66
- If you want to enable them to, you have to use this notation:
67
-
68
- [angularjs: **/*.html]
69
- encoding = utf-8
70
- allowed_tags = a, i
71
- allowed_attributes_a = href
72
- allowed_attributes_i = class
73
-
74
- The allowed_attribues_x setting needs to be accompanied by appropriate 'allowed_tags' setting.
75
-
76
-
77
- Heavily inspired by
78
- https://bitbucket.org/shoreware/pybabel-angularjs
79
-
80
- Keywords: angularjs gettext babel i18n translate
81
- Platform: UNKNOWN
82
- Classifier: Development Status :: 5 - Production/Stable
83
- Classifier: Intended Audience :: Developers
84
- Classifier: Topic :: Software Development :: Internationalization
85
- Classifier: License :: OSI Approved :: Apache Software License
86
- Classifier: Operating System :: OS Independent
87
- Classifier: Programming Language :: Python
88
- Classifier: Programming Language :: Python :: 2
89
- Classifier: Programming Language :: Python :: 2.6
90
- Classifier: Programming Language :: Python :: 2.7
91
- Classifier: Programming Language :: Python :: 3
92
- Classifier: Programming Language :: Python :: 3.2
93
- Classifier: Programming Language :: Python :: 3.3
94
- Classifier: Programming Language :: Python :: 3.4
95
- Classifier: Programming Language :: Python :: 3.5
@@ -1,70 +0,0 @@
1
- pybabel-angularjs
2
- =================
3
-
4
- [![Build Status](https://travis-ci.org/chuckyblack/pybabel-angularjs.svg?branch=master)](https://travis-ci.org/chuckyblack/pybabel-angularjs.svg?branch=master)
5
-
6
- A Babel extractor for AngularJS templates.
7
-
8
- To translate the content of an HTML element use the `i18n`
9
- attribute:
10
-
11
- <div i18n>hello world!</div>
12
-
13
- To give somme context to your translators add value to the attribute:
14
-
15
- <div i18n="page title">hello world!</div>
16
-
17
- ## Babel configuration
18
-
19
- ### extract_attribute
20
-
21
- To change default `i18n` attribute use `extract_attribute` options:
22
-
23
- [angularjs: **/*.html]
24
- encoding = utf-8
25
- extract_attribute = translate
26
-
27
- Then use in template:
28
-
29
- <div translate="page title">hello world!</div>
30
-
31
- ### include_attributes
32
-
33
- To translate attributes of HTML nodes use `include_attributes` options:
34
-
35
- [angularjs: **/*.html]
36
- encoding = utf-8
37
- include_attributes = title, alt
38
-
39
- Then use in template:
40
-
41
- <div title="some title">hello world!</div>
42
- <img src="..." alt="some image description">
43
-
44
-
45
- ### allowed_tags
46
-
47
- Content of every translated tag is checked for tags it contains. You have to define sub-tags that can occur.
48
- Tags allowed by default are: strong, br, i
49
-
50
- [angularjs: **/*.html]
51
- encoding = utf-8
52
- allowed_tags = a, strong, br
53
-
54
-
55
- ### allowed_attributes_x
56
-
57
- Sub-tags (described in 'allowed_tags') may by default contain NO attributes at all.
58
- If you want to enable them to, you have to use this notation:
59
-
60
- [angularjs: **/*.html]
61
- encoding = utf-8
62
- allowed_tags = a, i
63
- allowed_attributes_a = href
64
- allowed_attributes_i = class
65
-
66
- The allowed_attribues_x setting needs to be accompanied by appropriate 'allowed_tags' setting.
67
-
68
-
69
- Heavily inspired by
70
- https://bitbucket.org/shoreware/pybabel-angularjs
@@ -1,10 +0,0 @@
1
- [aliases]
2
- test = pytest
3
-
4
- [bdist_wheel]
5
- universal = 1
6
-
7
- [egg_info]
8
- tag_build =
9
- tag_date = 0
10
-
@@ -1,41 +0,0 @@
1
- # coding=utf-8
2
-
3
- from setuptools import setup, find_packages
4
-
5
- setup(
6
- name="pybabel-angularjs",
7
- version="1.3.5",
8
- author="Jaromír Pufler",
9
- author_email="jaromir.pufler@gmail.com",
10
- url="https://github.com/chuckyblack/pybabel-angularjs",
11
- description="An AngularJS extractor for Babel",
12
- long_description=open('README.md').read(),
13
- package_dir={'': 'src'},
14
- packages=find_packages('src'),
15
- install_requires=['babel', 'beautifulsoup4'],
16
- setup_requires=['pytest-runner'],
17
- tests_require=['pytest'],
18
- entry_points={
19
- 'babel.extractors': [
20
- 'angularjs=pybabel_angularjs.extractor:extract_angularjs',
21
- ],
22
- },
23
- license="Apache Software License",
24
- keywords="angularjs gettext babel i18n translate",
25
- classifiers=[
26
- "Development Status :: 5 - Production/Stable",
27
- "Intended Audience :: Developers",
28
- "Topic :: Software Development :: Internationalization",
29
- "License :: OSI Approved :: Apache Software License",
30
- "Operating System :: OS Independent",
31
- "Programming Language :: Python",
32
- "Programming Language :: Python :: 2",
33
- "Programming Language :: Python :: 2.6",
34
- "Programming Language :: Python :: 2.7",
35
- "Programming Language :: Python :: 3",
36
- "Programming Language :: Python :: 3.2",
37
- "Programming Language :: Python :: 3.3",
38
- "Programming Language :: Python :: 3.4",
39
- "Programming Language :: Python :: 3.5",
40
- ],
41
- )
@@ -1,235 +0,0 @@
1
- # coding=utf-8
2
-
3
- try:
4
- from html.parser import HTMLParser
5
- except ImportError:
6
- from HTMLParser import HTMLParser
7
-
8
- import re
9
-
10
-
11
- class TagNotAllowedException(Exception):
12
- pass
13
-
14
-
15
- class TagAttributeNotAllowedException(Exception):
16
- pass
17
-
18
-
19
- class ExtractAttributeNotAllowedException(Exception):
20
- pass
21
-
22
-
23
- class MissingAttributeException(Exception):
24
- pass
25
-
26
-
27
- class AngularJSGettextHTMLParser(HTMLParser):
28
- """Parse HTML to find translate directives.
29
-
30
- Currently this parses for these forms of translation:
31
-
32
- <p data-translate>content</p>
33
- The content will be translated. Angular value templating will be
34
- recognised and transformed into gettext-familiar translation
35
- entries (i.e. "{$ expression $}" becomes "%(expression)")
36
- """
37
-
38
- def __init__(self, encoding, include_tags, include_attributes, extract_attribute, allowed_attributes_by_tag):
39
- try:
40
- super(AngularJSGettextHTMLParser, self).__init__()
41
- except TypeError:
42
- HTMLParser.__init__(self)
43
-
44
- self.encoding = encoding
45
- self.include_tags = include_tags
46
- self.include_attributes = include_attributes
47
- self.extract_attribute = extract_attribute
48
- self.allowed_attributes_by_tag = allowed_attributes_by_tag
49
-
50
- self.in_translate = False
51
- self.inner_tags = []
52
- self.data = ''
53
- self.entries = []
54
- self.start_lineno = 0
55
- self.plural = False
56
- self.plural_form = ''
57
- self.comments = []
58
- self.re_collapse_whitespaces = re.compile("\s+")
59
- self.in_do_not_translate = False
60
-
61
- @property
62
- def do_not_extract_attribute(self):
63
- return "no-" + self.extract_attribute
64
-
65
- def normalize_string(self, string, replace_whitespace=u" "):
66
- """
67
- :type string: str
68
- :type replace_whitespace: str
69
- """
70
- string = (
71
- string
72
- .replace("\n", " ")
73
- .replace("\t", " ")
74
- .replace("/>", ">")
75
- .replace("</br>", "")
76
- .replace(u" ", "&nbsp;")
77
- )
78
- if isinstance(string, bytes):
79
- string = string.decode("utf-8")
80
- return self.re_collapse_whitespaces.sub(replace_whitespace, string).strip()
81
-
82
- def add_entry(self, message, comments=[], lineno=None):
83
- self.entries.append(
84
- (
85
- lineno or self.start_lineno,
86
- u'gettext',
87
- self.normalize_string(message),
88
- [self.normalize_string(comment) for comment in comments],
89
- ("angularjs-format", ) if "{{" in message else tuple()
90
- )
91
- )
92
-
93
- def append_inner_tag(self, tag):
94
- if tag not in ("br", "input", "img"):
95
- self.inner_tags.append(tag)
96
-
97
- def attrdict_contains(self, attrdict, search=None):
98
- search = search or [self.extract_attribute, self.do_not_extract_attribute]
99
- for attr in attrdict: # type: str
100
- for string in search:
101
- if attr.startswith(string):
102
- return True
103
- return False
104
-
105
- def handle_starttag(self, tag, attrs):
106
- attrdict = dict(attrs)
107
- lineno = self.getpos()[0]
108
-
109
- if self.in_do_not_translate:
110
- if self.attrdict_contains(attrdict):
111
- raise ExtractAttributeNotAllowedException((lineno, tag, attrdict))
112
- self.append_inner_tag(tag)
113
- return
114
-
115
- if tag == "div" and self.do_not_extract_attribute in attrdict:
116
- self.in_do_not_translate = True
117
- if self.attrdict_contains(attrdict, [self.extract_attribute]):
118
- raise ExtractAttributeNotAllowedException((lineno, tag, attrdict))
119
- return
120
-
121
- # handle data-translate attribute for translating content
122
- if self.extract_attribute in attrdict or (tag in self.include_tags and self.do_not_extract_attribute not in attrdict):
123
- self.start_lineno = lineno
124
- self.in_translate = True
125
- comment = attrdict.get(self.extract_attribute)
126
- if comment:
127
- self.comments.append(comment)
128
- elif self.in_translate:
129
- if tag not in self.allowed_attributes_by_tag:
130
- raise TagNotAllowedException((lineno, tag))
131
-
132
- allowed_attributes = self.allowed_attributes_by_tag[tag]
133
- diff_attributes = set(attrdict.keys()) - set(allowed_attributes)
134
- for attr in diff_attributes:
135
- if attr.startswith(self.extract_attribute + "-"): # i18n-
136
- pairAttr = attr.split("-", 1)[1]
137
- else:
138
- pairAttr = "%s-%s" % (self.extract_attribute, attr)
139
- if pairAttr not in attrdict:
140
- raise TagAttributeNotAllowedException((lineno, tag, attrdict))
141
-
142
- if attrs:
143
- insert_value = ""
144
- for attr in attrs:
145
- name = attr[0]
146
- value = attr[1]
147
- insert_value += " " + '%s="%s"' % (name, value or "")
148
- self.data += '<%s %s>' % (tag, insert_value)
149
- else:
150
- self.data += '<%s>' % tag
151
-
152
- self.append_inner_tag(tag)
153
-
154
- already_added_attrs = []
155
- # auto-add attributes
156
- for attr in self.include_attributes:
157
- exclude_attribute = "%s-%s" % (self.do_not_extract_attribute, attr)
158
- if attr in attrdict and exclude_attribute not in attrdict:
159
- self.add_entry(attrdict[attr], [attr], lineno)
160
- already_added_attrs.append(attr)
161
-
162
- # i18n-marked attributes
163
- for attr in attrdict: # type: str
164
- if attr.startswith(self.extract_attribute + "-"):
165
- name = attr.split("-", 1)[1]
166
- if name not in attrdict:
167
- raise MissingAttributeException((lineno, tag, name))
168
-
169
- if name not in already_added_attrs:
170
- self.add_entry(attrdict[name], [name], lineno)
171
-
172
- def handle_data(self, data):
173
- if self.in_translate:
174
- self.data += data
175
-
176
- def handle_endtag(self, tag):
177
- if self.in_do_not_translate:
178
- if len(self.inner_tags) > 0:
179
- self.inner_tags.pop()
180
- return
181
-
182
- self.in_do_not_translate = False
183
-
184
- if self.in_translate:
185
- if len(self.inner_tags) > 0:
186
- tag = self.inner_tags.pop()
187
- self.data += "</%s>" % tag
188
- return
189
-
190
- self.add_entry(self.data, self.comments)
191
- self.in_translate = False
192
- self.data = ''
193
- self.comments = []
194
-
195
-
196
- def get_option_list(options, name, default=[]):
197
- value = options.get(name)
198
- return value and value.split(" ") or default
199
-
200
-
201
- def extract_angularjs(fileobj, keywords, comment_tags, options):
202
- """Extract messages from AngularJS template (HTML) files that use the
203
- data-translate directive as per.
204
-
205
- :param fileobj: the file-like object the messages should be extracted from
206
- :param keywords: This is a standard parameter so it isaccepted but ignored.
207
- :param comment_tags: This is a standard parameter so it is accepted but ignored.
208
- :param options: Another standard parameter that is accepted but ignored.
209
- :return: an iterator over ``(lineno, funcname, message, comments, flags)`` tuples
210
- :rtype: ``iterator``
211
- """
212
- include_tags = get_option_list(options, "include_tags")
213
- include_attributes = get_option_list(options, "include_attributes")
214
- allowed_tags = get_option_list(options, "allowed_tags", ["strong", "br", "i"])
215
- extract_attribute = options.get("extract_attribute") or "i18n"
216
- allowed_attributes_by_tag = {tag: get_option_list(options, "allowed_attributes_" + tag) for tag in allowed_tags}
217
- encoding = options.get('encoding', 'utf-8')
218
-
219
- parser = AngularJSGettextHTMLParser(
220
- encoding,
221
- include_tags,
222
- include_attributes,
223
- extract_attribute,
224
- allowed_attributes_by_tag
225
- )
226
-
227
- for line in fileobj:
228
- if isinstance(line, bytes):
229
- line = line.decode("utf-8")
230
- line = line.replace("&#xa;", "<br>")
231
- line = line.replace("&nbsp;", u" ")
232
- parser.feed(line)
233
-
234
- for entry in parser.entries:
235
- yield entry
@@ -1,95 +0,0 @@
1
- Metadata-Version: 1.1
2
- Name: pybabel-angularjs
3
- Version: 1.3.5
4
- Summary: An AngularJS extractor for Babel
5
- Home-page: https://github.com/chuckyblack/pybabel-angularjs
6
- Author: Jaromír Pufler
7
- Author-email: jaromir.pufler@gmail.com
8
- License: Apache Software License
9
- Description: pybabel-angularjs
10
- =================
11
-
12
- [![Build Status](https://travis-ci.org/chuckyblack/pybabel-angularjs.svg?branch=master)](https://travis-ci.org/chuckyblack/pybabel-angularjs.svg?branch=master)
13
-
14
- A Babel extractor for AngularJS templates.
15
-
16
- To translate the content of an HTML element use the `i18n`
17
- attribute:
18
-
19
- <div i18n>hello world!</div>
20
-
21
- To give somme context to your translators add value to the attribute:
22
-
23
- <div i18n="page title">hello world!</div>
24
-
25
- ## Babel configuration
26
-
27
- ### extract_attribute
28
-
29
- To change default `i18n` attribute use `extract_attribute` options:
30
-
31
- [angularjs: **/*.html]
32
- encoding = utf-8
33
- extract_attribute = translate
34
-
35
- Then use in template:
36
-
37
- <div translate="page title">hello world!</div>
38
-
39
- ### include_attributes
40
-
41
- To translate attributes of HTML nodes use `include_attributes` options:
42
-
43
- [angularjs: **/*.html]
44
- encoding = utf-8
45
- include_attributes = title, alt
46
-
47
- Then use in template:
48
-
49
- <div title="some title">hello world!</div>
50
- <img src="..." alt="some image description">
51
-
52
-
53
- ### allowed_tags
54
-
55
- Content of every translated tag is checked for tags it contains. You have to define sub-tags that can occur.
56
- Tags allowed by default are: strong, br, i
57
-
58
- [angularjs: **/*.html]
59
- encoding = utf-8
60
- allowed_tags = a, strong, br
61
-
62
-
63
- ### allowed_attributes_x
64
-
65
- Sub-tags (described in 'allowed_tags') may by default contain NO attributes at all.
66
- If you want to enable them to, you have to use this notation:
67
-
68
- [angularjs: **/*.html]
69
- encoding = utf-8
70
- allowed_tags = a, i
71
- allowed_attributes_a = href
72
- allowed_attributes_i = class
73
-
74
- The allowed_attribues_x setting needs to be accompanied by appropriate 'allowed_tags' setting.
75
-
76
-
77
- Heavily inspired by
78
- https://bitbucket.org/shoreware/pybabel-angularjs
79
-
80
- Keywords: angularjs gettext babel i18n translate
81
- Platform: UNKNOWN
82
- Classifier: Development Status :: 5 - Production/Stable
83
- Classifier: Intended Audience :: Developers
84
- Classifier: Topic :: Software Development :: Internationalization
85
- Classifier: License :: OSI Approved :: Apache Software License
86
- Classifier: Operating System :: OS Independent
87
- Classifier: Programming Language :: Python
88
- Classifier: Programming Language :: Python :: 2
89
- Classifier: Programming Language :: Python :: 2.6
90
- Classifier: Programming Language :: Python :: 2.7
91
- Classifier: Programming Language :: Python :: 3
92
- Classifier: Programming Language :: Python :: 3.2
93
- Classifier: Programming Language :: Python :: 3.3
94
- Classifier: Programming Language :: Python :: 3.4
95
- Classifier: Programming Language :: Python :: 3.5
@@ -1,2 +0,0 @@
1
- babel
2
- beautifulsoup4