SetupTranslationsTable

Manages the translations ListObject of a setup workbook, together with the helper tag column that sits beside it. UpdateFromRegistry reads the watched ranges of the update registry and writes one row per label. EnsureLanguages creates the language columns, SwitchDefaultLanguage promotes one of them, SwitchableLanguages and Languages list what is there, and ResetSequence puts the row counter back. MissingLabels, NumberOfMissing, DuplicateLabels and UnresolvedRanges report on the table, and Export writes it into another workbook.

LABEL MATCHING POLICY

A label carries its case. "Hello" and "hello" are two labels, they take two rows, and each one stands for itself. FindLabelRow, DeduplicateLabels and ComputeDuplicateSummary all answer from one keyed Collection built by LabelKey, and that key spells the capitalisation out so two spellings never share it. A Collection matches its own keys without regard to case, so the case travels inside the key. TranslationObject.LookupRow reads this table at run time and compares with vbBinaryCompare.

Column titles, registry status words, mode keywords and defined-name lookups are matched without regard to case. Excel matches defined names that way itself.

DUPLICATES ARE COLOURED BY GROUP

ApplyFormatting gives every duplicate group in a column a fill of its own, walked off the hue wheel by DuplicateGroupColor. A column painted in one colour says which cells are duplicated and nothing about which of them go together, and a translator staring at forty red cells has to read every one to find the pairs. One rule per group answers both questions at a glance.

CollectDuplicateGroups finds the groups, and the summary message reads its groups from the same function, so the sheet and the message never disagree. The rules are EXACT tests, which is what carries the capitalisation through to the sheet: "Hello" and "hello" are two labels here and neither takes the colour of the other.

The red rule that used to paint every duplicate is still there, added last so it holds the lowest priority. It now marks a duplicate this class could not group: one past the end of the palette, one whose label is too long for a rule formula, or one whose formula Excel refused.

THE HELPER TAG COLUMN

The translations ListObject sits with one spare worksheet column to its left holding a tag per row, shaped __. That column lives outside the ListObject most of the time. During an update the table is resized one column left so each tag travels with its row through the sort, then resized back. LabelColumnIndex() answers 2 while the tag column is inside the table and 1 otherwise, and every column index in this class comes from that one function.

CREATE WRITES NOTHING

Create locates and checks the helper column. The title, the formatting and the hidden language list are written by the update path alone, through EnsureTagColumnReady and EnsureLanguages, so a manager can be built over a protected sheet and read from.

SOURCE RANGES ARE CONTIGUOUS

A registry range refers to one block of cells on one worksheet. SetupPreparation and UpdatedValues both build their names over a single table column. ProcessTextRange and ProcessFormulaRange read each source in one crossing, and Range.Value2 answers for the first area of a range, so a name built by hand over scattered cells brings in its first block alone.

ERROR NUMBERS

ProjectError.ErrorUnexpectedState is 1004, which is also Excel's generic error number. An Excel 1004 that escapes an update is raised again as 1004, so a caller reading the number alone sees one value for both.

Factory helpers

Create #

create

Create a configured translations table manager instance.

Signature:

Public Function Create(ByVal translationTable As ListObject, Optional ByVal stateScope As ApplicationState = Nothing) As SetupTranslationsTable

Parameters:

  • translationTable: ListObject. The managed translations table.
  • stateScope: Optional ApplicationState. Guard for Excel settings during updates.

Returns: SetupTranslationsTable. Ready to process registry updates.


Public configuration

LanguagesNameId #

languages-name-id

The HiddenName key of the persisted language list.

Signature:

Public Property Get LanguagesNameId() As String

Name of the worksheet-level HiddenName this class writes the semicolon separated language list under on its Translations sheet. The designer reads the list back through this key when a setup file is loaded, so the key lives here, on the class that writes it. The answer is a constant, so the property works on the predeclared instance.

Returns: String. The HiddenName identifier.


Tag column infrastructure

DuplicateGroupColor #

duplicate-group-color

Colour for the nth duplicate group.

Signature:

Public Function DuplicateGroupColor(ByVal groupIndex As Long) As Long

