2026-01-22 13:47:01 +01:00
2026-01-23 01:56:18 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 23:52:53 +01:00
2026-01-23 01:56:03 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 15:54:43 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 13:47:01 +01:00
2026-01-22 19:29:25 +01:00
2026-01-22 19:29:25 +01:00
2026-01-22 13:47:01 +01:00
2026-01-23 00:34:48 +01:00

Specification: Translation Dictionary for Living Christianity

Overview

"Sanasto Wiki" is a web-based dictionary application for simultaneous translators in the living Christianity. The application provides publicly accessible translations while restricting editing and commenting to invited contributors.


Core Concepts

Supported Languages

Initial seed data:

Code Name Native Name Sort Order
fi Finnish Suomi 1
en English English 2
sv Swedish Svenska 3
no Norwegian Norsk 4
de German Deutsch 5
ru Russian Русский 6

Language codes are fixed because translations are stored in columns on entries. The supported_languages table controls labels, ordering, and whether a language is active. To add a language, you must add a new column to entries and add a corresponding row to supported_languages.

Entry

An entry represents a translatable unit which may be:

  • word — Single word
  • phrase — Multi-word expression or idiom, sentence
  • proper_name — Person's name (for consistent transliteration)
  • title — Book, publication, or hymn title
  • reference — Biblical or doctrinal term
  • other — Any other translatable text unit

Each entry has translations in multiple languages.

Suggested Meaning

When translators disagree on a translation or want to suggest alternatives (regional variations, contextual meanings, etc.), they can submit a suggested meaning for community review.


Technical Stack

  • Framework: Rails 8
  • Database: SQLite with FTS5
  • Authentication: Rails 8 built-in authentication
  • Authorization: Invitation-only for contributors
  • Deployment: Kamal

Authentication Flow

Public Access

  • No authentication required for browsing and searching entries
  • Read-only access to all dictionary content

Invitation-Only Registration

  • Admins send email invitations with unique tokens
  • Invited users register by setting name and password
  • invitation_token cleared after successful registration

Login & Sessions

  • Email + password authentication
  • Session-based (encrypted cookies, Rails default)
  • Optional "remember me" for extended sessions

Authorization

  • Contributor: Create/edit entries, add comments, suggest translations
  • Reviewer: All contributor actions + review suggestions, verify entries
  • Admin: All actions + invite users, manage roles

Security

  • Passwords hashed with bcrypt
  • Rate limiting on login attempts
  • Invitation tokens expire after 14 days

Database Schema

# db/schema.rb

ActiveRecord::Schema[8.0].define(version: 2025_01_22_100000) do
  create_table "entries", force: :cascade do |t|
    t.integer "category", null: false  # word, phrase, proper_name, title, reference, other
    
    # Language columns
    t.string "fi"  # Finnish
    t.string "en"  # English
    t.string "sv"  # Swedish
    t.string "no"  # Norwegian
    t.string "ru"  # Russian
    t.string "de"  # German
    
    t.text "notes"
    t.boolean "verified", default: false
    t.integer "created_by_id"
    t.integer "updated_by_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    
    t.index ["category"], name: "index_entries_on_category"
  end

  create_table "suggested_meanings", force: :cascade do |t|
    t.integer "entry_id", null: false
    t.string "language_code", null: false
    t.string "alternative_translation", null: false
    t.text "context"
    t.text "reasoning"
    t.string "source"
    t.string "region"
    t.integer "status", default: 0  # pending, accepted, rejected
    t.integer "submitted_by_id"
    t.integer "reviewed_by_id"
    t.datetime "reviewed_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    
    t.index ["entry_id"], name: "index_suggested_meanings_on_entry_id"
    t.index ["language_code"], name: "index_suggested_meanings_on_language_code"
    t.index ["status"], name: "index_suggested_meanings_on_status"
  end

  create_table "comments", force: :cascade do |t|
    t.integer "user_id", null: false
    t.string "commentable_type", null: false
    t.integer "commentable_id", null: false
    t.text "body", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    
    t.index ["commentable_type", "commentable_id"], name: "index_comments_on_commentable"
  end

  create_table "users", force: :cascade do |t|
    t.string "email", null: false
    t.string "password_digest", null: false
    t.string "name"
    t.integer "role", default: 0  # contributor, reviewer, admin
    t.string "primary_language"
    t.string "invitation_token"
    t.datetime "invitation_sent_at"
    t.datetime "invitation_accepted_at"
    t.integer "invited_by_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
  end

  create_table "entry_versions", force: :cascade do |t|
    t.integer "entry_id", null: false
    t.integer "user_id", null: false
    t.json "changes_made", null: false
    t.string "change_type"  # create, update, verify
    t.datetime "created_at", null: false
    
    t.index ["entry_id"], name: "index_entry_versions_on_entry_id"
  end

  create_table "supported_languages", force: :cascade do |t|
    t.string "code", null: false
    t.string "name", null: false
    t.string "native_name", null: false
    t.integer "sort_order", default: 0
    t.boolean "active", default: true
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    
    t.index ["code"], name: "index_supported_languages_on_code", unique: true
  end

  add_foreign_key "suggested_meanings", "entries"
  add_foreign_key "suggested_meanings", "supported_languages", column: "language_code", primary_key: "code"
  add_foreign_key "suggested_meanings", "users", column: "submitted_by_id"
  add_foreign_key "suggested_meanings", "users", column: "reviewed_by_id"
  add_foreign_key "comments", "users"
  add_foreign_key "entries", "users", column: "created_by_id"
  add_foreign_key "entries", "users", column: "updated_by_id"
  add_foreign_key "entry_versions", "entries"
  add_foreign_key "entry_versions", "users"
