---
title: Load and tokenize a localized text template
summary: Resolves a culture-specific text template from disk or an assembly manifest, falling back through broader cultures, then parses replaceable tokens from the loaded content.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Resources
reference_type: package
operation_id: OP-RES-01
trigger: Caller constructs a clsFileResourceManager or clsAssemblyResourceManager and calls LoadResource
---

# Load and tokenize a localized text template

This operation loads a text template — from a configured filesystem directory or from an assembly's embedded manifest resources — for a requested culture, then hands the loaded text to the shared base class to record the original text and parse `{token}`-style placeholders for later replacement. Both concrete loaders (`clsFileResourceManager` and `clsAssemblyResourceManager`) implement the same culture fallback chain independently, each against its own storage medium.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-RES-01 |
| **Trigger** | Caller instantiates `clsFileResourceManager` (with a resource directory) or `clsAssemblyResourceManager` (with an `Assembly`) and calls `LoadResource(inResourceName, inTemplateExtension, inCultureCode)` (or the single-argument overload, which defaults the culture code to the current UI culture) |
| **Inputs** | Resource name, template file extension (defaults to `html` on the base overload), culture code, and — for the file-based loader — the configured resource directory, or — for the assembly-based loader — the target `Assembly` and an optional namespace override |
| **Outputs** | Populated `Text` and `ReplacedText` on the loader instance, and a parsed `Tokens` list; no content is loaded and prior state is left unchanged if no matching file/resource is ever found |
| **Primary components** | `clsFileResourceManager.LoadResource`, `clsAssemblyResourceManager.LoadResource`, `clsResourceManager.Initialize`, `clsResourceManager.LoadTokens` |
| **Entry point** | `Resources\SAIF.Resources\clsFileResourceManager.vb`, `Resources\SAIF.Resources\clsAssemblyResourceManager.vb`, `Resources\SAIF.Resources\clsResourceManager.vb` |

## Steps

1. **Select a loader.** The caller instantiates either `clsFileResourceManager` (constructed with a resource directory, trimmed of a trailing backslash) or `clsAssemblyResourceManager` (constructed with an `Assembly`, defaulting to the executing assembly).
2. **Build the exact-culture resource identifier.**
   - File loader: builds the path `{ResourceDirectory}\{inResourceName}_{inCultureCode}.{inTemplateExtension}` (omitting the culture segment entirely when the culture code is empty).
   - Assembly loader: resolves the namespace (the supplied `inNamespace`, or the assembly's own name when none is supplied) and builds the manifest resource name `{namespace}.{inResourceName}_{inCultureCode}.{inTemplateExtension}` (again omitting the culture segment when empty).
3. **Attempt to load the exact-culture resource.**
   - File loader: checks `IO.File.Exists` for the built path.
   - Assembly loader: calls `Dll.GetManifestResourceStream` for the built resource name.
4. **Fall back to a two-letter culture if the exact match is not found.** If the requested culture code is longer than two characters, the loader retries steps 2–3 using only the first two characters of the culture code (for example, `en-US` retries as `en`).
5. **Fall back to no culture suffix if the two-letter match is also not found.** If the (possibly already-shortened) culture code is still non-empty, the loader retries steps 2–3 with an empty culture code, which resolves to the unsuffixed default resource name.
   - If no exact, two-letter, or unsuffixed resource exists, the loader returns without loading any content — `Text`, `ReplacedText`, and `Tokens` remain at their prior (or initial empty) state.
6. **Read the found content.**
   - File loader: opens an `IO.StreamReader` on the resolved path and reads the full text with `ReadToEnd`.
   - Assembly loader: opens the manifest resource stream and reads the full text with `ReadToEnd` through an `IO.StreamReader`.
7. **Initialize the shared state.** The loader calls `clsResourceManager.Initialize(text)`, which stores the raw text in `Text`, copies it into `ReplacedText`, and calls `LoadTokens()`.
8. **Parse simple tokens.** `LoadTokens` matches the pattern `{token-start}(?<token>[a-zA-Z0-9_]*){token-end}` (delimiters default to `{` and `}`) against the loaded text and adds a `Token` entry (name, pattern, raw value) for every match.
9. **Parse content-bearing tokens.** `LoadTokens` then matches the pattern `{token-start}(?<token>[a-zA-Z0-9_]*):(?<content>.*){token-end}` for colon-delimited tokens and adds a `Token` entry that also records the captured content, using a token-specific pattern for later replacement.
10. **Return the token list.** `LoadTokens` returns the populated `Tokens` list, now available on the loader instance for use by [Replace a token in loaded text](replace-token-in-loaded-text.md).

## Process flow

The following diagram visualizes the culture fallback and tokenization flow shared by both concrete resource loaders.

```mermaid
flowchart TD
	Start([Caller calls LoadResource]) --> BuildExact[Build exact-culture path<br>or manifest resource name]
	BuildExact --> FoundExact{Resource found?}
	FoundExact -->|Yes| Read[Read full template text]
	FoundExact -->|No| TwoLetter{Culture code<br>longer than 2 chars?}
	TwoLetter -->|Yes| BuildTwo[Retry with first<br>two characters]
	BuildTwo --> FoundTwo{Resource found?}
	FoundTwo -->|Yes| Read
	FoundTwo -->|No| NoSuffix{Culture code<br>still non-empty?}
	TwoLetter -->|No| NoSuffix
	NoSuffix -->|Yes| BuildDefault[Retry with empty<br>culture code]
	BuildDefault --> FoundDefault{Resource found?}
	FoundDefault -->|Yes| Read
	FoundDefault -->|No| EndNoLoad([Return without loading;<br>prior state unchanged])
	NoSuffix -->|No| EndNoLoad
	Read --> Init[Initialize stores Text<br>and ReplacedText]
	Init --> Tokens[LoadTokens parses<br>simple and content tokens]
	Tokens --> End([Tokens available for replacement])
```

## Failure and edge-case behavior

- If neither the exact-culture, two-letter-culture, nor unsuffixed resource exists, `LoadResource` returns silently without loading content or raising an error; `Text`, `ReplacedText`, and `Tokens` retain whatever state they held before the call.
- The two-letter fallback only triggers when the supplied culture code is longer than two characters, so a culture code already at two characters (e.g., `en`) skips directly to the unsuffixed fallback if the two-letter form is not found.
- An empty culture code on the initial call goes straight to the unsuffixed resource name, since the fallback conditions for both the two-letter and no-suffix retries require a non-empty starting culture code.
- The assembly loader resolves its own assembly's name as the default namespace whenever the caller omits `inNamespace`, so callers embedding resources under a different namespace must supply it explicitly.
- Both loaders implement the identical three-tier fallback chain independently in their own `LoadResource` overrides rather than sharing a common fallback helper.*

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `Resources\SAIF.Resources\clsResourceManager.vb`
- `Resources\SAIF.Resources\clsFileResourceManager.vb`
- `Resources\SAIF.Resources\clsAssemblyResourceManager.vb`