The hue walks the wheel in strides of DUPLICATE_HUE_STRIDE. The stride and the hue count share no factor, so every hue is still reached, and two groups that follow each other land most of a wheel apart rather than one step apart. Each further lap of the wheel drops the lightness by one band. Past the palette the index wraps, so two groups do share a colour there; HighlightDuplicateGroups stops before that happens and leaves the rest to the red catch-all.

Parameters:

  • groupIndex: Long. Zero based position of the group.

Returns: Long. An RGB value ready for Interior.Color.


Internal members (not exported)

Factory helpers

InitialiseCore #

initialise-core

Store the supplied table and optional scope inside the current instance.

Signature:

Public Sub InitialiseCore(ByVal translationTable As ListObject, Optional ByVal stateScope As ApplicationState = Nothing)

Public configuration

HostWorksheet #

host-worksheet

Worksheet hosting the translations table.

Signature:

Public Property Get HostWorksheet() As Worksheet

TableName #

table-name

Name of the managed translations ListObject.

Signature:

Public Property Get TableName() As String

SetDisplayPrompts #

set-display-prompts

Allow callers to toggle display prompts used during updates.

Signature:

Public Sub SetDisplayPrompts(ByVal state As Boolean)

ResolveScope #

resolve-scope

Guarded access to the application scope.

Signature:

Private Function ResolveScope() As ApplicationState

Language management

EnsureLanguages #

ensure-languages

Ensure all provided languages exist as table headers.

Signature:

Public Sub EnsureLanguages(Optional ByVal lang As String = vbNullString)

TryGetWrittenLanguages #

try-get-written-languages

Collect language names written to the right of the table.

Signature:

Private Function TryGetWrittenLanguages(ByRef languages As String, ByRef typedCells As Range, ByVal newLang As String) As Boolean

Parameters:


EnsureLanguageColumn #

ensure-language-column

Create the language column when it does not exist.

Signature:

Private Sub EnsureLanguageColumn(ByVal languageName As String)

PersistLanguageList #

persist-language-list

Persist the available languages into the worksheet hidden names.

Signature:

Private Sub PersistLanguageList()

SwitchDefaultLanguage #

switch-default-language

Promote the requested language column to become the primary language.

Signature:

Public Sub SwitchDefaultLanguage(ByVal languageName As String)

SwitchableLanguages #

switchable-languages

Retrieve the available languages excluding the default column.

Signature:

Public Function SwitchableLanguages() As BetterArray

Languages #

languages

Languages available for translation excluding the default column unless requested.

Signature:

Public Property Get Languages(Optional ByVal includeDefault As Boolean = False) As BetterArray

Language utilities

DefaultLanguageHeader #

default-language-header

Resolve the current default language header.

Signature:

Private Function DefaultLanguageHeader() As String

LanguageColumnIndex #

language-column-index

Resolve the column index for a provided language header.

Signature:

Private Function LanguageColumnIndex(ByVal languageName As String) As Long

ResolveLanguageColumn #

resolve-language-column

Resolve the data body range for a given language column.

Signature:

Private Function ResolveLanguageColumn(ByVal languageName As String) As Range

SwapLanguageColumns #

swap-language-columns

Swap the headers and the data between two language columns.

Signature:

Private Sub SwapLanguageColumns(ByVal firstIndex As Long, ByVal secondIndex As Long)

The data body of each column is read and written as one block, so a swap costs four Excel crossings whatever the row count. Number formats stay where they are: translation columns hold text. The translations table carries no totals row, so nothing here handles one.


UniqueTemporaryHeader #

unique-temporary-header

Generate a temporary header that does not collide with existing columns.

Signature:

Private Function UniqueTemporaryHeader() As String

Registry processing

ResetSequence #

reset-sequence

Reset the hidden update sequence counter to zero.

Signature:

Public Sub ResetSequence(ByVal registrySheet As Worksheet)

UpdateFromRegistry #

update-from-registry

Update the translations table using the supplied registry sheet.

Signature:

Public Sub UpdateFromRegistry(ByVal registrySheet As Worksheet, _
                             Optional ByVal languages As String = vbNullString)

