-
-
Notifications
You must be signed in to change notification settings - Fork 709
Generate l10n per locale #3585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
cheweaaron609-png
wants to merge
39
commits into
vacanza:dev
Choose a base branch
from
cheweaaron609-png:generate-l10n-per-locale
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+37,817
−0
Draft
Generate l10n per locale #3585
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
4ccf40a
Add json_builder.py with --refresh and --split flags
cheweaaron609-png c10d538
Remove json_splitter.py reference from pyproject.toml
cheweaaron609-png 649381f
Fix path injection warning by resolving output path
cheweaaron609-png 6a62c23
Rename holidays_intermediate.json to holidays_l10n.json and track in …
cheweaaron609-png 5b3a0b1
Refactor to instance-based class, fix flat-language split bug, add ba…
cheweaaron609-png 343f5a8
Add Aaron Chewe to CONTRIBUTORS
cheweaaron609-png 11a7a68
Refactor script
KJhellico e181dd1
Merge branch 'dev' into gsoc/my-l10n-per-locale
KJhellico 5a7da51
Latest translations
KJhellico 64007a5
Add new comment's field
KJhellico 3c3be1d
Merge remote-tracking branch 'upstream/dev' into generate-l10n-per-lo…
cheweaaron609-png 3dbf3d8
Latest translations
KJhellico 19975f6
Keep new comment value
KJhellico 5a00682
Add Cap 149 pre-2012 citation for HK Lunar New Year's Eve and new_com…
cheweaaron609-png 7d36890
HK Lunar New Year's Eve update
KJhellico 3966675
XHKG fix
KJhellico a88d76f
Add generate_locale_po_files.py for per-locale .pot and .po generation
cheweaaron609-png eef00f1
Update script
KJhellico c215d95
Merge branch 'dev' into gsoc/l10n-per-locale
KJhellico 8c737aa
Update JSON with latest translations
KJhellico 8dda65e
Merge branch 'dev' into gsoc/l10n-per-locale
KJhellico 26e4a37
Update JSON with latest translations
KJhellico 4a98ea9
Split Independence Day
KJhellico 4253841
Replace tr() strings with l10n msgid
cheweaaron609-png 84b63a1
Fix replace_tr_strings.py
cheweaaron609-png 838f614
Merge branch 'dev' into gsoc/l10n-per-locale
KJhellico 696f4c1
Refactor replace_tr_strings.py
cheweaaron609-png 55e1eea
Refactor replace_tr_strings.py further
cheweaaron609-png 4b6d917
Update replace_tr_strings.py
cheweaaron609-png caf9f76
Split nested entries in json
cheweaaron609-png dc673e6
Add warning and handle multi-line comments in replace_tr_strings.py
cheweaaron609-png da84edc
Revert "Split nested entries in json"
cheweaaron609-png 9b13a10
Fix multi-line comment removal
cheweaaron609-png 716f4e5
Merge branch 'dev' into gsoc/l10n-per-locale
KJhellico d7d8719
Update JSON with latest translations
KJhellico ac116cc
Merge branch 'dev' into gsoc/l10n-per-locale
KJhellico 01a8664
Update JSON with latest translations
KJhellico e0cc6c0
Merge branch 'refs/heads/dev' into gsoc/l10n-per-locale
KJhellico d20b2c4
Update JSON with latest translations
KJhellico File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| Aadesh Shrivastava | ||
| Aaqil Yousuf | ||
| Aaron Chewe | ||
| Aaron Picht | ||
| Aart Goossens | ||
| Abdelkhalek Boukli Hacene | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| #!/usr/bin/env python3 | ||
|
|
||
|
|
||
| # holidays | ||
| # -------- | ||
| # A fast, efficient Python library for generating country, province and state | ||
| # specific sets of holidays on the fly. It aims to make determining whether a | ||
| # specific date is a holiday as fast and flexible as possible. | ||
| # | ||
| # Authors: Vacanza Team and individual contributors (see CONTRIBUTORS file) | ||
| # dr-prodigy <dr.prodigy.github@gmail.com> (c) 2017-2023 | ||
| # ryanss <ryanssdev@icloud.com> (c) 2014-2017 | ||
| # Website: https://github.com/vacanza/holidays | ||
| # License: MIT (see LICENSE file) | ||
|
|
||
| """Generate per-locale .pot and .po files from the JSON file. | ||
|
|
||
| Run with: | ||
| python scripts/l10n/generate_locale_po_files.py | ||
|
|
||
| This generates: | ||
| * holidays/locale/holidays.pot - master template with all msgids | ||
| * holidays/locale/{lang}.po - one per language | ||
| """ | ||
|
|
||
| import json | ||
| import re | ||
| import sys | ||
| from datetime import datetime | ||
| from pathlib import Path | ||
|
|
||
| from polib import POEntry, POFile | ||
|
|
||
| sys.path.insert(0, str(Path.cwd())) | ||
| from holidays import __version__ as package_version | ||
|
|
||
| JSON_PATH = Path("scripts/l10n/holidays_l10n.json") | ||
| LOCALE_PATH = Path("holidays/locale") | ||
| HEADER_PATH = Path("docs/file_header.txt") | ||
| POT_FILENAME = "holidays.pot" | ||
| WRAP_WIDTH = 99 | ||
| MSGID_BUGS_ADDRESS = "l10n@vacanza.dev" | ||
| TRANSLATOR_PATTERN = re.compile(r"[^\s<]+(?:\s+[^\s<]+)*\s+<[^@\s<]+@[^@\s<.]+(?:\.[^@\s<.]+)+>") | ||
|
|
||
|
|
||
| class LocalePOGenerator: | ||
| """Generates per-locale .pot and .po files from the JSON.""" | ||
|
|
||
| def __init__(self) -> None: | ||
| if not JSON_PATH.exists(): | ||
| raise FileNotFoundError(f"{JSON_PATH} not found!") | ||
| with JSON_PATH.open(encoding="utf-8") as f: | ||
| self.data: list[dict] = json.load(f) | ||
|
|
||
| self.timestamp = datetime.now().astimezone().strftime("%Y-%m-%d %H:%M%z") | ||
| self.license_header = self._get_license_header() | ||
|
|
||
| @staticmethod | ||
| def _get_license_header() -> str: | ||
| """Read and format the license header from docs/file_header.txt.""" | ||
| content = HEADER_PATH.read_text(encoding="utf-8").lstrip("\n") | ||
|
KJhellico marked this conversation as resolved.
|
||
| return ( | ||
| "\n".join( | ||
| f"# {stripped}" if (stripped := line.rstrip()) else "#" | ||
| for line in content.splitlines() | ||
| ) | ||
| + "\n#" | ||
| ) | ||
|
|
||
| def _make_metadata(self, lang: str | None = None) -> dict: | ||
| """Build standard Gettext metadata for a .po or .pot file.""" | ||
| return { | ||
| "Project-Id-Version": f"Holidays {package_version}", | ||
| "Report-Msgid-Bugs-To": MSGID_BUGS_ADDRESS, | ||
| "POT-Creation-Date": self.timestamp, | ||
| "PO-Revision-Date": self.timestamp, | ||
| "Last-Translator": f"Holidays Localization Team <{MSGID_BUGS_ADDRESS}>", | ||
| "Language-Team": "Holidays Localization Team", | ||
| "Language": lang or "en", | ||
| "MIME-Version": "1.0", | ||
| "Content-Type": "text/plain; charset=UTF-8", | ||
| "Content-Transfer-Encoding": "8bit", | ||
| "X-Source-Language": "en", | ||
| } | ||
|
|
||
| def _write_po_header(self, po_path: Path, lang: str | None) -> None: | ||
| """Prepend the license header to a written .po file.""" | ||
| output = [ | ||
| self.license_header, | ||
| f"# Holidays {lang} localization." if lang else "# Holidays localization.", | ||
| "#", | ||
| po_path.read_text(encoding="utf-8"), | ||
| ] | ||
| po_path.write_text("\n".join(output), encoding="utf-8", newline="\n") | ||
|
Check failure on line 94 in scripts/l10n/generate_locale_po_files.py
|
||
|
|
||
|
|
||
| def _build_po(self, lang: str | None = None) -> None: | ||
| """Build a per-locale .po file for a given language.""" | ||
| po = POFile(wrapwidth=WRAP_WIDTH) | ||
| po.metadata = self._make_metadata(lang) | ||
|
|
||
| for entry in self.data: | ||
| po.append( | ||
| POEntry( | ||
| msgid=entry["msgid"], | ||
| msgstr=entry["messages"].get(lang) or "", | ||
|
KJhellico marked this conversation as resolved.
|
||
| comment=entry.get("new_comment"), | ||
|
KJhellico marked this conversation as resolved.
|
||
| flags=["c-format"] if "%" in entry["msgid"] else [], | ||
| ) | ||
| ) | ||
|
|
||
| po_path = LOCALE_PATH / (f"{lang}.po" if lang else POT_FILENAME) | ||
| po.save(str(po_path), newline="\n") | ||
| self._write_po_header(po_path, lang) | ||
| print(f"Saved {po_path} ({len(po)} entries)") | ||
|
|
||
| def _collect_languages(self) -> set[str]: | ||
| """Collect all language codes present across all entries.""" | ||
| langs: set[str] = set() | ||
| for entry in self.data: | ||
| for lang, val in entry["messages"].items(): | ||
| if isinstance(val, str): | ||
| langs.add(lang) | ||
| else: | ||
|
KJhellico marked this conversation as resolved.
|
||
| raise ValueError( | ||
| f"Msgid `{entry['msgid']}` contains multiple translation for lang `{lang}`" | ||
| ) | ||
|
|
||
| return langs | ||
|
|
||
| def run(self) -> None: | ||
| """Generate the .pot and all per-locale .po files.""" | ||
| langs = self._collect_languages() | ||
| # build .pot file. | ||
| self._build_po() | ||
|
|
||
| print(f"Generating .po files for {len(langs)} languages...") | ||
| for lang in sorted(langs): | ||
| self._build_po(lang) | ||
|
|
||
| print("Done.") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| LocalePOGenerator().run() | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.