Skip to content

Commit

Permalink
Use Hugo's default language setting and support TOML string files
Browse files Browse the repository at this point in the history
- String files in other languages are generated with the same file type as the string file in the default language
- Config file and string file in default language are looked for automatically
  • Loading branch information
PhuNH committed Sep 8, 2023
1 parent ed95ad7 commit 720a3b6
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 46 deletions.
27 changes: 26 additions & 1 deletion hugo_gettext/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import glob
import importlib.util
import inspect
import logging
import os
from typing import List, Dict, Callable, Set, Type, Tuple

Expand Down Expand Up @@ -63,6 +64,25 @@ def _read_content_config(i18n_config) -> Dict[str, List[str]]:
return content_files


def _find_string_file(default_lang: str) -> str:
if not os.path.isdir('i18n'):
return ''
possible_paths = [f'i18n/{default_lang}.toml',
f'i18n/{default_lang}.yaml']
for path in possible_paths:
if os.path.isfile(path):
return path
return ''


def _find_config_file() -> str:
possible_paths = ['hugo.toml', 'hugo.yaml', 'config.toml', 'config.yaml']
for path in possible_paths:
if os.path.isfile(path):
return path
return ''


excluded_keys = {'aliases', 'date',
'i18n_configs', 'layout',
'publishDate',
Expand Down Expand Up @@ -168,6 +188,11 @@ def __init__(self, hugo_config, config_path: str = '', customs_path: str = ''):
self.excluded_keys = excluded_keys | custom_excluded_keys | set(i18n_config.get('excludedKeys', '').split())
self.shortcodes = i18n_config.get('shortcodes', {})

self.default_lang = hugo_config.get('defaultContentLanguage', 'en')
self.string_file_path = _find_string_file(self.default_lang)
if self.do_strings and not self.string_file_path:
logging.warning('Strings specified as an i18n target, but no string file in the default language found')

goldmark_config = hugo_config.get('markup', {}).get('goldmark', {})
extensions_config = goldmark_config.get('extensions', {})
self.parse_definition_list = extensions_config.get('definitionList', True)
Expand All @@ -181,7 +206,7 @@ def __init__(self, hugo_config, config_path: str = '', customs_path: str = ''):
@classmethod
def from_config_file(cls, config_path: str, customs_path: str = ''):
if not config_path:
config_path = 'hugo.toml'
config_path = _find_config_file()
hugo_config = utils.read_file(config_path)
return cls(hugo_config, config_path, customs_path)

Expand Down
21 changes: 12 additions & 9 deletions hugo_gettext/extraction/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,33 @@ def i12ize_data_files(self):
def i12ize_data_others(self):
hg_config = self.hg_config
# config fields
path = 'config.yaml'
default_language_config = hg_config.hugo_config.get('languages', {}).get('en', {})
default_language_config = hg_config.hugo_config.get('languages', {}).get(hg_config.default_lang, {})
if hg_config.do_title:
if 'title' not in default_language_config:
logging.warning(f"Default language config section doesn't have a `title` field.")
else:
self.default_domain_e.add_entry(path, default_language_config['title'], 0)
self.default_domain_e.add_entry(hg_config.config_path, default_language_config['title'], 0)
if hg_config.do_description:
if 'params' not in default_language_config or 'description' not in default_language_config['params']:
logging.warning(f"Default language config section doesn't have a `params.description` field.")
else:
self.default_domain_e.add_entry(path, default_language_config['params']['description'], 0)
self.default_domain_e.add_entry(hg_config.config_path,
default_language_config['params']['description'],
0)
if hg_config.do_menu:
for menu_entry in default_language_config['menu']['main']:
self.default_domain_e.add_entry(path, menu_entry['name'], 0)
self.default_domain_e.add_entry(hg_config.config_path, menu_entry['name'], 0)
# data
if hg_config.data:
self.i12ize_data_files()
# strings
if hg_config.do_strings:
path = 'i18n/en.yaml'
src_strings = utils.read_strings()
if hg_config.do_strings and hg_config.string_file_path:
src_strings = utils.read_file(hg_config.string_file_path)
for _, string in src_strings.items():
self.default_domain_e.add_entry(path, string['other'], 0, string.get('comment', ''))
self.default_domain_e.add_entry(hg_config.string_file_path,
string['other'],
0,
string.get('comment', ''))

def extract(self, target_dir: str):
os.makedirs(target_dir, exist_ok=True)
Expand Down
35 changes: 17 additions & 18 deletions hugo_gettext/generation/g_lang.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
import os
from typing import List, Dict

import yaml
from markdown_gettext.domain_generation import gettext_func
from mdit_py_i18n.utils import L10NResult

from .g_domain import HugoDomainG
from .. import utils
from ..utils import HugoGProtocol
from ..utils import HugoGProtocol, TextFormat

L10NResults = Dict[str, List[L10NResult]]

Expand All @@ -26,7 +25,7 @@ def __init__(self, g: HugoGProtocol, lang_code: str):
self.g = g
self.lang_code = lang_code
self.hugo_lang_code = self.g.hg_config.convert_lang_code(self.lang_code)
self.lang_prefix = '' if self.hugo_lang_code == 'en' else f'/{self.hugo_lang_code}'
self.lang_prefix = '' if self.hugo_lang_code == self.g.hg_config.default_lang else f'/{self.hugo_lang_code}'
self.l10n_results: L10NResults = {}
self.file_l10n_count = 0
self.default_domain_g = None
Expand All @@ -50,10 +49,10 @@ def localize_strings(self) -> L10NResult:

def write_strings(self, target_strings):
if len(target_strings) > 0:
i18n_path = f'i18n/{self.hugo_lang_code}.yaml'
with open(i18n_path, 'w+') as f_target_i18n:
logging.info(i18n_path)
f_target_i18n.write(yaml.dump(target_strings, default_flow_style=False, allow_unicode=True))
text_format = TextFormat.decide_by_path(self.g.hg_config.string_file_path)
file_path = f'i18n/{self.hugo_lang_code}{text_format.value}'
utils.write_file(file_path, target_strings)
logging.info(file_path)

def localize_languages(self):
hg_config = self.g.hg_config
Expand All @@ -76,7 +75,7 @@ def localize_languages(self):
def localize_menu(self):
menu = {'main': []}
hugo_config = self.g.hg_config.hugo_config
for menu_item in hugo_config['languages']['en']['menu']['main']:
for menu_item in hugo_config['languages'][self.g.hg_config.default_lang]['menu']['main']:
target_menu_item = copy.deepcopy(menu_item)
target_menu_item['name'] = self.default_domain_g.l10n_func(target_menu_item['name'])
menu['main'].append(target_menu_item)
Expand All @@ -85,13 +84,14 @@ def localize_menu(self):
def localize_description(self):
hugo_config = self.g.hg_config.hugo_config
hugo_config['languages'][self.hugo_lang_code]['params'] = {
'description': self.default_domain_g.l10n_func(hugo_config['languages']['en']['params']['description'])
'description': self.default_domain_g.l10n_func(
hugo_config['languages'][self.g.hg_config.default_lang]['params']['description'])
}

def localize_title(self):
hugo_config = self.g.hg_config.hugo_config
hugo_config['languages'][self.hugo_lang_code]['title'] = (
self.default_domain_g.l10n_func(hugo_config['languages']['en']['title']))
self.default_domain_g.l10n_func(hugo_config['languages'][self.g.hg_config.default_lang]['title']))

