Service - Translations: Difference between revisions

From Izara Wiki
Jump to navigation Jump to search
No edit summary
 
(16 intermediate revisions by one other user not shown)
Line 1: Line 1:
= Overview =
= Overview =


Service manages translations in the service.
Service manages language translations.


= Repository =
= Repository =


https://bitbucket.org/stb_working/translations/src/master/
https://bitbucket.org/izara-core-shared/izara-core-shared-translations


= DynamoDB tables =
= Schemas =


== [[Standard Config Table Per Service]] ==
==ObjectSchemas==


=== Configuration tags ===
=== translationText ===


<syntaxhighlight lang="JavaScript">
<syntaxhighlight lang="JavaScript">
{
{
configKey: "TranslationsGraphServiceName"
  "objectType": "translationText",
configTag: "TranslationsGraphServiceName"
  "storageResources": {
configValue: xxx // eg: "TranslationsGraph"
    "graph": {
      "storageType": "graph",
      "graphServerTag": "GraphHandler"
    },
  },
  "addOnDataStructure": [],
  "fieldNames": {
    "translationTextId": {
      "storageResourceTags": [
        "graph"
      ]
    },
  },
identifiers: [
{
type: "identifier",
fieldName: "translationTextId"
}
],
  "generatedBy": "userGenerated"
}
}
</syntaxhighlight>
</syntaxhighlight>
* actual text used, identified by text so shared by all use cases
* both translationLink and systemTextTranslationLink connect to translation instances
=== translationLink ===


<syntaxhighlight lang="JavaScript">
<syntaxhighlight lang="JavaScript">
{
{
configKey: "GraphNodeLabelSuffix"
  "objectType": "translationLink",
configTag: "Translation"
  "storageResources": {
configValue: xxx // eg: "translation"
    "graph": {
      "storageType": "graph",
      "graphServerTag": "GraphHandler"
    },
    // probably has dynamo storage for flow status such as recalulate weight
  },
  "addOnDataStructure": [],
  "fieldNames": {
    "translationLinkId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "languageId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "textTag": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "weight": {
      "storageResourceTags": [
        "graph"
      ]
    }
  },
identifiers: [
{
type: "identifier",
fieldName: "translationLinkId"
}
],
  "generatedBy": "userGenerated"
}
}
</syntaxhighlight>
</syntaxhighlight>


* combines with subject label/s to create translation node label
=== systemTextTranslationLink ===


<syntaxhighlight lang="JavaScript">
<syntaxhighlight lang="JavaScript">
{
{
configKey: "GraphRelationshipTypeSuffix"
  "objectType": "systemTextTranslationLink",
configTag: "Translation"
  "storageResources": {
configValue: xxx // eg: "Translation"
    "graph": {
      "storageType": "graph",
      "graphServerTag": "GraphHandler"
    },
    // probably has dynamo storage for flow status such as recalulate weight
  },
  "addOnDataStructure": [],
  "fieldNames": {
    "systemTextTranslationLinkId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "languageId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "weight": {
      "storageResourceTags": [
        "graph"
      ]
    }
  },
identifiers: [
{
type: "identifier",
fieldName: "systemTextTranslationLinkId"
}
],
  "generatedBy": "userGenerated"
}
}
</syntaxhighlight>
</syntaxhighlight>


* combines with [[NPM module - izara-shared#constants]] ''has'' and ''current'' to create the various translation relationship types
== Relationships ==
* Uppercase so joins with other wording correctly
 
=== isTranslationText ===


= Graph database =
<syntaxhighlight lang="JavaScript">
{
isTranslationText: {
storageResources: {
myGraph: {
storageType: "graph",
graphServerTag: "GraphHandler"
}
},
links: [
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "Translations",
objectType: "translationLink"
},
linkType: "many",
},
to: {
objType: {
serviceTag: "Translations",
objectType: "TranslationText"
},
linkType: "one"
}
},
{
storageResourceTags: ["myGraph"],
from: {
objType: {
serviceTag: "Translations",
objectType: "SystemTextTranslationLink"
},
linkType: "many",
},
to: {
objType: {
serviceTag: "Translations",
objectType: "TranslationText"
},
linkType: "one"
}
},


== [[Service - Translations Graph]] ==
]
}
}
</syntaxhighlight>
 
 
= DynamoDB tables (delete) =


