Giter VIP home page Giter VIP logo

laravel's Introduction

Translation.io client for Laravel 5.5+ to 11.x

Software License Build Status Test Coverage Maintainability Package Version Downloads

Add this package to localize your Laravel application.

Use the official Laravel syntax (with PHP or JSON files), or use the GetText syntax.

Write only the source text, and keep it synchronized with your translators on Translation.io.

Translation.io interface

Technical Demo (2.5min)

Need help? [email protected]

Table of contents

Localization syntaxes

Laravel Localization (PHP key/values)

The default Laravel method to localize.

// Regular
__('inbox.title');

// Regular with sublevel key
__('inbox.menu.title');

// Pluralization
trans_choice('inbox.messages', $number);

// Interpolation
__('inbox.hello', ['name' => $user->name]);

With the PHP file lang/en/inbox.php:

<?php
return [
    'title' => 'Title to be translated',
    'hello' => 'Hello :name',
    'messages' => 'One message|Many messages',
    'menu' => [
        'title' => 'Title of menu'
    ]
];

Notes:

  • trans can also be used instead of __.
  • You can organize your PHP files with subfolders like en/subfolder/inbox.php using keys like subfolder/inbox.title.

Laravel Localization (JSON source text)

A new feature of Laravel 5.4 is the possibility to use __ with the source text (and not only with keys like in the previous section).

These translations are stored into JSON files located in the lang directory.

// Regular
__("Text to be translated");

// Pluralization
trans_choice(__('One message|Many messages'), $number);

// Interpolation
__('Hello :name', ['name' => $user->name]);

With the JSON file lang/en.json:

{
    "Text to be translated": "",
    "One message|Many messages": "",
    "Hello :name": ""
}

Notes:

  • To spend less time dealing with multiple JSON files, we advise to only edit the original language (usually en.json) to add new strings, and leave the translations empty. During a sync, This package will automatically create and fill the JSON files of the target languages.

  • If you want to organize your JSON files by feature, you can register new paths in AppServiceProvider like this:

public function boot()
{
    $loader = $this->app['translation.loader'];

    // or 'resources/lang/my_feature' in Laravel < 9
    $loader->addJsonPath(base_path('lang/my_feature')); 
}

GetText

This package adds the GetText support to Laravel. We strongly suggest that you use GetText to localize your application since it allows an easier and more complete syntax.

Moreover, you won't need to create and manage any PHP or JSON file since your code will be automatically scanned for any string to translate.

// Regular
t("Text to be translated");

// Pluralization
n("Singular text", "Plural text", $number);

// Regular with context
p("context", "Text to be translated");

// Pluralization with context
np("context", "Singular text", "Plural text", $number);

// Simple Interpolations (works with n, p and np too)
t('Hello %s', $user->name);

// Complex Interpolations (works with n, p and np too)
t(':city1 is bigger than :city2', [ ':city1' => 'NYC', ':city2' => 'BXL' ]);

Installation

  1. Add the package via Composer:
composer require tio/laravel
  1. Create a new translation project from the UI.
  2. Copy the initializer into your Laravel app (config/translation.php) or execute php artisan vendor:publish.

The initializer looks like this:

<?php
return [
    'key' => env('TRANSLATIONIO_KEY'),
    'source_locale' => 'en',
    'target_locales' => ['fr', 'nl', 'de', 'es']
];
  1. Add the API key (TRANSLATIONIO_KEY) in your .env file.
  2. Initialize your project and push existing translations to Translation.io with:
php artisan translation:init

Note: since Laravel 9, the lang directory and the default set of language files used by Laravel are not included by default in new projects (see official documentation), so you may need to run the lang:publish command to generate them:

php artisan lang:publish

If you need to add or remove languages in the future, please read this section about that.

Usage

Sync

To send new translatable keys/strings and get new translations from Translation.io, simply run:

php artisan translation:sync

Sync and Show Purgeable

If you need to find out what are the unused keys/strings from Translation.io, using the current branch as reference:

php artisan translation:sync_and_show_purgeable

As the name says, this operation will also perform a sync at the same time.

Sync and Purge

If you need to remove unused keys/strings from Translation.io, using the current branch as reference:

php artisan translation:sync_and_purge

