Skip to content

Commit e60f5a8

Browse files
committed
Enhance translation docs, dark mode styles, and dependencies
- Improved file structure in translation documentation for clarity. - Expanded dark mode CSS with specific rules for headings, links, and syntax highlighting. - Updated `conf.py` to configure `linkify` and added `pygments_style` for syntax highlighting. - Added `sphinx-autobuild` and reorganized requirements in `requirements.txt`.
1 parent 14d4a78 commit e60f5a8

File tree

4 files changed

+114
-5
lines changed

4 files changed

+114
-5
lines changed

_static/dark_mode.css

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,58 @@ body.dark-mode h3,
3030
body.dark-mode h4,
3131
body.dark-mode h5,
3232
body.dark-mode h6 {
33-
color: #ffffff; /* White headings */
33+
color: #ffffff !important; /* White headings */
34+
}
35+
36+
/* More specific rules for content headings */
37+
body.dark-mode .rst-content h1,
38+
body.dark-mode .rst-content h2,
39+
body.dark-mode .rst-content h3,
40+
body.dark-mode .rst-content h4,
41+
body.dark-mode .rst-content h5,
42+
body.dark-mode .rst-content h6 {
43+
color: #ffffff !important; /* White headings in content */
44+
}
45+
46+
/* Fix heading links that inherit link colors */
47+
body.dark-mode .rst-content h1 a,
48+
body.dark-mode .rst-content h2 a,
49+
body.dark-mode .rst-content h3 a,
50+
body.dark-mode .rst-content h4 a,
51+
body.dark-mode .rst-content h5 a,
52+
body.dark-mode .rst-content h6 a {
53+
color: #ffffff !important; /* White heading links */
54+
}
55+
56+
/* Target the specific toc-backref links in headings */
57+
body.dark-mode .rst-content a.toc-backref {
58+
color: #ffffff !important; /* White toc backref links */
59+
}
60+
61+
/* Target headerlink anchors in headings */
62+
body.dark-mode .rst-content a.headerlink {
63+
color: #ffffff !important; /* White header anchor links */
64+
}
65+
66+
/* Even more specific for document section headings */
67+
body.dark-mode .document h1,
68+
body.dark-mode .document h2,
69+
body.dark-mode .document h3,
70+
body.dark-mode .document h4,
71+
body.dark-mode .document h5,
72+
body.dark-mode .document h6 {
73+
color: #ffffff !important; /* White headings in document */
3474
}
3575

3676
body.dark-mode a {
3777
color: #4da8da; /* Light blue links */
3878
}
3979

80+
/* Only apply visited link color to content area, not navigation */
81+
body.dark-mode .rst-content a:visited {
82+
color: #bb86fc; /* Light purple for visited links */
83+
}
84+
4085
body.dark-mode a:hover {
4186
color: #66b3ff; /* Lighter blue on hover */
4287
}
@@ -47,6 +92,65 @@ body.dark-mode pre {
4792
border: 1px solid #3c3c3c;
4893
}
4994

