11import html
22import io
3+ import json
34import math
45import os
56import re
@@ -24,24 +25,32 @@ def element_attr(element, attr, default=None):
2425class QGSReader :
2526 """ Read QGIS projects and extract data for QWC config """
2627
27- def __init__ (self , config , logger , assets_dir , use_cached_project_metadata , global_print_layouts ):
28+ def __init__ (self , config , logger , assets_dir , translations_dir , use_cached_project_metadata , global_print_layouts ):
2829 """Constructor
2930
3031 :param obj config: Config generator config
3132 :param Logger logger: Application logger
3233 :param string assets_dir: Assets directory
34+ :param str translations_dir: Viewer translations directory
3335 :param bool use_cached_project_metadata: Whether to use cached project metadata
3436 :param list global_print_layouts: Global print layouts
3537 """
3638 self .config = config
3739 self .logger = logger
3840 self .assets_dir = assets_dir
41+ self .translations_dir = translations_dir
3942 self .use_cached_project_metadata = use_cached_project_metadata
4043 self .global_print_layouts = global_print_layouts
4144
4245 self .qgs_resources_path = config .get ('qgis_projects_base_dir' , '/tmp/' )
4346 self .qgs_ext = config .get ('qgis_project_extension' , '.qgs' )
4447 self .nested_nrels = config .get ('generate_nested_nrel_forms' , False )
48+ try :
49+ with open (os .path .join (self .translations_dir , 'tsconfig.json' )) as fh :
50+ self .viewer_languages = json .load (fh )['languages' ]
51+ except :
52+ self .logger .warning ("Failed to detect viewer languages from tsconfig.json" )
53+ self .viewer_languages = ["en-US" ]
4554
4655 self .db_engine = DatabaseEngine ()
4756
@@ -57,8 +66,9 @@ def read(self, map_prefix, theme_item, edit_datasets):
5766 try :
5867 if map_prefix .startswith ("pg/" ):
5968 parts = map_prefix .split ("/" )
60- qgs_path = self .qgs_resources_path
69+ qgs_dir = self .qgs_resources_path
6170 qgs_filename = 'postgresql:///?service=qgisprojects&schema=%s&project=%s' % (parts [1 ], parts [2 ])
71+ projectname = parts [2 ]
6272
6373 qgis_projects_db = self .db_engine .db_engine ("postgresql:///?service=qgisprojects" )
6474
@@ -84,6 +94,8 @@ def read(self, map_prefix, theme_item, edit_datasets):
8494 else :
8595 qgs_filename = map_prefix + self .qgs_ext
8696 qgs_path = os .path .join (self .qgs_resources_path , qgs_filename )
97+ qgs_dir = os .path .dirname (qgs_path )
98+ projectname = os .path .basename (qgs_path ).removesuffix (self .qgs_ext )
8799 if not os .path .exists (qgs_path ):
88100 self .logger .error ("Could not find QGS project '%s'" % qgs_filename )
89101 return None
@@ -131,9 +143,10 @@ def read(self, map_prefix, theme_item, edit_datasets):
131143
132144 return {
133145 "project_crs" : self .__project_crs (root ),
146+ "translations" : self .__theme_translations (qgs_dir , projectname ),
134147 "print_templates" : self .__print_templates (root , shortname_map ),
135148 "visibility_presets" : self .__visibility_presets (root ),
136- "layer_metadata" : self .__layer_metadata (root , shortname_map , map_prefix , edit_datasets , theme_item , qgs_path )
149+ "layer_metadata" : self .__layer_metadata (root , shortname_map , map_prefix , edit_datasets , theme_item , qgs_dir ),
137150 }
138151
139152
@@ -142,6 +155,28 @@ def __project_crs(self, root):
142155 authid = root .find ('./projectCrs/spatialrefsys/authid' )
143156 return authid .text if authid is not None else None
144157
158+ def __theme_translations (self , qgs_dir , projectname ):
159+ """ Read theme portion of translations from <projectname>_<lang>.json. """
160+ all_translations = {}
161+
162+ for language in self .viewer_languages :
163+ translations = {}
164+
165+ json_file = os .path .join (qgs_dir , f"{ projectname } _{ language } .json" )
166+ if not os .path .exists (json_file ):
167+ json_file = os .path .join (qgs_dir , f"{ projectname } _{ language [0 :2 ]} .json" )
168+ if os .path .exists (json_file ):
169+ self .logger .info ('Reading project translations %s' % json_file )
170+ try :
171+ with open (json_file ) as fh :
172+ translations = json .load (fh )['theme' ]
173+ except Exception as e :
174+ self .logger .info ('Failed to read project translations %s: %s' % (json_file , str (e )))
175+
176+ if translations :
177+ all_translations [language ] = translations
178+
179+ return all_translations
145180
146181 def __print_templates (self , root , shortname_map ):
147182 """ Collect print templates from QGS and merge with global print layouts. """
@@ -248,7 +283,7 @@ def __visibility_presets(self, root):
248283 return result
249284
250285
251- def __layer_metadata (self , root , shortname_map , map_prefix , edit_datasets , theme_item , qgs_path ):
286+ def __layer_metadata (self , root , shortname_map , map_prefix , edit_datasets , theme_item , qgs_dir ):
252287 """ Read additional layer metadata from QGS. """
253288 layers_metadata = {}
254289 # Collect metadata for layers
@@ -276,7 +311,7 @@ def __layer_metadata(self, root, shortname_map, map_prefix, edit_datasets, theme
276311
277312 # Edit metadata
278313 if editable :
279- self .__layer_edit_metadata (root , layer_metadata , maplayer , layername , map_prefix , shortname_map , qgs_path , theme_item )
314+ self .__layer_edit_metadata (root , layer_metadata , maplayer , layername , map_prefix , shortname_map , qgs_dir , theme_item )
280315
281316 layers_metadata [layername ] = layer_metadata
282317
@@ -291,7 +326,7 @@ def __layer_metadata(self, root, shortname_map, map_prefix, edit_datasets, theme
291326 return layers_metadata
292327
293328
294- def __layer_edit_metadata (self , root , layer_metadata , maplayer , layername , map_prefix , shortnames , qgs_path , theme_item ):
329+ def __layer_edit_metadata (self , root , layer_metadata , maplayer , layername , map_prefix , shortnames , qgs_dir , theme_item ):
295330 """ Read layer metadata relevant for editing from QGS. """
296331
297332 provider = maplayer .find ('provider' ).text
@@ -384,7 +419,7 @@ def __layer_edit_metadata(self, root, layer_metadata, maplayer, layername, map_p
384419
385420 # Generate form
386421 layer_metadata ["edit_form" ] = self .__generate_edit_form (
387- root , qgs_path , map_prefix , shortnames , maplayer , layer_metadata , layername , theme_item
422+ root , qgs_dir , map_prefix , shortnames , maplayer , layer_metadata , layername , theme_item
388423 )
389424
390425
@@ -686,7 +721,7 @@ def __column_metadata(self, field_metadata, datasource, column, data_type_only =
686721 constraints ['max' ] = ranges [data_type ]['max' ]
687722
688723
689- def __generate_edit_form (self , project , qgs_path , map_prefix , shortnames , maplayer , layer_metadata , layername , theme_item ):
724+ def __generate_edit_form (self , project , qgs_dir , map_prefix , shortnames , maplayer , layer_metadata , layername , theme_item ):
690725 """ Copy / generate edit from from QGIS form settings. """
691726
692727 projectname = os .path .basename (map_prefix )
@@ -708,7 +743,7 @@ def __generate_edit_form(self, project, qgs_path, map_prefix, shortnames, maplay
708743 if editform is not None :
709744 formpath = editform .text
710745 if not os .path .isabs (formpath ):
711- formpath = os .path .join (os . path . dirname ( qgs_path ) , formpath )
746+ formpath = os .path .join (qgs_dir , formpath )
712747 try :
713748 os .makedirs (outputdir , exist_ok = True )
714749 shutil .copy (formpath , outputfile )
0 commit comments