=== Nodes ===
== [[Standard Config Table Per Service]] ==


==== (subject nodes) ====
=== Configuration tags ===


* nodeIdentifierLabels: matches that specific object being translated, eg: catalogName
<syntaxhighlight lang="JavaScript">
* nodeUniqueIdProperties: up to the object and the service that manages it, not set by translation service
{
* nodeProperties: (not set by translation service)
configKey: "TranslationGraphServiceName"
configTag: "TranslationGraphServiceName"
configValue: xxx // eg: "TranslationGraph"
}
</syntaxhighlight>


==== translation ====
== LogicalResults ==


===== nodeIdentifierLabels =====
Stores results for any requests to perform logical searches on media links


Three labels for future query possibilities
<syntaxhighlight lang="JavaScript">
{
resultId: xxx // eg: filterMainId for a single logical element
dataId: xxx // one translationLinkId or one subject nodes identifier (the logical request will set what property should be used)
}
</syntaxhighlight>


# combine subject node label with languageCode and config table: configKey: "GraphNodeLabel", configTag: "translation"
* partition key: resultId
# combine subject node label with config table: configKey: "GraphNodeLabel", configTag: "translation"
* sort key: dataId
# configKey: "GraphNodeLabel", configTag: "translation"


===== nodeUniqueIdProperties =====
= Graph database (delete)  =  


Previously planned a unique translationId, but in neo4j feel the text+languageCode properties can be used as the unique id
== [[Service - Translations Graph]] ==


* text
* {textTag} is the name of the text being translated, eg a Catalog subject node will have a textTag "catalogName"
* languageCode


===== nodeProperties =====
=== Nodes ===


* text - the text of the translation
<syntaxhighlight lang="JavaScript">
* language - language code
{
nodeLabel: "{TranslationSharedLib.translationLinkNodeLabel()}", //eg: translationLink
schema: {
identifier: true,
restrictProperties: true,
restrictRelationships: true,
properties: {
translationLinkId: {
identifier: true, // create unique id from request details
}
languageId: {
immutable: true,
}
textTag: {
immutable: true, // tag of what text is being translated
}
weight: {
}
},
}
}
</syntaxhighlight>
* creates a link between a subject node and a translation text
* when recalculating current translation for a languageCode we add the calculated weighted value to this node as a property


=== Relationships ===
<syntaxhighlight lang="JavaScript">
{
nodeLabel: {TranslationSharedLib.TRANSLATION_GRAPH_NODE_LABEL}, //eg: translation
schema: {
identifier: true,
restrictProperties: true,
restrictRelationships: true,
properties: {
text: {
identifier: true,
},
},
}
}
</syntaxhighlight>


==== has{translation} ====
==== (subject nodes) ====


* All possible translations are linked to their subjectId with a relationship of this type
Subject node schemas are managed by each service that needs translations, normally as a basic schema with identifier properties only.
* This relationship is never removed


==== has{languageCode}{translation} ====
* nodeIdentifierLabels: matches that specific object being translated, eg: catalog
* nodeIdentifierProperties: matches that specific object being translated, eg: catalogId
* nodeProperties: Can store additional properties, not set by translation service
* node schema should set identifier = true, immutable = true (which includes elementCanBeRemoved = false)


* All possible translations for each languageCode are linked to their subjectId with a relationship of this type
=== Relationships ===
* When recalculating current translation for a languageCode for each has..translation relationship we add the calculated weighted value to this relationship
* This relationship is never removed, but those with low weights can be ignored over time


==== current{languageCode}{translation} ====
<syntaxhighlight lang="JavaScript">
{
relationshipType: "{TranslationSharedLib.translationLinkHasRelType()", // eg: has_translationLink
schema: {
immutable: true,
restrictProperties: true,
properties: {
originTimestamp: //timestamp the request to create/change this relationship was sent
},
}
}
</syntaxhighlight>
* every translationLink will have this relationship
* is never removed, but those with low weighted links can be ignored over time


