Phrase and beyond
How to Use Phrase Strings’ In-Context Editor
One of the most powerful and useful tools that Phrase Strings, the software localization platform within the Phrase Suite, offers is the in-context editor.
It is super easy to use and the functionality is well worth your time. Despite this, we still receive a lot of questions about how to properly use it.
Luckily I'm here to walk you through it, step by step.
So let's get started.
Installing the Phrase in-context editor
Because we love making your life easy, our editor already comes equipped with adapters for the most common web-frameworks.
And we'll be walking you through 4 of the most common.
You can also build your own custom integration if you can't find the framework you're looking for below.
1. Ruby on Rails (i18n)
The first step is going to be to add the gem:
Add the phraseapp-in-context-editor-ruby
gem to the environment you want to use the in-context editor with:
group :development do gem 'phraseapp-in-context-editor-ruby' end
Then install it using the bundle command.
Initialize the gem
Generate the initializer file for the in-context editor using the generator that ships with the gem:
bundle exec rails generate phraseapp_in_context_editor:install --access-token=YOUR_ACCESS_TOKEN --project-id=YOUR_PROJECT_ID
Access token
You can create and manage access tokens in your profile settings or via the Authorizations API.
Project-ID
You can find the ID of your project in your project settings in the translation center.
This will create an initializer file with some configuration options.
Activate in-context editor
Next you'll want to enable the in-context editor in your phraseapp_in_context_editor.rb
initializer file:
config.enabled = true
Add the JavaScript snippet
Add the JavaScript snippet to your application layout within the <head>
section by using the phraseapp_in_context_editor_js
helper:
<head> ... <%= phraseapp_in_context_editor_js %> ... </head>
Done
Open your application in the browser to see the in-context editor applied to your app. You can sign in with any of your Phrase users.
Turbolinks
There is a little workaround involved with making the in-context editor work with turbolinks.
To solve this little problem, we typically recommend disabling turbolinks when using editor by adding the data-no-turbolink
attribute to your body
tag:
<body <%= PhraseApp::InContextEditor.enabled? ? "data-no-turbolink" : "" %>>
Ruby on Rails Gem configuration
You can easily enable & disable the in-context editor.
However, this setting is only available when you're using the phraseapp-in-context-editor-ruby-gem.
Enabling or disabling the in-context editor will affect the inclusion of your JavaScript snippet when you're using the view helper as well as the rendering of decorated key names in your views.
PhraseApp::InContextEditor.enabled = true|false
You can bind the flag to an environment variable:
PhraseApp::InContextEditor.enabled = (ENV["IN_CONTEXT_EDITING"] == "1")
*Please remember that the in-context editor is disabled by default.*
2. AngularJS
Here's a quick rundown of it, but we've also got a more detailed guide on how to translate AngularJS applications in context. Either way, before we get into it, first you'll need to install angular-phrase if you haven't already done so.
If you don't already have angular-phrase
via Bower you can or download it manually by clicking this link.
bower install angular-phrase
Once that's settled we'll add the module to the AngularJS application
Add the angular-phrase
module to your existing AngularJS application after loading the angular-translate
module:
var myApp = angular.module("myApp", ['pascalprecht.translate', 'phrase']);
Configure the module:
myApp.value("phraseProjectId", "YOUR-PROJECT-ID"); myApp.value("phraseEnabled", true); myApp.value("phraseDecoratorPrefix", "{{__"); myApp.value("phraseDecoratorSuffix", "__}}");
You can find the ID of your project in your project settings in the translation center.
Add the JavaScript snippet
Add the phrase-javascript
directive inside the application. This is usually best within the <head>
: tag.
<phrase-javascript></phrase-javascript>
And you're done!
Open your application in the browser again to see the in-context editor applied to your application.
You can now sign in with any number of users currently in your Phrase organization.
That wasn't so bad.
3. Symfony 2.X
The first thing you're going to need to do here is to create a new environment.
We recommend creating a new environment in which the in-context editor will run. Let's just call this brand new environment translation
:
Start out by creating a new configuration file:
# app/config/config_translation.yml imports: - { resource: config.yml } parameters: translator.class: Acme\YourBundle\Translation\PhraseTranslator
The environment should be accessible in the browser, so next lets create a front controller for it:
# web/app_translation.php <?php require_once __DIR__.'/../app/bootstrap.php.cache'; require_once __DIR__.'/../app/AppKernel.php'; use Symfony\Component\HttpFoundation\Request; $kernel = new AppKernel('translation', false); $kernel->handle(Request::createFromGlobals())->send();
Extending the base translator
You need to override the standard translation method in order to expose the key names to the in-context editor:
# Acme/YourBundle/Translation/PhraseTranslator.php <?php namespace Acme\YourBundle\Translation; use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator; class PhraseTranslator extends BaseTranslator { public function trans($id, array $parameters = array(), $domain = 'messages', $locale = null) { $prefix = "{{__phrase_"; $suffix = "__}}"; if (!isset($locale)) { $locale = $this->getLocale(); } if (!isset($this->catalogues[$locale])) { $this->loadCatalogue($locale); } if ($domain == 'routes') { // Return translated values for 'routes' domain return strtr($this->catalogues[$locale]->get((string) $id, $domain), $parameters); } else { // Return PhraseApp translation keys for all other domains return $prefix.$id.$suffix; } } }
Add the JavaScript snippet
To load the in-context editor, you need to add the JavaScript snippet to your layout:
# Acme/YourBundle/Resources/views/layout.html.twig {% if app.environment == 'translation' %} <script> window.PHRASEAPP_CONFIG = { projectId: "YOUR-PROJECT-ID" }; (function() { var phraseapp = document.createElement('script'); phraseapp.type = 'text/javascript'; phraseapp.async = true; phraseapp.src = ['https://', 'phraseapp.com/assets/in-context-editor/2.0/app.js?', new Date().getTime()].join(''); var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(phraseapp, s); })(); </script> {% endif %}
Done
Start translating your app by accessing your front controller in the browser!
(The code for this step was generously provided by Malte Marx of marxbeck.)
4. Django
If you're using Django, this one's going to be super simple to implement.
Adding the package
Of course you'll first need to install the django-phrase
package with pip
:
pip install django-phrase
And add phrase
to the list of installed apps:
INSTALLED_APPS = ( 'phrase', )
Next, extend the template
You can now use the phrase_i18n
template tag in your templates:
{% load phrase_i18n %}
Note: You have to load phrase_i18n
after you load ì18n
in order to let django-phrase
override the translation methods.
Add the JavaScript snippet
Add the JavaScript snippet to your base layout file. This should go inside the <head> section of your template file:
{% phrase_javascript %}
Configuration
You can configure the in-context editor in your settings by using these options:
PHRASE_ENABLED = True PHRASE_PROJECT_ID = 'YOUR_PROJECT_ID' PHRASE_PREFIX = '{{__' PHRASE_SUFFIX = '__}}'
And you're done
Open your application in the browser to see the in-context editor applied to your application. Once again, you can sign in with any of your Phrase users.
Other frameworks
Custom Integration
If you weren't able to find the framework you're currently working with, don't despair! We've got instructions right here on how you can easily implement our in-context editor manually with your own system with custom integrations.
Configuring the editor
Now that you've finished installing the in-context editor on your framework it's time to configure everything.
You've got several options at this point that will help you to customize things so that it works smoothly with whatever software you're using.
Ignoring keys
This setting is likewise only available when using the ruby-gem.
Let's say that you don't want to include certain keys from being rendered in by the editor. If you're working with Rails those keys could include error messages or date/time formats.
If you want to exclude these keys from being handled automatically by the phraseapp-in-context-editor-ruby gem, all you have to do is add an array of keys to your phraseapp_in_context_editor.rb
initializer.
You can also use wildcards:
PhraseApp::InContextEditor.configure do |config| config.ignored_keys = ["date.*", "forbidden.key", "errors.messages*"] end
Keys that match one of these patterns won't be made accessible to the in-context editor but will instead be rendered normally.
Customize key decorators
If you're using in-context editor you would usually wrap the key name with "decorators" (by default they're those curly brackets) in order to to generate unique identification keys in context with your document:
{{__phrase_YOUR.KEY__}}
However, this can cause conflicts with other libraries such as client-side template engines like AngularJS or Ember.js) using similar syntax.
If you happen to find yourself having this problem, you may consider changing the Phrase in-context editor decorator prefix and suffix in your setup.
In order to tell the in-context editor which decorators the parser should be on the lookout for, all you have to do is add the following configuration values before the JavaScript snippet:
window.PHRASEAPP_CONFIG = { prefix: '[[__', suffix: "__]]" }
These configuration values will tell the editor to look for tags that begin with [[__
and end with __]].
For example:
[[__phrase_YOUR.KEY__]]
If you’re using the phraseapp-in-context-editor-ruby gem to provide in-context editor functions, you'll need to be sure that you have to configured your decorators there too:
PhraseApp::InContextEditor.configure do |config| config.prefix = "[[__" config.suffix = "__]]" end
If you're not using the gem, you'll need to make sure that you remember to adjust the key name exposure pattern in your custom code.
Debug mode
If for some reason you need to enable debug mode, all that is required is to add the following configuration before the JavaScript snippet:
window.PHRASEAPP_CONFIG = { debugMode: true }
Ajax mode
The Phrase in-context editor also supports Ajax and DOM manipulation (i.e. via JavaScript) out of the box.
In order to achieve this, we use mutation observers. Keep in mind, though, that mutation observers are only supported by modern browsers.
Ajax mode can sometimes cause problems that can result in severe performance issues with the in-context editor. If you want to disable Ajax mode, all you have to do is add this configuration before the JavaScript snippet:
window.PHRASEAPP_CONFIG = { ajaxObserver: false }
Auto lowercase
As a default setting, the in-context editor document parser will automatically convert all of your keys into lowercase.
If you’re experiencing issues with this behavior and would prefer to instead use case-sensitive keys with the in-context editor, you can disable this auto lowercase feature with this:
window.PHRASEAPP_CONFIG = { autoLowercase: false }
Force locale
If your goal is to set a specific locale when starting up the in-context editor you can use the forceLocale
setting to do so.
This would certainly make sense if you want to pre-select the locale that is currently displayed in your web application in the in-context editor as well.
window.PHRASEAPP_CONFIG = { forceLocale: "pt-BR" }
Direct links to your translated content
The in-context editor keeps track of the position of translatable content within your application.
Once set up we offer you backlinks to the in-context editor with the translation center interface, provided that you've added your in-context editor URL in your project's settings.
Make an environment for your translators
In order to use our in-context editor you're probably going to need to have a dedicated environment for your translators.
There are two ways that we can do this.
1. Use a dedicated environment
This is the method we recommend most strongly.
You can use a clone of one of your existing staging environments to create a dedicated environment for your translators.
If you decide to go with this route, the editor will always be enabled and your translators will be able to browse your website and make edits wherever they may be required.
While this may require a little bit more effort on your part in order to set up, we feel strongly that it will not only lead to a more streamlined workflow but will, in general, give your translators a much easier time.
2. Use an existing environment with a feature switch
If you really, really insist on not setting up a brand new, dedicated environment you can always use an existing one that comes equipped with a feature enabled or disabled.
If you're using a Ruby gem (our favorite, can't you tell?) it could end up looking something like this:
before_filter :toggle_in_context_editor ... def toggle_in_context_editor PhraseApp::InContextEditor.enabled = (params[:in_context_editor_enabled] == "1") end
Note, however, that if you're using our Ruby gem that this setting will impact the current thread. This might end up causing some strange behavior if you're working with multiple users in the same staging environment.
Again, we really do recommend the first option, but it's ultimately your call.
Conclusion
That wasn't too bad, was it?
Our in-context editor is a really powerful tool that, if set up properly, will massively enhance the ability of your translators to get things done efficiently and effectively.
We hope that this guide answers some of your questions and makes your life a bit simpler.
Last updated on February 20, 2024.