1.2.0 • Published 12 months ago

@norman-huth/translator-js v1.2.0

Weekly downloads
-
License
MIT
Repository
-
Last release
12 months ago

TranslatorJs

JavaScript (JSON) Translator based on Laravel™ Translator. The Translator supports variables (optional with first charakter uppercase or complete uppercase) and pluralization.

Installation

Using PNPM

pnpm add -D @norman-huth/translator-js

Using NPM

npm i -D @norman-huth/translator-js

Contents

Example:

Example JSON-File with translations:

{
  "Hello": "Hallo",
  "Welcome, :name": "Willkommen :name",
  "Good morning :name": "Guten Morgen :Name",
  "Good evening :name": "Guten Abend :NAME",
  "There is one apple|There are many apples": "Hay una manzana|Hay muchas manzanas",
  "apples": "{0} There are none|[1,19] There are some|[20,*] There are many",
  "minutes_ago": "{1} :value minute ago|[2,*] :value minutes ago"
}
UsageResultNote
trans('Hello')Hallo
trans('Welcome, :name', {name: 'Norman'})Willkommen Norman
trans('Good morning :name', {name: 'norman'})Guten Morgen Norman:Name
trans('Good evening :name', {name: 'norman'})Guten Abend NORMAN:NAME
trans_choice('There is one apple\|There are many apples', 1)Hay una manzana
trans_choice('There is one apple\|There are many apples', 5)Hay muchas manzanas
trans_choice('apples', 0)There are none
trans_choice('apples', 12)There are some
trans_choice('apples', 22)There are many
trans_choice('minutes_ago', 1, {value: 1})1 minute ago
trans_choice('minutes_ago', 5, {value: 5})5 minutes ago

Usage

Simple VanillaJs

import Translator from '@norman-huth/translator-js'

const Trans = new Translator()

return Trans.trans('Hello')

Or create alternativ an "empty" instance:

Translator.factory()
Translator.factory(translations)

Laravel™ with Inertia.js

Share the App JSON-Translations via HandleInertiaRequests middleware.

class HandleInertiaRequests extends Middleware
{
    // --

    /**
     * Define the props that are shared by default.
     *
     * @return array<string, mixed>
     */
    public function share(Request $request): array
    {
        return [
            ...parent::share($request),
            'translations' => $this->jsonTranslations(),
        ];
    }

    /**
     * Load the messages for the given locale.
     *
     * @return array<string, string>
     */
    protected function jsonTranslations(): array
    {
        return app('translator')
            ->getLoader()
            ->load(app()->getLocale(), '*', '*');
    }
}

Vue.js / React / VanillaJs etc

Add the Translator to the /resources/js/bootstrap.{js|ts}. This example add the alias __() for trans(). This makes it possible to use trans() or __() for translation well as in Laravel™.

import Translator from '@norman-huth/translator-js'

const JsonTranslator = new Translator()

window.__ = function(key, replace = {}) {
  return JsonTranslator.trans(key, replace)
}
window.trans = function(key, replace = {}) {
  return JsonTranslator.trans(key, replace)
}
window.trans_choice = function(key, number, replace = {}) {
  return JsonTranslator.trans_choice(key, number, replace)
}

TypeScript:

//...
window.__ = function(key: string, replace = {}) {
  return JsonTranslator.trans(key, replace)
}
window.trans = function(key: string, replace = {}) {
  return JsonTranslator.trans(key, replace)
}
window.trans_choice = function(key: string, number: number, replace = {}) {
  return JsonTranslator.trans_choice(key, number, replace)
}
Vue.js

To have the functions also available in the <template>, edit the /resources/js/app.{js|ts} and add the functions as mixin:

createInertiaApp({
  //...
  setup({ el, App, props, plugin }) {
    return createApp({ render: () => h(App, props) })
      .use(plugin)
      .mixin({
        methods: {
          __: function(key, replace = {}) {
            return __(key, replace)
          },
          trans: function(key, replace = {}) {
            return trans(key, replace)
          },
          trans_choice: function(key, number, replace = {}) {
            return trans_choice(key, number, replace)
          }
        }
      })
      .mount(el);
  },
  //...
})

TypeScript:

//..
__: function(key: string, replace = {}) {
  return __(key, replace)
},
trans: function(key: string, replace = {}) {
  return trans(key, replace)
},
trans_choice: function(key: string, number: number, replace = {}) {
  return trans_choice(key, number, replace)
}
Optional: TypeScript

Extend the /resources/js/types/global.d.ts file.

//...
const JsonTranslator = new Translator()
const __ = (key: string, replace = {}) => {
  return JsonTranslator.translator(key, replace)
}
const trans = (key: string, replace = {}) => {
  return JsonTranslator.translator(key, replace)
}
const trans_choice = (key, number, replace = {}) => {
  return JsonTranslator.trans_choice(key, number, replace)
}

declare global {
  interface Window {
    axios: AxiosInstance;
    __: typeof __
    trans: typeof trans
    trans_choice: typeof trans_choice
  }

  let __ = function(key: string, replace = {}) {
    return JsonTranslator.trans(key, replace)
  }
  let trans = function(key: string, replace = {}) {
    return JsonTranslator.trans(key, replace)
  }
  let trans_choice = function(key, number, replace = {}) {
    return JsonTranslator.trans_choice(key, number, replace)
  }
  //..
}

// And for Vue.js <template>
declare module 'vue' {
  interface ComponentCustomProperties {
    // ...
    __: typeof __
    trans: typeof trans
    trans_choice: typeof trans_choice
  }
}
Optional: ESLint

.eslintrc.cjs

module.exports = {
  globals: {
    __: true,
    trans: true,
    trans_choice: true,
  },
}

Digging Deeper

The locale is only used from the pluralizer.

The Translator Constructor

This script is oriented towards Inertia.js and determines the translation from the JSON ({"translations": {}}) of the data-page attribute in the div id="app". and the locale by <html lang="en"> tag. By default the class bootstrap the translations data.

The Constructor with defaults:

constructor(
  prop: string = 'translations',
  elementId: string = 'app',
  dataAttribute: string = 'page',
  locale: string | null = null,
  translations: Translations | null = null,
  bootstrap: boolean = true
)
ArgumentDefaultDescription
proptranslationsThe page props key with the translations
elementIdappThe ID of the described div
dataAttributepageThe div data-* attribute
localenullInitialize the class with locale (override on bootrap)
translationsnullInitialize the class with translations (override on bootrap)
bootstraptrueBootrap the translations' data.

Translator.setTranslations

Manually set the translations.

Translator.setTranslations(
  { "Foo": "Bar" }
)

Translator.setLocale

Manually set the locale.

Translator.setLocale('en')

Translator.bootstrap

Bootrap the translations' data (again).

Translator.bootstrap()

Example: Other Inertia.js Share Key

Change the array for the translations.

class HandleInertiaRequests extends Middleware
{
    public function share(Request $request): array
    {
        return [
            ...parent::share($request),
            'app' => [
                'translations' => $this->jsonTranslations(),
            ],
        ];
    }
}

Set nested array by using "dot" notation in the Translator script:

import Translator from '@norman-huth/translator-js'

const JsonTranslator = new Translator('app.translations')
1.2.0

12 months ago

1.1.1

12 months ago

1.1.2

12 months ago

1.1.0

1 year ago

1.0.0

1 year ago

0.0.6

1 year ago

0.0.5

1 year ago

0.0.4

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago