<p>If each locale uses the same TLD but uses a subfolder for localized content (i.e. example.com/en, example.com/de, etc.). You can move between development, staging, and production environments without having to change settings in the admin panel by simply using an absolute path in the Admin assets source URL setting (i.e. <code>/assets/img/uploads</code>) and a relative path for the File System Path there (i.e. <code>../public_html/assets/img/uploads</code>).</p>

<p>For more complicated setups, such as independent site URLs (i.e. example.com, example.co.uk, etc) for each locale, I've set asset paths by setting an assetsUrl environment variable in <code>general.php</code> like so:</p>

<pre><code>'example.com' =&gt; array(
    'environmentVariables' =&gt; array(
        'siteUrl'        =&gt; '//example.co.uk/',
        'assetsUrl'    =&gt; '//example.com/'
    )
)
</code></pre>

<p>Then in the Admin panel's assets source settings, I set a relative path for the File System Path and use the <code>{assetsUrl}</code> environment variable for the URL.</p>

<p><img src="https://i.sstatic.net/7u9YP.png" alt="Screenshot of Craft Assets Source Settings"></p>

<p>With this setup you can also move between development, staging, and production environments without having to change settings in the admin panel.</p>

<p>Once <code>{assetsUrl}</code> is set in the Admin panel for the URL, writing <code>{{ file.url }}</code> in your template will return the full URL using the assets source URL setting.</p>

<p>Or, you can link to assets (e.g. scripts) in your templates using the <code>assetsUrl</code> environment variable.</p>

<pre><code>{{ craft.config.environmentVariables['assetsUrl'] }}assets/js/main.js
</code></pre>

CC BY-SA 3.0
2014-06-12T03:53:48.107Z
Good point about when you actually do want to use per-language customized assets.
narration_sd
CC BY-SA 3.0
2014-06-12T04:17:12.650Z
(Nasty comment system here, cuts off thought) continuing: Your ../ style server paths are however only going to work for that case, if they do, as they are going to be relative to the language folder where the index.php is called. Have you verified that transforms are indeed successfully generated, and for all kinds of assets, language-specific or not? The other issue will be actual server folder layout, and possible open_basedir restrictions...
narration_sd
CC BY-SA 3.0
2014-06-12T05:41:54.737Z
I've added your case to the original question, for its uses, and would suggest that the usual non-localized assets should use the original answer, while for necessarily localized assets, with care to server circumstances and verification, your relative references can be useful. To cover both cases, you'd define each type of asset in their own Craft Asset Source.
narration_sd
CC BY-SA 3.0
2014-06-12T08:16:46.170Z
@narration_sd if I am getting this right, Stephens answer to use relative path notation for the File System Path has nothing to do with localized assets. It is just a simple way to link to the same folder from each locales subfolder (i.e. example.com/de).
carlcs
CC BY-SA 3.0
2014-06-12T20:24:16.260Z
Christian, you're correct, to the point. I was mistaken in late evening by Stephen referring to localized content, but indeed it's centralized content which would operate with site localization that he's pathed. However, I've just tested and confirmed that this ../ pathing does not fully work. Asset indexing in the main CP icon panel reports the path is mis-set, and I think this also interrupts further indexing, so that for my case S3 assets aren't set up as well, unless they perhaps were so previously. Craft will tell you to use full paths as in the other solution, and there are reasons...
narration_sd
CC BY-SA 3.0
2014-06-14T07:30:19.667Z
Ok, comments on the checked solution should explain why I chose it, even as I wished relative file paths might have  worked. I would mention here in the interest of clarity that the relative paths Stephen has used here are proper only for separate url-per-language (and a particular server layout), not for single-url-subdirectories form of language enabling. You have to think it through (or write a diagram) to see how each way would work, if it did. The last three comments on the checkmarked solution should explain what goes wrong if you try it. Unless you know another way... ;)
narration_sd
CC BY-SA 3.0
2014-06-14T08:29:07.250Z
Here's what I saw might be the case where Stephen's suggestion could work. Someone else will have to try it, as I lack the multiple free URLs. To prove it's sound, you'll need to kill all previously generated transform assets, as described in the third comment on the checked thread, and see if they actually regenerate. The case where it's possible this may work is the one Stephen was principally describing, where you have a URL per language, instead of a subdirectory per language. Good to see if that actually works, in that view.
narration_sd
CC BY-SA 3.0
2017-09-26T01:08:12.360Z
This example uses protocol relative URLs in the `environmentVariables` array. This is now considered an anti-pattern and using HTTPS is recommended. See: https://www.paulirish.com/2010/the-protocol-relative-url/
Ben Parizek
CC BY-SA 3.0
2014-06-12T03:36:10.490Z
2014-06-12T15:17:51.333Z
2014-06-12T15:17:51.333Z
Stephen Bowling
<p>Great answer above: <a href="https://craftcms.stackexchange.com/a/30/1056">https://craftcms.stackexchange.com/a/30/1056</a> Works like a charm.</p>