As the name says, this operation will also perform a sync at the same time.

Warning: all keys that are not present in the current local branch will be permanently deleted from Translation.io.

Manage Languages

Add or Remove Language

You can add or remove a language by updating 'target_locales' => [] in your config/translation.php file, and executing php artisan translation:sync.

If you want to add a new language with existing translations (ex. if you already have a translated PHP file in your lang directory), you will need to create a new project on Translation.io and run php artisan translation:init for them to appear.

Edit Language

To edit existing languages while keeping their translations (e.g. changing from en to en-US).

  1. Create a new project on Translation.io with the correct languages.
  2. Adapt config/translation.php (new API key and languages)
  3. Adapt directory language names in lang or resources/lang (optional: adapt GetText .po headers)
  4. Execute php artisan translation:init and check that everything went fine.
  5. Invite your collaborators in the new project.
  6. Remove the old project.

Since you created a new project, the translation history and tags will unfortunately be lost.

Custom Languages

A custom language is always derived from an existing language. It's useful if you want to adapt some translations to another instance of your application, or to a specific customer.

The structure of a custom language is: existing language code + - + custom text, where custom text can only contain alphanumeric characters and -.

Examples: en-microsoft or fr-BE-custom.

Custom languages can be added and used like any other language.

Change the current locale

Globally

The easiest way to change the current locale is with the set.locale Middleware.

// in routes/web.php

// Solution 1: Apply the locale selection to root.
//             => https://yourdomain.com?locale=fr
Route::get('/', function () {
    return view('welcome');
})->middleware('set.locale');

// Solution 2: Apply the locale selection to many routes.
//             => https://yourdomain.com/...?locale=fr
Route::middleware('set.locale')->group(function () {
    Route::get('/', function () {
        return view('welcome');
    });
});

// Solution 3: prefix your routes with the locale and apply it.
//             => https://yourdomain.com/fr
//             => https://yourdomain.com/fr/...
Route::prefix('{locale?}')->middleware('set.locale')->group(function() {
    Route::get('/', function () {
        return view('welcome');
    });
});

First time the user will connect, it will automatically set the locale extracted from the browser HTTP_ACCEPT_LANGUAGE value, and keep it in the session between requests.

The set.locale Middleware code is here, feel free to adapt it with your own locale management.

Locally

Change the current locale with:

use Tio\Laravel\Facade as Translation;

Translation::setLocale('fr');

Frontend Localization

Using this Package

This package is also able to cover frontend localization (React, Vue, ...).

There are several ways to pass the translation strings from the backend to the frontend: JavaScript serialization, data- HTML attributes, JSON files etc.

The easiest strategy when dealing with React/Vue would be to pass the corresponding translations as props when mounting the components.

Notes:

  • You can structure the i18n props with multiple levels of depth and pass the subtree as props to each of your sub-components.
  • It also works great with server-side rendering of your components.

Using our official React & JavaScript package

As Translation.io is directly integrated in the great Lingui internationalization framework, you can also consider frontend localization as a completely different localization project.

Please read more about this on:

Advanced Configuration Options

The config/translation.php file can take several optional configuration options.

Some options are described below but for an exhaustive list, please refer to translation.php.

Ignored PHP keys

If you would like to ignore specific PHP keys, or even entire PHP files or subdirectories from the source language, you can use the ignored_key_prefixes option.

For example:

<?php
return [
    ...
    'ignored_key_prefixes' => [
        'validation',        // ignore the whole validation.php file.
        'validation.custom', // ignore the "custom" subtree in validation.php file.
        'subfolder/more',    // ignore the whole subfolder/more.php file.
    ],
    ...
];

Testing

To run the specs with oldest dependencies:

composer update --no-interaction --prefer-stable --prefer-lowest
./vendor/bin/phpunit

To run the specs with latest dependencies:

composer update --no-interaction --prefer-stable
./vendor/bin/phpunit

Contributing

Please read the CONTRIBUTING file.

List of clients for Translation.io

The following clients are officially supported by Translation.io and are well documented.

Some of these implementations (and other non-officially supported ones) were started by contributors for their own translation projects. We are thankful to all contributors for their hard work!

Ruby on Rails (Ruby)

