Source code for flexicon.code.Lists.TranslationTypeOperations

#
#   TranslationTypeOperations.py
#
#   Class: TranslationTypeOperations
#          Translation type management operations for FieldWorks Language Explorer
#          projects via SIL Language and Culture Model (LCM) API.
#
#   Platform: Python.NET
#             FieldWorks Version 9+
#
#   Copyright 2025
#

# Import FLEx LCM types
from SIL.LCModel import (
    ITextRepository,
    IStTxtParaRepository,
)
from SIL.LCModel.Core.KernelInterfaces import ITsString
from SIL.LCModel.Core.Text import TsStringUtils
import System

# Import flexlibs exceptions
from ..FLExProject import FP_ParameterError
from ..BaseOperations import OperationsMethod
from .possibility_item_base import PossibilityItemOperations


[docs] class TranslationTypeOperations(PossibilityItemOperations): """ Translation type operations for managing translation categories. Translation types categorize different kinds of translations such as free translation (idiomatic), literal translation (word-for-word), and back translation (reverse translation for verification). Inherited CRUD Operations (from PossibilityItemOperations): - GetAll() - Get all translation types - Create() - Create new type - Delete() - Delete type - Duplicate() - Clone type - Find() - Find by name - Exists() - Check existence - GetName() / SetName() - Get/set name - GetDescription() / SetDescription() - Get/set description - GetGuid() - Get GUID - CompareTo() - Compare by name Domain-Specific Methods (TranslationTypeOperations): - GetAbbreviation() / SetAbbreviation() - Get/set abbreviation - GetAnalysisWS() / SetAnalysisWS() - Get/set analysis writing systems - GetTextsWithType() - Find texts using type - GetSegmentsWithType() - Find segments using type - GetFreeTranslationType() - Get predefined free type - GetLiteralTranslationType() - Get predefined literal type - GetBackTranslationType() - Get predefined back type - FindByWS() - Find by writing system - IsDefault() / SetDefault() - Check/set default status """ def __init__(self, project): """ Initialize TranslationTypeOperations with a FLExProject instance. Args: project: The FLExProject instance to operate on. """ super().__init__(project) def _get_item_class_name(self): """Get the item class name for error messages.""" return "TranslationType" def _get_list_object(self): """Get the translation types list container.""" return self.project.lp.TranslationTagsOA # --- Property Accessors --- @OperationsMethod def GetAbbreviation(self, type_or_hvo, wsHandle=None): """ Get the abbreviation of a translation type. Args: type_or_hvo: The ICmPossibility object or HVO. wsHandle: Optional writing system handle. Defaults to analysis WS. Returns: str: The translation type abbreviation, or empty string if not set. Raises: FP_NullParameterError: If type_or_hvo is None. Example: >>> free = project.TranslationTypes.GetFreeTranslationType() >>> abbr = project.TranslationTypes.GetAbbreviation(free) >>> print(abbr) fr >>> literal = project.TranslationTypes.GetLiteralTranslationType() >>> abbr = project.TranslationTypes.GetAbbreviation(literal) >>> print(abbr) lit See Also: SetAbbreviation, GetName """ self._ValidateParam(type_or_hvo, "type_or_hvo") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) wsHandle = self._PossibilityItemOperations__WSHandle(wsHandle) abbr = ITsString(trans_type.Abbreviation.get_String(wsHandle)).Text return abbr or "" @OperationsMethod def SetAbbreviation(self, type_or_hvo, abbreviation, wsHandle=None): """ Set the abbreviation of a translation type. Args: type_or_hvo: The ICmPossibility object or HVO. abbreviation (str): The new abbreviation. wsHandle: Optional writing system handle. Defaults to analysis WS. Raises: FP_ReadOnlyError: If the project is not opened with write enabled. FP_NullParameterError: If type_or_hvo or abbreviation is None. FP_ParameterError: If abbreviation is empty. Example: >>> custom = project.TranslationTypes.Find("Idiomatic Translation") >>> if custom: ... project.TranslationTypes.SetAbbreviation(custom, "Idio") Warning: - Avoid changing abbreviations for predefined types - Abbreviations should be short and distinctive - Only modify custom types you created See Also: GetAbbreviation, SetName """ self._EnsureWriteEnabled() self._ValidateParam(type_or_hvo, "type_or_hvo") self._ValidateParam(abbreviation, "abbreviation") if not abbreviation or not abbreviation.strip(): raise FP_ParameterError("Abbreviation cannot be empty") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) wsHandle = self._PossibilityItemOperations__WSHandle(wsHandle) mkstr = TsStringUtils.MakeString(abbreviation, wsHandle) trans_type.Abbreviation.set_String(wsHandle, mkstr) # --- Writing System Methods --- @OperationsMethod def GetAnalysisWS(self, type_or_hvo): """ Get the analysis writing systems used by a translation type. Returns the writing systems in which this translation type has translations defined. Args: type_or_hvo: The ICmPossibility object or HVO. Returns: list: List of writing system handles (integers) for which this type has content defined. Raises: FP_NullParameterError: If type_or_hvo is None. Example: >>> free = project.TranslationTypes.GetFreeTranslationType() >>> ws_list = project.TranslationTypes.GetAnalysisWS(free) >>> for ws_handle in ws_list: ... ws_obj = project.project.ServiceLocator.WritingSystemManager.Get(ws_handle) ... print(f"Writing system: {ws_obj.Id}") Writing system: en Notes: - Returns handles for writing systems, not WS objects - Translation types typically use analysis writing systems - Empty list means no specific WS associations See Also: SetAnalysisWS, GetName """ self._ValidateParam(type_or_hvo, "type_or_hvo") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) # Get all writing systems where this type has content ws_list = [] # Check name field for available writing systems if trans_type.Name: for ws in trans_type.Name.AvailableWritingSystemIds: if ws not in ws_list: ws_list.append(ws) return ws_list @OperationsMethod def SetAnalysisWS(self, type_or_hvo, wsHandle, name=None, abbreviation=None): """ Set the name and abbreviation for a translation type in a specific writing system. Args: type_or_hvo: The ICmPossibility object or HVO. wsHandle: Writing system handle to set content for. name (str, optional): Name in the specified writing system. If None, uses existing or empty. Defaults to None. abbreviation (str, optional): Abbreviation in the specified writing system. If None, uses existing or empty. Defaults to None. Raises: FP_ReadOnlyError: If the project is not opened with write enabled. FP_NullParameterError: If type_or_hvo or wsHandle is None. Example: >>> # Set French translations for a type >>> free = project.TranslationTypes.GetFreeTranslationType() >>> fr_ws = project.WSHandle('fr') >>> project.TranslationTypes.SetAnalysisWS( ... free, fr_ws, ... name="Traduction libre", ... abbreviation="tl") Notes: - Allows translation types to have names in multiple languages - If name or abbreviation is None, that field is not updated - Useful for multilingual projects See Also: GetAnalysisWS, GetName, SetName """ self._EnsureWriteEnabled() self._ValidateParam(type_or_hvo, "type_or_hvo") self._ValidateParam(wsHandle, "wsHandle") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) with self._TransactionCM("Set translation type writing system"): # Set name if provided if name is not None: mkstr_name = TsStringUtils.MakeString(name, wsHandle) trans_type.Name.set_String(wsHandle, mkstr_name) # Set abbreviation if provided if abbreviation is not None: mkstr_abbr = TsStringUtils.MakeString(abbreviation, wsHandle) trans_type.Abbreviation.set_String(wsHandle, mkstr_abbr) # --- Usage Tracking --- @OperationsMethod def GetTextsWithType(self, type_or_hvo): """ Get all texts that use a specific translation type. Searches through all texts in the project and returns those that reference this translation type in their translations. Args: type_or_hvo: The ICmPossibility object or HVO. Yields: IText: Each text object that uses this translation type. Raises: FP_NullParameterError: If type_or_hvo is None. Example: >>> free = project.TranslationTypes.GetFreeTranslationType() >>> texts = list(project.TranslationTypes.GetTextsWithType(free)) >>> print(f"{len(texts)} texts use free translation") 12 texts use free translation >>> for text in texts: ... name = text.Name.BestAnalysisAlternative.Text ... print(f" - {name}") Notes: - May be slow for large projects (scans all texts) - Useful for determining if a type is in use before deleting - Returns empty sequence if type is not used - Checks text-level translations, not segment-level See Also: GetSegmentsWithType, Delete """ self._ValidateParam(type_or_hvo, "type_or_hvo") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) type_guid = trans_type.Guid # Search all texts text_repo = self.project.project.ServiceLocator.GetInstance(ITextRepository) for text in text_repo.AllInstances(): # Check if text has translations using this type if hasattr(text, "TranslationsOC") and text.TranslationsOC: for translation in text.TranslationsOC: if hasattr(translation, "TypeRA") and translation.TypeRA: if translation.TypeRA.Guid == type_guid: yield text break # Count each text only once @OperationsMethod def GetSegmentsWithType(self, type_or_hvo): """ Get all segments that use a specific translation type. Searches through all segments in all texts and returns those that reference this translation type in their translations. Args: type_or_hvo: The ICmPossibility object or HVO. Yields: ISegment: Each segment object that uses this translation type. Raises: FP_NullParameterError: If type_or_hvo is None. Example: >>> literal = project.TranslationTypes.GetLiteralTranslationType() >>> segments = list(project.TranslationTypes.GetSegmentsWithType(literal)) >>> print(f"{len(segments)} segments use literal translation") 458 segments use literal translation Warning: - This operation can be very slow for large projects - Scans all paragraphs and segments in the entire project - Consider using GetTextsWithType() for faster overview Notes: - Returns empty sequence if type is not used - Useful for detailed usage analysis - Each segment is yielded only once See Also: GetTextsWithType, Delete """ self._ValidateParam(type_or_hvo, "type_or_hvo") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) type_guid = trans_type.Guid # Search all paragraphs and their segments para_repo = self.project.project.ServiceLocator.GetInstance(IStTxtParaRepository) for para in para_repo.AllInstances(): if hasattr(para, "SegmentsOS"): for segment in para.SegmentsOS: # Check segment translations # Note: Segments typically don't have typed translations # in the same way texts do, but we check for completeness if hasattr(segment, "FreeTranslation"): # Segments have FreeTranslation and LiteralTranslation # but these are typically not typed in the same way # This method is provided for API completeness pass # --- Predefined Translation Types --- @OperationsMethod def GetFreeTranslationType(self): """ Get the predefined "Free translation" type. Returns the standard free translation type that is present in all FLEx projects. Free translation represents idiomatic, natural language translation. Returns: ICmPossibility or None: The free translation type object, or None if not found. Example: >>> free = project.TranslationTypes.GetFreeTranslationType() >>> if free: ... name = project.TranslationTypes.GetName(free) ... abbr = project.TranslationTypes.GetAbbreviation(free) ... print(f"{name} ({abbr})") Free translation (fr) Notes: - This is a predefined type with GUID: eb92e50f-ba96-4d1d-b632-057b5c274132 - Should be present in all standard FLEx projects - Cannot be deleted - Default translation type for natural language translations See Also: GetLiteralTranslationType, GetBackTranslationType """ # Free translation GUID guid = System.Guid("eb92e50f-ba96-4d1d-b632-057b5c274132") for trans_type in self.GetAll(): if trans_type.Guid == guid: return trans_type return None @OperationsMethod def GetLiteralTranslationType(self): """ Get the predefined "Literal translation" type. Returns the standard literal translation type that is present in all FLEx projects. Literal translation represents word-for-word, morpheme-aligned translation. Returns: ICmPossibility or None: The literal translation type object, or None if not found. Example: >>> literal = project.TranslationTypes.GetLiteralTranslationType() >>> if literal: ... name = project.TranslationTypes.GetName(literal) ... abbr = project.TranslationTypes.GetAbbreviation(literal) ... print(f"{name} ({abbr})") Literal translation (lit) Notes: - This is a predefined type with GUID: c6e13529-97ed-4a8a-86f9-7b30b3b0b1c0 - Should be present in all standard FLEx projects - Cannot be deleted - Used for interlinear, word-for-word translations See Also: GetFreeTranslationType, GetBackTranslationType """ # Literal translation GUID guid = System.Guid("c6e13529-97ed-4a8a-86f9-7b30b3b0b1c0") for trans_type in self.GetAll(): if trans_type.Guid == guid: return trans_type return None @OperationsMethod def GetBackTranslationType(self): """ Get the predefined "Back translation" type. Returns the standard back translation type that is present in all FLEx projects. Back translation is a reverse translation from the target language back to the source language for verification purposes. Returns: ICmPossibility or None: The back translation type object, or None if not found. Example: >>> back = project.TranslationTypes.GetBackTranslationType() >>> if back: ... name = project.TranslationTypes.GetName(back) ... abbr = project.TranslationTypes.GetAbbreviation(back) ... print(f"{name} ({abbr})") Back translation (bt) Notes: - This is a predefined type with GUID: d7f713e4-e8cf-11d3-9764-00c04f186933 - Should be present in all standard FLEx projects - Cannot be deleted - Used for translation checking and verification See Also: GetFreeTranslationType, GetLiteralTranslationType """ # Back translation GUID guid = System.Guid("d7f713e4-e8cf-11d3-9764-00c04f186933") for trans_type in self.GetAll(): if trans_type.Guid == guid: return trans_type return None # --- Query Methods --- @OperationsMethod def FindByWS(self, wsHandle): """ Find all translation types that have content in a specific writing system. Args: wsHandle: Writing system handle to search for. Yields: ICmPossibility: Each translation type that has name or abbreviation defined in the specified writing system. Raises: FP_NullParameterError: If wsHandle is None. Example: >>> # Find types with English content >>> en_ws = project.WSHandle('en') >>> for trans_type in project.TranslationTypes.FindByWS(en_ws): ... name = project.TranslationTypes.GetName(trans_type, en_ws) ... print(name) Free translation Literal translation Back translation Notes: - Checks both name and abbreviation fields - Useful for finding types available in a specific language - Returns empty sequence if no types have content in that WS See Also: GetAnalysisWS, SetAnalysisWS """ self._ValidateParam(wsHandle, "wsHandle") for trans_type in self.GetAll(): # Check if this type has content in the specified WS if trans_type.Name: for ws in trans_type.Name.AvailableWritingSystemIds: if ws == wsHandle: yield trans_type break @OperationsMethod def IsDefault(self, type_or_hvo): """ Check if a translation type is one of the predefined default types. Args: type_or_hvo: The ICmPossibility object or HVO. Returns: bool: True if this is a predefined type (free, literal, or back), False if it's a custom type. Raises: FP_NullParameterError: If type_or_hvo is None. Example: >>> free = project.TranslationTypes.GetFreeTranslationType() >>> is_default = project.TranslationTypes.IsDefault(free) >>> print(f"Is default: {is_default}") Is default: True >>> custom = project.TranslationTypes.Find("Idiomatic") >>> if custom: ... is_default = project.TranslationTypes.IsDefault(custom) ... print(f"Is default: {is_default}") Is default: False Notes: - Predefined types cannot be deleted - Custom types can be deleted - Useful for distinguishing system vs. user-created types See Also: GetFreeTranslationType, Delete """ self._ValidateParam(type_or_hvo, "type_or_hvo") trans_type = self._PossibilityItemOperations__ResolveObject(type_or_hvo) guid = trans_type.Guid # Check against predefined GUIDs predefined_guids = [ System.Guid("eb92e50f-ba96-4d1d-b632-057b5c274132"), # Free System.Guid("c6e13529-97ed-4a8a-86f9-7b30b3b0b1c0"), # Literal System.Guid("d7f713e4-e8cf-11d3-9764-00c04f186933"), # Back ] return guid in predefined_guids @OperationsMethod def SetDefault(self, type_or_hvo): """ Set a translation type as the default for new translations. Note: This functionality may not be fully supported in all FLEx versions, as translation type defaults are often context-dependent. Args: type_or_hvo: The ICmPossibility object or HVO. Raises: FP_ReadOnlyError: If the project is not opened with write enabled. FP_NullParameterError: If type_or_hvo is None. FP_ParameterError: Feature not fully supported. Example: >>> # This method is provided for API completeness >>> # but may not have full functionality >>> free = project.TranslationTypes.GetFreeTranslationType() >>> # project.TranslationTypes.SetDefault(free) Warning: - This feature may not be fully implemented in FLEx - Translation type defaults are typically context-dependent - Consider this method as a placeholder for future enhancement Notes: - Translation types don't have a single "default" - Free translation is typically used by default for texts - Literal translation is typically used for interlinear - This method is provided for API consistency See Also: IsDefault, GetFreeTranslationType """ self._EnsureWriteEnabled() self._ValidateParam(type_or_hvo, "type_or_hvo") # Placeholder for potential future implementation # Translation type defaults are context-dependent pass