<p>But for multiple environments it can get pretty nasty to set up the file system for each environment individually. This is what I did to figure out the correct file system path:</p>

<pre><code>return array(
    '*' =&gt; array(
        ...
        'environmentVariables' =&gt; array(
            'assetsPath' =&gt; realpath(__DIR__ . '/../../public/assets')
        ),
    ),
    ...
);
</code></pre>

<p>The config path never changes, so it’s a good way to use it to figure out the assets path.</p>

<p><strong>Watch out:</strong> For PHP &lt; 5.3 it <a href="https://stackoverflow.com/a/11094813/2342963">has to be</a> </p>

<pre><code>'assetsPath' =&gt; realpath(dirname(__FILE__) . '/../../public/assets')
</code></pre>

CC BY-SA 3.0
2017-05-23T09:41:00.480Z
I like it :)  There's another method using environmental tags you set in the index.php which is bulletproof, but to extent this reliably functions, automation is great. Nice you've picked up the PHP level it needs to adjust to. Nice also to update this post, which is by now getting a bit 'properly aged'...people will find your answer here, upvoted.
narration_sd
CC BY-SA 3.0
2017-05-22T09:02:06.720Z
2017-05-22T09:12:00.717Z
2017-05-23T12:38:53.957Z
medoingthings
<p>An answer that works is to make your own environment variables, setting those apart from language variables, and as needed for each of your multiple sites. </p>

<p>Then you can use these variables to make full paths for your Asset definitions.</p>

<p>You'll need definitions for both the file system path and URL path. Let's name them appropriately so we don't get confused with {siteUrl}, which is common in a multilingual config or {{siteUrl}} which is the Twig variable resulting from whatever sets it for a given Craft site for templates, but not usable within CP configuration.</p>

<p>Here's an example config:</p>

<p><code>return array(
    'cpTrigger' => 'yourTrigger',
    'environmentVariables' => array(
        'siteStore' => '/storage/yourId/www/yoursite_html/',
        'sitePath'  => '<a href="http://yoursite.com/">http://yoursite.com/</a>',
    ),
    'siteUrl' => array(
        'en' => '<a href="http://yoursite.com/en/">http://yoursite.com/en/</a>',
        'de' => '<a href="http://yoursite.com/de/">http://yoursite.com/de/</a>',
        'fi' => '<a href="http://yoursite.com/fi/">http://yoursite.com/fi/</a>',
    ),
);</code></p>

<p>In the CP on a multi-language site, we'd fill in Assets->Sources->Local Images->File System path as:</p>

<pre><code>{siteStore}yourResources/images/
</code></pre>

<p>And to match, the URL would be set to:</p>

<pre><code>{sitePath}yourResources/images/
</code></pre>

<p>With this, your paths for images and their generated transforms will be stable and correct across languages as well as the default URL.</p>

<p>To extend across multiple development, staging, and live sites, you'd just replicate this extra config in the usual way, filling in suitable siteStore and sitePath values for each environment.</p>

CC BY-SA 3.0
2014-06-12T20:44:20.883Z
Ok, had to change the comment here, as though I appreciate Stephen's thought, it does turn out apparently to not work, details commented there. This is not exactly a surprise having traced the code in this area when I wanted to use relative paths also, and by matching Craftpersons' advice. Still interested, though, as there are aspects which haven't been covered. I think these will make another interesting Craft SE question...
narration_sd
CC BY-SA 3.0
2014-06-14T07:02:02.987Z
Ok, I've looked over this very carefully before checking this solution as the accepted one, and it will take more than one comment to explain that. I too wanted all-relative paths to work; it's how I found the problems, and I appreciate that a lot of favoriting of Stephen's proposal occurred because of this desire. However, I am pretty confident it just can't work at the present in Craft. It may appear to. Relative paths can indeed be correct for the Asset URL path. But relative paths can't work for the Asset File System path, because they will not be correct for transformed image generation.
narration_sd
CC BY-SA 3.0
2014-06-14T07:11:54.917Z
This means that when you have icons, reduced sizes, etc. as transforms, i a Locale-activated system their assets won't be generated. You may think they have been if you earlier used non-localized setup, as the files will be left from that. But if you clear them, by the CP button and by removing asset cache and site assets _name subdirectories for them, you'll find they will only regenerate if you have an absolute path for the File System Path. It's how Craft operates at present.
narration_sd
CC BY-SA 3.0
2014-06-14T07:26:01.303Z
Ok, my 'I think you'll find/as far as I know' edits were zapped by this timeout comment system, but you may assume them, please. To return to the issue of the URL path, yes, it can be made root-relative (/resources/images) instead of {SitePath}resources/images in the Asset definition form, if you keep it consistent between site rather than language variations, and want to go that way. I think I've come over to the full-path-everywhere point of view, after a lot of fiddling with otherwise, unless the Craft crew may change the situation, probably as they may be adding features. Cheers to all.
narration_sd
CC BY-SA 3.0
2014-06-14T08:25:08.000Z
And - of course there is one more thought, from that handy off-line engine where we get ideas. If it proves out, great, and then I would really wish to be able to check two answers. 'Correct' is generally a fallacy; usually it's works in this case, and/or works in that. We'll see if that's true here.
narration_sd
CC BY-SA 3.0
2014-06-12T03:13:31.797Z
2014-06-12T05:31:26.907Z
2014-06-12T05:31:26.907Z
narration_sd
<p>This is actually a fairly crucial matter, since relative paths definitely won't work with languages, unless you really want all assets in a given Source to be localized or at least copied to each language folder. As well, hard paths in the CP will fail with multi-environment config where dev, staging, and deployment sites can have different full storage paths.</p>

<p>Things may appear to operate at first with relative paths, for example, and it may feel like a safe way from experience with other systems, but then you'll find that features like automatic generation of image transforms that you've set up (icons, controlled sizes, etc.) will fail.</p>

<image-transforms><localization>
What accurately will set asset paths for multilingual sites?
# What accurately will set asset paths for multilingual sites?

(Asked by: username_0 on 2014-06-12)

This is actually a fairly crucial matter, since relative paths definitely won't work with languages, unless you really want all assets in a given Source to be localized or at least copied to each language folder. As well, hard paths in the CP will fail with multi-environment config where dev, staging, and deployment sites can have different full storage paths.

Things may appear to operate at first with relative paths, for example, and it may feel like a safe way from experience with other systems, but then you'll find that features like automatic generation of image transforms that you've set up (icons, controlled sizes, etc.) will fail.

**Tags:** image-transforms, localization

---

## 3 answers

### Answer by username_0 on 2014-06-12. Score: 9 | Accepted answer

An answer that works is to make your own environment variables, setting those apart from language variables, and as needed for each of your multiple sites. 
Then you can use these variables to make full paths for your Asset definitions.
You'll need definitions for both the file system path and URL path. Let's name them appropriately so we don't get confused with {siteUrl}, which is common in a multilingual config or {{siteUrl}} which is the Twig variable resulting from whatever sets it for a given Craft site for templates, but not usable within CP configuration.
Here's an example config:
return array(
    'cpTrigger' => 'yourTrigger',
    'environmentVariables' => array(
        'siteStore' => '/storage/yourId/www/yoursite_html/',
        'sitePath'  => 'http://yoursite.com/',
    ),
    'siteUrl' => array(
        'en' => 'http://yoursite.com/en/',
        'de' => 'http://yoursite.com/de/',
        'fi' => 'http://yoursite.com/fi/',
    ),
);
In the CP on a multi-language site, we'd fill in Assets->Sources->Local Images->File System path as:
{siteStore}yourResources/images/

And to match, the URL would be set to:
{sitePath}yourResources/images/

With this, your paths for images and their generated transforms will be stable and correct across languages as well as the default URL.
To extend across multiple development, staging, and live sites, you'd just replicate this extra config in the usual way, filling in suitable siteStore and sitePath values for each environment.

> **Comments:**
> **username_0**: Ok, had to change the comment here, as though I appreciate Stephen's thought, it does turn out apparently to not work, details commented there. This is not exactly a surprise having traced the code in this area when I wanted to use relative paths also, and by matching Craftpersons' advice. Still interested, though, as there are aspects which haven't been covered. I think these will make another interesting Craft SE question...  
> **username_0**: Ok, I've looked over this very carefully before checking this solution as the accepted one, and it will take more than one comment to explain that. I too wanted all-relative paths to work; it's how I found the problems, and I appreciate that a lot of favoriting of Stephen's proposal occurred because of this desire. However, I am pretty confident it just can't work at the present in Craft. It may appear to. Relative paths can indeed be correct for the Asset URL path. But relative paths can't work for the Asset File System path, because they will not be correct for transformed image generation.  
> **username_0**: This means that when you have icons, reduced sizes, etc. as transforms, i a Locale-activated system their assets won't be generated. You may think they have been if you earlier used non-localized setup, as the files will be left from that. But if you clear them, by the CP button and by removing asset cache and site assets _name subdirectories for them, you'll find they will only regenerate if you have an absolute path for the File System Path. It's how Craft operates at present.  
> **username_0**: Ok, my 'I think you'll find/as far as I know' edits were zapped by this timeout comment system, but you may assume them, please. To return to the issue of the URL path, yes, it can be made root-relative (/resources/images) instead of {SitePath}resources/images in the Asset definition form, if you keep it consistent between site rather than language variations, and want to go that way. I think I've come over to the full-path-everywhere point of view, after a lot of fiddling with otherwise, unless the Craft crew may change the situation, probably as they may be adding features. Cheers to all.  
> **username_0**: And - of course there is one more thought, from that handy off-line engine where we get ideas. If it proves out, great, and then I would really wish to be able to check two answers. 'Correct' is generally a fallacy; usually it's works in this case, and/or works in that. We'll see if that's true here.  

---

### Answer by username_1 on 2014-06-12. Score: 12

If each locale uses the same TLD but uses a subfolder for localized content (i.e. example.com/en, example.com/de, etc.). You can move between development, staging, and production environments without having to change settings in the admin panel by simply using an absolute path in the Admin assets source URL setting (i.e. /assets/img/uploads) and a relative path for the File System Path there (i.e. ../public_html/assets/img/uploads).
For more complicated setups, such as independent site URLs (i.e. example.com, example.co.uk, etc) for each locale, I've set asset paths by setting an assetsUrl environment variable in general.php like so:
'example.com' => array(
    'environmentVariables' => array(
        'siteUrl'        => '//example.co.uk/',
        'assetsUrl'    => '//example.com/'
    )
)

