Giter Site home page Giter Site logo

xico2k / laravel-vue-i18n Goto Github PK

View Code? Open in Web Editor NEW
563.0 10.0 48.0 876 KB

Allows to connect your `Laravel` Framework translation files with `Vue`.

License: MIT License

JavaScript 1.10% TypeScript 98.90%
javascript vue vuejs vue3 laravel laravel-framework typescript

laravel-vue-i18n's Introduction

Laravel Vue i18n

GitHub Workflow Status (master) License Version Total Downloads

laravel-vue-i18n is a Vue3 plugin that allows to connect your Laravel Framework translation files with Vue. It uses the same logic used on Laravel Localization.

Installation

With npm:

npm i laravel-vue-i18n

or with yarn:

yarn add laravel-vue-i18n

Setup

If you want to see a screencast on how to setup check out this video: How to use Laravel Vue i18n plugin.

With Vite

import { createApp } from 'vue'
import { i18nVue } from 'laravel-vue-i18n'

createApp()
    .use(i18nVue, {
        resolve: async lang => {
            const langs = import.meta.glob('../../lang/*.json');
            return await langs[`../../lang/${lang}.json`]();
        }
    })
    .mount('#app');

SSR (Server Side Rendering)

For Server Side Rendering the resolve method should not receive a Promise and instead take advantage of the eager param like this:

.use(i18nVue, {
    lang: 'pt',
    resolve: lang => {
        const langs = import.meta.glob('../../lang/*.json', { eager: true });
        return langs[`../../lang/${lang}.json`].default;
    },
})

PHP Translations Available on Vue

In order to load php translations, you can use this Vite plugin.

// vite.config.js
import i18n from 'laravel-vue-i18n/vite';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css'
            'resources/js/app.js',
        ]),
        vue(),

        // Laravel >= 9
        i18n(),

        // Laravel < 9, since the lang folder is inside the resources folder
        // you will need to pass as parameter:
        // i18n('resources/lang'),
    ],
});

Vite plugin options

In addition to that, you can use this Vite plugin with additional paths to load from, this is usefull when you are using a package that let's you override your translations, or in case you are getting your application's lang files from different paths.

Note that if one key found in two paths, priority will be given to the last given path between these two (In this example translation key will be loaded from public/locales)

// vite.config.js
import i18n from 'laravel-vue-i18n/vite';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css'
            'resources/js/app.js',
        ]),
        vue(),

        i18n({
            // you can also change your langPath here
            // langPath: 'locales' 
            additionalLangPaths: [
                'public/locales' // Load translations from this path too! 
            ]
        }),
    ],
});

During the npm run dev execution time, the plugin will create some files like this php_{lang}.json on your lang folder. And to avoid that to be commited to your code base, I suggest to your .gitignore this like:

lang/php_*.json

With Webpack / Laravel Mix

import { createApp } from 'vue'
import { i18nVue } from 'laravel-vue-i18n'

createApp()
    .use(i18nVue, {
        resolve: lang => import(`../../lang/${lang}.json`),
    })
    .mount('#app');

SSR (Server Side Rendering)

For Server Side Rendering the resolve method should receive a require instead of a Promise:

.use(i18nVue, {
    lang: 'pt',
    resolve: lang => require(`../../lang/${lang}.json`),
})

PHP Translations Available on Vue

In order to load php translations, you can use this Mix plugin.

const mix = require('laravel-mix');
require('laravel-vue-i18n/mix');

// Laravel >= 9
mix.i18n();

// Laravel < 9, since the lang folder is inside the resources folder
// you will need to pass as parameter:

// mix.i18n('resources/lang');

Usage

<template>
    <div>
        <h1>{{ $t('Welcome, :name!', { name: 'Francisco' }) }}. </h1>
        <div>Logged in {{ $tChoice('{1} :count minute ago|[2,*] :count minutes ago', 10) }}</div>
    </div>
</template>

Plugin Options

  • lang (optional): If not provided it will try to find from the <html lang="pt"> tag.
  • fallbackLang (optional): If the lang was not provided or is invalid, it will try reach for this fallbackLang instead, default is: en.
  • fallbackMissingTranslations (optional): If the lang is provided, but the translation key does not exist in that language it will fallback to the fallbackLang instead.
  • resolve (required): The way to reach your language files.
  • shared (optional): Whether to share the same I18n instance between different Vue apps, default is: true.
  • onLoad (optional): It's called everytime a language is loaded.
createApp().use(i18nVue, {
    lang: 'pt',
    resolve: lang => import(`../../lang/${lang}.json`),
})

trans(message: string, replacements: {})

The trans() method can translate a given message.

// lang/pt.json
{
    "Welcome!": "Bem-vindo!",
    "Welcome, :name!": "Bem-vindo, :name!"
}

import { trans } from 'laravel-vue-i18n';

trans('Welcome!'); // Bem-vindo!
trans('Welcome, :name!', { name: 'Francisco' }) // Bem-vindo Francisco!
trans('Welcome, :NAME!', { name: 'Francisco' }) // Bem-vindo FRANCISCO!

wTrans(message: string, replacements: {})

The wTrans() same as trans() but returns a reactive obj with translated value, use it instead of trans() to watch any changes (language changes or lang files loaded) and set the new value.

// lang/pt.json
{
    "Welcome!": "Bem-vindo!",
    "Welcome, :name!": "Bem-vindo, :name!"
}

import { wTrans } from 'laravel-vue-i18n';

