Cleaned up script and formatted remaining EN files

This commit is contained in:
Dan Brown 2018-12-16 13:12:13 +00:00
parent 86a00a59d4
commit 2753629dbe
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
9 changed files with 259 additions and 223 deletions

View File

@ -1,21 +1,15 @@
<?php
/**
* Authentication Language Lines
* The following language lines are used during authentication for various
* messages that we need to display to the user.
*/
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
/**
* Login & Register
*/
// Login & Register
'sign_up' => 'Sign up',
'log_in' => 'Log in',
'log_in_with' => 'Login with :socialDriver',
@ -43,23 +37,18 @@ return [
'register_success' => 'Thanks for signing up! You are now registered and signed in.',
/**
* Password Reset
*/
// Password Reset
'reset_password' => 'Reset Password',
'reset_password_send_instructions' => 'Enter your email below and you will be sent an email with a password reset link.',
'reset_password_send_button' => 'Send Reset Link',
'reset_password_sent_success' => 'A password reset link has been sent to :email.',
'reset_password_success' => 'Your password has been successfully reset.',
'email_reset_subject' => 'Reset your :appName password',
'email_reset_text' => 'You are receiving this email because we received a password reset request for your account.',
'email_reset_not_requested' => 'If you did not request a password reset, no further action is required.',
/**
* Email Confirmation
*/
// Email Confirmation
'email_confirm_subject' => 'Confirm your email on :appName',
'email_confirm_greeting' => 'Thanks for joining :appName!',
'email_confirm_text' => 'Please confirm your email address by clicking the button below:',

View File

@ -1,9 +1,10 @@
<?php
/**
* Common elements found throughout many areas of BookStack.
*/
return [
/**
* Buttons
*/
// Buttons
'cancel' => 'Cancel',
'confirm' => 'Confirm',
'back' => 'Back',
@ -12,18 +13,14 @@ return [
'select' => 'Select',
'more' => 'More',
/**
* Form Labels
*/
// Form Labels
'name' => 'Name',
'description' => 'Description',
'role' => 'Role',
'cover_image' => 'Cover image',
'cover_image_description' => 'This image should be approx 440x250px.',
/**
* Actions
*/
// Actions
'actions' => 'Actions',
'view' => 'View',
'create' => 'Create',
@ -40,9 +37,7 @@ return [
'remove' => 'Remove',
'add' => 'Add',
/**
* Misc
*/
// Misc
'deleted_user' => 'Deleted User',
'no_activity' => 'No activity to show',
'no_items' => 'No items available',
@ -54,15 +49,11 @@ return [
'list_view' => 'List View',
'default' => 'Default',
/**
* Header
*/
// Header
'view_profile' => 'View Profile',
'edit_profile' => 'Edit Profile',
/**
* Email Content
*/
// Email Content
'email_action_help' => 'If youre having trouble clicking the ":actionText" button, copy and paste the URL below into your web browser:',
'email_rights' => 'All rights reserved',
];

View File

@ -1,9 +1,10 @@
<?php
/**
* Text used in custom JavaScript driven components.
*/
return [
/**
* Image Manager
*/
// Image Manager
'image_select' => 'Image Select',
'image_all' => 'All',
'image_all_title' => 'View all images',
@ -24,9 +25,7 @@ return [
'image_delete_success' => 'Image successfully deleted',
'image_upload_remove' => 'Remove',
/**
* Code editor
*/
// Code Editor
'code_editor' => 'Edit Code',
'code_language' => 'Code Language',
'code_content' => 'Code Content',

View File

@ -1,9 +1,11 @@
<?php
/**
* Text used for 'Entities' (Document Structure Elements) such as
* Books, Shelves, Chapters & Pages
*/
return [
/**
* Shared
*/
// Shared
'recently_created' => 'Recently Created',
'recently_created_pages' => 'Recently Created Pages',
'recently_updated_pages' => 'Recently Updated Pages',
@ -31,17 +33,13 @@ return [
'export_pdf' => 'PDF File',
'export_text' => 'Plain Text File',
/**
* Permissions and restrictions
*/
// Permissions and restrictions
'permissions' => 'Permissions',
'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.',
'permissions_enable' => 'Enable Custom Permissions',
'permissions_save' => 'Save Permissions',
/**
* Search
*/
// Search
'search_results' => 'Search Results',
'search_total_results_found' => ':count result found|:count total results found',
'search_clear' => 'Clear Search',
@ -66,9 +64,7 @@ return [
'search_set_date' => 'Set Date',
'search_update' => 'Update Search',
/**
* Shelves
*/
// Shelves
'shelf' => 'Shelf',
'shelves' => 'Shelves',
'shelves_long' => 'Bookshelves',
@ -98,9 +94,7 @@ return [
'shelves_copy_permissions_explain' => 'This will apply the current permission settings of this bookshelf to all books contained within. Before activating, ensure any changes to the permissions of this bookshelf have been saved.',
'shelves_copy_permission_success' => 'Bookshelf permissions copied to :count books',
/**
* Books
*/
// Books
'book' => 'Book',
'books' => 'Books',
'x_books' => ':count Book|:count Books',
@ -134,9 +128,7 @@ return [
'books_sort_show_other' => 'Show Other Books',
'books_sort_save' => 'Save New Order',
/**
* Chapters
*/
// Chapters
'chapter' => 'Chapter',
'chapters' => 'Chapters',
'x_chapters' => ':count Chapter|:count Chapters',
@ -159,9 +151,7 @@ return [
'chapters_permissions_success' => 'Chapter Permissions Updated',
'chapters_search_this' => 'Search this chapter',
/**
* Pages
*/
// Pages
'page' => 'Page',
'pages' => 'Pages',
'x_pages' => ':count Page|:count Pages',
@ -235,9 +225,7 @@ return [
'pages_draft_discarded' => 'Draft discarded, The editor has been updated with the current page content',
'pages_specific' => 'Specific Page',
/**
* Editor sidebar
*/
// Editor Sidebar
'page_tags' => 'Page Tags',
'chapter_tags' => 'Chapter Tags',
'book_tags' => 'Book Tags',
@ -273,18 +261,14 @@ return [
'attachments_file_updated' => 'File successfully updated',
'attachments_link_attached' => 'Link successfully attached to page',
/**
* Profile View
*/
// Profile View
'profile_user_for_x' => 'User for :time',
'profile_created_content' => 'Created Content',
'profile_not_created_pages' => ':userName has not created any pages',
'profile_not_created_chapters' => ':userName has not created any chapters',
'profile_not_created_books' => ':userName has not created any books',
/**
* Comments
*/
// Comments
'comment' => 'Comment',
'comments' => 'Comments',
'comment_add' => 'Add Comment',
@ -302,9 +286,7 @@ return [
'comment_delete_confirm' => 'Are you sure you want to delete this comment?',
'comment_in_reply_to' => 'In reply to :commentId',
/**
* Revision
*/
// Revision
'revision_delete_confirm' => 'Are you sure you want to delete this revision?',
'revision_delete_success' => 'Revision deleted',
'revision_cannot_delete_latest' => 'Cannot delete the latest revision.'

View File

@ -1,11 +1,9 @@
<?php
/**
* Text shown in error messaging.
*/
return [
/**
* Error text strings.
*/
// Permissions
'permission' => 'You do not have permission to access the requested page.',
'permissionJson' => 'You do not have permission to perform the requested action.',
@ -80,4 +78,5 @@ return [
'error_occurred' => 'An Error Occurred',
'app_down' => ':appName is down right now',
'back_soon' => 'It will be back up soon.',
];

View File

@ -1,18 +1,11 @@
<?php
/**
* Pagination Language Lines
* The following language lines are used by the paginator library to build
* the simple pagination links.
*/
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',

View File

@ -1,18 +1,11 @@
<?php
/**
* Password Reminder Language Lines
* The following language lines are the default lines which match reasons
* that are given by the password broker for a password update attempt has failed.
*/
return [
/*
|--------------------------------------------------------------------------
| Password Reminder Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'password' => 'Passwords must be at least six characters and match the confirmation.',
'user' => "We can't find a user with that e-mail address.",
'token' => 'This password reset token is invalid.',

View File

@ -1,21 +1,17 @@
<?php
/**
* Settings text strings
* Contains all text strings used in the general settings sections of BookStack
* including users and roles.
*/
return [
/**
* Settings text strings
* Contains all text strings used in the general settings sections of BookStack
* including users and roles.
*/
// Common Messages
'settings' => 'Settings',
'settings_save' => 'Save Settings',
'settings_save_success' => 'Settings saved',
/**
* App settings
*/
// App Settings
'app_settings' => 'App Settings',
'app_name' => 'Application name',
'app_name_desc' => 'This name is shown in the header and any emails.',
@ -37,10 +33,7 @@ return [
'app_disable_comments' => 'Disable comments',
'app_disable_comments_desc' => 'Disable comments across all pages in the application. Existing comments are not shown.',
/**
* Registration settings
*/
// Registration Settings
'reg_settings' => 'Registration Settings',
'reg_allow' => 'Allow registration?',
'reg_default_role' => 'Default user role after registration',
@ -50,10 +43,7 @@ return [
'reg_confirm_restrict_domain_desc' => 'Enter a comma separated list of email domains you would like to restrict registration to. Users will be sent an email to confirm their address before being allowed to interact with the application. <br> Note that users will be able to change their email addresses after successful registration.',
'reg_confirm_restrict_domain_placeholder' => 'No restriction set',
/**
* Maintenance settings
*/
// Maintenance settings
'maint' => 'Maintenance',
'maint_image_cleanup' => 'Cleanup Images',
'maint_image_cleanup_desc' => "Scans page & revision content to check which images and drawings are currently in use and which images are redundant. Ensure you create a full database and image backup before running this.",
@ -63,10 +53,7 @@ return [
'maint_image_cleanup_success' => ':count potentially unused images found and deleted!',
'maint_image_cleanup_nothing_found' => 'No unused images found, Nothing deleted!',
/**
* Role settings
*/
// Role Settings
'roles' => 'Roles',
'role_user_roles' => 'User Roles',
'role_create' => 'Create New Role',
@ -99,10 +86,7 @@ return [
'role_users' => 'Users in this role',
'role_users_none' => 'No users are currently assigned to this role',
/**
* Users
*/
// Users
'users' => 'Users',
'user_profile' => 'User Profile',
'users_add_new' => 'Add New User',

View File

@ -4,119 +4,150 @@
/**
* Format a language file in the same way as the EN equivalent.
* Matches the line numbers of translated content.
* Potentially destructive, Ensure you have a backup of your translation content before running.
*/
$args = array_slice($argv, 1);
if (count($args) < 2) {
errorOut("Please provide a language code as the first argument and a translation file name as the second (./format.php fr activities)");
errorOut("Please provide a language code as the first argument and a translation file name, or '--all', as the second (./format.php fr activities)");
}
$lang = formatLang($args[0]);
$lang = formatLocale($args[0]);
$fileName = explode('.', $args[1])[0];
$filesNames = [$fileName];
if ($fileName === '--all') {
$fileNames = getTranslationFileNames();
}
$enLines = loadLangFileLines('en', $fileName);
$langContent = loadLang($lang, $fileName);
$enContent = loadLang('en', $fileName);
foreach ($fileNames as $fileName) {
$formatted = formatFileContents($lang, $fileName);
writeLangFile($lang, $fileName, $formatted);
}
// Calculate the longest top-level key length
$longestKeyLength = longestKey($enContent);
// Start formatted content
$formatted = [];
$mode = 'header';
$arrayKeys = [];
/**
* Format the contents of a single translation file in the given language.
* @param string $lang
* @param string $fileName
* @return string
*/
function formatFileContents(string $lang, string $fileName) : string {
$enLines = loadLangFileLines('en', $fileName);
$langContent = loadLang($lang, $fileName);
$enContent = loadLang('en', $fileName);
foreach($enLines as $index => $line) {
$trimLine = trim($line);
if ($mode === 'header') {
$formatted[$index] = $line;
if (str_replace(' ', '', $trimLine) === 'return[') $mode = 'body';
}
// Calculate the longest top-level key length
$longestKeyLength = calculateKeyPadding($enContent);
if ($mode === 'body') {
$matches = [];
// Start formatted content
$formatted = [];
$mode = 'header';
$arrayKeys = [];
// Comment
if (strpos($trimLine, '//') === 0) {
$formatted[$index] = "\t" . $trimLine;
continue;
foreach($enLines as $index => $line) {
$trimLine = trim($line);
if ($mode === 'header') {
$formatted[$index] = $line;
if (str_replace(' ', '', $trimLine) === 'return[') $mode = 'body';
}
// Arrays
$arrayStartMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\[(\],)?\s*?$/', $trimLine, $matches);
$arrayEndMatch = preg_match('/]\s*,\s*$/', $trimLine);
$indent = count($arrayKeys) + 1;
if ($arrayStartMatch === 1) {
$arrayKeys[] = $matches[1];
$formatted[$index] = str_repeat(" ", $indent * 4) . str_pad("'{$matches[1]}'", $longestKeyLength) . "=> [";
if ($arrayEndMatch !== 1) continue;
}
if ($arrayEndMatch === 1) {
unsetArrayByKeys($langContent, $arrayKeys);
$key = array_pop($arrayKeys);
if (isset($formatted[$index])) {
$formatted[$index] .= '],';
} else {
$formatted[$index] = str_repeat(" ", ($indent-1) * 4) . "],";
}
continue;
}
if ($mode === 'body') {
$matches = [];
// Translation
$translationMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\'(.*)?\'.+?$/', $trimLine, $matches);
if ($translationMatch === 1) {
$key = $matches[1];
$keys = array_merge($arrayKeys, [$key]);
$langVal = getTranslationByKeys($langContent, $keys);
if (empty($langVal)) continue;
$keyPad = $longestKeyLength;
if (count($arrayKeys) === 0) {
unset($langContent[$key]);
} else {
$keyPad = longestKey(getTranslationByKeys($enContent, $arrayKeys));
// Comment
if (strpos($trimLine, '//') === 0) {
$formatted[$index] = "\t" . $trimLine;
continue;
}
$formatted[$index] = formatTranslationLine($key, $langVal, $indent, $keyPad);
continue;
// Arrays
$arrayStartMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\[(\],)?\s*?$/', $trimLine, $matches);
$arrayEndMatch = preg_match('/]\s*,\s*$/', $trimLine);
$indent = count($arrayKeys) + 1;
if ($arrayStartMatch === 1) {
$arrayKeys[] = $matches[1];
$formatted[$index] = str_repeat(" ", $indent * 4) . str_pad("'{$matches[1]}'", $longestKeyLength) . "=> [";
if ($arrayEndMatch !== 1) continue;
}
if ($arrayEndMatch === 1) {
unsetArrayByKeys($langContent, $arrayKeys);
array_pop($arrayKeys);
if (isset($formatted[$index])) {
$formatted[$index] .= '],';
} else {
$formatted[$index] = str_repeat(" ", ($indent-1) * 4) . "],";
}
continue;
}
// Translation
$translationMatch = preg_match('/^\'(.*)\'\s+?=>\s+?\'(.*)?\'.+?$/', $trimLine, $matches);
if ($translationMatch === 1) {
$key = $matches[1];
$keys = array_merge($arrayKeys, [$key]);
$langVal = getTranslationByKeys($langContent, $keys);
if (empty($langVal)) continue;
$keyPad = $longestKeyLength;
if (count($arrayKeys) === 0) {
unset($langContent[$key]);
} else {
$keyPad = calculateKeyPadding(getTranslationByKeys($enContent, $arrayKeys));
}
$formatted[$index] = formatTranslationLine($key, $langVal, $indent, $keyPad);
continue;
}
}
}
// Fill missing lines
$arraySize = max(array_keys($formatted));
$formatted = array_replace(array_fill(0, $arraySize, ''), $formatted);
// Add remaining translations
$langContent = array_filter($langContent, function($item) {
return !is_null($item) && !empty($item);
});
if (count($langContent) > 0) {
$formatted[] = '';
$formatted[] = "\t// Unmatched";
}
foreach ($langContent as $key => $value) {
if (is_array($value)) {
$formatted[] = formatTranslationArray($key, $value);
} else {
$formatted[] = formatTranslationLine($key, $value);
}
}
// Add end line
$formatted[] = '];';
return implode("\n", $formatted);
}
// Fill missing lines
$arraySize = max(array_keys($formatted));
$formatted = array_replace(array_fill(0, $arraySize, ''), $formatted);
// Add remaining translations
$langContent = array_filter($langContent, function($item) {
return !is_null($item) && !empty($item);
});
if (count($langContent) > 0) {
$formatted[] = '';
$formatted[] = "\t// Unmatched";
}
foreach ($langContent as $key => $value) {
if (is_array($value)) {
$formatted[] = formatTranslationArray($key, $value);
} else {
$formatted[] = formatTranslationLine($key, $value);
}
}
// Add end line
$formatted[] = '];';
$formatted = implode("\n", $formatted);
writeLangFile($lang, $fileName, $formatted);
function formatTranslationLine(string $key, string $value, int $indent = 1, int $keyPad = 1) {
/**
* Format a translation line.
* @param string $key
* @param string $value
* @param int $indent
* @param int $keyPad
* @return string
*/
function formatTranslationLine(string $key, string $value, int $indent = 1, int $keyPad = 1) : string {
$escapedValue = str_replace("'", "\\'", $value);
return str_repeat(" ", $indent * 4) . str_pad("'{$key}'", $keyPad, ' ') ."=> '{$escapedValue}',";
}
function longestKey(array $array) {
/**
* Find the longest key in the array and provide the length
* for all keys to be used when printed.
* @param array $array
* @return int
*/
function calculateKeyPadding(array $array) : int {
$top = 0;
foreach ($array as $key => $value) {
$keyLen = strlen($key);
@ -125,12 +156,27 @@ function longestKey(array $array) {
return $top + 3;
}
function formatTranslationArray(string $key, array $array) {
/**
* Format an translation array with the given key.
* Simply prints as an old-school php array.
* Used as a last-resort backup to save unused translations.
* @param string $key
* @param array $array
* @return string
*/
function formatTranslationArray(string $key, array $array) : string {
$arrayPHP = var_export($array, true);
return " '{$key}' => {$arrayPHP},";
}
function getTranslationByKeys(array $translations, array $keys) {
/**
* Find a string translation value within a multi-dimensional array
* by traversing the given array of keys.
* @param array $translations
* @param array $keys
* @return string|array
*/
function getTranslationByKeys(array $translations, array $keys) {
$val = $translations;
foreach ($keys as $key) {
$val = $val[$key] ?? '';
@ -139,6 +185,12 @@ function getTranslationByKeys(array $translations, array $keys) {
return $val;
}
/**
* Unset an inner item of a multi-dimensional array by
* traversing the given array of keys.
* @param array $input
* @param array $keys
*/
function unsetArrayByKeys(array &$input, array $keys) {
$val = &$input;
$lastIndex = count($keys) - 1;
@ -151,6 +203,12 @@ function unsetArrayByKeys(array &$input, array $keys) {
}
}
/**
* Write the given content to a translation file.
* @param string $lang
* @param string $fileName
* @param string $content
*/
function writeLangFile(string $lang, string $fileName, string $content) {
$path = __DIR__ . "/{$lang}/{$fileName}.php";
if (!file_exists($path)) {
@ -159,7 +217,13 @@ function writeLangFile(string $lang, string $fileName, string $content) {
file_put_contents($path, $content);
}
function loadLangFileLines(string $lang, string $fileName) {
/**
* Load the contents of a language file as an array of text lines.
* @param string $lang
* @param string $fileName
* @return array
*/
function loadLangFileLines(string $lang, string $fileName) : array {
$path = __DIR__ . "/{$lang}/{$fileName}.php";
if (!file_exists($path)) {
errorOut("Expected translation file '{$path}' does not exist");
@ -170,7 +234,13 @@ function loadLangFileLines(string $lang, string $fileName) {
}, $lines);
}
function loadLang(string $lang, string $fileName) {
/**
* Load the contents of a language file
* @param string $lang
* @param string $fileName
* @return array
*/
function loadLang(string $lang, string $fileName) : array {
$path = __DIR__ . "/{$lang}/{$fileName}.php";
if (!file_exists($path)) {
errorOut("Expected translation file '{$path}' does not exist");
@ -180,21 +250,57 @@ function loadLang(string $lang, string $fileName) {
return $fileData;
}
function formatLang($lang) {
/**
* Fetch an array containing the names of all translation files without the extension.
* @return array
*/
function getTranslationFileNames() : array {
$dir = __DIR__ . "/en";
if (!file_exists($dir)) {
errorOut("Expected directory '{$dir}' does not exist");
}
$files = scandir($dir);
$fileNames = [];
foreach ($files as $file) {
if (substr($file, -4) === '.php') {
$fileNames[] = substr($file, 0, strlen($file) - 4);
}
}
return $fileNames;
}
/**
* Format a locale to follow the lowercase_UPERCASE standard
* @param string $lang
* @return string
*/
function formatLocale(string $lang) : string {
$langParts = explode('_', strtoupper($lang));
$langParts[0] = strtolower($langParts[0]);
return implode('_', $langParts);
}
/**
* Dump a variable then die.
* @param $content
*/
function dd($content) {
print_r($content);
exit(1);
}
/**
* Log out some information text in blue
* @param $text
*/
function info($text) {
echo "\e[34m" . $text . "\e[0m\n";
}
/**
* Log out an error in red and exit.
* @param $text
*/
function errorOut($text) {
echo "\e[31m" . $text . "\e[0m\n";
exit(1);