The sequence counter is written after the rows settle. A run that fails halfway leaves the counter where it was, so the retry works at the same sequence and the rows the failed run tagged survive.


ProcessRegistry #

process-registry

Iterate all registry tables and process each watcher row.

Signature:

Private Sub ProcessRegistry(ByVal registrySheet As Worksheet, ByVal updateSequence As Long)

ProcessRegistryTable #

process-registry-table

Process a single registry ListObject.

Signature:

Private Sub ProcessRegistryTable(ByVal registryTable As ListObject, ByVal updateSequence As Long)

RegistryColumn #

registry-column

Resolve a registry column by header name, falling back to its published position.

Signature:

Private Function RegistryColumn(ByVal registryTable As ListObject, _
                                ByVal headerName As String, _
                                ByVal fallbackColumn As Long) As Long

RegistryColumnByHeader #

registry-column-by-header

Find a registry column by header name, answering 0 when the header is absent.

Signature:

Private Function RegistryColumnByHeader(ByVal registryTable As ListObject, _
                                        ByVal headerName As String) As Long

ThrowRegistryShape #

throw-registry-shape

Report a registry table that carries too few columns.

Signature:

Private Sub ThrowRegistryShape(ByVal registryTable As ListObject, ByVal columnCount As Long)

ShouldProcessRange #

should-process-range

Determine whether the named range should be processed this cycle.

Signature:

Private Function ShouldProcessRange(ByVal status As String, ByVal updateSequence As Long) As Boolean

ProcessSourceRange #

process-source-range

Dispatch processing based on the requested translation mode.

Signature:

Private Sub ProcessSourceRange(ByVal sourceRange As Range, ByVal rngTag As String, ByVal mode As String)

The mode is lowered and trimmed once, and every branch reads that one value. A watched range and a blank mode both carry no labels, so both are skipped without a word.


ProcessTextRange #

process-text-range

Add literal cell values to the translations table.

Signature:

Private Sub ProcessTextRange(ByVal sourceRange As Range, ByVal rngTag As String)

ProcessFormulaRange #

process-formula-range

Extract quoted portions of formulas and add them as chunks.

Signature:

Private Sub ProcessFormulaRange(ByVal sourceRange As Range, ByVal rngTag As String)

AddTokens #

add-tokens

Add every extracted formula token as a chunk.

Signature:

Private Sub AddTokens(ByVal tokens As BetterArray, ByVal rngTag As String)

EffectiveSourceRange #

effective-source-range

Narrow a source range to the part of the sheet that holds data.

Signature:

Private Function EffectiveSourceRange(ByVal sourceRange As Range) As Range

A defined name over a whole column answers with a 1,048,576 row array. The intersection with the used range keeps the read small.


ExtractFormulaChunks #

extract-formula-chunks

Extract quoted text segments from a formula while handling escaped quotes.

Signature:

Private Function ExtractFormulaChunks(ByVal formulaText As String) As BetterArray

The walk jumps from quote to quote with InStr, so the cost is one call per quote. Escaped double quotes are stripped first, which is what makes IF(A1="", ...) skip its empty comparison string.


Chunk management

AddChunk #

add-chunk

Add or update a translation chunk in the table.

Signature:

Private Sub AddChunk(ByVal label As String, ByVal rngTag As String)

AppendRow #

append-row

Record a new label in memory, to be written to the sheet in one batch.

Signature:

Private Sub AppendRow(ByVal label As String, ByVal rngTag As String)

FlushPendingRows #

flush-pending-rows

Grow the table once and write every new label in one block.

Signature:

Private Sub FlushPendingRows()

GrowTableRows #

grow-table-rows

Extend the managed table by the requested number of rows in one call.

Signature:

Private Sub GrowTableRows(ByVal extraRows As Long)

EnsureLabelCapacity #

ensure-label-capacity

Grow the label buffer geometrically so appends stay linear.

Signature:

Private Sub EnsureLabelCapacity(ByVal wanted As Long)

EnsureTagCapacity #

ensure-tag-capacity

Grow the tag buffer geometrically so appends stay linear.

Signature:

Private Sub EnsureTagCapacity(ByVal wanted As Long)

Label buffer

InitLabelBuffer #

init-label-buffer

Read the label column into a buffer and build the lookup for the cycle.

Signature:

Private Sub InitLabelBuffer()

LabelKey #

label-key

Build the lookup key for a label, one key per spelling.

Signature:

Private Function LabelKey(ByVal label As String) As String

The leading character keeps a numeric label legal as a Collection key. The trailing signature is what makes two spellings different keys: a Collection matches its own keys without regard to case, so dropping the label in on its own would fold "Hello" onto "hello" no matter how it was cased here.


CaseSignature #

case-signature

Spell a label's capitalisation out in digits.

Signature:

Private Function CaseSignature(ByVal label As String) As String

Digits carry no case of their own, so a Collection holds this part of the key exactly as written. A character reads 1 when it differs from its own lower case, which is the whole of what a case-insensitive comparison throws away.


RegisterLabelKey #

register-label-key

Record the row a label sits on, keeping the first row when the same spelling repeats.

Signature:

Private Sub RegisterLabelKey(ByVal label As String, ByVal rowIndex As Long)

FindLabelRow #

find-label-row

Find the row index for a label through the keyed lookup.

Signature:

Private Function FindLabelRow(ByVal label As String) As Long

LabelAt #

label-at

Read a label out of the in-memory buffer.

Signature:

Private Function LabelAt(ByVal rowIndex As Long) As String

Tag buffer

InitTagBuffer #

init-tag-buffer

Read the tag column into a buffer for batch writes.

Signature:

Private Sub InitTagBuffer()

A row that carries a label and no tag is given the manual tag. It was never claimed by a watched range, so it must survive the update.


FlushTagBuffer #

flush-tag-buffer

Write the accumulated tag buffer back to the tag column in one operation.

Signature:

Private Sub FlushTagBuffer()

ReleaseUpdateBuffers #

release-update-buffers

Drop the per-cycle buffers so a large table leaves no memory behind.

Signature:

Private Sub ReleaseUpdateBuffers()

Process tracking

TrackProcessedRange #

track-processed-range

Track the ranges processed during the current registry cycle.

Signature:

Private Sub TrackProcessedRange(ByVal rngName As String)

TrackUnresolvedRange #

track-unresolved-range

Record a registry range whose defined name could not be resolved.

Signature:

Private Sub TrackUnresolvedRange(ByVal rngName As String)

WasRangeProcessed #

was-range-processed

Determine whether a registry range was processed during the active cycle.

Signature:

Private Function WasRangeProcessed(ByVal rngName As String) As Boolean

ResetProcessedRanges #

reset-processed-ranges

Reset processed ranges tracking.

Signature:

Private Sub ResetProcessedRanges()

UnresolvedRanges #

unresolved-ranges

Registry ranges that failed to resolve during the last update.

Signature:

Public Property Get UnresolvedRanges() As BetterArray

RemoveObsoleteLabels #

remove-obsolete-labels

Remove labels whose source ranges were processed but whose tags are stale.

Signature:

Private Sub RemoveObsoleteLabels(ByVal updateSequence As Long)

A row that carries a label and no tag stays. Only a row with neither a label nor a tag is dropped, and that is the blank row a ListObject keeps when it holds no data.


DeduplicateLabels #

deduplicate-labels

Remove duplicate labels keeping the row with the oldest (lowest) tag sequence.

Signature:

Private Sub DeduplicateLabels()

DeleteRowsByIndex #

delete-rows-by-index

Delete the listed table rows, batching them into one Excel call each.

Signature:

Private Sub DeleteRowsByIndex(ByRef indices() As Long, ByVal count As Long)

The indices are sorted downward so a flushed batch leaves the remaining indices valid. Union slows down past a few thousand areas, so the batch is capped.


SortIndicesDescending #

sort-indices-descending

Sort a 1-based Long array in descending order (simple insertion sort).

Signature:

Private Sub SortIndicesDescending(ByRef arr() As Long, ByVal count As Long)

ParseTag #

parse-tag

Parse helper tag text into its components.

Signature:

Private Function ParseTag(ByVal tagText As String, ByRef rangeName As String, ByRef sequenceValue As Long) As Boolean

The split happens at the LAST separator, so a range name that itself carries the separator still yields its sequence number.


CreateBuffer #

create-buffer

Create a BetterArray buffer with deterministic bounds.

Signature:

Private Function CreateBuffer() As BetterArray

BuildDuplicateLine #

build-duplicate-line

Format a single duplicate-count line for reporting.

Signature:

Private Function BuildDuplicateLine(ByVal labelValue As String, ByVal occurrenceCount As Long) As String

Reporting

MissingLabels #

missing-labels

Count missing translation labels for a specific language.

Signature:

Public Function MissingLabels(ByVal lang As String) As Long

NumberOfMissing #

number-of-missing

Summarise missing translations per language and optionally prompt the user.

Signature:

Public Function NumberOfMissing() As String

AppendUnresolvedLine #

append-unresolved-line

Name the registry ranges that could not be resolved during the update.

Signature:

Private Sub AppendUnresolvedLine(ByVal messageLines As BetterArray)

UpdateMissingSummary #

update-missing-summary

Update internal missing summary.

Signature:

Private Sub UpdateMissingSummary(ByVal summary As BetterArray)

InternalMissingSummary #

internal-missing-summary

Cached missing-labels summary across languages.

Signature:

Public Property Get InternalMissingSummary() As BetterArray

UpdateDuplicatesSummary #

update-duplicates-summary

Build duplicate summary for every language column.

Signature:

Private Sub UpdateDuplicatesSummary()

InternalDuplicatesSummary #

internal-duplicates-summary

Cached duplicates summary across languages.

Signature:

Public Property Get InternalDuplicatesSummary() As BetterArray

DuplicateLabels #

duplicate-labels

Report duplicate translation labels when they exist.

Signature:

Public Function DuplicateLabels(ByRef duplicateMessage As String, Optional ByVal languageName As String = vbNullString) As Boolean

ComputeDuplicateSummary #

compute-duplicate-summary

Count duplicates for one language or for the label column.

Signature:

Private Function ComputeDuplicateSummary(ByVal languageName As String) As TDuplicateSummary

Every label is counted through one keyed Collection, so the cost is linear in the row count. Two spellings of the same word are two labels here, so neither is reported as a duplicate of the other.


CollectDuplicateGroups #

collect-duplicate-groups

Find every value a column holds more than once, in first-appearance order.

Signature:

