Docs / Language Support & Multilingual Architecture

Language Support & Multilingual Architecture

This document details language support in LocalNPC, explaining why v1.0 ships English-only, the technical seams designed for multilingual expansion, and the strict engineering gate required to add any new language.


1. Shipping Status: English Only in v1.0

LocalNPC v1.0 ships with official support for English (en-US).

Both presets (Balanced, the default, and Fast) are configured with:

Important

The pipeline is designed to be language-agnostic, but v1.0 ships and tests English (en-US) only, and some English assumptions are still in the code (see section 2). Non-English languages are not officially supported in v1.0. We do not make false marketing claims regarding multilingual readiness until every stage passes our quality gate.


2. The Architectural Seams

No core pipeline file (NpcPipeline.cs, NpcAgent.cs, WindowsSpeechSynthesizer.cs, WhisperRecognizer.cs) is meant to contain hardcoded English strings, terminators, or language logic. This is not fully true yet: NpcPipeline.cs still falls back to the language code "en", uses an English abbreviation list when no LanguageProfile is set, and filters a short list of English phrases out of transcripts.

All language behaviour is encapsulated behind three contracts:

graph TD
    LP[LanguageProfile Asset] --> TN[ITextNormalizer]
    LP --> PH[IPhonemizer]
    LP --> ST[Sentence Delimiters & Abbreviation Rules]
    LP --> WC[Whisper Language Code]
    LP --> SV[Windows Voices: systemVoices]

1. LanguageProfile (LanguageProfile.cs)

A ScriptableObject defining:

Choosing a Voice for Each NPC

By default every NPC speaks with the shared voice. To give an NPC its own, select its NpcAgent and pick a voice under Voice in the Inspector. Speaking Rate sets its speed: 1.0 is the voice's normal rate, the range is 0.6 to 1.5, and Default Speed is 0.95. From a script, set SystemVoice and SpeakingRate before the agent starts; a change after that is ignored with a warning.

2. ITextNormalizer (INpcModules.cs)

Expands numbers, currencies, dates, and symbols into pronounceable words before the sentence goes to the voice (e.g. converting 100kg into one hundred kilograms).

3. IPhonemizer (INpcModules.cs)

Translates graphemes (letters) into phonemes (phonetic sounds). The Windows voice reads text, so v1.0 does not use a phonemizer.


3. The 7-Point Language Gate (§14.1)

Before scheduling or announcing official support for any new language, the following 7 questions must be answered affirmatively:

#QuestionHard Constraint
1Does Windows have a voice for the language?The player installs it in Settings > Time & language > Speech. Without one the NPC answers in text only.
2Can G2P (Grapheme-to-Phoneme) be solved permissively?Only for your own synthesizer that takes phonemes; the Windows voice does not need it. Must use an open-source dictionary or clean-room rule engine. Alternatively, developers can provide an external IPhonemizer plugin.
3Which Whisper model reaches acceptable Word Error Rate (WER)?Multilingual tiny has significantly worse WER than tiny.en. A larger model (base or small) is a larger download; not measured with LocalNPC.
4Which LLM produces acceptable grammar at low RAM?0.5B models struggle with complex morphology in languages like German or Japanese; a 1.5B or larger model may be mandatory.
5Does the chat template need modifications?ChatML templates must be verified for correct token framing in the target language.
6Do sentence terminators and digits differ?Non-Latin scripts (Arabic, Bengali, Devanagari, Japanese, Thai) require custom delimiter rules and numeral mappings.
7Does the subtitle font shape correctly in TextMeshPro?Complex Indic/Arabic scripts require specialized OpenType font tables and harfbuzz-compatible text shaping.

Warning

Question 1 is a research blocker. If Windows has no voice for a language, the NPC cannot speak it.


4. How to Implement a Community Language

If you wish to add a custom language to your game:

  1. Implement ITextNormalizer:
    public class SpanishTextNormalizer : ITextNormalizer
    {
        public string Normalize(string input)
        {
            // Strip markdown, expand € / números
            return expandedText;
        }
    }
  2. Optional: implement IPhonemizer (only for your own synthesizer that takes phonemes; the Windows voice does not use it):
    public class SpanishPhonemizer : IPhonemizer
    {
        public int[] Phonemize(string sentence)
        {
            // Return the phoneme ids your synthesizer expects
            return phonemeIds;
        }
    }
  3. Create LanguageProfile_es-ES.asset: Set whisperLanguageCode to "es", set languageTag to "es-ES", put the assembly-qualified type names of your classes in customNormalizerType and customPhonemizerType, list the Spanish Windows voices to use in systemVoices (with an empty list, any installed es-ES voice is used), and assign the profile as the default language profile of your NpcRuntimeConfig.
  4. Select Multilingual Whisper & LLM: NpcRuntimeConfig has no setting for the Whisper model or for another LLM. LocalNPC uses the speech-to-text model of the model catalogue, ggml-tiny.en.bin, which is English only, and the LLM of the chosen preset. A multilingual speech model and automatic language detection have not been tested with the built-in recognizer. To use others, write your own ISpeechRecognizer or ILanguageModel and register it before the first agent starts, with NpcServiceLocator.RegisterRecognizerFactory or NpcServiceLocator.RegisterLanguageModelFactory.

5. Roadmap & Future Languages

This page is the file docs/10-language-support.md of the LocalNPC package documentation (also in the package as Documentation~/10-language-support.md).