setup() {
    return {
        welcomeLabel: wTrans('Welcome!'),
        welcomeFrancisco: wTrans('Welcome, :name!', { name: 'Francisco' })
    }
}

<template>
    <div>{{ welcomeLabel }}</div> // <div>Bem-vindo!</div>
    <div>{{ welcomeFrancisco }}</div> // <div>Bem-vindo, Francisco!</div>
</template>

transChoice(message: string, count: number, replacements: {})

The transChoice() method can translate a given message based on a count, there is also available an trans_choice alias, and a mixin called $tChoice().

// lang/pt.json
{
    "There is one apple|There are many apples": "Existe uma maça|Existe muitas maças",
    "{0} There are none|[1,19] There are some|[20,*] There are many": "Não tem|Tem algumas|Tem muitas",
    "{1} :count minute ago|[2,*] :count minutes ago": "{1} há :count minuto|[2,*] há :count minutos"
}

import { transChoice } from 'laravel-vue-i18n';

transChoice('There is one apple|There are many apples', 1); // Existe uma maça
transChoice('{0} There are none|[1,19] There are some|[20,*] There are many', 19); // Tem algumas
transChoice('{1} :count minute ago|[2,*] :count minutes ago', 10); // Há 10 minutos.

wTransChoice(message: string, count: number, replacements: {})

The wTransChoice() same as transChoice() but returns a reactive obj with translated value, use it instead of transChoice() to watch any changes (language changes or lang files loaded) and set the new value.

// lang/pt.json
{
    "There is one apple|There are many apples": "Existe uma maça|Existe muitas maças",
    "{0} There are none|[1,19] There are some|[20,*] There are many": "Não tem|Tem algumas|Tem muitas",
    "{1} :count minute ago|[2,*] :count minutes ago": "{1} há :count minuto|[2,*] há :count minutos"
}

import { wTransChoice } from 'laravel-vue-i18n';

setup() {
    return {
        oneAppleLabel: wTransChoice('There is one apple|There are many apples', 1),
        multipleApplesLabel: wTransChoice('{0} There are none|[1,19] There are some|[20,*] There are many', 19)
    }
}

<template>
    <div>{{ oneAppleLabel }}</div> // <div>Existe uma maça</div>
    <div>{{ multipleApplesLabel }}</div> // <div>Tem algumas</div>
</template>

loadLanguageAsync(lang: string)

The loadLanguageAsync() can be used to change the location during the runtime.

import { loadLanguageAsync } from 'laravel-vue-i18n';

<template>
    <div>{{ $t('Welcome!') }}</div>
    <button @click="loadLanguageAsync('pt')">Change to Portuguese Language</button>
</template>

getActiveLanguage()

The getActiveLanguage() returns the language that is currently being used.

import { getActiveLanguage } from 'laravel-vue-i18n';

const lang = getActiveLanguage(); // en

isLoaded(lang?: string)

The isLoaded() method checks if the language is loaded. If the lang parameter is not passed it will check for the actual language set.

import { isLoaded } from 'laravel-vue-i18n';

const loaded = isLoaded(); // true
const loaded = isLoaded('fr'); // false

Using multiple instances

Under the hood, the Vue plugin is using a I18n class which encapsulates all the translation logic and the currently active language. This means that it's possible to create multiple class instances, each with different options and active language. This can be useful for scenarios where part of the app needs to be translated to a language different from the main UI.

Note that loaded languages are still shared between different instances. This avoids loading the same set of translations multiple times. The main difference between different instances will be the currently active language.

import { I18n } from 'laravel-vue-i18n'

const resolver = lang => import(`./fixtures/lang/${lang}.json`)

const i18nEn = new I18n({
    lang: 'en',
    resolve: resolver
})
const i18nPt = new I18n({
    lang: 'pt',
    resolve: resolver
})

i18nEn.trans('Welcome!') // will output "Welcome!"
i18nPt.trans('Welcome!') // will output "Bem-vindo!"

By default, installing the the i18nVue plugin will create a shared instance. This instance is accessed when importing the translation functions, such as trans, directly. When using multiple Vue app instances, it's possible to either share the I18n instance between them, or have each app create its own instance.

Shared usage (default) - all Vue app instances will use the same I18n class and currently active language:

import { i18nVue } from 'laravel-vue-i18n'

const appA = createApp()
    .use(i18nVue, { lang: 'pt' })
    .mount('#app-1');

const appB = createApp()
    .use(i18nVue)
    .mount('#app-2');

// elsewhere
import { trans } from 'laravel-vue-i18n'

trans('Welcome!') // will output "Bem-vindo!"

Non-shared usage - each Vue app will have its own I18n instance & currently active language.

import { i18nVue } from 'laravel-vue-i18n'

const appA = createApp()
    .use(i18nVue, {
        lang: 'es'
        shared: false, // don't use the shared instance
    })
    .mount('#app-1');

const appB = createApp()
    .use(i18nVue, {
        lang: 'pt'
        shared: false, // don't use the shared instance
    })
    .mount('#app-2');

Accessing the shared instance

It's possible to access the shared instance via code as well:

import { I18n } from 'laravel-vue-i18n'

I18n.getSharedInstance()

Caveats

It is possible to import a translation function before installing the i18nVue plugin. When calling the translation function, ie trans(), and the plugin has not been installed, a shared I18n instance will be created with default options. This ensures that it's possible to import and call these functions without any fatal errors. However, this may yield undesired results. Therefore, it is advisable to never call any translation methods before the plugin is installed.

laravel-vue-i18n's People

Contributors