Officially supported on https://translation.io/rails

Credits: @aurels, @michaelhoste

Laravel (PHP)

Officially supported on https://translation.io/laravel

Credits: @armandsar, @michaelhoste

React, React Native and JavaScript

Officially supported on https://translation.io/lingui

Translation.io is directly integrated in the great Lingui internationalization project.

Angular

Officially supported on https://translation.io/angular

Credits: @SimonCorellia, @didier-84, @michaelhoste

Others

If you want to create a new client for your favorite language or framework, please read our Create a Translation.io Library guide and use the special init and sync endpoints.

You can also use the more traditional API.

Feel free to contact us on [email protected] if you need some help or if you want to share your library.

License

The MIT License (MIT). Please see License File for more information.

laravel's People

Contributors

armandsar avatar didier-84 avatar fabcocco avatar jeffersonsimaogoncalves avatar michaelhoste avatar nikosv 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  avatar

laravel's Issues

File that is mentioned in 'ignored_key_prefixes' is removed after sync

Hi!
I am using the v1.12 of your package, and PHP 7.3.23.

I have a translation.php file as follows:

	...

	'source_locale' => 'de',

    'target_locales'       => ['en'],

    /*
    |--------------------------------------------------------------------------
    | # Ignored PHP key prefixes.
    |--------------------------------------------------------------------------
    |
    | Ex: * 'validation':        ignore the whole validation.php file.
    |     * 'validation.custom': ignore the "custom" subtree in validation.php file.
    |     * 'subfolder/more':    ignore the whole subfolder/more.php file.
    |
    */
    'ignored_key_prefixes' => ['legacy', 'validation'],

	...

So, I want to translate from german to english.
The validation.php file is only available in the en, but not in the de folder (as I just need this file for internalt tests). So I have some structure like this:

de/
	file1.php
	file2.php
en/
	file1.php
	validation.php

But although validation is mentioned in the ignored_key_prefixes, the en/validation.php file is removed after I call php artisan translation:sync. My structure after syncing is:

de/
	file1.php
	file2.php
en/
	file1.php
	file2.php

If I understand correctly, the file en/validation.php should not be touched, because it is ignored, so I think I found a bug here?

Working with variable translation keys

Hello,

I'm wondering if there is a way to register translation keys that come from other sources rather than being hardcoded.
Example use case is having a set of data (e.g. API or local constants), which need to be translated, but they would need to be changed over time.

I would envision a need for a separate scanning tool, that would require a script to be fully functional and therefore would be able to read variables/constants runtime.

Use example:

class User  {
    const ROLE_ADMIN = 'admin';
}

//dynamic-translations.php
rtp('enums.user-roles', User::ROLE_ADMIN);

//config/translation.php
'scan_runtime' => [
    'runnable-file.php'
];

//Result:
msgctxt "enums.user-roles"
msgid "admin"
msgstr ""

If one wants to change the value of ROLE_ADMIN to let's say, administrator, it would need to be done in just one place.
In theory, is this something that you would be eager to have as a part of your package?

php8 issue

i got error php 8

Gettext\Utils\FunctionsScanner::Gettext\Utils{closure}(): Argument #1 ($carry) must be passed by reference, value given

Laravel 6 support

Hi, it would be great if you can release a new version with Laravel 6 support.

Laravel 9 upgrade

In reading the Laravel 9 upgrade, they are moving the lang directory from resources/lang to the project directory.
Are you going to implement this change?

Support for multiple JSON files

We have a very large application that has multiple JSON translation files, registered with Lang::addJsonPath(). These files are split based on multiple modules within the app.

It looks like it'd be relatively simple to update GettextPOGenerator::jsonFiles() to use all the registered JSON paths. Something like:

$paths = [$this->application['path.lang']];

$loader = Lang::getLoader();
if ($loader instanceof FileLoader) {
  foreach ($loader->jsonPaths() as $jsonPath) {
    $paths[] = $jsonPath;
  }
}

foreach ($paths as $path) {
  foreach (glob($path . DIRECTORY_SEPARATOR . '*.json') as $filename) {
    $files[] = $filename;
  }
}

