# 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 We currently support the following languages: * Finnish * English * Swedish * Norwegian * Russian * German ### Entry An entry represents a translatable unit which may be: - `word` — Single word - `phrase` — Multi-word expression or idiom, sentence - `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 --- ## 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, 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 Found in '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 --- ## 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 | --- ## User Interface ### Pages 1. **Home/Search** — Search box, quick stats, recent entries 2. **Browse** — Alphabetical listing with language tabs 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