* Matches one translation as the currently used translation for one languageCode
<syntaxhighlight lang="JavaScript">
* Only one should exist per subject node per languageCode
{
* Languages that have no translations will not have one
relationshipType: "{TranslationSharedLib.translationLinkCurrentRelType()}", // eg: current_translationLink
* Can be removed and replaced when RecalculateCurrentTranslation
schema: {
elementCanBeRemoved: true,
restrictProperties: true,
properties: {
originTimestamp: //timestamp the request to create/change this relationship was sent
},
}
}
</syntaxhighlight>
* the currently used translationLink for the language the link points to
* only one should exist per subject node and textTag/languageCode combination, but each language for each textTag will have it's own current relationship
* this relationship will not exist for languages that have no translations
* can be removed/added when RecalculateCurrentTranslation


==== default{translation} ====
<syntaxhighlight lang="JavaScript">
{
relationshipType: "{TranslationSharedLib.translationLinkDefaultRelType()}", // eg: default_translationLink
schema: {
elementCanBeRemoved: true,
restrictProperties: true,
properties: {
originTimestamp: //timestamp the request to create/change this relationship was sent
},
}
}
</syntaxhighlight>
* sets the default translationLink to use when no translationLink for the requested language/s exist
* can be changed but each subject/textTag must have 1
* initially set to the first translation created, later can move it around eg to English if English gets added later
* could create logic that goes through a sorted list of languages and applies the first languageCode found as the default
 
<syntaxhighlight lang="JavaScript">
{
relationshipType: "{TranslationSharedLib.isTranslationDefaultRelType()}",
schema: {
elementCanBeRemoved: false,
allPropertiesImmutable: true,
restrictProperties: true,
properties: {
originTimestamp: //timestamp the request to create/change this relationship was sent
},
}
}
</syntaxhighlight>
 
= Complex Filter requests =


* Used when no desired languageCode translation exists
<syntaxhighlight lang="JavaScript">
* Initially set to the first translation created, later can move it around eg to English if English gets added later
{
* Only one should exist per subject node
filterType: "XXX" // up to calling service
* Can create admin logic that goes through a sorted list of languages and applies the first languageCode found as the default
type: "group",
elements:
[
{
type: "logical",
logicalTag: "textTag_languageId_text",
resultType: "mediaLinkProperty"
textTag: "mediaLinkPropertyValue",
languageId: "en",
text: "Blue",
subjectIdentifierPropertyName: "propertyId",
caseSensitive: true
},
]
}
</syntaxhighlight>
- searches for specific and full text, optional case sensitive
- finds an identifier property on the subjects node and stores in LogicalResults for the request
- resultType must exist in request because want it to match filterType and Translation has no way of knowing filterType of request


= SQS queues =
= SQS queues =
Line 107: Line 364:
== RecalculateCurrentTranslation ==
== RecalculateCurrentTranslation ==


Add to this queue the subject nodeIdentifierLabels, subject nodeUniqueIdProperties, languageCode
Add to this queue the subject nodeIdentifierLabels, subject nodeIdentifierProperties, languageCode


* subject nodeIdentifierLabels: Label/s for the entity being translated, eg: ''categoryName''
* subject nodeIdentifierLabels
* subject nodeUniqueIdProperties: used to find the specific subject node
* subject nodeIdentifierProperties
* languageCode: see below
* languageCode: see below



Latest revision as of 07:14, 16 January 2026

Overview

Service manages language translations.

Repository

https://bitbucket.org/izara-core-shared/izara-core-shared-translations

Schemas

ObjectSchemas

translationText