The trickier issue would be resolving which JSON file to write back to on sync. Is this something you're interested in supporting? I've been digging around in GettextTranslationSaver and it seems like it'd take a bit of a refactor to support this use-case.

Strings inside blade attributes not recognized

We've encountered an issue where having a blade component with a translated string as a attribute. Example code below:

<x-form-row :label="t('Name')"></x-form-row>

This unfortunately won't get picked up when running the sync command. There are ways around this obviously but I just wondered if anyone has an idea on if this could be solved?

How do I add new segments to a pre-existing project?

Hello,

This isn't a bug report but simply a question. We've been using this package for a while now and everything works well. However I need to add a couple of hundred new translations (that I already have as .php files). However, when I run the sync command, I only get the source texts imported. All my translation files are overwritten with empty data from translation.io.
I guess this is the way it's intended since it seems to use translation.io as a "source of truth".

But still, I don't really have the time to add all these manually. Is there a way to sort of "re-init" or sync with the codebase as the source? Or is the only solution to create a new project from scratch?

php artisan translation:init suceeds, php artisan translation:sync tells me to init first

After I init the translation (seemingly successfully, see output below), the backend still shows the "setup" page. If i try to php artisan translation:sync it tells me: {"error":"This project has not been initialized yet. Please use the \"init\" operation."} wven though I already initialized.

My translation.php

<?php

return [
    'key' => env('TRANSLATIONIO_KEY'),
    'source_locale' => 'de-CH',
    'target_locales' => ['fr-FR'],

    /* Directories to scan for Gettext strings */
    'gettext_parse_paths' => ['app', 'resources'],

    /* Where the Gettext translations are stored */
    'gettext_locales_path' => 'resources/lang/gettext'
];

The key is in my .env

How i start the initialization: $ docker-compose exec app php artisan translation:init

The output I get

Init started
Init ended with success
----------
Use this URL to translate: https://translation.io/sandrotanner/my-project-name
----------

Do your logs give any insight on what might go wrong? Thanks in advance :)

BTW I use Laravel 8 and the official php docker image "php:8.0-fpm"

Laravel 11 hasn't no lang directory by default

I've tried to initiate a new project, based on Laravel 11. The init command runs without error, but the project site isn't showing translations.

With a translation:sync I got:

php artisan translation:sync
Sync started

   ErrorException

  file_put_contents(C:\laragon\www\secpal\lang\.translation_io): Failed to open stream: No such file or directory

  at vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php:204
    200▕      * @return int|bool
    201▕      */
    202▕     public function put($path, $contents, $lock = false)
    203▕     {
  ➜ 204▕         return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
    205▕     }
    206▕
    207▕     /**
    208▕      * Write the contents of a file, replacing it atomically if it already exists.

  1   vendor\laravel\framework\src\Illuminate\Filesystem\Filesystem.php:204

  2   vendor\tio\laravel\src\Service\SourceEditSync.php:166
      Illuminate\Filesystem\Filesystem::put("C:\laragon\www\secpal\lang\.translation_io", "{"timestamp":1715527102}")

The reason is, that Laravel 11 doesn't create an lang directory by default, anymore. I'm using __('My Text'), so I created/published it neither.
A php artisan lang:publish and another php artisan translation:init fixed it.

So I think, the problem isn't the Windows environment but the missing/not published lang folder.

Folder "app" doest not exists. Gettext scan aborted.

With a vanilla Laravel 8.10.0 project, I am getting the following error when calling translation:init

Init started

   Exception

  Folder "app" doest not exists. Gettext scan aborted.

  at /var/www/project/vendor/tio/laravel/src/GettextPOGenerator.php:52
     48▕
     49▕         // Extract GetText strings from project
     50▕         foreach ($directories as $dir) {
     51▕             if (!is_dir($dir)) {
  ➜  52▕                 throw new \Exception('Folder "' . $dir . '" doest not exists. Gettext scan aborted.');
     53▕             }
     54▕
     55▕             foreach ($this->scanDir($dir) as $file) {
     56▕                 if (strstr($file, '.blade.php')) {

      +18 vendor frames
  19  /var/www/project/artisan:37
      Illuminate\Foundation\Console\Kernel::handle()

The config which directories to scan is unchanged with 'gettext_parse_paths' => ['app', 'resources'],

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.