end

Initial Data

See 'public/Kristillisyyden sanasto ver 23.5.2013.xlsx'


User Roles & Permissions

Action Public Contributor Reviewer Admin
View entries
Search entries
Create entry
Edit entry
Add comment
Submit suggested meaning
Review suggested meanings
Mark entry as verified
Invite new users
Manage users

Features

Public Features

Search & Browse

  • Full-text search across all languages
  • Filter by category
  • Alphabetical browsing per language
  • View entry with all translations
  • Download the entries table as an XLSX file, without :id attribute

Contributor Features

Entry Management

  • Create new entries with translations in known languages
  • Edit existing translations
  • Leave empty translations for others to fill in
  • Add notes/context to entries
  • View edit history

Discussion

  • Add comments to entries
  • Submit alternative translations as suggested meanings
  • Participate in translation discussions

Reviewer Features

Quality Control

  • Review and approve/reject suggested meanings
  • Mark entries as verified
  • Merge duplicate entries

Admin Features

User Management

  • Send invitations via email
  • Assign/change user roles
  • Deactivate users

System Management

  • Bulk import/export (CSV)
  • Database backup

User Interface

Pages

  1. Home/Search — Search box, quick stats, recent entries
  2. Browse — Alphabetical listing with language selection
  3. Entry View — Single entry with all translations, comments, suggested meanings
  4. Entry Edit — Form for editing translations (contributors only)
  5. New Entry — Form for creating entries (contributors only)
  6. Suggested Meanings Queue — List for reviewers
  7. User Profile — Personal settings, contribution history
  8. Admin Dashboard — User management, invitations, stats

Design Principles

  • Clean, readable typography (translations must be easy to read quickly)
  • Mobile-friendly (translators may use during services)
  • Fast search (primary use case)
  • Clear visual distinction between verified and unverified entries

API (Optional Future)

REST API for potential mobile app or integration:

GET    /api/entries
GET    /api/entries/:id
GET    /api/entries/search?q=:query&lang=:code
POST   /api/entries (authenticated)
PATCH  /api/entries/:id (authenticated)

Deployment

Server: Single VPS with Kamal Database: SQLite with Litestream for replication/backup Assets: Propshaft (Rails 8 default) Background Jobs: Solid Queue (for invitation emails)

Future Considerations

Export to PDF/print format for offline use Audio pronunciation recordings Mobile app Offline mode with sync Additional languages via migration

Description
Sanasto Wiki is a web-based glossary for the living Christianity.
Readme 1.6 MiB
Languages
Ruby 56.7%
HTML 41%
JavaScript 0.8%
Dockerfile 0.7%
Shell 0.7%
Other 0.1%