Skip to content

Commit

Permalink
feat(TSE-1189): Add support for new In-Context Editor (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
itsahsiao authored Dec 7, 2023
1 parent e1c110d commit edc8400
Show file tree
Hide file tree
Showing 50 changed files with 10,777 additions and 85 deletions.
43 changes: 0 additions & 43 deletions Acme/YourBundle/Translation/PhraseTranslator.php

This file was deleted.

1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @Varpusparvi @francawinter @itsahsiao @lookasc @flowreaction @valeraine
66 changes: 66 additions & 0 deletions PhraseStringsInContextEditor/Translator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Service\PhraseStringsInContextEditor;

use Symfony\Bundle\FrameworkBundle\Translation\Translator as BaseTranslator;
use Symfony\Component\DependencyInjection\Attribute\When;
use Symfony\Component\Translation\MessageCatalogueInterface;
use Symfony\Component\Translation\TranslatorBagInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

#[When(env: 'dev')]
class Translator implements TranslatorInterface, TranslatorBagInterface, LocaleAwareInterface
{
private BaseTranslator $translator;

private bool $isPhraseEnabled = true;
private string $phrasePrefix = '{{__';
private string $phraseSuffix = '__}}';

public function __construct(BaseTranslator $translator)
{
$this->translator = $translator;
}

/**
* Translates accordingly based on if Phrase is enabled or not.
*/
public function trans(?string $id, array $parameters = [], string $domain = null, string $locale = null): string
{
if ($this->isPhraseEnabled) return $this->getPhraseStringsKey($id);

return $this->translator->trans($id, $parameters, $domain, $locale);
}

/**
* Converts the Id to a PhraseStrings-compatible Id.
*/
protected function getPhraseStringsKey(?string $id): string
{
if (!$id) return '';

return $this->phrasePrefix . 'phrase_' . $id . $this->phraseSuffix;
}

// below functions are needed due to the interfaces and do not have any custom logic
public function getLocale(): string
{
return $this->translator->getLocale();
}

public function setLocale(string $locale)
{
return $this->translator->setLocale($locale);
}

public function getCatalogue(string $locale = null): MessageCatalogueInterface
{
return $this->translator->getCatalogue($locale);
}

public function getCatalogues(): array
{
return $this->translator->getCatalogues();
}
}
136 changes: 94 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,115 @@
# Phrase In-Context Editor for Symfony2
# Phrase Strings In-Context Editor for Symfony

The Symfony2 adapter lets you to connect the [Phrase In-Context Editor](https://help.phrase.com/translate-website-and-app-content/use-in-context-editor-to-translate/translate-directly-on-your-website) to your Symfony2 application.
**phrase-in-context-editor-symfony** is the official adapter for integrating the [Phrase Strings In-Context Editor](https://support.phrase.com/hc/en-us/articles/5784095916188-In-Context-Editor-Strings) with your Symfony application.

For more information, read the [documentation](https://help.phrase.com/).
## :scroll: Documentation

## Installation ##
### Prerequisites

We recommend creating a new environment in which the In-Context Editor is available. Let's call the new environment "translation":
To use the In-Context Editor with your application you have to:

Start by creating a new configuration file:
* Sign up for a Phrase account: [https://app.phrase.com/signup](https://app.phrase.com/signup)
* Use the [Symfony](https://symfony.com/) framework for PHP

# app/config/config_translation.yml
imports:
- { resource: config.yml }
parameters:
translator.class: Acme\YourBundle\Translation\PhraseTranslator
**Note:** Version 2.0.0 supports Symfony 5 and up, along with a new version of the ICE. If you are using Symfony 2, 3, 4, please [check out to version 1.0.0 and follow the README there](https://github.com/phrase/phrase-in-context-editor-symfony/blob/v1.0.0/README.md).

The environment should be accessible in the browser, so we should create a front controller for it:
### Demo

# web/app_translation.php
<?php
You can find a demo project in the `demo` folder, just follow [the README.md in that folder](https://github.com/phrase/phrase-in-context-editor-symfony/tree/master/demo) to start up the app and try out the In-Context Editor for Symfony. Feel free to check out the sample code too!

require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppKernel.php';
### Installation

use Symfony\Component\HttpFoundation\Request;
Follow these steps to integrate the In-Context Editor with your Symfony application.

$kernel = new AppKernel('translation', false);
$kernel->handle(Request::createFromGlobals())->send();
1. Copy `PhraseStringsInContextEditor` and its contents from this repository into your repository's `/src/Service` folder or wherever you would like to place it. Make sure to adjust the namespace accordingly if you decide to place it somewhere else.

Add the "PhraseTranslator" class to your bundle. It will override the standard translation method to expose the translation keys to the In-Context Editor.
2. Adjust `config/services.yaml` to decorate the `translator` service with our adapter:
```yaml
services:
...
App\Service\PhraseStringsInContextEditor\Translator:
decorates: translator
```
When everything is in place, add the JavaScript snippet to your layout:
3. Add this JavaScript snippet to your base or layout Twig template between the `{% block javascripts %}` so the In-Context Editor can read the webpage:
```js
<script>
window.PHRASEAPP_CONFIG = {
accountId: '0bed59e5',
projectId: '00000000000000004158e0858d2fa45c',
datacenter: 'eu',
origin: 'phrase-symfony',
};
(function() {
var phrasejs = document.createElement('script');
phrasejs.type = 'module';
phrasejs.async = true;
phrasejs.src = 'https://d2bgdldl6xit7z.cloudfront.net/latest/ice/index.js'
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(phrasejs, s);
})();
</script>
```

# 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://', 'phrase.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 %}
You can find your Project-ID and Account-ID in the Phrase Translation Center.

You can find your Project-ID in the Phrase Translation Center.
4. Your application is now connected to the In-Context Editor. Reload your application and login with your Phrase credentials to start the translation process directly on your webpage!

Your application is connected to the In-Context Editor. Reload your application to start the translation process!
### Development

### More Information ###
#### Translate in Symfony with ICE
As our adapter is now decorating the translator service, you wTranslate as you would normally would in Symfony:

* https://phrase.com/
* https://help.phrase.com/
1. Through the `translator` service's `trans` method, e.g. translating from inside a controller:
```php
$translated = $translate->trans('key_name');
```

*The code in this tutorial was originally created by Malte Marx from [marxbeck](http://www.marxbeck.de)*
2. Through the `trans` filter in a twig template:
```
{{ 'key_name'|trans }}
```

## Get help / support
See [Symfony docs on translations](https://symfony.com/doc/current/translation.html) for more details on how to handle translations.

Please contact [[email protected]](mailto:[email protected]?subject=[GitHub]%20) and we can take more direct action toward finding a solution.
#### Using the old version of ICE
To use the old version of ICE, add the option `useOldICE: true` to your config in the JavaScript snippet:
```js
window.PHRASEAPP_CONFIG = {
accountId: '0bed59e5',
projectId: '00000000000000004158e0858d2fa45c',
datacenter: 'eu',
origin: 'phrase-symfony',
useOldICE: true,
};
```

#### Using the US Datacenter with ICE
In addition to the settings in your config, set the US datacenter to enable it working with the US endpoints.
```js
datacenter: 'us',
```

#### Setting the ICE for a Different Environment
If you want the ICE running on a different environment instead of `dev`, change the env on Line 12 in the Translator file:
```php
# PhraseStringsInContextEditor\Translator.php
#[When(env: 'dev')]
```

## :white_check_mark: Commits & Pull Requests

We welcome anyone who wants to contribute to our codebase, so if you notice something, feel free to open a Pull Request! However, we ask that you please use the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification for your commit messages and titles when opening a Pull Request.

Example: `chore: Update README`

## :question: Issues, Questions, Support

Please use [GitHub issues](https://github.com/phrase/Flask-Phrase/issues) to share your problem, and we will do our best to answer any questions or to support you in finding a solution.

## :books: Resources

* [Installing & Setting Up the Symfony Framework](https://symfony.com/doc/current/setup.html)
* [Localization Guides and Software Translation Best Practices](http://phrase.com/blog/)
* [Phrase Help Center](https://support.phrase.com/)
* [Contact Phrase Team](https://phrase.com/contact)
41 changes: 41 additions & 0 deletions demo/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
# https://symfony.com/doc/current/configuration/secrets.html
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration

###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=e9a3e1ba264ffb7a98e65fd48e5391a4
###< symfony/framework-bundle ###

###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
# DATABASE_URL="mysql://app:[email protected]:3306/app?serverVersion=8.0.32&charset=utf8mb4"
# DATABASE_URL="mysql://app:[email protected]:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4"
DATABASE_URL="postgresql://app:[email protected]:5432/app?serverVersion=15&charset=utf8"
###< doctrine/doctrine-bundle ###

###> symfony/messenger ###
# Choose one of the transports below
# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages
MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
###< symfony/messenger ###

###> symfony/mailer ###
# MAILER_DSN=null://null
###< symfony/mailer ###
6 changes: 6 additions & 0 deletions demo/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
20 changes: 20 additions & 0 deletions demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

###> symfony/framework-bundle ###
/.env.local
/.env.local.php
/.env.*.local
/config/secrets/prod/prod.decrypt.private.php
/public/bundles/
/var/
/vendor/
###< symfony/framework-bundle ###

###> phpunit/phpunit ###
/phpunit.xml
.phpunit.result.cache
###< phpunit/phpunit ###

###> symfony/phpunit-bridge ###
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###
32 changes: 32 additions & 0 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Demo Symfony Application with Phrase Strings In-Context Editor

This demo application uses Symfony version 6.3.10.

## Prerequisites
* PHP 8.2 or higher
* Symfony CLI

See [Symfony docs re: technical requirements](https://symfony.com/doc/current/setup.html#technical-requirements)

## Installation
1. Git clone the base repository and cd into this folder
```bash
git clone [email protected]:phrase/phrase-symfony2.git
cd phrase-symfony/demo
```

2. Install dependencies
```bash
symfony composer install
```

3. Start up the server
```bash
symfony server:start
```

4. Go to [http://localhost:8000](http://localhost:8000) and start playing around with the In-Context Editor to translate directly on the webpage!




17 changes: 17 additions & 0 deletions demo/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env php
<?php

use App\Kernel;
use Symfony\Bundle\FrameworkBundle\Console\Application;

if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) {
throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".');
}

require_once dirname(__DIR__).'/vendor/autoload_runtime.php';

return function (array $context) {
$kernel = new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);

return new Application($kernel);
};
Loading

0 comments on commit edc8400

Please sign in to comment.