building your translation process
TRANSCRIPT
![Page 1: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/1.jpg)
Building your translation process
Tobias Nyholm
@tobiasnyholm
@tobiasnyholm
![Page 2: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/2.jpg)
@tobiasnyholm
Why?
![Page 3: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/3.jpg)
@tobiasnyholm
Language != CountryLanguage != Currency
![Page 4: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/4.jpg)
@tobiasnyholm
Why should we listen?• Don’t make my misstakes
• Show things I was struggling with
• Tell you of different processes
![Page 5: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/5.jpg)
@tobiasnyholm
Tobias Nyholm• Full stack unicorn on Happyr.com
• Sound of Symfony podcast
• Certified Symfony developer
• PHP-Stockholm
• Open source
![Page 6: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/6.jpg)
@tobiasnyholm
Open source
PHP-cache
HTTPlugMailgun
LinkedIn API clientSwap
Stampie
BazingaGeocoderBundlePHP-Geocoder
FriendsOfApi/boilerplateGuzzle Buzz
CacheBundlePSR7
SymfonyBundleTest
NSA
SimpleBus integrations
PSR HTTP clients
Neo4j
KNP Github API
![Page 7: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/7.jpg)
@tobiasnyholm
Open source
Happyr/TranslationBundle
Happyr/AutoFallbackTranslation
JMSTranslationBundle
Contributed toLexikTranslationBundle
![Page 8: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/8.jpg)
@tobiasnyholm
What is the translation component?
![Page 9: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/9.jpg)
@tobiasnyholm
Translator<?php
class Translator { public function addResource($format, $resource);
public function addLoader(LoaderInterface $loader);
public function trans($key, $params, $domain); }
![Page 10: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/10.jpg)
@tobiasnyholm
Loaders / Dumpers
![Page 11: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/11.jpg)
@tobiasnyholm
So how?
![Page 12: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/12.jpg)
@tobiasnyholm
MVPMy Very first Page
![Page 13: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/13.jpg)
@tobiasnyholm
MVP{% extends "::base.html.twig" %}
{% block body %} <h1>Welcome</h1> <p>My first paragraph.</p> {% endblock %}
![Page 14: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/14.jpg)
@tobiasnyholm
MVP{% extends "::base.html.twig" %}
{% block body %} <h1>{{ 'startpage.headig'|trans }}</h1> <p>{{ 'startpage.paragraph0'|trans }}</p> {% endblock %}
startpage: heading: 'Welcome' paragraph0: 'My first paragraph.'
![Page 15: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/15.jpg)
![Page 16: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/16.jpg)
@tobiasnyholm
Thank you. Questions?
![Page 17: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/17.jpg)
@tobiasnyholm
MVP
Add more users to your project?
![Page 18: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/18.jpg)
![Page 19: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/19.jpg)
![Page 20: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/20.jpg)
![Page 21: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/21.jpg)
@tobiasnyholm
Your translation source
![Page 22: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/22.jpg)
@tobiasnyholm
Your translation source
GIT
![Page 23: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/23.jpg)
@tobiasnyholm
Your translation sourceLoco (localise.biz) Transifex Crowdin OpenLocalization POEditor PhraseApp OneSky GetLocalization WebTranslateIt Locale Weblate
![Page 24: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/24.jpg)
![Page 25: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/25.jpg)
@tobiasnyholm
Download at each deployment
![Page 26: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/26.jpg)
@tobiasnyholm
Uploads?
![Page 27: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/27.jpg)
@tobiasnyholm
Translation file format
I don’t care(and neither should you)
![Page 28: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/28.jpg)
@tobiasnyholm
Use a converter
![Page 29: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/29.jpg)
@tobiasnyholm
<?php
class Converter { public function __construct(LoaderInterface $loader, $format) { $this->reader = new TranslationReader($loader, $format); $this->writer = new TranslationWriter(); $this->writer->addDumper('xlf', new XliffDumper()); } // ...
![Page 30: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/30.jpg)
@tobiasnyholm
public function convert($inputDir, $outputDir, array $locales) { $inputDir = realpath($inputDir); $inStorage = new FileStorage($this->writer, $this->reader, [$inputDir]);
$outputDir = realpath($outputDir); $outStorage = new FileStorage($this->writer, $this->reader, [$outputDir]);
foreach ($locales as $locale) { $inputCatalogue = new MessageCatalogue($locale); $outputCatalogue = new MessageCatalogue($locale);
$inStorage->export($inputCatalogue); foreach ($inputCatalogue->all() as $domain => $messages) { $outputCatalogue->add($messages, $domain); }
$outStorage->import($outputCatalogue); } } }
![Page 31: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/31.jpg)
@tobiasnyholm
URLs
![Page 32: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/32.jpg)
@tobiasnyholm
What about URLs?https://example.com/ https://example.com/svhttps://example.com/fr
https://example.com/en/price https://example.com/sv/price https://example.com/fr/price
https://example.com/my-account
![Page 33: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/33.jpg)
@tobiasnyholm
What about URLs?https://example.com/ https://sv.example.com/ https://fr.example.com/
https://example.com/price https://sv.example.com/price https://fr.example.com/price
https://example.com/my-account https://sv.example.com/my-account https://fr.example.com/my-account
![Page 34: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/34.jpg)
@tobiasnyholm
Show other languages<link rel="alternate" hreflang="sv" href="https://example.com/sv/">
<link rel="alternate" hreflang="en" href="https://example.com/en/">
<link rel="alternate" hreflang="fr" href="https://example.com/fr/">
![Page 35: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/35.jpg)
@tobiasnyholmclass LocaleResolver implements LocaleResolverInterface { public function resolveLocale(Request $request, array $availableLocales) { $locale = $this->getFromQueryParam($request); if (in_array($locale, $availableLocales)) { return $locale; } $locale = $this->getFromSession($request); if (in_array($locale, $availableLocales)) { return $locale; } $locale = $this->getFromCookie($request); if (in_array($locale, $availableLocales)) { return $locale; } $locale = $this->getFromUser(); if (in_array($locale, $availableLocales)) { return $locale; } $locale = $this->getFromIp($request); if (in_array($locale, $availableLocales)) { return $locale; } $locale = $this->getFromAcceptHeader($request, $availableLocales); if (in_array($locale, $availableLocales)) { return $locale; } return; } }
![Page 36: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/36.jpg)
@tobiasnyholm
Design
![Page 37: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/37.jpg)
@tobiasnyholm
Length of words
EN: Save user FI: tallenna käyttäjä
![Page 38: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/38.jpg)
@tobiasnyholm
Language switcher
![Page 39: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/39.jpg)
@tobiasnyholm
Arabic
لم أدفع ما يكفي من الترجمة
![Page 40: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/40.jpg)
@tobiasnyholmclass WhenRtlLanguageInjectStyle { public function onKernelResponse(FilterResponseEvent $event) { if (!$event->isMasterRequest()) { return; }
$locale = $event->getRequest()->getLocale(); if ($this->isRtlLanguage($locale)) { $this->injectToolbar($event->getResponse()); } }
private function injectToolbar(Response $response) { $content = $response->getContent(); if (false === $pos = stripos($content, '</HEAD>')) { return; }
$toolbar = '<style>html {direction: rtl; unicode-bidi: bidi-override;}</style>'; $content = substr($content, 0, $pos).$toolbar.substr($content, $pos); $response->setContent($content); }
private function isRtlLanguage($locale) { return $locale === 'ar'; } }
![Page 41: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/41.jpg)
@tobiasnyholm
Translations in JavaScript
![Page 42: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/42.jpg)
@tobiasnyholm
{% block toggle_button %} <a data-show-label="{{ 'show'|trans }}" data-hide-label="{{ 'hide'|trans }}” > {{ 'show'|trans }} </a> {% endblock %}
![Page 43: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/43.jpg)
@tobiasnyholm
![Page 44: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/44.jpg)
@tobiasnyholm
// translation.js.twig var Trans = { show: "{{ 'show'|trans }}", hide: "{{ 'hide'|trans }}" };
// Use it like: console.log(Trans.show);
![Page 45: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/45.jpg)
@tobiasnyholm
The process
![Page 46: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/46.jpg)
@tobiasnyholm
Adding new translation
![Page 47: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/47.jpg)
![Page 48: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/48.jpg)
@tobiasnyholm
Extract from source
![Page 49: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/49.jpg)
![Page 50: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/50.jpg)
![Page 51: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/51.jpg)
@tobiasnyholm
![Page 52: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/52.jpg)
@tobiasnyholm
Feature branches
Never change translations
![Page 53: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/53.jpg)
@tobiasnyholm
Feature branches
![Page 54: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/54.jpg)
@tobiasnyholm
Change translations
Key English Swedish Russian
user.apply.heading Foo Bar Baz
user.apply.get_started.button Start Börja начало
![Page 55: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/55.jpg)
@tobiasnyholm
Change translations
Key English Swedish Russian
user.apply.heading Foo Bar Baz
user.apply.get_started.button Read more Börja начало
![Page 56: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/56.jpg)
@tobiasnyholm
Deploy new translationsWhat to do when new translation is added?
A - Wait for all translators to finish before you deploy your changes
C - Use Google translate
B - Use your fallback locale
![Page 57: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/57.jpg)
@tobiasnyholm
Prioritize translation keys
![Page 58: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/58.jpg)
class TranslatorLogger { public function onTerminate(PostResponseEvent $event) { $messages = $this->translator->getCollectedMessages(); $missing = []; $fallback = []; $valid = [];
//Sort the messages foreach ($messages as $message) { if ($message['state'] === DataCollectorTranslator::MESSAGE_MISSING) { $missing[] = $message; } elseif ($message['state'] === DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK) { $fallback[] = $message; } else { $valid[] = $message; } }
$request = $event->getRequest(); $data = [ 'locale' => $request->getLocale(), 'host' => $request->getHost(), 'url' => $request->getUri(), 'messages' => $messages, ];
// Store in cache or send somewhere } }
![Page 59: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/59.jpg)
@tobiasnyholm
Context
![Page 60: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/60.jpg)
http://php-translation.readthedocs.io/en/latest/best-practice/index.html
![Page 61: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/61.jpg)
@tobiasnyholm
English is easy - Languages are hard
difficult
![Page 62: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/62.jpg)
@tobiasnyholm
Do not reuse keys
![Page 63: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/63.jpg)
@tobiasnyholm
“Users” - heading“Users” - link
![Page 64: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/64.jpg)
@tobiasnyholm
Clusivity
We’ve just won the lottery
![Page 65: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/65.jpg)
@tobiasnyholm
Direction
![Page 66: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/66.jpg)
@tobiasnyholm
Eskimos
50 words for snow
![Page 67: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/67.jpg)
@tobiasnyholm
Swedish
Swedish EnglishVal WhaleVal ElectionVal Choice
![Page 68: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/68.jpg)
@tobiasnyholm
Do not reuse keys
![Page 69: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/69.jpg)
@tobiasnyholm
Do not reuse keys
![Page 70: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/70.jpg)
@tobiasnyholm
DO NOT REUSE KEYS
![Page 71: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/71.jpg)
@tobiasnyholm
DO NOT REUSE KEYS(unless when you do)
![Page 72: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/72.jpg)
@tobiasnyholm
Work now Work later
![Page 73: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/73.jpg)
@tobiasnyholm
Tools
![Page 74: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/74.jpg)
@tobiasnyholm
ToolsPHP-Translation
GUI, Extractor, Saas integration, AutoFallback
JMSTranslatorBundle GUI, Extractor
LexikTranslationBundle GUI, DB-access
![Page 75: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/75.jpg)
@tobiasnyholm
CLI
![Page 76: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/76.jpg)
@tobiasnyholm
CLI
![Page 77: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/77.jpg)
@tobiasnyholm
![Page 78: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/78.jpg)
@tobiasnyholm
Questions?
https://joind.in/talk/a4245
![Page 79: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/79.jpg)
{% extends "::base.html.twig" %}
{% block body %} <h1>{{ 'startpage.headig'|trans }}</h1> <p>{{ 'startpage.paragraph0'|trans }}</p> <p> {{ 'startpage.paragraph1'|trans }} <a href="http://tnyholm.se" class="foo"> {{ 'startpage.clicking_here'|trans }} </a> </p> {% endblock %}
![Page 80: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/80.jpg)
{% extends "::base.html.twig" %}
{% block body %} <h1>{{ 'startpage.headig'|trans }}</h1> <p>{{ 'startpage.paragraph0'|trans }}</p> <p>{% trans with { '%url_start%':'<a href="http://tnyholm.se" class="foo">', '%url_end%':'</a>' } %}startpage.paragraph1{% endtrans %}</p> {% endblock %}
![Page 81: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/81.jpg)
startpage: heading: 'Welcome' paragraph0: 'My first paragraph.' paragraph1: 'Visit my website by %url_start%clicking here%url_end%.'
![Page 82: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/82.jpg)
@tobiasnyholm
Questions?
https://joind.in/talk/a4245
![Page 83: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/83.jpg)
![Page 84: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/84.jpg)
![Page 85: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/85.jpg)
@tobiasnyholm
Questions?
https://joind.in/talk/92db0
![Page 86: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/86.jpg)
{% extends "::base.html.twig" %}
{% block body %} <img src="{{ asset('images/foo'~app.request.locale~'.jpg') }}"> {% endblock %}
![Page 87: Building your translation process](https://reader035.vdocuments.mx/reader035/viewer/2022062906/5a6479eb7f8b9a40568b47e3/html5/thumbnails/87.jpg)
@tobiasnyholm
Questions?
https://joind.in/talk/a4245