a-ghorab avatar aghorabhekouky avatar andreiio avatar askdkc avatar avpet979 avatar ckyoung avatar daniser avatar fa-braik avatar homcenco avatar kitro avatar lenssoft avatar majkie avatar markdegrootnl avatar naincykumariknoldus avatar quadrubo avatar rafalglowacz avatar ragulka avatar rozsazoltan avatar tfevan avatar tomcoonen avatar xico2k avatar yoeriboven avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-vue-i18n's Issues

Translation not loaded on initial page load composition api

Similarly to #62 , the translations aren't loaded yet when the composition api runs after the first page load.

Calling it inside of onMounted doesn't work either and I tried to make it work with the new onLoad callback from #70 but I didn't find a good way to do it (can't find a way to force a refresh and using stores/:key works but it adds unnecessary boilderplate and sub optimal).

I'm wondering if it would be possible to fix it the same way as #62
another solution I could see is something like the onMounted hook

This package or vue-i18n? Can't use both?

I was using the vue-i18n package primarily to format number strings.
https://vue-i18n.intlify.dev/
It seems I can't use both this package and vue-i18n since the APIs overlap somewhat (both use $t() helper for example).

Should I ditch vue-i18n and use something else for number formatting? Or is there some solution to be able to use both these packages? What are the advantages of laravel-vue-i18n over vue-i18n, apart from the php language files compilation?

Maybe you could add some clarification in the readme, since the names of these packages are so similar and someone might try to use both (like me :))

This is not a bug report, but I didn't know where I could ask these questions. I hope it's ok.

Ability to split language file into multiple objects

Is it possible to divide a translation file into multiple objects. So as an example:
"home": { "header": { "test": "test" }, "description": "description" }, "about-me": { "test": "test" } }

And that you can then call those keys with $t('home.header.test')?

If this isn't possible yet, isn't that an idea for a new feature?

Webpack is not generating PHP language files

I'm following your instructions to have Webpack process the PHP language files (located in my /resources/lang/ directory for Laravel < v9.0)

I have this at the top of my webpack.mix.js file:
const mix = require('laravel-mix'); require('laravel-vue-i18n/mix');

And I'm using the plugin like so:
.i18n('resources/lang')

Webpack compiles successfully but it does not process my PHP language files (only the .json files). This is the only language files in the Laravel Mix output:

js/resources_lang_en_json.js │ 1.27 KiB │
js/resources_lang_es_json.js │ 1.27 KiB │
js/resources_lang_fr_json.js │ 1.26 KiB │

Any suggestions? Is it required to use Inertia.js?

I failed to change locale to "en"...

I need to add i18n support in Laravel 9/Inertiajs2/vuejs3 app and I try to use
"laravel-vue-i18n": "^1.4.4". I added 2 dirs AppPath/lang/en and AppPath/lang/ua
and in resources/js/app.js I added i18n support :

import { i18nVue } from 'laravel-vue-i18n'
...
createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(i18nVue, {
                resolve: lang => import(`../../lang/${lang}.json`),
            })

            .component('inertia-link', Link)
            ...
            .mixin({ methods: { route } })
            .mount(el);
    },
});

and in webpack.mix.js :

require('laravel-vue-i18n/mix');

mix.js('resources/js/app.js', 'public/js')
    .i18n()
    .vue(3)

As result I have 2 generated files in public/js/lang_php_en_json.js and public/js/lang_php_ua_json.js with all
labels from AppPath/lang/ and english label is applyed in vue file with {{ $t(' method.

I need to set ua as default language. I set in config/app.php :
'locale' => 'ua',
it works.

But I failed to change locale to en with control method :

    public function change_locale(Request $request)
    {
        App::setLocale($request->lang);
        session()->put('locale', $request->lang);

        $app_locale = app()->getLocale();
        \Log::info(  $app_locale ); // it shows “en”

        return response()->json([
            'lang'    => $request->lang,
            'message' => 'Language was successfully changed',
        ], 200);

    }

On client side I still see "ua" labels
have I to set changes locale on js side somehow ?

Thanks in advance!

[2.x] Vulnerabilities founded

# npm audit report

file-type  <16.5.4
Severity: moderate
file-type vulnerable to Infinite Loop via malformed MKV file - https://github.com/advisories/GHSA-mhxj-85r3-2x55
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/file-type
  imagemin  5.2.0 - 8.0.0
  Depends on vulnerable versions of file-type
  node_modules/imagemin
    laravel-mix  >=4.0.11
    Depends on vulnerable versions of imagemin
    node_modules/laravel-mix
      laravel-vue-i18n  >=1.4.4
      Depends on vulnerable versions of laravel-mix
npm WARN using --force Recommended protections disabled.
npm WARN audit Updating laravel-vue-i18n to 1.4.3,which is a SemVer major change.

After executing the npm audit fix --force command in the package.json file, the version of the laravel-vue-i18n dependency has changed to ^1.4.3

Keys printed instead of translations with Inertia

Hello,

Thanks for this package!

Basically, my problem is that when I invoke $t('auth.failed') in my templates, all I get is the key auth.failed which validates that the package is working but it doesn't seem to be able to find the proper key in my json file.

I have scratched my head really hard on this, read both closed and opened issues and can't find a solution so I turn to you to help me figure out what I'm doing wrong.

I have an app that is using Inertia and I've followed the instructions twice to install the package.
I want to use the PHP way to get my translations because I find it easier to maintain, so I edited my webpack.mix.js according to the instructions and I can see it compiles everything fine when I run either npm run dev or npm run watch.
So the problem must be elsewhere.

Here are the relevant files:
app.js

require('./bootstrap');

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import { i18nVue } from 'laravel-vue-i18n'

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(i18nVue, {
                resolve: lang => import(`../../lang/${lang}.json`),
            })
            .mixin({ methods: { route } })
            .mount(el);
    },
});

