mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	Split dynamic javascript files into two separate directories
- One gets translated and is served statically - One does not get translated and is served dynamically - Add CI step
This commit is contained in:
		
							
								
								
									
										28
									
								
								.github/workflows/javascript.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								.github/workflows/javascript.yaml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | # Check javascript template files | ||||||
|  |  | ||||||
|  | name: Javascript Templates | ||||||
|  |  | ||||||
|  | on: | ||||||
|  |   push: | ||||||
|  |     branches: | ||||||
|  |       - master | ||||||
|  |  | ||||||
|  |   pull_request: | ||||||
|  |     branches-ignore: | ||||||
|  |       - l10* | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |  | ||||||
|  |   python: | ||||||
|  |     runs-on: ubuntu-latest | ||||||
|  |  | ||||||
|  |     env: | ||||||
|  |       GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||
|  |     steps: | ||||||
|  |       - name: Checkout Code | ||||||
|  |         uses: actions/checkout@v2 | ||||||
|  |       - name: Check Files | ||||||
|  |         run: | | ||||||
|  |           cd ci | ||||||
|  |           python check_js_templates.py | ||||||
|  |    | ||||||
| @@ -202,7 +202,7 @@ STATICFILES_DIRS = [ | |||||||
|  |  | ||||||
| # Translated Template settings | # Translated Template settings | ||||||
| STATICFILES_I18_PREFIX = 'i18n' | STATICFILES_I18_PREFIX = 'i18n' | ||||||
| STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js') | STATICFILES_I18_SRC = os.path.join(BASE_DIR, 'templates', 'js', 'translated') | ||||||
| STATICFILES_I18_TRG = STATICFILES_DIRS[0] + '_' + STATICFILES_I18_PREFIX | STATICFILES_I18_TRG = STATICFILES_DIRS[0] + '_' + STATICFILES_I18_PREFIX | ||||||
| STATICFILES_DIRS.append(STATICFILES_I18_TRG) | STATICFILES_DIRS.append(STATICFILES_I18_TRG) | ||||||
| STATICFILES_I18_TRG = os.path.join(STATICFILES_I18_TRG, STATICFILES_I18_PREFIX) | STATICFILES_I18_TRG = os.path.join(STATICFILES_I18_TRG, STATICFILES_I18_PREFIX) | ||||||
|   | |||||||
| @@ -93,28 +93,32 @@ settings_urls = [ | |||||||
|     url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/settings.html'), name='settings'), |     url(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/settings.html'), name='settings'), | ||||||
| ] | ] | ||||||
|  |  | ||||||
| # Some javascript files are served 'dynamically', allowing them to pass through the Django translation layer | # These javascript files are served "dynamically" - i.e. rendered on demand | ||||||
| dynamic_javascript_urls = [ | dynamic_javascript_urls = [ | ||||||
|     url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.js'), |     url(r'^inventree.js', DynamicJsView.as_view(template_name='js/dynamic/inventree.js'), name='inventree.js'), | ||||||
|     url(r'^attachment.js', DynamicJsView.as_view(template_name='js/attachment.js'), name='attachment.js'), | ] | ||||||
|     url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.js'), name='barcode.js'), |  | ||||||
|     url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.js'), name='bom.js'), | # These javascript files are pased through the Django translation layer | ||||||
|     url(r'^build.js', DynamicJsView.as_view(template_name='js/build.js'), name='build.js'), | translated_javascript_urls = [ | ||||||
|     url(r'^calendar.js', DynamicJsView.as_view(template_name='js/calendar.js'), name='calendar.js'), |     url(r'^api.js', DynamicJsView.as_view(template_name='js/translated/api.js'), name='api.js'), | ||||||
|     url(r'^company.js', DynamicJsView.as_view(template_name='js/company.js'), name='company.js'), |     url(r'^attachment.js', DynamicJsView.as_view(template_name='js/translated/attachment.js'), name='attachment.js'), | ||||||
|     url(r'^filters.js', DynamicJsView.as_view(template_name='js/filters.js'), name='filters.js'), |     url(r'^barcode.js', DynamicJsView.as_view(template_name='js/translated/barcode.js'), name='barcode.js'), | ||||||
|     url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'), |     url(r'^bom.js', DynamicJsView.as_view(template_name='js/translated/bom.js'), name='bom.js'), | ||||||
|     url(r'^inventree.js', DynamicJsView.as_view(template_name='js/inventree.js'), name='inventree.js'), |     url(r'^build.js', DynamicJsView.as_view(template_name='js/translated/build.js'), name='build.js'), | ||||||
|     url(r'^label.js', DynamicJsView.as_view(template_name='js/label.js'), name='label.js'), |     url(r'^calendar.js', DynamicJsView.as_view(template_name='js/translated/calendar.js'), name='calendar.js'), | ||||||
|     url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'), |     url(r'^company.js', DynamicJsView.as_view(template_name='js/translated/company.js'), name='company.js'), | ||||||
|     url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'), |     url(r'^filters.js', DynamicJsView.as_view(template_name='js/translated/filters.js'), name='filters.js'), | ||||||
|     url(r'^nav.js', DynamicJsView.as_view(template_name='js/nav.js'), name='nav.js'), |     url(r'^forms.js', DynamicJsView.as_view(template_name='js/translated/forms.js'), name='forms.js'), | ||||||
|     url(r'^order.js', DynamicJsView.as_view(template_name='js/order.js'), name='order.js'), |     url(r'^label.js', DynamicJsView.as_view(template_name='js/translated/label.js'), name='label.js'), | ||||||
|     url(r'^part.js', DynamicJsView.as_view(template_name='js/part.js'), name='part.js'), |     url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/translated/model_renderers.js'), name='model_renderers.js'), | ||||||
|     url(r'^report.js', DynamicJsView.as_view(template_name='js/report.js'), name='report.js'), |     url(r'^modals.js', DynamicJsView.as_view(template_name='js/translated/modals.js'), name='modals.js'), | ||||||
|     url(r'^stock.js', DynamicJsView.as_view(template_name='js/stock.js'), name='stock.js'), |     url(r'^nav.js', DynamicJsView.as_view(template_name='js/translated/nav.js'), name='nav.js'), | ||||||
|     url(r'^tables.js', DynamicJsView.as_view(template_name='js/tables.js'), name='tables.js'), |     url(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.js'), | ||||||
|     url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.js'), name='table_filters.js'), |     url(r'^part.js', DynamicJsView.as_view(template_name='js/translated/part.js'), name='part.js'), | ||||||
|  |     url(r'^report.js', DynamicJsView.as_view(template_name='js/translated/report.js'), name='report.js'), | ||||||
|  |     url(r'^stock.js', DynamicJsView.as_view(template_name='js/translated/stock.js'), name='stock.js'), | ||||||
|  |     url(r'^tables.js', DynamicJsView.as_view(template_name='js/translated/tables.js'), name='tables.js'), | ||||||
|  |     url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/translated/table_filters.js'), name='table_filters.js'), | ||||||
| ] | ] | ||||||
|  |  | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
| @@ -123,7 +127,8 @@ urlpatterns = [ | |||||||
|     url(r'^supplier-part/', include(supplier_part_urls)), |     url(r'^supplier-part/', include(supplier_part_urls)), | ||||||
|  |  | ||||||
|     # "Dynamic" javascript files which are rendered using InvenTree templating. |     # "Dynamic" javascript files which are rendered using InvenTree templating. | ||||||
|     url(r'^dynamic/', include(dynamic_javascript_urls)), |     url(r'^js/dynamic/', include(dynamic_javascript_urls)), | ||||||
|  |     url(r'^js/i18n/', include(translated_javascript_urls)), | ||||||
|  |  | ||||||
|     url(r'^common/', include(common_urls)), |     url(r'^common/', include(common_urls)), | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										121
									
								
								ci/check_js_templates.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								ci/check_js_templates.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | """ | ||||||
|  | Test that the "translated" javascript files to not contain template tags | ||||||
|  | which need to be determined at "run time". | ||||||
|  |  | ||||||
|  | This is because the "translated" javascript files are compiled into the "static" directory. | ||||||
|  |  | ||||||
|  | They should only contain template tags that render static information. | ||||||
|  | """ | ||||||
|  |  | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  | from __future__ import unicode_literals | ||||||
|  |  | ||||||
|  | import sys | ||||||
|  | import re | ||||||
|  | import os | ||||||
|  | import pathlib | ||||||
|  |  | ||||||
|  | here = os.path.abspath(os.path.dirname(__file__)) | ||||||
|  | template_dir = os.path.abspath(os.path.join(here, '..', 'InvenTree', 'templates')) | ||||||
|  |  | ||||||
|  | # We only care about the 'translated' files | ||||||
|  | js_i18n_dir = os.path.join(template_dir, 'js', 'translated') | ||||||
|  | js_dynamic_dir = os.path.join(template_dir, 'js', 'dynamic') | ||||||
|  |  | ||||||
|  | errors = 0 | ||||||
|  |  | ||||||
|  | print("=================================") | ||||||
|  | print("Checking static javascript files:") | ||||||
|  | print("=================================") | ||||||
|  |  | ||||||
|  | def check_invalid_tag(data): | ||||||
|  |  | ||||||
|  |     pattern = r"{%(\w+)" | ||||||
|  |  | ||||||
|  |     err_count = 0 | ||||||
|  |  | ||||||
|  |     for idx, line in enumerate(data): | ||||||
|  |  | ||||||
|  |         results = re.findall(pattern, line) | ||||||
|  |  | ||||||
|  |         for result in results: | ||||||
|  |             err_count += 1 | ||||||
|  |  | ||||||
|  |             print(f" - Error on line {idx+1}: %{{{result[0]}") | ||||||
|  |  | ||||||
|  |     return err_count | ||||||
|  |  | ||||||
|  | def check_prohibited_tags(data): | ||||||
|  |  | ||||||
|  |     allowed_tags = [ | ||||||
|  |         'if', | ||||||
|  |         'elif', | ||||||
|  |         'else', | ||||||
|  |         'endif', | ||||||
|  |         'for', | ||||||
|  |         'endfor', | ||||||
|  |         'trans', | ||||||
|  |         'load', | ||||||
|  |         'include', | ||||||
|  |         'url', | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     pattern = r"{% (\w+)\s" | ||||||
|  |  | ||||||
|  |     err_count = 0 | ||||||
|  |  | ||||||
|  |     has_trans = False | ||||||
|  |  | ||||||
|  |     for idx, line in enumerate(data): | ||||||
|  |  | ||||||
|  |         for tag in re.findall(pattern, line): | ||||||
|  |  | ||||||
|  |             if tag not in allowed_tags: | ||||||
|  |                 print(f" > Line {idx+1} - '{tag}'") | ||||||
|  |                 err_count += 1 | ||||||
|  |  | ||||||
|  |             if tag == 'trans': | ||||||
|  |                 has_trans = True | ||||||
|  |  | ||||||
|  |     if not has_trans: | ||||||
|  |         print(f" > missing 'trans' tag") | ||||||
|  |         err_count += 1 | ||||||
|  |  | ||||||
|  |     return err_count | ||||||
|  |  | ||||||
|  |  | ||||||
|  | for filename in pathlib.Path(js_i18n_dir).rglob('*.js'): | ||||||
|  |  | ||||||
|  |     print(f"Checking file 'translated/{os.path.basename(filename)}':") | ||||||
|  |  | ||||||
|  |     with open(filename, 'r') as js_file: | ||||||
|  |         data = js_file.readlines() | ||||||
|  |  | ||||||
|  |     errors += check_invalid_tag(data) | ||||||
|  |     errors += check_prohibited_tags(data) | ||||||
|  |  | ||||||
|  | for filename in pathlib.Path(js_dynamic_dir).rglob('*.js'): | ||||||
|  |  | ||||||
|  |     print(f"Checking file 'dynamic/{os.path.basename(filename)}':") | ||||||
|  |  | ||||||
|  |     # Check that the 'dynamic' files do not contains any translated strings | ||||||
|  |     with open(filename, 'r') as js_file: | ||||||
|  |         data = js_file.readlines() | ||||||
|  |  | ||||||
|  |     pattern = r'{% trans ' | ||||||
|  |      | ||||||
|  |     err_count = 0 | ||||||
|  |  | ||||||
|  |     for idx, line in enumerate(data): | ||||||
|  |  | ||||||
|  |         results = re.findall(pattern, line) | ||||||
|  |  | ||||||
|  |         if len(results) > 0: | ||||||
|  |             errors += 1 | ||||||
|  |  | ||||||
|  |             print(f" > {{% trans %}} tag found at line {idx + 1}") | ||||||
|  |  | ||||||
|  | if errors > 0: | ||||||
|  |     print(f"Found {errors} incorrect template tags") | ||||||
|  |  | ||||||
|  | sys.exit(errors) | ||||||
		Reference in New Issue
	
	Block a user