Private Function CollectDuplicateGroups(ByVal targetRange As Range, _
                                        ByRef groupLabels() As String, _

One keyed Collection carries the whole count, so the cost is linear in the row count. The key comes from LabelKey and spells the capitalisation out, so "Hello" and "hello" are counted apart and neither is a duplicate of the other. Both the summary message and the sheet colouring read their groups from here, which is what keeps the two of them saying the same thing.

Parameters:

Returns: Long. Number of duplicate groups found.


LabelColumnData #

label-column-data

Access the label column data range.

Signature:

Private Function LabelColumnData() As Range

ColumnBlock #

column-block

Read a one column range in a single crossing.

Signature:

Private Function ColumnBlock(ByVal source As Range) As Variant

BlockText #

block-text

Read one row out of a column block as text.

Signature:

Private Function BlockText(ByVal block As Variant, ByVal rowIndex As Long) As String

SafeText #

safe-text

Turn a sheet value into text, answering empty for an error or a Null.

Signature:

Private Function SafeText(ByVal candidate As Variant) As String

A cell holding #N/A or #REF! answers with an Error variant, and CStr on one raises 13. That killed a whole update and reported a type mismatch that pointed nowhere.


Tag column infrastructure

TagColumnDataRange #

tag-column-data-range

Retrieve the helper tag column data range.

Signature:

Private Function TagColumnDataRange() As Range

ApplyTagColumnFormatting #

apply-tag-column-formatting

Ensure the helper column keeps its stealth formatting regardless of state.

Signature:

Private Sub ApplyTagColumnFormatting()

PaintTagBorders #

paint-tag-borders

Paint every edge of the tag range white so the column reads as empty.

Signature:

Private Sub PaintTagBorders(ByVal target As Range)

PaintHairlineBorder #

paint-hairline-border

Paint one edge of a range as a white hairline.

Signature:

Private Sub PaintHairlineBorder(ByVal target As Range, ByVal edge As Long)

ApplyLangColumnFormatting #

apply-lang-column-formatting

Apply font, sizing, and duplicate highlighting to a language column.

Signature:

Private Sub ApplyLangColumnFormatting(ByVal langRng As Range, ByRef painted As Long)

The group rules go on first and the red catch-all goes on last. FormatConditions.Add appends, so the rule added last holds the lowest priority and shows through only where no group rule claimed the cell.

Parameters:


HighlightDuplicateGroups #

highlight-duplicate-groups

Give every duplicate group in a column a fill of its own.

Signature:

Private Sub HighlightDuplicateGroups(ByVal langRng As Range, ByRef painted As Long)

A column painted in one colour says which cells are duplicated and nothing about which of them belong together. One rule per group says both, and the eye pairs them without reading a word.

Three things send a group back to the red catch-all: a palette that has run out (MAX_DUPLICATE_GROUPS), a label whose rule formula would pass MAX_RULE_FORMULA_LENGTH, and a formula Excel refuses. So red no longer reads as "duplicate". It reads as "duplicate this could not group", and a sheet with red on it is still telling the truth.

THE COUNTER IS THE CALLER'S, NOT THIS ROUTINE'S It used to start at zero on every column, so the first group of every language drew the same colour. An untranslated row carries the source spelling in both columns, so those same-coloured cells landed on the same rows and the sheet read as though whole rows were highlighted. Duplicates are counted within one column and always were; what crossed the columns was the colour. Carrying the count across the pass gives every group on the sheet a colour of its own, and the palette is then spent sheet-wide rather than per column.

Parameters:


AddGroupCondition #

add-group-condition

Give one duplicate group its own format condition.

Signature:

Private Function AddGroupCondition(ByVal langRng As Range, _
                                   ByVal anchor As String, _
                                   ByVal label As String, _
                                   ByVal fillColor As Long) As Boolean

EXACT is what carries the case, so the sheet groups labels the way CollectDuplicateGroups counts them and "Hello" never shares a colour with "hello".

Range.Formula reads US syntax whatever the host locale is and Formula1 follows it, so the formula is written in US form with a comma and no localised form is attempted. FormatConditions.Add appends without complaint, so the count is what says whether it was accepted.

Returns: Boolean. True when the group came away with a rule.


GroupConditionFormula #

group-condition-formula

Build the EXACT test for one duplicate group.

Signature:

Private Function GroupConditionFormula(ByVal anchor As String, _
                                       ByVal label As String) As String

A label carrying a double quote has to have it doubled or the formula closes early and Excel refuses the whole rule.

Returns: String. The formula, or empty when it would pass the length cap.


DuplicateColorCount #

duplicate-color-count

How many duplicate groups the palette colours before it repeats.

Signature:

Public Property Get DuplicateColorCount() As Long

HslToRgb #

hsl-to-rgb

Convert one HSL triplet into the Long an Interior.Color takes.

Signature:

Private Function HslToRgb(ByVal hue As Double, _
                          ByVal saturation As Double, _
                          ByVal lightness As Double) As Long

Hue picks the sector of the wheel, chroma is how far the colour sits from grey at that lightness, and the match value lifts all three channels so the result reads back at the lightness asked for. Stepping hue alone then keeps every group equally pale, which is what makes the black Consolas text on top stay readable whatever colour a group drew.

Parameters:

Returns: Long. RGB colour.


ColorByte #

color-byte

Turn a 0 to 1 channel into the 0 to 255 byte RGB expects.

Signature:

Private Function ColorByte(ByVal channel As Double) As Long

ConfigureTagColumn #

configure-tag-column

Locate and validate the helper column. No cell is written here.

Signature:

Private Sub ConfigureTagColumn()

EnsureTagColumnReady #

ensure-tag-column-ready

Write the helper column title and its stealth formatting.

Signature:

Private Sub EnsureTagColumnReady()

RequireTagHeader #

require-tag-header

Return the tag header cell, raising an error when unavailable.

Signature:

Private Function RequireTagHeader() As Range

IsTagHeaderAttached #

is-tag-header-attached

Test that the held header cell is alive and still sits beside the table.

Signature:

Private Function IsTagHeaderAttached() As Boolean

Deleting the helper column invalidates the held Range. Inserting a column between the helper and the table leaves it alive and no longer adjacent, and resizing over the wrong column follows from that.


AttachTagHeader #

attach-tag-header

Attempt to reconfigure and attach the tag header cell.

Signature:

Private Sub AttachTagHeader()

IsRangeValid #

is-range-valid

Test whether a Range reference is still alive and readable.

Signature:

Private Function IsRangeValid(ByVal candidate As Range) As Boolean

Tag integration helpers

BeginTagIntegration #

begin-tag-integration

Temporarily include the helper tag column inside the managed table.

Signature:

Private Sub BeginTagIntegration()

EndTagIntegration #

end-tag-integration

Restore the translations table to exclude the helper tag column.

Signature:

Private Sub EndTagIntegration()

The tag formatting is applied here alone, once per cycle.


LabelColumnIndex #

label-column-index

Resolve the current column index storing translation labels.

Signature:

Private Function LabelColumnIndex() As Long

Sorting and formatting

SortTranslations #

sort-translations

Sort the translations by their primary language column.

Signature:

Private Sub SortTranslations()

ApplyFormatting #

apply-formatting

Apply light formatting and duplicate highlighting once per update.

Signature:

Private Sub ApplyFormatting()

The row autofit runs once at the end. EntireRow.AutoFit measures every used column on the sheet, so one call per language column was the same measurement done again and again.


Data exchange

Export #

export

Export translations into a destination workbook.

Signature:

Public Sub Export(ByVal exportWorkbook As Workbook, Optional ByVal Hide As Long = xlSheetVisible)

Registry bookkeeping

PlannedUpdateSequence #

planned-update-sequence

Work out the sequence this cycle runs at, without writing it.

Signature:

Private Function PlannedUpdateSequence(ByVal registrySheet As Worksheet) As Long

PersistCounterValue #

persist-counter-value

Persist the counter value inside a hidden worksheet-level name.

Signature:

Private Sub PersistCounterValue(ByVal registrySheet As Worksheet, ByVal counterValue As Long)

CounterNumericValue #

counter-numeric-value

Retrieve the current counter value stored in worksheet names.

Signature:

Private Function CounterNumericValue(ByVal registrySheet As Worksheet) As Long

HiddenNameStore #

hidden-name-store

Create a HiddenNames wrapper for the supplied registry sheet.

Signature:

Private Function HiddenNameStore(ByVal registrySheet As Worksheet) As HiddenNames

A store that cannot be built means the sequence counter is never written. The next run then reads zero, treats the cycle as sequence 1 and reprocesses every row whatever its status, so this failure has to be heard.


MetadataStore #

metadata-store

Resolve the hidden name store hosting metadata.

Signature:

Private Function MetadataStore() As HiddenNames

Validation and utilities

ValidateInitialised #

validate-initialised

Ensure the manager has been initialised before use.

Signature:

Private Sub ValidateInitialised()

ValidateTranslationTable #

validate-translation-table

Validate the supplied translations table.

Signature:

Private Sub ValidateTranslationTable(ByVal translationTable As ListObject)

ValidateRegistrySheet #

validate-registry-sheet

Validate the registry sheet before processing.

Signature:

Private Sub ValidateRegistrySheet(ByVal registrySheet As Worksheet)

ResolveNamedRange #

resolve-named-range

Resolve a named range from the workbook, returning Nothing when missing.

Signature:

Private Function ResolveNamedRange(ByVal hostwb As Workbook, ByVal rangeName As String) As Range

ThrowProjectError #

throw-project-error

Raise a project error with a contextual message.

Signature:

Private Sub ThrowProjectError(ByVal errNumber As Long, ByVal message As String)

Parameters:


Used in (11 file(s))