webpack.mix.js

const mix = require('laravel-mix');
require('laravel-vue-i18n/mix');

mix.js('resources/js/app.js', 'public/js').vue()
    .postCss('resources/css/app.css', 'public/css', [
        require('postcss-import'),
        require('tailwindcss'),
    ])
    .i18n()
    .alias({
        '@': 'resources/js',
    });

if (mix.inProduction()) {
    mix.version();
}

my translations files are the regular ones:

- /lang
- - /en
- - - auth.php

In the Welcome.vue that comes with Jetstream I have tried this:

<script setup>
import { Head, Link } from '@inertiajs/inertia-vue3';
import { trans } from 'laravel-vue-i18n';

defineProps({
    canLogin: Boolean,
    canRegister: Boolean,
    laravelVersion: String,
    phpVersion: String,
});

const test = trans('auth.failed')
</script>

<template>
        {{ $t('auth.failed') }}
        {{ $t('auth.password') }}
        {{ test }}
</template>

And all it shows are the keys, not the proper translations.
In the console tab of my browser I can see it calling the lang_php_en_json.js which contains what I want.

Am I missing something here ?

Cannot read properties of undefined (reading 'VITE_LARAVEL_VUE_I18N_HAS_PHP')

  • laravel-vue-i18n - 2.1.1
  • vite - 2.9.9
  • vuejs 3.2.25
  • node 16.16.0
  • without laravel
// .env

VITE_LARAVEL_VUE_I18N_HAS_PHP=false
// src/main.ts

import { createApp } from 'vue'
import { i18nVue } from 'laravel-vue-i18n'
import i18nOptions from '@/utils/lang'

import pinia from '@/utils/pinia'

createApp(App)
    .use(i18nVue, i18nOptions(pinia))
// src/utils/lang

import { Pinia } from 'pinia'
import { useSettingsStore } from '@/stores/settings'

export default (pinia: Pinia) => {
    const lang = useSettingsStore(pinia).locale

    const resolve = async (lang: string) => {
        const files = import.meta.glob('../../lang/*.json')

        return await files[`../../lang/${ lang }.json`]()
    }

    return { lang, resolve }
}

image

Result: not working

image

If we add output to the console, we see that the files are loaded:

const resolve = async (lang: string) => {
    const files = import.meta.glob('../../lang/*.json')

    console.log(files)
    console.log(
        import.meta.env.VITE_API_URL,
        import.meta.env.VITE_LARAVEL_VUE_I18N_HAS_PHP
    )

    return await files[`../../lang/${ lang }.json`]()
}

image

image

Without the VITE_LARAVEL_VUE_I18N_HAS_PHP key, I also get the error:

image

Version 1.4.4 worked perfectly.

Incompatibility with themer library

Hello
I'm using the qirolab/laravel-themer library. In this case, the translation files are created in public/themes/{them-name}/js instead of in the public/js. So in order for the text in the components to be translated correctly, I have to manually copy and paste the files.

Cannot load language files

Hello,

Why I get the following error?

GET http://***.com/js/resources_lang_hu_json.js net::ERR_ABORTED 404 (Not Found)
Uncaught (in promise) TypeError: Cannot load lang: hu file: Loading chunk resources_lang_hu_json failed.

The resources/lang/en.json file exists.

Translations with multiple words don't work

I have a strange issue where translations that have multiple words don't load. Only single word translations load.

I'm using Vite and the new laravel-vite-plugin like this:

.use(i18nVue, {
    resolve: lang => {
        const langs = import.meta.globEager('../../lang/*.json');
        return langs[`../../lang/${lang}.json`];
    }
})

I don't like the flash of untranslated text when loading them async, so I do that instead. This part seems to work fine!

What's strange is the exported/loaded translation file looks like this:
image

Single word translations are set as a constants, and multi word translations are just strings.
This should still work, right?
But it doesn't for some reason.

// these translate fine
{{ $t('Search') }}
{{ $t('Filter') }}

// but these don't - and yes, they are available in the translation file
{{ $t('Confirm Password') }}
{{ $t('Price range') }}
{{ $t('Visit store') }} 

Any clue? Am I doing something wrong?

TypeError: langs[(("../../lang/" + (intermediate value)) + ".json")] is not a function

Hi,

I've tried installing this package and followed the documentation for Vite, but I'm getting the following error in the console.

Uncaught (in promise) TypeError: langs[(("../../lang/" + (intermediate value)) + ".json")] is not a function

I am getting this on a fresh installation of Laravel Jetstream and the installation of this package

laravel new example --jet 
npm i laravel-vue-i18n

vite.config.js

import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import vue from "@vitejs/plugin-vue";
import i18n from "laravel-vue-i18n/vite";

