483 lines
19 KiB
Markdown
483 lines
19 KiB
Markdown
|
|
# Translating Engine, CLI and Backend
|
||
|
|
|
||
|
|
|
||
|
|
## Table of contents
|
||
|
|
* [Overview]
|
||
|
|
* [Software preparation]
|
||
|
|
* [GitHub preparation]
|
||
|
|
* [Tools]
|
||
|
|
* [Clone preparation]
|
||
|
|
* [Language Codes]
|
||
|
|
* [Translation steps]
|
||
|
|
* [Updates to msgids]
|
||
|
|
* [Adding a new language]
|
||
|
|
* [Technical details]
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
This document has instructions for translation in [PO files] and the
|
||
|
|
[Gettext system]. It is used in Zonemaster-Engine, Zonemaster-CLI and
|
||
|
|
Zonemaster-Backend. Zonemaster-GUI uses a different solution. See the
|
||
|
|
[Zonemaster GUI translation guide] for instructions for that part.
|
||
|
|
|
||
|
|
[PO files] are found in the following directories:
|
||
|
|
* [share][zonemaster-engine share] in Zonemaster-Engine
|
||
|
|
* [share][zonemaster-cli share] in Zonemaster-CLI
|
||
|
|
* [share][zonemaster-backend share] in Zonemaster-Backend
|
||
|
|
|
||
|
|
There is one PO file per language in each component. A PO file consists of
|
||
|
|
multiple entries. An entry consists of three parts. First an optional header
|
||
|
|
(lines starting with "#") which can have the "fuzzy" tag (more below), second
|
||
|
|
the *msgid* which is the untranslated text (in English in the case of Zonemaster)
|
||
|
|
that comes from the program code (Perl code in the case of Zonemaster), and the
|
||
|
|
third part is the *msgstr* which is the translated text. The task of the
|
||
|
|
translator is to create and update *msgstr*.
|
||
|
|
|
||
|
|
In many *msgid* there is one or several arguments within `{...}`, e.g.
|
||
|
|
`{ns_ip_list}`. The same arguments must be found in *msgid* and *msgstr*. The
|
||
|
|
value of the argument will be inserted at run time. The format of that value
|
||
|
|
depends on the argument name, and a specification for arguments used, mainly in
|
||
|
|
Zonemaster-Engine, can be found in [Arguments for test case messages].
|
||
|
|
|
||
|
|
## Software preparation
|
||
|
|
|
||
|
|
For the steps below you need to work on a computer with Git, Perl and Gettext.
|
||
|
|
Select what OS you want to work on from the list below. Other OSs will also work,
|
||
|
|
but you will have to find instructions elsewhere.
|
||
|
|
|
||
|
|
* Rocky Linux
|
||
|
|
|
||
|
|
Install the following:
|
||
|
|
```
|
||
|
|
dnf install git make perl-App-cpanminus perl-Try-Tiny
|
||
|
|
cpanm Locale::PO
|
||
|
|
```
|
||
|
|
|
||
|
|
* Debian
|
||
|
|
|
||
|
|
Install the following:
|
||
|
|
```
|
||
|
|
apt install gettext git liblocale-po-perl
|
||
|
|
```
|
||
|
|
|
||
|
|
* FreeBSD
|
||
|
|
|
||
|
|
Install the following:
|
||
|
|
```
|
||
|
|
pkg install gettext-tools git-lite gmake p5-Locale-PO p5-Try-Tiny
|
||
|
|
```
|
||
|
|
|
||
|
|
* Ubuntu
|
||
|
|
|
||
|
|
Install the following:
|
||
|
|
```
|
||
|
|
apt install gettext git make liblocale-po-perl
|
||
|
|
```
|
||
|
|
|
||
|
|
## GitHub preparation
|
||
|
|
|
||
|
|
For full integration with Zonemaster translation you need a GitHub account
|
||
|
|
and forks of the Zonemaster repositories. If you do not have one you can easily
|
||
|
|
[create an account at GitHub][GitHub signup]. If you are not willing to create
|
||
|
|
one, contact the Zonemaster work group for instructions by sending an email to
|
||
|
|
"zonemaster@zonemaster.net".
|
||
|
|
|
||
|
|
To create the forks of the Zonemaster repositories
|
||
|
|
1. Go to [GitHub] and log in with your account.
|
||
|
|
2. Go to the [Zonemaster-Engine repository].
|
||
|
|
3. Press "Fork" in the top right corner (see "[Forking a repository]").
|
||
|
|
4. Repeat steps 2 and 3 for the the following repositories:
|
||
|
|
* [Zonemaster-CLI repository]
|
||
|
|
* [Zonemaster-Backend repository]
|
||
|
|
|
||
|
|
Make sure that your public *ssh* key is uploaded to GitHub
|
||
|
|
(see "[Adding a new SSH key to your GitHub account]") and that its private key
|
||
|
|
is available on the computer you are going to work from.
|
||
|
|
|
||
|
|
|
||
|
|
## Tools
|
||
|
|
|
||
|
|
The [PO file][PO files] can be edited with a plain text editor, but then it is
|
||
|
|
important to keep the database structure of the file. There are tools that
|
||
|
|
makes editing of the PO files easier. When using those, the PO file is
|
||
|
|
handled as a database instead of as a plain file.
|
||
|
|
|
||
|
|
* There is [Emacs PO-mode], available as a plug-in to the [GNU Emacs] file
|
||
|
|
editor, which makes updating and searching in the ".po" file easier and more
|
||
|
|
robust.
|
||
|
|
* There is also "[GNOME Translation Editor]", a graphical PO editor
|
||
|
|
available for at least Windows and Linux.
|
||
|
|
* There is [POEDIT] in free version that Zonemaster translator has reported to
|
||
|
|
work well.
|
||
|
|
* There are more tools available, either cloud services or programs
|
||
|
|
for download, and they could be found by searching for "po editor".
|
||
|
|
|
||
|
|
|
||
|
|
## Clone preparation
|
||
|
|
|
||
|
|
You need a local clone of the repository to work in (see
|
||
|
|
"[Cloning a repository]"). You need that for all repositories with messages to
|
||
|
|
translate -- Zonemaster-Engine, Zonemaster-CLI and Zonemaster-Backend. (For
|
||
|
|
Zonemaster-GUI see [Zonemaster GUI translation guide].)
|
||
|
|
|
||
|
|
Here it is assumed that the three repositories are cloned from the same
|
||
|
|
directory, i.e. all three clones are sub-directories to the same directory.
|
||
|
|
|
||
|
|
* If you use "old" clones, instead of creating them afresh, then you must do the
|
||
|
|
following (if there is no `develop` branch, checkout `origin/develop` and skip
|
||
|
|
`pull`).
|
||
|
|
|
||
|
|
```
|
||
|
|
git fetch --all
|
||
|
|
git checkout develop
|
||
|
|
git pull
|
||
|
|
```
|
||
|
|
|
||
|
|
* Clone the three repositories:
|
||
|
|
```sh
|
||
|
|
git clone https://github.com/zonemaster/zonemaster-engine
|
||
|
|
git clone https://github.com/zonemaster/zonemaster-cli
|
||
|
|
git clone https://github.com/zonemaster/zonemaster-backend
|
||
|
|
```
|
||
|
|
|
||
|
|
* Check out `origin/develop` branch in the three repositories:
|
||
|
|
```sh
|
||
|
|
git -C zonemaster-engine checkout origin/develop
|
||
|
|
git -C zonemaster-cli checkout origin/develop
|
||
|
|
git -C zonemaster-backend checkout origin/develop
|
||
|
|
```
|
||
|
|
|
||
|
|
You must always start from `develop` branch (or `origin/develop` branch) and any
|
||
|
|
`develop` branch must be even with `origin/develop`.
|
||
|
|
|
||
|
|
Now it is time to connect your own forks created in [GitHub preparation] above
|
||
|
|
to the created clones. We take *Zonemaster-Engine* as an example, but should be
|
||
|
|
repeated for all clones.
|
||
|
|
|
||
|
|
* You have a user name at GitHub. Here we use "xxxx" as your user name and also
|
||
|
|
the name of the remote in clone on the local machine.
|
||
|
|
* Enter the clone:
|
||
|
|
```
|
||
|
|
cd zonemaster-engine
|
||
|
|
```
|
||
|
|
|
||
|
|
* Create the connection to your fork by making it "remote" and synchronize to
|
||
|
|
it:
|
||
|
|
```
|
||
|
|
git remote add xxxx git@github.com:xxxx/zonemaster-engine.git
|
||
|
|
git fetch --all
|
||
|
|
```
|
||
|
|
|
||
|
|
Now you should have updated local clones of all three repositories.
|
||
|
|
|
||
|
|
|
||
|
|
## Language Codes
|
||
|
|
|
||
|
|
Zonemaster uses [ISO 639-1] two-letter language codes, in lower case.
|
||
|
|
Zonemaster-GUI is currently available in the following languages:
|
||
|
|
|
||
|
|
* `da` for Danish language
|
||
|
|
* `en` for English language
|
||
|
|
* `es` for Spanish language
|
||
|
|
* `fi` for Finnish language
|
||
|
|
* `fr` for French language
|
||
|
|
* `nb` for Norwegian language
|
||
|
|
* `sl` for Slovenian language
|
||
|
|
* `sv` for Swedish language
|
||
|
|
|
||
|
|
If a language is added the correct two-letter code must be used.
|
||
|
|
|
||
|
|
In the steps below `xx` represent the language code that you should work with.
|
||
|
|
Replace that with the correct code.
|
||
|
|
|
||
|
|
|
||
|
|
## Translation steps
|
||
|
|
|
||
|
|
The steps in this section will cover most translation work. The steps are the
|
||
|
|
same for all three repositories.
|
||
|
|
|
||
|
|
* Make sure that the working tree is clean. Remove all other files and updates.
|
||
|
|
If you have edited your PO file, then make a copy of it outside the repository.
|
||
|
|
```
|
||
|
|
git clean -dfx
|
||
|
|
git reset --hard
|
||
|
|
```
|
||
|
|
|
||
|
|
* The following command should report that the working tree is clean.
|
||
|
|
```
|
||
|
|
git status --ignored
|
||
|
|
```
|
||
|
|
|
||
|
|
* Check-out the *develop* branch and create a new branch to work in. You can call
|
||
|
|
the new branch whatever you want, but here we use the name
|
||
|
|
"translation-update". If that name is already taken, you have to give it a new
|
||
|
|
name or remove the old branch.
|
||
|
|
```
|
||
|
|
git checkout origin/develop
|
||
|
|
git checkout -b translation-update
|
||
|
|
```
|
||
|
|
|
||
|
|
* Go to the *share* directory. Stay in the *share* directory for the remaining
|
||
|
|
translation steps.
|
||
|
|
```
|
||
|
|
cd share
|
||
|
|
```
|
||
|
|
|
||
|
|
* If you have a partly edited PO file that you want to continue on, then it is
|
||
|
|
time to copy it back into the `share` directory before the next step. Or use
|
||
|
|
the PO file already in the `share` directory.
|
||
|
|
|
||
|
|
* Run the update command for the PO file for the language you are going to work
|
||
|
|
with. Replace "xx" with the language code in question. This will synchronize
|
||
|
|
the PO file with the *msgids* in the Perl code.
|
||
|
|
```
|
||
|
|
./update-po xx.po
|
||
|
|
```
|
||
|
|
|
||
|
|
* The PO file is updated with new *msgids*, if any, and now you can start
|
||
|
|
working with it. Unless this is the first translation you only have to work
|
||
|
|
with updated or untranslated items.
|
||
|
|
|
||
|
|
* Update the PO file with the tool of your choice (see section "[Tools]" above).
|
||
|
|
You can copy the PO file to another computer, edit it there, and then copy it
|
||
|
|
back to your Zonemaster-Engine clone -- or Zonemaster-CLI clone or
|
||
|
|
Zonemaster-Backend clone depending on what repository you do the translation
|
||
|
|
for.
|
||
|
|
|
||
|
|
* When doing the update, do not change the *msgid*, only the *msgstr*. The
|
||
|
|
*msgid* cannot be updated in this process. They are the links between the Perl
|
||
|
|
module and the PO file.
|
||
|
|
|
||
|
|
* If you find a *msgid* that needs an update please see section
|
||
|
|
[Updates to msgids] for how to report it.
|
||
|
|
|
||
|
|
* If there is a `{...}` in the *msgid* then [Arguments for test case messages]
|
||
|
|
will help with the type of data if not obvious.
|
||
|
|
|
||
|
|
* Try to translate as close to the original as possible, but still make sure
|
||
|
|
that the language is sound and valid.
|
||
|
|
|
||
|
|
* Inspect every *fuzzy entry* (tagged with "fuzzy"). Update *msgstr*
|
||
|
|
if needed and remove the "fuzzy" tag. The "fuzzy" tag must always be removed.
|
||
|
|
|
||
|
|
* Search for *untranslated entries* (empty *msgstr*) and add a
|
||
|
|
translation.
|
||
|
|
|
||
|
|
* At the end of the file there could be *obsolete entries* (lines starting with
|
||
|
|
"#~") and those could have matching translations, especially of the *msgid*
|
||
|
|
has been changed.
|
||
|
|
|
||
|
|
* Any remaining *obsolete entries* (lines at the end of the file starting
|
||
|
|
with "#~") could be removed. They serve no purpose anymore.
|
||
|
|
|
||
|
|
* With the following command, check that the messages arguments (`{...}`) in all
|
||
|
|
*msgstr* strings match up with those in the *msgid* strings.
|
||
|
|
```
|
||
|
|
../../zonemaster-engine/util/check-msg-args xx.po
|
||
|
|
```
|
||
|
|
|
||
|
|
* When the update of all *msgstr* is complete run the `tidy-po` command to
|
||
|
|
create a consistent formatting of the PO file. Do this again if you do
|
||
|
|
further updates.
|
||
|
|
|
||
|
|
```
|
||
|
|
make POFILES=xx.po tidy-po
|
||
|
|
```
|
||
|
|
|
||
|
|
* You can check all updates that have been done to the xx.po file. That includes
|
||
|
|
both updates done by the update command and your updates.
|
||
|
|
```
|
||
|
|
git diff xx.po
|
||
|
|
```
|
||
|
|
|
||
|
|
* When the update is completed, it is time to commit the changes. You should
|
||
|
|
only commit the "xx.po" file.
|
||
|
|
```
|
||
|
|
git commit -m 'Write a description of the change' xx.po
|
||
|
|
```
|
||
|
|
|
||
|
|
* There could be other files changed or added that should not be included.
|
||
|
|
Run the status command to see them.
|
||
|
|
```
|
||
|
|
git status
|
||
|
|
```
|
||
|
|
|
||
|
|
* Other changed files could be reset by a `git checkout`. This could also
|
||
|
|
be done before creating the commit.
|
||
|
|
```
|
||
|
|
git checkout FILENAME
|
||
|
|
```
|
||
|
|
|
||
|
|
* Files that were created but are not needed can just be removed. This could also
|
||
|
|
be done before the commit.
|
||
|
|
```
|
||
|
|
rm FILENAME
|
||
|
|
```
|
||
|
|
|
||
|
|
* Now push the local branch you created to your fork at GitHub.
|
||
|
|
"translation-update" is name of the branch you created above and
|
||
|
|
have committed the updates to. Use your GitHub user name instead of
|
||
|
|
"xxxx".
|
||
|
|
```
|
||
|
|
git push -u xxxx translation-update
|
||
|
|
```
|
||
|
|
|
||
|
|
* Go to your fork collection at GitHub, https://github.com/xxxx/ using your
|
||
|
|
GitHub user name instead of "xxxx". There you can select the fork for this
|
||
|
|
translation.
|
||
|
|
|
||
|
|
* Select to create a new pull request. Here we use Zonemaster-Engine as an
|
||
|
|
example.
|
||
|
|
* The base repository should be *zonemaster/zonemaster-engine*.
|
||
|
|
* The base branch should be *develop* (not *master*).
|
||
|
|
* The "head" should be your fork.
|
||
|
|
* The "compare" should be the same branch as you created above and pushed to
|
||
|
|
your fork, e.g. "translation-update".
|
||
|
|
|
||
|
|
* Inspect what GitHub says that will change by the pull request. It should
|
||
|
|
only be the PO file that you have updated and nothing else. If additional
|
||
|
|
files are listed, please correct or request for help.
|
||
|
|
|
||
|
|
* If you by mistake have not started with an updated version of the develop
|
||
|
|
branch you can get extra files listed.
|
||
|
|
|
||
|
|
* If you want to correct something now before the pull request has been created,
|
||
|
|
do that in your local clone and do a new commit and push that to your fork.
|
||
|
|
|
||
|
|
* Press "create pull request", write a nice description and press "create"
|
||
|
|
again.
|
||
|
|
|
||
|
|
* If you go back to your own computer and just keep the clone as it is, you
|
||
|
|
can easily update the pull request if needed with more changes to the same
|
||
|
|
PO file. When the pull request has been merged by the Zonemaster work group,
|
||
|
|
you can delete the local clone and on your GitHub fork you can remove the
|
||
|
|
branch. Or keep them for next time.
|
||
|
|
|
||
|
|
|
||
|
|
## Updates to msgids
|
||
|
|
|
||
|
|
The *msgid* cannot be updated in the translation process. If you find an *msgid*
|
||
|
|
that needs an update you can provide that information to the project. The
|
||
|
|
preferred way is to create an issue in the relevant repository.
|
||
|
|
|
||
|
|
* Message *(msgid)* in Zonemaster-Engine: [issue][new issue zonemaster-engine]
|
||
|
|
* Message *(msgid)* in Zonemaster-CLI: [issue][new issue zonemaster-cli]
|
||
|
|
* Message *(msgid)* in Zonemaster-Backend: [issue][new issue zonemaster-backend]
|
||
|
|
|
||
|
|
If the message is in Zonemaster-Engine then include the message tag found in the
|
||
|
|
header, e.g. "BASIC:NO_PARENT", in the issue description. Also include the *msgid*
|
||
|
|
as it is now and a suggestion for new wording.
|
||
|
|
|
||
|
|
|
||
|
|
## Adding a new language
|
||
|
|
|
||
|
|
If you want to add a new language, then follow steps in section
|
||
|
|
"[Translation steps]" above with some modifications. Before you add a language
|
||
|
|
contact the Zonemaster project to discuss timeplan and other aspects of the new
|
||
|
|
language. Every language should be updated at every new release of Zonemaster if
|
||
|
|
there are updated or added messages to be translated.
|
||
|
|
|
||
|
|
* First, as in the translation steps, create the branch to work in.
|
||
|
|
```
|
||
|
|
git checkout origin/develop
|
||
|
|
git checkout -b translation-update
|
||
|
|
```
|
||
|
|
|
||
|
|
There is no PO file for new language, and it has to be created. The easiest way
|
||
|
|
is to make a copy of an existing file.
|
||
|
|
|
||
|
|
* Determine what language code to use for the new language (also see section
|
||
|
|
"[Language Codes]").
|
||
|
|
|
||
|
|
* It must be a code that is available in the *locale* system in the OSs that
|
||
|
|
Zonemaster supports. Try the following commands to see if it is available.
|
||
|
|
Replace "xx" with that code that you think it should be. Consult with
|
||
|
|
Zonemaster Project if in doubt.
|
||
|
|
```
|
||
|
|
locale -a | grep xx_ # Works in FreeBSD and Rocky Linux
|
||
|
|
grep xx_ /etc/locale.gen # Works in Debian and Ubuntu
|
||
|
|
```
|
||
|
|
|
||
|
|
* Go to the *share* directory and create a new blank PO file. Then "add" it
|
||
|
|
to `git` before working on it.
|
||
|
|
```
|
||
|
|
cd share
|
||
|
|
make POLANG=xx new-po
|
||
|
|
git add xx.po
|
||
|
|
```
|
||
|
|
|
||
|
|
* Verify and update the file header if needed.
|
||
|
|
|
||
|
|
* Now you go back to section "[Translation steps]" and continue in the same way
|
||
|
|
as with an existing language.
|
||
|
|
|
||
|
|
|
||
|
|
## Technical details
|
||
|
|
|
||
|
|
The first step in updating the translations is to generate a new template file
|
||
|
|
("Zonemaster-Engine.pot"). In practice you rarely need to think about generating
|
||
|
|
it as it is generally performed as an implicit intermediate step.
|
||
|
|
If you do want to generate it, the command is `make extract-pot`.
|
||
|
|
|
||
|
|
The translated strings are maintained in files named "<LANG-CODE>.po". You will
|
||
|
|
find the current PO files in the "share" directories listed in the "[Overview]"
|
||
|
|
section (also see section "[Language Codes]").
|
||
|
|
|
||
|
|
The command `./update-po` will update the PO file with new message ids (*msgid*)
|
||
|
|
from the source code. Execute `./update-po xx.po` to update the PO file for
|
||
|
|
language "xx". This should only be strictly necessary to do when a module has
|
||
|
|
been added, changed or removed, but it it recommended to do this step every time.
|
||
|
|
|
||
|
|
Execute `make update-po` to update all the PO files with new message ids from the
|
||
|
|
source code.
|
||
|
|
|
||
|
|
By default the updated PO file will suggested translations for new message
|
||
|
|
ids based on fuzzy matching of similar strings. This is not always desirable
|
||
|
|
and you can disable fuzzy matching by executing one of the following
|
||
|
|
commands instead:
|
||
|
|
```
|
||
|
|
make update-po MSGMERGE_OPTS=--no-fuzzy-matching POFILES=xx.po
|
||
|
|
make update-po MSGMERGE_OPTS=--no-fuzzy-matching
|
||
|
|
```
|
||
|
|
|
||
|
|
|
||
|
|
<!-- Zonemaster links point on purpose on the develop branch. -->
|
||
|
|
[Adding a new SSH key to your GitHub account]: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account
|
||
|
|
[Adding a new language]: #adding-a-new-language
|
||
|
|
[Arguments for test case messages]: ../../public/specifications/tests/ArgumentsForTestCaseMessages.md
|
||
|
|
[Clone preparation]: #clone-preparation
|
||
|
|
[Cloning a repository]: https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository#cloning-a-repository
|
||
|
|
[Emacs PO-mode]: https://www.gnu.org/software/gettext/manual/html_node/PO-Mode.html#PO-Mode
|
||
|
|
[Forking a repository]: https://docs.github.com/en/get-started/quickstart/fork-a-repo#forking-a-repository
|
||
|
|
[GNOME Translation Editor]: https://wiki.gnome.org/Apps/Gtranslator
|
||
|
|
[GNU Emacs]: https://www.gnu.org/software/emacs/
|
||
|
|
[Gettext system]: https://www.gnu.org/software/gettext/
|
||
|
|
[GitHub preparation]: #github-preparation
|
||
|
|
[GitHub signup]: https://github.com/signup
|
||
|
|
[GitHub]: https://github.com/
|
||
|
|
[ISO 639-1]: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
|
||
|
|
[Language Codes]: #language-codes
|
||
|
|
[New issue zonemaster-backend]: https://github.com/zonemaster/zonemaster-backend/issues/new
|
||
|
|
[New issue zonemaster-cli]: https://github.com/zonemaster/zonemaster-cli/issues/new
|
||
|
|
[New issue zonemaster-engine]: https://github.com/zonemaster/zonemaster-engine/issues/new
|
||
|
|
[Overview]: #overview
|
||
|
|
[PO files]: https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
|
||
|
|
[POEDIT]: https://poedit.net/
|
||
|
|
[Software preparation]: #software-preparation
|
||
|
|
[Technical details]: #technical-details
|
||
|
|
[Tools]: #tools
|
||
|
|
[Translation steps]: #translation-steps
|
||
|
|
[Translation]: https://github.com/zonemaster/zonemaster-engine/blob/develop/docs/Translation.pod
|
||
|
|
[Updates to msgids]: #updates-to-msgids
|
||
|
|
[Zonemaster GUI translation guide]: https://github.com/zonemaster/zonemaster-gui/blob/develop/docs/TranslationGuide.md
|
||
|
|
[Zonemaster-Backend repository]: https://github.com/zonemaster/zonemaster-backend
|
||
|
|
[Zonemaster-CLI repository]: https://github.com/zonemaster/zonemaster-cli
|
||
|
|
[Zonemaster-Engine repository]: https://github.com/zonemaster/zonemaster-engine
|
||
|
|
[Zonemaster-backend share]: https://github.com/zonemaster/zonemaster-backend/tree/develop/share
|
||
|
|
[Zonemaster-cli share]: https://github.com/zonemaster/zonemaster-cli/tree/develop/share
|
||
|
|
[Zonemaster-engine share]: https://github.com/zonemaster/zonemaster-engine/tree/develop/share
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|