def generate_data_files(self):
for path, data in self.g.src_data.items():
Expand All @@ -106,19 +106,18 @@ def generate_data_files(self):
utils.write_file(target_path, data)

def generate_data_others(self):
"""Generate strings file and data files, and localize config fields.
Strings file will be generated even if the language doesn't meet requirements.
"""Generate string file and data files, and localize config fields.
String file will be generated even if the language doesn't meet requirements.
Config fields and data files won't.
"""
hg_config = self.g.hg_config
src_strings = self.g.src_strings
file_total_count = self.g.file_total_count
file_l10n_count = self.file_l10n_count
strings_ok = True
if hg_config.do_strings and src_strings is not None:
strings_result = self.localize_strings()
self.write_strings(strings_result.localized)
strings_ok = strings_result.l10n_count > 0
# src_strings is already checked outside, no check needed here anymore
strings_result = self.localize_strings()
self.write_strings(strings_result.localized)
# strings is considered ok when there's no source string or when some strings are translated
strings_ok = strings_result.rate == -1 or strings_result.l10n_count > 0

# Only generate the config section and data files for the language if conditions are met
# X = 'languages' in hugo_config and (
Expand Down
5 changes: 4 additions & 1 deletion hugo_gettext/generation/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ def generate(args):
:return: None
"""
hg_config, mdi = initialize(RendererHugoL10N, args.customs, args.config)
src_strings = utils.read_strings()
if hg_config.do_strings and hg_config.string_file_path:
src_strings = utils.read_file(hg_config.string_file_path)
else:
src_strings = {}
original_hugo_config = copy.deepcopy(hg_config.hugo_config)
src_data = utils.read_data_files(hg_config.data)

Expand Down
24 changes: 7 additions & 17 deletions hugo_gettext/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ class HugoDomainGProtocol(DomainGenerationProtocol):


class TextFormat(Enum):
ELSE = -1
YAML = 0
TOML = 1
ELSE = ''
YAML = '.yaml'
TOML = '.toml'

@classmethod
def decide_by_path(cls, path: str) -> 'TextFormat':
if (ext := os.path.splitext(path)[1]) in {'.yaml', '.yml'}:
if (ext := os.path.splitext(path)[1]) == cls.YAML.value or ext == '.yml':
return cls.YAML
elif ext == '.toml':
elif ext == cls.TOML.value:
return cls.TOML
else:
return cls.ELSE

def load_str(self, content: str):
def load_content(self, content: str):
if self == TextFormat.YAML:
return yaml.safe_load(content)
elif self == TextFormat.TOML:
Expand All @@ -81,7 +81,7 @@ def dump_obj(self, obj):
def read_file(file_path: str):
text_format = TextFormat.decide_by_path(file_path)
with open(file_path) as f:
return text_format.load_str(f.read())
return text_format.load_content(f.read())


def write_file(file_path: str, obj):
Expand All @@ -97,13 +97,3 @@ def read_data_files(file_paths: List[str]) -> Dict:
continue
src_data[path] = read_file(path)
return src_data


def read_strings() -> Dict:
try:
with open("i18n/en.yaml", 'r') as f_i18n:
src_strings = yaml.safe_load(f_i18n)
except FileNotFoundError:
src_strings = {}

return src_strings

0 comments on commit 720a3b6

Please sign in to comment.