{
  "objectType": "translationText",
  "storageResources": {
    "graph": {
      "storageType": "graph",
      "graphServerTag": "GraphHandler"
    },
  },
  "addOnDataStructure": [],
  "fieldNames": {
    "translationTextId": {
      "storageResourceTags": [
        "graph"
      ]
    },
  },
	identifiers: [
		{
			type: "identifier",
			fieldName: "translationTextId"
		}
	],
  "generatedBy": "userGenerated"
}
  • actual text used, identified by text so shared by all use cases
  • both translationLink and systemTextTranslationLink connect to translation instances

translationLink

{
  "objectType": "translationLink",
  "storageResources": {
    "graph": {
      "storageType": "graph",
      "graphServerTag": "GraphHandler"
    },
    // probably has dynamo storage for flow status such as recalulate weight
  },
  "addOnDataStructure": [],
  "fieldNames": {
    "translationLinkId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "languageId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "textTag": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "weight": {
      "storageResourceTags": [
        "graph"
      ]
    }
  },
	identifiers: [
		{
			type: "identifier",
			fieldName: "translationLinkId"
		}
	],
  "generatedBy": "userGenerated"
}

systemTextTranslationLink

{
  "objectType": "systemTextTranslationLink",
  "storageResources": {
    "graph": {
      "storageType": "graph",
      "graphServerTag": "GraphHandler"
    },
    // probably has dynamo storage for flow status such as recalulate weight
  },
  "addOnDataStructure": [],
  "fieldNames": {
    "systemTextTranslationLinkId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "languageId": {
      "storageResourceTags": [
        "graph"
      ]
    },
    "weight": {
      "storageResourceTags": [
        "graph"
      ]
    }
  },
	identifiers: [
		{
			type: "identifier",
			fieldName: "systemTextTranslationLinkId"
		}
	],
  "generatedBy": "userGenerated"
}

Relationships

isTranslationText

{
	isTranslationText: {
		storageResources: {
			myGraph: {
				storageType: "graph",
				graphServerTag: "GraphHandler"			
			}
		},
		links: [
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "Translations",
						objectType: "translationLink"
					},
					linkType: "many",
				},
				to: {
					objType: {
						serviceTag: "Translations",
						objectType: "TranslationText"
					},
					linkType: "one"
				}
			},
			{
				storageResourceTags: ["myGraph"],
				from: {
					objType: {
						serviceTag: "Translations",
						objectType: "SystemTextTranslationLink"
					},
					linkType: "many",
				},
				to: {
					objType: {
						serviceTag: "Translations",
						objectType: "TranslationText"
					},
					linkType: "one"
				}
			},

		]
	}
}


DynamoDB tables (delete)

Standard Config Table Per Service

Configuration tags

{
	configKey: "TranslationGraphServiceName"
	configTag: "TranslationGraphServiceName"
	configValue: xxx // eg: "TranslationGraph"
}

LogicalResults

Stores results for any requests to perform logical searches on media links

{
	resultId: xxx // eg: filterMainId for a single logical element
	dataId: xxx // one translationLinkId or one subject nodes identifier (the logical request will set what property should be used)
}
  • partition key: resultId
  • sort key: dataId

Graph database (delete)

Service - Translations Graph

  • {textTag} is the name of the text being translated, eg a Catalog subject node will have a textTag "catalogName"

Nodes

{
	nodeLabel: "{TranslationSharedLib.translationLinkNodeLabel()}", //eg: translationLink
	schema: {
		identifier: true,
		restrictProperties: true,
		restrictRelationships: true,
		properties: {
			translationLinkId: {
				identifier: true, // create unique id from request details
			}
			languageId: {
				immutable: true,
			}
			textTag: {
				immutable: true, // tag of what text is being translated
			}
			weight: {
			}
		},
	}
}
  • creates a link between a subject node and a translation text
  • when recalculating current translation for a languageCode we add the calculated weighted value to this node as a property
{
	nodeLabel: {TranslationSharedLib.TRANSLATION_GRAPH_NODE_LABEL}, //eg: translation
	schema: {
		identifier: true,
		restrictProperties: true,
		restrictRelationships: true,
		properties: {
			text: {
				identifier: true,
			},
		},
	}
}

(subject nodes)

