Files
meshcore-hub/docs/i18n.md
T
Louis King f8c2a7bb40 Rename channel visibility 'public' to 'community'
- Rename ChannelVisibility.PUBLIC to ChannelVisibility.COMMUNITY
- Update stored value from 'public' to 'community' across model, schema, API, CLI, and frontend
- Add Alembic migration to update existing database rows
- Consolidate upgrade docs: merge v0.11.0, v0.12.0, v0.13.0 into single v0.11.0 section
- Add i18n visibility level translation keys (en, nl)
- Update section headings on channels page to use t() for i18n
- Keep visibility badges lowercase per UI design
2026-06-04 14:07:12 +01:00

21 KiB
Raw Blame History

Translation Reference Guide

This document provides a comprehensive reference for translating the MeshCore Hub web dashboard.

File Structure

Translation files are JSON files named by language code (e.g., en.json, es.json, fr.json) and located in /src/meshcore_hub/web/static/locales/.

Variable Interpolation

Many translations use {{variable}} syntax for dynamic content. These must be preserved exactly:

"total": "{{count}} total"

When translating, keep the variable names unchanged:

"total": "{{count}} au total"  // French example

Translation Sections

1. entities

Core entity names used throughout the application. These are referenced by other translations for composition.

Key English Context
home Home Homepage/breadcrumb navigation
dashboard Dashboard Main dashboard page
nodes Nodes Mesh network nodes (plural)
node Node Single mesh network node
node_detail Node Detail Node details page
advertisements Adverts Network advertisements (plural, used in nav menus and hero cards)
advertisement Advert Single advertisement
messages Messages Network messages (plural)
message Message Single message
map Map Network map page
members Members Network members (plural)
member Member Single network member
tags Tags Node metadata tags (plural)
tag Tag Single tag
channel Channel Mesh network channel

Usage: These are used with composite patterns. For example, t('common.add_entity', { entity: t('entities.node') }) produces "Add Node".

2. common

Reusable patterns and UI elements used across multiple pages.

Actions

Key English Context
filter Filter Filter button/action
clear Clear Clear action
clear_filters Clear Filters Reset all filters
search Search Search button/action
cancel Cancel Cancel button in dialogs
delete Delete Delete button
edit Edit Edit button
move Move Move button
save Save Save button
save_changes Save Changes Save changes button
add Add Add button
close close Close button (lowercase for accessibility)
sign_in Sign In Authentication sign in
sign_out Sign Out Authentication sign out
go_home Go Home Return to homepage button

Composite Patterns with Entity

These patterns use {{entity}} variable - the entity name is provided dynamically:

Key English Example Output
add_entity Add {{entity}} "Add Node", "Add Tag"
add_new_entity Add New {{entity}} "Add New Member"
edit_entity Edit {{entity}} "Edit Tag"
delete_entity Delete {{entity}} "Delete Member"
delete_all_entity Delete All {{entity}} "Delete All Tags"
move_entity Move {{entity}} "Move Tag"
move_entity_to_another_node Move {{entity}} to Another Node "Move Tag to Another Node"
copy_entity Copy {{entity}} "Copy Tags"
copy_all_entity_to_another_node Copy All {{entity}} to Another Node "Copy All Tags to Another Node"
view_entity View {{entity}} "View Node"
recent_entity Recent {{entity}} "Recent Advertisements"
total_entity Total {{entity}} "Total Nodes"
all_entity All {{entity}} "All Messages"

Empty State Patterns

These patterns indicate when data is absent. Use {{entity}} in lowercase (e.g., "nodes", not "Nodes"):

Key English Context
no_entity_found No {{entity}} found Search/filter returned no results
no_entity_recorded No {{entity}} recorded No historical records exist
no_entity_defined No {{entity}} defined No configuration/definitions exist
no_entity_in_database No {{entity}} in database Database is empty
no_entity_configured No {{entity}} configured System not configured
no_entity_yet No {{entity}} yet Empty state, expecting data later
entity_not_found_details {{entity}} not found: {{details}} Specific item not found with details
page_not_found Page not found 404 error message

Confirmation Patterns

Used in delete/move dialogs. Variables: {{entity}}, {{name}}, {{count}}:

Key English Context
delete_entity_confirm Are you sure you want to delete {{entity}} {{name}}? Single item delete confirmation
delete_all_entity_confirm Are you sure you want to delete all {{count}} {{entity}} from {{name}}? Bulk delete confirmation
cannot_be_undone This action cannot be undone. Warning in delete dialogs

Success Messages

Toast/flash messages after successful operations:

Key English Context
entity_added_success {{entity}} added successfully After creating new item
entity_updated_success {{entity}} updated successfully After updating item
entity_deleted_success {{entity}} deleted successfully After deleting item
entity_moved_success {{entity}} moved successfully After moving tag to another node
all_entity_deleted_success All {{entity}} deleted successfully After bulk delete
copy_all_entity_description Copy all {{count}} {{entity}} from {{name}} to another node. Copy operation description

Navigation & Status

Key English Context
previous Previous Pagination previous
next Next Pagination next
loading Loading... Loading indicator
error Error Error state
failed_to_load_page Failed to load page Page load error

Counts & Metrics

Key English Context
total {{count}} total Total count display
shown {{count}} shown Filtered count display
count_entity {{count}} {{entity}} Generic count with entity

Form Fields & Labels

Key English Context
type Type Type field/column header
name Name Name field/column header
key Key Key field (for tags)
value Value Value field (for tags)
time Time Time column header
actions Actions Actions column header
updated Updated Last updated timestamp
view_details View Details View details link
all_types All Types "All types" filter option
all_channels All Channels "All channels" filter option
all_members All Members "All members" filter option (only shown when OIDC is enabled)
all_operators All Operators "All operators" filter option for operator-only filter dropdowns
filter_member_label Member Label for member filter dropdown
filter_operator_label Operator Label for operator filter dropdown (used on Nodes, Advertisements, Map pages)
node_type Node Type Node type field
show Show Show/display action
search_placeholder Search by name, ID, or public key... Search input placeholder
contact Contact Contact information field
description Description Description field
callsign Callsign Amateur radio callsign field
tags Tags Tags label/header
last_seen Last Seen Last seen timestamp (table header)
first_seen_label First seen: First seen label (inline with colon)
last_seen_label Last seen: Last seen label (inline with colon)
location Location Geographic location
public_key Public Key Node public key
received Received Received timestamp
received_by Received By Received by field
receivers Receivers Multiple receivers
from From Message sender
hops Hops Number of mesh hops (table header)
observers Observers Observers of an event
snr_db SNR (dB) Signal-to-noise ratio in decibels (table header)
unnamed Unnamed Fallback for unnamed items
unnamed_node Unnamed Node Fallback for unnamed nodes
sort_by Sort by Label before mobile sort dropdown

Note: Keys ending in _label have colons and are used inline. Keys without _label are for table headers.

Platform and external link labels:

Key English Context
website Website Website link label
github GitHub GitHub link label (preserve capitalization)
discord Discord Discord link label
youtube YouTube YouTube link label (preserve capitalization)
profile Profile Radio profile label

4. auto_refresh

Auto-refresh controls for list pages (nodes, advertisements, messages):

Key English Context
pause Pause auto-refresh Tooltip on pause button when auto-refresh is active
resume Resume auto-refresh Tooltip on play button when auto-refresh is paused

5. time

Time-related labels and formats:

Key English Context
days_ago {{count}}d ago Days ago (abbreviated)
hours_ago {{count}}h ago Hours ago (abbreviated)
minutes_ago {{count}}m ago Minutes ago (abbreviated)
less_than_minute <1m ago Less than one minute ago
last_7_days Last 7 days Last 7 days label
per_day_last_7_days Per day (last 7 days) Per day over last 7 days
over_time_last_7_days Over time (last 7 days) Over time last 7 days
activity_per_day_last_7_days Activity per day (last 7 days) Activity chart label

6. node_types

Mesh network node type labels:

Key English Context
chat Chat Chat node type
repeater Repeater Repeater/relay node type
companion Companion Companion/observer node type
room Room Server Room server/group node type
unknown Unknown Unknown node type fallback

7. home

Homepage-specific content:

Key English Context
welcome_default Welcome to the {{network_name}} mesh network dashboard. Monitor network activity, view connected nodes, and explore message history. Default welcome message
all_discovered_nodes All discovered nodes Stat description
network_info Network Info Network info card title
network_activity Network Activity Activity chart title
frequency Frequency Radio frequency label
bandwidth Bandwidth Radio bandwidth label
spreading_factor Spreading Factor LoRa spreading factor label
coding_rate Coding Rate LoRa coding rate label
tx_power TX Power Transmit power label
advertisements Adverts Homepage stat label
messages Messages Homepage stat label

Note: MeshCore tagline "Off-Grid, Open-Source Encrypted Messaging" is hardcoded in English and should not be translated (trademark).

8. dashboard

Dashboard page content:

Key English Context
all_discovered_nodes All discovered nodes Stat label
recent_channel_messages Recent Channel Messages Recent messages card title
channel Channel {{number}} Channel label with number

9. nodes

Node detail page labels:

Key English Context
scan_to_add Scan to add as contact QR code instruction
ownership Ownership Adoption card heading on node detail page
adopt Adopt Adopt button (operator/admin only)
release Release Release button (owner or admin only)
adopted_by Adopted by {{name}} Display name of adopting user ({{name}} = user name or ID)
not_adopted This node has not been adopted by any operator. Shown when node is unadopted and user is operator/admin
adopt_success Node adopted successfully Flash message after adopting
release_success Node released successfully Flash message after releasing
release_confirm Are you sure you want to release this node? Confirmation dialog for release

Sort Options (nodes.sort)

Mobile sort dropdown labels for the nodes list page:

Key English Context
sort.last_seen_newest Last Seen (newest) Default sort: most recently seen first
sort.last_seen_oldest Last Seen (oldest) Least recently seen first
sort.name_az Name (AZ) Alphabetical by display name
sort.name_za Name (ZA) Reverse alphabetical by display name
sort.key_asc Public Key (ascending) Sorted by public key ascending
sort.key_desc Public Key (descending) Sorted by public key descending

10. advertisements

Route type filter and sort options for the advertisements list page:

Route Type Filter

Key English Context
filter_route_type_label Advert Type Label for route type filter dropdown
route_type_all All Show all route types (no filter)
route_type_flood Flood & Relay Show flood and transport_flood adverts (default)
route_type_direct Zero-hop only Show only direct (zero-hop) adverts
route_type_unknown Unknown Displayed when route_type is NULL (historical records)
col_route_type Type Table column header for route type

Sort Options (advertisements.sort)

Mobile sort dropdown labels for the advertisements list page:

Key English Context
sort.newest Time (newest) Default sort: most recent first
sort.oldest Time (oldest) Oldest first
sort.node_az Node (AZ) Alphabetical by node display name
sort.node_za Node (ZA) Reverse alphabetical by node display name
sort.key_asc Public Key (ascending) Sorted by public key ascending
sort.key_desc Public Key (descending) Sorted by public key descending

11. messages

Message type labels:

Key English Context
type_direct Direct Direct message type
type_channel Channel Channel message type
type_contact Contact Contact message type
type_public Public Public message type

Sort Options (messages.sort)

Mobile sort dropdown labels for the messages list page:

Key English Context
sort.newest Time (newest) Default sort: most recent first
sort.oldest Time (oldest) Oldest first
sort.type_az Type (AZ) Alphabetical by message type
sort.type_za Type (ZA) Reverse alphabetical by message type
sort.from_az From (AZ) Alphabetical by sender name
sort.from_za From (ZA) Reverse alphabetical by sender name
sort.message_az Message (AZ) Alphabetical by message text
sort.message_za Message (ZA) Reverse alphabetical by message text

12. map

Map page content:

Key English Context
show_labels Show Labels Toggle to show node labels
infrastructure_only Infrastructure Only Toggle to show only infrastructure nodes (OIDC required, only rendered when OIDC_ENABLED=true; data sourced from node adoption, not tags)
legend Legend: Map legend header (only rendered when OIDC_ENABLED=true)
infrastructure Infrastructure Infrastructure node category (only rendered when OIDC_ENABLED=true; based on adoption status)
public Public Public node category
nodes_on_map {{count}} nodes on map Status text with coordinates
nodes_none_have_coordinates {{count}} nodes (none have coordinates) Status text without coordinates
gps_description Nodes are placed on the map based on GPS coordinates from node reports or manual tags. Map data source explanation
owner Owner: Node owner label
role Role: Member role label
select_destination_node -- Select destination node -- Dropdown placeholder