95+
/* Code blocks in dark mode */
96+
/*.dark-mode .highlight {*/
97+
/* background: #2b2b2b !important;*/
98+
/* border: 1px solid #444 !important;*/
99+
/*}*/
100+
101+
/* Inline code in dark mode */
102+
.dark-mode .rst-content code.literal,
103+
.dark-mode .rst-content tt.literal {
104+
background: #404040 !important;
105+
color: #f8f8f2 !important;
106+
border: 1px solid #555 !important;
107+
padding: 2px 4px !important;
108+
}
109+
110+
/* Syntax highlighting colors for dark mode */
111+
.dark-mode .highlight .c { color: #75715e !important; } /* comments */
112+
.dark-mode .highlight .k { color: #66d9ef !important; } /* keywords */
113+
.dark-mode .highlight .s { color: #e6db74 !important; } /* strings */
114+
.dark-mode .highlight .mi { color: #ae81ff !important; } /* numbers */
115+
.dark-mode .highlight .n { color: #f8f8f2 !important; } /* names */
116+
.dark-mode .highlight .nb { color: #f92672 !important; } /* builtins */
117+
.dark-mode .highlight .nf { color: #a6e22e !important; } /* functions */
118+
.dark-mode .highlight .o { color: #f92672 !important; } /* operators */
119+
.dark-mode .highlight .p { color: #f8f8f2 !important; } /* punctuation */
120+
.dark-mode .highlight .nn { color: #66d9ef !important; } /* imports/namespaces */
121+
.dark-mode .highlight .kn { color: #f92672 !important; } /* import keywords */
122+
.dark-mode .highlight .na { color: #a6e22e !important; } /* attribute names */
123+
.dark-mode .highlight .nc { color: #a6e22e !important; } /* class names */
124+
.dark-mode .highlight .nd { color: #a6e22e !important; } /* decorators */
125+
.dark-mode .highlight .ne { color: #a6e22e !important; } /* exceptions */
126+
.dark-mode .highlight .ni { color: #f92672 !important; } /* name indicators */
127+
.dark-mode .highlight .nl { color: #f92672 !important; } /* name labels */
128+
.dark-mode .highlight .nt { color: #f92672 !important; } /* name tags */
129+
.dark-mode .highlight .nv { color: #f8f8f2 !important; } /* name variables */
130+
.dark-mode .highlight .ow { color: #f92672 !important; } /* operator words */
131+
.dark-mode .highlight .w { color: #f8f8f2 !important; } /* whitespace */
132+
.dark-mode .highlight .mf { color: #ae81ff !important; } /* numbers float */
133+
.dark-mode .highlight .mh { color: #ae81ff !important; } /* numbers hex */
134+
.dark-mode .highlight .mo { color: #ae81ff !important; } /* numbers octal */
135+
.dark-mode .highlight .sb { color: #e6db74 !important; } /* string backtick */
136+
.dark-mode .highlight .sc { color: #e6db74 !important; } /* string char */
137+
.dark-mode .highlight .sd { color: #e6db74 !important; } /* string doc */
138+
.dark-mode .highlight .s2 { color: #e6db74 !important; } /* string double */
139+
.dark-mode .highlight .se { color: #ae81ff !important; } /* string escape */
140+
.dark-mode .highlight .sh { color: #e6db74 !important; } /* string heredoc */
141+
.dark-mode .highlight .si { color: #e6db74 !important; } /* string interpol */
142+
.dark-mode .highlight .sx { color: #e6db74 !important; } /* string other */
143+
.dark-mode .highlight .sr { color: #e6db74 !important; } /* string regex */
144+
.dark-mode .highlight .s1 { color: #e6db74 !important; } /* string single */
145+
.dark-mode .highlight .ss { color: #e6db74 !important; } /* string symbol */
146+
147+
148+
/* Code block container */
149+
/*.dark-mode .rst-content .highlight {*/
150+
/* margin: 1em 0 !important;*/
151+
/*}*/
152+
153+
50154
/* Optional: Style the toggle button */
51155
button {
52156
padding: 8px 16px;

conf.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@
3636
myst_enable_extensions = [
3737
'colon_fence',
3838
'attrs_inline',
39-
'linkify',
40-
'colon_fence'
39+
'linkify'
4140
]
4241

42+
# Configure linkify to only auto-link www.* and https://* patterns
43+
myst_linkify_fuzzy_links = False
44+
myst_url_schemes = ["https", "http"]
45+
4346
master_doc = 'index'
4447

4548
source_suffix = [".md"]
@@ -51,6 +54,7 @@
5154
# directories to ignore when looking for source files.
5255
# This pattern also affects html_static_path and html_extra_path.
5356
exclude_patterns = ['README.md']
57+
pygments_style = 'default'
5458

5559

5660
# -- Options for HTML output -------------------------------------------------
-19 Bytes

# Python Tool Translation Guide This guide covers translating GhostBSD Python applications using the standard workflow implemented in update-station. ## Prerequisites - Python development environment - Git access to the repository - Text editor for .po files - gettext tools: `sudo pkg install gettext-tools` ## Setup.py Implementation GhostBSD Python tools use these custom setuptools commands (based on update-station): ```python import os import glob from setuptools import setup, Command from DistUtilsExtra.command.build_extra import build_extra from DistUtilsExtra.command.build_i18n import build_i18n from DistUtilsExtra.command.clean_i18n import clean_i18n class UpdateTranslationsCommand(Command): """Custom command to extract messages and update .po files.""" description = 'Extract messages to .pot and update .po' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): pot_file = 'po/[tool-name].pot' po_files = glob.glob('po/*.po') # Extract messages to .pot file print("Extracting messages to .pot file...") os.system(f'xgettext --from-code=UTF-8 -L Python -o {pot_file} [tool_directory]/*.py [main-script]') # Update .po files print("Updating .po files with new translations...") for po_file in po_files: print(f"Updating {po_file}...") os.system(f'msgmerge -U {po_file} {pot_file}') print("Translation update complete.") class CreateTranslationCommand(Command): """Custom command to create a new .po file for a specific language.""" description = 'Create a new .po file for the specified language' user_options = [ ('locale=', 'l', 'Locale code for the new translation (e.g., fr_FR, pt_BR)') ] def initialize_options(self): self.locale = None def finalize_options(self): if self.locale is None: raise Exception("You must specify the locale code (e.g., --locale=fr_FR)") def run(self): pot_file = 'po/[tool-name].pot' po_dir = 'po' po_file = os.path.join(po_dir, f'{self.locale}.po') # Create .pot file if needed if not os.path.exists(pot_file): print("Extracting messages to .pot file...") os.system(f'xgettext --from-code=UTF-8 -L Python -o {pot_file} [tool_directory]/*.py [main-script]') # Create new .po file if not os.path.exists(po_file): print(f"Creating new {po_file} for locale '{self.locale}'...") os.makedirs(po_dir, exist_ok=True) os.system(f'msginit --locale={self.locale} --input={pot_file} --output-file={po_file}') else: print(f"PO file for locale '{self.locale}' already exists: {po_file}") setup( cmdclass={ 'create_translation': CreateTranslationCommand, 'update_translations': UpdateTranslationsCommand, 'build': build_extra, 'build_i18n': build_i18n, 'clean': clean_i18n } ) ``` ## Translation Workflow ### 1. Clone Repository ```bash git clone https://github.com/ghostbsd/[tool-name] cd [tool-name] ``` ### 2. Create New Translation ```bash python setup.py create_translation --locale=fr_FR ``` Creates `po/fr_FR.po` with proper locale settings. ### 3. Update Translations After code changes: ```bash python setup.py update_translations ``` Updates all .po files with new/changed strings. ### 4. Edit Translations Edit the .po file: ```po #: update_station/main.py:45 msgid "Network Manager" msgstr "Gestionnaire de R�seau" ``` ### 5. Build and Test ```bash python setup.py build LANG=fr_FR.UTF-8 python3 [main-script] ``` ## Directory Structure ``` repository/ � po/ � � [tool-name].pot # Template (generated) � � fr_FR.po # French (France) � � fr_CA.po # French (Canada) � � pt_BR.po # Portuguese (Brazil) � build/ � � lib/ � � locale/ # Compiled .mo files � setup.py # Translation commands ``` ## Locale Format Use full locale format `language_COUNTRY` following install-station standard: ### Supported Locales (from install-station) - `ar_EG` - Arabic (Egypt) - `bg_BG` - Bulgarian (Bulgaria) - `bn_BD` - Bengali (Bangladesh) - `ca_ES` - Catalan (Spain) - `cs_CZ` - Czech (Czech Republic) - `da_DK` - Danish (Denmark) - `de_DE` - German (Germany) - `el_GR` - Greek (Greece) - `en_GB` - English (United Kingdom) - `en_US` - English (United States) - `es_ES` - Spanish (Spain) - `es_MX` - Spanish (Mexico) - `et_EE` - Estonian (Estonia) - `eu_ES` - Basque (Spain) - `fi_FI` - Finnish (Finland) - `fr_CA` - French (Canada) - `fr_FR` - French (France) - `gl_ES` - Galician (Spain) - `he_IL` - Hebrew (Israel) - `hi_IN` - Hindi (India) - `hr_HR` - Croatian (Croatia) - `hu_HU` - Hungarian (Hungary) - `id_ID` - Indonesian (Indonesia) - `is_IS` - Icelandic (Iceland) - `it_IT` - Italian (Italy) - `ja_JP` - Japanese (Japan) - `ko_KR` - Korean (South Korea) - `lt_LT` - Lithuanian (Lithuania) - `lv_LV` - Latvian (Latvia) - `mk_MK` - Macedonian (North Macedonia) - `nb_NO` - Norwegian Bokmål (Norway) - `nl_NL` - Dutch (Netherlands) - `nn_NO` - Norwegian Nynorsk (Norway) - `pl_PL` - Polish (Poland) - `pt_BR` - Portuguese (Brazil) - `pt_PT` - Portuguese (Portugal) - `ro_RO` - Romanian (Romania) - `ru_RU` - Russian (Russia) - `sk_SK` - Slovak (Slovakia) - `sl_SI` - Slovenian (Slovenia) - `sr_RS` - Serbian (Serbia) - `sv_SE` - Swedish (Sweden) - `th_TH` - Thai (Thailand) - `tr_TR` - Turkish (Turkey) - `uk_UA` - Ukrainian (Ukraine) - `vi_VN` - Vietnamese (Vietnam) - `zh_CN` - Chinese (China) - `zh_TW` - Chinese (Taiwan) ## Repository Status ### Tools Using This Standard - � **update-station** - Reference implementation - � **install-station** - Same implementation ### Tools Needing Implementation - **networkmgr** - Needs migration to standard commands - **setup-station** - Needs translation commands added - **station-tweak** - Needs translation commands added - **software-station** - Needs translation commands added - **backup-station** - Needs migration from DistUtilsExtra - **gbi** - Needs translation commands added ## Best Practices - Use full `language_COUNTRY` locale format - Keep UI text concise for interface constraints - Test translations in actual application - Use consistent terminology across GhostBSD tools - Commit only .po files (not .pot or .mo files) - Run `update_translations` regularly after code changes ## Contributing 1. Fork repository 2. Create/update translations: `python setup.py create_translation --locale=fr_FR` 3. Edit .po files with translations 4. Build and test: `python setup.py build` 5. Commit only .po files 6. Submit pull request

Python Tool Translation Guide

This guide covers translating GhostBSD Python applications using the standard workflow implemented in update-station.

Prerequisites

  • Python development environment
  • Git access to the repository
  • Text editor for .po files
  • gettext tools: sudo pkg install gettext-tools

Setup.py Implementation

GhostBSD Python tools use these custom setuptools commands (based on update-station):

import os
import glob
from setuptools import setup, Command
from DistUtilsExtra.command.build_extra import build_extra
from DistUtilsExtra.command.build_i18n import build_i18n
from DistUtilsExtra.command.clean_i18n import clean_i18n

class UpdateTranslationsCommand(Command):
    """Custom command to extract messages and update .po files."""
    description = 'Extract messages to .pot and update .po'
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        pot_file = 'po/[tool-name].pot'
        po_files = glob.glob('po/*.po')
        
        # Extract messages to .pot file
        print("Extracting messages to .pot file...")
        os.system(f'xgettext --from-code=UTF-8 -L Python -o {pot_file} [tool_directory]/*.py [main-script]')
        
        # Update .po files
        print("Updating .po files with new translations...")
        for po_file in po_files:
            print(f"Updating {po_file}...")
            os.system(f'msgmerge -U {po_file} {pot_file}')
        print("Translation update complete.")

class CreateTranslationCommand(Command):
    """Custom command to create a new .po file for a specific language."""
    description = 'Create a new .po file for the specified language'
    user_options = [
        ('locale=', 'l', 'Locale code for the new translation (e.g., fr_FR, pt_BR)')
    ]

    def initialize_options(self):
        self.locale = None

    def finalize_options(self):
        if self.locale is None:
            raise Exception("You must specify the locale code (e.g., --locale=fr_FR)")

    def run(self):
        pot_file = 'po/[tool-name].pot'
        po_dir = 'po'
        po_file = os.path.join(po_dir, f'{self.locale}.po')
        
        # Create .pot file if needed
        if not os.path.exists(pot_file):
            print("Extracting messages to .pot file...")
            os.system(f'xgettext --from-code=UTF-8 -L Python -o {pot_file} [tool_directory]/*.py [main-script]')
        
        # Create new .po file
        if not os.path.exists(po_file):
            print(f"Creating new {po_file} for locale '{self.locale}'...")
            os.makedirs(po_dir, exist_ok=True)
            os.system(f'msginit --locale={self.locale} --input={pot_file} --output-file={po_file}')
        else:
            print(f"PO file for locale '{self.locale}' already exists: {po_file}")

setup(
    cmdclass={
        'create_translation': CreateTranslationCommand,
        'update_translations': UpdateTranslationsCommand,
        'build': build_extra,
        'build_i18n': build_i18n,
        'clean': clean_i18n
    }
)

Translation Workflow

1. Clone Repository

git clone https://github.com/ghostbsd/[tool-name]
cd [tool-name]

2. Create New Translation

python setup.py create_translation --locale=fr_FR

Creates po/fr_FR.po with proper locale settings.

3. Update Translations

After code changes:

python setup.py update_translations

Updates all .po files with new/changed strings.

4. Edit Translations

Edit the .po file:

#: update_station/main.py:45
msgid "Network Manager"
msgstr "Gestionnaire de R�seau"

5. Build and Test

python setup.py build
LANG=fr_FR.UTF-8 python3 [main-script]

Directory Structure

repository/
   po/
      [tool-name].pot    # Template (generated)
      fr_FR.po           # French (France)
      fr_CA.po           # French (Canada)
      pt_BR.po           # Portuguese (Brazil)
   build/
      lib/
          locale/        # Compiled .mo files
   setup.py               # Translation commands

Locale Format

Use full locale format language_COUNTRY following install-station standard:

Supported Locales (from install-station)

  • ar_EG - Arabic (Egypt)
  • bg_BG - Bulgarian (Bulgaria)
  • bn_BD - Bengali (Bangladesh)
  • ca_ES - Catalan (Spain)
  • cs_CZ - Czech (Czech Republic)
  • da_DK - Danish (Denmark)
  • de_DE - German (Germany)
  • el_GR - Greek (Greece)
  • en_GB - English (United Kingdom)
  • en_US - English (United States)
  • es_ES - Spanish (Spain)
  • es_MX - Spanish (Mexico)
  • et_EE - Estonian (Estonia)
  • eu_ES - Basque (Spain)
  • fi_FI - Finnish (Finland)
  • fr_CA - French (Canada)
  • fr_FR - French (France)
  • gl_ES - Galician (Spain)
  • he_IL - Hebrew (Israel)
  • hi_IN - Hindi (India)
  • hr_HR - Croatian (Croatia)
  • hu_HU - Hungarian (Hungary)
  • id_ID - Indonesian (Indonesia)
  • is_IS - Icelandic (Iceland)
  • it_IT - Italian (Italy)
  • ja_JP - Japanese (Japan)
  • ko_KR - Korean (South Korea)
  • lt_LT - Lithuanian (Lithuania)
  • lv_LV - Latvian (Latvia)
  • mk_MK - Macedonian (North Macedonia)
  • nb_NO - Norwegian Bokmål (Norway)
  • nl_NL - Dutch (Netherlands)
  • nn_NO - Norwegian Nynorsk (Norway)
  • pl_PL - Polish (Poland)
  • pt_BR - Portuguese (Brazil)
  • pt_PT - Portuguese (Portugal)
  • ro_RO - Romanian (Romania)
  • ru_RU - Russian (Russia)
  • sk_SK - Slovak (Slovakia)
  • sl_SI - Slovenian (Slovenia)
  • sr_RS - Serbian (Serbia)
  • sv_SE - Swedish (Sweden)
  • th_TH - Thai (Thailand)
  • tr_TR - Turkish (Turkey)
  • uk_UA - Ukrainian (Ukraine)
  • vi_VN - Vietnamese (Vietnam)
  • zh_CN - Chinese (China)
  • zh_TW - Chinese (Taiwan)

Repository Status

Tools Using This Standard

  • update-station - Reference implementation
  • install-station - Same implementation

Tools Needing Implementation

  • networkmgr - Needs migration to standard commands
  • setup-station - Needs translation commands added
  • station-tweak - Needs translation commands added
  • software-station - Needs translation commands added
  • backup-station - Needs migration from DistUtilsExtra
  • gbi - Needs translation commands added

Best Practices

  • Use full language_COUNTRY locale format
  • Keep UI text concise for interface constraints
  • Test translations in actual application
  • Use consistent terminology across GhostBSD tools
  • Commit only .po files (not .pot or .mo files)
  • Run update_translations regularly after code changes

Contributing

  1. Fork repository
  2. Create/update translations: python setup.py create_translation --locale=fr_FR
  3. Edit .po files with translations
  4. Build and test: python setup.py build
  5. Commit only .po files
  6. Submit pull request

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
linkify-it-py
12
myst-parser
2-
sphinx-rtd-theme
3-
linkify-it-py
3+
sphinx-autobuild
4+
sphinx-rtd-theme

0 commit comments

Comments
 (0)