From 45c143b4363fdede50c236e1f3ba0564c55b5881 Mon Sep 17 00:00:00 2001 From: Felipe Moreno Date: Thu, 6 Jun 2024 09:13:06 -0400 Subject: [PATCH 1/6] Cleaned up the current noxfile.py --- noxfile.py | 89 ++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 53 deletions(-) diff --git a/noxfile.py b/noxfile.py index 7ba28129..2c0509a0 100644 --- a/noxfile.py +++ b/noxfile.py @@ -5,79 +5,62 @@ nox.options.reuse_existing_virtualenvs = True -OUTPUT_DIR = "_build" -docs_dir = os.path.join("_build", "html") -build_command = ["-b", "html", ".", docs_dir] +## Sphinx related options + +# Sphinx output and source directories +OUTPUT_DIR = pathlib.Path("_build", "html") +SOURCE_DIR = pathlib.Path(".") + +# Sphinx build commands +SPHINX_BUILD = "sphinx-build" +SPHINX_AUTO_BUILD = "sphinx-autobuild" + +# Sphinx parameters used to build the guide +BUILD_PARAMETERS = ["-b", "html"] + +# Sphinx parameters used to test the build of the guide +TEST_PARAMETERS = ['-W', '--keep-going', '-E', '-a'] + +# Sphinx-autobuild ignore and include parameters +AUTOBUILD_IGNORE = [ + "_build", + "build_assets", + "tmp", +] +AUTOBUILD_INCLUDE = [ + pathlib.Path("_static", "pyos.css") +] @nox.session def docs(session): + """Build the packaging guide.""" session.install("-e", ".") - cmd = ["sphinx-build"] - cmd.extend(build_command + session.posargs) + cmd = [SPHINX_BUILD, *BUILD_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs] session.run(*cmd) @nox.session(name="docs-test") def docs_test(session): - """ - Same as `docs`, but rebuild everything and fail on warnings for testing - """ + """Build the packaging guide with additional parameters.""" session.install("-e", ".") - cmd = ["sphinx-build"] - cmd.extend(['-W', '--keep-going', '-E', '-a']) - cmd.extend(build_command + session.posargs) + cmd = [SPHINX_BUILD, *BUILD_PARAMETERS, *TEST_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs] session.run(*cmd) - @nox.session(name="docs-live") def docs_live(session): + """Build and launch a local copy of the guide.""" session.install("-e", ".") - - AUTOBUILD_IGNORE = [ - "_build", - "build_assets", - "tmp", - ] - - # Explicitly include custom CSS in each build since - # sphinx doesn't think _static files should change since, - # well, they're static. - # Include these as the final `filenames` argument - - AUTOBUILD_INCLUDE = [ - os.path.join("_static", "pyos.css") - ] - - # ---------------- - # Assemble command - cmd = ["sphinx-autobuild"] + cmd = [SPHINX_AUTO_BUILD, *BUILD_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs] for folder in AUTOBUILD_IGNORE: cmd.extend(["--ignore", f"*/{folder}/*"]) - - #cmd.extend(build_command) - cmd.extend(build_command + session.posargs) - - # Use positional arguments if we have them - # if len(session.posargs) > 0: - # cmd.extend(session.posargs) - # # Otherwise use default output and include directory - # else: - # cmd.extend(AUTOBUILD_INCLUDE) - session.run(*cmd) - - @nox.session(name="docs-clean") -def clean_dir(dir_path=docs_dir): - """ - Clean out the docs directory used in the - live build. - """ - dir_path = pathlib.Path(dir_path) - dir_contents = dir_path.glob('*') - +def clean_dir(session): + """Clean out the docs directory used in the live build.""" + session.warn(f"Cleaning out {OUTPUT_DIR}") + dir_contents = OUTPUT_DIR.glob('*') for content in dir_contents: - print(content) + session.log(f'removing {content}') if content.is_dir(): shutil.rmtree(content) else: From a4c0bc16e742e7b067b8dee9b4b6d71e5b12d10b Mon Sep 17 00:00:00 2001 From: Felipe Moreno Date: Sun, 16 Jun 2024 12:07:50 -0400 Subject: [PATCH 2/6] Added internationalization to the nox file --- noxfile.py | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 154 insertions(+), 7 deletions(-) diff --git a/noxfile.py b/noxfile.py index 2c0509a0..dfb14f6b 100644 --- a/noxfile.py +++ b/noxfile.py @@ -8,9 +8,13 @@ ## Sphinx related options # Sphinx output and source directories -OUTPUT_DIR = pathlib.Path("_build", "html") +BUILD_DIR = '_build' +OUTPUT_DIR = pathlib.Path(BUILD_DIR, "html") SOURCE_DIR = pathlib.Path(".") +# Location of the translation templates +TRANSLATION_TEMPLATE_DIR = pathlib.Path(BUILD_DIR, "gettext") + # Sphinx build commands SPHINX_BUILD = "sphinx-build" SPHINX_AUTO_BUILD = "sphinx-autobuild" @@ -21,9 +25,13 @@ # Sphinx parameters used to test the build of the guide TEST_PARAMETERS = ['-W', '--keep-going', '-E', '-a'] +# Sphinx parameters to generate translation templates +TRANSLATION_TEMPLATE_PARAMETERS = ["-b", "gettext"] + # Sphinx-autobuild ignore and include parameters AUTOBUILD_IGNORE = [ "_build", + ".nox", "build_assets", "tmp", ] @@ -31,29 +39,95 @@ pathlib.Path("_static", "pyos.css") ] +## Localization options (translations) + +# List of languages for which locales will be generated in (/locales/) +LANGUAGES = ["es"] + +# List of languages that should be built when releasing the guide +RELEASE_LANGUAGES = ['es'] + + @nox.session def docs(session): """Build the packaging guide.""" session.install("-e", ".") - cmd = [SPHINX_BUILD, *BUILD_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs] - session.run(*cmd) + session.run(SPHINX_BUILD, *BUILD_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs) + # When building the guide, also build the translations in RELEASE_LANGUAGES + session.notify("build-translations", ['release-build']) + @nox.session(name="docs-test") def docs_test(session): - """Build the packaging guide with additional parameters.""" + """ + Build the packaging guide with more restricted parameters. + + Note: this is the session used in CI/CD to release the guide. + """ session.install("-e", ".") - cmd = [SPHINX_BUILD, *BUILD_PARAMETERS, *TEST_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs] - session.run(*cmd) + session.run(SPHINX_BUILD, *BUILD_PARAMETERS, *TEST_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs) + # When building the guide with additional parameters, also build the translations in RELEASE_LANGUAGES + # with those same parameters. + session.notify("build-translations", ['release-build', *TEST_PARAMETERS]) + @nox.session(name="docs-live") def docs_live(session): - """Build and launch a local copy of the guide.""" + """ + Build and launch a local copy of the guide. + + This session will use sphinx-autobuild to build the guide and launch a local server so you can + browse it locally. It will automatically rebuild the guide when changes are detected in the source. + + It can be used with the language parameter to build a specific translation, for example: + + nox -s docs-live -- -D language=es + + Note: The docs-live-lang session below is provided as a convenience session for beginner contributors + so they don't need to remember the specific sphinx-build parameters to build a different language. + """ session.install("-e", ".") cmd = [SPHINX_AUTO_BUILD, *BUILD_PARAMETERS, SOURCE_DIR, OUTPUT_DIR, *session.posargs] for folder in AUTOBUILD_IGNORE: cmd.extend(["--ignore", f"*/{folder}/*"]) + # This part was commented in the previous version of the nox file, keeping the same here + # for folder in AUTOBUILD_INCLUDE: + # cmd.extend(["--watch", folder]) session.run(*cmd) + +@nox.session(name="docs-live-lang") +def docs_live_lang(session): + """ + A convenience session for beginner contributors to use the docs-live session with + a specific language. + + It expects the language code to be passed as the first positional argument, so it needs + to be called with from the command line with the following syntax: + + nox -s docs-live-lang -- LANG + + where LANG is one of the available languages defined in LANGUAGES. + For example, for Spanish: nox -s docs-live-lang -- es + """ + if not session.posargs: + session.error( + "Please provide a language using:\n\n " + "nox -s docs-live-lang -- LANG\n\n " + f" where LANG is one of: {LANGUAGES}" + ) + lang = session.posargs[0] + if lang in LANGUAGES: + session.posargs.pop(0) + session.notify("docs-live", ('-D', f"language={lang}", *session.posargs)) + else: + session.error( + f"[{lang}] locale is not available. Try using:\n\n " + "nox -s docs-live-lang -- LANG\n\n " + f"where LANG is one of: {LANGUAGES}" + ) + + @nox.session(name="docs-clean") def clean_dir(session): """Clean out the docs directory used in the live build.""" @@ -65,3 +139,76 @@ def clean_dir(session): shutil.rmtree(content) else: os.remove(content) + + +@nox.session(name="update-translations") +def update_translations(session): + """ + Update the translation files (./locales/*/.po) for all languages translations. + + Note: this step is important because it makes sure that the translation files are + up to date with the latest changes in the guide. + """ + session.install("-e", ".") + session.install("sphinx-intl") + session.log("Updating templates (.pot)") + session.run(SPHINX_BUILD, *TRANSLATION_TEMPLATE_PARAMETERS, SOURCE_DIR, TRANSLATION_TEMPLATE_DIR, *session.posargs) + for lang in LANGUAGES: + session.log(f"Updating .po files for [{lang}] translation") + session.run("sphinx-intl", "update", "-p", TRANSLATION_TEMPLATE_DIR, "-l", lang) + + +@nox.session(name="build-languages") +def build_languages(session): + """ + Build the translations of the guide for the specified language. + + Note: This sessions expects a list of languages to build in the first position of the session arguments. + It does not need to be called directly, it is started by build_translations session. + """ + if not session.posargs: + session.error("Please provide the list of languages to build the translation for") + languages_to_build = session.posargs.pop(0) + + session.install("-e", ".") + for lang in languages_to_build: + if lang not in LANGUAGES: + session.warn(f"Language [{lang}] is not available for translation") + continue + session.log(f"Building [{lang}] guide") + session.run(SPHINX_BUILD, *BUILD_PARAMETERS, "-D", f"language={lang}", ".", OUTPUT_DIR / lang, *session.posargs) + + +@nox.session(name="build-translations") +def build_translations(session): + """ + Build translations of the guide. + + Note: this session can be called directly to build all available translations (defined in LANGUAGES). + It is also called by the docs and docs-test sessions with 'release-build' as the first positional + argument, to build only the translations defined in RELEASE_LANGUAGES. + """ + release_build = False + if session.posargs and session.posargs[0] == 'release-build': + session.posargs.pop(0) + release_build = True + # if running from the docs or docs-test sessions, build only release languages + BUILD_LANGUAGES = RELEASE_LANGUAGES if release_build else LANGUAGES + session.log(f"Existing translations: {LANGUAGES}") + session.log(f"Release Languages: {RELEASE_LANGUAGES}") + session.log(f"Building languages{' for release' if release_build else ''}: {BUILD_LANGUAGES}") + if not BUILD_LANGUAGES: + session.warn("No translations to build") + else: + session.notify("build-languages", [BUILD_LANGUAGES, *session.posargs]) + + +@nox.session(name="build-translations-test") +def build_translations_test(session): + """ + Build all translations of the guide with testing parameters. + + This is a convenience session to test the build of all translations with the testing parameters + in the same way docs-test does for the English version. + """ + session.notify("build-translations", [*TEST_PARAMETERS]) From 5ebb26a5943de07ac365e8dac65fc3b49531ee20 Mon Sep 17 00:00:00 2001 From: Felipe Moreno Date: Sun, 16 Jun 2024 12:12:00 -0400 Subject: [PATCH 3/6] Adding dev requirements for translation --- pyproject.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0ed39dcf..86610023 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,8 +26,12 @@ dependencies = [ [project.optional-dependencies] dev = [ - # for checking style rules - "vale" + # for general build workflows + "nox", + # for prose linting + "vale", + # for managing translation files + "sphinx-intl", ] [tool.hatch.build.targets.wheel] From 393cbd7dd8ecf8217ad548a00ba49549dc7896c5 Mon Sep 17 00:00:00 2001 From: Felipe Moreno Date: Sun, 16 Jun 2024 12:14:30 -0400 Subject: [PATCH 4/6] Exclude .mo translations file from version control --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 76f84092..f0a64e0b 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ __pycache__ *.idea* # Grammar / syntax checkers styles/ +# Exclude translation .mo files +locales/*/LC_MESSAGES/*.mo From 765578365d833e094031d8c1a88c3d0659c776a4 Mon Sep 17 00:00:00 2001 From: Felipe Moreno Date: Sun, 16 Jun 2024 12:57:20 -0400 Subject: [PATCH 5/6] Check locale folder exists before building --- noxfile.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/noxfile.py b/noxfile.py index dfb14f6b..4a0ea835 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,6 +14,7 @@ # Location of the translation templates TRANSLATION_TEMPLATE_DIR = pathlib.Path(BUILD_DIR, "gettext") +TRANSLATION_LOCALES_DIR = pathlib.Path("locales") # Sphinx build commands SPHINX_BUILD = "sphinx-build" @@ -44,8 +45,8 @@ # List of languages for which locales will be generated in (/locales/) LANGUAGES = ["es"] -# List of languages that should be built when releasing the guide -RELEASE_LANGUAGES = ['es'] +# List of languages that should be built when releasing the guide (docs or docs-test sessions) +RELEASE_LANGUAGES = [] @nox.session @@ -194,8 +195,10 @@ def build_translations(session): release_build = True # if running from the docs or docs-test sessions, build only release languages BUILD_LANGUAGES = RELEASE_LANGUAGES if release_build else LANGUAGES - session.log(f"Existing translations: {LANGUAGES}") - session.log(f"Release Languages: {RELEASE_LANGUAGES}") + # only build languages that have a locale folder + BUILD_LANGUAGES = [lang for lang in BUILD_LANGUAGES if (TRANSLATION_LOCALES_DIR / lang).exists()] + session.log(f"Declared languages: {LANGUAGES}") + session.log(f"Release languages: {RELEASE_LANGUAGES}") session.log(f"Building languages{' for release' if release_build else ''}: {BUILD_LANGUAGES}") if not BUILD_LANGUAGES: session.warn("No translations to build") From 8c26f89490d2ab28b5e0662f9c605bc5dc7708cc Mon Sep 17 00:00:00 2001 From: Felipe Moreno Date: Sun, 16 Jun 2024 13:16:07 -0400 Subject: [PATCH 6/6] Exclude .po files from codespell checks --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 037a87a2..09e7c394 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -33,7 +33,7 @@ repos: - tomli exclude: > (?x)^( - .*vale-styles.* + (.*vale-styles.*)|(.*\.po) )$ - repo: https://github.com/errata-ai/vale