export default defineConfig({
    plugins: [
        laravel({
            input: "resources/js/app.js",
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
        i18n(),
    ],
});

app.json

import "./bootstrap";
import "../css/app.css";

import { createApp, h } from "vue";
import { createInertiaApp } from "@inertiajs/inertia-vue3";
import { InertiaProgress } from "@inertiajs/progress";
import { resolvePageComponent } from "laravel-vite-plugin/inertia-helpers";
import { ZiggyVue } from "../../vendor/tightenco/ziggy/dist/vue.m";
import { i18nVue } from "laravel-vue-i18n";

const appName =
    window.document.getElementsByTagName("title")[0]?.innerText || "Laravel";

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) =>
        resolvePageComponent(
            `./Pages/${name}.vue`,
            import.meta.glob("./Pages/**/*.vue")
        ),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(i18nVue, {
                resolve: async (lang) => {
                    const langs = import.meta.glob("../../lang/*.json");
                    return await langs[`../../lang/${lang}.json`]();
                },
            })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .mount(el);
    },
});

InertiaProgress.init({ color: "#4B5563" });

Am I stupid and am I forgetting something or is something not working properly ?

Translation not showing on initial app launch

Hi,

We recently updated our project to use vite instead of webpack and also modified also our vuejs files to make it compatible, everything is working well except for one thing. Yesterday I noticed that the requested translations did not load on the first load of the project when you refresh or visit the website.

For example when I put the url in my webbrowser and visit it, the translations will be in English but if I click on 1 menu item to go to another page, everything will change to the Dutch translations (which is correct).

Our app.js is as follows:

import './bootstrap';
import '../css/app.css';

// Import modules...
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3'
import { InertiaProgress } from '@inertiajs/progress'
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { library } from "@fortawesome/fontawesome-svg-core";
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
import { faEdit } from "@fortawesome/free-solid-svg-icons";
import { faEye } from "@fortawesome/free-solid-svg-icons";
import { faSun } from "@fortawesome/free-solid-svg-icons";
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { i18nVue } from 'laravel-vue-i18n';

library.add(faInfoCircle);
library.add(faEdit);
library.add(faEye);
library.add(faSun);

  createInertiaApp({
      resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
      setup({ el, app, props, plugin }) {
          return createApp({ render: () => h(app, props) })
              .use(plugin)
              .use(i18nVue, {
                  resolve: async lang => {
                      const langs = import.meta.glob('../../lang/*.json');
                      return await langs[`../../lang/${lang}.json`]();
                  }
              })
              .mixin({ methods: { route, hasAnyPermission: function (permissions) {
                      var allPermissions = this.$page.props.auth.can;
                      var hasPermission = false;

                      permissions.forEach(function(item){
                          if(allPermissions[item]) hasPermission = true;
                      });
                      return hasPermission;
                  } } })
              .mixin({ methods: { route } })
              .component("font-awesome-icon", FontAwesomeIcon)
              .mount(el);
      },
  });

and in our vuejs files we use {{ $t('translation') }} to load the translations for a specific text, what can be the reason that the translation only load when you navigate to another page?

mix.version

Using mix.version() will output app.js as the version as desired. But if you include this module here for example with mix.js('resources/js/app.js', 'public/js').vue().i18n().version(); at the end, after entering npm run prod, inside the app.js file are several (1-2) javascript files with seemingly random numbers, e.g. 501.js (without version behind it). In this 501.js file are all the translations that need to be done. Because there is no version number appended, this leads to the fact that the visitors have to empty the cache first after implementing new language variables.

Can these 501.js, 598.js etc. also be provided with version numbers?

"npm run build" is slower than "npm run dev"

Hello, first of all sorry for my English, I use google translate.

When I use "npm run dev", the translation process is done quickly without any problems, but when I do "npm run build", the file "php_tr.32683819.js" loads quite late depending on the internet speed. This causes "keys" to appear in the first opening of the page.

resim_2022-09-10_000114141

As seen in the picture, "php_tr.32683819.js" file is loaded 2000ms after the page is opened.

image

Dependencies
"laravel-vue-i18n": "^2.2.2",
"vite": "^3.0.0",
"vue": "^3.2.31"

Laravel 9+

vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import i18n from 'laravel-vue-i18n/vite';


