From cfcd66158cf1a6a48ca1468293c969566de01831 Mon Sep 17 00:00:00 2001 From: Jared Hancock <jared@osticket.com> Date: Fri, 29 Aug 2014 10:04:30 -0500 Subject: [PATCH] i18n: Use @trans to mark a bare string translatable And allow for @context to add context to the bare string literal. For instance, /* @trans, @context "noun" */ 'Open' Would mark the string 'Open' translatable with context "noun". --- include/class.dynamic_forms.php | 4 +-- include/class.export.php | 4 +-- include/class.filter.php | 14 ++++---- include/class.forms.php | 40 +++++++++++------------ include/class.list.php | 2 +- include/class.note.php | 4 +-- include/class.organization.php | 2 +- include/class.staff.php | 2 +- include/class.template.php | 58 ++++++++++++++++----------------- include/class.ticket.php | 4 +-- include/class.topic.php | 2 +- include/class.user.php | 20 ++++++------ setup/cli/modules/i18n.php | 24 +++++++++++--- setup/doc/i18n.md | 6 ++-- 14 files changed, 101 insertions(+), 85 deletions(-) diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index 46c5045c3..24412e180 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -243,7 +243,7 @@ class UserForm extends DynamicForm { return static::$instance; } } -Filter::addSupportedMatches(/* trans */ 'User Data', function() { +Filter::addSupportedMatches(/* @trans */ 'User Data', function() { $matches = array(); foreach (UserForm::getInstance()->getFields() as $f) { if (!$f->hasData()) @@ -333,7 +333,7 @@ class TicketForm extends DynamicForm { } } // Add fields from the standard ticket form to the ticket filterable fields -Filter::addSupportedMatches(/* trans */ 'Ticket Data', function() { +Filter::addSupportedMatches(/* @trans */ 'Ticket Data', function() { $matches = array(); foreach (TicketForm::getInstance()->getFields() as $f) { if (!$f->hasData()) diff --git a/include/class.export.php b/include/class.export.php index 78be2d432..3471ba5f6 100644 --- a/include/class.export.php +++ b/include/class.export.php @@ -18,8 +18,8 @@ class Export { // XXX: This may need to be moved to a print-specific class static $paper_sizes = array( - /* trans */ 'Letter', - /* trans */ 'Legal', + /* @trans */ 'Letter', + /* @trans */ 'Legal', 'A4', 'A3', ); diff --git a/include/class.filter.php b/include/class.filter.php index 229875587..d30a6c68b 100644 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -20,16 +20,16 @@ class Filter { var $ht; static $match_types = array( - /* trans */ 'User Information' => array( - array('name' => /* trans */ 'Name', - 'email' => /* trans */ 'Email', + /* @trans */ 'User Information' => array( + array('name' => /* @trans */ 'Name', + 'email' => /* @trans */ 'Email', ), 900 ), - /* trans */ 'Email Meta-Data' => array( - array('reply-to' => /* trans */ 'Reply-To Email', - 'reply-to-name' => /* trans */ 'Reply-To Name', - 'addressee' => /* trans */ 'Addressee (To and Cc)', + /* @trans */ 'Email Meta-Data' => array( + array('reply-to' => /* @trans */ 'Reply-To Email', + 'reply-to-name' => /* @trans */ 'Reply-To Name', + 'addressee' => /* @trans */ 'Addressee (To and Cc)', ), 200 ), diff --git a/include/class.forms.php b/include/class.forms.php index 08adccab7..b66421adf 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -131,15 +131,15 @@ class FormField { var $presentation_only = false; static $types = array( - /* trans */ 'Basic Fields' => array( - 'text' => array( /* trans */ 'Short Answer', 'TextboxField'), - 'memo' => array( /* trans */ 'Long Answer', 'TextareaField'), - 'thread' => array( /* trans */ 'Thread Entry', 'ThreadEntryField', false), - 'datetime' => array(/* trans */ 'Date and Time', 'DatetimeField'), - 'phone' => array( /* trans */ 'Phone Number', 'PhoneField'), - 'bool' => array( /* trans */ 'Checkbox', 'BooleanField'), - 'choices' => array( /* trans */ 'Choices', 'ChoiceField'), - 'break' => array( /* trans */ 'Section Break', 'SectionBreakField'), + /* @trans */ 'Basic Fields' => array( + 'text' => array( /* @trans */ 'Short Answer', 'TextboxField'), + 'memo' => array( /* @trans */ 'Long Answer', 'TextareaField'), + 'thread' => array( /* @trans */ 'Thread Entry', 'ThreadEntryField', false), + 'datetime' => array(/* @trans */ 'Date and Time', 'DatetimeField'), + 'phone' => array( /* @trans */ 'Phone Number', 'PhoneField'), + 'bool' => array( /* @trans */ 'Checkbox', 'BooleanField'), + 'choices' => array( /* @trans */ 'Choices', 'ChoiceField'), + 'break' => array( /* @trans */ 'Section Break', 'SectionBreakField'), ), ); static $more_types = array(); @@ -1017,7 +1017,7 @@ class PriorityField extends ChoiceField { ); } } -FormField::addFieldTypes(/*trans*/ 'Dynamic Fields', function() { +FormField::addFieldTypes(/*@trans*/ 'Dynamic Fields', function() { return array( 'priority' => array(__('Priority Level'), PriorityField), ); @@ -1028,27 +1028,27 @@ class TicketStateField extends ChoiceField { static $_states = array( 'open' => array( - 'name' => /* trans */ 'Open', - 'verb' => /* trans */ 'Open' + 'name' => /* @trans */ 'Open', + 'verb' => /* @trans */ 'Open' ), 'resolved' => array( - 'name' => /* trans */ 'Resolved', - 'verb' => /* trans */ 'Resolve' + 'name' => /* @trans */ 'Resolved', + 'verb' => /* @trans */ 'Resolve' ), 'closed' => array( - 'name' => /* trans */ 'Closed', - 'verb' => /* trans */ 'Close' + 'name' => /* @trans */ 'Closed', + 'verb' => /* @trans */ 'Close' ) ); // Private states static $_privatestates = array( 'archived' => array( - 'name' => /* trans */ 'Archived', - 'verb' => /* trans */ 'Archive' + 'name' => /* @trans */ 'Archived', + 'verb' => /* @trans */ 'Archive' ), 'deleted' => array( - 'name' => /* trans */ 'Deleted', - 'verb' => /* trans */ 'Delete' + 'name' => /* @trans */ 'Deleted', + 'verb' => /* @trans */ 'Delete' ) ); diff --git a/include/class.list.php b/include/class.list.php index 86a428c22..3decd37f9 100644 --- a/include/class.list.php +++ b/include/class.list.php @@ -433,7 +433,7 @@ class DynamicList extends VerySimpleModel implements CustomList { } } -FormField::addFieldTypes(/* trans */ 'Custom Lists', array('DynamicList', 'getSelections')); +FormField::addFieldTypes(/* @trans */ 'Custom Lists', array('DynamicList', 'getSelections')); /** * Represents a single item in a dynamic list diff --git a/include/class.note.php b/include/class.note.php index 5443c8b37..d16112d4e 100644 --- a/include/class.note.php +++ b/include/class.note.php @@ -27,8 +27,8 @@ class QuickNoteModel extends VerySimpleModel { class QuickNote extends QuickNoteModel { static $types = array( - 'U' => /* trans */ 'User', - 'O' => /* trans */ 'Organization', + 'U' => /* @trans */ 'User', + 'O' => /* @trans */ 'Organization', ); var $_staff; diff --git a/include/class.organization.php b/include/class.organization.php index ae6f88784..10bd20294 100644 --- a/include/class.organization.php +++ b/include/class.organization.php @@ -433,7 +433,7 @@ class OrganizationForm extends DynamicForm { } } -Filter::addSupportedMatches(/*trans*/ 'Organization Data', function() { +Filter::addSupportedMatches(/*@trans*/ 'Organization Data', function() { $matches = array(); foreach (OrganizationForm::getInstance()->getFields() as $f) { if (!$f->hasData()) diff --git a/include/class.staff.php b/include/class.staff.php index fa776422d..da2473c0e 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -671,7 +671,7 @@ class Staff extends AuthenticatedUser { $token = Misc::randCode(48); // 290-bits if (!$content) - return new Error(/* trans */ 'Unable to retrieve password reset email template'); + return new Error(/* @trans */ 'Unable to retrieve password reset email template'); $vars = array( 'url' => $ost->getConfig()->getBaseUrl(), diff --git a/include/class.template.php b/include/class.template.php index 28b6c9d0e..d8e2b8a5d 100644 --- a/include/class.template.php +++ b/include/class.template.php @@ -22,63 +22,63 @@ class EmailTemplateGroup { var $ht; var $_templates; static $all_groups = array( - 'sys' => /* trans */ 'System Management Templates', - 'ticket.user' => /* trans */ 'End-User Email Templates', - 'ticket.staff' => /* trans */ 'Agent Email Templates', + 'sys' => /* @trans */ 'System Management Templates', + 'ticket.user' => /* @trans */ 'End-User Email Templates', + 'ticket.staff' => /* @trans */ 'Agent Email Templates', ); static $all_names=array( 'ticket.autoresp'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'New Ticket Auto-response', - 'desc'=>/* trans */ 'Autoresponse sent to user, if enabled, on new ticket.'), + 'name'=>/* @trans */ 'New Ticket Auto-response', + 'desc'=>/* @trans */ 'Autoresponse sent to user, if enabled, on new ticket.'), 'ticket.autoreply'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'New Ticket Auto-reply', - 'desc'=>/* trans */ 'Canned Auto-reply sent to user on new ticket, based on filter matches. Overwrites "normal" auto-response.'), + 'name'=>/* @trans */ 'New Ticket Auto-reply', + 'desc'=>/* @trans */ 'Canned Auto-reply sent to user on new ticket, based on filter matches. Overwrites "normal" auto-response.'), 'message.autoresp'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'New Message Auto-response', - 'desc'=>/* trans */ 'Confirmation sent to user when a new message is appended to an existing ticket.'), + 'name'=>/* @trans */ 'New Message Auto-response', + 'desc'=>/* @trans */ 'Confirmation sent to user when a new message is appended to an existing ticket.'), 'ticket.notice'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'New Ticket Notice', - 'desc'=>/* trans */ 'Notice sent to user, if enabled, on new ticket created by an agent on their behalf (e.g phone calls).'), + 'name'=>/* @trans */ 'New Ticket Notice', + 'desc'=>/* @trans */ 'Notice sent to user, if enabled, on new ticket created by an agent on their behalf (e.g phone calls).'), 'ticket.overlimit'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'Over Limit Notice', - 'desc'=>/* trans */ 'A one-time notice sent, if enabled, when user has reached the maximum allowed open tickets.'), + 'name'=>/* @trans */ 'Over Limit Notice', + 'desc'=>/* @trans */ 'A one-time notice sent, if enabled, when user has reached the maximum allowed open tickets.'), 'ticket.reply'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'Response/Reply Template', - 'desc'=>/* trans */ 'Template used on ticket response/reply'), + 'name'=>/* @trans */ 'Response/Reply Template', + 'desc'=>/* @trans */ 'Template used on ticket response/reply'), 'ticket.activity.notice'=>array( 'group'=>'ticket.user', - 'name'=>/* trans */ 'New Activity Notice', - 'desc'=>/* trans */ 'Template used to notify collaborators on ticket activity (e.g CC on reply)'), + 'name'=>/* @trans */ 'New Activity Notice', + 'desc'=>/* @trans */ 'Template used to notify collaborators on ticket activity (e.g CC on reply)'), 'ticket.alert'=>array( 'group'=>'ticket.staff', - 'name'=>/* trans */ 'New Ticket Alert', - 'desc'=>/* trans */ 'Alert sent to agents, if enabled, on new ticket.'), + 'name'=>/* @trans */ 'New Ticket Alert', + 'desc'=>/* @trans */ 'Alert sent to agents, if enabled, on new ticket.'), 'message.alert'=>array( 'group'=>'ticket.staff', - 'name'=>/* trans */ 'New Message Alert', - 'desc'=>/* trans */ 'Alert sent to agents, if enabled, when user replies to an existing ticket.'), + 'name'=>/* @trans */ 'New Message Alert', + 'desc'=>/* @trans */ 'Alert sent to agents, if enabled, when user replies to an existing ticket.'), 'note.alert'=>array( 'group'=>'ticket.staff', - 'name'=>/* trans */ 'Internal Note Alert', - 'desc'=>/* trans */ 'Alert sent to selected agents, if enabled, on new internal note.'), + 'name'=>/* @trans */ 'Internal Note Alert', + 'desc'=>/* @trans */ 'Alert sent to selected agents, if enabled, on new internal note.'), 'assigned.alert'=>array( 'group'=>'ticket.staff', - 'name'=>/* trans */ 'Ticket Assignment Alert', - 'desc'=>/* trans */ 'Alert sent to agents on ticket assignment.'), + 'name'=>/* @trans */ 'Ticket Assignment Alert', + 'desc'=>/* @trans */ 'Alert sent to agents on ticket assignment.'), 'transfer.alert'=>array( 'group'=>'ticket.staff', - 'name'=>/* trans */ 'Ticket Transfer Alert', - 'desc'=>/* trans */ 'Alert sent to agents on ticket transfer.'), + 'name'=>/* @trans */ 'Ticket Transfer Alert', + 'desc'=>/* @trans */ 'Alert sent to agents on ticket transfer.'), 'ticket.overdue'=>array( 'group'=>'ticket.staff', - 'name'=>/* trans */ 'Overdue Ticket Alert', - 'desc'=>/* trans */ 'Alert sent to agents on stale or overdue tickets.'), + 'name'=>/* @trans */ 'Overdue Ticket Alert', + 'desc'=>/* @trans */ 'Alert sent to agents on stale or overdue tickets.'), ); function EmailTemplateGroup($id){ diff --git a/include/class.ticket.php b/include/class.ticket.php index daa241d91..acded0c81 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -56,8 +56,8 @@ class Ticket { // Status -- listed here until we have a formal status class static $STATUSES = array( - /* trans */ 'open', - /* trans */ 'closed', + /* @trans */ 'open', + /* @trans */ 'closed', ); function Ticket($id) { diff --git a/include/class.topic.php b/include/class.topic.php index f05f41ce1..1dd6d0b48 100644 --- a/include/class.topic.php +++ b/include/class.topic.php @@ -433,4 +433,4 @@ class Topic { } // Add fields from the standard ticket form to the ticket filterable fields -Filter::addSupportedMatches(/* trans */ 'Help Topic', array('topicId' => 'Topic ID'), 100); +Filter::addSupportedMatches(/* @trans */ 'Help Topic', array('topicId' => 'Topic ID'), 100); diff --git a/include/class.user.php b/include/class.user.php index 8130551a9..c7c668caf 100644 --- a/include/class.user.php +++ b/include/class.user.php @@ -586,16 +586,16 @@ class PersonsName { var $name; static $formats = array( - 'first' => array( /*trans*/ "First", 'getFirst'), - 'last' => array( /*trans*/ "Last", 'getLast'), - 'full' => array( /*trans*/ "First Last", 'getFull'), - 'legal' => array( /*trans*/ "First M. Last", 'getLegal'), - 'lastfirst' => array( /*trans*/ "Last, First", 'getLastFirst'), - 'formal' => array( /*trans*/ "Mr. Last", 'getFormal'), - 'short' => array( /*trans*/ "First L.", 'getShort'), - 'shortformal' => array(/*trans*/ "F. Last", 'getShortFormal'), - 'complete' => array( /*trans*/ "Mr. First M. Last Sr.", 'getComplete'), - 'original' => array( /*trans*/ '-- As Entered --', 'getOriginal'), + 'first' => array( /*@trans*/ "First", 'getFirst'), + 'last' => array( /*@trans*/ "Last", 'getLast'), + 'full' => array( /*@trans*/ "First Last", 'getFull'), + 'legal' => array( /*@trans*/ "First M. Last", 'getLegal'), + 'lastfirst' => array( /*@trans*/ "Last, First", 'getLastFirst'), + 'formal' => array( /*@trans*/ "Mr. Last", 'getFormal'), + 'short' => array( /*@trans*/ "First L.", 'getShort'), + 'shortformal' => array(/*@trans*/ "F. Last", 'getShortFormal'), + 'complete' => array( /*@trans*/ "Mr. First M. Last Sr.", 'getComplete'), + 'original' => array( /*@trans*/ '-- As Entered --', 'getOriginal'), ); function __construct($name, $format=null) { diff --git a/setup/cli/modules/i18n.php b/setup/cli/modules/i18n.php index c520483f7..04baeb734 100644 --- a/setup/cli/modules/i18n.php +++ b/setup/cli/modules/i18n.php @@ -406,13 +406,29 @@ class i18n_Compiler extends Module { break; case T_COMMENT: case T_DOC_COMMENT: - if (preg_match('`\*\s*trans\s*\*`', $T[1])) { + $translate = false; + $hints = array(); + if (preg_match('`^/\*+\s*@(\w+)`m', $T[1])) { + foreach (preg_split('`,\s*`m', $T[1]) as $command) { + $command = trim($command, " \n\r\t\"*/\\"); + @list($command, $args) = explode(' ', $command, 2); + switch ($command) { + case '@context': + $hints['context'] = trim($args, " \"*\n\t\r"); + case '@trans': + $translate = true; + default: + continue; + } + } + } + if ($translate) { // Find the next textual token list($S, $T) = $this->__read_next_string($tokens); - $string = array('forms'=>array($S['form']), 'line'=>$S['line']); + $string = array('forms'=>array($S['form']), 'line'=>$S['line']) + + $hints; if (isset($S['comments'])) - $string['comments'] = array_merge( - @$string['comments'] ?: array(), $S['comments']); + $string['comments'] = $S['comments']; $T_funcs[] = $string; } break; diff --git a/setup/doc/i18n.md b/setup/doc/i18n.md index 210489667..92409a0de 100644 --- a/setup/doc/i18n.md +++ b/setup/doc/i18n.md @@ -65,7 +65,7 @@ set something like this up: ```php class A { - static $name = /* trans */ 'Localized string'; + static $name = /* @trans */ 'Localized string'; } print __(A::$name); @@ -74,8 +74,8 @@ set something like this up: In this case the localized version of the class variable is translated when it is used — not when it is defined. -The `* trans *` text in comment is significant. Both the asterisks and the -term `trans` are used to signify that the phrase should be made +The `* @trans *` text in comment is significant. Both the asterisks and the +term `@trans` are used to signify that the phrase should be made translatable. The comment must also be placed immedately before or after the string without any other PHP symbols in between (like the semi-colon). -- GitLab