@@ -94,6 +94,10 @@ def handle(self, *args, **kwargs):
9494 updated_remote_ids = set ()
9595 created_ns_initiatives_pk = []
9696
97+ # In-memory alignment helpers
98+ category_by_remote_index = {} # remote_id -> list[NSDInitiativesCategory]
99+ pending_translations = {} # remote_id -> list[(lang, index, label)]
100+
97101 for lang , resp in responses :
98102 for element in resp :
99103 try :
@@ -119,44 +123,99 @@ def handle(self, *args, **kwargs):
119123 for field , value in defaults .items ():
120124 setattr (ni , field , value )
121125 ni .save (update_fields = defaults .keys ())
122- updated_remote_ids .add (remote_id ) # Mark as updated, only for EN entries
126+ updated_remote_ids .add (remote_id )
123127 created_ns_initiatives_pk .append (ni .pk )
124- else :
125- try :
126- # We could use ISO also to identify the entry, but remote_id is more robust
127- ni = NSDInitiatives .objects .get (remote_id = remote_id )
128- setattr (ni , title_field , element .get ("InitiativeTitle" ))
129- setattr (ni , risk_field , element .get ("Risk" ))
130- ni .save (update_fields = [title_field , risk_field ])
131- except NSDInitiatives .DoesNotExist :
132- # Should not happen – only if EN entry is missing
133- ni = NSDInitiatives .objects .create (
134- remote_id = remote_id ,
135- ** defaults ,
136- )
137- added += 1
138- created_ns_initiatives_pk .append (ni .pk )
139- logger .warning (f"Created non-EN entry: { remote_id } / { lang } " )
140128
141- # Handle categories (language-aware)
142- raw_categories = element .get ("Categories" ) or []
143- if isinstance ( raw_categories , ( list , tuple )):
129+ # Establish baseline categories from EN by index
130+ raw_categories = element .get ("Categories" ) or []
131+ cats_en = []
144132 cat_objs = []
145- for c in raw_categories :
146- if not c :
147- continue
148- name = str (c ).strip ()
149- if not name :
150- continue
151- # Create / fetch category for this specific language
152- obj , _ = NSDInitiativesCategory .objects .get_or_create (
153- name = name ,
154- lang = lang ,
155- )
156- cat_objs .append (obj )
157-
158- if cat_objs :
159- ni .categories .add (* cat_objs )
133+ if isinstance (raw_categories , (list , tuple )):
134+ for idx , raw in enumerate (raw_categories ):
135+ label = (raw or "" ).strip ()
136+ if not label :
137+ cats_en .append (None )
138+ continue
139+ # Reuse/create a global category by English label
140+ cat = NSDInitiativesCategory .objects .filter (name_en__iexact = label ).first ()
141+ if not cat :
142+ cat = NSDInitiativesCategory .objects .create (name = label , name_en = label )
143+ else :
144+ # Ensure plain 'name' mirrors EN for convenience
145+ to_update = []
146+ if getattr (cat , "name_en" , None ) != label :
147+ cat .name_en = label
148+ to_update .append ("name_en" )
149+ if getattr (cat , "name" , None ) != label :
150+ cat .name = label
151+ to_update .append ("name" )
152+ if to_update :
153+ cat .save (update_fields = to_update )
154+ cats_en .append (cat )
155+ cat_objs .append (cat )
156+
157+ if cat_objs :
158+ ni .categories .set (cat_objs )
159+ else :
160+ ni .categories .clear ()
161+
162+ # Save baseline for this remote_id
163+ category_by_remote_index [remote_id ] = cats_en
164+
165+ # Apply any pending translations queued before EN
166+ for item in pending_translations .pop (remote_id , []):
167+ plang , pidx , plabel = item
168+ if 0 <= pidx < len (cats_en ) and cats_en [pidx ]:
169+ field = f"name_{ plang } "
170+ cat = cats_en [pidx ]
171+ if getattr (cat , field , None ) != plabel :
172+ setattr (cat , field , plabel )
173+ cat .save (update_fields = [field ])
174+ continue # Done with EN row; go next element
175+
176+ # Non-EN branch: update fields and queue/apply category translations
177+ try :
178+ ni = NSDInitiatives .objects .get (remote_id = remote_id )
179+ setattr (ni , title_field , element .get ("InitiativeTitle" ))
180+ setattr (ni , risk_field , element .get ("Risk" ))
181+ ni .save (update_fields = [title_field , risk_field ])
182+ except NSDInitiatives .DoesNotExist :
183+ # Should not happen – only if EN entry is missing
184+ ni = NSDInitiatives .objects .create (
185+ remote_id = remote_id ,
186+ ** defaults ,
187+ )
188+ added += 1
189+ created_ns_initiatives_pk .append (ni .pk )
190+ logger .warning (f"Created non-EN entry: { remote_id } / { lang } " )
191+
192+ # Align categories by index to the EN baseline for this remote_id
193+ raw_categories = element .get ("Categories" ) or []
194+ if not isinstance (raw_categories , (list , tuple )):
195+ continue
196+
197+ cats_en = category_by_remote_index .get (remote_id )
198+ if cats_en is None :
199+ # Baseline not processed yet; queue these translations
200+ q = pending_translations .setdefault (remote_id , [])
201+ for idx , raw in enumerate (raw_categories ):
202+ label = (raw or "" ).strip ()
203+ if label :
204+ q .append ((lang , idx , label ))
205+ continue
206+
207+ # Baseline exists: update translated fields by index
208+ field = f"name_{ lang } "
209+ for idx , raw in enumerate (raw_categories ):
210+ label = (raw or "" ).strip ()
211+ if not label or idx >= len (cats_en ):
212+ continue
213+ cat = cats_en [idx ]
214+ if not cat :
215+ continue
216+ if getattr (cat , field , None ) != label :
217+ setattr (cat , field , label )
218+ cat .save (update_fields = [field ])
160219
161220 # Remove old entries not present in the latest fetch
162221 NSDInitiatives .objects .exclude (id__in = created_ns_initiatives_pk ).delete ()
0 commit comments