export default defineConfig({

    plugins: [
        laravel({
            input: 'resources/js/app.js',
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
        i18n(),
    ],
});
app.js
createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob('./Pages/**/*.vue')),
    setup({ el, app, props, plugin }) {
        const captcheKey = props.initialPage.props.recaptcha_site_key;
        const application = createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(i18nVue, {
                resolve: async lang => {
                    const langs = import.meta.glob('../../lang/*.json');
                    return await langs[`../../lang/${lang}.json`]();
                }
            })
    ...

Feature request: Language array

Hi,

I'm not sure if this is already possible, but can there be a function which allows you to use an array of language strings.

I for example have in my en.php

<?php

return [
    'homepage' => [
        'title' => 'This is the homepage',
        'content' => [
            'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam convallis vitae est vitae posuere. Quisque imperdiet nunc nisi, ut imperdiet lectus auctor eu. Donec elit neque, dignissim eu tempor placerat, volutpat sed odio. Praesent non ligula odio. Curabitur finibus est quis urna sagittis, a finibus nulla lobortis. Phasellus sit amet ligula non urna congue elementum id vitae eros. Ut faucibus cursus finibus. Sed pretium at tortor ac semper. Morbi quis est quis ligula maximus mollis at non est. Aenean tempor metus mattis quam pretium suscipit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.',
            'Duis ultrices elementum nulla, et posuere velit eleifend eget. Donec vitae malesuada neque. Curabitur ac ipsum at risus consectetur mattis. Nam id ipsum quis velit dignissim venenatis. Pellentesque vulputate semper leo eu aliquet. Vestibulum ornare nunc neque, non vulputate nulla tempus eget. Donec in turpis sed turpis facilisis consectetur at tristique odio. In non congue augue, sit amet posuere quam. Cras pulvinar leo posuere lectus aliquet cursus. Vivamus metus ligula, scelerisque in finibus quis, elementum et urna. Pellentesque purus lorem, imperdiet et pulvinar quis, dapibus id nisi. Sed varius orci id arcu mollis tempor. Donec vitae pretium urna. Integer egestas ipsum et tempus euismod.',
        ],
    ]
];

In the Json this gets converted to.

{
	"pages.homepage.title": "This is the homepage",
	"pages.homepage.content.0": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam convallis vitae est vitae posuere. Quisque imperdiet nunc nisi, ut imperdiet lectus auctor eu. Donec elit neque, dignissim eu tempor placerat, volutpat sed odio. Praesent non ligula odio. Curabitur finibus est quis urna sagittis, a finibus nulla lobortis. Phasellus sit amet ligula non urna congue elementum id vitae eros. Ut faucibus cursus finibus. Sed pretium at tortor ac semper. Morbi quis est quis ligula maximus mollis at non est. Aenean tempor metus mattis quam pretium suscipit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.",
	"pages.homepage.content.1": "Duis ultrices elementum nulla, et posuere velit eleifend eget. Donec vitae malesuada neque. Curabitur ac ipsum at risus consectetur mattis. Nam id ipsum quis velit dignissim venenatis. Pellentesque vulputate semper leo eu aliquet. Vestibulum ornare nunc neque, non vulputate nulla tempus eget. Donec in turpis sed turpis facilisis consectetur at tristique odio. In non congue augue, sit amet posuere quam. Cras pulvinar leo posuere lectus aliquet cursus. Vivamus metus ligula, scelerisque in finibus quis, elementum et urna. Pellentesque purus lorem, imperdiet et pulvinar quis, dapibus id nisi. Sed varius orci id arcu mollis tempor. Donec vitae pretium urna. Integer egestas ipsum et tempus euismod.",
}

Now I'm not sure how to retrieve these language strings from the array.
The reason I want to do it like this, is because I want them to be seperate paragraphs.
Each line is supposed to be a <p></p>

So preferably I would do something like:

<p v-for="line in $t('pages.homepage.content')">
    {{line}}
</p>

But this just outputs.

   <p>p</p>
   <p>a</p>
   <p>g</p>
   <p>e</p>
   <p>s</p>
   <p>.</p>
   <p>h</p>
   <p>o</p>
   <p>m</p>
   <p>e</p>
   <p>p</p>
   <p>a</p>
   <p>g</p>
   <p>e</p>
   <p>.</p>
   <p>c</p>
   <p>o</p>
   <p>n</p>
   <p>t</p>
   <p>e</p>
   <p>n</p>
   <p>t</p>

Is there a 'simple' fix for this?
Or could there maybe be a seperate function that can work for multiline/arrays like that. (E.g: $tm() )

Register Globally

Hi,

Im would like to make this plugin globally but something wrong not working can you help ??
Im trying to set but blank page appears

import { trans } from 'laravel-vue-i18n'

...
.mixin({ components: { trans } })
...

Can't seem to get trans to work

I'm using Vue 3 with composition API and while $t and $tChoice both function perfectly, I can't seem to get trans or transChoice to function properly. It's as if it's using a different configuration from $t and $tChoice. Thus no language strings are loaded.

It may just be a case of me doing something very wrong, as I work with Vue 2 daily and this is my first Vue 3 Composition API project.

Just in case it's important, here's the app.js file that I use
require('./bootstrap');

import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import { i18nVue } from 'laravel-vue-i18n';

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {
        return createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(i18nVue, {
              resolve: lang => import (`../lang/${lang}.json`),
            })
            .mixin({ methods: { route } })
            .mount(el);
    },
});

InertiaProgress.init({ color: '#4B5563' });

How to use $t inside of computed ?

In Laravel 9 / vuejs 3 with Composition API app I use “this” when I need to get label in current locale
withing js script of form request :

import {defineComponent, ref} from 'vue'
import {Inertia} from '@inertiajs/inertia'


