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 | ||||
| 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_DIRS.append(STATICFILES_I18_TRG) | ||||
| 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'), | ||||
| ] | ||||
|  | ||||
| # 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 = [ | ||||
|     url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.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'), | ||||
|     url(r'^build.js', DynamicJsView.as_view(template_name='js/build.js'), name='build.js'), | ||||
|     url(r'^calendar.js', DynamicJsView.as_view(template_name='js/calendar.js'), name='calendar.js'), | ||||
|     url(r'^company.js', DynamicJsView.as_view(template_name='js/company.js'), name='company.js'), | ||||
|     url(r'^filters.js', DynamicJsView.as_view(template_name='js/filters.js'), name='filters.js'), | ||||
|     url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'), | ||||
|     url(r'^inventree.js', DynamicJsView.as_view(template_name='js/inventree.js'), name='inventree.js'), | ||||
|     url(r'^label.js', DynamicJsView.as_view(template_name='js/label.js'), name='label.js'), | ||||
|     url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'), | ||||
|     url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'), | ||||
|     url(r'^nav.js', DynamicJsView.as_view(template_name='js/nav.js'), name='nav.js'), | ||||
|     url(r'^order.js', DynamicJsView.as_view(template_name='js/order.js'), name='order.js'), | ||||
|     url(r'^part.js', DynamicJsView.as_view(template_name='js/part.js'), name='part.js'), | ||||
|     url(r'^report.js', DynamicJsView.as_view(template_name='js/report.js'), name='report.js'), | ||||
|     url(r'^stock.js', DynamicJsView.as_view(template_name='js/stock.js'), name='stock.js'), | ||||
|     url(r'^tables.js', DynamicJsView.as_view(template_name='js/tables.js'), name='tables.js'), | ||||
|     url(r'^table_filters.js', DynamicJsView.as_view(template_name='js/table_filters.js'), name='table_filters.js'), | ||||
|     url(r'^inventree.js', DynamicJsView.as_view(template_name='js/dynamic/inventree.js'), name='inventree.js'), | ||||
| ] | ||||
|  | ||||
| # These javascript files are pased through the Django translation layer | ||||
| translated_javascript_urls = [ | ||||
|     url(r'^api.js', DynamicJsView.as_view(template_name='js/translated/api.js'), name='api.js'), | ||||
|     url(r'^attachment.js', DynamicJsView.as_view(template_name='js/translated/attachment.js'), name='attachment.js'), | ||||
|     url(r'^barcode.js', DynamicJsView.as_view(template_name='js/translated/barcode.js'), name='barcode.js'), | ||||
|     url(r'^bom.js', DynamicJsView.as_view(template_name='js/translated/bom.js'), name='bom.js'), | ||||
|     url(r'^build.js', DynamicJsView.as_view(template_name='js/translated/build.js'), name='build.js'), | ||||
|     url(r'^calendar.js', DynamicJsView.as_view(template_name='js/translated/calendar.js'), name='calendar.js'), | ||||
|     url(r'^company.js', DynamicJsView.as_view(template_name='js/translated/company.js'), name='company.js'), | ||||
|     url(r'^filters.js', DynamicJsView.as_view(template_name='js/translated/filters.js'), name='filters.js'), | ||||
|     url(r'^forms.js', DynamicJsView.as_view(template_name='js/translated/forms.js'), name='forms.js'), | ||||
|     url(r'^label.js', DynamicJsView.as_view(template_name='js/translated/label.js'), name='label.js'), | ||||
|     url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/translated/model_renderers.js'), name='model_renderers.js'), | ||||
|     url(r'^modals.js', DynamicJsView.as_view(template_name='js/translated/modals.js'), name='modals.js'), | ||||
|     url(r'^nav.js', DynamicJsView.as_view(template_name='js/translated/nav.js'), name='nav.js'), | ||||
|     url(r'^order.js', DynamicJsView.as_view(template_name='js/translated/order.js'), name='order.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 = [ | ||||
| @@ -123,7 +127,8 @@ urlpatterns = [ | ||||
|     url(r'^supplier-part/', include(supplier_part_urls)), | ||||
|  | ||||
|     # "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)), | ||||
|  | ||||
|   | ||||
							
								
								
									
										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