Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support customizable language #13

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions docs/.vitepress/locale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function getLocaleConfig(lang: string) {
const urlPrefix = lang && lang !== 'en' ? `/${lang}` : '';
const title = t('React Tiptap Editor');
const description = t(
'A modern WYSIWYG rich text editor based on tiptap and shadcn ui for Reactjs',
'A modern WYSIWYG rich text editor based on tiptap and shadcn ui for React',
);

const head: HeadConfig[] = [
Expand Down Expand Up @@ -50,6 +50,10 @@ export function getLocaleConfig(lang: string) {
text: t('Getting Started'),
link: `${urlPrefix}/guide/getting-started`,
},
{
text: t('Internationalization'),
link: `${urlPrefix}/guide/internationalization`,
},
],
},
{
Expand Down Expand Up @@ -133,7 +137,7 @@ export function getLocaleConfig(lang: string) {
},
{
text: t('Column'),
link: '/extensions/column/multilple-column.md',
link: '/extensions/column/multiple-column.md',
},
{
text: t('Iframe'),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Multilple Column
description: Multiple Column

next:
text: Iframe
Expand Down
2 changes: 1 addition & 1 deletion docs/extensions/table/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Table

next:
text: Column
link: /extensions/column/multilple-column.md
link: /extensions/column/multiple-column.md
---

## Usage
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
description: How to install reactjs-tiptap-editor

next:
text: Alignment
link: /extensions/align/text-align.md
text: Internationalization
link: /guide/internationalization.md
---

# Installation
Expand Down
55 changes: 55 additions & 0 deletions docs/guide/internationalization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
description: Internationalization

next:
text: Alignment
link: /extensions/align/text-align.md
---

# Internationalization (i18n)

The editor provides built-in internationalization support, with English as the default language.

## Usage

```javascript
// Import the locale object
import { locale } from 'reactjs-tiptap-editor'
// Set the language to English
locale.setLang('en')
// End
```

## Supported Languages

Currently, the editor supports the following languages:

| Language | Config | Version |
|--------------------|--------|----------------------------------------------------------------------------------|
| English | en | [v0.0.5](https://github.com/hunghg255/reactjs-tiptap-editor/releases/tag/v0.0.5) |
| Vietnamese | vi | |
| Simplified Chinese | zh_CN | |

## Adding a New Language

If the platform doesn't support your desired language, you can add a custom language, for example: `fr`.

```javascript
// Don't worry about which content to translate; setMessage supports TypeScript
locale.setMessage('fr', {
'editor.remove': 'Supprimer'
// ...
})
```

### Overriding Default Language

To override part of the current language system, first choose a new language name, then import the default language data, and finally override the translations you want.

```javascript
import { en } from 'reactjs-tiptap-editor'
locale.setMessage("en_US", {
...en,
"editor.remove": "Delete"
})
```
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"main": "./lib/reactjs-tiptap-editor.cjs",
"module": "./lib/reactjs-tiptap-editor.js",
"types": "./lib/index.d.ts",
"description": "A modern WYSIWYG rich text editor based on tiptap and shadcn ui for React",
"packageManager": "[email protected]",
"exports": {
".": {
Expand Down
4 changes: 2 additions & 2 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ export * from '@/extensions'

export { default } from '@/components/RcTiptapEditor'

import locale from './locales'
import locale, { en, vi, zh_CN } from './locales'

export { locale }
export { locale, en, vi, zh_CN }
2 changes: 1 addition & 1 deletion src/locales/en.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const locale: Record<string, string> = {
const locale = {
'editor.remove': 'Remove',
'editor.copy': 'Copy',
'editor.words': 'WORDS',
Expand Down
32 changes: 24 additions & 8 deletions src/locales/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,24 @@ import mitt from '@/utils/mitt'
import type { EventType } from '@/utils/mitt'
import { DEFAULT_LANG_VALUE } from '@/constants'

type LanguageType = 'en' | 'vi' | 'zh_CN'
// Define supported language types
type LanguageType = 'en' | 'vi' | 'zh_CN' | string

// Define message key types based on the 'en' locale
type MessageKeysType = keyof typeof en

// Interface for locale configuration
interface LocaleInterface {
lang: LanguageType
message: Record<LanguageType, Record<string, string>>
message: Record<LanguageType, Record<MessageKeysType, string>>
}

// Interface for Mitt events
interface MittEvents extends Record<EventType, unknown> {
lang: LanguageType
}

// Default locale configuration
export const DEFAULT_LOCALE: LocaleInterface = {
lang: DEFAULT_LANG_VALUE,
message: {
Expand All @@ -35,6 +42,7 @@ class Locale {
this.emitter = mitt<MittEvents>()
}

// Getter and setter for current language
get lang(): LanguageType {
return DEFAULT_LOCALE.lang
}
Expand All @@ -51,27 +59,32 @@ class Locale {
this.emitter.emit('lang', lang)
}

get message(): Record<LanguageType, Record<string, string>> {
// Getter and setter for messages
get message(): Record<LanguageType, Record<MessageKeysType, string>> {
return DEFAULT_LOCALE.message
}

set message(message: Record<LanguageType, Record<string, string>>) {
set message(message: Record<LanguageType, Record<MessageKeysType, string>>) {
DEFAULT_LOCALE.message = message
}

loadLangMessage(lang: LanguageType): Record<string, string> {
// Load messages for a specific language
loadLangMessage(lang: LanguageType): Record<MessageKeysType, string> {
return this.message[lang]
}

// Check if a language is supported
private isLangSupported(lang: LanguageType): boolean {
const supportedLangs = Object.keys(this.message) as LanguageType[]
return supportedLangs.includes(lang)
}

// Set the current language
public setLang(lang: LanguageType) {
this.lang = lang
}

// Register a language change watcher
public registerWatchLang(hook: (lang: LanguageType) => void) {
this.emitter.on('lang', hook)

Expand All @@ -84,25 +97,28 @@ class Locale {
}
}

public setMessage(lang: LanguageType, message: Record<string, string>) {
// Set messages for a specific language
public setMessage(lang: string, message: Record<MessageKeysType, string>) {
this.message[lang] = message
}

// Build a translation function for a given language
buildLocalesHandler(lang?: LanguageType) {
if (!lang) {
lang = this.lang
}

const message = this.loadLangMessage(lang)

return function t(path: string): string {
return function t(path: MessageKeysType) {
return message[path] || path
}
}
}

const locale = new Locale()

// Proxy for reactive language state
const atomLang = proxy({
lang: DEFAULT_LOCALE.lang,
})
Expand Down Expand Up @@ -131,7 +147,7 @@ function useLocale() {
}

const localeActions = {
t: (path: string) => {
t: (path: MessageKeysType) => {
return locale.buildLocalesHandler(atomLang.lang)(path)
},
}
Expand Down
2 changes: 1 addition & 1 deletion src/locales/vi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const locale: Record<string, string> = {
const locale = {
'editor.remove': 'Xóa',
'editor.copy': 'Sao chép',
'editor.words': 'TỪ',
Expand Down
Loading