Subject node schemas are managed by each service that needs translations, normally as a basic schema with identifier properties only.

  • nodeIdentifierLabels: matches that specific object being translated, eg: catalog
  • nodeIdentifierProperties: matches that specific object being translated, eg: catalogId
  • nodeProperties: Can store additional properties, not set by translation service
  • node schema should set identifier = true, immutable = true (which includes elementCanBeRemoved = false)

Relationships

{
	relationshipType: "{TranslationSharedLib.translationLinkHasRelType()", // eg: has_translationLink
	schema: {
		immutable: true,
		restrictProperties: true,
		properties: {
			originTimestamp: //timestamp the request to create/change this relationship was sent
		},
	}
}
  • every translationLink will have this relationship
  • is never removed, but those with low weighted links can be ignored over time
{
	relationshipType: "{TranslationSharedLib.translationLinkCurrentRelType()}", // eg: current_translationLink
	schema: {
		elementCanBeRemoved: true,
		restrictProperties: true,
		properties: {
			originTimestamp: //timestamp the request to create/change this relationship was sent
		},
	}
}
  • the currently used translationLink for the language the link points to
  • only one should exist per subject node and textTag/languageCode combination, but each language for each textTag will have it's own current relationship
  • this relationship will not exist for languages that have no translations
  • can be removed/added when RecalculateCurrentTranslation
{
	relationshipType: "{TranslationSharedLib.translationLinkDefaultRelType()}", // eg: default_translationLink
	schema: {
		elementCanBeRemoved: true,
		restrictProperties: true,
		properties: {
			originTimestamp: //timestamp the request to create/change this relationship was sent
		},
	}
}
  • sets the default translationLink to use when no translationLink for the requested language/s exist
  • can be changed but each subject/textTag must have 1
  • initially set to the first translation created, later can move it around eg to English if English gets added later
  • could create logic that goes through a sorted list of languages and applies the first languageCode found as the default
{
	relationshipType: "{TranslationSharedLib.isTranslationDefaultRelType()}",
	schema: {
		elementCanBeRemoved: false,
		allPropertiesImmutable: true,
		restrictProperties: true,
		properties: {
			originTimestamp: //timestamp the request to create/change this relationship was sent
		},
	}
}

Complex Filter requests

{
	filterType: "XXX" // up to calling service
	type: "group",
	elements: 
	[
		{
			type: "logical",
			logicalTag: "textTag_languageId_text",
			resultType: "mediaLinkProperty"
			textTag: "mediaLinkPropertyValue",
			languageId: "en",
			text: "Blue",
			subjectIdentifierPropertyName: "propertyId",
			caseSensitive: true
		},
	]
}

- searches for specific and full text, optional case sensitive - finds an identifier property on the subjects node and stores in LogicalResults for the request - resultType must exist in request because want it to match filterType and Translation has no way of knowing filterType of request

SQS queues

RecalculateCurrentTranslation

Add to this queue the subject nodeIdentifierLabels, subject nodeIdentifierProperties, languageCode

  • subject nodeIdentifierLabels
  • subject nodeIdentifierProperties
  • languageCode: see below

This queue does not have a Lambda trigger, we could poll it when resource costs really cheap as it is low importance (and/or have an API endpoint that polls and processes a batch).

Language codes

Considering using ISO 639-3 codes and designing a way to substring them to automatically go up the hierarchy if no lower level variants match, an alternative would be to allow users to create ordered lists of preferred translations and share these.

How translations are found for users

Plan is to allow users to create ordered lists of prefered languages (and perhaps optionally automatic translating as a last option?), and new users are automatically set to a list depending on their location when signing up.

For each text to translate: work through the list and find the first matching translation, if none found fall back onto the default option.

cache results for efficient resource use.

System text translations

System text follows the same Label + UniqueIdProperty system to identify specific translation subjects (one system text output), the labels and unique ids can set in npm modules.

  • Label example: hard coded or as a constant in NavBar service: "sysTxtNavBar"
  • UniqueIdProperty example: "sysTxtTag", value: "SignOut" (can set as a constant in NavBar service)

Working documents

Working_documents - Translations