Skip to content

Localization (i18n)

The editor ships with built-in English and German translations for all UI strings — toolbar labels, command descriptions, outline placeholders, and accessibility text.

Switching the Language

Via HTML attribute

The <sciflow-editor> element accepts a locale attribute. Set it declaratively or update it at runtime — the editor and all connected components switch immediately.

<!-- Set the initial locale declaratively -->
<sciflow-editor locale="de"></sciflow-editor>
// Or change it at runtime via the DOM property
document.querySelector('sciflow-editor').locale = 'en';

Via JavaScript

import { setLocale } from '@sciflow/editor-start';
// or: import { setLocale } from '@sciflow/editor-core';

// Switch to German
setLocale('de');

// Switch back to English
setLocale('en');

When setLocale() is called:

  1. The internal locale updates immediately.
  2. A sciflow-locale-change CustomEvent fires on document.
  3. All mounted components re-render with the new strings.
  4. Command metadata (tooltips, aria-labels) resolves to the new locale on next read.

No editor restart or feature re-initialization is needed.

Reading the Current Locale

import { getLocale } from '@sciflow/editor-start';

console.log(getLocale()); // 'en' | 'de'

Available Locales

Code Language
en English (default)
de German

Using the Translation Function Directly

If you build custom UI around the editor, you can use t() to access any translation key:

import { t } from '@sciflow/editor-start';

const label = t('cmd.insertNativeTableFigure.label');
// English: "Insert table"
// German:  "Tabelle einfügen"

Listening for Locale Changes

Custom components can react to locale switches by listening for the event:

import { LOCALE_CHANGE_EVENT } from '@sciflow/editor-start';

document.addEventListener(LOCALE_CHANGE_EVENT, (event) => {
  const { locale } = event.detail;
  console.log(`Locale changed to: ${locale}`);
});

Adding Custom Translations

If you build custom UI components around the editor, use registerTranslations() to add your own keys to the shared dictionary. This way your components use the same t() function and react to the same setLocale() calls — no separate i18n system needed.

import { registerTranslations, t } from '@sciflow/editor-start';

// Register translations for each locale you support
registerTranslations('en', {
  'myApp.sidebar.title': 'My Sidebar',
  'myApp.exportButton': 'Export PDF',
});

registerTranslations('de', {
  'myApp.sidebar.title': 'Meine Seitenleiste',
  'myApp.exportButton': 'PDF exportieren',
});

// Use the same t() everywhere
const label = t('myApp.sidebar.title');

Custom keys are resolved before built-in keys, so you can also override any built-in string if needed. Subsequent calls for the same locale merge into the existing entries.

Namespace your keys

Use a prefix like myApp. or acme. to avoid collisions with current or future built-in keys.

Lit Component Example

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { t, LOCALE_CHANGE_EVENT, registerTranslations } from '@sciflow/editor-start';

registerTranslations('en', { 'myWidget.heading': 'Dashboard' });
registerTranslations('de', { 'myWidget.heading': 'Übersicht' });

@customElement('my-widget')
class MyWidget extends LitElement {
  private localeListener?: EventListener;

  connectedCallback(): void {
    super.connectedCallback();
    this.localeListener = () => this.requestUpdate();
    document.addEventListener(LOCALE_CHANGE_EVENT, this.localeListener);
  }

  disconnectedCallback(): void {
    if (this.localeListener) {
      document.removeEventListener(LOCALE_CHANGE_EVENT, this.localeListener);
    }
    super.disconnectedCallback();
  }

  render() {
    return html`<h2>${t('myWidget.heading')}</h2>`;
  }
}

React Component Example

import { useEffect, useState } from 'react';
import { t, registerTranslations, LOCALE_CHANGE_EVENT, getLocale } from '@sciflow/editor-start';

registerTranslations('en', { 'myPanel.title': 'Analytics' });
registerTranslations('de', { 'myPanel.title': 'Auswertungen' });

function MyPanel() {
  const [, setLocale] = useState(getLocale());

  useEffect(() => {
    const handler = (e: Event) => setLocale((e as CustomEvent).detail.locale);
    document.addEventListener(LOCALE_CHANGE_EVENT, handler);
    return () => document.removeEventListener(LOCALE_CHANGE_EVENT, handler);
  }, []);

  return <h2>{t('myPanel.title')}</h2>;
}

Integration with PKP OJS

PKP OJS has its own XML-based locale system (locale/<code>/locale.xml). An OJS plugin can bridge the two systems so the editor inherits whatever language OJS is currently using.

Mapping OJS locale strings to the editor

In your plugin's page or template handler, read the OJS locale and pass the editor's built-in keys through registerTranslations():

// In your OJS plugin (PHP side)
// Pass the current OJS locale and any custom strings to the frontend
$templateMgr->assign('ojsLocale', AppLocale::getLocale());        // e.g. "de_DE"
$templateMgr->assign('editorStrings', json_encode([
    'myPlugin.submitManuscript' => __('plugins.generic.sciflow.submitManuscript'),
    'myPlugin.saveProgress'     => __('plugins.generic.sciflow.saveProgress'),
]));
<!-- In your Smarty template -->
<sciflow-editor id="editor" locale="{$ojsLocale|substr:0:2}"></sciflow-editor>

<script type="module">
  import { registerTranslations, setLocale } from '@sciflow/editor-start';

  // Register plugin-specific strings translated via OJS's locale XML
  const strings = {$editorStrings|json_encode};
  const locale = '{$ojsLocale|substr:0:2}'; // "de_DE" → "de"

  registerTranslations(locale, strings);
  setLocale(locale);
</script>

OJS locale XML example

Add your plugin's editor strings to the standard OJS locale file:

<!-- plugins/generic/sciflow/locale/en/locale.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<locale name="en" full_name="English">
  <message key="plugins.generic.sciflow.submitManuscript">Submit Manuscript</message>
  <message key="plugins.generic.sciflow.saveProgress">Save Progress</message>
</locale>
<!-- plugins/generic/sciflow/locale/de/locale.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<locale name="de" full_name="Deutsch">
  <message key="plugins.generic.sciflow.submitManuscript">Manuskript einreichen</message>
  <message key="plugins.generic.sciflow.saveProgress">Fortschritt speichern</message>
</locale>

How it works

  1. OJS determines the active locale as usual (user preference, journal default).
  2. The plugin reads OJS locale strings with __() and passes them to JavaScript.
  3. registerTranslations() merges them into the editor's dictionary.
  4. The locale attribute on <sciflow-editor> (or a setLocale() call) activates the matching language.
  5. Built-in editor strings (toolbar, commands, accessibility labels) switch automatically. Plugin-specific strings resolve through the same t() function.

The editor ships with English and German built-in. For other OJS-supported languages, use registerTranslations() to provide translations for the editor's built-in keys as well — they are listed in the translation key reference below.

OJS locale codes

OJS uses codes like de_DE, fr_FR, es_ES. The editor expects the two-letter language prefix (de, fr, es). Extract it with substr(0, 2) or equivalent.

Sub-path Import

The i18n module is also available as a dedicated sub-path export:

import { setLocale, t } from '@sciflow/editor-core/i18n';

Server-Side / Node.js

setLocale() and t() work in Node.js. The CustomEvent dispatch is skipped when document is unavailable, so the runtime is safe for SSR.