sitegen.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import argparse
  2. from jinja2 import Environment, FileSystemLoader, contextfilter
  3. from pathlib import Path
  4. from os import walk, makedirs
  5. from os.path import join, exists, splitext, split
  6. from shutil import rmtree, copy, copytree
  7. from functools import lru_cache
  8. LANGUAGES = 'languages'
  9. #TODO: load from config file
  10. DEFAULT_LANG = 'en'
  11. OTHER_LANGS = set(['es'])
  12. @lru_cache(None)
  13. def get_lang_dic(lang):
  14. if not exists(LANGUAGES):
  15. makedirs(LANGUAGES)
  16. lang_file = join(LANGUAGES, lang + '.txt')
  17. if not exists(lang_file):
  18. return {}
  19. else:
  20. dic = {}
  21. with open(lang_file) as f:
  22. for line in f.readlines():
  23. key, value = line.strip('\n').split(':')
  24. dic[key] = value
  25. return dic
  26. def save_dic(lang, dic):
  27. with open(join(LANGUAGES, lang + '.txt'), 'w') as f:
  28. for key, value in dic.items():
  29. f.write(f"{key}:{value}\n")
  30. def add_lang_prefix(lang, path):
  31. if lang == DEFAULT_LANG:
  32. return path
  33. if lang not in OTHER_LANGS:
  34. print(f"Not registered language: `{lang}`")
  35. return f"/{lang}{path}"
  36. @contextfilter
  37. def lang(ctx, value):
  38. lang = ctx.environment.globals['lang']
  39. if lang == DEFAULT_LANG:
  40. return value
  41. else:
  42. dic = get_lang_dic(lang)
  43. if value in dic and dic[value]:
  44. return dic[value]
  45. else:
  46. dic[value] = ""
  47. save_dic(lang, dic)
  48. print(f"Not translated phrase: `{value}`")
  49. return value
  50. @contextfilter
  51. def lang_url(ctx, lang):
  52. name, _ = splitext(ctx.name)
  53. if name.startswith('./'):
  54. name = name[2:]
  55. if name == 'index':
  56. name = ''
  57. return add_lang_prefix(lang, f"/{name}")
  58. @contextfilter
  59. def cur_lang(ctx, path):
  60. lang = ctx.environment.globals['lang']
  61. return add_lang_prefix(lang, path)
  62. def static(value):
  63. return f"/static/{value}"
  64. def compile(env, path, target):
  65. lang = env.globals['lang']
  66. for base, _, docs in walk(path):
  67. cur_base = Path(base)
  68. cur_base = Path(*cur_base.parts[1:])
  69. for doc in docs:
  70. if doc.startswith('_'):
  71. # Ignore this files
  72. continue
  73. src = join(base, doc)
  74. if args.with_index and doc != 'index.html':
  75. name, _ = splitext(doc)
  76. dst = join(cur_base, name, 'index.html')
  77. else:
  78. dst = join(cur_base, doc)
  79. if lang != DEFAULT_LANG:
  80. dst = join(lang, dst)
  81. dst = join(target, dst)
  82. dst_folder, _ = split(dst)
  83. if not exists(dst_folder):
  84. makedirs(dst_folder)
  85. template = env.get_template(join(cur_base, doc))
  86. output = template.render()
  87. with open(dst, 'w') as f:
  88. f.write(output)
  89. def run(args):
  90. # Load layout
  91. file_loader = FileSystemLoader(args.source)
  92. env = Environment(loader=file_loader)
  93. env.globals['lang'] = DEFAULT_LANG
  94. # Add filters
  95. env.filters['lang'] = lang
  96. env.filters['lang_url'] = lang_url
  97. env.filters['cur_lang'] = cur_lang
  98. env.filters['static'] = static
  99. path = Path(args.source)
  100. if exists(args.target):
  101. rmtree(args.target)
  102. if exists('root'):
  103. copytree('root', args.target)
  104. else:
  105. makedirs(args.target)
  106. compile(env, path, args.target)
  107. copytree('static', join(args.target, 'static'))
  108. for other_lang in OTHER_LANGS:
  109. env.globals['lang'] = other_lang
  110. compile(env, path, args.target)
  111. if __name__ == '__main__':
  112. parser = argparse.ArgumentParser("Site generator")
  113. parser.add_argument('--with_index', action='store_true', default=False)
  114. parser.add_argument('--source', default='layout')
  115. parser.add_argument('--target', default='build')
  116. args = parser.parse_args()
  117. run(args)