export default defineComponent({
    props: {
        status: String
    },

    setup(props) {
        let formLogin = ref(useForm({
            email: '',
            password: '',
            remember: true
        }))

        function loginSubmit() {


            formLogin.value.post(route('login'), {
                preserveScroll: true,
                onSuccess: (data) => {

                    Toast.fire({
                        icon: 'success',
                        position: 'center',
                        title: this.$t('You are logged into the app as admin') // IT WORKS !
                    })
                    

But I failed to make similar way when using $t inside of computed :

    setup(props, attrs) {
        ...
        let self= this
        let getSharedDocumentSubmitBtnTitle = computed(() => {
            console.log(this)     // I got "undefined" here
            console.log(self)     // I got "undefined" here
            console.log(self.$t)  // I got error here

            // I see it like that :
            return Condition ? capitalize(self.$t('common.create')) : capitalize(self.$t('common.update'))
        });

In which way can I get valid context and use $t inside of computed ?

Thanks in advance!

Guide to load Lang from database or external files

I have a Laravel Vue application, the application is hosted on Vapor.

The admin can update the language files but since Vapor is serverless, I cant write to update the lang/ folder.

My question is, how do I either write to external storage system that stores my lang folder (e.g s3) or use database to store the language key pair?

Infinite laravel mix alert in run watch

Hi @xiCO2k , Thanks you for this helpful librairie.

But i face some issues. I install the librairie with Laravel and Vue3, in combinaision with LaravelMix. When i launch npm run watch, i'm pop with a ton of Laravel Mix alert of successful compilation. I don't know why. Thanks

Vite Message: laravel-vue-i18n doesn't appear to be written in CJS

Hi @xiCO2k,
i migrated yesterday to the Vite Integration. Everything's seems fine. Thanks for the fast adaption.

I noticed this message when use "vite build --ssr".

laravel-vue-i18n doesn't appear to be written in CJS, but also doesn't appear to be a valid ES module (i.e. it doesn't have "type": "module" or an .mjs extension for the entry point). Please contact the package author to fix.

Vapor support

Hi there,

Is there any way of using this package together with laravel-vapor to support the replaced URL's with the CDN instead?

Create multiple instances for different locales?

I have a use-case where I need to show part of an app in one language, and another part in another language - both being visible at the same time. Would this be possible with this package, somehow? I was hoping I could just create an instance of some sort of i18n class, but it looks like there is no class at all?

How can I show date/datetime values ?

Hello! Thanks for your work !
Working with xiCO2k/laravel-vue-i18n (1.4.4) I did not find how can I show date/datetime values in
formats like “25 June, 2022 5:54 PM” and “2 days ago” ?

Cannot find module in Inertia SSR context

Thanks for the great package!

I'm trying to get it to work in a VILT stack with InertiaJS SSR feature, but I run into issues unfortunately.

One of the issues is that the package seems to work well on the client side, but when I run it on a node server it cannot find the language files. It seems to be looking for the files in the root of the app, and not in the /public folder.

Error: Cannot find module '../../js/resources_lang_en_json.js'
Require stack:
- /Users/Name/Websites/TheProjectDir/public/js/ssr.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:793:17)
    at Function.Module._load (internal/modules/cjs/loader.js:686:27)
    at Module.require (internal/modules/cjs/loader.js:848:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.__webpack_require__.f.require (/Users/Name/Websites/TheProjectDir/public/js/ssr.js:28299:28)
    at /Users/Name/Websites/TheProjectDir/public/js/ssr.js:28222:40
    at Array.reduce (<anonymous>)
    at Function.__webpack_require__.e (/Users/Name/Websites/TheProjectDir/public/js/ssr.js:28221:67)
    at webpackAsyncContext (/Users/Name/Websites/TheProjectDir/public/js/ssr.js:27901:29)
    at Object.resolve (/Users/Name/Websites/TheProjectDir/public/js/ssr.js:28365:90) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/Users/Name/Websites/TheProjectDir/public/js/ssr.js' ]
}

I use this in my app.js (which works):

.use(i18nVue, {
	resolve: (lang) => import(`../lang/${lang}.json`),
})

And I use the exact same syntax in my ssr.js file, which doesn't work and triggers the above mentioned error on the node server.
The resources are compiled just fine and have the right name, in /public/js

Is there anyone here that tried out this package in combination with InertiaJS and its SSR feature?

How work with multiple language files

Hello,

How i can work with multiple language files like:

lang/en/home.json
lang/en/pricing.json
lang/en/features.json

lang/pt/home.json
lang/pt/pricing.json
lang/pt/features.json

It's possible?

Need assistance to install the package using InertiaJs

Hello, thanks for the great package, is exactly what I need for my project.

I follow all the installation process but still I am not able to render the translations in the frontend (application using Laravel 9, Vite and InertiaJs - all latest versions).
This is my setup:

app.js

import { i18nVue } from "laravel-vue-i18n";

...

createInertiaApp({
    ...
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .use(i18nVue, {
                lang: 'en',
                fallbackLang: 'en',
                resolve: async lang => {
                    const languages = import.meta.glob('../../lang/*.json');
                    return await languages[`../../lang/${lang}.json`]();
                }
            })
            .mount(el)
    },
})

vite.config.js

import i18n from 'laravel-vue-i18n/vite';

...

export default defineConfig({
    plugins: [
       ...
        i18n(),
    ],

The build goes fine, I am also able to generate the json file from php, but if I am trying to render {{ $t('auth.failed' )}} in a vue component, it shows me the key. I tried to debug using your helpers isLoaded, getActiveLanguage and this is what I get:

const lang = getActiveLanguage();
const loaded = isLoaded();
console.log(lang, loaded, trans('auth.failed'));

// Output: 
// 'en', false, 'auth.failed'
// 'en', true, 'auth.failed'
// I guess it's double logging because of async resolve.

Any help to understand what am I doing wrong? You mentioned that you are using it with InertiaJs so I guess I am missing something here.

Thanks

Support json with nested structure

Vue i18n supports json with a nested structure.

JSON:

{
  message: {
    hello: 'Hello world'
  }
}

Template:

<p>{{ $t('message.hello') }}</p>

I tried that, but the translation returns the keys.

Simple Question about the Json files

I don't know if some one asked it already, but do I need to mange the .json-files or should I only add/change language phrases inside the php files?

P.S.: Awsome work 😄 sadly I need to open a issue for it, due you have not enabled Github's discussion feature 😉

Resolve callback is required with Laravel Mix Plugin

Hi @xiCO2k, thanks for the great plugin! 🙏

I'm wondering if/why the resolve callback is required even if we use the Laravel Mix plugin to import PHP files?

Is it possible to make this optional if my application only utilizes PHP based language files?

Thanks again for your time!

Datatable refresh problem

Hello

I installed the Datatable plugin. When the page is opened for the first time, there is no problem, when we refresh the page, the language gradually starts to appear. Can anyone help to resolve this issue?

Laravel 9
Inertiajs + vue3
datatable.net

Ekran Resmi 2022-09-19 21 47 09

Ekran Resmi 2022-09-19 21 47 19

Translation not working when using v1.4.4 or v2.0.0

I can't get translation to work using latest two releases of this package (v1.4.4 or v2.0.0), but v1.4.3 does seems work with the setup below.

When using v1.4.4 and v2.0.0, the $t() function does not translate the given string and the isLoaded function always returns false, but if I replace either of those versions with v1.4.3, then the isLaoded function returns true and translation works.

There are no errors raised and I can see the generated translation files gets fetched when loading my application in the browser.

webpack.mix.js

const mix = require('laravel-mix');
require('laravel-vue-i18n/mix');

mix.js('resources/js/app.js', 'public/js').vue()
    .i18n()
    .sass('resources/sass/app.scss', 'public/css')
    .sourceMaps()
    .webpackConfig(require('./webpack.config'));

if (mix.inProduction()) {
    mix.version();
}

app.js

require('./bootstrap');

// Import modules...
import { createApp, h } from 'vue';
import { createInertiaApp } from '@inertiajs/inertia-vue3';
import { InertiaProgress } from '@inertiajs/progress';
import { i18nVue } from 'laravel-vue-i18n';
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime';
import localizedFormat from 'dayjs/plugin/localizedFormat';
import 'dayjs/locale/en-gb'

const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';

createInertiaApp({
    title: (title) => `${title} - ${appName}`,
    resolve: (name) => require(`./Pages/${name}.vue`),
    setup({ el, app, props, plugin }) {

        dayjs.extend(relativeTime);
        dayjs.extend(localizedFormat);
        dayjs.locale('en-gb');

        const VueApp = createApp({ render: () => h(app, props) });

        VueApp.config.globalProperties.$_ = _;

        VueApp.config.globalProperties.$dayjs = dayjs;

        VueApp.config.globalProperties.$filters = {
            truncate(text, length, clamp){
                clamp = clamp || '...';
                var node = document.createElement('div');
                node.innerHTML = text;
                var content = node.textContent;
                return content.length > length ? content.slice(0, length) + clamp : content;
            }
        }

        VueApp.use(plugin)
            .use(i18nVue, {
                resolve: lang => import(`../../lang/${lang}.json`),
            })
            .mixin({ methods: { route } })
            .mount(el);

        return VueApp;
    },
});

InertiaProgress.init({ color: '#4B5563' });

Can't Install laravel-vue-i18n

Hi, thanks a lot for this greate package, unfortunately i can's install it on fresh laravel install.
Here is the error log.
$ npm i laravel-vue-i18n
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: [email protected]
npm WARN Found: laravel-mix@undefined
npm WARN node_modules/laravel-mix
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer laravel-mix@"^6.0.43" from [email protected]
npm WARN node_modules/laravel-vue-i18n
npm WARN laravel-vue-i18n@"*" from the root project
npm ERR! code FETCH_ERROR
npm ERR! errno FETCH_ERROR
npm ERR! invalid json response body at https://registry.npmjs.org/laravel-mix reason: Invalid response body while trying to fetch https://registry.npmjs.org/laravel-mix: read ECONNRESET

how to change active lang to the new locale

hello
i'm using the package and i can chang locale and files comes from Lang folder can be changed to the new locale when using loadLanguageAsync() function but i can't chang active lang , it is always 'en'
also any translated data comming from database remain the same in english not to the new locale
i am using astrotomic laravel translatable
i tried to change locale in config/app manually to check that astrotomic is working fine and it is working .

any help
thank you

Concatenation in PHP language files causes an error in the loader

If I have a translation file like this:

// lang/en/user.php

return [
    'lorem' => "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " .  
               "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis.",
];

then I get the following error when running npm run dev:

[webpack-cli] TypeError: Cannot read property 'kind' of undefined
at parseItem (/var/www/node_modules/laravel-vue-i18n/dist/loader.js:60:14)
at parseItem (/var/www/node_modules/laravel-vue-i18n/dist/loader.js:73:12)
at parseItem (/var/www/node_modules/laravel-vue-i18n/dist/loader.js:71:36)
at /var/www/node_modules/laravel-vue-i18n/dist/loader.js:64:46
at Array.map ()
at parseItem (/var/www/node_modules/laravel-vue-i18n/dist/loader.js:64:32)
at parse (/var/www/node_modules/laravel-vue-i18n/dist/loader.js:56:32)
at /var/www/node_modules/laravel-vue-i18n/dist/loader.js:39:66
at Array.forEach ()
at parseAll (/var/www/node_modules/laravel-vue-i18n/dist/loader.js:38:14)

After removing . and turning the translation into a one-line string the problem disappears, but that's a workaround. Looking at the loader's source it seems that it might not be an easy fix, each part of the string is a separate item so they'd have to be buffered until the entire string is known. But maybe I missed something and it's actually not that hard. What do you think?

Generate translations when using vite

Hi,

I'm using a new Laravel Jetstream application and am using vite. I've followed the readme, but the language json files aren't generated when running 'npm run build' (or npm run dev)

Which command should I run to generate the language json files?

change locale(question)

Good day, i try change locale like this:
import { loadLanguageAsync } from 'laravel-vue-i18n';

<template>
    <div>{{ $t('Welcome!') }}</div>
    <button @click="loadLanguageAsync('pt')">Change to Portuguese Language</button>
</template>

And i recive this error:
Uncaught TypeError: _ctx.loadLanguageAsync is not a function
Can you please tell me how to change the language?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.