diff --git a/readme.md b/readme.md index e048e8ea6..1b3db4a56 100644 --- a/readme.md +++ b/readme.md @@ -54,8 +54,19 @@ Once done you can run `phpunit` in the application root directory to run all tes As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`. You will also need to add the language to the `locales` array in the `config/app.php` file. + +There is a script available which compares translation content to `en` files to see what items are missing or redundant. This can be ran like so from your BookStack install folder: + +```bash +# Syntax +php resources/lang/check.php + +# Examples +php resources/lang/check.php fr +php resources/lang/check.php pt_BR +``` - Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. +Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. ## Contributing diff --git a/resources/lang/check.php b/resources/lang/check.php new file mode 100755 index 000000000..92a7b1eaf --- /dev/null +++ b/resources/lang/check.php @@ -0,0 +1,114 @@ +#!/usr/bin/env php + $enStr) { + if (strpos($enKey, 'settings.language_select.') === 0) { + unset($langContent[$enKey]); + continue; + } + if (!isset($langContent[$enKey])) { + $missingLangStrings[$enKey] = $enStr; + continue; + } + unset($langContent[$enKey]); +} + +if (count($missingLangStrings) > 0) { + info("\n========================"); + info("Missing language content"); + info("========================"); + outputFlatArray($missingLangStrings, $lang); +} + +if (count($langContent) > 0) { + info("\n=========================="); + info("Redundant language content"); + info("=========================="); + outputFlatArray($langContent, $lang); +} + +function outputFlatArray($arr, $lang) { + $grouped = []; + foreach ($arr as $key => $val) { + $explodedKey = explode('.', $key); + $group = $explodedKey[0]; + $path = implode('.', array_slice($explodedKey, 1)); + if (!isset($grouped[$group])) $grouped[$group] = []; + $grouped[$group][$path] = $val; + } + foreach ($grouped as $filename => $arr) { + echo "\e[36m" . $lang . '/' . $filename . ".php\e[0m\n"; + echo json_encode($arr, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) . "\n"; + } +} + +function formatLang($lang) { + $langParts = explode('_', strtoupper($lang)); + $langParts[0] = strtolower($langParts[0]); + return implode('_', $langParts); +} + +function loadLang(string $lang) { + $dir = __DIR__ . "/{$lang}"; + if (!file_exists($dir)) { + errorOut("Expected directory '{$dir}' does not exist"); + } + $files = scandir($dir); + $data = []; + foreach ($files as $file) { + if (substr($file, -4) !== '.php') continue; + $fileData = include ($dir . '/' . $file); + $name = substr($file, 0, -4); + $data[$name] = $fileData; + } + return flattenArray($data); +} + +function flattenArray(array $arr) { + $data = []; + foreach ($arr as $key => $arrItem) { + if (!is_array($arrItem)) { + $data[$key] = $arrItem; + continue; + } + + $toUse = flattenArray($arrItem); + foreach ($toUse as $innerKey => $item) { + $data[$key . '.' . $innerKey] = $item; + } + } + return $data; +} + +function info($text) { + echo "\e[34m" . $text . "\e[0m\n"; +} + +function errorOut($text) { + echo "\e[31m" . $text . "\e[0m\n"; + exit(1); +} \ No newline at end of file