Then in the Admin panel's assets source settings, I set a relative path for the File System Path and use the {assetsUrl} environment variable for the URL.

With this setup you can also move between development, staging, and production environments without having to change settings in the admin panel.
Once {assetsUrl} is set in the Admin panel for the URL, writing {{ file.url }} in your template will return the full URL using the assets source URL setting.
Or, you can link to assets (e.g. scripts) in your templates using the assetsUrl environment variable.
{{ craft.config.environmentVariables['assetsUrl'] }}assets/js/main.js

> **Comments:**
> **username_0**: Good point about when you actually do want to use per-language customized assets.  
> **username_0**: (Nasty comment system here, cuts off thought) continuing: Your ../ style server paths are however only going to work for that case, if they do, as they are going to be relative to the language folder where the index.php is called. Have you verified that transforms are indeed successfully generated, and for all kinds of assets, language-specific or not? The other issue will be actual server folder layout, and possible open_basedir restrictions...  
> **username_0**: I've added your case to the original question, for its uses, and would suggest that the usual non-localized assets should use the original answer, while for necessarily localized assets, with care to server circumstances and verification, your relative references can be useful. To cover both cases, you'd define each type of asset in their own Craft Asset Source.  
> **username_2**: @narration_sd if I am getting this right, Stephens answer to use relative path notation for the File System Path has nothing to do with localized assets. It is just a simple way to link to the same folder from each locales subfolder (i.e. example.com/de).  
> **username_0**: Christian, you're correct, to the point. I was mistaken in late evening by Stephen referring to localized content, but indeed it's centralized content which would operate with site localization that he's pathed. However, I've just tested and confirmed that this ../ pathing does not fully work. Asset indexing in the main CP icon panel reports the path is mis-set, and I think this also interrupts further indexing, so that for my case S3 assets aren't set up as well, unless they perhaps were so previously. Craft will tell you to use full paths as in the other solution, and there are reasons...  
> **username_0**: Ok, comments on the checked solution should explain why I chose it, even as I wished relative file paths might have  worked. I would mention here in the interest of clarity that the relative paths Stephen has used here are proper only for separate url-per-language (and a particular server layout), not for single-url-subdirectories form of language enabling. You have to think it through (or write a diagram) to see how each way would work, if it did. The last three comments on the checkmarked solution should explain what goes wrong if you try it. Unless you know another way... ;)  
> **username_0**: Here's what I saw might be the case where Stephen's suggestion could work. Someone else will have to try it, as I lack the multiple free URLs. To prove it's sound, you'll need to kill all previously generated transform assets, as described in the third comment on the checked thread, and see if they actually regenerate. The case where it's possible this may work is the one Stephen was principally describing, where you have a URL per language, instead of a subdirectory per language. Good to see if that actually works, in that view.  
> **username_3**: This example uses protocol relative URLs in the `environmentVariables` array. This is now considered an anti-pattern and using HTTPS is recommended. See: https://www.paulirish.com/2010/the-protocol-relative-url/  

---

### Answer by username_4 on 2017-05-22. Score: 3

Great answer above: https://craftcms.stackexchange.com/a/30/1056 Works like a charm.
But for multiple environments it can get pretty nasty to set up the file system for each environment individually. This is what I did to figure out the correct file system path:
return array(
    '*' => array(
        ...
        'environmentVariables' => array(
            'assetsPath' => realpath(__DIR__ . '/../../public/assets')
        ),
    ),
    ...
);

The config path never changes, so it’s a good way to use it to figure out the assets path.
Watch out: For PHP < 5.3 it has to be 
'assetsPath' => realpath(dirname(__FILE__) . '/../../public/assets')

> **Comments:**
> **username_0**: I like it :)  There's another method using environmental tags you set in the index.php which is bulletproof, but to extent this reliably functions, automation is great. Nice you've picked up the PHP level it needs to adjust to. Nice also to update this post, which is by now getting a bit 'properly aged'...people will find your answer here, upvoted.  

---

