Internationalization (i18n)
Truthound provides an enterprise-grade i18n system for internationalizing validator error messages.
Supported Languages
Core Languages (7)
| Code |
Language |
Direction |
en |
English |
LTR |
ko |
Korean |
LTR |
ja |
Japanese |
LTR |
zh |
Chinese |
LTR |
de |
German |
LTR |
fr |
French |
LTR |
es |
Spanish |
LTR |
Extended Languages (8)
| Code |
Language |
Direction |
Notes |
pt |
Portuguese |
LTR |
|
pt-BR |
Portuguese (Brazil) |
LTR |
Brazil |
pt-PT |
Portuguese (Portugal) |
LTR |
Portugal |
it |
Italian |
LTR |
|
ru |
Russian |
LTR |
|
ar |
Arabic |
RTL |
|
he |
Hebrew |
RTL |
|
fa |
Persian |
RTL |
|
Basic Usage
Setting the Locale
from truthound.validators.i18n import (
set_validator_locale,
get_validator_locale,
)
# Set locale
set_validator_locale("ko")
# Get current locale
locale = get_validator_locale()
print(locale) # "ko"
Retrieving Messages
from truthound.validators.i18n import (
get_validator_message,
ValidatorMessageCode,
)
# Set locale
set_validator_locale("ko")
# Retrieve message
msg = get_validator_message(
ValidatorMessageCode.NULL_VALUES_FOUND,
column="email",
count=10,
)
print(msg) # "'email' 컬럼에서 10개의 null 값이 발견되었습니다"
from truthound.validators.i18n import format_issue_message
from truthound.validators.base import ValidationIssue
issue = ValidationIssue(
column="email",
issue_type="null_value",
count=10,
severity="high",
)
# Format issue message
msg = format_issue_message(issue, locale="ko")
ValidatorMessageCode
All validator message codes:
Completeness
| Code |
Description |
NULL_VALUES_FOUND |
Null values found |
COMPLETENESS_BELOW_THRESHOLD |
Completeness below threshold |
REQUIRED_COLUMN_MISSING |
Required column missing |
Uniqueness
| Code |
Description |
DUPLICATE_VALUES_FOUND |
Duplicate values found |
UNIQUENESS_CONSTRAINT_VIOLATED |
Uniqueness constraint violated |
Range & Distribution
| Code |
Description |
VALUES_OUT_OF_RANGE |
Values out of range |
MIN_VALUE_EXCEEDED |
Below minimum value |
MAX_VALUE_EXCEEDED |
Exceeds maximum value |
OUTLIERS_DETECTED |
Outliers detected |
| Code |
Description |
PATTERN_MISMATCH |
Pattern mismatch |
INVALID_EMAIL_FORMAT |
Invalid email format |
INVALID_DATE_FORMAT |
Invalid date format |
INVALID_PHONE_FORMAT |
Invalid phone format |
Type
| Code |
Description |
TYPE_MISMATCH |
Type mismatch |
UNEXPECTED_TYPE |
Unexpected type |
Relationship
| Code |
Description |
FOREIGN_KEY_VIOLATION |
Foreign key violation |
REFERENTIAL_INTEGRITY_ERROR |
Referential integrity error |
CLDR Plural Rules
Support for CLDR (Common Locale Data Repository) standard plural rules:
Plural Categories
| Category |
Description |
Example |
zero |
Zero |
Arabic 0 |
one |
Singular |
1 item |
two |
Dual |
Arabic 2 |
few |
Few |
Russian 2-4 |
many |
Many |
Russian 5-20 |
other |
Other |
General plural |
Using Plurals
from truthound.validators.i18n import (
pluralize,
get_plural_category,
PluralCategory,
)
# Get plural category
category = get_plural_category(5, "ru")
print(category) # PluralCategory.FEW
# Plural message
msg = pluralize(
count=5,
forms={
"one": "{count} файл",
"few": "{count} файла",
"many": "{count} файлов",
"other": "{count} файлов",
},
locale="ru",
)
print(msg) # "5 файлов"
Plural Rules by Language
| Language |
Categories |
Rules |
| English |
one, other |
1 = one, else other |
| Korean |
other |
All other |
| Japanese |
other |
All other |
| Chinese |
other |
All other |
| Russian |
one, few, many, other |
Complex rules |
| Arabic |
zero, one, two, few, many, other |
6 forms |
| French |
one, other |
0, 1 = one, else other |
| German |
one, other |
1 = one, else other |
from truthound.validators.i18n import (
format_number,
format_currency,
NumberStyle,
)
# Number formatting
format_number(1234567.89, "de") # "1.234.567,89"
format_number(1234567.89, "en") # "1,234,567.89"
format_number(1234567.89, "ko") # "1,234,567.89"
format_number(1234567.89, "ar") # "١٬٢٣٤٬٥٦٧٫٨٩"
# Currency formatting
format_currency(1000, "USD", "en") # "$1,000.00"
format_currency(1000, "EUR", "de") # "1.000,00 €"
format_currency(1000, "KRW", "ko") # "₩1,000"
from truthound.validators.i18n import (
format_date,
format_time,
format_relative_time,
DateStyle,
TimeStyle,
)
from datetime import datetime, timedelta
now = datetime.now()
# Date formatting
format_date(now, "ko", DateStyle.SHORT) # "24. 12. 28."
format_date(now, "ko", DateStyle.MEDIUM) # "2024. 12. 28."
format_date(now, "ko", DateStyle.LONG) # "2024년 12월 28일"
format_date(now, "ko", DateStyle.FULL) # "2024년 12월 28일 토요일"
format_date(now, "de", DateStyle.LONG) # "28. Dezember 2024"
format_date(now, "ja", DateStyle.LONG) # "2024年12月28日"
# Time formatting
format_time(now, "en", TimeStyle.SHORT) # "3:30 PM"
format_time(now, "de", TimeStyle.SHORT) # "15:30"
format_time(now, "ko", TimeStyle.MEDIUM) # "오후 3:30:00"
# Relative time
format_relative_time(timedelta(days=-1), "ko") # "어제"
format_relative_time(timedelta(hours=-3), "en") # "3 hours ago"
format_relative_time(timedelta(days=2), "de") # "in 2 Tagen"
RTL Language Support
Right-to-left (RTL) language support:
RTL Languages
from truthound.validators.i18n import (
RTL_LANGUAGES,
is_rtl_language,
get_locale_direction,
TextDirection,
)
print(RTL_LANGUAGES)
# {"ar", "he", "fa", "ur", "yi", "ps", "sd", "dv", "ug", "ku"}
is_rtl_language("ar") # True
is_rtl_language("ko") # False
get_locale_direction("ar") # TextDirection.RTL
get_locale_direction("en") # TextDirection.LTR
BiDi Handling
from truthound.validators.i18n import (
BiDiHandler,
BiDiConfig,
BiDiControl,
wrap_bidi,
detect_direction,
)
# Detect text direction
direction = detect_direction("مرحبا") # TextDirection.RTL
direction = detect_direction("Hello") # TextDirection.LTR
# BiDi handler
config = BiDiConfig(
insert_marks=True, # Insert direction markers
force_direction=None, # Force direction (None = auto)
isolate_numbers=True, # Isolate numbers
strip_marks=False, # Strip existing markers
)
handler = BiDiHandler(config)
wrapped = handler.process("Hello مرحبا 123")
# Convenience function
wrapped = wrap_bidi("Hello مرحبا", BiDiControl.LRI)
Regional Dialect Support
Registering Dialects
from truthound.validators.i18n import (
create_dialect,
register_dialect,
get_dialect_registry,
get_fallback_chain,
)
# Create dialect
en_us = create_dialect(
code="en-US",
parent="en",
name="English (United States)",
overrides={
ValidatorMessageCode.DATE_FORMAT_ERROR: "Invalid date format. Expected MM/DD/YYYY.",
},
)
# Register dialect
register_dialect(en_us)
# Get fallback chain
chain = get_fallback_chain("en-US")
# ["en-US", "en"]
chain = get_fallback_chain("pt-BR")
# ["pt-BR", "pt"]
Setting Regional Locale
from truthound.validators.i18n import set_validator_locale
# Set regional dialect
set_validator_locale("en-US")
set_validator_locale("zh-TW") # Traditional Chinese
set_validator_locale("pt-BR") # Brazilian Portuguese
TMS Integration
Translation Management System (TMS) integration:
Supported TMS Providers
| Provider |
Class |
API |
| Crowdin |
CrowdinProvider |
REST API v2 |
| Lokalise |
LokaliseProvider |
REST API v2 |
| Phrase |
PhraseProvider |
REST API v2 |
TMS Configuration
from truthound.validators.i18n import (
TMSConfig,
TMSManager,
create_provider,
CrowdinProvider,
)
# Crowdin configuration
config = TMSConfig(
provider="crowdin",
api_key="your-api-key",
project_id="your-project-id",
base_url="https://api.crowdin.com/api/v2",
sync_interval_seconds=3600,
auto_sync=True,
)
# Create provider
provider = create_provider(config)
# Or create directly
provider = CrowdinProvider(
api_key="your-api-key",
project_id="your-project-id",
)
TMS Manager
from truthound.validators.i18n import get_tms_manager
manager = get_tms_manager(config)
# Sync translations
await manager.sync()
# Check translation status
status = await manager.get_translation_status("ko")
print(status.progress_percentage)
print(status.translated_count)
print(status.approved_count)
# Handle webhook
event = manager.parse_webhook(request_body)
if event.event_type == "translation.completed":
await manager.sync()
Dynamic Catalog Management
CatalogManager
from truthound.validators.i18n import (
CatalogManager,
get_catalog_manager,
FileSystemStorage,
MemoryStorage,
)
# Memory storage (default)
manager = get_catalog_manager()
# File system storage
storage = FileSystemStorage(path="/translations")
manager = CatalogManager(storage=storage)
# Load catalog
catalog = manager.load_catalog("ko")
# Save catalog
manager.save_catalog("ko", catalog)
# Invalidate cache
manager.invalidate_cache("ko")
manager.clear_cache()
Context-Based Messages
from truthound.validators.i18n import (
ContextResolver,
MessageContext,
resolve_message,
)
# Context resolver
resolver = ContextResolver()
# Context-specific message retrieval
msg = resolve_message(
code=ValidatorMessageCode.NULL_VALUES_FOUND,
context=MessageContext.TECHNICAL, # formal, informal, technical
locale="ko",
column="email",
count=10,
)
Custom Catalogs
Creating Catalogs
from truthound.validators.i18n import (
ValidatorMessageCatalog,
CatalogBuilder,
create_custom_catalog,
)
# Create with builder
builder = CatalogBuilder("custom")
builder.add_message(
ValidatorMessageCode.NULL_VALUES_FOUND,
"Column '{column}' contains {count} null values",
)
builder.add_message(
ValidatorMessageCode.DUPLICATE_VALUES_FOUND,
"Found {count} duplicate values in '{column}'",
)
catalog = builder.build()
# Convenience function
catalog = create_custom_catalog(
locale="custom",
messages={
ValidatorMessageCode.NULL_VALUES_FOUND: "Custom null message: {count}",
},
fallback="en",
)
Registering Catalogs
from truthound.validators.i18n import get_catalog_manager
manager = get_catalog_manager()
manager.register_catalog("custom", catalog)
# Use
set_validator_locale("custom")
msg = get_validator_message(ValidatorMessageCode.NULL_VALUES_FOUND, count=5)
Retrieving Existing Catalogs
from truthound.validators.i18n import (
get_all_catalogs,
get_all_extended_catalogs,
get_supported_locales,
get_extended_supported_locales,
get_default_messages,
get_korean_messages,
get_japanese_messages,
get_chinese_messages,
get_german_messages,
get_french_messages,
get_spanish_messages,
get_portuguese_messages,
get_italian_messages,
get_russian_messages,
get_arabic_messages,
get_hebrew_messages,
get_persian_messages,
)
# Supported locales list
locales = get_supported_locales()
# ["en", "ko", "ja", "zh", "de", "fr", "es"]
extended = get_extended_supported_locales()
# ["pt", "pt-BR", "pt-PT", "it", "ru", "ar", "he", "fa"]
# All catalogs
all_catalogs = get_all_catalogs()
all_extended = get_all_extended_catalogs()
# Individual catalogs
en_messages = get_default_messages()
ko_messages = get_korean_messages()
ar_messages = get_arabic_messages()
Next Steps