mirror of
https://github.com/Einundzwanzig-Podcast/einundzwanzig-portal.git
synced 2025-12-11 06:46:47 +00:00
huge Laravel 10 upgrade
This commit is contained in:
35
support/laravel-translation/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
35
support/laravel-translation/.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
17
support/laravel-translation/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
support/laravel-translation/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
24
support/laravel-translation/.github/workflows/run-tests.yml
vendored
Normal file
24
support/laravel-translation/.github/workflows/run-tests.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.0
|
||||
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
|
||||
coverage: none
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --prefer-dist --no-interaction
|
||||
|
||||
- name: Execute tests
|
||||
run: vendor/bin/phpunit
|
||||
3
support/laravel-translation/.gitignore
vendored
Normal file
3
support/laravel-translation/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/vendor/
|
||||
/node_modules
|
||||
.phpunit.result.cache
|
||||
4
support/laravel-translation/.styleci.yml
Normal file
4
support/laravel-translation/.styleci.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
preset: laravel
|
||||
finder:
|
||||
exclude:
|
||||
- "tests/fixtures"
|
||||
21
support/laravel-translation/LICENSE.md
Normal file
21
support/laravel-translation/LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Joe Dixon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
44
support/laravel-translation/composer.json
Normal file
44
support/laravel-translation/composer.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "joedixon/laravel-translation",
|
||||
"description": "A tool for managing all of your Laravel translations",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Joe Dixon",
|
||||
"email": "hello@joedixon.co.uk"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"illuminate/support": "^8.0||^9.0||^10.0",
|
||||
"laravel/legacy-factories": "^1.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"orchestra/testbench": "^6.0",
|
||||
"phpunit/phpunit": "^9.0",
|
||||
"mockery/mockery": "^1.0.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"JoeDixon\\Translation\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"JoeDixon\\Translation\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit",
|
||||
"test-coverage": "vendor/bin/phpunit --coverage-html coverage"
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"JoeDixon\\Translation\\TranslationServiceProvider",
|
||||
"JoeDixon\\Translation\\TranslationBindingsServiceProvider"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
7808
support/laravel-translation/composer.lock
generated
Normal file
7808
support/laravel-translation/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
77
support/laravel-translation/config/translation.php
Normal file
77
support/laravel-translation/config/translation.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Package driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The package supports different drivers for translation management.
|
||||
|
|
||||
| Supported: "file", "database"
|
||||
|
|
||||
*/
|
||||
'driver' => 'file',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Route group configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The package ships with routes to handle language management. Update the
|
||||
| configuration here to configure the routes with your preferred group options.
|
||||
|
|
||||
*/
|
||||
'route_group_config' => [
|
||||
'middleware' => 'web',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Translation methods
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Update this array to tell the package which methods it should look for
|
||||
| when finding missing translations.
|
||||
|
|
||||
*/
|
||||
'translation_methods' => ['trans', '__'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Scan paths
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Update this array to tell the package which directories to scan when
|
||||
| looking for missing translations.
|
||||
|
|
||||
*/
|
||||
'scan_paths' => [app_path(), resource_path()],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| UI URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define the URL used to access the language management too.
|
||||
|
|
||||
*/
|
||||
'ui_url' => 'languages',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Define the settings for the database driver here.
|
||||
|
|
||||
*/
|
||||
'database' => [
|
||||
|
||||
'connection' => '',
|
||||
|
||||
'languages_table' => 'languages',
|
||||
|
||||
'translations_table' => 'translations',
|
||||
],
|
||||
];
|
||||
15
support/laravel-translation/contributing.md
Normal file
15
support/laravel-translation/contributing.md
Normal file
@@ -0,0 +1,15 @@
|
||||
CONTRIBUTING
|
||||
============
|
||||
|
||||
Contributions are welcome, and are accepted via pull requests. Please review these guidelines before submitting any pull requests.
|
||||
|
||||
## Guidelines
|
||||
|
||||
* Please follow the [PSR-2 Coding Style Guide](http://www.php-fig.org/psr/psr-2/), enforced by [StyleCI](https://styleci.io/).
|
||||
* Ensure that the current tests pass, and if you've added something new, add the tests where relevant.
|
||||
* Send a coherent commit history, making sure each individual commit in your pull request is meaningful.
|
||||
* You may need to [rebase](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) to avoid merge conflicts.
|
||||
* If you are changing the behavior, or the public api, you may need to update the docs.
|
||||
* Please remember that we follow [SemVer](http://semver.org/).
|
||||
|
||||
We have [StyleCI](https://styleci.io/) setup to automatically fix any code style issues.
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator;
|
||||
use JoeDixon\Translation\Language;
|
||||
|
||||
$factory->define(Language::class, function (Generator $faker) {
|
||||
return [
|
||||
'language' => $faker->word,
|
||||
'name' => $faker->word,
|
||||
];
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Faker\Generator;
|
||||
use JoeDixon\Translation\Language;
|
||||
use JoeDixon\Translation\Translation;
|
||||
|
||||
$factory->define(Translation::class, function (Generator $faker) {
|
||||
return [
|
||||
'language_id' => function () {
|
||||
return factory(Language::class)->create()->id;
|
||||
},
|
||||
'group' => $faker->word,
|
||||
'key' => $faker->word,
|
||||
'value' => $faker->sentence,
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Translation::class, 'group', function (Generator $faker) {
|
||||
return [
|
||||
'language_id' => function () {
|
||||
return factory(Language::class)->create()->id;
|
||||
},
|
||||
'group' => $faker->word,
|
||||
'key' => $faker->word,
|
||||
'value' => $faker->sentence,
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Translation::class, 'single', function (Generator $faker) {
|
||||
return [
|
||||
'language_id' => function () {
|
||||
return factory(Language::class)->create()->id;
|
||||
},
|
||||
'group' => 'single',
|
||||
'key' => $faker->word,
|
||||
'value' => $faker->sentence,
|
||||
];
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use JoeDixon\Translation\Language;
|
||||
|
||||
class CreateLanguagesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::connection(config('translation.database.connection'))
|
||||
->create(config('translation.database.languages_table'), function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name')->nullable();
|
||||
$table->string('language');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
$initialLanguages = array_unique([
|
||||
config('app.fallback_locale'),
|
||||
config('app.locale'),
|
||||
]);
|
||||
|
||||
foreach ($initialLanguages as $language) {
|
||||
Language::firstOrCreate([
|
||||
'language' => $language,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::connection(config('translation.database.connection'))
|
||||
->dropIfExists(config('translation.database.languages_table'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTranslationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::connection(config('translation.database.connection'))
|
||||
->create(config('translation.database.translations_table'), function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('language_id');
|
||||
$table->foreign('language_id')->references('id')
|
||||
->on(config('translation.database.languages_table'));
|
||||
$table->string('group')->nullable();
|
||||
$table->text('key');
|
||||
$table->text('value')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::connection(config('translation.database.connection'))
|
||||
->dropIfExists(config('translation.database.translations_table'));
|
||||
}
|
||||
}
|
||||
BIN
support/laravel-translation/logo.png
Normal file
BIN
support/laravel-translation/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
4
support/laravel-translation/mix-manifest.json
Normal file
4
support/laravel-translation/mix-manifest.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"/Users/joe/Code/translation/public/vendor/translation/js/app.js": "/Users/joe/Code/translation/public/vendor/translation/js/app.js",
|
||||
"/../../../public/vendor/translation/css/main.css": "/../../../public/vendor/translation/css/main.css"
|
||||
}
|
||||
21940
support/laravel-translation/package-lock.json
generated
Normal file
21940
support/laravel-translation/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
support/laravel-translation/package.json
Normal file
19
support/laravel-translation/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"watch": "NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"hot": "NODE_ENV=development webpack-dev-server --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"laravel-mix": "^4.1.2",
|
||||
"postcss": "^7.0.36",
|
||||
"tailwindcss": "^0.6.6",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.1",
|
||||
"vue": "^2.5.21"
|
||||
}
|
||||
}
|
||||
19
support/laravel-translation/phpunit.xml
Normal file
19
support/laravel-translation/phpunit.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<coverage processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">./src</directory>
|
||||
</include>
|
||||
<exclude>
|
||||
<directory>./src/Console</directory>
|
||||
</exclude>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="Feature">
|
||||
<directory suffix="Test.php">./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_KEY" value="AckfSECXIvnK5r28GVIWUAxmbBSjTsmF"/>
|
||||
</php>
|
||||
</phpunit>
|
||||
1
support/laravel-translation/public/assets/css/main.css
Normal file
1
support/laravel-translation/public/assets/css/main.css
Normal file
File diff suppressed because one or more lines are too long
1
support/laravel-translation/public/assets/js/app.js
Normal file
1
support/laravel-translation/public/assets/js/app.js
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js",
|
||||
"/css/main.css": "/css/main.css"
|
||||
}
|
||||
201
support/laravel-translation/readme.md
Normal file
201
support/laravel-translation/readme.md
Normal file
@@ -0,0 +1,201 @@
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
Translation management for your Laravel application.
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
------
|
||||
|
||||
## About Laravel Translation
|
||||
|
||||
Laravel Translation is a package for Laravel which allows you full control
|
||||
over your translations when using [Laravel's
|
||||
localization](https://laravel.com/docs/5.7/localization) functionality.
|
||||
|
||||
The package allows you to manage your translations using either the native file
|
||||
based translations, but also provides a database driver which is useful in
|
||||
multi-server setups.
|
||||
|
||||
It exposes a user interface allowing you to update existing and add new
|
||||
translations to your application.
|
||||
|
||||
Below are a full list of features:
|
||||
|
||||
- File and database drivers
|
||||
- Database translation loader (automatically load translations from the database
|
||||
when Laravel's translation retrieval methods and the database driver)
|
||||
- User interface to add new languages and add and update translations
|
||||
- Artisan commands to manage your translations
|
||||
- Scan your application for missing translations
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
| Laravel | Laravel Translation |
|
||||
| ------------- | ------------------- |
|
||||
| 6.x | 1.x |
|
||||
| 7.x | 1.x |
|
||||
| 8.x | 2.x |
|
||||
| 9.x | 2.x |
|
||||
|
||||
## Installation
|
||||
|
||||
Install the package via Composer
|
||||
|
||||
`composer require joedixon/laravel-translation`
|
||||
|
||||
Publish configuration and assets
|
||||
|
||||
`php artisan vendor:publish --provider="JoeDixon\Translation\TranslationServiceProvider"`
|
||||
|
||||
The service provider is loaded automatically using [package discovery](https://laravel.com/docs/5.7/packages#package-discovery).
|
||||
|
||||
## Usage
|
||||
|
||||
### Configuration
|
||||
|
||||
The package ships with a configuration file called `translation.php` which is published to the
|
||||
config directory during installation. Below is an outline of the settings.
|
||||
|
||||
```
|
||||
driver [file|database]
|
||||
```
|
||||
Choose either `file` or `database`. File translations utilise Laravel's native
|
||||
file based translations and includes support for both `array` based and `json` based
|
||||
language files.
|
||||
|
||||
```
|
||||
route_group_config.middleware [string|array]
|
||||
```
|
||||
Apply middleware to the routes which ship with the package. For example, you may
|
||||
which to use the `auth` middleware to ensure package user interface is only
|
||||
accessible to logged in users.
|
||||
|
||||
```
|
||||
translation_methods [array]
|
||||
```
|
||||
Choose which of Laravel's translation methods to use when searching for missing
|
||||
translation keys.
|
||||
|
||||
```
|
||||
scan_paths [array]
|
||||
```
|
||||
Choose which paths to use when searching for missing translations. Narrowing the
|
||||
search to specific directories will result in a performance increase when
|
||||
scanning for missing translations.
|
||||
|
||||
```
|
||||
ui_url [string]
|
||||
```
|
||||
Choose the root URL where the package user interface can be accessed. All routes
|
||||
will be prefixed by this value.
|
||||
|
||||
e.g. setting this value to `languages` will result in URLs such as `translations/{language}/translations`
|
||||
|
||||
```
|
||||
database.languages_table
|
||||
```
|
||||
Choose the name of the languages table when using the database driver.
|
||||
|
||||
```
|
||||
database.translations_table
|
||||
```
|
||||
Choose the name of the translations table when using the database driver.
|
||||
|
||||
### Drivers
|
||||
|
||||
#### File
|
||||
Utitlises Laravel's native php array and JSON based language files and exposes a
|
||||
user interface to manage the enclosed translations. Add and update languages and translations
|
||||
using either the user interface or the built-in [Artisan commands](https://laravel.com/docs/5.7/artisan).
|
||||
|
||||
#### Database
|
||||
The database driver takes all of the functionality of Laravel's file based
|
||||
language files, but moves the storage to the database, utilising the connection
|
||||
configured for your Laravel application.
|
||||
|
||||
It also replaces the translation loader in the container so all of Laravel's
|
||||
translation retrieval methods (`__()`, `trans()`, `@lang()`, etc) will load the
|
||||
relevant strings from the database rather than the files without the need to
|
||||
change any code in your application. It's a like for like swap.
|
||||
|
||||
To utilise the database driver, make sure to update the database table names in
|
||||
the configuration file and run the migrations.
|
||||
|
||||
#### Changing Drivers from File (default) to Database
|
||||
|
||||
1. Update the driver to use database in `./config/translation.php`.
|
||||
|
||||
```php
|
||||
'driver' => 'database'
|
||||
```
|
||||
|
||||
2. Run the migration to add translations and languages tables.
|
||||
|
||||
```shell
|
||||
php artisan migrate
|
||||
```
|
||||
|
||||
3. Run the following command and folow the prompts to synchronise the translations between drivers.
|
||||
|
||||
```shell
|
||||
php artisan translation:sync-translations
|
||||
```
|
||||
|
||||
4. A few questions will be prompted which have to be answered. See the screenshot below:
|
||||
|
||||
### User interface
|
||||
Navigate to http://your-project.test/languages (update `languages` to match the
|
||||
`translation.ui_url` configuration setting) and use the interface to manage
|
||||
your translations.
|
||||
|
||||
First, click on the language you wish to edit. On the subsequent page, find the
|
||||
translation you want to edit and click on the pencil icon or on the text and
|
||||
make your edits. As soon as you remove focus from the input, your translation
|
||||
will be saved, indicated by the green check icon.
|
||||
|
||||
### Artisan Commands
|
||||
The package ships with a series of Artisan commands which assist with
|
||||
translation management.
|
||||
|
||||
```
|
||||
translation:add-language
|
||||
```
|
||||
Add a new language to the application.
|
||||
|
||||
```
|
||||
translation:add-translation-key
|
||||
```
|
||||
Add a new language key for the application.
|
||||
|
||||
```
|
||||
translation:list-languages
|
||||
```
|
||||
List all of the available languages in the application.
|
||||
|
||||
```
|
||||
translation:list-missing-translation-keys
|
||||
```
|
||||
List all of the translation keys in the app which don't have a corresponding translation.
|
||||
|
||||
```
|
||||
translation:sync-translations
|
||||
```
|
||||
Synchronise translations between drivers. This is useful if you have an exisitng
|
||||
application using the native file based language files and wish to move to the
|
||||
database driver. Running this command will take all of the translations from the
|
||||
language files and insert them in to the database.
|
||||
|
||||
```
|
||||
translation:sync-missing-translation-keys
|
||||
```
|
||||
This command will scan your project (using the paths supplied in the
|
||||
configuration file) and create all of the missing translation keys. This can be
|
||||
run for all languages or a single language.
|
||||
|
||||
262
support/laravel-translation/resources/assets/css/main.css
Normal file
262
support/laravel-translation/resources/assets/css/main.css
Normal file
@@ -0,0 +1,262 @@
|
||||
/**
|
||||
* This injects Tailwind's base styles, which is a combination of
|
||||
* Normalize.css and some additional base styles.
|
||||
*
|
||||
* You can see the styles here:
|
||||
* https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css
|
||||
*
|
||||
* If using `postcss-import`, use this import instead:
|
||||
*
|
||||
* @import "tailwindcss/preflight";
|
||||
*/
|
||||
|
||||
@tailwind preflight;
|
||||
/**
|
||||
* This injects any component classes registered by plugins.
|
||||
*
|
||||
* If using `postcss-import`, use this import instead:
|
||||
*
|
||||
* @import "tailwindcss/components";
|
||||
*/
|
||||
|
||||
@tailwind components;
|
||||
/**
|
||||
* Here you would add any of your custom component classes; stuff that you'd
|
||||
* want loaded *before* the utilities so that the utilities could still
|
||||
* override them.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* .btn { ... }
|
||||
* .form-input { ... }
|
||||
*
|
||||
* Or if using a preprocessor or `postcss-import`:
|
||||
*
|
||||
* @import "components/buttons";
|
||||
* @import "components/forms";
|
||||
*/
|
||||
|
||||
/**
|
||||
* This injects all of Tailwind's utility classes, generated based on your
|
||||
* config file.
|
||||
*
|
||||
* If using `postcss-import`, use this import instead:
|
||||
*
|
||||
* @import "tailwindcss/utilities";
|
||||
*/
|
||||
|
||||
@tailwind utilities;
|
||||
/**
|
||||
* Here you would add any custom utilities you need that don't come out of the
|
||||
* box with Tailwind.
|
||||
*
|
||||
* Example :
|
||||
*
|
||||
* .bg-pattern-graph-paper { ... }
|
||||
* .skew-45 { ... }
|
||||
*
|
||||
* Or if using a preprocessor or `postcss-import`:
|
||||
*
|
||||
* @import "utilities/background-patterns";
|
||||
* @import "utilities/skew-transforms";
|
||||
*/
|
||||
|
||||
body {
|
||||
@apply bg-grey-lighter text-grey-darkest
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
@apply flex;
|
||||
}
|
||||
|
||||
li {
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-blue;
|
||||
}
|
||||
|
||||
nav.header {
|
||||
background: linear-gradient(90deg, #125b93, #2891c4);
|
||||
@apply border-b flex items-center h-16 text-white w-full
|
||||
}
|
||||
|
||||
nav a {
|
||||
@apply .opacity-75 text-white no-underline flex items-center
|
||||
}
|
||||
|
||||
nav a.active {
|
||||
@apply opacity-100
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
@apply opacity-100 underline
|
||||
}
|
||||
|
||||
.panel {
|
||||
@apply bg-white rounded m-6 shadow text-grey-dark
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
@apply p-4 text-lg border-b flex items-center font-thin
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
@apply border-t bg-grey-lighter p-4
|
||||
}
|
||||
|
||||
.panel-body table {
|
||||
@apply w-full table-fixed;
|
||||
}
|
||||
|
||||
.panel-body th,
|
||||
.panel-body td {
|
||||
@apply text-left p-4 overflow-x-auto
|
||||
}
|
||||
|
||||
.panel-body th {
|
||||
@apply text-grey-darker
|
||||
}
|
||||
|
||||
.panel-body td {
|
||||
@apply font-thin align-top
|
||||
}
|
||||
|
||||
.panel-body tr {
|
||||
@apply border-b
|
||||
}
|
||||
|
||||
.panel-body thead tr {
|
||||
@apply bg-grey-lighter
|
||||
}
|
||||
|
||||
.panel-body tbody tr:nth-child(even) {
|
||||
@apply bg-grey-lighter
|
||||
}
|
||||
|
||||
.panel-body tbody tr:hover,
|
||||
.panel-body tbody tr:nth-child(even):hover {
|
||||
@apply bg-blue-lightest
|
||||
}
|
||||
|
||||
.panel-body tbody tr:last-child {
|
||||
@apply border-none
|
||||
}
|
||||
|
||||
.panel-body td textarea {
|
||||
overflow-wrap: inherit;
|
||||
@apply border-none resize-none bg-transparent text-grey-darker w-full font-thin h-auto p-0
|
||||
}
|
||||
|
||||
.panel-body td textarea.active {
|
||||
@apply w-full rounded h-32 p-2 border border-solid border-grey
|
||||
}
|
||||
|
||||
.panel-body td textarea:focus {
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply bg-transparent text-grey-darker py-2 px-4 border border-grey rounded text-sm font-bold no-underline
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
@apply text-blue
|
||||
}
|
||||
|
||||
.button-blue {
|
||||
@apply bg-blue text-white border-blue
|
||||
}
|
||||
|
||||
.button-blue:hover {
|
||||
@apply text-white bg-blue-dark
|
||||
}
|
||||
|
||||
.input-group {
|
||||
@apply w-full mb-6
|
||||
}
|
||||
|
||||
.input-group label {
|
||||
@apply block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2
|
||||
}
|
||||
|
||||
.input-group input {
|
||||
@apply appearance-none block w-full bg-grey-lighter text-grey-darker border rounded py-3 px-4 mb-3 leading-tight
|
||||
}
|
||||
|
||||
.input-group:last-child {
|
||||
@apply mb-0
|
||||
}
|
||||
|
||||
.input-group input.error {
|
||||
@apply border-red
|
||||
}
|
||||
|
||||
.input-group .error-text {
|
||||
@apply text-red text-xs italic
|
||||
}
|
||||
|
||||
.select-group {
|
||||
@apply relative mr-2
|
||||
}
|
||||
|
||||
.select-group:last-child {
|
||||
@apply m-0
|
||||
}
|
||||
|
||||
.select-group select {
|
||||
@apply text-base block appearance-none bg-white border text-grey-darker uppercase py-2 px-4 pr-8 rounded leading-tight max-w-xs font-thin
|
||||
}
|
||||
|
||||
.select-group select:focus {
|
||||
@apply outline-none border-grey
|
||||
}
|
||||
|
||||
.select-group .caret {
|
||||
@apply pointer-events-none absolute pin-y pin-r flex items-center px-2 text-grey-darker
|
||||
}
|
||||
|
||||
.select-group .caret svg {
|
||||
@apply fill-current h-4 w-4
|
||||
}
|
||||
|
||||
.w-1\/10 {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
background: url('data:image/svg+xml;charset=utf8,<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com"><path d="M 11.732 12.439 C 9.047 14.525 5.109 12.921 4.645 9.553 C 4.181 6.183 7.538 3.575 10.689 4.858 C 13.399 5.962 14.306 9.349 12.512 11.66 L 15.466 14.603 L 14.682 15.388 L 11.738 12.439 Z M 9.027 12.263 C 11.577 12.263 13.172 9.5 11.897 7.291 C 11.304 6.267 10.21 5.634 9.027 5.634 C 6.476 5.634 4.88 8.397 6.157 10.606 C 6.749 11.63 7.842 12.263 9.027 12.263 Z" style="fill: rgb(96, 111, 123);"/></svg>');
|
||||
@apply bg-grey-lighter rounded pl-10 py-2 pr-4 bg-no-repeat bg-contain transition border text-grey-darker font-thin w-full
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
@apply outline-none bg-white border border-grey-light
|
||||
}
|
||||
|
||||
.transition {
|
||||
transition: all .1s ease-in;
|
||||
}
|
||||
|
||||
.search {
|
||||
max-width: 500px;
|
||||
@apply mx-2 relative flex-1
|
||||
}
|
||||
|
||||
ul.search-results {
|
||||
max-height: 300px;
|
||||
@apply font-thin pl-0 block absolute w-full bg-grey-lighter border border-t-0 rounded rounded-t-none overflow-x-hidden overflow-y-scroll
|
||||
}
|
||||
|
||||
ul.search-results li {
|
||||
@apply px-4 py-2 border-b pl-10;
|
||||
}
|
||||
|
||||
ul.search-results li:last-child {
|
||||
@apply border-b-0;
|
||||
}
|
||||
|
||||
.search.has-results .search-input {
|
||||
@apply border-b-0 rounded-b-none bg-white
|
||||
}
|
||||
63
support/laravel-translation/resources/assets/js/app.js
Normal file
63
support/laravel-translation/resources/assets/js/app.js
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
/**
|
||||
* First we will load all of this project's JavaScript dependencies which
|
||||
* includes Vue and other libraries. It is a great starting point when
|
||||
* building robust, powerful web applications using Vue and Laravel.
|
||||
*/
|
||||
|
||||
// require('./bootstrap');
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
window.axios = require('axios');
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Next we will register the CSRF Token as a common header with Axios so that
|
||||
* all outgoing HTTP requests automatically have it attached. This is just
|
||||
* a simple convenience so we don't have to attach every token manually.
|
||||
*/
|
||||
|
||||
let token = document.head.querySelector('meta[name="csrf-token"]');
|
||||
|
||||
if (token) {
|
||||
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
|
||||
} else {
|
||||
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
|
||||
}
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
/**
|
||||
* Next, we will create a fresh Vue application instance and attach it to
|
||||
* the page. Then, you may begin adding components to this application
|
||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||
*/
|
||||
|
||||
Vue.component('translation-input', require('./components/TranslationInput.vue').default);
|
||||
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
showAdvancedOptions: false,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
submit: function(event) {
|
||||
event.target.form.submit();
|
||||
},
|
||||
|
||||
toggleAdvancedOptions(event) {
|
||||
event.preventDefault();
|
||||
this.showAdvancedOptions = !this.showAdvancedOptions;
|
||||
}
|
||||
}
|
||||
});
|
||||
56
support/laravel-translation/resources/assets/js/bootstrap.js
vendored
Normal file
56
support/laravel-translation/resources/assets/js/bootstrap.js
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
window._ = require('lodash');
|
||||
window.Popper = require('popper.js').default;
|
||||
|
||||
/**
|
||||
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
|
||||
* for JavaScript based Bootstrap features such as modals and tabs. This
|
||||
* code may be modified to fit the specific needs of your application.
|
||||
*/
|
||||
|
||||
try {
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
|
||||
require('bootstrap');
|
||||
} catch (e) {}
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
window.axios = require('axios');
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Next we will register the CSRF Token as a common header with Axios so that
|
||||
* all outgoing HTTP requests automatically have it attached. This is just
|
||||
* a simple convenience so we don't have to attach every token manually.
|
||||
*/
|
||||
|
||||
let token = document.head.querySelector('meta[name="csrf-token"]');
|
||||
|
||||
if (token) {
|
||||
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
|
||||
} else {
|
||||
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo'
|
||||
|
||||
// window.Pusher = require('pusher-js');
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: process.env.MIX_PUSHER_APP_KEY,
|
||||
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
|
||||
// encrypted: true
|
||||
// });
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div class="flex">
|
||||
<svg v-show="!isActive && isLoading" v-on:click="setActive" class="cursor-pointer fill-current w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M0 2C0 .9.9 0 2 0h14l4 4v14a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2zm5 0v6h10V2H5zm6 1h3v4h-3V3z"/></svg>
|
||||
<svg v-show="!isActive && hasSaved" v-on:click="setActive" class="cursor-pointer fill-current text-green w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm12.73-1.41A8 8 0 1 0 4.34 4.34a8 8 0 0 0 11.32 11.32zM6.7 9.29L9 11.6l4.3-4.3 1.4 1.42L9 14.4l-3.7-3.7 1.4-1.42z"/></svg>
|
||||
<svg v-show="!isActive && hasErrored" v-on:click="setActive" class="cursor-pointer fill-current text-red w-5 h-5 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M2.93 17.07A10 10 0 1 1 17.07 2.93 10 10 0 0 1 2.93 17.07zm1.41-1.41A8 8 0 1 0 15.66 4.34 8 8 0 0 0 4.34 15.66zm9.9-8.49L11.41 10l2.83 2.83-1.41 1.41L10 11.41l-2.83 2.83-1.41-1.41L8.59 10 5.76 7.17l1.41-1.41L10 8.59l2.83-2.83 1.41 1.41z"/></svg>
|
||||
<svg v-show="!isActive && !hasSaved && !hasErrored && !isLoading" v-on:click="setActive" class="cursor-pointer fill-current w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M12.3 3.7l4 4L4 20H0v-4L12.3 3.7zm1.4-1.4L16 0l4 4-2.3 2.3-4-4z"/></svg>
|
||||
<textarea
|
||||
rows="1"
|
||||
v-model="translation"
|
||||
v-bind:class="{ active: isActive }"
|
||||
v-on:focus="setActive"
|
||||
v-on:blur="storeTranslation"
|
||||
ref="trans"
|
||||
></textarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['initialTranslation', 'language', 'group', 'translationKey', 'route'],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
isActive: false,
|
||||
hasSaved: false,
|
||||
hasErrored: false,
|
||||
isLoading: false,
|
||||
hasChanged: false,
|
||||
translation: this.initialTranslation
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
setActive: function() {
|
||||
this.isActive = true;
|
||||
this.$refs.trans.focus();
|
||||
},
|
||||
storeTranslation: function() {
|
||||
this.isActive = false;
|
||||
if(!this.hasChanged) {
|
||||
return;
|
||||
}
|
||||
this.isLoading = true;
|
||||
window.axios.post(`/${this.route}/${this.language}`, {
|
||||
language: this.language,
|
||||
group: this.group,
|
||||
key: this.translationKey,
|
||||
value: this.translation
|
||||
}).then((response) => {
|
||||
this.hasSaved = true;
|
||||
this.isLoading = false;
|
||||
this.hasChanged = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.hasErrored = true;
|
||||
this.isLoading = false;
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
hasSaved: function(hasSaved) {
|
||||
if(hasSaved) {
|
||||
setTimeout(() => { this.hasSaved = false }, 3000)
|
||||
}
|
||||
},
|
||||
hasErrored: function(hasErrored) {
|
||||
if(hasErrored) {
|
||||
setTimeout(() => { this.hasErrored = false }, 3000)
|
||||
}
|
||||
},
|
||||
translation: function(translation)
|
||||
{
|
||||
this.hasChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
113
support/laravel-translation/resources/helpers.php
Normal file
113
support/laravel-translation/resources/helpers.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
if (! function_exists('set_active')) {
|
||||
/**
|
||||
* Determine if a route is the currently active route.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $class
|
||||
* @return string
|
||||
*/
|
||||
function set_active($path, $class = 'active')
|
||||
{
|
||||
return Request::is(config('translation.ui_url').$path) ? $class : '';
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('strs_contain')) {
|
||||
/**
|
||||
* Determine whether any of the provided strings in the haystack contain the needle.
|
||||
*
|
||||
* @param array $haystacks
|
||||
* @param string $needle
|
||||
* @return bool
|
||||
*/
|
||||
function strs_contain($haystacks, $needle)
|
||||
{
|
||||
$haystacks = (array) $haystacks;
|
||||
|
||||
foreach ($haystacks as $haystack) {
|
||||
if (is_array($haystack)) {
|
||||
return strs_contain($haystack, $needle);
|
||||
} elseif (Str::contains(strtolower($haystack), strtolower($needle))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('array_diff_assoc_recursive')) {
|
||||
/**
|
||||
* Recursively diff two arrays.
|
||||
*
|
||||
* @param array $arrayOne
|
||||
* @param array $arrayTwo
|
||||
* @return array
|
||||
*/
|
||||
function array_diff_assoc_recursive($arrayOne, $arrayTwo)
|
||||
{
|
||||
$difference = [];
|
||||
foreach ($arrayOne as $key => $value) {
|
||||
if (is_array($value) || $value instanceof Illuminate\Support\Collection) {
|
||||
if (! isset($arrayTwo[$key])) {
|
||||
$difference[$key] = $value;
|
||||
} elseif (! (is_array($arrayTwo[$key]) || $arrayTwo[$key] instanceof Illuminate\Support\Collection)) {
|
||||
$difference[$key] = $value;
|
||||
} else {
|
||||
$new_diff = array_diff_assoc_recursive($value, $arrayTwo[$key]);
|
||||
if ($new_diff != false) {
|
||||
$difference[$key] = $new_diff;
|
||||
}
|
||||
}
|
||||
} elseif (! isset($arrayTwo[$key])) {
|
||||
$difference[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $difference;
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('str_before')) {
|
||||
/**
|
||||
* Get the portion of a string before a given value.
|
||||
*
|
||||
* @param string $subject
|
||||
* @param string $search
|
||||
* @return string
|
||||
*/
|
||||
function str_before($subject, $search)
|
||||
{
|
||||
return $search === '' ? $subject : explode($search, $subject)[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Array undot
|
||||
if (! function_exists('array_undot')) {
|
||||
/**
|
||||
* Expands a single level array with dot notation into a multi-dimensional array.
|
||||
*
|
||||
* @param array $dotNotationArray
|
||||
* @return array
|
||||
*/
|
||||
function array_undot(array $dotNotationArray)
|
||||
{
|
||||
$array = [];
|
||||
foreach ($dotNotationArray as $key => $value) {
|
||||
// if there is a space after the dot, this could legitimately be
|
||||
// a single key and not nested.
|
||||
if (count(explode('. ', $key)) > 1) {
|
||||
$array[$key] = $value;
|
||||
} else {
|
||||
Arr::set($array, $key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
6
support/laravel-translation/resources/lang/de/errors.php
Normal file
6
support/laravel-translation/resources/lang/de/errors.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'language_exists' => 'Die Sprache { :language } ist bereits vorhanden',
|
||||
'key_exists' => 'Der Übersetzungsschlüssel { :key } ist bereits vorhanden',
|
||||
];
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'languages' => 'Sprachen',
|
||||
'language' => 'Sprache',
|
||||
'type' => 'Typ',
|
||||
'file' => 'Datei',
|
||||
'key' => 'Schlüssel',
|
||||
'prompt_language' => 'Geben Sie den Sprachcode ein, den Sie hinzufügen möchten (z.B. en).',
|
||||
'language_added' => 'Neue Sprache wurde erfolgreich hinzugefügt 🙌',
|
||||
'prompt_language_for_key' => 'Geben Sie die Sprache für den Schlüssel ein (z.B. en)',
|
||||
'prompt_type' => 'Ist das ein Json- oder Array-Schlüssel?',
|
||||
'prompt_file' => 'In welcher Datei wird das gespeichert?',
|
||||
'prompt_key' => 'Was ist der Schlüssel für diese Übersetzung?',
|
||||
'prompt_value' => 'Was ist der Wert für diese Übersetzung',
|
||||
'type_error' => 'Übersetzungstyp muss json oder ein Array sein',
|
||||
'language_key_added' => 'Neuer Sprachenschlüssel wurde erfolgreich hinzugefügt 👏',
|
||||
'no_missing_keys' => 'Es fehlen keine Übersetzungsschlüssel in der App 🎉',
|
||||
'keys_synced' => 'Fehlende Schlüssel erfolgreich synchronisiert 🎊',
|
||||
'search' => 'Alle Übersetzungen suchen',
|
||||
'translations' => 'Übersetzung',
|
||||
'language_name' => 'Name',
|
||||
'locale' => 'locale',
|
||||
'add' => '+ Hinzufügen',
|
||||
'add_language' => 'Neue Sprache hinzufügen',
|
||||
'save' => 'save',
|
||||
'language_exists' => 'Das :attribute ist bereits vorhanden.',
|
||||
'uh_oh' => 'Etwas ist nicht ganz richtig',
|
||||
'group_single' => 'Gruppe / Single',
|
||||
'Gruppe' => 'Gruppe',
|
||||
'single' => 'single',
|
||||
'value' => 'Wert',
|
||||
'namespace' => 'Namespace',
|
||||
'synchronisieren' => 'Übersetzungen synchronisieren ⏳',
|
||||
'synced' => 'Übersetzungen wurden synchronisiert 😎',
|
||||
'add_translation' => 'Übersetzung hinzufügen',
|
||||
'translation_added' => 'Neue Übersetzung erfolgreich hinzugefügt 🙌',
|
||||
'namespace_label' => 'Namespace (optional)',
|
||||
'group_label' => 'Gruppe (optional)',
|
||||
'key_label' => 'Schlüssel',
|
||||
'value_label' => 'Wert',
|
||||
'namespace_placeholder' => 'z.B. my_package',
|
||||
'group_placeholder' => 'z.B. validation',
|
||||
'key_placeholder' => 'z.B. invalid_key',
|
||||
'value_placeholder' => 'z.B. Schlüssel müssen eine einzige Zeichenfolge sein',
|
||||
'advanced_options' => 'Erweiterte Optionen umschalten',
|
||||
];
|
||||
6
support/laravel-translation/resources/lang/en/errors.php
Normal file
6
support/laravel-translation/resources/lang/en/errors.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'language_exists' => 'The language { :language } already exists',
|
||||
'key_exists' => 'The translation key { :key } already exists',
|
||||
];
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'languages' => 'Languages',
|
||||
'language' => 'Language',
|
||||
'type' => 'Type',
|
||||
'file' => 'File',
|
||||
'key' => 'Key',
|
||||
'prompt_language' => 'Enter the language code you would like to add (e.g. en)',
|
||||
'language_added' => 'New language added successfully 🙌',
|
||||
'prompt_language_for_key' => 'Enter the language for the key (e.g. en)',
|
||||
'prompt_type' => 'Is this a json or array key?',
|
||||
'prompt_file' => 'Which file will this be stored in?',
|
||||
'prompt_key' => 'What is the key for this translation?',
|
||||
'prompt_value' => 'What is the value for this translation',
|
||||
'type_error' => 'Translation type must be json or array',
|
||||
'language_key_added' => 'New language key added successfully 👏',
|
||||
'no_missing_keys' => 'There are no missing translation keys in the app 🎉',
|
||||
'keys_synced' => 'Missing keys synchronised successfully 🎊',
|
||||
'search' => 'Search all translations',
|
||||
'translations' => 'Translation',
|
||||
'language_name' => 'Name',
|
||||
'locale' => 'Locale',
|
||||
'add' => '+ Add',
|
||||
'add_language' => 'Add a new language',
|
||||
'save' => 'Save',
|
||||
'language_exists' => 'The :attribute already exists.',
|
||||
'uh_oh' => 'Something\'s not quite right',
|
||||
'group_single' => 'Group / Single',
|
||||
'group' => 'Group',
|
||||
'single' => 'Single',
|
||||
'value' => 'Value',
|
||||
'namespace' => 'Namespace',
|
||||
'add_translation' => 'Add a translation',
|
||||
'translation_added' => 'New translation added successfull 🙌',
|
||||
'namespace_label' => 'Namespace (Optional)',
|
||||
'group_label' => 'Group (Optional)',
|
||||
'key_label' => 'Key',
|
||||
'value_label' => 'Value',
|
||||
'namespace_placeholder' => 'e.g. my_package',
|
||||
'group_placeholder' => 'e.g. validation',
|
||||
'key_placeholder' => 'e.g. invalid_key',
|
||||
'value_placeholder' => 'e.g. Keys must be a single string',
|
||||
'advanced_options' => 'Toggle advanced options',
|
||||
];
|
||||
6
support/laravel-translation/resources/lang/fr/errors.php
Normal file
6
support/laravel-translation/resources/lang/fr/errors.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'key_exists' => 'La clé de traduction { :key } existe déjà',
|
||||
'language_exists' => 'La langue { :language } existe déjà',
|
||||
];
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'add' => '+ Ajouter',
|
||||
'add_language' => 'Ajouter une nouvelle langue',
|
||||
'add_translation' => 'Ajouter une traduction',
|
||||
'advanced_options' => 'Afficher les options avancées',
|
||||
'file' => 'Fichier',
|
||||
'group' => 'Groupe',
|
||||
'group_label' => 'Groupe (Optionnel)',
|
||||
'group_placeholder' => 'Ex: validation',
|
||||
'group_single' => 'Groupe / Unique',
|
||||
'key' => 'Clé',
|
||||
'key_label' => 'Clé',
|
||||
'key_placeholder' => 'Par exemple : invalid_key',
|
||||
'keys_synced' => 'Clés manquantes synchronisées avec succès 🎊',
|
||||
'language' => 'Langue',
|
||||
'language_added' => 'Nouvelle langue ajoutée avec succés 🙌',
|
||||
'language_exists' => 'Le :attribute existe déjà.',
|
||||
'language_key_added' => 'Nouvelle clé dans la langue ajoutée avec succès 👏',
|
||||
'language_name' => 'Nom',
|
||||
'languages' => 'Langues',
|
||||
'locale' => 'Locale',
|
||||
'namespace' => 'Namespace',
|
||||
'namespace_label' => 'Namespace (Optionnel)',
|
||||
'namespace_placeholder' => 'Par exemple : my_package',
|
||||
'no_missing_keys' => 'Il ne manque aucune clé de traduction dans l\'application 🎉',
|
||||
'prompt_file' => 'Dans quel fichier sera t\'elle stockée ?',
|
||||
'prompt_key' => 'Quelle est la clé de cette traduction ?',
|
||||
'prompt_language' => 'Entrez le code langue que vous aimeriez ajouter (Ex: fr)',
|
||||
'prompt_language_for_key' => 'Entrez la langue pour la clé (Ex: fr)',
|
||||
'prompt_type' => 'Est-ce une clé Json ou Array ?',
|
||||
'prompt_value' => 'Quelle est la valeur de la traduction',
|
||||
'save' => 'Sauvegarder',
|
||||
'search' => 'Rechercher toutes les traductions',
|
||||
'single' => 'Unique',
|
||||
'translation_added' => 'Nouvelle traduction ajoutée avec succès 🙌',
|
||||
'translations' => 'Traduction',
|
||||
'type' => 'Type',
|
||||
'type_error' => 'Le type de traduction doit être en json ou en array',
|
||||
'uh_oh' => 'Quelque chose ne fonctionne pas',
|
||||
'value' => 'Valeur',
|
||||
'value_label' => 'Valeur',
|
||||
'value_placeholder' => 'Par exemple : Les clés doivent être une seule chaîne',
|
||||
];
|
||||
6
support/laravel-translation/resources/lang/nl/errors.php
Normal file
6
support/laravel-translation/resources/lang/nl/errors.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'language_exists' => 'De taal { :language } bestaat al',
|
||||
'key_exists' => 'De vertaalsleutel { :key } bestaat al',
|
||||
];
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'languages' => 'Talen',
|
||||
'language' => 'Taal',
|
||||
'type' => 'Type',
|
||||
'file' => 'Bestand',
|
||||
'key' => 'Sleutel',
|
||||
'prompt_language' => 'Voer de taalcode in die u wilt toevoegen (bijvoorbeeld: en)',
|
||||
'language_added' => 'Nieuwe taal met succes toegevoegd 🙌',
|
||||
'prompt_language_for_key' => 'Voer de taal voor de sleutel in (bijvoorbeeld: en)',
|
||||
'prompt_type' => 'Is dit een json- of arraysleutel?',
|
||||
'prompt_file' => 'In welk bestand wordt dit opgeslagen?',
|
||||
'prompt_key' => 'Wat is de sleutel voor deze vertaling?',
|
||||
'prompt_value' => 'Wat is de text voor deze vertaling',
|
||||
'type_error' => 'Het vertaaltype moet json of array zijn',
|
||||
'language_key_added' => 'Nieuwe taalcode toegevoegd 👏',
|
||||
'no_missing_keys' => 'Er zijn geen ontbrekende vertaalsleutels in de app 🎉',
|
||||
'keys_synced' => 'Ontbrekende toetsen gesynchroniseerd met succes 🎊',
|
||||
'search' => 'Doorzoek alle vertalingen',
|
||||
'translations' => 'Vertaling',
|
||||
'language_name' => 'Naam',
|
||||
'locale' => 'locale',
|
||||
'add' => '+ Toevoegen',
|
||||
'add_language' => 'Voeg een nieuwe taal toe',
|
||||
'save' => 'Opslaan',
|
||||
'language_exists' => 'Het kenmerk :attribute bestaat al.',
|
||||
'uh_oh' => 'Er klopt iets niet helemaal',
|
||||
'group_single' => 'Groep / Enkelvoudig',
|
||||
'group' => 'Groep',
|
||||
'single' => 'Enkelvoudig',
|
||||
'value' => 'Waarde',
|
||||
'namespace' => 'Namespace',
|
||||
'add_translation' => 'Voeg een vertaling toe',
|
||||
'translation_added' => 'Nieuwe vertaling succesvol toegevoegd 🙌',
|
||||
'namespace_label' => 'Namespace (optioneel)',
|
||||
'group_label' => 'Groep (optioneel)',
|
||||
'key_label' => 'Sleutel',
|
||||
'value_label' => 'Waarde',
|
||||
'namespace_placeholder' => 'bijv. Mijn_pakket',
|
||||
'group_placeholder' => 'bijv. bevestiging',
|
||||
'key_placeholder' => 'bijv. ongeldige sleutel',
|
||||
'value_placeholder' => 'bijv. Sleutels mogen geen spaties bevatten',
|
||||
'advanced_options' => 'Schakel geavanceerde opties in',
|
||||
];
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="search">
|
||||
<input type="text" class="search-input" placeholder="{{ __('translation::translation.search') }}" name="{{ $name }}" value="{{ $value }}">
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<div class="select-group">
|
||||
|
||||
<select name="{{ $name }}" @if(isset($submit) && $submit) v-on:change="submit" @endif>
|
||||
@if(isset($optional) && $optional)<option value> ----- </option>@endif
|
||||
@foreach($items as $key => $value)
|
||||
@if(is_numeric($key))
|
||||
<option value="{{ $value }}" @if(isset($selected) && $selected === $value) selected="selected" @endif>{{ $value }}</option>
|
||||
@else
|
||||
<option value="{{ $key }}" @if(isset($selected) && $selected === $key) selected="selected" @endif>{{ $value }}</option>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
|
||||
<div class="caret">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<div class="input-group">
|
||||
<label for="{{ $field }}">
|
||||
{{ $label }}
|
||||
</label>
|
||||
<input
|
||||
class="@if($errors->has($field)) error @endif"
|
||||
name="{{ $field }}"
|
||||
id="{{ $field }}"
|
||||
type="text"
|
||||
placeholder="{{ isset($placeholder) ? $placeholder : '' }}"
|
||||
value="{{ old($field) }}"
|
||||
{{ isset($required) ? 'required' : '' }}>
|
||||
@if($errors->has($field))
|
||||
@foreach($errors->get($field) as $error)
|
||||
<p class="error-text">{!! $error !!}</p>
|
||||
@endforeach
|
||||
@endif
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
<svg class="{{ isset($class) ? $class : 'fill-current w-4 h-4 mr-2' }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 20a10 10 0 1 1 0-20 10 10 0 0 1 0 20zm2-2.25a8 8 0 0 0 4-2.46V9a2 2 0 0 1-2-2V3.07a7.95 7.95 0 0 0-3-1V3a2 2 0 0 1-2 2v1a2 2 0 0 1-2 2v2h3a2 2 0 0 1 2 2v5.75zm-4 0V15a2 2 0 0 1-2-2v-1h-.5A1.5 1.5 0 0 1 4 10.5V8H2.25A8.01 8.01 0 0 0 8 17.75z"/></svg>
|
||||
|
After Width: | Height: | Size: 389 B |
@@ -0,0 +1 @@
|
||||
<svg class="{{ isset($class) ? $class : 'fill-current w-4 h-4 mr-2' }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M7.41 9l2.24 2.24-.83 2L6 10.4l-3.3 3.3-1.4-1.42L4.58 9l-.88-.88c-.53-.53-1-1.3-1.3-2.12h2.2c.15.28.33.53.51.7l.89.9.88-.88C7.48 6.1 8 4.84 8 4H0V2h5V0h2v2h5v2h-2c0 1.37-.74 3.15-1.7 4.12L7.4 9zm3.84 8L10 20H8l5-12h2l5 12h-2l-1.25-3h-5.5zm.83-2h3.84L14 10.4 12.08 15z"/></svg>
|
||||
|
After Width: | Height: | Size: 412 B |
@@ -0,0 +1,41 @@
|
||||
@extends('translation::layout')
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="panel w-1/2">
|
||||
|
||||
<div class="panel-header">
|
||||
|
||||
{{ __('translation::translation.add_language') }}
|
||||
|
||||
</div>
|
||||
|
||||
<form action="{{ route('languages.store') }}" method="POST">
|
||||
|
||||
<fieldset>
|
||||
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<div class="panel-body p-4">
|
||||
|
||||
@include('translation::forms.text', ['field' => 'name', 'label' => __('translation::translation.language_name'), ])
|
||||
|
||||
@include('translation::forms.text', ['field' => 'locale', 'label' => __('translation::translation.locale'), ])
|
||||
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div class="panel-footer flex flex-row-reverse">
|
||||
|
||||
<button class="button button-blue">
|
||||
{{ __('translation::translation.save') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,56 @@
|
||||
@extends('translation::layout')
|
||||
|
||||
@section('body')
|
||||
|
||||
@if(count($languages))
|
||||
|
||||
<div class="panel w-1/2">
|
||||
|
||||
<div class="panel-header">
|
||||
|
||||
{{ __('translation::translation.languages') }}
|
||||
|
||||
<div class="flex flex-grow justify-end items-center">
|
||||
|
||||
<a href="{{ route('languages.create') }}" class="button">
|
||||
{{ __('translation::translation.add') }}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('translation::translation.language_name') }}</th>
|
||||
<th>{{ __('translation::translation.locale') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach($languages as $language => $name)
|
||||
<tr>
|
||||
<td>
|
||||
{{ $name }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('languages.translations.index', $language) }}">
|
||||
{{ $language }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endif
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,56 @@
|
||||
@extends('translation::layout')
|
||||
|
||||
@section('body')
|
||||
|
||||
<div class="panel w-1/2">
|
||||
|
||||
<div class="panel-header">
|
||||
|
||||
{{ __('translation::translation.add_translation') }}
|
||||
|
||||
</div>
|
||||
|
||||
<form action="{{ route('languages.translations.store', $language) }}" method="POST">
|
||||
|
||||
<fieldset>
|
||||
|
||||
<input type="hidden" name="_token" value="{{ csrf_token() }}">
|
||||
|
||||
<div class="panel-body p-4">
|
||||
|
||||
@include('translation::forms.text', ['field' => 'group', 'label' => __('translation::translation.group_label'), 'placeholder' => __('translation::translation.group_placeholder')])
|
||||
|
||||
@include('translation::forms.text', ['field' => 'key', 'label' => __('translation::translation.key_label'), 'placeholder' => __('translation::translation.key_placeholder')])
|
||||
|
||||
@include('translation::forms.text', ['field' => 'value', 'label' => __('translation::translation.value_label'), 'placeholder' => __('translation::translation.value_placeholder')])
|
||||
|
||||
<div class="input-group">
|
||||
|
||||
<button v-on:click="toggleAdvancedOptions" class="text-blue">{{ __('translation::translation.advanced_options') }}</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-show="showAdvancedOptions">
|
||||
|
||||
@include('translation::forms.text', ['field' => 'namespace', 'label' => __('translation::translation.namespace_label'), 'placeholder' => __('translation::translation.namespace_placeholder')])
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div class="panel-footer flex flex-row-reverse">
|
||||
|
||||
<button class="button button-blue">
|
||||
{{ __('translation::translation.save') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
@@ -0,0 +1,89 @@
|
||||
@extends('translation::layout')
|
||||
|
||||
@section('body')
|
||||
|
||||
<form action="{{ route('languages.translations.index', ['language' => $language]) }}" method="get">
|
||||
|
||||
<div class="panel">
|
||||
|
||||
<div class="panel-header">
|
||||
|
||||
{{ __('translation::translation.translations') }}
|
||||
|
||||
<div class="flex flex-grow justify-end items-center">
|
||||
|
||||
@include('translation::forms.search', ['name' => 'filter', 'value' => Request::get('filter')])
|
||||
|
||||
@include('translation::forms.select', ['name' => 'language', 'items' => $languages, 'submit' => true, 'selected' => $language])
|
||||
|
||||
<div class="sm:hidden lg:flex items-center">
|
||||
|
||||
@include('translation::forms.select', ['name' => 'group', 'items' => $groups, 'submit' => true, 'selected' => Request::get('group'), 'optional' => true])
|
||||
|
||||
<a href="{{ route('languages.translations.create', $language) }}" class="button">
|
||||
{{ __('translation::translation.add') }}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
|
||||
@if(count($translations))
|
||||
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="w-1/5 uppercase font-thin">{{ __('translation::translation.group_single') }}</th>
|
||||
<th class="w-1/5 uppercase font-thin">{{ __('translation::translation.key') }}</th>
|
||||
<th class="uppercase font-thin">{{ config('app.locale') }}</th>
|
||||
<th class="uppercase font-thin">{{ $language }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
@foreach($translations as $type => $items)
|
||||
|
||||
@foreach($items as $group => $translations)
|
||||
|
||||
@foreach($translations as $key => $value)
|
||||
|
||||
@if(!is_array($value[config('app.locale')]))
|
||||
<tr>
|
||||
<td>{{ $group }}</td>
|
||||
<td>{{ $key }}</td>
|
||||
<td>{{ $value[config('app.locale')] }}</td>
|
||||
<td>
|
||||
<translation-input
|
||||
initial-translation="{{ $value[$language] }}"
|
||||
language="{{ $language }}"
|
||||
group="{{ $group }}"
|
||||
translation-key="{{ $key }}"
|
||||
route="{{ config('translation.ui_url') }}">
|
||||
</translation-input>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
|
||||
@endforeach
|
||||
|
||||
@endforeach
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
@endsection
|
||||
24
support/laravel-translation/resources/views/layout.blade.php
Normal file
24
support/laravel-translation/resources/views/layout.blade.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>{{ config('app.name') }}</title>
|
||||
<link rel="stylesheet" href="{{ asset('/vendor/translation/css/main.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app">
|
||||
|
||||
@include('translation::nav')
|
||||
@include('translation::notifications')
|
||||
|
||||
@yield('body')
|
||||
|
||||
</div>
|
||||
|
||||
<script src="{{ asset('/vendor/translation/js/app.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
20
support/laravel-translation/resources/views/nav.blade.php
Normal file
20
support/laravel-translation/resources/views/nav.blade.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<nav class="header">
|
||||
|
||||
<h1 class="text-lg px-6">{{ config('app.name') }}</h1>
|
||||
|
||||
<ul class="flex-grow justify-end pr-2">
|
||||
<li>
|
||||
<a href="{{ route('languages.index') }}" class="{{ set_active('') }}{{ set_active('/create') }}">
|
||||
@include('translation::icons.globe')
|
||||
{{ __('translation::translation.languages') }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('languages.translations.index', config('app.locale')) }}" class="{{ set_active('*/translations') }}">
|
||||
@include('translation::icons.translate')
|
||||
{{ __('translation::translation.translations') }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
@@ -0,0 +1,15 @@
|
||||
@if(Session::has('success'))
|
||||
<div class="bg-green-lightest text-green-darker p-6 shadow-md" role="alert">
|
||||
<div class="flex justify-center">
|
||||
<p>{{ Session::get('success') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(Session::has('error'))
|
||||
<div class="bg-red-lightest text-red-darker p-6 shadow-md" role="alert">
|
||||
<div class="flex justify-center">
|
||||
<p>{!! Session::get('error') !!}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
24
support/laravel-translation/routes/web.php
Normal file
24
support/laravel-translation/routes/web.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
Route::group(config('translation.route_group_config') + ['namespace' => 'JoeDixon\\Translation\\Http\\Controllers'], function ($router) {
|
||||
$router->get(config('translation.ui_url'), 'LanguageController@index')
|
||||
->name('languages.index');
|
||||
|
||||
$router->get(config('translation.ui_url').'/create', 'LanguageController@create')
|
||||
->name('languages.create');
|
||||
|
||||
$router->post(config('translation.ui_url'), 'LanguageController@store')
|
||||
->name('languages.store');
|
||||
|
||||
$router->get(config('translation.ui_url').'/{language}/translations', 'LanguageTranslationController@index')
|
||||
->name('languages.translations.index');
|
||||
|
||||
$router->post(config('translation.ui_url').'/{language}', 'LanguageTranslationController@update')
|
||||
->name('languages.translations.update');
|
||||
|
||||
$router->get(config('translation.ui_url').'/{language}/translations/create', 'LanguageTranslationController@create')
|
||||
->name('languages.translations.create');
|
||||
|
||||
$router->post(config('translation.ui_url').'/{language}/translations', 'LanguageTranslationController@store')
|
||||
->name('languages.translations.store');
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
class AddLanguageCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'translation:add-language';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add a new language to the application';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// ask the user for the language they wish to add
|
||||
$language = $this->ask(__('translation::translation.prompt_language'));
|
||||
$name = $this->ask(__('translation::translation.prompt_name'));
|
||||
|
||||
// attempt to add the key and fail gracefully if exception thrown
|
||||
try {
|
||||
$this->translation->addLanguage($language, $name);
|
||||
$this->info(__('translation::translation.language_added'));
|
||||
} catch (\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
class AddTranslationKeyCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'translation:add-translation-key';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add a new language key for the application';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$language = $this->ask(__('translation::translation.prompt_language_for_key'));
|
||||
|
||||
// we know this should be single or group so we can use the `anticipate`
|
||||
// method to give our users a helping hand
|
||||
$type = $this->anticipate(__('translation::translation.prompt_type'), ['single', 'group']);
|
||||
|
||||
// if the group type is selected, prompt for the group key
|
||||
if ($type === 'group') {
|
||||
$file = $this->ask(__('translation::translation.prompt_group'));
|
||||
}
|
||||
$key = $this->ask(__('translation::translation.prompt_key'));
|
||||
$value = $this->ask(__('translation::translation.prompt_value'));
|
||||
|
||||
// attempt to add the key for single or group and fail gracefully if
|
||||
// exception is thrown
|
||||
if ($type === 'single') {
|
||||
try {
|
||||
$this->translation->addSingleTranslation($language, 'single', $key, $value);
|
||||
|
||||
return $this->info(__('translation::translation.language_key_added'));
|
||||
} catch (\Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
} elseif ($type === 'group') {
|
||||
try {
|
||||
$file = str_replace('.php', '', $file);
|
||||
$this->translation->addGroupTranslation($language, $file, $key, $value);
|
||||
|
||||
return $this->info(__('translation::translation.language_key_added'));
|
||||
} catch (\Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
} else {
|
||||
return $this->error(__('translation::translation.type_error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
|
||||
class BaseCommand extends Command
|
||||
{
|
||||
protected $translation;
|
||||
|
||||
public function __construct(Translation $translation)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->translation = $translation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
class ListLanguagesCommand extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'translation:list-languages';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'List all of the available languages in the application';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$headers = [__('translation::translation.language_name'), __('translation::translation.language')];
|
||||
$languages = $this->translation->allLanguages()->toArray();
|
||||
$mappedLanguages = [];
|
||||
|
||||
foreach ($languages as $language => $name) {
|
||||
$mappedLanguages[] = [$name, $language];
|
||||
}
|
||||
|
||||
// return a table of results
|
||||
$this->table($headers, $mappedLanguages);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
class ListMissingTranslationKeys extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'translation:list-missing-translation-keys';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'List all of the translation keys in the app which don\'t have a corresponding translation';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$missingTranslations = [];
|
||||
$rows = [];
|
||||
|
||||
foreach ($this->translation->allLanguages() as $language => $name) {
|
||||
$missingTranslations[$language] = $this->translation->findMissingTranslations($language);
|
||||
}
|
||||
|
||||
// check whether or not there are any missing translations
|
||||
$empty = true;
|
||||
foreach ($missingTranslations as $language => $values) {
|
||||
if (! empty($values)) {
|
||||
$empty = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if no missing translations, inform the user and move on with your day
|
||||
if ($empty) {
|
||||
return $this->info(__('translation::translation.no_missing_keys'));
|
||||
}
|
||||
|
||||
// set some headers for the table of results
|
||||
$headers = [__('translation::translation.language'), __('translation::translation.type'), __('translation::translation.group'), __('translation::translation.key')];
|
||||
|
||||
// iterate over each of the missing languages
|
||||
foreach ($missingTranslations as $language => $types) {
|
||||
// iterate over each of the file types (json or array)
|
||||
foreach ($types as $type => $keys) {
|
||||
// iterate over each of the keys
|
||||
foreach ($keys as $key => $value) {
|
||||
// populate the array with the relevant data to fill the table
|
||||
foreach ($value as $k => $v) {
|
||||
$rows[] = [$language, $type, $key, $k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render the table of results
|
||||
$this->table($headers, $rows);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
class SynchroniseMissingTranslationKeys extends BaseCommand
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'translation:sync-missing-translation-keys {language?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Add all of the missing translation keys for all languages or a single language';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$language = $this->argument('language') ?: false;
|
||||
|
||||
try {
|
||||
// if we have a language, pass it in, if not the method will
|
||||
// automagically sync all languages
|
||||
$this->translation->saveMissingTranslations($language);
|
||||
|
||||
return $this->info(__('translation::translation.keys_synced'));
|
||||
} catch (\Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use JoeDixon\Translation\Drivers\Database;
|
||||
use JoeDixon\Translation\Drivers\File;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
use JoeDixon\Translation\Scanner;
|
||||
|
||||
class SynchroniseTranslationsCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'translation:sync-translations {from?} {to?} {language?}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Synchronise translations between drivers';
|
||||
|
||||
/**
|
||||
* File scanner.
|
||||
*
|
||||
* @var Scanner
|
||||
*/
|
||||
private $scanner;
|
||||
|
||||
/**
|
||||
* Translation.
|
||||
*
|
||||
* @var Translation
|
||||
*/
|
||||
private $translation;
|
||||
|
||||
/**
|
||||
* From driver.
|
||||
*/
|
||||
private $fromDriver;
|
||||
|
||||
/**
|
||||
* To driver.
|
||||
*/
|
||||
private $toDriver;
|
||||
|
||||
/**
|
||||
* Translation drivers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $drivers = ['file', 'database'];
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Scanner $scanner, Translation $translation)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->scanner = $scanner;
|
||||
$this->translation = $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$languages = array_keys($this->translation->allLanguages()->toArray());
|
||||
|
||||
// If a valid from driver has been specified as an argument.
|
||||
if ($this->argument('from') && in_array($this->argument('from'), $this->drivers)) {
|
||||
$this->fromDriver = $this->argument('from');
|
||||
}
|
||||
|
||||
// When the from driver will be entered manually or if the argument is invalid.
|
||||
else {
|
||||
$this->fromDriver = $this->anticipate('Which driver would you like to take translations from?', $this->drivers);
|
||||
|
||||
if (! in_array($this->fromDriver, $this->drivers)) {
|
||||
return $this->error('Invalid driver');
|
||||
}
|
||||
}
|
||||
|
||||
// Create the driver.
|
||||
$this->fromDriver = $this->createDriver($this->fromDriver);
|
||||
|
||||
// When the to driver has been specified.
|
||||
if ($this->argument('to') && in_array($this->argument('to'), $this->drivers)) {
|
||||
$this->toDriver = $this->argument('to');
|
||||
}
|
||||
|
||||
// When the to driver will be entered manually.
|
||||
else {
|
||||
$this->toDriver = $this->anticipate('Which driver would you like to add the translations to?', $this->drivers);
|
||||
|
||||
if (! in_array($this->toDriver, $this->drivers)) {
|
||||
return $this->error('Invalid driver');
|
||||
}
|
||||
}
|
||||
|
||||
// Create the driver.
|
||||
$this->toDriver = $this->createDriver($this->toDriver);
|
||||
|
||||
// If the language argument is set.
|
||||
if ($this->argument('language')) {
|
||||
|
||||
// If all languages should be synced.
|
||||
if ($this->argument('language') == 'all') {
|
||||
$language = false;
|
||||
}
|
||||
// When a specific language is set and is valid.
|
||||
elseif (in_array($this->argument('language'), $languages)) {
|
||||
$language = $this->argument('language');
|
||||
} else {
|
||||
return $this->error('Invalid language');
|
||||
}
|
||||
} // When the language will be entered manually or if the argument is invalid.
|
||||
else {
|
||||
$language = $this->anticipate('Which language? (leave blank for all)', $languages);
|
||||
|
||||
if ($language && ! in_array($language, $languages)) {
|
||||
return $this->error('Invalid language');
|
||||
}
|
||||
}
|
||||
|
||||
$this->line('Syncing translations');
|
||||
|
||||
// If a specific language is set.
|
||||
if ($language) {
|
||||
$this->mergeTranslations($this->toDriver, $language, $this->fromDriver->allTranslationsFor($language));
|
||||
} // Else process all languages.
|
||||
else {
|
||||
$translations = $this->mergeLanguages($this->toDriver, $this->fromDriver->allTranslations());
|
||||
}
|
||||
|
||||
$this->info('Translations have been synced');
|
||||
}
|
||||
|
||||
private function createDriver($driver)
|
||||
{
|
||||
if ($driver === 'file') {
|
||||
return new File(new Filesystem, app('path.lang'), config('app.locale'), $this->scanner);
|
||||
}
|
||||
|
||||
return new Database(config('app.locale'), $this->scanner);
|
||||
}
|
||||
|
||||
private function mergeLanguages($driver, $languages)
|
||||
{
|
||||
foreach ($languages as $language => $translations) {
|
||||
$this->mergeTranslations($driver, $language, $translations);
|
||||
}
|
||||
}
|
||||
|
||||
private function mergeTranslations($driver, $language, $translations)
|
||||
{
|
||||
$this->mergeGroupTranslations($driver, $language, $translations['group']);
|
||||
$this->mergeSingleTranslations($driver, $language, $translations['single']);
|
||||
}
|
||||
|
||||
private function mergeGroupTranslations($driver, $language, $groups)
|
||||
{
|
||||
foreach ($groups as $group => $translations) {
|
||||
foreach ($translations as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
$driver->addGroupTranslation($language, $group, $key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function mergeSingleTranslations($driver, $language, $vendors)
|
||||
{
|
||||
foreach ($vendors as $vendor => $translations) {
|
||||
foreach ($translations as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
$driver->addSingleTranslation($language, $vendor, $key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
support/laravel-translation/src/ContractDatabaseLoader.php
Normal file
74
support/laravel-translation/src/ContractDatabaseLoader.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Contracts\Translation\Loader;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
|
||||
class ContractDatabaseLoader implements Loader
|
||||
{
|
||||
private $translation;
|
||||
|
||||
public function __construct(Translation $translation)
|
||||
{
|
||||
$this->translation = $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the messages for the given locale.
|
||||
*
|
||||
* @param string $locale
|
||||
* @param string $group
|
||||
* @param string $namespace
|
||||
* @return array
|
||||
*/
|
||||
public function load($locale, $group, $namespace = null)
|
||||
{
|
||||
if ($group == '*' && $namespace == '*') {
|
||||
return $this->translation->getSingleTranslationsFor($locale)->get('single', collect())->toArray();
|
||||
}
|
||||
|
||||
if (is_null($namespace) || $namespace == '*') {
|
||||
return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group) {
|
||||
return $key === $group;
|
||||
})->first();
|
||||
}
|
||||
|
||||
return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group, $namespace) {
|
||||
return $key === "{$namespace}::{$group}";
|
||||
})->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new namespace to the loader.
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param string $hint
|
||||
* @return void
|
||||
*/
|
||||
public function addNamespace($namespace, $hint)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new JSON path to the loader.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function addJsonPath($path)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all the registered namespaces.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function namespaces()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
279
support/laravel-translation/src/Drivers/Database.php
Normal file
279
support/laravel-translation/src/Drivers/Database.php
Normal file
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Drivers;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use JoeDixon\Translation\Exceptions\LanguageExistsException;
|
||||
use JoeDixon\Translation\Language;
|
||||
use JoeDixon\Translation\Translation as TranslationModel;
|
||||
use Throwable;
|
||||
|
||||
class Database extends Translation implements DriverInterface
|
||||
{
|
||||
protected $sourceLanguage;
|
||||
|
||||
protected $scanner;
|
||||
|
||||
protected array $groupTranslationCache = [];
|
||||
|
||||
protected array $languageCache = [];
|
||||
|
||||
public function __construct($sourceLanguage, $scanner)
|
||||
{
|
||||
$this->sourceLanguage = $sourceLanguage;
|
||||
$this->scanner = $scanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all languages from the application.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allLanguages()
|
||||
{
|
||||
return Language::all()->mapWithKeys(function ($language) {
|
||||
return [$language->language => $language->name ?: $language->language];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all group translations from the application.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function allGroup($language)
|
||||
{
|
||||
$groups = TranslationModel::getGroupsForLanguage($language);
|
||||
|
||||
return $groups->map(function ($translation) {
|
||||
return $translation->group;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the translations from the application.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allTranslations()
|
||||
{
|
||||
return $this->allLanguages()->mapWithKeys(function ($name, $language) {
|
||||
return [$language => $this->allTranslationsFor($language)];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all translations for a particular language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function allTranslationsFor($language)
|
||||
{
|
||||
return Collection::make([
|
||||
'group' => $this->getGroupTranslationsFor($language),
|
||||
'single' => $this->getSingleTranslationsFor($language),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new language to the application.
|
||||
*
|
||||
* @param string $language
|
||||
* @return void
|
||||
*/
|
||||
public function addLanguage($language, $name = null)
|
||||
{
|
||||
if ($this->languageExists($language)) {
|
||||
throw new LanguageExistsException(__('translation::errors.language_exists', ['language' => $language]));
|
||||
}
|
||||
|
||||
Language::create([
|
||||
'language' => $language,
|
||||
'name' => $name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new group type translation.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addGroupTranslation($language, $group, $key, $value = '')
|
||||
{
|
||||
if (! $this->languageExists($language)) {
|
||||
$this->addLanguage($language);
|
||||
}
|
||||
|
||||
Language::where('language', $language)
|
||||
->first()
|
||||
->translations()
|
||||
->updateOrCreate([
|
||||
'group' => $group,
|
||||
'key' => $key,
|
||||
], [
|
||||
'group' => $group,
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new single type translation.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addSingleTranslation($language, $vendor, $key, $value = '')
|
||||
{
|
||||
if (! $this->languageExists($language)) {
|
||||
$this->addLanguage($language);
|
||||
}
|
||||
|
||||
Language::where('language', $language)
|
||||
->first()
|
||||
->translations()
|
||||
->updateOrCreate([
|
||||
'group' => $vendor,
|
||||
'key' => $key,
|
||||
], [
|
||||
'key' => $key,
|
||||
'value' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the single translations for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSingleTranslationsFor($language)
|
||||
{
|
||||
$translations = $this->getLanguage($language)
|
||||
->translations()
|
||||
->where('group', 'like', '%single')
|
||||
->orWhereNull('group')
|
||||
->get()
|
||||
->groupBy('group');
|
||||
|
||||
// if there is no group, this is a legacy translation so we need to
|
||||
// update to 'single'. We do this here so it only happens once.
|
||||
if ($this->hasLegacyGroups($translations->keys())) {
|
||||
TranslationModel::whereNull('group')->update(['group' => 'single']);
|
||||
// if any legacy groups exist, rerun the method so we get the
|
||||
// updated keys.
|
||||
return $this->getSingleTranslationsFor($language);
|
||||
}
|
||||
|
||||
return $translations->map(function ($translations, $group) {
|
||||
return $translations->mapWithKeys(function ($translation) {
|
||||
return [$translation->key => $translation->value];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the group translations for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupTranslationsFor($language)
|
||||
{
|
||||
if (isset($this->groupTranslationCache[$language])) {
|
||||
return $this->groupTranslationCache[$language];
|
||||
}
|
||||
|
||||
$languageModel = $this->getLanguage($language);
|
||||
|
||||
if (is_null($languageModel)) {
|
||||
return collect();
|
||||
}
|
||||
|
||||
$translations = $languageModel
|
||||
->translations()
|
||||
->whereNotNull('group')
|
||||
->where('group', 'not like', '%single')
|
||||
->get()
|
||||
->groupBy('group');
|
||||
|
||||
$result = $translations->map(function ($translations) {
|
||||
return $translations->mapWithKeys(function ($translation) {
|
||||
return [$translation->key => $translation->value];
|
||||
});
|
||||
});
|
||||
|
||||
$this->groupTranslationCache[$language] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a language exists.
|
||||
*
|
||||
* @param string $language
|
||||
* @return bool
|
||||
*/
|
||||
public function languageExists($language)
|
||||
{
|
||||
return $this->getLanguage($language) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of group names for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupsFor($language)
|
||||
{
|
||||
return $this->allGroup($language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a language from the database.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Language
|
||||
*/
|
||||
private function getLanguage($language)
|
||||
{
|
||||
if (isset($this->languageCache[$language])) {
|
||||
return $this->languageCache[$language];
|
||||
}
|
||||
|
||||
// Some constallation of composer packages can lead to our code being executed
|
||||
// as a dependency of running migrations. That's why we need to be able to
|
||||
// handle the case where the database is empty / our tables don't exist:
|
||||
try {
|
||||
$result = Language::where('language', $language)->first();
|
||||
} catch (Throwable) {
|
||||
$result = null;
|
||||
}
|
||||
|
||||
$this->languageCache[$language] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a set of single translations contains any legacy groups.
|
||||
* Previously, this was handled by setting the group value to NULL, now
|
||||
* we use 'single' to cater for vendor JSON language files.
|
||||
*
|
||||
* @param Collection $groups
|
||||
* @return bool
|
||||
*/
|
||||
private function hasLegacyGroups($groups)
|
||||
{
|
||||
return $groups->filter(function ($key) {
|
||||
return $key === '';
|
||||
})->count() > 0;
|
||||
}
|
||||
}
|
||||
128
support/laravel-translation/src/Drivers/DriverInterface.php
Normal file
128
support/laravel-translation/src/Drivers/DriverInterface.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Drivers;
|
||||
|
||||
interface DriverInterface
|
||||
{
|
||||
/**
|
||||
* Get all languages from the application.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allLanguages();
|
||||
|
||||
/**
|
||||
* Get all group translations from the application.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function allGroup($language);
|
||||
|
||||
/**
|
||||
* Get all the translations from the application.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allTranslations();
|
||||
|
||||
/**
|
||||
* Get all translations for a particular language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function allTranslationsFor($language);
|
||||
|
||||
/**
|
||||
* Add a new language to the application.
|
||||
*
|
||||
* @param string $language
|
||||
* @return void
|
||||
*/
|
||||
public function addLanguage($language, $name = null);
|
||||
|
||||
/**
|
||||
* Add a new group type translation.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addGroupTranslation($language, $group, $key, $value = '');
|
||||
|
||||
/**
|
||||
* Add a new single type translation.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addSingleTranslation($language, $vendor, $key, $value = '');
|
||||
|
||||
/**
|
||||
* Get all of the single translations for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSingleTranslationsFor($language);
|
||||
|
||||
/**
|
||||
* Get all of the group translations for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupTranslationsFor($language);
|
||||
|
||||
/**
|
||||
* Determine whether or not a language exists.
|
||||
*
|
||||
* @param string $language
|
||||
* @return bool
|
||||
*/
|
||||
public function languageExists($language);
|
||||
|
||||
/**
|
||||
* Find all of the translations in the app without translation for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return array
|
||||
*/
|
||||
public function findMissingTranslations($language);
|
||||
|
||||
/**
|
||||
* Save all of the translations in the app without translation for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return void
|
||||
*/
|
||||
public function saveMissingTranslations($language = false);
|
||||
|
||||
/**
|
||||
* Get a collection of group names for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupsFor($language);
|
||||
|
||||
/**
|
||||
* Get all translations for a given language merged with the source language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSourceLanguageTranslationsWith($language);
|
||||
|
||||
/**
|
||||
* Filter all keys and translations for a given language and string.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $filter
|
||||
* @return Collection
|
||||
*/
|
||||
public function filterTranslationsFor($language, $filter);
|
||||
}
|
||||
369
support/laravel-translation/src/Drivers/File.php
Normal file
369
support/laravel-translation/src/Drivers/File.php
Normal file
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Drivers;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use JoeDixon\Translation\Exceptions\LanguageExistsException;
|
||||
|
||||
class File extends Translation implements DriverInterface
|
||||
{
|
||||
private $disk;
|
||||
|
||||
private $languageFilesPath;
|
||||
|
||||
protected $sourceLanguage;
|
||||
|
||||
protected $scanner;
|
||||
|
||||
public function __construct(Filesystem $disk, $languageFilesPath, $sourceLanguage, $scanner)
|
||||
{
|
||||
$this->disk = $disk;
|
||||
$this->languageFilesPath = $languageFilesPath;
|
||||
$this->sourceLanguage = $sourceLanguage;
|
||||
$this->scanner = $scanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all languages from the application.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allLanguages()
|
||||
{
|
||||
// As per the docs, there should be a subdirectory within the
|
||||
// languages path so we can return these directory names as a collection
|
||||
$directories = Collection::make($this->disk->directories($this->languageFilesPath));
|
||||
|
||||
return $directories->mapWithKeys(function ($directory) {
|
||||
$language = basename($directory);
|
||||
|
||||
return [$language => $language];
|
||||
})->filter(function ($language) {
|
||||
// at the moemnt, we're not supporting vendor specific translations
|
||||
return $language != 'vendor';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all group translations from the application.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function allGroup($language)
|
||||
{
|
||||
$groupPath = "{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}";
|
||||
|
||||
if (! $this->disk->exists($groupPath)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$groups = Collection::make($this->disk->allFiles($groupPath));
|
||||
|
||||
return $groups->map(function ($group) {
|
||||
return $group->getBasename('.php');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the translations from the application.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function allTranslations()
|
||||
{
|
||||
return $this->allLanguages()->mapWithKeys(function ($language) {
|
||||
return [$language => $this->allTranslationsFor($language)];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all translations for a particular language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function allTranslationsFor($language)
|
||||
{
|
||||
return Collection::make([
|
||||
'group' => $this->getGroupTranslationsFor($language),
|
||||
'single' => $this->getSingleTranslationsFor($language),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new language to the application.
|
||||
*
|
||||
* @param string $language
|
||||
* @return void
|
||||
*/
|
||||
public function addLanguage($language, $name = null)
|
||||
{
|
||||
if ($this->languageExists($language)) {
|
||||
throw new LanguageExistsException(__('translation::errors.language_exists', ['language' => $language]));
|
||||
}
|
||||
|
||||
$this->disk->makeDirectory("{$this->languageFilesPath}".DIRECTORY_SEPARATOR."$language");
|
||||
if (! $this->disk->exists("{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}.json")) {
|
||||
$this->saveSingleTranslations($language, collect(['single' => collect()]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new group type translation.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addGroupTranslation($language, $group, $key, $value = '')
|
||||
{
|
||||
if (! $this->languageExists($language)) {
|
||||
$this->addLanguage($language);
|
||||
}
|
||||
|
||||
$translations = $this->getGroupTranslationsFor($language);
|
||||
|
||||
// does the group exist? If not, create it.
|
||||
if (! $translations->keys()->contains($group)) {
|
||||
$translations->put($group, collect());
|
||||
}
|
||||
|
||||
$values = $translations->get($group);
|
||||
$values[$key] = $value;
|
||||
$translations->put($group, collect($values));
|
||||
|
||||
$this->saveGroupTranslations($language, $group, $translations->get($group));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new single type translation.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @return void
|
||||
*/
|
||||
public function addSingleTranslation($language, $vendor, $key, $value = '')
|
||||
{
|
||||
if (! $this->languageExists($language)) {
|
||||
$this->addLanguage($language);
|
||||
}
|
||||
|
||||
$translations = $this->getSingleTranslationsFor($language);
|
||||
$translations->get($vendor) ?: $translations->put($vendor, collect());
|
||||
$translations->get($vendor)->put($key, $value);
|
||||
|
||||
$this->saveSingleTranslations($language, $translations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the single translations for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSingleTranslationsFor($language)
|
||||
{
|
||||
$files = new Collection($this->disk->allFiles($this->languageFilesPath));
|
||||
|
||||
return $files->filter(function ($file) use ($language) {
|
||||
return strpos($file, "{$language}.json");
|
||||
})->flatMap(function ($file) {
|
||||
if (strpos($file->getPathname(), 'vendor')) {
|
||||
$vendor = Str::before(Str::after($file->getPathname(), 'vendor'.DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR);
|
||||
|
||||
return ["{$vendor}::single" => new Collection(json_decode($this->disk->get($file), true))];
|
||||
}
|
||||
|
||||
return ['single' => new Collection(json_decode($this->disk->get($file), true))];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the group translations for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupTranslationsFor($language)
|
||||
{
|
||||
return $this->getGroupFilesFor($language)->mapWithKeys(function ($group) {
|
||||
// here we check if the path contains 'vendor' as these will be the
|
||||
// files which need namespacing
|
||||
if (Str::contains($group->getPathname(), 'vendor')) {
|
||||
$vendor = Str::before(Str::after($group->getPathname(), 'vendor'.DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR);
|
||||
|
||||
return ["{$vendor}::{$group->getBasename('.php')}" => new Collection(Arr::dot($this->disk->getRequire($group->getPathname())))];
|
||||
}
|
||||
|
||||
return [$group->getBasename('.php') => new Collection(Arr::dot($this->disk->getRequire($group->getPathname())))];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the translations for a given file.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $file
|
||||
* @return array
|
||||
*/
|
||||
public function getTranslationsForFile($language, $file)
|
||||
{
|
||||
$file = Str::finish($file, '.php');
|
||||
$filePath = "{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}".DIRECTORY_SEPARATOR."{$file}";
|
||||
$translations = [];
|
||||
|
||||
if ($this->disk->exists($filePath)) {
|
||||
$translations = Arr::dot($this->disk->getRequire($filePath));
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a language exists.
|
||||
*
|
||||
* @param string $language
|
||||
* @return bool
|
||||
*/
|
||||
public function languageExists($language)
|
||||
{
|
||||
return $this->allLanguages()->contains($language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new group of translations.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $group
|
||||
* @return void
|
||||
*/
|
||||
public function addGroup($language, $group)
|
||||
{
|
||||
$this->saveGroupTranslations($language, $group, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save group type language translations.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $group
|
||||
* @param array $translations
|
||||
* @return void
|
||||
*/
|
||||
public function saveGroupTranslations($language, $group, $translations)
|
||||
{
|
||||
// here we check if it's a namespaced translation which need saving to a
|
||||
// different path
|
||||
$translations = $translations instanceof Collection ? $translations->toArray() : $translations;
|
||||
ksort($translations);
|
||||
$translations = array_undot($translations);
|
||||
if (Str::contains($group, '::')) {
|
||||
return $this->saveNamespacedGroupTranslations($language, $group, $translations);
|
||||
}
|
||||
$this->disk->put("{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}".DIRECTORY_SEPARATOR."{$group}.php", "<?php\n\nreturn ".var_export($translations, true).';'.\PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save namespaced group type language translations.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $group
|
||||
* @param array $translations
|
||||
* @return void
|
||||
*/
|
||||
private function saveNamespacedGroupTranslations($language, $group, $translations)
|
||||
{
|
||||
[$namespace, $group] = explode('::', $group);
|
||||
$directory = "{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR."{$namespace}".DIRECTORY_SEPARATOR."{$language}";
|
||||
|
||||
if (! $this->disk->exists($directory)) {
|
||||
$this->disk->makeDirectory($directory, 0755, true);
|
||||
}
|
||||
|
||||
$this->disk->put("$directory".DIRECTORY_SEPARATOR."{$group}.php", "<?php\n\nreturn ".var_export($translations, true).';'.\PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save single type language translations.
|
||||
*
|
||||
* @param string $language
|
||||
* @param array $translations
|
||||
* @return void
|
||||
*/
|
||||
private function saveSingleTranslations($language, $translations)
|
||||
{
|
||||
foreach ($translations as $group => $translation) {
|
||||
$vendor = Str::before($group, '::single');
|
||||
$languageFilePath = $vendor !== 'single' ? 'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}.json" : "{$language}.json";
|
||||
$this->disk->put(
|
||||
"{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$languageFilePath}",
|
||||
json_encode((object) $translations->get($group), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the group files for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupFilesFor($language)
|
||||
{
|
||||
$groups = new Collection($this->disk->allFiles("{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}"));
|
||||
// namespaced files reside in the vendor directory so we'll grab these
|
||||
// the `getVendorGroupFileFor` method
|
||||
$groups = $groups->merge($this->getVendorGroupFilesFor($language));
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of group names for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getGroupsFor($language)
|
||||
{
|
||||
return $this->getGroupFilesFor($language)->map(function ($file) {
|
||||
if (Str::contains($file->getPathname(), 'vendor')) {
|
||||
$vendor = Str::before(Str::after($file->getPathname(), 'vendor'.DIRECTORY_SEPARATOR), DIRECTORY_SEPARATOR);
|
||||
|
||||
return "{$vendor}::{$file->getBasename('.php')}";
|
||||
}
|
||||
|
||||
return $file->getBasename('.php');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the vendor group files for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getVendorGroupFilesFor($language)
|
||||
{
|
||||
if (! $this->disk->exists("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$vendorGroups = [];
|
||||
foreach ($this->disk->directories("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor') as $vendor) {
|
||||
$vendor = Arr::last(explode(DIRECTORY_SEPARATOR, $vendor));
|
||||
if (! $this->disk->exists("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}")) {
|
||||
array_push($vendorGroups, []);
|
||||
} else {
|
||||
array_push($vendorGroups, $this->disk->allFiles("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}"));
|
||||
}
|
||||
}
|
||||
|
||||
return new Collection(Arr::flatten($vendorGroups));
|
||||
}
|
||||
}
|
||||
120
support/laravel-translation/src/Drivers/Translation.php
Normal file
120
support/laravel-translation/src/Drivers/Translation.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Drivers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Str;
|
||||
use JoeDixon\Translation\Events\TranslationAdded;
|
||||
|
||||
abstract class Translation
|
||||
{
|
||||
/**
|
||||
* Find all of the translations in the app without translation for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return array
|
||||
*/
|
||||
public function findMissingTranslations($language)
|
||||
{
|
||||
return array_diff_assoc_recursive(
|
||||
$this->scanner->findTranslations(),
|
||||
$this->allTranslationsFor($language)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save all of the translations in the app without translation for a given language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return void
|
||||
*/
|
||||
public function saveMissingTranslations($language = false)
|
||||
{
|
||||
$languages = $language ? [$language => $language] : $this->allLanguages();
|
||||
|
||||
foreach ($languages as $language => $name) {
|
||||
$missingTranslations = $this->findMissingTranslations($language);
|
||||
|
||||
foreach ($missingTranslations as $type => $groups) {
|
||||
foreach ($groups as $group => $translations) {
|
||||
foreach ($translations as $key => $value) {
|
||||
if (Str::contains($group, 'single')) {
|
||||
$this->addSingleTranslation($language, $group, $key);
|
||||
} else {
|
||||
$this->addGroupTranslation($language, $group, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all translations for a given language merged with the source language.
|
||||
*
|
||||
* @param string $language
|
||||
* @return Collection
|
||||
*/
|
||||
public function getSourceLanguageTranslationsWith($language)
|
||||
{
|
||||
$sourceTranslations = $this->allTranslationsFor($this->sourceLanguage);
|
||||
$languageTranslations = $this->allTranslationsFor($language);
|
||||
|
||||
return $sourceTranslations->map(function ($groups, $type) use ($language, $languageTranslations) {
|
||||
return $groups->map(function ($translations, $group) use ($type, $language, $languageTranslations) {
|
||||
$translations = $translations->toArray();
|
||||
array_walk($translations, function (&$value, $key) use ($type, $group, $language, $languageTranslations) {
|
||||
$value = [
|
||||
$this->sourceLanguage => $value,
|
||||
$language => $languageTranslations->get($type, collect())->get($group, collect())->get($key),
|
||||
];
|
||||
});
|
||||
|
||||
return $translations;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter all keys and translations for a given language and string.
|
||||
*
|
||||
* @param string $language
|
||||
* @param string $filter
|
||||
* @return Collection
|
||||
*/
|
||||
public function filterTranslationsFor($language, $filter)
|
||||
{
|
||||
$allTranslations = $this->getSourceLanguageTranslationsWith(($language));
|
||||
if (! $filter) {
|
||||
return $allTranslations;
|
||||
}
|
||||
|
||||
return $allTranslations->map(function ($groups, $type) use ($language, $filter) {
|
||||
return $groups->map(function ($keys, $group) use ($language, $filter) {
|
||||
return collect($keys)->filter(function ($translations, $key) use ($group, $language, $filter) {
|
||||
return strs_contain([$group, $key, $translations[$language], $translations[$this->sourceLanguage]], $filter);
|
||||
});
|
||||
})->filter(function ($keys) {
|
||||
return $keys->isNotEmpty();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public function add(Request $request, $language, $isGroupTranslation)
|
||||
{
|
||||
$namespace = $request->has('namespace') && $request->get('namespace') ? "{$request->get('namespace')}::" : '';
|
||||
$group = $namespace.$request->get('group');
|
||||
$key = $request->get('key');
|
||||
$value = $request->get('value') ?: '';
|
||||
|
||||
if ($isGroupTranslation) {
|
||||
$this->addGroupTranslation($language, $group, $key, $value);
|
||||
} else {
|
||||
$this->addSingleTranslation($language, 'single', $key, $value);
|
||||
}
|
||||
|
||||
Event::dispatch(new TranslationAdded($language, $group ?: 'single', $key, $value));
|
||||
}
|
||||
}
|
||||
28
support/laravel-translation/src/Events/TranslationAdded.php
Normal file
28
support/laravel-translation/src/Events/TranslationAdded.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Events;
|
||||
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
|
||||
class TranslationAdded
|
||||
{
|
||||
use Dispatchable;
|
||||
|
||||
public $key;
|
||||
public $group;
|
||||
public $value;
|
||||
public $language;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $language, string $group, string $key, string $value)
|
||||
{
|
||||
$this->language = $language;
|
||||
$this->group = $group;
|
||||
$this->key = $key;
|
||||
$this->value = $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Exceptions;
|
||||
|
||||
class LanguageExistsException extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Exceptions;
|
||||
|
||||
class LanguageKeyExistsException extends \Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
use JoeDixon\Translation\Http\Requests\LanguageRequest;
|
||||
|
||||
class LanguageController extends Controller
|
||||
{
|
||||
private $translation;
|
||||
|
||||
public function __construct(Translation $translation)
|
||||
{
|
||||
$this->translation = $translation;
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$languages = $this->translation->allLanguages();
|
||||
|
||||
return view('translation::languages.index', compact('languages'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
return view('translation::languages.create');
|
||||
}
|
||||
|
||||
public function store(LanguageRequest $request)
|
||||
{
|
||||
$this->translation->addLanguage($request->locale, $request->name);
|
||||
|
||||
return redirect()
|
||||
->route('languages.index')
|
||||
->with('success', __('translation::translation.language_added'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
use JoeDixon\Translation\Http\Requests\TranslationRequest;
|
||||
|
||||
class LanguageTranslationController extends Controller
|
||||
{
|
||||
private $translation;
|
||||
|
||||
public function __construct(Translation $translation)
|
||||
{
|
||||
$this->translation = $translation;
|
||||
}
|
||||
|
||||
public function index(Request $request, $language)
|
||||
{
|
||||
// dd($this->translation->getSingleTranslationsFor('en'));
|
||||
if ($request->has('language') && $request->get('language') !== $language) {
|
||||
return redirect()
|
||||
->route('languages.translations.index', ['language' => $request->get('language'), 'group' => $request->get('group'), 'filter' => $request->get('filter')]);
|
||||
}
|
||||
|
||||
$languages = $this->translation->allLanguages();
|
||||
$groups = $this->translation->getGroupsFor(config('app.locale'))->merge('single');
|
||||
$translations = $this->translation->filterTranslationsFor($language, $request->get('filter'));
|
||||
|
||||
if ($request->has('group') && $request->get('group')) {
|
||||
if ($request->get('group') === 'single') {
|
||||
$translations = $translations->get('single');
|
||||
$translations = new Collection(['single' => $translations]);
|
||||
} else {
|
||||
$translations = $translations->get('group')->filter(function ($values, $group) use ($request) {
|
||||
return $group === $request->get('group');
|
||||
});
|
||||
|
||||
$translations = new Collection(['group' => $translations]);
|
||||
}
|
||||
}
|
||||
|
||||
return view('translation::languages.translations.index', compact('language', 'languages', 'groups', 'translations'));
|
||||
}
|
||||
|
||||
public function create(Request $request, $language)
|
||||
{
|
||||
return view('translation::languages.translations.create', compact('language'));
|
||||
}
|
||||
|
||||
public function store(TranslationRequest $request, $language)
|
||||
{
|
||||
$isGroupTranslation = $request->filled('group');
|
||||
|
||||
$this->translation->add($request, $language, $isGroupTranslation);
|
||||
|
||||
return redirect()
|
||||
->route('languages.translations.index', $language)
|
||||
->with('success', __('translation::translation.translation_added'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $language)
|
||||
{
|
||||
$isGroupTranslation = ! Str::contains($request->get('group'), 'single');
|
||||
|
||||
$this->translation->add($request, $language, $isGroupTranslation);
|
||||
|
||||
return ['success' => true];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use JoeDixon\Translation\Rules\LanguageNotExists;
|
||||
|
||||
class LanguageRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'nullable|string',
|
||||
'locale' => ['required', new LanguageNotExists],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TranslationRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'key' => 'required',
|
||||
'value' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
74
support/laravel-translation/src/InterfaceDatabaseLoader.php
Normal file
74
support/laravel-translation/src/InterfaceDatabaseLoader.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Translation\LoaderInterface;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
|
||||
class InterfaceDatabaseLoader implements LoaderInterface
|
||||
{
|
||||
private $translation;
|
||||
|
||||
public function __construct(Translation $translation)
|
||||
{
|
||||
$this->translation = $translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the messages for the given locale.
|
||||
*
|
||||
* @param string $locale
|
||||
* @param string $group
|
||||
* @param string $namespace
|
||||
* @return array
|
||||
*/
|
||||
public function load($locale, $group, $namespace = null)
|
||||
{
|
||||
if ($group == '*' && $namespace == '*') {
|
||||
return $this->translation->getSingleTranslationsFor($locale)->get('single', collect())->toArray();
|
||||
}
|
||||
|
||||
if (is_null($namespace) || $namespace == '*') {
|
||||
return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group) {
|
||||
return $key === $group;
|
||||
})->first();
|
||||
}
|
||||
|
||||
return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group, $namespace) {
|
||||
return $key === "{$namespace}::{$group}";
|
||||
})->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new namespace to the loader.
|
||||
*
|
||||
* @param string $namespace
|
||||
* @param string $hint
|
||||
* @return void
|
||||
*/
|
||||
public function addNamespace($namespace, $hint)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new JSON path to the loader.
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function addJsonPath($path)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all the registered namespaces.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function namespaces()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
22
support/laravel-translation/src/Language.php
Normal file
22
support/laravel-translation/src/Language.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Language extends Model
|
||||
{
|
||||
protected $guarded = [];
|
||||
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
$this->connection = config('translation.database.connection');
|
||||
$this->table = config('translation.database.languages_table');
|
||||
}
|
||||
|
||||
public function translations()
|
||||
{
|
||||
return $this->hasMany(Translation::class);
|
||||
}
|
||||
}
|
||||
33
support/laravel-translation/src/Rules/LanguageNotExists.php
Normal file
33
support/laravel-translation/src/Rules/LanguageNotExists.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Rules;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
|
||||
class LanguageNotExists implements Rule
|
||||
{
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
$translation = app()->make(Translation::class);
|
||||
|
||||
return ! $translation->languageExists($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function message()
|
||||
{
|
||||
return __('translation::translation.language_exists');
|
||||
}
|
||||
}
|
||||
64
support/laravel-translation/src/Scanner.php
Normal file
64
support/laravel-translation/src/Scanner.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
|
||||
class Scanner
|
||||
{
|
||||
private $disk;
|
||||
|
||||
private $scanPaths;
|
||||
|
||||
private $translationMethods;
|
||||
|
||||
public function __construct(Filesystem $disk, $scanPaths, $translationMethods)
|
||||
{
|
||||
$this->disk = $disk;
|
||||
$this->scanPaths = $scanPaths;
|
||||
$this->translationMethods = $translationMethods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan all the files in the provided $scanPath for translations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findTranslations()
|
||||
{
|
||||
$results = ['single' => [], 'group' => []];
|
||||
|
||||
// This has been derived from a combination of the following:
|
||||
// * Laravel Language Manager GUI from Mohamed Said (https://github.com/themsaid/laravel-langman-gui)
|
||||
// * Laravel 5 Translation Manager from Barry vd. Heuvel (https://github.com/barryvdh/laravel-translation-manager)
|
||||
$matchingPattern =
|
||||
'[^\w]'. // Must not start with any alphanum or _
|
||||
'(?<!->)'. // Must not start with ->
|
||||
'('.implode('|', $this->translationMethods).')'. // Must start with one of the functions
|
||||
"\(". // Match opening parentheses
|
||||
"\s*". // Whitespace before param
|
||||
"[\'\"]". // Match " or '
|
||||
'('. // Start a new group to match:
|
||||
'.+'. // Must start with group
|
||||
')'. // Close group
|
||||
"[\'\"]". // Closing quote
|
||||
"\s*". // Whitespace after param
|
||||
"[\),]"; // Close parentheses or new parameter
|
||||
|
||||
foreach ($this->disk->allFiles($this->scanPaths) as $file) {
|
||||
if (preg_match_all("/$matchingPattern/siU", $file->getContents(), $matches)) {
|
||||
foreach ($matches[2] as $key) {
|
||||
if (preg_match("/(^[a-zA-Z0-9:_-]+([.][^\1)\ ]+)+$)/siU", $key, $arrayMatches)) {
|
||||
[$file, $k] = explode('.', $arrayMatches[0], 2);
|
||||
$results['group'][$file][$k] = '';
|
||||
continue;
|
||||
} else {
|
||||
$results['single']['single'][$key] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
33
support/laravel-translation/src/Translation.php
Normal file
33
support/laravel-translation/src/Translation.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Translation extends Model
|
||||
{
|
||||
protected $guarded = [];
|
||||
|
||||
public function __construct(array $attributes = [])
|
||||
{
|
||||
parent::__construct($attributes);
|
||||
$this->connection = config('translation.database.connection');
|
||||
$this->table = config('translation.database.translations_table');
|
||||
}
|
||||
|
||||
public function language()
|
||||
{
|
||||
return $this->belongsTo(Language::class);
|
||||
}
|
||||
|
||||
public static function getGroupsForLanguage($language)
|
||||
{
|
||||
return static::whereHas('language', function ($q) use ($language) {
|
||||
$q->where('language', $language);
|
||||
})->whereNotNull('group')
|
||||
->where('group', 'not like', '%single')
|
||||
->select('group')
|
||||
->distinct()
|
||||
->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Translation\TranslationServiceProvider as ServiceProvider;
|
||||
use Illuminate\Translation\Translator;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
|
||||
class TranslationBindingsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register package bindings in the container.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
if ($this->app['config']['translation.driver'] === 'database') {
|
||||
$this->registerDatabaseTranslator();
|
||||
} else {
|
||||
parent::register();
|
||||
}
|
||||
}
|
||||
|
||||
private function registerDatabaseTranslator()
|
||||
{
|
||||
$this->registerDatabaseLoader();
|
||||
|
||||
$this->app->singleton('translator', function ($app) {
|
||||
$loader = $app['translation.loader'];
|
||||
// When registering the translator component, we'll need to set the default
|
||||
// locale as well as the fallback locale. So, we'll grab the application
|
||||
// configuration so we can easily get both of these values from there.
|
||||
$locale = $app['config']['app.locale'];
|
||||
$trans = new Translator($loader, $locale);
|
||||
$trans->setFallback($app['config']['app.fallback_locale']);
|
||||
|
||||
return $trans;
|
||||
});
|
||||
}
|
||||
|
||||
protected function registerDatabaseLoader()
|
||||
{
|
||||
$this->app->singleton('translation.loader', function ($app) {
|
||||
// Post Laravel 5.4, the interface was moved to the contracts
|
||||
// directory. Here we perform a check to see whether or not the
|
||||
// interface exists and instantiate the relevant loader accordingly.
|
||||
if (interface_exists('Illuminate\Contracts\Translation\Loader')) {
|
||||
return new ContractDatabaseLoader($this->app->make(Translation::class));
|
||||
}
|
||||
|
||||
return new InterfaceDatabaseLoader($this->app->make(Translation::class));
|
||||
});
|
||||
}
|
||||
}
|
||||
47
support/laravel-translation/src/TranslationManager.php
Normal file
47
support/laravel-translation/src/TranslationManager.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\Str;
|
||||
use JoeDixon\Translation\Drivers\Database;
|
||||
use JoeDixon\Translation\Drivers\File;
|
||||
|
||||
class TranslationManager
|
||||
{
|
||||
private $app;
|
||||
|
||||
private $config;
|
||||
|
||||
private $scanner;
|
||||
|
||||
public function __construct($app, $config, $scanner)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->config = $config;
|
||||
$this->scanner = $scanner;
|
||||
}
|
||||
|
||||
public function resolve()
|
||||
{
|
||||
$driver = $this->config['driver'];
|
||||
$driverResolver = Str::studly($driver);
|
||||
$method = "resolve{$driverResolver}Driver";
|
||||
|
||||
if (! method_exists($this, $method)) {
|
||||
throw new \InvalidArgumentException("Invalid driver [$driver]");
|
||||
}
|
||||
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
protected function resolveFileDriver()
|
||||
{
|
||||
return new File(new Filesystem, $this->app['path.lang'], $this->app->config['app']['locale'], $this->scanner);
|
||||
}
|
||||
|
||||
protected function resolveDatabaseDriver()
|
||||
{
|
||||
return new Database($this->app->config['app']['locale'], $this->scanner);
|
||||
}
|
||||
}
|
||||
185
support/laravel-translation/src/TranslationServiceProvider.php
Normal file
185
support/laravel-translation/src/TranslationServiceProvider.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation;
|
||||
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use JoeDixon\Translation\Console\Commands\AddLanguageCommand;
|
||||
use JoeDixon\Translation\Console\Commands\AddTranslationKeyCommand;
|
||||
use JoeDixon\Translation\Console\Commands\ListLanguagesCommand;
|
||||
use JoeDixon\Translation\Console\Commands\ListMissingTranslationKeys;
|
||||
use JoeDixon\Translation\Console\Commands\SynchroniseMissingTranslationKeys;
|
||||
use JoeDixon\Translation\Console\Commands\SynchroniseTranslationsCommand;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
|
||||
class TranslationServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the package services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->loadViews();
|
||||
|
||||
$this->registerRoutes();
|
||||
|
||||
$this->publishConfiguration();
|
||||
|
||||
$this->publishAssets();
|
||||
|
||||
$this->loadMigrations();
|
||||
|
||||
$this->loadTranslations();
|
||||
|
||||
$this->registerHelpers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register package bindings in the container.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->mergeConfiguration();
|
||||
|
||||
$this->registerCommands();
|
||||
|
||||
$this->registerContainerBindings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and publish package views.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function loadViews()
|
||||
{
|
||||
$this->loadViewsFrom(__DIR__.'/../resources/views', 'translation');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../resources/views' => resource_path('views/vendor/translation'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register package routes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function registerRoutes()
|
||||
{
|
||||
$this->loadRoutesFrom(__DIR__.'/../routes/web.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish package configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function publishConfiguration()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__.'/../config/translation.php' => config_path('translation.php'),
|
||||
], 'config');
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge package configuration.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function mergeConfiguration()
|
||||
{
|
||||
$this->mergeConfigFrom(__DIR__.'/../config/translation.php', 'translation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish package assets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function publishAssets()
|
||||
{
|
||||
$this->publishes([
|
||||
__DIR__.'/../public/assets' => public_path('vendor/translation'),
|
||||
], 'assets');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load package migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function loadMigrations()
|
||||
{
|
||||
if (config('translation.driver') !== 'database') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load package translations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function loadTranslations()
|
||||
{
|
||||
$this->loadTranslationsFrom(__DIR__.'/../resources/lang', 'translation');
|
||||
|
||||
$this->publishes([
|
||||
__DIR__.'/../resources/lang' => resource_path('lang/vendor/translation'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register package commands.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function registerCommands()
|
||||
{
|
||||
if ($this->app->runningInConsole()) {
|
||||
$this->commands([
|
||||
AddLanguageCommand::class,
|
||||
AddTranslationKeyCommand::class,
|
||||
ListLanguagesCommand::class,
|
||||
ListMissingTranslationKeys::class,
|
||||
SynchroniseMissingTranslationKeys::class,
|
||||
SynchroniseTranslationsCommand::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register package helper functions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function registerHelpers()
|
||||
{
|
||||
require __DIR__.'/../resources/helpers.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register package bindings in the container.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function registerContainerBindings()
|
||||
{
|
||||
$this->app->singleton(Scanner::class, function () {
|
||||
$config = $this->app['config']['translation'];
|
||||
|
||||
return new Scanner(new Filesystem(), $config['scan_paths'], $config['translation_methods']);
|
||||
});
|
||||
|
||||
$this->app->singleton(Translation::class, function ($app) {
|
||||
return (new TranslationManager($app, $app['config']['translation'], $app->make(Scanner::class)))->resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
952
support/laravel-translation/tailwind.js
Normal file
952
support/laravel-translation/tailwind.js
Normal file
@@ -0,0 +1,952 @@
|
||||
/*
|
||||
|
||||
Tailwind - The Utility-First CSS Framework
|
||||
|
||||
A project by Adam Wathan (@adamwathan), Jonathan Reinink (@reinink),
|
||||
David Hemphill (@davidhemphill) and Steve Schoger (@steveschoger).
|
||||
|
||||
Welcome to the Tailwind config file. This is where you can customize
|
||||
Tailwind specifically for your project. Don't be intimidated by the
|
||||
length of this file. It's really just a big JavaScript object and
|
||||
we've done our very best to explain each section.
|
||||
|
||||
View the full documentation at https://tailwindcss.com.
|
||||
|
||||
|
||||
|-------------------------------------------------------------------------------
|
||||
| The default config
|
||||
|-------------------------------------------------------------------------------
|
||||
|
|
||||
| This variable contains the default Tailwind config. You don't have
|
||||
| to use it, but it can sometimes be helpful to have available. For
|
||||
| example, you may choose to merge your custom configuration
|
||||
| values with some of the Tailwind defaults.
|
||||
|
|
||||
*/
|
||||
|
||||
// let defaultConfig = require('tailwindcss/defaultConfig')()
|
||||
|
||||
|
||||
/*
|
||||
|-------------------------------------------------------------------------------
|
||||
| Colors https://tailwindcss.com/docs/colors
|
||||
|-------------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can specify the colors used in your project. To get you started,
|
||||
| we've provided a generous palette of great looking colors that are perfect
|
||||
| for prototyping, but don't hesitate to change them for your project. You
|
||||
| own these colors, nothing will break if you change everything about them.
|
||||
|
|
||||
| We've used literal color names ("red", "blue", etc.) for the default
|
||||
| palette, but if you'd rather use functional names like "primary" and
|
||||
| "secondary", or even a numeric scale like "100" and "200", go for it.
|
||||
|
|
||||
*/
|
||||
|
||||
let colors = {
|
||||
'transparent': 'transparent',
|
||||
|
||||
'black': '#22292f',
|
||||
'grey-darkest': '#3d4852',
|
||||
'grey-darker': '#606f7b',
|
||||
'grey-dark': '#8795a1',
|
||||
'grey': '#b8c2cc',
|
||||
'grey-light': '#dae1e7',
|
||||
'grey-lighter': '#f1f5f8',
|
||||
'grey-lightest': '#f8fafc',
|
||||
'white': '#ffffff',
|
||||
|
||||
'red-darkest': '#3b0d0c',
|
||||
'red-darker': '#621b18',
|
||||
'red-dark': '#cc1f1a',
|
||||
'red': '#e3342f',
|
||||
'red-light': '#ef5753',
|
||||
'red-lighter': '#f9acaa',
|
||||
'red-lightest': '#fcebea',
|
||||
|
||||
'orange-darkest': '#462a16',
|
||||
'orange-darker': '#613b1f',
|
||||
'orange-dark': '#de751f',
|
||||
'orange': '#f6993f',
|
||||
'orange-light': '#faad63',
|
||||
'orange-lighter': '#fcd9b6',
|
||||
'orange-lightest': '#fff5eb',
|
||||
|
||||
'yellow-darkest': '#453411',
|
||||
'yellow-darker': '#684f1d',
|
||||
'yellow-dark': '#f2d024',
|
||||
'yellow': '#ffed4a',
|
||||
'yellow-light': '#fff382',
|
||||
'yellow-lighter': '#fff9c2',
|
||||
'yellow-lightest': '#fcfbeb',
|
||||
|
||||
'green-darkest': '#0f2f21',
|
||||
'green-darker': '#1a4731',
|
||||
'green-dark': '#1f9d55',
|
||||
'green': '#38c172',
|
||||
'green-light': '#51d88a',
|
||||
'green-lighter': '#a2f5bf',
|
||||
'green-lightest': '#e3fcec',
|
||||
|
||||
'teal-darkest': '#0d3331',
|
||||
'teal-darker': '#20504f',
|
||||
'teal-dark': '#38a89d',
|
||||
'teal': '#4dc0b5',
|
||||
'teal-light': '#64d5ca',
|
||||
'teal-lighter': '#a0f0ed',
|
||||
'teal-lightest': '#e8fffe',
|
||||
|
||||
'blue-darkest': '#12283a',
|
||||
'blue-darker': '#1c3d5a',
|
||||
'blue-dark': '#125b93',
|
||||
'blue': '#2891c4',
|
||||
'blue-light': '#6cb2eb',
|
||||
'blue-lighter': '#bcdefa',
|
||||
'blue-lightest': '#eff8ff',
|
||||
|
||||
'indigo-darkest': '#191e38',
|
||||
'indigo-darker': '#2f365f',
|
||||
'indigo-dark': '#5661b3',
|
||||
'indigo': '#6574cd',
|
||||
'indigo-light': '#7886d7',
|
||||
'indigo-lighter': '#b2b7ff',
|
||||
'indigo-lightest': '#e6e8ff',
|
||||
|
||||
'purple-darkest': '#21183c',
|
||||
'purple-darker': '#382b5f',
|
||||
'purple-dark': '#794acf',
|
||||
'purple': '#9561e2',
|
||||
'purple-light': '#a779e9',
|
||||
'purple-lighter': '#d6bbfc',
|
||||
'purple-lightest': '#f3ebff',
|
||||
|
||||
'pink-darkest': '#451225',
|
||||
'pink-darker': '#6f213f',
|
||||
'pink-dark': '#eb5286',
|
||||
'pink': '#f66d9b',
|
||||
'pink-light': '#fa7ea8',
|
||||
'pink-lighter': '#ffbbca',
|
||||
'pink-lightest': '#ffebef',
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Colors https://tailwindcss.com/docs/colors
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| The color palette defined above is also assigned to the "colors" key of
|
||||
| your Tailwind config. This makes it easy to access them in your CSS
|
||||
| using Tailwind's config helper. For example:
|
||||
|
|
||||
| .error { color: config('colors.red') }
|
||||
|
|
||||
*/
|
||||
|
||||
colors: colors,
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Screens https://tailwindcss.com/docs/responsive-design
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Screens in Tailwind are translated to CSS media queries. They define the
|
||||
| responsive breakpoints for your project. By default Tailwind takes a
|
||||
| "mobile first" approach, where each screen size represents a minimum
|
||||
| viewport width. Feel free to have as few or as many screens as you
|
||||
| want, naming them in whatever way you'd prefer for your project.
|
||||
|
|
||||
| Tailwind also allows for more complex screen definitions, which can be
|
||||
| useful in certain situations. Be sure to see the full responsive
|
||||
| documentation for a complete list of options.
|
||||
|
|
||||
| Class name: .{screen}:{utility}
|
||||
|
|
||||
*/
|
||||
|
||||
screens: {
|
||||
'sm': '576px',
|
||||
'md': '768px',
|
||||
'lg': '992px',
|
||||
'xl': '1200px',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Fonts https://tailwindcss.com/docs/fonts
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your project's font stack, or font families.
|
||||
| Keep in mind that Tailwind doesn't actually load any fonts for you.
|
||||
| If you're using custom fonts you'll need to import them prior to
|
||||
| defining them here.
|
||||
|
|
||||
| By default we provide a native font stack that works remarkably well on
|
||||
| any device or OS you're using, since it just uses the default fonts
|
||||
| provided by the platform.
|
||||
|
|
||||
| Class name: .font-{name}
|
||||
|
|
||||
*/
|
||||
|
||||
fonts: {
|
||||
'sans': [
|
||||
'system-ui',
|
||||
'BlinkMacSystemFont',
|
||||
'-apple-system',
|
||||
'Segoe UI',
|
||||
'Roboto',
|
||||
'Oxygen',
|
||||
'Ubuntu',
|
||||
'Cantarell',
|
||||
'Fira Sans',
|
||||
'Droid Sans',
|
||||
'Helvetica Neue',
|
||||
'sans-serif',
|
||||
],
|
||||
'serif': [
|
||||
'Constantia',
|
||||
'Lucida Bright',
|
||||
'Lucidabright',
|
||||
'Lucida Serif',
|
||||
'Lucida',
|
||||
'DejaVu Serif',
|
||||
'Bitstream Vera Serif',
|
||||
'Liberation Serif',
|
||||
'Georgia',
|
||||
'serif',
|
||||
],
|
||||
'mono': [
|
||||
'Menlo',
|
||||
'Monaco',
|
||||
'Consolas',
|
||||
'Liberation Mono',
|
||||
'Courier New',
|
||||
'monospace',
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Text sizes https://tailwindcss.com/docs/text-sizing
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your text sizes. Name these in whatever way
|
||||
| makes the most sense to you. We use size names by default, but
|
||||
| you're welcome to use a numeric scale or even something else
|
||||
| entirely.
|
||||
|
|
||||
| By default Tailwind uses the "rem" unit type for most measurements.
|
||||
| This allows you to set a root font size which all other sizes are
|
||||
| then based on. That said, you are free to use whatever units you
|
||||
| prefer, be it rems, ems, pixels or other.
|
||||
|
|
||||
| Class name: .text-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
textSizes: {
|
||||
'xs': '.75rem', // 12px
|
||||
'sm': '.875rem', // 14px
|
||||
'base': '1rem', // 16px
|
||||
'lg': '1.125rem', // 18px
|
||||
'xl': '1.25rem', // 20px
|
||||
'2xl': '1.5rem', // 24px
|
||||
'3xl': '1.875rem', // 30px
|
||||
'4xl': '2.25rem', // 36px
|
||||
'5xl': '3rem', // 48px
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Font weights https://tailwindcss.com/docs/font-weight
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your font weights. We've provided a list of
|
||||
| common font weight names with their respective numeric scale values
|
||||
| to get you started. It's unlikely that your project will require
|
||||
| all of these, so we recommend removing those you don't need.
|
||||
|
|
||||
| Class name: .font-{weight}
|
||||
|
|
||||
*/
|
||||
|
||||
fontWeights: {
|
||||
'hairline': 100,
|
||||
'thin': 200,
|
||||
'light': 300,
|
||||
'normal': 400,
|
||||
'medium': 500,
|
||||
'semibold': 600,
|
||||
'bold': 700,
|
||||
'extrabold': 800,
|
||||
'black': 900,
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Leading (line height) https://tailwindcss.com/docs/line-height
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your line height values, or as we call
|
||||
| them in Tailwind, leadings.
|
||||
|
|
||||
| Class name: .leading-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
leading: {
|
||||
'none': 1,
|
||||
'tight': 1.25,
|
||||
'normal': 1.5,
|
||||
'loose': 2,
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Tracking (letter spacing) https://tailwindcss.com/docs/letter-spacing
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your letter spacing values, or as we call
|
||||
| them in Tailwind, tracking.
|
||||
|
|
||||
| Class name: .tracking-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
tracking: {
|
||||
'tight': '-0.05em',
|
||||
'normal': '0',
|
||||
'wide': '0.05em',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Text colors https://tailwindcss.com/docs/text-color
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your text colors. By default these use the
|
||||
| color palette we defined above, however you're welcome to set these
|
||||
| independently if that makes sense for your project.
|
||||
|
|
||||
| Class name: .text-{color}
|
||||
|
|
||||
*/
|
||||
|
||||
textColors: colors,
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Background colors https://tailwindcss.com/docs/background-color
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your background colors. By default these use
|
||||
| the color palette we defined above, however you're welcome to set
|
||||
| these independently if that makes sense for your project.
|
||||
|
|
||||
| Class name: .bg-{color}
|
||||
|
|
||||
*/
|
||||
|
||||
backgroundColors: colors,
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Background sizes https://tailwindcss.com/docs/background-size
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your background sizes. We provide some common
|
||||
| values that are useful in most projects, but feel free to add other sizes
|
||||
| that are specific to your project here as well.
|
||||
|
|
||||
| Class name: .bg-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
backgroundSize: {
|
||||
'auto': 'auto',
|
||||
'cover': 'cover',
|
||||
'contain': 'contain',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Border widths https://tailwindcss.com/docs/border-width
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your border widths. Take note that border
|
||||
| widths require a special "default" value set as well. This is the
|
||||
| width that will be used when you do not specify a border width.
|
||||
|
|
||||
| Class name: .border{-side?}{-width?}
|
||||
|
|
||||
*/
|
||||
|
||||
borderWidths: {
|
||||
default: '1px',
|
||||
'0': '0',
|
||||
'2': '2px',
|
||||
'4': '4px',
|
||||
'8': '8px',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Border colors https://tailwindcss.com/docs/border-color
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your border colors. By default these use the
|
||||
| color palette we defined above, however you're welcome to set these
|
||||
| independently if that makes sense for your project.
|
||||
|
|
||||
| Take note that border colors require a special "default" value set
|
||||
| as well. This is the color that will be used when you do not
|
||||
| specify a border color.
|
||||
|
|
||||
| Class name: .border-{color}
|
||||
|
|
||||
*/
|
||||
|
||||
borderColors: global.Object.assign({ default: colors['grey-light'] }, colors),
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Border radius https://tailwindcss.com/docs/border-radius
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your border radius values. If a `default` radius
|
||||
| is provided, it will be made available as the non-suffixed `.rounded`
|
||||
| utility.
|
||||
|
|
||||
| If your scale includes a `0` value to reset already rounded corners, it's
|
||||
| a good idea to put it first so other values are able to override it.
|
||||
|
|
||||
| Class name: .rounded{-side?}{-size?}
|
||||
|
|
||||
*/
|
||||
|
||||
borderRadius: {
|
||||
'none': '0',
|
||||
'sm': '.125rem',
|
||||
default: '.25rem',
|
||||
'lg': '.5rem',
|
||||
'full': '9999px',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Width https://tailwindcss.com/docs/width
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your width utility sizes. These can be
|
||||
| percentage based, pixels, rems, or any other units. By default
|
||||
| we provide a sensible rem based numeric scale, a percentage
|
||||
| based fraction scale, plus some other common use-cases. You
|
||||
| can, of course, modify these values as needed.
|
||||
|
|
||||
|
|
||||
| It's also worth mentioning that Tailwind automatically escapes
|
||||
| invalid CSS class name characters, which allows you to have
|
||||
| awesome classes like .w-2/3.
|
||||
|
|
||||
| Class name: .w-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
width: {
|
||||
'auto': 'auto',
|
||||
'px': '1px',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
'48': '12rem',
|
||||
'64': '16rem',
|
||||
'1/2': '50%',
|
||||
'1/3': '33.33333%',
|
||||
'2/3': '66.66667%',
|
||||
'1/4': '25%',
|
||||
'3/4': '75%',
|
||||
'1/5': '20%',
|
||||
'2/5': '40%',
|
||||
'3/5': '60%',
|
||||
'4/5': '80%',
|
||||
'1/6': '16.66667%',
|
||||
'5/6': '83.33333%',
|
||||
'full': '100%',
|
||||
'screen': '100vw'
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Height https://tailwindcss.com/docs/height
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your height utility sizes. These can be
|
||||
| percentage based, pixels, rems, or any other units. By default
|
||||
| we provide a sensible rem based numeric scale plus some other
|
||||
| common use-cases. You can, of course, modify these values as
|
||||
| needed.
|
||||
|
|
||||
| Class name: .h-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
height: {
|
||||
'auto': 'auto',
|
||||
'px': '1px',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
'48': '12rem',
|
||||
'64': '16rem',
|
||||
'full': '100%',
|
||||
'screen': '100vh'
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Minimum width https://tailwindcss.com/docs/min-width
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your minimum width utility sizes. These can
|
||||
| be percentage based, pixels, rems, or any other units. We provide a
|
||||
| couple common use-cases by default. You can, of course, modify
|
||||
| these values as needed.
|
||||
|
|
||||
| Class name: .min-w-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
minWidth: {
|
||||
'0': '0',
|
||||
'full': '100%',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Minimum height https://tailwindcss.com/docs/min-height
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your minimum height utility sizes. These can
|
||||
| be percentage based, pixels, rems, or any other units. We provide a
|
||||
| few common use-cases by default. You can, of course, modify these
|
||||
| values as needed.
|
||||
|
|
||||
| Class name: .min-h-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
minHeight: {
|
||||
'0': '0',
|
||||
'full': '100%',
|
||||
'screen': '100vh'
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Maximum width https://tailwindcss.com/docs/max-width
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your maximum width utility sizes. These can
|
||||
| be percentage based, pixels, rems, or any other units. By default
|
||||
| we provide a sensible rem based scale and a "full width" size,
|
||||
| which is basically a reset utility. You can, of course,
|
||||
| modify these values as needed.
|
||||
|
|
||||
| Class name: .max-w-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
maxWidth: {
|
||||
'xs': '20rem',
|
||||
'sm': '30rem',
|
||||
'md': '40rem',
|
||||
'lg': '50rem',
|
||||
'xl': '60rem',
|
||||
'2xl': '70rem',
|
||||
'3xl': '80rem',
|
||||
'4xl': '90rem',
|
||||
'5xl': '100rem',
|
||||
'full': '100%',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Maximum height https://tailwindcss.com/docs/max-height
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your maximum height utility sizes. These can
|
||||
| be percentage based, pixels, rems, or any other units. We provide a
|
||||
| couple common use-cases by default. You can, of course, modify
|
||||
| these values as needed.
|
||||
|
|
||||
| Class name: .max-h-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
maxHeight: {
|
||||
'full': '100%',
|
||||
'screen': '100vh',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Padding https://tailwindcss.com/docs/padding
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your padding utility sizes. These can be
|
||||
| percentage based, pixels, rems, or any other units. By default we
|
||||
| provide a sensible rem based numeric scale plus a couple other
|
||||
| common use-cases like "1px". You can, of course, modify these
|
||||
| values as needed.
|
||||
|
|
||||
| Class name: .p{side?}-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
padding: {
|
||||
'px': '1px',
|
||||
'0': '0',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'20': '5rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Margin https://tailwindcss.com/docs/margin
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your margin utility sizes. These can be
|
||||
| percentage based, pixels, rems, or any other units. By default we
|
||||
| provide a sensible rem based numeric scale plus a couple other
|
||||
| common use-cases like "1px". You can, of course, modify these
|
||||
| values as needed.
|
||||
|
|
||||
| Class name: .m{side?}-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
margin: {
|
||||
'auto': 'auto',
|
||||
'px': '1px',
|
||||
'0': '0',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'20': '5rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Negative margin https://tailwindcss.com/docs/negative-margin
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your negative margin utility sizes. These can
|
||||
| be percentage based, pixels, rems, or any other units. By default we
|
||||
| provide matching values to the padding scale since these utilities
|
||||
| generally get used together. You can, of course, modify these
|
||||
| values as needed.
|
||||
|
|
||||
| Class name: .-m{side?}-{size}
|
||||
|
|
||||
*/
|
||||
|
||||
negativeMargin: {
|
||||
'px': '1px',
|
||||
'0': '0',
|
||||
'1': '0.25rem',
|
||||
'2': '0.5rem',
|
||||
'3': '0.75rem',
|
||||
'4': '1rem',
|
||||
'5': '1.25rem',
|
||||
'6': '1.5rem',
|
||||
'8': '2rem',
|
||||
'10': '2.5rem',
|
||||
'12': '3rem',
|
||||
'16': '4rem',
|
||||
'20': '5rem',
|
||||
'24': '6rem',
|
||||
'32': '8rem',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Shadows https://tailwindcss.com/docs/shadows
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your shadow utilities. As you can see from
|
||||
| the defaults we provide, it's possible to apply multiple shadows
|
||||
| per utility using comma separation.
|
||||
|
|
||||
| If a `default` shadow is provided, it will be made available as the non-
|
||||
| suffixed `.shadow` utility.
|
||||
|
|
||||
| Class name: .shadow-{size?}
|
||||
|
|
||||
*/
|
||||
|
||||
shadows: {
|
||||
default: '0 2px 4px 0 rgba(0,0,0,0.10)',
|
||||
'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)',
|
||||
'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)',
|
||||
'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)',
|
||||
'outline': '0 0 0 3px rgba(52,144,220,0.5)',
|
||||
'none': 'none',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Z-index https://tailwindcss.com/docs/z-index
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your z-index utility values. By default we
|
||||
| provide a sensible numeric scale. You can, of course, modify these
|
||||
| values as needed.
|
||||
|
|
||||
| Class name: .z-{index}
|
||||
|
|
||||
*/
|
||||
|
||||
zIndex: {
|
||||
'auto': 'auto',
|
||||
'0': 0,
|
||||
'10': 10,
|
||||
'20': 20,
|
||||
'30': 30,
|
||||
'40': 40,
|
||||
'50': 50,
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Opacity https://tailwindcss.com/docs/opacity
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your opacity utility values. By default we
|
||||
| provide a sensible numeric scale. You can, of course, modify these
|
||||
| values as needed.
|
||||
|
|
||||
| Class name: .opacity-{name}
|
||||
|
|
||||
*/
|
||||
|
||||
opacity: {
|
||||
'0': '0',
|
||||
'25': '.25',
|
||||
'50': '.5',
|
||||
'75': '.75',
|
||||
'100': '1',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| SVG fill https://tailwindcss.com/docs/svg
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your SVG fill colors. By default we just provide
|
||||
| `fill-current` which sets the fill to the current text color. This lets you
|
||||
| specify a fill color using existing text color utilities and helps keep the
|
||||
| generated CSS file size down.
|
||||
|
|
||||
| Class name: .fill-{name}
|
||||
|
|
||||
*/
|
||||
|
||||
svgFill: {
|
||||
'current': 'currentColor',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| SVG stroke https://tailwindcss.com/docs/svg
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you define your SVG stroke colors. By default we just provide
|
||||
| `stroke-current` which sets the stroke to the current text color. This lets
|
||||
| you specify a stroke color using existing text color utilities and helps
|
||||
| keep the generated CSS file size down.
|
||||
|
|
||||
| Class name: .stroke-{name}
|
||||
|
|
||||
*/
|
||||
|
||||
svgStroke: {
|
||||
'current': 'currentColor',
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Modules https://tailwindcss.com/docs/configuration#modules
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you control which modules are generated and what variants are
|
||||
| generated for each of those modules.
|
||||
|
|
||||
| Currently supported variants:
|
||||
| - responsive
|
||||
| - hover
|
||||
| - focus
|
||||
| - active
|
||||
| - group-hover
|
||||
|
|
||||
| To disable a module completely, use `false` instead of an array.
|
||||
|
|
||||
*/
|
||||
|
||||
modules: {
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: ['responsive'],
|
||||
backgroundColors: ['responsive', 'hover', 'focus'],
|
||||
backgroundPosition: ['responsive'],
|
||||
backgroundRepeat: ['responsive'],
|
||||
backgroundSize: ['responsive'],
|
||||
borderCollapse: [],
|
||||
borderColors: ['responsive', 'hover', 'focus'],
|
||||
borderRadius: ['responsive'],
|
||||
borderStyle: ['responsive'],
|
||||
borderWidths: ['responsive'],
|
||||
cursor: ['responsive'],
|
||||
display: ['responsive'],
|
||||
flexbox: ['responsive'],
|
||||
float: ['responsive'],
|
||||
fonts: ['responsive'],
|
||||
fontWeights: ['responsive', 'hover', 'focus'],
|
||||
height: ['responsive'],
|
||||
leading: ['responsive'],
|
||||
lists: ['responsive'],
|
||||
margin: ['responsive'],
|
||||
maxHeight: ['responsive'],
|
||||
maxWidth: ['responsive'],
|
||||
minHeight: ['responsive'],
|
||||
minWidth: ['responsive'],
|
||||
negativeMargin: ['responsive'],
|
||||
opacity: ['responsive'],
|
||||
outline: ['focus'],
|
||||
overflow: ['responsive'],
|
||||
padding: ['responsive'],
|
||||
pointerEvents: ['responsive'],
|
||||
position: ['responsive'],
|
||||
resize: ['responsive'],
|
||||
shadows: ['responsive', 'hover', 'focus'],
|
||||
svgFill: [],
|
||||
svgStroke: [],
|
||||
tableLayout: ['responsive'],
|
||||
textAlign: ['responsive'],
|
||||
textColors: ['responsive', 'hover', 'focus'],
|
||||
textSizes: ['responsive'],
|
||||
textStyle: ['responsive', 'hover', 'focus'],
|
||||
tracking: ['responsive'],
|
||||
userSelect: ['responsive'],
|
||||
verticalAlign: ['responsive'],
|
||||
visibility: ['responsive'],
|
||||
whitespace: ['responsive'],
|
||||
width: ['responsive'],
|
||||
zIndex: ['responsive'],
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Plugins https://tailwindcss.com/docs/plugins
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register any plugins you'd like to use in your
|
||||
| project. Tailwind's built-in `container` plugin is enabled by default to
|
||||
| give you a Bootstrap-style responsive container component out of the box.
|
||||
|
|
||||
| Be sure to view the complete plugin documentation to learn more about how
|
||||
| the plugin system works.
|
||||
|
|
||||
*/
|
||||
|
||||
plugins: [
|
||||
require('tailwindcss/plugins/container')({
|
||||
// center: true,
|
||||
// padding: '1rem',
|
||||
}),
|
||||
],
|
||||
|
||||
|
||||
/*
|
||||
|-----------------------------------------------------------------------------
|
||||
| Advanced Options https://tailwindcss.com/docs/configuration#options
|
||||
|-----------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can tweak advanced configuration options. We recommend
|
||||
| leaving these options alone unless you absolutely need to change them.
|
||||
|
|
||||
*/
|
||||
|
||||
options: {
|
||||
prefix: '',
|
||||
important: false,
|
||||
separator: ':',
|
||||
},
|
||||
|
||||
}
|
||||
375
support/laravel-translation/tests/DatabaseDriverTest.php
Normal file
375
support/laravel-translation/tests/DatabaseDriverTest.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Tests;
|
||||
|
||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
use JoeDixon\Translation\Events\TranslationAdded;
|
||||
use JoeDixon\Translation\Exceptions\LanguageExistsException;
|
||||
use JoeDixon\Translation\Language;
|
||||
use JoeDixon\Translation\Translation as TranslationModel;
|
||||
use JoeDixon\Translation\TranslationBindingsServiceProvider;
|
||||
use JoeDixon\Translation\TranslationServiceProvider;
|
||||
use Orchestra\Testbench\TestCase;
|
||||
|
||||
class DatabaseDriverTest extends TestCase
|
||||
{
|
||||
use DatabaseMigrations;
|
||||
|
||||
private $translation;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*/
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->withFactories(__DIR__.'/../database/factories');
|
||||
$this->translation = $this->app[Translation::class];
|
||||
}
|
||||
|
||||
protected function getEnvironmentSetUp($app)
|
||||
{
|
||||
$app['config']->set('translation.driver', 'database');
|
||||
$app['config']->set('database.default', 'testing');
|
||||
$app['config']->set('database.connections.testing', [
|
||||
'driver' => 'sqlite',
|
||||
'database' => ':memory:',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
TranslationServiceProvider::class,
|
||||
TranslationBindingsServiceProvider::class,
|
||||
];
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_returns_all_languages()
|
||||
{
|
||||
$newLanguages = factory(Language::class, 2)->create();
|
||||
$newLanguages = $newLanguages->mapWithKeys(function ($language) {
|
||||
return [$language->language => $language->name];
|
||||
})->toArray();
|
||||
$languages = $this->translation->allLanguages();
|
||||
|
||||
$this->assertEquals($languages->count(), 3);
|
||||
$this->assertEquals($languages->toArray(), ['en' => 'en'] + $newLanguages);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_returns_all_translations()
|
||||
{
|
||||
$default = Language::where('language', config('app.locale'))->first();
|
||||
factory(Language::class)->create(['language' => 'es', 'name' => 'Español']);
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'group' => 'single', 'key' => 'Hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'group' => 'single', 'key' => "What's up", 'value' => "What's up!"]);
|
||||
|
||||
$translations = $this->translation->allTranslations();
|
||||
|
||||
$this->assertEquals($translations->count(), 2);
|
||||
$this->assertEquals(['single' => ['single' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'group' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray()['en']);
|
||||
$this->assertArrayHasKey('en', $translations->toArray());
|
||||
$this->assertArrayHasKey('es', $translations->toArray());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_returns_all_translations_for_a_given_language()
|
||||
{
|
||||
$default = Language::where('language', config('app.locale'))->first();
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'group' => 'single', 'key' => 'Hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'group' => 'single', 'key' => "What's up", 'value' => "What's up!"]);
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('en');
|
||||
$this->assertEquals($translations->count(), 2);
|
||||
$this->assertEquals(['single' => ['single' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'group' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray());
|
||||
$this->assertArrayHasKey('single', $translations->toArray());
|
||||
$this->assertArrayHasKey('group', $translations->toArray());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_throws_an_exception_if_a_language_exists()
|
||||
{
|
||||
$this->expectException(LanguageExistsException::class);
|
||||
$this->translation->addLanguage('en');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_language()
|
||||
{
|
||||
$this->assertDatabaseMissing(config('translation.database.languages_table'), [
|
||||
'language' => 'fr',
|
||||
'name' => 'Français',
|
||||
]);
|
||||
|
||||
$this->translation->addLanguage('fr', 'Français');
|
||||
$this->assertDatabaseHas(config('translation.database.languages_table'), [
|
||||
'language' => 'fr',
|
||||
'name' => 'Français',
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_translation_to_a_new_group()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('es');
|
||||
|
||||
$this->assertEquals(['test' => ['hello' => 'Hola!']], $translations->toArray()['group']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_translation_to_an_existing_translation_group()
|
||||
{
|
||||
$translation = factory(TranslationModel::class)->create();
|
||||
|
||||
$this->translation->addGroupTranslation($translation->language->language, "{$translation->group}", 'test', 'Testing');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor($translation->language->language);
|
||||
$this->assertSame([$translation->group => [$translation->key => $translation->value, 'test' => 'Testing']], $translations->toArray()['group']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_single_translation()
|
||||
{
|
||||
$this->translation->addSingleTranslation('es', 'single', 'Hello', 'Hola!');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('es');
|
||||
|
||||
$this->assertEquals(['single' => ['Hello' => 'Hola!']], $translations->toArray()['single']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_single_translation_to_an_existing_language()
|
||||
{
|
||||
$translation = factory(TranslationModel::class)->states('single')->create();
|
||||
|
||||
$this->translation->addSingleTranslation($translation->language->language, 'single', 'Test', 'Testing');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor($translation->language->language);
|
||||
|
||||
$this->assertEquals(['single' => ['Test' => 'Testing', $translation->key => $translation->value]], $translations->toArray()['single']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_get_a_collection_of_group_names_for_a_given_language()
|
||||
{
|
||||
$language = factory(Language::class)->create(['language' => 'en']);
|
||||
factory(TranslationModel::class)->create([
|
||||
'language_id' => $language->id,
|
||||
'group' => 'test',
|
||||
]);
|
||||
|
||||
$groups = $this->translation->getGroupsFor('en');
|
||||
|
||||
$this->assertEquals($groups->toArray(), ['test']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_merge_a_language_with_the_base_language()
|
||||
{
|
||||
$default = Language::where('language', config('app.locale'))->first();
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'group' => 'single', 'key' => 'Hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'group' => 'single', 'key' => "What's up", 'value' => "What's up!"]);
|
||||
|
||||
$this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
|
||||
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
|
||||
|
||||
$this->assertEquals($translations->toArray(), [
|
||||
'group' => [
|
||||
'test' => [
|
||||
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
|
||||
'whats_up' => ['en' => "What's up!", 'es' => ''],
|
||||
],
|
||||
],
|
||||
'single' => [
|
||||
'single' => [
|
||||
'Hello' => [
|
||||
'en' => 'Hello',
|
||||
'es' => '',
|
||||
],
|
||||
"What's up" => [
|
||||
'en' => "What's up!",
|
||||
'es' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_vendor_namespaced_translations()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'translation_test::test', 'hello', 'Hola!');
|
||||
|
||||
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
|
||||
'group' => [
|
||||
'translation_test::test' => [
|
||||
'hello' => 'Hola!',
|
||||
],
|
||||
],
|
||||
'single' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_nested_translation()
|
||||
{
|
||||
$this->translation->addGroupTranslation('en', 'test', 'test.nested', 'Nested!');
|
||||
|
||||
$this->assertEquals($this->translation->getGroupTranslationsFor('en')->toArray(), [
|
||||
'test' => [
|
||||
'test.nested' => 'Nested!',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_nested_vendor_namespaced_translations()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'translation_test::test', 'nested.hello', 'Hola!');
|
||||
|
||||
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
|
||||
'group' => [
|
||||
'translation_test::test' => [
|
||||
'nested.hello' => 'Hola!',
|
||||
],
|
||||
],
|
||||
'single' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_merge_a_namespaced_language_with_the_base_language()
|
||||
{
|
||||
$this->translation->addGroupTranslation('en', 'translation_test::test', 'hello', 'Hello');
|
||||
$this->translation->addGroupTranslation('es', 'translation_test::test', 'hello', 'Hola!');
|
||||
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
|
||||
|
||||
$this->assertEquals($translations->toArray(), [
|
||||
'group' => [
|
||||
'translation_test::test' => [
|
||||
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
|
||||
],
|
||||
],
|
||||
'single' => [],
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_list_of_languages_can_be_viewed()
|
||||
{
|
||||
$newLanguages = factory(Language::class, 2)->create();
|
||||
$response = $this->get(config('translation.ui_url'));
|
||||
|
||||
$response->assertSee(config('app.locale'));
|
||||
foreach ($newLanguages as $language) {
|
||||
$response->assertSee($language->language);
|
||||
}
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_language_creation_page_can_be_viewed()
|
||||
{
|
||||
$this->translation->addGroupTranslation(config('app.locale'), 'translation::translation', 'add_language', 'Add a new language');
|
||||
$this->get(config('translation.ui_url').'/create')
|
||||
->assertSee('Add a new language');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_language_can_be_added()
|
||||
{
|
||||
$this->post(config('translation.ui_url'), ['locale' => 'de'])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertDatabaseHas('languages', ['language' => 'de']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_list_of_translations_can_be_viewed()
|
||||
{
|
||||
$default = Language::where('language', config('app.locale'))->first();
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'key' => 'Hello', 'value' => 'Hello!']);
|
||||
factory(TranslationModel::class)->states('single')->create(['language_id' => $default->id, 'key' => "What's up", 'value' => 'Sup!']);
|
||||
|
||||
$this->get(config('translation.ui_url').'/en/translations')
|
||||
->assertSee('hello')
|
||||
->assertSee('whats_up')
|
||||
->assertSee('Hello')
|
||||
->assertSee('Sup!');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_translation_creation_page_can_be_viewed()
|
||||
{
|
||||
$this->translation->addGroupTranslation('en', 'translation::translation', 'add_translation', 'Add a translation');
|
||||
$this->get(config('translation.ui_url').'/'.config('app.locale').'/translations/create')
|
||||
->assertSee('Add a translation');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_new_translation_can_be_added()
|
||||
{
|
||||
$this->post(config('translation.ui_url').'/'.config('app.locale').'/translations', ['group' => 'single', 'key' => 'joe', 'value' => 'is cool'])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertDatabaseHas('translations', ['language_id' => 1, 'key' => 'joe', 'value' => 'is cool']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_translation_can_be_updated()
|
||||
{
|
||||
$default = Language::where('language', config('app.locale'))->first();
|
||||
factory(TranslationModel::class)->states('group')->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
|
||||
$this->assertDatabaseHas('translations', ['language_id' => 1, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
|
||||
|
||||
$this->post(config('translation.ui_url').'/en', ['group' => 'test', 'key' => 'hello', 'value' => 'Hello there!'])
|
||||
->assertStatus(200);
|
||||
|
||||
$this->assertDatabaseHas('translations', ['language_id' => 1, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello there!']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function adding_a_translation_fires_an_event_with_the_expected_data()
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
$data = ['key' => 'joe', 'value' => 'is cool'];
|
||||
$this->post(config('translation.ui_url').'/en/translations', $data);
|
||||
|
||||
Event::assertDispatched(TranslationAdded::class, function ($event) use ($data) {
|
||||
return $event->language === 'en' &&
|
||||
$event->group === 'single' &&
|
||||
$event->value === $data['value'] &&
|
||||
$event->key === $data['key'];
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function updating_a_translation_fires_an_event_with_the_expected_data()
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
$data = ['group' => 'test', 'key' => 'hello', 'value' => 'Hello there!'];
|
||||
$this->post(config('translation.ui_url').'/en/translations', $data);
|
||||
|
||||
Event::assertDispatched(TranslationAdded::class, function ($event) use ($data) {
|
||||
return $event->language === 'en' &&
|
||||
$event->group === $data['group'] &&
|
||||
$event->value === $data['value'] &&
|
||||
$event->key === $data['key'];
|
||||
});
|
||||
}
|
||||
}
|
||||
380
support/laravel-translation/tests/FileDriverTest.php
Normal file
380
support/laravel-translation/tests/FileDriverTest.php
Normal file
@@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Tests;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use JoeDixon\Translation\Drivers\Translation;
|
||||
use JoeDixon\Translation\Events\TranslationAdded;
|
||||
use JoeDixon\Translation\Exceptions\LanguageExistsException;
|
||||
use JoeDixon\Translation\TranslationBindingsServiceProvider;
|
||||
use JoeDixon\Translation\TranslationServiceProvider;
|
||||
use Orchestra\Testbench\TestCase;
|
||||
|
||||
class FileDriverTest extends TestCase
|
||||
{
|
||||
private $translation;
|
||||
|
||||
/**
|
||||
* Setup the test environment.
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
app()['path.lang'] = __DIR__.'/fixtures/lang';
|
||||
$this->translation = app()->make(Translation::class);
|
||||
}
|
||||
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
TranslationServiceProvider::class,
|
||||
TranslationBindingsServiceProvider::class,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getEnvironmentSetUp($app)
|
||||
{
|
||||
$app['config']->set('translation.driver', 'file');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_returns_all_languages()
|
||||
{
|
||||
$languages = $this->translation->allLanguages();
|
||||
|
||||
$this->assertEquals($languages->count(), 2);
|
||||
$this->assertEquals($languages->toArray(), ['en' => 'en', 'es' => 'es']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_returns_all_translations()
|
||||
{
|
||||
$translations = $this->translation->allTranslations();
|
||||
|
||||
$this->assertEquals($translations->count(), 2);
|
||||
$this->assertEquals(['single' => ['single' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'group' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray()['en']);
|
||||
$this->assertArrayHasKey('en', $translations->toArray());
|
||||
$this->assertArrayHasKey('es', $translations->toArray());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_returns_all_translations_for_a_given_language()
|
||||
{
|
||||
$translations = $this->translation->allTranslationsFor('en');
|
||||
$this->assertEquals($translations->count(), 2);
|
||||
$this->assertEquals(['single' => ['single' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'group' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray());
|
||||
$this->assertArrayHasKey('single', $translations->toArray());
|
||||
$this->assertArrayHasKey('group', $translations->toArray());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_throws_an_exception_if_a_language_exists()
|
||||
{
|
||||
$this->expectException(LanguageExistsException::class);
|
||||
$this->translation->addLanguage('en');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_language()
|
||||
{
|
||||
$this->translation->addLanguage('fr');
|
||||
|
||||
$this->assertTrue(file_exists(__DIR__.'/fixtures/lang/fr.json'));
|
||||
$this->assertTrue(file_exists(__DIR__.'/fixtures/lang/fr'));
|
||||
|
||||
rmdir(__DIR__.'/fixtures/lang/fr');
|
||||
unlink(__DIR__.'/fixtures/lang/fr.json');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_translation_to_a_new_group()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('es');
|
||||
|
||||
$this->assertEquals(['test' => ['hello' => 'Hola!']], $translations->toArray()['group']);
|
||||
|
||||
unlink(__DIR__.'/fixtures/lang/es/test.php');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_translation_to_an_existing_translation_group()
|
||||
{
|
||||
$this->translation->addGroupTranslation('en', 'test', 'test', 'Testing');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('en');
|
||||
|
||||
$this->assertEquals(['test' => ['hello' => 'Hello', 'whats_up' => 'What\'s up!', 'test' => 'Testing']], $translations->toArray()['group']);
|
||||
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en/test.php',
|
||||
"<?php\n\nreturn ".var_export(['hello' => 'Hello', 'whats_up' => 'What\'s up!'], true).';'.\PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_single_translation()
|
||||
{
|
||||
$this->translation->addSingleTranslation('es', 'single', 'Hello', 'Hola!');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('es');
|
||||
|
||||
$this->assertEquals(['single' => ['Hello' => 'Hola!']], $translations->toArray()['single']);
|
||||
|
||||
unlink(__DIR__.'/fixtures/lang/es.json');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_new_single_translation_to_an_existing_language()
|
||||
{
|
||||
$this->translation->addSingleTranslation('en', 'single', 'Test', 'Testing');
|
||||
|
||||
$translations = $this->translation->allTranslationsFor('en');
|
||||
|
||||
$this->assertEquals(['single' => ['Hello' => 'Hello', 'What\'s up' => 'What\'s up!', 'Test' => 'Testing']], $translations->toArray()['single']);
|
||||
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en.json',
|
||||
json_encode((object) ['Hello' => 'Hello', 'What\'s up' => 'What\'s up!'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_get_a_collection_of_group_names_for_a_given_language()
|
||||
{
|
||||
$groups = $this->translation->getGroupsFor('en');
|
||||
|
||||
$this->assertEquals($groups->toArray(), ['test']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_merge_a_language_with_the_base_language()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
|
||||
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
|
||||
|
||||
$this->assertEquals($translations->toArray(), [
|
||||
'group' => [
|
||||
'test' => [
|
||||
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
|
||||
'whats_up' => ['en' => "What's up!", 'es' => ''],
|
||||
],
|
||||
],
|
||||
'single' => [
|
||||
'single' => [
|
||||
'Hello' => [
|
||||
'en' => 'Hello',
|
||||
'es' => '',
|
||||
],
|
||||
"What's up" => [
|
||||
'en' => "What's up!",
|
||||
'es' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
unlink(__DIR__.'/fixtures/lang/es/test.php');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_vendor_namespaced_translations()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'translation_test::test', 'hello', 'Hola!');
|
||||
|
||||
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
|
||||
'group' => [
|
||||
'translation_test::test' => [
|
||||
'hello' => 'Hola!',
|
||||
],
|
||||
],
|
||||
'single' => [],
|
||||
]);
|
||||
|
||||
\File::deleteDirectory(__DIR__.'/fixtures/lang/vendor');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_a_nested_translation()
|
||||
{
|
||||
$this->translation->addGroupTranslation('en', 'test', 'test.nested', 'Nested!');
|
||||
|
||||
$this->assertEquals($this->translation->getGroupTranslationsFor('en')->toArray(), [
|
||||
'test' => [
|
||||
'hello' => 'Hello',
|
||||
'test.nested' => 'Nested!',
|
||||
'whats_up' => 'What\'s up!',
|
||||
],
|
||||
]);
|
||||
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en/test.php',
|
||||
"<?php\n\nreturn ".var_export(['hello' => 'Hello', 'whats_up' => 'What\'s up!'], true).';'.\PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_add_nested_vendor_namespaced_translations()
|
||||
{
|
||||
$this->translation->addGroupTranslation('es', 'translation_test::test', 'nested.hello', 'Hola!');
|
||||
|
||||
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
|
||||
'group' => [
|
||||
'translation_test::test' => [
|
||||
'nested.hello' => 'Hola!',
|
||||
],
|
||||
],
|
||||
'single' => [],
|
||||
]);
|
||||
|
||||
\File::deleteDirectory(__DIR__.'/fixtures/lang/vendor');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_merge_a_namespaced_language_with_the_base_language()
|
||||
{
|
||||
$this->translation->addGroupTranslation('en', 'translation_test::test', 'hello', 'Hello');
|
||||
$this->translation->addGroupTranslation('es', 'translation_test::test', 'hello', 'Hola!');
|
||||
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
|
||||
|
||||
$this->assertEquals($translations->toArray(), [
|
||||
'group' => [
|
||||
'test' => [
|
||||
'hello' => ['en' => 'Hello', 'es' => ''],
|
||||
'whats_up' => ['en' => "What's up!", 'es' => ''],
|
||||
],
|
||||
'translation_test::test' => [
|
||||
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
|
||||
],
|
||||
],
|
||||
'single' => [
|
||||
'single' => [
|
||||
'Hello' => [
|
||||
'en' => 'Hello',
|
||||
'es' => '',
|
||||
],
|
||||
"What's up" => [
|
||||
'en' => "What's up!",
|
||||
'es' => '',
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
\File::deleteDirectory(__DIR__.'/fixtures/lang/vendor');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_list_of_languages_can_be_viewed()
|
||||
{
|
||||
$this->get(config('translation.ui_url'))
|
||||
->assertSee('en');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_language_creation_page_can_be_viewed()
|
||||
{
|
||||
$this->get(config('translation.ui_url').'/create')
|
||||
->assertSee('Add a new language');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_language_can_be_added()
|
||||
{
|
||||
$this->post(config('translation.ui_url'), ['locale' => 'de'])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertTrue(file_exists(__DIR__.'/fixtures/lang/de.json'));
|
||||
$this->assertTrue(file_exists(__DIR__.'/fixtures/lang/de'));
|
||||
|
||||
rmdir(__DIR__.'/fixtures/lang/de');
|
||||
unlink(__DIR__.'/fixtures/lang/de.json');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_list_of_translations_can_be_viewed()
|
||||
{
|
||||
$this->get(config('translation.ui_url').'/en/translations')
|
||||
->assertSee('hello')
|
||||
->assertSee('whats_up');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_translation_creation_page_can_be_viewed()
|
||||
{
|
||||
$this->get(config('translation.ui_url').'/'.config('app.locale').'/translations/create')
|
||||
->assertSee('Add a translation');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_new_translation_can_be_added()
|
||||
{
|
||||
$this->post(config('translation.ui_url').'/en/translations', ['key' => 'joe', 'value' => 'is cool'])
|
||||
->assertRedirect();
|
||||
$translations = $this->translation->getSingleTranslationsFor('en');
|
||||
|
||||
$this->assertEquals(['Hello' => 'Hello', 'What\'s up' => 'What\'s up!', 'joe' => 'is cool'], $translations->toArray()['single']);
|
||||
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en.json',
|
||||
json_encode((object) ['Hello' => 'Hello', 'What\'s up' => 'What\'s up!'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_translation_can_be_updated()
|
||||
{
|
||||
$this->post(config('translation.ui_url').'/en', ['group' => 'test', 'key' => 'hello', 'value' => 'Hello there!'])
|
||||
->assertStatus(200);
|
||||
|
||||
$translations = $this->translation->getGroupTranslationsFor('en');
|
||||
|
||||
$this->assertEquals(['hello' => 'Hello there!', 'whats_up' => 'What\'s up!'], $translations->toArray()['test']);
|
||||
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en/test.php',
|
||||
"<?php\n\nreturn ".var_export(['hello' => 'Hello', 'whats_up' => 'What\'s up!'], true).';'.\PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function adding_a_translation_fires_an_event_with_the_expected_data()
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
$data = ['key' => 'joe', 'value' => 'is cool'];
|
||||
$this->post(config('translation.ui_url').'/en/translations', $data);
|
||||
|
||||
Event::assertDispatched(TranslationAdded::class, function ($event) use ($data) {
|
||||
return $event->language === 'en' &&
|
||||
$event->group === 'single' &&
|
||||
$event->value === $data['value'] &&
|
||||
$event->key === $data['key'];
|
||||
});
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en.json',
|
||||
json_encode((object) ['Hello' => 'Hello', 'What\'s up' => 'What\'s up!'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function updating_a_translation_fires_an_event_with_the_expected_data()
|
||||
{
|
||||
Event::fake();
|
||||
|
||||
$data = ['group' => 'test', 'key' => 'hello', 'value' => 'Hello there!'];
|
||||
$this->post(config('translation.ui_url').'/en/translations', $data);
|
||||
|
||||
Event::assertDispatched(TranslationAdded::class, function ($event) use ($data) {
|
||||
return $event->language === 'en' &&
|
||||
$event->group === $data['group'] &&
|
||||
$event->value === $data['value'] &&
|
||||
$event->key === $data['key'];
|
||||
});
|
||||
file_put_contents(
|
||||
app()['path.lang'].'/en/test.php',
|
||||
"<?php\n\nreturn ".var_export(['hello' => 'Hello', 'whats_up' => 'What\'s up!'], true).';'.\PHP_EOL
|
||||
);
|
||||
}
|
||||
}
|
||||
25
support/laravel-translation/tests/PackageIsLoadedTest.php
Normal file
25
support/laravel-translation/tests/PackageIsLoadedTest.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Tests;
|
||||
|
||||
use JoeDixon\Translation\TranslationBindingsServiceProvider;
|
||||
use JoeDixon\Translation\TranslationServiceProvider;
|
||||
use Orchestra\Testbench\TestCase;
|
||||
|
||||
class PackageIsLoadedTest extends TestCase
|
||||
{
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
TranslationServiceProvider::class,
|
||||
TranslationBindingsServiceProvider::class,
|
||||
];
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_translation_pacakage_is_loaded()
|
||||
{
|
||||
$this->assertArrayHasKey(TranslationServiceProvider::class, app()->getLoadedProviders());
|
||||
$this->assertArrayHasKey(TranslationBindingsServiceProvider::class, app()->getLoadedProviders());
|
||||
}
|
||||
}
|
||||
37
support/laravel-translation/tests/ScannerTest.php
Normal file
37
support/laravel-translation/tests/ScannerTest.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace JoeDixon\Translation\Tests;
|
||||
|
||||
use JoeDixon\Translation\Scanner;
|
||||
use JoeDixon\Translation\TranslationBindingsServiceProvider;
|
||||
use JoeDixon\Translation\TranslationServiceProvider;
|
||||
use Orchestra\Testbench\TestCase;
|
||||
|
||||
class ScannerTest extends TestCase
|
||||
{
|
||||
private $scanner;
|
||||
|
||||
protected function getPackageProviders($app)
|
||||
{
|
||||
return [
|
||||
TranslationServiceProvider::class,
|
||||
TranslationBindingsServiceProvider::class,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getEnvironmentSetUp($app)
|
||||
{
|
||||
$app['config']->set('translation.scan_paths', __DIR__.'/fixtures/scan-tests');
|
||||
$app['config']->set('translation.translation_methods', ['__', 'trans', 'trans_choice', '@lang', 'Lang::get']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_finds_all_translations()
|
||||
{
|
||||
$this->scanner = app()->make(Scanner::class);
|
||||
$matches = $this->scanner->findTranslations();
|
||||
|
||||
$this->assertEquals($matches, ['single' => ['single' => ['This will go in the JSON array' => '', 'This will also go in the JSON array' => '', 'trans' => '']], 'group' => ['lang' => ['first_match' => ''], 'lang_get' => ['first' => '', 'second' => ''], 'trans' => ['first_match' => '', 'third_match' => ''], 'trans_choice' => ['with_params' => '']]]);
|
||||
$this->assertCount(2, $matches);
|
||||
}
|
||||
}
|
||||
4
support/laravel-translation/tests/fixtures/lang/en.json
vendored
Normal file
4
support/laravel-translation/tests/fixtures/lang/en.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"Hello": "Hello",
|
||||
"What's up": "What's up!"
|
||||
}
|
||||
6
support/laravel-translation/tests/fixtures/lang/en/test.php
vendored
Normal file
6
support/laravel-translation/tests/fixtures/lang/en/test.php
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return array (
|
||||
'hello' => 'Hello',
|
||||
'whats_up' => 'What\'s up!',
|
||||
);
|
||||
0
support/laravel-translation/tests/fixtures/lang/es/.gitignore
vendored
Normal file
0
support/laravel-translation/tests/fixtures/lang/es/.gitignore
vendored
Normal file
6
support/laravel-translation/tests/fixtures/scan-tests/__.txt
vendored
Normal file
6
support/laravel-translation/tests/fixtures/scan-tests/__.txt
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
__('This will go in the JSON array')
|
||||
|
||||
__(
|
||||
'This will also go in the JSON array'
|
||||
)
|
||||
2
support/laravel-translation/tests/fixtures/scan-tests/at_lang.txt
vendored
Normal file
2
support/laravel-translation/tests/fixtures/scan-tests/at_lang.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
@lang('lang.first_match')
|
||||
3
support/laravel-translation/tests/fixtures/scan-tests/lang_get.txt
vendored
Normal file
3
support/laravel-translation/tests/fixtures/scan-tests/lang_get.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
Lang::get('lang_get.first')
|
||||
Lang::get('lang_get.second');
|
||||
4
support/laravel-translation/tests/fixtures/scan-tests/trans.txt
vendored
Normal file
4
support/laravel-translation/tests/fixtures/scan-tests/trans.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
trans('trans.first_match');
|
||||
trans('trans');
|
||||
trans('trans.third_match');
|
||||
2
support/laravel-translation/tests/fixtures/scan-tests/trans_choice.txt
vendored
Normal file
2
support/laravel-translation/tests/fixtures/scan-tests/trans_choice.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
trans_choice('trans_choice.with_params', ['parameters' => 'Go here'])
|
||||
BIN
support/laravel-translation/translation.png
Normal file
BIN
support/laravel-translation/translation.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 402 KiB |
58
support/laravel-translation/webpack.mix.js
Normal file
58
support/laravel-translation/webpack.mix.js
Normal file
@@ -0,0 +1,58 @@
|
||||
let mix = require('laravel-mix');
|
||||
var tailwindcss = require('tailwindcss');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mix Asset Management
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Mix provides a clean, fluent API for defining some Webpack build steps
|
||||
| for your Laravel application. By default, we are compiling the Sass
|
||||
| file for your application, as well as bundling up your JS files.
|
||||
|
|
||||
*/
|
||||
|
||||
mix.setPublicPath('public/assets');
|
||||
// mix.setPublicPath('../../../public/vendor/translation');
|
||||
|
||||
mix.postCss('resources/assets/css/main.css', 'css', [
|
||||
tailwindcss('./tailwind.js'),
|
||||
]).js('resources/assets/js/app.js', 'js')
|
||||
|
||||
// Full API
|
||||
// mix.js(src, output);
|
||||
// mix.react(src, output); <-- Identical to mix.js(), but registers React Babel compilation.
|
||||
// mix.preact(src, output); <-- Identical to mix.js(), but registers Preact compilation.
|
||||
// mix.coffee(src, output); <-- Identical to mix.js(), but registers CoffeeScript compilation.
|
||||
// mix.ts(src, output); <-- TypeScript support. Requires tsconfig.json to exist in the same folder as webpack.mix.js
|
||||
// mix.extract(vendorLibs);
|
||||
// mix.sass(src, output);
|
||||
// mix.standaloneSass('src', output); <-- Faster, but isolated from Webpack.
|
||||
// mix.fastSass('src', output); <-- Alias for mix.standaloneSass().
|
||||
// mix.less(src, output);
|
||||
// mix.stylus(src, output);
|
||||
// mix.postCss(src, output, [require('postcss-some-plugin')()]);
|
||||
// mix.browserSync('my-site.test');
|
||||
// mix.combine(files, destination);
|
||||
// mix.babel(files, destination); <-- Identical to mix.combine(), but also includes Babel compilation.
|
||||
// mix.copy(from, to);
|
||||
// mix.copyDirectory(fromDir, toDir);
|
||||
// mix.minify(file);
|
||||
// mix.sourceMaps(); // Enable sourcemaps
|
||||
// mix.version(); // Enable versioning.
|
||||
// mix.disableNotifications();
|
||||
// mix.setPublicPath('path/to/public');
|
||||
// mix.setResourceRoot('prefix/for/resource/locators');
|
||||
// mix.autoload({}); <-- Will be passed to Webpack's ProvidePlugin.
|
||||
// mix.webpackConfig({}); <-- Override webpack.config.js, without editing the file directly.
|
||||
// mix.babelConfig({}); <-- Merge extra Babel configuration (plugins, etc.) with Mix's default.
|
||||
// mix.then(function () {}) <-- Will be triggered each time Webpack finishes building.
|
||||
// mix.extend(name, handler) <-- Extend Mix's API with your own components.
|
||||
// mix.options({
|
||||
// extractVueStyles: false, // Extract .vue component styling to file, rather than inline.
|
||||
// globalVueStyles: file, // Variables file to be imported in every component.
|
||||
// processCssUrls: true, // Process/optimize relative stylesheet url()'s. Set to false, if you don't want them touched.
|
||||
// purifyCss: false, // Remove unused CSS selectors.
|
||||
// uglify: {}, // Uglify-specific options. https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
|
||||
// postCss: [] // Post-CSS options: https://github.com/postcss/postcss/blob/master/docs/plugins.md
|
||||
// });
|
||||
Reference in New Issue
Block a user