13. members

Members page content:

Key English Context
empty_state_description No members yet. Empty state heading
empty_description Members will appear here once users log in and adopt nodes. Empty state description

14. channels

Channel management and filter UI:

Key English Context
title Channels Page title
add_channel Add Channel Add button label
edit_channel Edit Channel Edit modal title
delete_channel Delete Channel Delete modal title
delete_confirm Are you sure you want to delete channel {{name}}? Delete confirmation message
name_label Channel Name Form label
key_label Channel Key (hex) Form label
visibility_label Visibility Form label
visibility_community Community Community visibility section heading
visibility_member Member Member visibility section heading
visibility_operator Operator Operator visibility section heading
visibility_admin Admin Admin visibility section heading
enabled_label Enabled Form label
channel_hash_label Hash Column header
disabled Disabled Disabled channel badge
optgroup_standard Standard Optgroup label for built-in channels (Public, Test) in channel filter dropdown
optgroup_custom Custom Optgroup label for user-defined channels in channel filter dropdown

15. not_found

404 page content:

Key English Context
description The page you're looking for doesn't exist or has been moved. 404 description

16. custom_page

Custom markdown page errors:

Key English Context
failed_to_load Failed to load page Page load error

17. auth

Authentication UI:

Key English Context
login Login Login button text
logout Logout Logout menu item
login_required Login required Login required heading
admin_required Admin access required Admin access denied message
login_hint Log in to access admin features Hint shown to non-admin users
logged_in_as Logged in as {{name}} Logged in status ({{name}} = user display name)
session_expired Session expired, please log in again Session expiry notice
role_admin admin Admin role badge text
role_member member Member role badge text

Footer content:

Key English Context
powered_by Powered by "Powered by" attribution

19. user_profile

User profile page (OIDC authenticated users):

Key English Context
title Profile Page heading
your_profile Your Profile Profile card heading
profile_updated Profile updated successfully Flash message after save
save_profile Save Profile Save button label
name_label Display Name Form label
name_placeholder Your name or preferred name Input placeholder
callsign_label Callsign Form label
callsign_placeholder Amateur radio callsign (e.g., W1ABC) Input placeholder
description_label Description Form label
description_placeholder A short bio or description Input placeholder
url_label Website / Profile Link Form label
url_placeholder https://... Input placeholder
adopted_nodes Adopted Nodes Adopted nodes card heading
no_adopted_nodes No adopted nodes Empty state
login_to_view Log in to view your profile Unauthenticated notice

Translation Tips

  1. Preserve HTML tags: Some strings contain <code>, <strong>, or <br/> tags - keep these intact.

  2. Preserve variables: Keep {{variable}} placeholders exactly as-is, only translate surrounding text.

  3. Entity composition: Many translations reference entities.* keys. When translating entities, consider how they'll work in composite patterns (e.g., "Add {{entity}}" should make sense with "Node", "Tag", etc.).

  4. Capitalization:

    • Entity names should follow your language's capitalization rules for UI elements
    • Inline labels (with colons) typically use sentence case
    • Table headers typically use title case
    • Action buttons can vary by language convention
  5. Colons: Keys ending in _label include colons in English. Adjust punctuation to match your language's conventions for inline labels.

  6. Plurals: Some languages have complex plural rules. You may need to add plural variants for {{count}} patterns. Consult the i18n library documentation for plural support.

  7. Length: UI space is limited. Try to keep translations concise, especially for button labels and table headers.

  8. Brand names: Preserve "MeshCore", "GitHub", "YouTube" capitalization.

Testing Your Translation

  1. Create your translation file: locales/xx.json (where xx is your language code)
  2. Copy the structure from en.json
  3. Translate all values, preserving all variables and HTML
  4. Test in the application by setting the language
  5. Check all pages for:
    • Text overflow/truncation
    • Proper variable interpolation
    • Natural phrasing in context

Getting Help

If you're unsure about the context of a translation key, check:

  1. The "Context" column in this reference
  2. The JavaScript files in /src/meshcore_hub/web/static/js/spa/pages/
  3. Grep for the key: grep -r "t('section.key')" src/