Learn Language
unlistedby Juanjo Arranz
Advanced Learn Language Management for Obsidian
Learn Language Plugin for Obsidian
A flexible language learning management plugin for Obsidian that supports any language pair. Features dictionary management, verb conjugation reference, interactive filtering, and OpenAI integration for AI-assisted term creation.
Features
๐ Multi-Language Support
- Configurable language pair: Learn any language from any source language
- Supports 25+ languages with automatic locale-based sorting
- Dynamic UI labels based on your configured languages
๐ Dictionary Management
- View and filter all dictionary entries from your vault
- Advanced filtering by target word, source translation, type, context, and revision status
- Pagination support for large dictionaries
- Quick access via ribbon icon or command palette
๐ค Verb Conjugation Reference
- Dedicated view for verb entries
- Filter by verb group (1, 2, 3, irregular)
- Display conjugations: Prรฉsent, Subjonctif, Imparfait, Passรฉ composรฉ, Futur
- Track irregular verbs
๐ Study Mode (Flashcards)
- Toggle between normal view and study mode
- Target โ Source or Source โ Target directions
- Collapsible answers for self-testing
- Works in both Dictionary and Verbs views
๐ค OpenAI Integration
- AI-assisted term creation and classification
- Automatic translation suggestions
- Term type and context classification based on your custom taxonomies
- Auto-sync of type/context files with OpenAI Assistant
๐ Advanced Filtering
- Filter by any property (target word, source word, Type, Context, Revision)
- Type-ahead search for target and source word filters (real-time filtering as you type)
- Hierarchical tag expansion (e.g.,
#verbe/rรฉgulier/1matches#verbe) - Locale-aware sorting based on target language
- Filter state persistence
๐ Embed Dictionary in Notes
- Use the
learn-dictionarycode block to embed an interactive dictionary directly in any note - Full filtering and pagination support within the embedded view
- Same UI and functionality as the sidebar view
- Configure initial filters via YAML-like options
- Optional export of the currently filtered results to a delimited
.txtfile
Installation
From Obsidian Community Plugins (Coming Soon)
- Open Settings โ Community plugins
- Search for "Learn Language"
- Install and enable
Manual Installation
- Download the latest release from GitHub
- Extract to your vault's
.obsidian/plugins/learn-language/folder - Reload Obsidian
- Enable the plugin in Settings โ Community plugins
Build from Source
cd learn-language-plugin
npm install
npm run build
Copy main.js, manifest.json, and styles.css to your vault's .obsidian/plugins/learn-language/ folder.
Configuration
Go to Settings โ Learn Language to configure:
Language Configuration
- Target language: The language you are learning (e.g., French, German, Italian)
- Source language: Your native/source language (e.g., Spanish, English)
The plugin automatically determines the correct locale for sorting based on the language name. Supported languages include: French, Spanish, Italian, Portuguese, German, English, Dutch, Swedish, Russian, Polish, Japanese, Chinese, Korean, Greek, Turkish, Arabic, and many more.
Note: The language names are also used to find the corresponding frontmatter fields in your notes. For example, if
Target languageis "French" andSource languageis "Spanish", the plugin will look forFrench:andSpanish:fields in your note frontmatter.
Folder Paths
- Dictionary folder: Where your dictionary entries are stored (default:
10. Dictionary) - Verbs folder: Optional separate folder for verbs
- Grammar folder: Grammar resources location
- Templates folder: Note templates location
Classification Files
- Term types file: File containing term type definitions (e.g.,
#verbe,#nom,#expression) - Context types file: File containing context definitions (e.g.,
#social,#culinary)
OpenAI Settings
- API Key: Your OpenAI API key
- Auto-sync: Automatically update types/context files in OpenAI when they change
Usage
Commands
Access via Command Palette (Ctrl/Cmd + P):
| Command | Description |
|---|---|
| Open Dictionary View | Open the dictionary browser |
| Open Verbs View | Open the verbs browser |
| Create New Term | Open modal to create a new dictionary entry |
| Ask AI for Term | Quick AI lookup and term creation |
| Edit Current Term | Edit the currently open dictionary entry |
| Refresh Dictionary Cache | Force reload of dictionary data |
| Reset OpenAI Conversation | Start fresh AI conversation thread |
Ribbon Icons
- ๐ Book icon: Open Dictionary View
- ๐ฃ๏ธ Languages icon: Open Verbs View
- โ Plus icon: Create New Term
Dictionary Entry Structure
Your dictionary entries should follow this structure:
---
Spanish: translation
cssclasses:
- ja-readable
---
Type:: #verbe/rรฉgulier/1
Synonyms::
Context:: #social/greetings
Examples:: Bonjour, comment allez-vous?<br>Bonjour ร tous!
Rating:: #โญโญ
Relations::
Revision:: 1
Project:: [[Learn French]]
Embedding Dictionary in Notes
You can embed an interactive dictionary view directly in any note using the learn-dictionary code block:
```learn-dictionary
type: verb
context: A1
pageSize: 25
```
Available Options
| Option | Description | Default |
|---|---|---|
targetWord | Initial filter for target word (type-ahead search) | all |
sourceWord | Initial filter for source word (type-ahead search) | all |
type | Filter by type (verb, noun, expression, etc.) | all |
context | Filter by context (A1, A2, social, etc.) | all |
revision | Filter by revision status | all |
study | Study mode (no, yes, source) | no |
limit | Maximum number of entries to load | no limit |
pageSize | Entries per page | 50 |
showStudy | Show study mode toggle | true |
showPagination | Show pagination controls | true |
allowExport | Show an Export button to export filtered results | false |
Export (TXT)
When allowExport: true, an Export button is displayed in the embedded dictionary.
Clicking Export opens a modal that exports the currently filtered rows to a delimited .txt file.
Modal options:
- Pages: export all pages (default) or select specific pages from the filtered result set
- File name: output file name (default:
dictionary-export.txt) - Folder: absolute folder path where the file will be saved (includes a desktop folder picker)
- Separator: field separator (
|default, or;) - Fields: choose which fields to export (checkboxes)
Special handling:
- If Examples is selected, exported values:
- Replace
<br>/<br/>/<br />with real newlines - Remove italics (both HTML
<em>/<i>and markdown emphasis like*text*/_text_)
- Replace
Note: The folder picker and writing to an absolute path require Obsidian Desktop.
Examples
Show only verbs with context A1:
```learn-dictionary
type: verb
context: A1
pageSize: 20
```
Simple embedded dictionary with 100 entries max:
```learn-dictionary
limit: 100
showStudy: false
```
Full dictionary with all options:
```learn-dictionary
type: expression
context: social
pageSize: 50
showStudy: true
showPagination: true
```
Note: The embedded dictionary uses the same
DictionaryComponentas the sidebar view, so all interactive features (type-ahead search, filters, pagination, study mode) work identically.
Global API (Dataview Compatibility)
The plugin exposes a global API for use in Dataview scripts:
// Access the plugin API
const learnLanguage = app.plugins.plugins["learn-language"];
const api = learnLanguage.api;
// Get language configuration
const targetLang = api.targetLanguage; // e.g., "French"
const sourceLang = api.sourceLanguage; // e.g., "Spanish"
// Get all dictionary entries
const entries = await api.getDictionary();
// Get all verbs
const verbs = await api.getVerbs();
// Get grammar pages
const grammar = await api.getGrammarPages();
// Filter entries
const filtered = api.filterEntries(entries, {
type: "#verbe",
context: "#social"
});
// Paginate results
const page = api.paginateEntries(filtered, 0, 100);
// Ask AI for a term
const response = await api.askAI("bonjour");
// Create a new term
await api.createTerm({
targetWord: "bonjour",
sourceWord: "hola",
type: "#expression",
context: "#social/greetings"
});
Entry Structure
Dictionary entries returned by the API have these properties:
| Property | Description |
|---|---|
file | Object with path, name, basename |
targetWord | The word in target language (lowercase) |
sourceWord | Translation in source language (lowercase) |
type | Term type tags (e.g., #verbe, #nom) |
context | Context tags (e.g., #social, #culinary) |
revision | Revision status (new, 1, 2, etc.) |
rating | Optional rating |
examples | Usage examples |
synonyms | Related synonyms |
relations | Related terms |
project | Associated project |
Example: Dynamic Table Headers
const api = app.plugins.plugins["learn-language"].api;
const entries = await api.getDictionary();
// Use configured language names as headers
dv.table(
[api.targetLanguage, api.sourceLanguage, "Type", "Examples"],
entries.slice(0, 20).map(e => [
dv.fileLink(e.file.path, false, e.file.name),
e.sourceWord || "",
e.type || "",
e.examples || ""
])
);
Migration from Dataview Scripts
If you're migrating from the previous Dataview-based implementation:
- Install the plugin and configure folder paths in settings
- Keep your existing queries - they'll continue to work via the global API
- Gradually migrate to plugin views for better performance
- Move OpenAI settings from JSON file to plugin settings
Legacy Support
The plugin includes CSS classes from the original implementation:
ja-readable,ja-dictionary,ja-mobileja-sticky-header,ja-table-verbsja-filter-active,ja-collapsible
Development
# Install dependencies
npm install
# Build for development (watch mode)
npm run dev
# Build for production
npm run build
Project Structure
learn-language-plugin/
โโโ src/
โ โโโ main.ts # Plugin entry point
โ โโโ types.ts # TypeScript types and interfaces
โ โโโ settings.ts # Settings tab
โ โโโ services/
โ โ โโโ DictionaryService.ts # Data management
โ โ โโโ OpenAIService.ts # AI integration
โ โ โโโ TermService.ts # Term CRUD operations
โ โ โโโ FilterService.ts # Filtering logic
โ โโโ context/
โ โ โโโ LearnLanguageContext.tsx # React context provider
โ โโโ hooks/
โ โ โโโ useFilters.ts # Filter state management hook
โ โ โโโ usePagination.ts # Pagination hook
โ โ โโโ useFilteredEntries.ts # Filtered data hook
โ โ โโโ useTypeAhead.ts # Type-ahead search hook
โ โ โโโ useDebounce.ts # Debounce utility hook
โ โโโ views/
โ โ โโโ DictionaryView.tsx # Dictionary sidebar (React)
โ โ โโโ VerbsView.tsx # Verbs sidebar (React)
โ โโโ components/
โ โ โโโ dictionary/
โ โ โ โโโ DictionaryComponent.tsx # Main dictionary component
โ โ โโโ verbs/
โ โ โ โโโ VerbsComponent.tsx # Main verbs component
โ โ โ โโโ VerbsTable.tsx # Verbs table with conjugations
โ โ โโโ filters/
โ โ โ โโโ TypeAheadFilter.tsx # Type-ahead search input
โ โ โ โโโ DropdownFilter.tsx # Dropdown select filter
โ โ โ โโโ StudyToggle.tsx # Study mode toggle
โ โ โโโ table/
โ โ โโโ DictionaryTable.tsx # Dictionary entries table
โ โ โโโ Pagination.tsx # Pagination controls
โ โโโ processors/
โ โ โโโ DictionaryCodeBlockProcessor.tsx # Embed dictionary in notes
โ โโโ utils/
โ โ โโโ reactMount.tsx # React mounting utilities
โ โโโ modals/
โ โโโ TermModal.ts # Term create/edit modal
โโโ styles.css # Plugin styles
โโโ manifest.json # Plugin manifest
โโโ package.json # NPM configuration
โโโ tsconfig.json # TypeScript config (JSX support)
React Architecture
The plugin uses React 18 for all UI components:
- Context Provider (
LearnLanguageContext): Sharesapp,settings,filterService, anddictionaryServiceacross all components - Custom Hooks: Encapsulate state logic for filters, pagination, debouncing, and data fetching
- Component Composition: Modular components for filters, tables, and controls
- React Mounting: Views use
createRoot()for mounting React components within Obsidian's ItemView system
License
MIT License - see LICENSE file for details.
Author
Juanjo Arranz
Acknowledgments
- Built for use with the Obsidian Dataview plugin
- OpenAI GPT-4 for AI-assisted features
- Inspired by language learning methodologies
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.