";
+ return div.innerHTML.indexOf('
') > 0
+}
+
+// #3663: IE encodes newlines inside attribute values while other browsers don't
+var shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false;
+// #6828: chrome encodes content in a[href]
+var shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false;
+
+/* */
+
+var idToTemplate = cached(function (id) {
+ var el = query(id);
+ return el && el.innerHTML
+});
+
+var mount = Vue.prototype.$mount;
+Vue.prototype.$mount = function (
+ el,
+ hydrating
+) {
+ el = el && query(el);
+
+ /* istanbul ignore if */
+ if (el === document.body || el === document.documentElement) {
+ true && warn(
+ "Do not mount Vue to or - mount to normal elements instead."
+ );
+ return this
+ }
+
+ var options = this.$options;
+ // resolve template/el and convert to render function
+ if (!options.render) {
+ var template = options.template;
+ if (template) {
+ if (typeof template === 'string') {
+ if (template.charAt(0) === '#') {
+ template = idToTemplate(template);
+ /* istanbul ignore if */
+ if ( true && !template) {
+ warn(
+ ("Template element not found or is empty: " + (options.template)),
+ this
+ );
+ }
+ }
+ } else if (template.nodeType) {
+ template = template.innerHTML;
+ } else {
+ if (true) {
+ warn('invalid template option:' + template, this);
+ }
+ return this
+ }
+ } else if (el) {
+ template = getOuterHTML(el);
+ }
+ if (template) {
+ /* istanbul ignore if */
+ if ( true && config.performance && mark) {
+ mark('compile');
+ }
+
+ var ref = compileToFunctions(template, {
+ outputSourceRange: "development" !== 'production',
+ shouldDecodeNewlines: shouldDecodeNewlines,
+ shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
+ delimiters: options.delimiters,
+ comments: options.comments
+ }, this);
+ var render = ref.render;
+ var staticRenderFns = ref.staticRenderFns;
+ options.render = render;
+ options.staticRenderFns = staticRenderFns;
+
+ /* istanbul ignore if */
+ if ( true && config.performance && mark) {
+ mark('compile end');
+ measure(("vue " + (this._name) + " compile"), 'compile', 'compile end');
+ }
+ }
+ }
+ return mount.call(this, el, hydrating)
+};
+
+/**
+ * Get outerHTML of elements, taking care
+ * of SVG elements in IE as well.
+ */
+function getOuterHTML (el) {
+ if (el.outerHTML) {
+ return el.outerHTML
+ } else {
+ var container = document.createElement('div');
+ container.appendChild(el.cloneNode(true));
+ return container.innerHTML
+ }
+}
+
+Vue.compile = compileToFunctions;
+
+/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Vue);
+
+
+/***/ })
+
+/******/ });
+/************************************************************************/
+/******/ // The module cache
+/******/ var __webpack_module_cache__ = {};
+/******/
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+/******/ // Check if module is in cache
+/******/ var cachedModule = __webpack_module_cache__[moduleId];
+/******/ if (cachedModule !== undefined) {
+/******/ return cachedModule.exports;
+/******/ }
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = __webpack_module_cache__[moduleId] = {
+/******/ // no module.id needed
+/******/ // no module.loaded needed
+/******/ exports: {}
+/******/ };
+/******/
+/******/ // Execute the module function
+/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+/******/
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = __webpack_modules__;
+/******/
+/************************************************************************/
+/******/ /* webpack/runtime/chunk loaded */
+/******/ (() => {
+/******/ var deferred = [];
+/******/ __webpack_require__.O = (result, chunkIds, fn, priority) => {
+/******/ if(chunkIds) {
+/******/ priority = priority || 0;
+/******/ for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
+/******/ deferred[i] = [chunkIds, fn, priority];
+/******/ return;
+/******/ }
+/******/ var notFulfilled = Infinity;
+/******/ for (var i = 0; i < deferred.length; i++) {
+/******/ var [chunkIds, fn, priority] = deferred[i];
+/******/ var fulfilled = true;
+/******/ for (var j = 0; j < chunkIds.length; j++) {
+/******/ if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
+/******/ chunkIds.splice(j--, 1);
+/******/ } else {
+/******/ fulfilled = false;
+/******/ if(priority < notFulfilled) notFulfilled = priority;
+/******/ }
+/******/ }
+/******/ if(fulfilled) {
+/******/ deferred.splice(i--, 1)
+/******/ var r = fn();
+/******/ if (r !== undefined) result = r;
+/******/ }
+/******/ }
+/******/ return result;
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/define property getters */
+/******/ (() => {
+/******/ // define getter functions for harmony exports
+/******/ __webpack_require__.d = (exports, definition) => {
+/******/ for(var key in definition) {
+/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
+/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
+/******/ }
+/******/ }
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/global */
+/******/ (() => {
+/******/ __webpack_require__.g = (function() {
+/******/ if (typeof globalThis === 'object') return globalThis;
+/******/ try {
+/******/ return this || new Function('return this')();
+/******/ } catch (e) {
+/******/ if (typeof window === 'object') return window;
+/******/ }
+/******/ })();
+/******/ })();
+/******/
+/******/ /* webpack/runtime/hasOwnProperty shorthand */
+/******/ (() => {
+/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
+/******/ })();
+/******/
+/******/ /* webpack/runtime/make namespace object */
+/******/ (() => {
+/******/ // define __esModule on exports
+/******/ __webpack_require__.r = (exports) => {
+/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
+/******/ }
+/******/ Object.defineProperty(exports, '__esModule', { value: true });
+/******/ };
+/******/ })();
+/******/
+/******/ /* webpack/runtime/jsonp chunk loading */
+/******/ (() => {
+/******/ // no baseURI
+/******/
+/******/ // object to store loaded and loading chunks
+/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
+/******/ // [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
+/******/ var installedChunks = {
+/******/ "/js/app": 0,
+/******/ "css/main": 0
+/******/ };
+/******/
+/******/ // no chunk on demand loading
+/******/
+/******/ // no prefetching
+/******/
+/******/ // no preloaded
+/******/
+/******/ // no HMR
+/******/
+/******/ // no HMR manifest
+/******/
+/******/ __webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
+/******/
+/******/ // install a JSONP callback for chunk loading
+/******/ var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
+/******/ var [chunkIds, moreModules, runtime] = data;
+/******/ // add "moreModules" to the modules object,
+/******/ // then flag all "chunkIds" as loaded and fire callback
+/******/ var moduleId, chunkId, i = 0;
+/******/ if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
+/******/ for(moduleId in moreModules) {
+/******/ if(__webpack_require__.o(moreModules, moduleId)) {
+/******/ __webpack_require__.m[moduleId] = moreModules[moduleId];
+/******/ }
+/******/ }
+/******/ if(runtime) var result = runtime(__webpack_require__);
+/******/ }
+/******/ if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
+/******/ for(;i < chunkIds.length; i++) {
+/******/ chunkId = chunkIds[i];
+/******/ if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
+/******/ installedChunks[chunkId][0]();
+/******/ }
+/******/ installedChunks[chunkId] = 0;
+/******/ }
+/******/ return __webpack_require__.O(result);
+/******/ }
+/******/
+/******/ var chunkLoadingGlobal = self["webpackChunk"] = self["webpackChunk"] || [];
+/******/ chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
+/******/ chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
+/******/ })();
+/******/
+/************************************************************************/
+/******/
+/******/ // startup
+/******/ // Load entry module and return exports
+/******/ // This entry module depends on other loaded chunks and execution need to be delayed
+/******/ __webpack_require__.O(undefined, ["css/main"], () => (__webpack_require__("./resources/assets/js/app.js")))
+/******/ var __webpack_exports__ = __webpack_require__.O(undefined, ["css/main"], () => (__webpack_require__("./resources/assets/css/main.css")))
+/******/ __webpack_exports__ = __webpack_require__.O(__webpack_exports__);
+/******/
+/******/ })()
+;
\ No newline at end of file
diff --git a/resources/assets/css/main.css b/resources/assets/css/main.css
index 05cb44f..7d14a35 100644
--- a/resources/assets/css/main.css
+++ b/resources/assets/css/main.css
@@ -1,68 +1,10 @@
-/**
- * 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 base;
@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
+ @apply bg-gray-100 text-gray-900
}
ul {
@@ -75,7 +17,7 @@ li {
}
a {
- @apply text-blue;
+ @apply text-blue-500;
}
nav.header {
@@ -84,7 +26,7 @@ nav.header {
}
nav a {
- @apply .opacity-75 text-white no-underline flex items-center
+ @apply opacity-75 text-white no-underline flex items-center
}
nav a.active {
@@ -96,7 +38,7 @@ nav a:hover {
}
.panel {
- @apply bg-white rounded m-6 shadow text-grey-dark
+ @apply bg-white rounded m-6 shadow text-gray-700
}
.panel-header {
@@ -104,7 +46,7 @@ nav a:hover {
}
.panel-footer {
- @apply border-t bg-grey-lighter p-4
+ @apply border-t bg-gray-100 p-4
}
.panel-body table {
@@ -117,7 +59,7 @@ nav a:hover {
}
.panel-body th {
- @apply text-grey-darker
+ @apply text-gray-800
}
.panel-body td {
@@ -129,16 +71,16 @@ nav a:hover {
}
.panel-body thead tr {
- @apply bg-grey-lighter
+ @apply bg-gray-100
}
.panel-body tbody tr:nth-child(even) {
- @apply bg-grey-lighter
+ @apply bg-gray-100
}
.panel-body tbody tr:hover,
.panel-body tbody tr:nth-child(even):hover {
- @apply bg-blue-lightest
+ @apply bg-blue-100
}
.panel-body tbody tr:last-child {
@@ -147,11 +89,11 @@ nav a:hover {
.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
+ @apply border-none resize-none bg-transparent text-gray-800 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
+ @apply w-full rounded h-32 p-2 border border-solid border-gray-500
}
.panel-body td textarea:focus {
@@ -159,19 +101,19 @@ nav a:hover {
}
.button {
- @apply bg-transparent text-grey-darker py-2 px-4 border border-grey rounded text-sm font-bold no-underline
+ @apply bg-transparent text-gray-700 py-2 px-4 border border-gray-500 rounded text-sm font-bold no-underline
}
.button:hover {
- @apply text-blue
+ @apply text-blue-500
}
.button-blue {
- @apply bg-blue text-white border-blue
+ @apply bg-blue-500 text-white border-blue-500
}
.button-blue:hover {
- @apply text-white bg-blue-dark
+ @apply text-white bg-blue-700
}
.input-group {
@@ -179,11 +121,11 @@ nav a:hover {
}
.input-group label {
- @apply block uppercase tracking-wide text-grey-darker text-xs font-bold mb-2
+ @apply block uppercase tracking-wide text-gray-700 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
+ @apply appearance-none block w-full bg-gray-100 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight
}
.input-group:last-child {
@@ -191,11 +133,11 @@ nav a:hover {
}
.input-group input.error {
- @apply border-red
+ @apply border-red-500
}
.input-group .error-text {
- @apply text-red text-xs italic
+ @apply text-red-500 text-xs italic
}
.select-group {
@@ -207,15 +149,15 @@ nav a:hover {
}
.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
+ @apply text-base block appearance-none bg-white border text-gray-700 uppercase py-2 px-4 pr-8 rounded leading-tight max-w-xs font-thin
}
.select-group select:focus {
- @apply outline-none border-grey
+ @apply outline-none border-gray-500
}
.select-group .caret {
- @apply pointer-events-none absolute pin-y pin-r flex items-center px-2 text-grey-darker
+ @apply pointer-events-none absolute flex items-center px-2 text-gray-700
}
.select-group .caret svg {
@@ -228,11 +170,11 @@ nav a:hover {
.search-input {
background: url('data:image/svg+xml;charset=utf8,
');
- @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
+ @apply bg-gray-100 rounded pl-10 py-2 pr-4 bg-no-repeat bg-contain transition border text-gray-700 font-thin w-full
}
.search-input:focus {
- @apply outline-none bg-white border border-grey-light
+ @apply outline-none bg-white border border-gray-200
}
.transition {
@@ -246,7 +188,7 @@ nav a:hover {
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
+ @apply font-thin pl-0 block absolute w-full bg-gray-100 border border-t-0 rounded rounded-t-none overflow-x-hidden overflow-y-scroll
}
ul.search-results li {
diff --git a/resources/helpers.php b/resources/helpers.php
index 14847f4..16d7a8d 100644
--- a/resources/helpers.php
+++ b/resources/helpers.php
@@ -51,6 +51,7 @@ function strs_contain($haystacks, $needle)
*/
function array_diff_assoc_recursive($arrayOne, $arrayTwo)
{
+ // dd($arrayOne, $arrayTwo);
$difference = [];
foreach ($arrayOne as $key => $value) {
if (is_array($value) || $value instanceof Illuminate\Support\Collection) {
diff --git a/src/Console/Commands/AddLanguageCommand.php b/src/Console/Commands/AddLanguage.php
similarity index 68%
rename from src/Console/Commands/AddLanguageCommand.php
rename to src/Console/Commands/AddLanguage.php
index 9e3aec4..75b3dbf 100644
--- a/src/Console/Commands/AddLanguageCommand.php
+++ b/src/Console/Commands/AddLanguage.php
@@ -2,28 +2,13 @@
namespace JoeDixon\Translation\Console\Commands;
-class AddLanguageCommand extends BaseCommand
+class AddLanguage extends Command
{
- /**
- * 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()
+ public function handle(): void
{
// ask the user for the language they wish to add
$language = $this->ask(__('translation::translation.prompt_language'));
diff --git a/src/Console/Commands/AddTranslationKeyCommand.php b/src/Console/Commands/AddTranslationKey.php
similarity index 59%
rename from src/Console/Commands/AddTranslationKeyCommand.php
rename to src/Console/Commands/AddTranslationKey.php
index 1bcdc03..2f7a87e 100644
--- a/src/Console/Commands/AddTranslationKeyCommand.php
+++ b/src/Console/Commands/AddTranslationKey.php
@@ -2,28 +2,13 @@
namespace JoeDixon\Translation\Console\Commands;
-class AddTranslationKeyCommand extends BaseCommand
+class AddTranslationKey extends Command
{
- /**
- * 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()
+ public function handle(): void
{
$language = $this->ask(__('translation::translation.prompt_language_for_key'));
@@ -42,23 +27,33 @@ public function handle()
// exception is thrown
if ($type === 'single') {
try {
- $this->translation->addSingleTranslation($language, 'single', $key, $value);
+ $this->translation->addStringKeyTranslation($language, 'single', $key, $value);
- return $this->info(__('translation::translation.language_key_added'));
+ $this->info(__('translation::translation.language_key_added'));
+
+ return;
} catch (\Exception $e) {
- return $this->error($e->getMessage());
+ $this->error($e->getMessage());
+
+ return;
}
} elseif ($type === 'group') {
try {
$file = str_replace('.php', '', $file);
- $this->translation->addGroupTranslation($language, $file, $key, $value);
+ $this->translation->addShortKeyTranslation($language, $file, $key, $value);
+
+ $this->info(__('translation::translation.language_key_added'));
- return $this->info(__('translation::translation.language_key_added'));
+ return;
} catch (\Exception $e) {
- return $this->error($e->getMessage());
+ $this->error($e->getMessage());
+
+ return;
}
} else {
- return $this->error(__('translation::translation.type_error'));
+ $this->error(__('translation::translation.type_error'));
+
+ return;
}
}
}
diff --git a/src/Console/Commands/BaseCommand.php b/src/Console/Commands/BaseCommand.php
deleted file mode 100644
index 667044f..0000000
--- a/src/Console/Commands/BaseCommand.php
+++ /dev/null
@@ -1,17 +0,0 @@
-translation = $translation;
- }
-}
diff --git a/src/Console/Commands/Command.php b/src/Console/Commands/Command.php
new file mode 100644
index 0000000..9bb6360
--- /dev/null
+++ b/src/Console/Commands/Command.php
@@ -0,0 +1,14 @@
+translation->allLanguages()->toArray();
diff --git a/src/Console/Commands/ListMissingTranslationKeys.php b/src/Console/Commands/ListMissingTranslationKeys.php
index c4b0c01..da9d346 100644
--- a/src/Console/Commands/ListMissingTranslationKeys.php
+++ b/src/Console/Commands/ListMissingTranslationKeys.php
@@ -2,47 +2,30 @@
namespace JoeDixon\Translation\Console\Commands;
-class ListMissingTranslationKeys extends BaseCommand
+class ListMissingTranslationKeys extends Command
{
- /**
- * 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()
+ public function handle(): void
{
- $missingTranslations = [];
$rows = [];
- foreach ($this->translation->allLanguages() as $language => $name) {
- $missingTranslations[$language] = $this->translation->findMissingTranslations($language);
- }
+ $missingTranslations = $this->translation->allLanguages()->mapWithKeys(
+ fn ($language) => [$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;
- }
- }
+ $isNotEmpty = $missingTranslations->first(function ($translations) {
+ return $translations->get('short')->isNotEmpty() || $translations->get('string')->isNotEmpty();
+ });
// if no missing translations, inform the user and move on with your day
- if ($empty) {
- return $this->info(__('translation::translation.no_missing_keys'));
+ if (! $isNotEmpty) {
+ $this->info(__('translation::translation.no_missing_keys'));
+
+ return;
}
// set some headers for the table of results
diff --git a/src/Console/Commands/SynchroniseMissingTranslationKeys.php b/src/Console/Commands/SynchroniseMissingTranslationKeys.php
index 597058e..c4e4511 100644
--- a/src/Console/Commands/SynchroniseMissingTranslationKeys.php
+++ b/src/Console/Commands/SynchroniseMissingTranslationKeys.php
@@ -2,39 +2,30 @@
namespace JoeDixon\Translation\Console\Commands;
-class SynchroniseMissingTranslationKeys extends BaseCommand
+class SynchroniseMissingTranslationKeys extends Command
{
- /**
- * 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()
+ public function handle(): void
{
- $language = $this->argument('language') ?: false;
+ $language = $this->argument('language') ?: null;
+
+ if (! (is_string($language) || is_null($language))) {
+ $this->error(__('translation::trnaslation.invalid_language'));
+
+ return;
+ }
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'));
+ $this->info(__('translation::translation.keys_synced'));
} catch (\Exception $e) {
- return $this->error($e->getMessage());
+ $this->error($e->getMessage());
}
}
}
diff --git a/src/Console/Commands/SynchroniseTranslations.php b/src/Console/Commands/SynchroniseTranslations.php
new file mode 100644
index 0000000..75f7207
--- /dev/null
+++ b/src/Console/Commands/SynchroniseTranslations.php
@@ -0,0 +1,182 @@
+translation->allLanguages()->keys()->toArray();
+
+ try {
+ $this->fromDriver = $this->loadDriverFromArgumentOrInput('from');
+ $this->toDriver = $this->loadDriverFromArgumentOrInput('to');
+ } catch (DriverNotFoundException $e) {
+ $this->error(__('translation::translation.invalid_driver'));
+
+ return;
+ }
+
+ try {
+ $language = $this->stringArgumentOrInputFromList(
+ 'language',
+ __('translation::translation.prompt_language_if_any'),
+ $languages + ['all']
+ );
+ } catch (Throwable) {
+ $this->error(__('translation::translation.invalid_language'));
+
+ return;
+ }
+
+ $this->line(__('translation::translation.syncing'));
+
+ // If a specific language is set.
+ if ($language !== 'all') {
+ $this->mergeTranslations($this->toDriver, $language, $this->fromDriver->allTranslationsFor($language));
+ } // Else process all languages.
+ else {
+ $this->mergeLanguages($this->toDriver, $this->fromDriver->allTranslations());
+ }
+
+ $this->info(__('translation::translation.synced'));
+ }
+
+ private function stringArgumentOrInputFromList(string $key, string $translation, array $allowed): string
+ {
+ try {
+ $value = $this->stringArgument($key);
+ if (! in_array($value, $allowed)) {
+ throw new UnexpectedValueException();
+ }
+ } catch (Throwable) {
+ $value = $this->anticipate($translation, $allowed);
+
+ if (! in_array($value, $allowed)) {
+ throw new UnexpectedValueException();
+ }
+ }
+
+ return $value;
+ }
+
+ private function loadDriverFromArgumentOrInput(string $which): Translation
+ {
+ try {
+ $driver = $this->stringArgumentOrInputFromList(
+ $which,
+ __('translation::translation.prompt_'.$which.'_driver'),
+ DriverType::values()
+ );
+ } catch (Throwable) {
+ throw new DriverNotFoundException();
+ }
+
+ // Create the driver.
+ return $this->createDriver($driver);
+ }
+
+ private function stringArgument(string $key): string
+ {
+ $value = $this->argument($key);
+
+ if (! is_string($value)) {
+ $type = gettype($value);
+ throw new UnexpectedValueException("Argument has to be string, $type provided.");
+ }
+
+ return $value;
+ }
+
+ private function createDriver(string $driver): Translation
+ {
+ if ($driver === 'file') {
+ return new File(new Filesystem, app('path.lang'), config('app.locale'), $this->scanner);
+ }
+
+ return new Database(config('app.locale'), $this->scanner);
+ }
+
+ /**
+ * @param Translation $driver
+ * @param Collection
$languages
+ * @return void
+ */
+ private function mergeLanguages(Translation $driver, Collection $languages): void
+ {
+ foreach ($languages as $language => $translations) {
+ $this->mergeTranslations($driver, $language, $translations);
+ }
+ }
+
+ private function mergeTranslations(Translation $driver, string $language, CombinedTranslations $translations): void
+ {
+ $this->mergeGroupTranslations($driver, $language, $translations->shortKeyTranslations);
+ $this->mergeSingleTranslations($driver, $language, $translations->stringKeyTranslations);
+ }
+
+ /**
+ * @param Translation $driver
+ * @param string $language
+ * @param Collection> $groups
+ * @return void
+ */
+ private function mergeGroupTranslations(Translation $driver, string $language, Collection $groups): void
+ {
+ foreach ($groups as $group => $translations) {
+ foreach ($translations as $key => $value) {
+ if (is_array($value)) {
+ continue;
+ }
+ $driver->addShortKeyTranslation($language, $group, $key, $value);
+ }
+ }
+ }
+
+ /**
+ * @param Translation $driver
+ * @param string $language
+ * @param Collection> $vendors
+ * @return void
+ */
+ private function mergeSingleTranslations(Translation $driver, string $language, Collection $vendors): void
+ {
+ foreach ($vendors as $vendor => $translations) {
+ foreach ($translations as $key => $value) {
+ if (is_array($value)) {
+ continue;
+ }
+ $driver->addStringKeyTranslation($language, $vendor, $key, $value);
+ }
+ }
+ }
+}
diff --git a/src/Console/Commands/SynchroniseTranslationsCommand.php b/src/Console/Commands/SynchroniseTranslationsCommand.php
deleted file mode 100644
index baf2b9e..0000000
--- a/src/Console/Commands/SynchroniseTranslationsCommand.php
+++ /dev/null
@@ -1,194 +0,0 @@
-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(__('translation::translation.prompt_from_driver'), $this->drivers);
-
- if (! in_array($this->fromDriver, $this->drivers)) {
- return $this->error(__('translation::translation.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(__('translation::translation.prompt_to_driver'), $this->drivers);
-
- if (! in_array($this->toDriver, $this->drivers)) {
- return $this->error(__('translation::translation.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(__('translation::translation.invalid_language'));
- }
- } // When the language will be entered manually or if the argument is invalid.
- else {
- $language = $this->anticipate(__('translation::translation.prompt_language_if_any'), $languages);
-
- if ($language && ! in_array($language, $languages)) {
- return $this->error(__('translation::translation.invalid_language'));
- }
- }
-
- $this->line(__('translation::translation.syncing'));
-
- // 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(__('translation::translation.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);
- }
- }
- }
-}
diff --git a/src/ContractDatabaseLoader.php b/src/ContractDatabaseLoader.php
index 67704cd..df46145 100644
--- a/src/ContractDatabaseLoader.php
+++ b/src/ContractDatabaseLoader.php
@@ -3,11 +3,12 @@
namespace JoeDixon\Translation;
use Illuminate\Contracts\Translation\Loader;
+use Illuminate\Support\Collection;
use JoeDixon\Translation\Drivers\Translation;
class ContractDatabaseLoader implements Loader
{
- private $translation;
+ private Translation $translation;
public function __construct(Translation $translation)
{
@@ -25,16 +26,16 @@ public function __construct(Translation $translation)
public function load($locale, $group, $namespace = null)
{
if ($group == '*' && $namespace == '*') {
- return $this->translation->getSingleTranslationsFor($locale)->get('single', collect())->toArray();
+ return $this->translation->allStringKeyTranslationsFor($locale)->get('single', new Collection())->toArray();
}
if (is_null($namespace) || $namespace == '*') {
- return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group) {
+ return $this->translation->allShortKeyTranslationsFor($locale)->filter(function ($value, $key) use ($group) {
return $key === $group;
})->first();
}
- return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group, $namespace) {
+ return $this->translation->allShortKeyTranslationsFor($locale)->filter(function ($value, $key) use ($group, $namespace) {
return $key === "{$namespace}::{$group}";
})->first();
}
diff --git a/src/Database/Factories/LanguageFactory.php b/src/Database/Factories/LanguageFactory.php
new file mode 100644
index 0000000..1f9961a
--- /dev/null
+++ b/src/Database/Factories/LanguageFactory.php
@@ -0,0 +1,24 @@
+ fake()->word,
+ 'name' => fake()->word,
+ ];
+ }
+}
diff --git a/src/Database/Factories/TranslationFactory.php b/src/Database/Factories/TranslationFactory.php
new file mode 100644
index 0000000..f98acb5
--- /dev/null
+++ b/src/Database/Factories/TranslationFactory.php
@@ -0,0 +1,45 @@
+ Language::factory(),
+ 'group' => fake()->word,
+ 'key' => fake()->word,
+ 'value' => fake()->sentence,
+ ];
+ }
+
+ public function shortKey(): static
+ {
+ return $this->state(function () {
+ return [
+ 'group' => fake()->word,
+ ];
+ });
+ }
+
+ public function stringKey(): static
+ {
+ return $this->state(function () {
+ return [
+ 'group' => 'string',
+ ];
+ });
+ }
+}
diff --git a/src/Drivers/CombinedTranslations.php b/src/Drivers/CombinedTranslations.php
new file mode 100644
index 0000000..f813a63
--- /dev/null
+++ b/src/Drivers/CombinedTranslations.php
@@ -0,0 +1,67 @@
+> $stringKeyTranslations
+ * @param Collection> $shortKeyTranslations
+ * @return void
+ */
+ public function __construct(
+ public Collection $stringKeyTranslations,
+ public Collection $shortKeyTranslations,
+ ) {
+ }
+
+ public function toArray(): array
+ {
+ return [
+ 'string' => $this->stringKeyTranslations,
+ 'short' => $this->shortKeyTranslations,
+ ];
+ }
+
+ public function map(Closure $callback): self
+ {
+ $this->stringKeyTranslations = $this->stringKeyTranslations->map($callback);
+ $this->shortKeyTranslations = $this->shortKeyTranslations->map($callback);
+
+ return $this;
+ }
+
+ public static function make(?Collection $stringKeyTranslations = null, ?Collection $shortKeyTranslations = null): self
+ {
+ return new static(
+ $stringKeyTranslations ?? new Collection(),
+ $shortKeyTranslations ?? new Collection(),
+ );
+ }
+
+ public function emptyValues()
+ {
+ $this->stringKeyTranslations = $this->emptyCollectionValues($this->stringKeyTranslations);
+ $this->shortKeyTranslations = $this->emptyCollectionValues($this->shortKeyTranslations);
+
+ return $this;
+ }
+
+ public function emptyCollectionValues(Collection $collection): Collection
+ {
+ return $collection->map(function ($item, $index) {
+ if ($item instanceof Collection) {
+ return $this->emptyCollectionValues($item);
+ }
+
+ if (is_array($item)) {
+ return $this->emptyCollectionValues(new Collection($item))->toArray();
+ }
+
+ return '';
+ });
+ }
+}
diff --git a/src/Drivers/Database.php b/src/Drivers/Database.php
deleted file mode 100644
index c5c2486..0000000
--- a/src/Drivers/Database.php
+++ /dev/null
@@ -1,245 +0,0 @@
-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)
- {
- $translations = $this->getLanguage($language)
- ->translations()
- ->whereNotNull('group')
- ->where('group', 'not like', '%single')
- ->get()
- ->groupBy('group');
-
- return $translations->map(function ($translations) {
- return $translations->mapWithKeys(function ($translation) {
- return [$translation->key => $translation->value];
- });
- });
- }
-
- /**
- * 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)
- {
- return Language::where('language', $language)->first();
- }
-
- /**
- * 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;
- }
-}
diff --git a/src/Drivers/Database/Database.php b/src/Drivers/Database/Database.php
new file mode 100644
index 0000000..cd9b78f
--- /dev/null
+++ b/src/Drivers/Database/Database.php
@@ -0,0 +1,70 @@
+mapWithKeys(function ($language) {
+ return [$language->language => $language->name ?: $language->language];
+ });
+ }
+
+ /**
+ * Determine whether the given language exists.
+ */
+ public function languageExists(string $language): bool
+ {
+ return Language::where('language', $language)->count() > 0;
+ }
+
+ /**
+ * Add a new language.
+ */
+ public function addLanguage(string $language, ?string $name = null): void
+ {
+ if ($this->languageExists($language)) {
+ throw new LanguageExistsException(__('translation::errors.language_exists', ['language' => $language]));
+ }
+
+ Language::create([
+ 'language' => $language,
+ 'name' => $name,
+ ]);
+ }
+
+ /**
+ * Get a language from the database.
+ */
+ private function getLanguage(string $language): Language
+ {
+ return Language::where('language', $language)->firstOrFail();
+ }
+
+ private function getOrCreateLanguage(string $language): Language
+ {
+ if (! $this->languageExists($language)) {
+ $this->addLanguage($language);
+ }
+
+ return $this->getLanguage($language);
+ }
+}
diff --git a/src/Drivers/Database/InteractsWithShortKeys.php b/src/Drivers/Database/InteractsWithShortKeys.php
new file mode 100644
index 0000000..0111a07
--- /dev/null
+++ b/src/Drivers/Database/InteractsWithShortKeys.php
@@ -0,0 +1,75 @@
+getLanguage($language)
+ ->translations()
+ ->whereNotNull('group')
+ ->where('group', 'not like', '%string')
+ ->get()
+ ->groupBy('group');
+
+ return $translations->map(function ($translations) {
+ return $translations->mapWithKeys(function ($translation) {
+ return [$translation->key => $translation->value];
+ });
+ });
+ }
+
+ /**
+ * Get all the short key groups for a given language.
+ *
+ * @return Collection
+ */
+ public function allShortKeyGroupsFor(string $language): Collection
+ {
+ return Translation::getGroupsForLanguage($language)
+ ->map(
+ fn (Translation $translation): string => $translation->group
+ );
+ }
+
+ /**
+ * Add a short key translation.
+ */
+ public function addShortKeyTranslation(string $language, string $group, string $key, string $value = ''): void
+ {
+ if (! $this->languageExists($language)) {
+ $this->addLanguage($language);
+ }
+
+ $this->getLanguage($language)
+ ->translations()
+ ->updateOrCreate([
+ 'group' => $group,
+ 'key' => $key,
+ ], [
+ 'group' => $group,
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+
+ /**
+ * 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.
+ */
+ protected function hasLegacyGroups(Collection $groups): bool
+ {
+ return $groups->filter(function ($key) {
+ return $key === '';
+ })->count() > 0;
+ }
+}
diff --git a/src/Drivers/Database/InteractsWithStringKeys.php b/src/Drivers/Database/InteractsWithStringKeys.php
new file mode 100644
index 0000000..e1570db
--- /dev/null
+++ b/src/Drivers/Database/InteractsWithStringKeys.php
@@ -0,0 +1,53 @@
+getLanguage($language)
+ ->translations()
+ ->where('group', 'like', '%string')
+ ->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())) {
+ Translation::whereNull('group')->update(['group' => 'string']);
+ // if any legacy groups exist, rerun the method so we get the
+ // updated keys.
+ return $this->allStringKeyTranslationsFor($language);
+ }
+
+ return $translations->map(function ($translations) {
+ return $translations->mapWithKeys(function ($translation) {
+ return [$translation->key => $translation->value];
+ });
+ });
+ }
+
+ /**
+ * Add a single translation.
+ */
+ public function addStringKeyTranslation(string $language, string $vendor, string $key, string $value = ''): void
+ {
+ $this->getOrCreateLanguage($language)
+ ->translations()
+ ->updateOrCreate([
+ 'group' => $vendor,
+ 'key' => $key,
+ ], [
+ 'key' => $key,
+ 'value' => $value,
+ ]);
+ }
+}
diff --git a/src/Drivers/DriverInterface.php b/src/Drivers/DriverInterface.php
deleted file mode 100644
index a86c36c..0000000
--- a/src/Drivers/DriverInterface.php
+++ /dev/null
@@ -1,128 +0,0 @@
-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", "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", " $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));
- }
-}
diff --git a/src/Drivers/File/File.php b/src/Drivers/File/File.php
new file mode 100644
index 0000000..070d4ea
--- /dev/null
+++ b/src/Drivers/File/File.php
@@ -0,0 +1,106 @@
+disk->allFiles($this->languageFilesPath))
+ ->flatMap(function ($file) {
+ $path = Str::of($file->getPathname())
+ ->replace($this->languageFilesPath, '')
+ ->replaceFirst(DIRECTORY_SEPARATOR, '');
+
+ $key = Str::of($path)
+ ->replaceLast(".{$file->getExtension()}", '')
+ ->replace(DIRECTORY_SEPARATOR, '.', $path);
+
+ return [(string) $key => (string) $path];
+ });
+
+ if ($key) {
+ return $map->get($key, $default);
+ }
+
+ return $map;
+ }
+
+ /**
+ * Get all languages.
+ */
+ public function allLanguages(): Collection
+ {
+ // 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));
+
+ $directoryLanguages = $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';
+ });
+
+ $fileLangauges = Collection::make($this->disk->allFiles($this->languageFilesPath))
+ ->filter(fn ($file) => $file->getExtension() === 'json')
+ ->mapWithKeys(fn ($file) => [Str::replace(".{$file->getExtension()}", '', $file->getFilename()) => Str::replace(".{$file->getExtension()}", '', $file->getFilename())]);
+
+ return $directoryLanguages->merge($fileLangauges);
+ }
+
+ /**
+ * Determine whether the given language exists.
+ */
+ public function languageExists(string $language): bool
+ {
+ return $this->allLanguages()->contains($language);
+ }
+
+ /**
+ * Add a new language.
+ */
+ public function addLanguage(string $language, ?string $name = null): void
+ {
+ 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->saveStringKeyTranslations($language, collect(['string' => new Collection()]));
+ }
+ }
+
+ public function allTranslationsFromMap(string $key): Collection
+ {
+ if (! $file = $this->map($key)) {
+ return new Collection();
+ }
+
+ if (Str::endsWith($file, '.php')) {
+ return Collection::make($this->disk->getRequire("{$this->languageFilesPath}/{$file}"));
+ }
+
+ return Collection::make(json_decode($this->disk->get("{$this->languageFilesPath}/{$file}"), true));
+ }
+}
diff --git a/src/Drivers/File/InteractsWithShortKeys.php b/src/Drivers/File/InteractsWithShortKeys.php
new file mode 100644
index 0000000..c0bdf44
--- /dev/null
+++ b/src/Drivers/File/InteractsWithShortKeys.php
@@ -0,0 +1,149 @@
+allShortKeyFilesFor($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')}" => $this->disk->getRequire($group->getPathname())];
+ }
+
+ $translations = $this->disk->getRequire($group->getPathname());
+
+ return [$group->getBasename('.php') => is_array($translations) ? $translations : []];
+ });
+ }
+
+ /**
+ * Get all the short key groups for a given language.
+ */
+ public function allShortKeyGroupsFor(string $language): Collection
+ {
+ return $this->allShortKeyFilesFor($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');
+ });
+ }
+
+ /**
+ * Add a short key translation.
+ */
+ public function addShortKeyTranslation(string $language, string $group, string $key, string $value = ''): void
+ {
+ if (! $this->languageExists($language)) {
+ $this->addLanguage($language);
+ }
+
+ $translations = $this->allShortKeyTranslationsFor($language);
+
+ // does the group exist? If not, create it.
+ if (! $translations->keys()->contains($group)) {
+ $translations->put($group, new Collection());
+ }
+
+ $values = $translations->get($group);
+ $values[$key] = $value;
+ $translations->put($group, new Collection($values));
+
+ $this->saveShortKeyTranslations($language, $group, new Collection($translations->get($group)));
+ }
+
+ /**
+ * Add a new group of short key translations.
+ */
+ protected function addShortKeyGroup(string $language, string $group): void
+ {
+ $this->saveShortKeyTranslations($language, $group, new Collection);
+ }
+
+ /**
+ * Get all the short key files for a given language.
+ */
+ protected function allShortKeyFilesFor(string $language): Collection
+ {
+ $path = "{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}";
+
+ if (! $this->disk->exists($path)) {
+ return new Collection;
+ }
+
+ $groups = Collection::make($this->disk->allFiles($path));
+
+ // namespaced files reside in the vendor directory so we'll grab these
+ // the `getVendorGroupFileFor` method
+ return $groups->merge($this->allVendorShortKeyFilesFor($language))
+ ->filter(function ($file) {
+ return Str::endsWith($file->getBasename(), '.php');
+ });
+ }
+
+ /**
+ * Get all the vendor short key files for a given language.
+ */
+ protected function allVendorShortKeyFilesFor(string $language): Collection
+ {
+ if (! $this->disk->exists("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor')) {
+ return new Collection();
+ }
+
+ return Collection::make($this->disk->directories("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'))
+ ->flatMap(function ($directory) use ($language) {
+ $vendor = Str::afterLast($directory, DIRECTORY_SEPARATOR);
+ if (! $this->disk->exists("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}")) {
+ return [];
+ } else {
+ return $this->disk->allFiles("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}");
+ // array_push($vendorGroups, $this->disk->allFiles("{$this->languageFilesPath}".DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}"));
+ }
+ });
+ }
+
+ /**
+ * Save short key translations.
+ */
+ protected function saveShortKeyTranslations(string $language, string $group, Collection $translations): void
+ {
+ // here we check if it's a namespaced translation which need saving to a
+ // different path
+ if (Str::contains($group, '::')) {
+ $this->saveNamespacedShortKeyTranslations($language, $group, $translations);
+
+ return;
+ }
+
+ $this->disk->put("{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$language}".DIRECTORY_SEPARATOR."{$group}.php", "toArray(), true).';'.\PHP_EOL);
+ }
+
+ /**
+ * Save namespaced short key translations.
+ */
+ protected function saveNamespacedShortKeyTranslations(string $language, string $group, Collection $translations): void
+ {
+ [$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", "toArray(), true).';'.\PHP_EOL);
+ }
+}
diff --git a/src/Drivers/File/InteractsWithStringKeys.php b/src/Drivers/File/InteractsWithStringKeys.php
new file mode 100644
index 0000000..7e02efc
--- /dev/null
+++ b/src/Drivers/File/InteractsWithStringKeys.php
@@ -0,0 +1,67 @@
+disk->allFiles($this->languageFilesPath));
+
+ return $files->filter(
+ fn ($file) => str_ends_with($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}::string" => json_decode($this->disk->get($file), true)];
+ }
+
+ $translations = json_decode($this->disk->get($file), true);
+
+ return ['string' => $translations !== null ? $translations : []];
+ });
+ }
+
+ /**
+ * Add a string key translation.
+ */
+ public function addStringKeyTranslation(string $language, string $vendor, string $key, string $value = ''): void
+ {
+ if (! $this->languageExists($language)) {
+ $this->addLanguage($language);
+ }
+
+ $translations = $this->allStringKeyTranslationsFor($language);
+ $translations->get($vendor) ?: $translations->put($vendor, new Collection());
+ $translations->get($vendor)->put($key, $value);
+
+ $this->saveStringKeyTranslations($language, $translations);
+ }
+
+ /**
+ * Save string key translations.
+ */
+ private function saveStringKeyTranslations(string $language, Collection $translations): void
+ {
+ foreach ($translations as $group => $translation) {
+ $vendor = Str::before($group, '::string');
+ $languageFilePath = $vendor !== 'string' ? 'vendor'.DIRECTORY_SEPARATOR."{$vendor}".DIRECTORY_SEPARATOR."{$language}.json" : "{$language}.json";
+ $json = json_encode((object) $translations->get($group), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
+ if ($json === false) {
+ continue;
+ }
+
+ $this->disk->put(
+ "{$this->languageFilesPath}".DIRECTORY_SEPARATOR."{$languageFilePath}",
+ $json
+ );
+ }
+ }
+}
diff --git a/src/Drivers/Translation.php b/src/Drivers/Translation.php
index bd77305..94bd5d5 100644
--- a/src/Drivers/Translation.php
+++ b/src/Drivers/Translation.php
@@ -7,30 +7,98 @@
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use JoeDixon\Translation\Events\TranslationAdded;
+use JoeDixon\Translation\Scanner;
abstract class Translation
{
+ protected Scanner $scanner;
+
+ protected string $sourceLanguage;
+
+ abstract public function map(): Collection|string|null;
+
/**
- * Find all of the translations in the app without translation for a given language.
- *
- * @param string $language
- * @return array
+ * Get all languages.
+ */
+ abstract public function allLanguages(): Collection;
+
+ /**
+ * Determine whether the given language exists.
+ */
+ abstract public function languageExists(string $language): bool;
+
+ /**
+ * Add a new language.
+ */
+ abstract public function addLanguage(string $language, ?string $name = null): void;
+
+ /**
+ * Get all translations.
+ */
+ public function allTranslations(): Collection
+ {
+ return $this->allLanguages()->mapWithKeys(
+ fn ($name, $language) => [$language => $this->allTranslationsFor($language)]
+ );
+ }
+
+ /**
+ * Get all translations for a given language.
*/
- public function findMissingTranslations($language)
+ public function allTranslationsFor(string $language): CombinedTranslations
{
- return array_diff_assoc_recursive(
- $this->scanner->findTranslations(),
- $this->allTranslationsFor($language)
+ return new CombinedTranslations(
+ $this->allStringKeyTranslationsFor($language),
+ $this->allShortKeyTranslationsFor($language),
);
}
+ /**
+ * Get short key translations for a given language.
+ */
+ abstract public function allShortKeyTranslationsFor(string $language): Collection;
+
+ /**
+ * Get all the short key groups for a given language.
+ */
+ abstract public function allShortKeyGroupsFor(string $language): Collection;
+
+ /**
+ * Add a short key translation.
+ */
+ abstract public function addShortKeyTranslation(string $language, string $group, string $key, string $value = ''): void;
+
+ /**
+ * Get string key translations for a given language.
+ */
+ abstract public function allStringKeyTranslationsFor(string $language): Collection;
+
+ /**
+ * Add a string key translation.
+ */
+ abstract public function addStringKeyTranslation(string $language, string $vendor, string $key, string $value = ''): void;
+
+ /**
+ * Find all of the translations in the app without translation for a given language.
+ */
+ public function findMissingTranslations(string $language): Collection
+ {
+ return $this->scanner->findTranslations()
+ ->map(function ($groups, $type) use ($language) {
+ return $groups->map(function ($translations, $group) use ($language, $type) {
+ $all = $this->allTranslationsFor($language)->get($type)->get($group);
+
+ return $translations->diffKeys($all);
+ })->filter(function ($translations) {
+ return $translations->isNotEmpty();
+ });
+ });
+ }
+
/**
* Save all of the translations in the app without translation for a given language.
- *
- * @param string $language
- * @return void
*/
- public function saveMissingTranslations($language = false)
+ public function saveMissingTranslations(?string $language = null): void
{
$languages = $language ? [$language => $language] : $this->allLanguages();
@@ -41,9 +109,9 @@ public function saveMissingTranslations($language = false)
foreach ($groups as $group => $translations) {
foreach ($translations as $key => $value) {
if (Str::contains($group, 'single')) {
- $this->addSingleTranslation($language, $group, $key);
+ $this->addStringKeyTranslation($language, $group, $key);
} else {
- $this->addGroupTranslation($language, $group, $key);
+ $this->addShortKeyTranslation($language, $group, $key);
}
}
}
@@ -53,11 +121,8 @@ public function saveMissingTranslations($language = false)
/**
* Get all translations for a given language merged with the source language.
- *
- * @param string $language
- * @return Collection
*/
- public function getSourceLanguageTranslationsWith($language)
+ public function getSourceLanguageTranslationsWith(string $language): CombinedTranslations
{
$sourceTranslations = $this->allTranslationsFor($this->sourceLanguage);
$languageTranslations = $this->allTranslationsFor($language);
@@ -79,12 +144,8 @@ 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)
+ public function filterTranslationsFor(string $language, ?string $filter): Collection
{
$allTranslations = $this->getSourceLanguageTranslationsWith(($language));
if (! $filter) {
@@ -102,7 +163,7 @@ public function filterTranslationsFor($language, $filter)
});
}
- public function add(Request $request, $language, $isGroupTranslation)
+ public function add(Request $request, string $language, bool $isGroupTranslation): void
{
$namespace = $request->has('namespace') && $request->get('namespace') ? "{$request->get('namespace')}::" : '';
$group = $namespace.$request->get('group');
@@ -110,11 +171,23 @@ public function add(Request $request, $language, $isGroupTranslation)
$value = $request->get('value') ?: '';
if ($isGroupTranslation) {
- $this->addGroupTranslation($language, $group, $key, $value);
+ $this->addShortKeyTranslation($language, $group, $key, $value);
} else {
- $this->addSingleTranslation($language, 'single', $key, $value);
+ $this->addStringKeyTranslation($language, 'string', $key, $value);
}
- Event::dispatch(new TranslationAdded($language, $group ?: 'single', $key, $value));
+ Event::dispatch(new TranslationAdded($language, $group ?: 'string', $key, $value));
+ }
+
+ abstract public function allTranslationsFromMap(string $key): Collection;
+
+ public function normalizedKeys(): CombinedTranslations
+ {
+ return $this->allTranslations()->reduce(function ($carry, $item) {
+ $carry->shortKeyTranslations = $carry->shortKeyTranslations->mergeRecursive($item->shortKeyTranslations);
+ $carry->stringKeyTranslations = $carry->stringKeyTranslations->mergeRecursive($item->stringKeyTranslations);
+
+ return $carry;
+ }, CombinedTranslations::make())->emptyValues();
}
}
diff --git a/src/Events/TranslationAdded.php b/src/Events/TranslationAdded.php
index 801799a..44cc088 100644
--- a/src/Events/TranslationAdded.php
+++ b/src/Events/TranslationAdded.php
@@ -8,21 +8,11 @@ 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;
+ public function __construct(
+ public string $language,
+ public string $group,
+ public string $key,
+ public string $value,
+ ) {
}
}
diff --git a/src/Exceptions/DriverNotFoundException.php b/src/Exceptions/DriverNotFoundException.php
new file mode 100644
index 0000000..5e260a2
--- /dev/null
+++ b/src/Exceptions/DriverNotFoundException.php
@@ -0,0 +1,9 @@
+translation = $translation;
+ public function __construct(
+ private Translation $translation
+ ) {
}
- public function index(Request $request)
+ public function index(Request $request): View
{
$languages = $this->translation->allLanguages();
return view('translation::languages.index', compact('languages'));
}
- public function create()
+ public function create(): View
{
return view('translation::languages.create');
}
- public function store(LanguageRequest $request)
+ public function store(LanguageRequest $request): RedirectResponse
{
$this->translation->addLanguage($request->locale, $request->name);
diff --git a/src/Http/Controllers/LanguageTranslationController.php b/src/Http/Controllers/LanguageTranslationController.php
index e657dc8..eac4cee 100644
--- a/src/Http/Controllers/LanguageTranslationController.php
+++ b/src/Http/Controllers/LanguageTranslationController.php
@@ -2,6 +2,9 @@
namespace JoeDixon\Translation\Http\Controllers;
+use Illuminate\Contracts\View\View;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Collection;
@@ -11,23 +14,24 @@
class LanguageTranslationController extends Controller
{
- private $translation;
-
- public function __construct(Translation $translation)
- {
- $this->translation = $translation;
+ public function __construct(
+ private Translation $translation
+ ) {
}
- public function index(Request $request, $language)
+ public function index(Request $request, string $language): RedirectResponse|View
{
- // 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')]);
+ ->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');
+ $groups = $this->translation->allShortKeyGroupsFor(config('app.locale'))->merge(['single']);
$translations = $this->translation->filterTranslationsFor($language, $request->get('filter'));
if ($request->has('group') && $request->get('group')) {
@@ -46,12 +50,12 @@ public function index(Request $request, $language)
return view('translation::languages.translations.index', compact('language', 'languages', 'groups', 'translations'));
}
- public function create(Request $request, $language)
+ public function create(Request $request, string $language): View
{
return view('translation::languages.translations.create', compact('language'));
}
- public function store(TranslationRequest $request, $language)
+ public function store(TranslationRequest $request, string $language): RedirectResponse
{
$isGroupTranslation = $request->filled('group');
@@ -62,12 +66,12 @@ public function store(TranslationRequest $request, $language)
->with('success', __('translation::translation.translation_added'));
}
- public function update(Request $request, $language)
+ public function update(Request $request, string $language): JsonResponse
{
$isGroupTranslation = ! Str::contains($request->get('group'), 'single');
$this->translation->add($request, $language, $isGroupTranslation);
- return ['success' => true];
+ return new JsonResponse(['success' => true]);
}
}
diff --git a/src/InterfaceDatabaseLoader.php b/src/InterfaceDatabaseLoader.php
index 665515f..69607ba 100644
--- a/src/InterfaceDatabaseLoader.php
+++ b/src/InterfaceDatabaseLoader.php
@@ -2,16 +2,15 @@
namespace JoeDixon\Translation;
-use Illuminate\Translation\LoaderInterface;
+use Illuminate\Contracts\Translation\Loader;
+use Illuminate\Support\Collection;
use JoeDixon\Translation\Drivers\Translation;
-class InterfaceDatabaseLoader implements LoaderInterface
+class InterfaceDatabaseLoader implements Loader
{
- private $translation;
-
- public function __construct(Translation $translation)
- {
- $this->translation = $translation;
+ public function __construct(
+ private Translation $translation
+ ) {
}
/**
@@ -19,22 +18,22 @@ public function __construct(Translation $translation)
*
* @param string $locale
* @param string $group
- * @param string $namespace
+ * @param ?string $namespace
* @return array
*/
- public function load($locale, $group, $namespace = null)
+ public function load($locale, $group, $namespace = null): array
{
if ($group == '*' && $namespace == '*') {
- return $this->translation->getSingleTranslationsFor($locale)->get('single', collect())->toArray();
+ return $this->translation->allStringKeyTranslationsFor($locale)->get('single', new Collection())->toArray();
}
if (is_null($namespace) || $namespace == '*') {
- return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group) {
+ return $this->translation->allShortKeyTranslationsFor($locale)->filter(function ($value, $key) use ($group) {
return $key === $group;
})->first();
}
- return $this->translation->getGroupTranslationsFor($locale)->filter(function ($value, $key) use ($group, $namespace) {
+ return $this->translation->allShortKeyTranslationsFor($locale)->filter(function ($value, $key) use ($group, $namespace) {
return $key === "{$namespace}::{$group}";
})->first();
}
diff --git a/src/Language.php b/src/Language.php
index 47fcc82..1c1ee9b 100644
--- a/src/Language.php
+++ b/src/Language.php
@@ -2,10 +2,15 @@
namespace JoeDixon\Translation;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\HasMany;
+use JoeDixon\Translation\Database\Factories\LanguageFactory;
class Language extends Model
{
+ use HasFactory;
+
protected $guarded = [];
public function __construct(array $attributes = [])
@@ -15,8 +20,13 @@ public function __construct(array $attributes = [])
$this->table = config('translation.database.languages_table');
}
- public function translations()
+ public function translations(): HasMany
{
return $this->hasMany(Translation::class);
}
+
+ protected static function newFactory(): LanguageFactory
+ {
+ return LanguageFactory::new();
+ }
}
diff --git a/src/Scanner.php b/src/Scanner.php
index 846056c..325e230 100644
--- a/src/Scanner.php
+++ b/src/Scanner.php
@@ -3,30 +3,26 @@
namespace JoeDixon\Translation;
use Illuminate\Filesystem\Filesystem;
+use Illuminate\Support\Collection;
+use JoeDixon\Translation\Drivers\CombinedTranslations;
class Scanner
{
- private $disk;
-
- private $scanPaths;
-
- private $translationMethods;
-
- public function __construct(Filesystem $disk, $scanPaths, $translationMethods)
- {
- $this->disk = $disk;
- $this->scanPaths = $scanPaths;
- $this->translationMethods = $translationMethods;
+ public function __construct(
+ private Filesystem $disk,
+ private array $scanPaths,
+ private array $translationMethods,
+ ) {
}
/**
* Scan all the files in the provided $scanPath for translations.
*
- * @return array
+ * @return CombinedTranslations
*/
- public function findTranslations()
+ public function findTranslations(): CombinedTranslations
{
- $results = ['single' => [], 'group' => []];
+ $results = new CombinedTranslations(new Collection(), new Collection());
// This has been derived from a combination of the following:
// * Laravel Language Manager GUI from Mohamed Said (https://github.com/themsaid/laravel-langman-gui)
@@ -43,15 +39,17 @@ public function findTranslations()
"[\'\"]". // Closing quote
"[\),]"; // 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] = '';
+ foreach ($this->scanPaths as $path) {
+ foreach ($this->disk->allFiles($path) 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);
+ data_set($results->shortKeyTranslations, $file.'.'.$k, '');
+ continue;
+ } else {
+ data_set($results->stringKeyTranslations, 'string.'.$key, '');
+ }
}
}
}
diff --git a/src/Translation.php b/src/Translation.php
index d224494..ca9a774 100644
--- a/src/Translation.php
+++ b/src/Translation.php
@@ -2,10 +2,17 @@
namespace JoeDixon\Translation;
+use Illuminate\Contracts\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Collection;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
+use JoeDixon\Translation\Database\Factories\TranslationFactory;
class Translation extends Model
{
+ use HasFactory;
+
protected $guarded = [];
public function __construct(array $attributes = [])
@@ -15,19 +22,27 @@ public function __construct(array $attributes = [])
$this->table = config('translation.database.translations_table');
}
- public function language()
+ public function language(): BelongsTo
{
return $this->belongsTo(Language::class);
}
- public static function getGroupsForLanguage($language)
+ /**
+ * @param string $language
+ * @return Collection
+ */
+ public static function getGroupsForLanguage(string $language): Collection
{
- return static::whereHas('language', function ($q) use ($language) {
- $q->where('language', $language);
- })->whereNotNull('group')
+ return static::whereHas('language', fn (Builder $q) => $q->where('language', $language))
+ ->whereNotNull('group')
->where('group', 'not like', '%single')
->select('group')
->distinct()
->get();
}
+
+ protected static function newFactory(): TranslationFactory
+ {
+ return TranslationFactory::new();
+ }
}
diff --git a/src/TranslationBindingsServiceProvider.php b/src/TranslationBindingsServiceProvider.php
index 8e73ab1..c1cecb4 100644
--- a/src/TranslationBindingsServiceProvider.php
+++ b/src/TranslationBindingsServiceProvider.php
@@ -15,14 +15,14 @@ class TranslationBindingsServiceProvider extends ServiceProvider
*/
public function register()
{
- if ($this->app['config']['translation.driver'] === 'database') {
+ if ($this->app->get('config')['translation.driver'] === 'database') {
$this->registerDatabaseTranslator();
} else {
parent::register();
}
}
- private function registerDatabaseTranslator()
+ private function registerDatabaseTranslator(): void
{
$this->registerDatabaseLoader();
@@ -39,7 +39,7 @@ private function registerDatabaseTranslator()
});
}
- protected function registerDatabaseLoader()
+ protected function registerDatabaseLoader(): void
{
$this->app->singleton('translation.loader', function ($app) {
// Post Laravel 5.4, the interface was moved to the contracts
diff --git a/src/TranslationManager.php b/src/TranslationManager.php
index 04186e2..817b932 100644
--- a/src/TranslationManager.php
+++ b/src/TranslationManager.php
@@ -4,25 +4,19 @@
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Str;
-use JoeDixon\Translation\Drivers\Database;
-use JoeDixon\Translation\Drivers\File;
+use JoeDixon\Translation\Drivers\Database\Database;
+use JoeDixon\Translation\Drivers\File\File;
+use JoeDixon\Translation\Drivers\Translation;
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 __construct(
+ private array $config,
+ private Scanner $scanner
+ ) {
}
- public function resolve()
+ public function resolve(): Translation
{
$driver = $this->config['driver'];
$driverResolver = Str::studly($driver);
@@ -35,13 +29,13 @@ public function resolve()
return $this->{$method}();
}
- protected function resolveFileDriver()
+ protected function resolveFileDriver(): File
{
- return new File(new Filesystem, $this->app['path.lang'], $this->app->config['app']['locale'], $this->scanner);
+ return new File(new Filesystem, app('path.lang'), config('app.locale'), $this->scanner);
}
- protected function resolveDatabaseDriver()
+ protected function resolveDatabaseDriver(): Database
{
- return new Database($this->app->config['app']['locale'], $this->scanner);
+ return new Database(config('app.locale'), $this->scanner);
}
}
diff --git a/src/TranslationServiceProvider.php b/src/TranslationServiceProvider.php
index 5684574..b560fac 100644
--- a/src/TranslationServiceProvider.php
+++ b/src/TranslationServiceProvider.php
@@ -3,13 +3,14 @@
namespace JoeDixon\Translation;
use Illuminate\Filesystem\Filesystem;
+use Illuminate\Foundation\Application;
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\AddLanguage;
+use JoeDixon\Translation\Console\Commands\AddTranslationKey;
+use JoeDixon\Translation\Console\Commands\ListLanguages;
use JoeDixon\Translation\Console\Commands\ListMissingTranslationKeys;
use JoeDixon\Translation\Console\Commands\SynchroniseMissingTranslationKeys;
-use JoeDixon\Translation\Console\Commands\SynchroniseTranslationsCommand;
+use JoeDixon\Translation\Console\Commands\SynchroniseTranslations;
use JoeDixon\Translation\Drivers\Translation;
class TranslationServiceProvider extends ServiceProvider
@@ -145,12 +146,12 @@ private function registerCommands()
{
if ($this->app->runningInConsole()) {
$this->commands([
- AddLanguageCommand::class,
- AddTranslationKeyCommand::class,
- ListLanguagesCommand::class,
+ AddLanguage::class,
+ AddTranslationKey::class,
+ ListLanguages::class,
ListMissingTranslationKeys::class,
SynchroniseMissingTranslationKeys::class,
- SynchroniseTranslationsCommand::class,
+ SynchroniseTranslations::class,
]);
}
}
@@ -172,14 +173,14 @@ private function registerHelpers()
*/
private function registerContainerBindings()
{
- $this->app->singleton(Scanner::class, function () {
- $config = $this->app['config']['translation'];
+ $config = $this->app->get('config')['translation'];
+ $this->app->singleton(Scanner::class, function () use ($config) {
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();
+ $this->app->singleton(Translation::class, function (Application $app) use ($config) {
+ return (new TranslationManager($config, $app->make(Scanner::class)))->resolve();
});
}
}
diff --git a/src/Types/DriverType.php b/src/Types/DriverType.php
new file mode 100644
index 0000000..c00b7e3
--- /dev/null
+++ b/src/Types/DriverType.php
@@ -0,0 +1,14 @@
+withFactories(__DIR__.'/../database/factories');
$this->translation = $this->app[Translation::class];
}
@@ -50,7 +49,7 @@ protected function getPackageProviders($app)
/** @test */
public function it_returns_all_languages()
{
- $newLanguages = factory(Language::class, 2)->create();
+ $newLanguages = Language::factory(2)->create();
$newLanguages = $newLanguages->mapWithKeys(function ($language) {
return [$language->language => $language->name];
})->toArray();
@@ -64,16 +63,16 @@ public function it_returns_all_languages()
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!"]);
+ Language::factory()->create(['language' => 'es', 'name' => 'Español']);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'group' => 'string', 'key' => 'Hello', 'value' => 'Hello']);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'group' => 'string', '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->assertEquals(['string' => ['string' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'short' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray()['en']);
$this->assertArrayHasKey('en', $translations->toArray());
$this->assertArrayHasKey('es', $translations->toArray());
}
@@ -82,16 +81,16 @@ public function it_returns_all_translations()
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!"]);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'group' => 'string', 'key' => 'Hello', 'value' => 'Hello']);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'group' => 'string', '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());
+ $this->assertEquals(['string' => ['string' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'short' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray());
+ $this->assertArrayHasKey('string', $translations->toArray());
+ $this->assertArrayHasKey('short', $translations->toArray());
}
/** @test */
@@ -119,56 +118,56 @@ public function it_can_add_a_new_language()
/** @test */
public function it_can_add_a_new_translation_to_a_new_group()
{
- $this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'test', 'hello', 'Hola!');
$translations = $this->translation->allTranslationsFor('es');
- $this->assertEquals(['test' => ['hello' => 'Hola!']], $translations->toArray()['group']);
+ $this->assertEquals(['test' => ['hello' => 'Hola!']], $translations->toArray()['short']);
}
/** @test */
public function it_can_add_a_new_translation_to_an_existing_translation_group()
{
- $translation = factory(TranslationModel::class)->create();
+ $translation = TranslationModel::factory()->create();
- $this->translation->addGroupTranslation($translation->language->language, "{$translation->group}", 'test', 'Testing');
+ $this->translation->addShortKeyTranslation($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']);
+ $this->assertSame([$translation->group => [$translation->key => $translation->value, 'test' => 'Testing']], $translations->toArray()['short']);
}
/** @test */
- public function it_can_add_a_new_single_translation()
+ public function it_can_add_a_new_short_key_translation()
{
- $this->translation->addSingleTranslation('es', 'single', 'Hello', 'Hola!');
+ $this->translation->addStringKeyTranslation('es', 'string', 'Hello', 'Hola!');
$translations = $this->translation->allTranslationsFor('es');
- $this->assertEquals(['single' => ['Hello' => 'Hola!']], $translations->toArray()['single']);
+ $this->assertEquals(['string' => ['Hello' => 'Hola!']], $translations->toArray()['string']);
}
/** @test */
- public function it_can_add_a_new_single_translation_to_an_existing_language()
+ public function it_can_add_a_new_short_key_translation_to_an_existing_language()
{
- $translation = factory(TranslationModel::class)->states('single')->create();
+ $translation = TranslationModel::factory()->stringKey()->create();
- $this->translation->addSingleTranslation($translation->language->language, 'single', 'Test', 'Testing');
+ $this->translation->addStringKeyTranslation($translation->language->language, 'string', 'Test', 'Testing');
$translations = $this->translation->allTranslationsFor($translation->language->language);
- $this->assertEquals(['single' => ['Test' => 'Testing', $translation->key => $translation->value]], $translations->toArray()['single']);
+ $this->assertEquals(['string' => ['Test' => 'Testing', $translation->key => $translation->value]], $translations->toArray()['string']);
}
/** @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 = Language::factory()->create(['language' => 'en']);
+ TranslationModel::factory()->create([
'language_id' => $language->id,
'group' => 'test',
]);
- $groups = $this->translation->getGroupsFor('en');
+ $groups = $this->translation->allShortKeyGroupsFor('en');
$this->assertEquals($groups->toArray(), ['test']);
}
@@ -177,23 +176,23 @@ public function it_can_get_a_collection_of_group_names_for_a_given_language()
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!"]);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'group' => 'string', 'key' => 'Hello', 'value' => 'Hello']);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'group' => 'string', 'key' => "What's up", 'value' => "What's up!"]);
- $this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'test', 'hello', 'Hola!');
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
$this->assertEquals($translations->toArray(), [
- 'group' => [
+ 'short' => [
'test' => [
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
'whats_up' => ['en' => "What's up!", 'es' => ''],
],
],
- 'single' => [
- 'single' => [
+ 'string' => [
+ 'string' => [
'Hello' => [
'en' => 'Hello',
'es' => '',
@@ -210,24 +209,24 @@ public function it_can_merge_a_language_with_the_base_language()
/** @test */
public function it_can_add_a_vendor_namespaced_translations()
{
- $this->translation->addGroupTranslation('es', 'translation_test::test', 'hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'translation_test::test', 'hello', 'Hola!');
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
- 'group' => [
+ 'short' => [
'translation_test::test' => [
'hello' => 'Hola!',
],
],
- 'single' => [],
+ 'string' => [],
]);
}
/** @test */
public function it_can_add_a_nested_translation()
{
- $this->translation->addGroupTranslation('en', 'test', 'test.nested', 'Nested!');
+ $this->translation->addShortKeyTranslation('en', 'test', 'test.nested', 'Nested!');
- $this->assertEquals($this->translation->getGroupTranslationsFor('en')->toArray(), [
+ $this->assertEquals($this->translation->allShortKeyTranslationsFor('en')->toArray(), [
'test' => [
'test.nested' => 'Nested!',
],
@@ -237,39 +236,39 @@ public function it_can_add_a_nested_translation()
/** @test */
public function it_can_add_nested_vendor_namespaced_translations()
{
- $this->translation->addGroupTranslation('es', 'translation_test::test', 'nested.hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'translation_test::test', 'nested.hello', 'Hola!');
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
- 'group' => [
+ 'short' => [
'translation_test::test' => [
'nested.hello' => 'Hola!',
],
],
- 'single' => [],
+ 'string' => [],
]);
}
/** @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!');
+ $this->translation->addShortKeyTranslation('en', 'translation_test::test', 'hello', 'Hello');
+ $this->translation->addShortKeyTranslation('es', 'translation_test::test', 'hello', 'Hola!');
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
$this->assertEquals($translations->toArray(), [
- 'group' => [
+ 'short' => [
'translation_test::test' => [
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
],
],
- 'single' => [],
+ 'string' => [],
]);
}
/** @test */
public function a_list_of_languages_can_be_viewed()
{
- $newLanguages = factory(Language::class, 2)->create();
+ $newLanguages = Language::factory(2)->create();
$response = $this->get(config('translation.ui_url'));
$response->assertSee(config('app.locale'));
@@ -281,7 +280,7 @@ public function a_list_of_languages_can_be_viewed()
/** @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->translation->addShortKeyTranslation(config('app.locale'), 'translation::translation', 'add_language', 'Add a new language');
$this->get(config('translation.ui_url').'/create')
->assertSee('Add a new language');
}
@@ -299,10 +298,10 @@ public function a_language_can_be_added()
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!']);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'hello', 'value' => 'Hello']);
+ TranslationModel::factory()->shortKey()->create(['language_id' => $default->id, 'group' => 'test', 'key' => 'whats_up', 'value' => "What's up!"]);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'key' => 'Hello', 'value' => 'Hello!']);
+ TranslationModel::factory()->stringKey()->create(['language_id' => $default->id, 'key' => "What's up", 'value' => 'Sup!']);
$this->get(config('translation.ui_url').'/en/translations')
->assertSee('hello')
@@ -314,7 +313,7 @@ public function a_list_of_translations_can_be_viewed()
/** @test */
public function the_translation_creation_page_can_be_viewed()
{
- $this->translation->addGroupTranslation('en', 'translation::translation', 'add_translation', 'Add a translation');
+ $this->translation->addShortKeyTranslation('en', 'translation::translation', 'add_translation', 'Add a translation');
$this->get(config('translation.ui_url').'/'.config('app.locale').'/translations/create')
->assertSee('Add a translation');
}
@@ -332,7 +331,7 @@ public function a_new_translation_can_be_added()
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']);
+ TranslationModel::factory()->shortKey()->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!'])
@@ -351,9 +350,9 @@ public function adding_a_translation_fires_an_event_with_the_expected_data()
Event::assertDispatched(TranslationAdded::class, function ($event) use ($data) {
return $event->language === 'en' &&
- $event->group === 'single' &&
- $event->value === $data['value'] &&
- $event->key === $data['key'];
+ $event->group === 'string' &&
+ $event->value === $data['value'] &&
+ $event->key === $data['key'];
});
}
@@ -367,9 +366,9 @@ public function updating_a_translation_fires_an_event_with_the_expected_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'];
+ $event->group === $data['group'] &&
+ $event->value === $data['value'] &&
+ $event->key === $data['key'];
});
}
}
diff --git a/tests/FileDriverTest.php b/tests/FileDriverTest.php
index c6ccf97..5b4ecad 100644
--- a/tests/FileDriverTest.php
+++ b/tests/FileDriverTest.php
@@ -52,7 +52,7 @@ 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->assertEquals(['string' => ['string' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'short' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray()['en']);
$this->assertArrayHasKey('en', $translations->toArray());
$this->assertArrayHasKey('es', $translations->toArray());
}
@@ -62,9 +62,9 @@ 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());
+ $this->assertEquals(['string' => ['string' => ['Hello' => 'Hello', "What's up" => "What's up!"]], 'short' => ['test' => ['hello' => 'Hello', 'whats_up' => "What's up!"]]], $translations->toArray());
+ $this->assertArrayHasKey('string', $translations->toArray());
+ $this->assertArrayHasKey('short', $translations->toArray());
}
/** @test */
@@ -89,11 +89,11 @@ public function it_can_add_a_new_language()
/** @test */
public function it_can_add_a_new_translation_to_a_new_group()
{
- $this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'test', 'hello', 'Hola!');
$translations = $this->translation->allTranslationsFor('es');
- $this->assertEquals(['test' => ['hello' => 'Hola!']], $translations->toArray()['group']);
+ $this->assertEquals(['test' => ['hello' => 'Hola!']], $translations->toArray()['short']);
unlink(__DIR__.'/fixtures/lang/es/test.php');
}
@@ -101,11 +101,11 @@ public function it_can_add_a_new_translation_to_a_new_group()
/** @test */
public function it_can_add_a_new_translation_to_an_existing_translation_group()
{
- $this->translation->addGroupTranslation('en', 'test', 'test', 'Testing');
+ $this->translation->addShortKeyTranslation('en', 'test', 'test', 'Testing');
$translations = $this->translation->allTranslationsFor('en');
- $this->assertEquals(['test' => ['hello' => 'Hello', 'whats_up' => 'What\'s up!', 'test' => 'Testing']], $translations->toArray()['group']);
+ $this->assertEquals(['test' => ['hello' => 'Hello', 'whats_up' => 'What\'s up!', 'test' => 'Testing']], $translations->toArray()['short']);
file_put_contents(
app()['path.lang'].'/en/test.php',
@@ -114,25 +114,25 @@ public function it_can_add_a_new_translation_to_an_existing_translation_group()
}
/** @test */
- public function it_can_add_a_new_single_translation()
+ public function it_can_add_a_new_string_key_translation()
{
- $this->translation->addSingleTranslation('es', 'single', 'Hello', 'Hola!');
+ $this->translation->addStringKeyTranslation('es', 'string', 'Hello', 'Hola!');
$translations = $this->translation->allTranslationsFor('es');
- $this->assertEquals(['single' => ['Hello' => 'Hola!']], $translations->toArray()['single']);
+ $this->assertEquals(['string' => ['Hello' => 'Hola!']], $translations->toArray()['string']);
unlink(__DIR__.'/fixtures/lang/es.json');
}
/** @test */
- public function it_can_add_a_new_single_translation_to_an_existing_language()
+ public function it_can_add_a_new_string_key_translation_to_an_existing_language()
{
- $this->translation->addSingleTranslation('en', 'single', 'Test', 'Testing');
+ $this->translation->addStringKeyTranslation('en', 'string', 'Test', 'Testing');
$translations = $this->translation->allTranslationsFor('en');
- $this->assertEquals(['single' => ['Hello' => 'Hello', 'What\'s up' => 'What\'s up!', 'Test' => 'Testing']], $translations->toArray()['single']);
+ $this->assertEquals(['string' => ['Hello' => 'Hello', 'What\'s up' => 'What\'s up!', 'Test' => 'Testing']], $translations->toArray()['string']);
file_put_contents(
app()['path.lang'].'/en.json',
@@ -143,7 +143,7 @@ public function it_can_add_a_new_single_translation_to_an_existing_language()
/** @test */
public function it_can_get_a_collection_of_group_names_for_a_given_language()
{
- $groups = $this->translation->getGroupsFor('en');
+ $groups = $this->translation->allShortKeyGroupsFor('en');
$this->assertEquals($groups->toArray(), ['test']);
}
@@ -151,18 +151,18 @@ public function it_can_get_a_collection_of_group_names_for_a_given_language()
/** @test */
public function it_can_merge_a_language_with_the_base_language()
{
- $this->translation->addGroupTranslation('es', 'test', 'hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'test', 'hello', 'Hola!');
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
$this->assertEquals($translations->toArray(), [
- 'group' => [
+ 'short' => [
'test' => [
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
'whats_up' => ['en' => "What's up!", 'es' => ''],
],
],
- 'single' => [
- 'single' => [
+ 'string' => [
+ 'string' => [
'Hello' => [
'en' => 'Hello',
'es' => '',
@@ -181,15 +181,15 @@ public function it_can_merge_a_language_with_the_base_language()
/** @test */
public function it_can_add_a_vendor_namespaced_translations()
{
- $this->translation->addGroupTranslation('es', 'translation_test::test', 'hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'translation_test::test', 'hello', 'Hola!');
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
- 'group' => [
+ 'short' => [
'translation_test::test' => [
'hello' => 'Hola!',
],
],
- 'single' => [],
+ 'string' => [],
]);
\File::deleteDirectory(__DIR__.'/fixtures/lang/vendor');
@@ -198,9 +198,9 @@ public function it_can_add_a_vendor_namespaced_translations()
/** @test */
public function it_can_add_a_nested_translation()
{
- $this->translation->addGroupTranslation('en', 'test', 'test.nested', 'Nested!');
+ $this->translation->addShortKeyTranslation('en', 'test', 'test.nested', 'Nested!');
- $this->assertEquals($this->translation->getGroupTranslationsFor('en')->toArray(), [
+ $this->assertEquals($this->translation->allShortKeyTranslationsFor('en')->toArray(), [
'test' => [
'hello' => 'Hello',
'test.nested' => 'Nested!',
@@ -217,15 +217,15 @@ public function it_can_add_a_nested_translation()
/** @test */
public function it_can_add_nested_vendor_namespaced_translations()
{
- $this->translation->addGroupTranslation('es', 'translation_test::test', 'nested.hello', 'Hola!');
+ $this->translation->addShortKeyTranslation('es', 'translation_test::test', 'nested.hello', 'Hola!');
$this->assertEquals($this->translation->allTranslationsFor('es')->toArray(), [
- 'group' => [
+ 'short' => [
'translation_test::test' => [
'nested.hello' => 'Hola!',
],
],
- 'single' => [],
+ 'string' => [],
]);
\File::deleteDirectory(__DIR__.'/fixtures/lang/vendor');
@@ -234,12 +234,12 @@ public function it_can_add_nested_vendor_namespaced_translations()
/** @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!');
+ $this->translation->addShortKeyTranslation('en', 'translation_test::test', 'hello', 'Hello');
+ $this->translation->addShortKeyTranslation('es', 'translation_test::test', 'hello', 'Hola!');
$translations = $this->translation->getSourceLanguageTranslationsWith('es');
$this->assertEquals($translations->toArray(), [
- 'group' => [
+ 'short' => [
'test' => [
'hello' => ['en' => 'Hello', 'es' => ''],
'whats_up' => ['en' => "What's up!", 'es' => ''],
@@ -248,8 +248,8 @@ public function it_can_merge_a_namespaced_language_with_the_base_language()
'hello' => ['en' => 'Hello', 'es' => 'Hola!'],
],
],
- 'single' => [
- 'single' => [
+ 'string' => [
+ 'string' => [
'Hello' => [
'en' => 'Hello',
'es' => '',
@@ -312,9 +312,9 @@ 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');
+ $translations = $this->translation->allStringKeyTranslationsFor('en');
- $this->assertEquals(['Hello' => 'Hello', 'What\'s up' => 'What\'s up!', 'joe' => 'is cool'], $translations->toArray()['single']);
+ $this->assertEquals(['Hello' => 'Hello', 'What\'s up' => 'What\'s up!', 'joe' => 'is cool'], $translations->toArray()['string']);
file_put_contents(
app()['path.lang'].'/en.json',
@@ -328,7 +328,7 @@ 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');
+ $translations = $this->translation->allShortKeyTranslationsFor('en');
$this->assertEquals(['hello' => 'Hello there!', 'whats_up' => 'What\'s up!'], $translations->toArray()['test']);
@@ -348,7 +348,7 @@ public function adding_a_translation_fires_an_event_with_the_expected_data()
Event::assertDispatched(TranslationAdded::class, function ($event) use ($data) {
return $event->language === 'en' &&
- $event->group === 'single' &&
+ $event->group === 'string' &&
$event->value === $data['value'] &&
$event->key === $data['key'];
});
diff --git a/tests/NewFileDriverTest.php b/tests/NewFileDriverTest.php
new file mode 100644
index 0000000..5d3a09c
--- /dev/null
+++ b/tests/NewFileDriverTest.php
@@ -0,0 +1,138 @@
+in(__DIR__);
+
+beforeEach(function () {
+ $this->translation = app(Translation::class);
+});
+
+test('a map of translation files can be built', function () {
+ assertEquals('vendor/laravel-translation/en/laravel-translation.php', $this->translation->map()->last());
+});
+
+test('a translation file can be found from the translation file map', function () {
+ assertEquals(
+ 'en.json',
+ $this->translation->map('en')
+ );
+});
+
+test('all languages can be returned', function () {
+ assertEquals(
+ collect([
+ 'de' => 'de',
+ 'en' => 'en',
+ 'es' => 'es',
+ 'fr' => 'fr',
+ 'jp' => 'jp',
+ ]),
+ $this->translation->allLanguages()
+ );
+});
+
+test('a language cannot be overwritten', function () {
+ $this->translation->addLanguage('en');
+})->throws(LanguageExistsException::class);
+
+test('all translations can be returned from a translation file', function () {
+ assertEquals(
+ collect([
+ 'products' => [
+ 'product_one' => [
+ 'title' => 'Product 1',
+ 'description' => 'This is product one',
+ ],
+ ],
+ ]),
+ $this->translation->allTranslationsFromMap('en.products')
+ );
+});
+
+test('a full list of normalized translation keys can be found by checking all languages', function () {
+ assertEquals(
+ new CombinedTranslations(
+ collect(['string' => ['Hello' => '', "What's up" => '']]),
+ collect([
+ 'errors' => [],
+ 'validation' => [
+ 'filled' => '',
+ 'gt' => [
+ 'array' => '',
+ 'file' => '',
+ 'numeric' => '',
+ 'string' => '',
+ ],
+ 'before_or_equal' => '',
+ 'between' => [
+ 'array' => '',
+ 'file' => '',
+ 'numeric' => '',
+ 'string' => '',
+ ],
+ ],
+ 'empty' => [],
+ 'products' => [
+ 'products' => [
+ 'product_one' => [
+ 'title' => '',
+ 'description' => '',
+ ],
+ ],
+ ],
+ 'laravel-translation::laravel-translation' => [
+ 'key' => '',
+ ],
+ ])),
+ $this->translation->normalizedKeys()
+ );
+});
+
+test('an individual translation can be found for a given language', function () {
+ assertEquals(
+ 'Product 1',
+ trans('products.products.product_one.title')
+ );
+});
+
+test('all vendor translations can be returned', function () {
+ $translations = $this->translation->allTranslationsFor('en');
+
+ assertCount(1, $translations->shortKeyTranslations['laravel-translation::laravel-translation']);
+ assertCount(0, $translations->shortKeyTranslations['laravel-translation::validation']);
+ assertCount(1, $translations->stringKeyTranslations['laravel-translation::string']);
+});
+
+test('both string key and short key translations can be returned', function () {
+ //
+})->skip();
+
+test('a string key translation can be saved in the correct file if it exists', function () {
+ //
+})->skip();
+
+test('a short key translation can be saved in the correct file if it exists', function () {
+ //
+})->skip();
+
+test('a string key translation can be saved in new file at the highest nesting level if a file cannot be found', function () {
+ //
+})->skip();
+
+test('a short key translation can be saved in new file at the highest nesting level if a file cannot be found', function () {
+ //
+})->skip();
+
+test('a vendor namespaced string key translation can be saved', function () {
+ //
+})->skip();
+
+test('a vendor namespaced short key translation can be saved', function () {
+ //
+})->skip();
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644
index 0000000..b11d165
--- /dev/null
+++ b/tests/TestCase.php
@@ -0,0 +1,23 @@
+ 'The :attribute field must have a value.',
+ 'gt' => [
+ 'array' => 'The :attribute must have more than :value items.',
+ 'file' => 'The :attribute must be greater than :value kilobytes.',
+ 'numeric' => 'The :attribute must be greater than :value.',
+ 'string' => 'The :attribute must be greater than :value characters.',
+ ],
+];
diff --git a/tests/fixtures/lang/en/empty.php b/tests/fixtures/lang/en/empty.php
new file mode 100644
index 0000000..e69de29
diff --git a/tests/fixtures/lang/en/products.php b/tests/fixtures/lang/en/products.php
new file mode 100644
index 0000000..540afb7
--- /dev/null
+++ b/tests/fixtures/lang/en/products.php
@@ -0,0 +1,10 @@
+ [
+ 'product_one' => [
+ 'title' => 'Product 1',
+ 'description' => 'This is product one',
+ ],
+ ],
+];
diff --git a/tests/fixtures/lang/en/test.php b/tests/fixtures/lang/en/test.php
deleted file mode 100644
index 27a33ed..0000000
--- a/tests/fixtures/lang/en/test.php
+++ /dev/null
@@ -1,6 +0,0 @@
- 'Hello',
- 'whats_up' => 'What\'s up!',
-);
diff --git a/tests/fixtures/lang/en/validation.php b/tests/fixtures/lang/en/validation.php
new file mode 100644
index 0000000..20aab8d
--- /dev/null
+++ b/tests/fixtures/lang/en/validation.php
@@ -0,0 +1,11 @@
+ 'The :attribute must be a date before or equal to :date.',
+ 'between' => [
+ 'array' => 'The :attribute must have between :min and :max items.',
+ 'file' => 'The :attribute must be between :min and :max kilobytes.',
+ 'numeric' => 'The :attribute must be between :min and :max.',
+ 'string' => 'The :attribute must be between :min and :max characters.',
+ ],
+];
diff --git a/tests/fixtures/lang/jp.json b/tests/fixtures/lang/jp.json
new file mode 100644
index 0000000..e69de29
diff --git a/tests/fixtures/lang/vendor/laravel-translation/en/en.json b/tests/fixtures/lang/vendor/laravel-translation/en/en.json
new file mode 100644
index 0000000..a977d99
--- /dev/null
+++ b/tests/fixtures/lang/vendor/laravel-translation/en/en.json
@@ -0,0 +1,3 @@
+{
+ "key": "value"
+}
\ No newline at end of file
diff --git a/tests/fixtures/lang/vendor/laravel-translation/en/laravel-translation.php b/tests/fixtures/lang/vendor/laravel-translation/en/laravel-translation.php
new file mode 100644
index 0000000..48318cf
--- /dev/null
+++ b/tests/fixtures/lang/vendor/laravel-translation/en/laravel-translation.php
@@ -0,0 +1,5 @@
+ 'value',
+];
diff --git a/tests/fixtures/lang/vendor/laravel-translation/en/validation.php b/tests/fixtures/lang/vendor/laravel-translation/en/validation.php
new file mode 100644
index 0000000..0b67a5f
--- /dev/null
+++ b/tests/fixtures/lang/vendor/laravel-translation/en/validation.php
@@ -0,0 +1,3 @@
+