Skip to content

Commit

Permalink
Merge pull request #61 from CloudCannon/feat/origin-urls
Browse files Browse the repository at this point in the history
Add "Default language at root" option
  • Loading branch information
Tate-CC authored Aug 15, 2024
2 parents 32fd761 + fc22e33 commit cdb0467
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 26 deletions.
10 changes: 6 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ ClientBin/
*.publishsettings
orleans.codegen.cs

# Including strong name files can present a security risk
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk

Expand Down Expand Up @@ -320,7 +320,7 @@ __pycache__/
# OpenCover UI analysis results
OpenCover/

# Azure Stream Analytics local run output
# Azure Stream Analytics local run output
ASALocalRun/

# MSBuild Binary and Structured Log
Expand All @@ -329,7 +329,7 @@ ASALocalRun/
# NVidia Nsight GPU debugger configuration file
*.nvuser

# MFractors (Xamarin productivity tool) working folder
# MFractors (Xamarin productivity tool) working folder
mfractor/

#nyc
Expand All @@ -339,4 +339,6 @@ coverage
source
dest

cache
cache

docs/public
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

## Unreleased

* Adds the ability to build the default language to the root path, rather than placing it under a language code.
* See [Docs > Build > Default language at root](https://rosey.app/docs/build/#default-language-at-root) for more information.

## v2.1.1 (August 13, 2024)

* Fixes the Windows release of Rosey via npm
Expand Down
17 changes: 17 additions & 0 deletions docs/content/docs/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ The default language for the site (i.e. the language of 'source.json'). Defaults
|-------------------------------|--------------------------|--------------------|
| `--default-language <STRING>` | `ROSEY_DEFAULT_LANGUAGE` | `default_language` |

### Default language at root

Configures Rosey to retain input URLs for the default language.

By default, Rosey will place the default language under a language code, e.g. `/en/index.html`,
and will generate a redirect file at `/index.html`.

By setting this flag, Rosey will output the default language at the root path, e.g. `/index.html`.

By setting this flag, Rosey will not generate any redirect pages.

| CLI Flag | ENV Variable | Config Key |
|-------------------------------|----------------------------------|----------------------------|
| `--default-language-at-root` | `ROSEY_DEFAULT_LANGUAGE_AT_ROOT` | `default_language_at_root` |

### Exclusions

A regular expression used to determine which files not to copy as assets. Defaults to `\.(html?|json)$`
Expand All @@ -70,6 +85,8 @@ The source folder that Rosey should look for translated images within. If omitte

Path to a custom redirect template that Rosey should use for the base URL.

This option is ignored if you have set the "Default language at root" flag.

| CLI Flag | ENV Variable | Config Key |
|--------------------------|-----------------------|-----------------|
| `--redirect-page <FILE>` | `ROSEY_REDIRECT_PAGE` | `redirect_page` |
Expand Down
5 changes: 4 additions & 1 deletion docs/content/docs/urls.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ weight: 6

Rosey URL locale files can contain translated URLs for your website in a given language.

If you just want to move one language to the root of the site, e.g. serve `/en/index.html` at `index.html` instead, see the
[Default language at root](/docs/build/#default-language-at-root) option for Rosey's build step.

## Creating translated URL locale files

Creating URL locale files is not a step performed by Rosey. This part of the translation workflow is left open ended, usually integrating into an existing translation workflow for a company, or being programmatically created by transforming the input URLs.
Expand Down Expand Up @@ -51,7 +54,7 @@ The `rosey/locales/ja-jp.urls.json` locale file should match the structure:
}
```

Each of these keys is an object with `original` and `value` strings. The `value` string should contain the translated destination file, and will be used by Rosey when building your final multilingual site.
Each of these keys is an object with `original` and `value` strings. The `value` string should contain the translated destination file, and will be used by Rosey when building your final multilingual site.

The output should always include the `.html` extension. Rosey will remove any trailing `index.html` filename where able.

Expand Down
90 changes: 90 additions & 0 deletions rosey/features/build/rosey-build-root-language.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Feature: Rosey Build Using Root Language URLs
Background:
Given I have the environment variables:
| ROSEY_SOURCE | dist/site |
| ROSEY_DEST | dist/translated_site |

Scenario: Rosey can build the default language to the root URLs
Given I have a "dist/site/index.html" file with the content:
"""
<html>
<body>
<p data-rosey="p">english sentence</p>
</body>
</html>
"""
And I have a "dist/site/about.html" file with the content:
"""
<html>
<body>
<h1><a href="/posts/hello-world">Hello World</a></h1>
</body>
</html>
"""
And I have a "rosey/locales/blank.json" file with the content:
"""
{
"p": "------- --------"
}
"""
And I have a "rosey/locales/nada.json" file with the content:
"""
{
"p": "de nada"
}
"""
When I run my program with the flags:
| build |
| --default-language-at-root |

Then I should not see the file "dist/translated_site/en/index.html"
Then I should not see the file "dist/translated_site/en/about.html"

And I should see a selector 'p' in "dist/translated_site/index.html" with the attributes:
| data-rosey | p |
| innerText | english sentence |
And I should see a selector 'p' in "dist/translated_site/nada/index.html" with the attributes:
| data-rosey | p |
| innerText | de nada |

Then I should see a selector 'h1>a' in "dist/translated_site/about.html" with the attributes:
| href | /posts/hello-world |
| innerText | Hello World |

Then I should not see a selector 'link' in "dist/translated_site/about.html" with the attributes:
| rel | alternate |
| href | /en/about.html |
| hreflang | en |
Then I should see a selector 'link' in "dist/translated_site/about.html" with the attributes:
| rel | alternate |
| href | /blank/about.html |
| hreflang | blank |
Then I should see a selector 'link' in "dist/translated_site/about.html" with the attributes:
| rel | alternate |
| href | /nada/about.html |
| hreflang | nada |

Then I should see a selector 'link' in "dist/translated_site/blank/about.html" with the attributes:
| rel | alternate |
| href | /about.html |
| hreflang | en |
Then I should see a selector 'link' in "dist/translated_site/blank/about.html" with the attributes:
| rel | alternate |
| href | /nada/about.html |
| hreflang | nada |

Then I should see a selector 'link' in "dist/translated_site/blank/index.html" with the attributes:
| rel | alternate |
| href | / |
| hreflang | en |
Then I should see a selector 'link' in "dist/translated_site/blank/index.html" with the attributes:
| rel | alternate |
| href | /nada/ |
| hreflang | nada |

Then I should see a selector 'meta' in "dist/translated_site/index.html" with the attributes:
| http-equiv | content-language |
| content | en |
Then I should see a selector 'meta' in "dist/translated_site/blank/index.html" with the attributes:
| http-equiv | content-language |
| content | blank |
11 changes: 7 additions & 4 deletions rosey/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ impl RoseyOptions {
std::process::exit(1);
});

if !matches!(subcommand, RoseyCommand::Check) && original_source.to_string_lossy().is_empty() {
if !matches!(subcommand, RoseyCommand::Check)
&& original_source.to_string_lossy().is_empty()
{
eprintln!(
"Rosey requires a source directory to process. Provide either: \n\
• A `--source <PATH>` CLI flag \n\
Expand Down Expand Up @@ -109,6 +111,7 @@ impl RoseyOptions {
base: working_dir.join(matches.get("base", base.base)),
base_urls: working_dir.join(matches.get("base-urls", base.base_urls)),
default_language: matches.get("default-language", base.default_language),
default_language_at_root: matches.is_present("default-language-at-root") || base.default_language_at_root,
redirect_page: matches
.get_opt("redirect-page", base.redirect_page)
.map(|p| working_dir.join(p)),
Expand All @@ -117,8 +120,8 @@ impl RoseyOptions {
.get_opt("images-source", base.images_source)
.map(|p| working_dir.join(p)),
wrap: match matches.values_of("wrap") {
Some(langs) => Some(langs.map(|l|{
Some(langs) => Some(langs.map(|l|{

if !SUPPORTED_WRAP_LANGS.iter().any(|lang| l.starts_with(lang)) {
eprintln!("Cannot wrap text for language '{l}'. Languages with supported text wrapping: {SUPPORTED_WRAP_LANGS:?}");
std::process::exit(1);
Expand Down Expand Up @@ -338,4 +341,4 @@ pub fn inline_templates(dom: &kuchiki::NodeRef) {
node.append(contents.clone());
}
})
}
}
7 changes: 7 additions & 0 deletions rosey/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ async fn main() {
.takes_value(true)
.help("The source folder that Rosey should look for translated images within. \n ─ Defaults to the source folder"),
)
.arg(
Arg::with_name("default-language-at-root")
.long("default-language-at-root")
.takes_value(false)
.conflicts_with("redirect-page")
.help("Configures Rosey to leave all input URLs in-place for the default language, and omit generating redirect files"),
)
.arg(
Arg::with_name("redirect-page")
.long("redirect-page")
Expand Down
25 changes: 20 additions & 5 deletions rosey/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct RoseyPublicConfig {
pub images_source: Option<PathBuf>,
pub default_language: String,
pub redirect_page: Option<PathBuf>,
pub default_language_at_root: bool,
pub wrap: Option<Vec<String>>,
pub wrap_class: Option<String>,
pub verbose: bool,
Expand All @@ -43,6 +44,7 @@ impl Default for RoseyPublicConfig {
images_source: None,
default_language: "en".into(),
redirect_page: None,
default_language_at_root: false,
wrap: None,
wrap_class: None,
verbose: false,
Expand Down Expand Up @@ -73,19 +75,32 @@ impl Display for RoseyPublicConfig {
writeln!(f, " - Base locale file: {}", self.base.display())?;
writeln!(f, " - Base urls file: {}", self.base_urls.display())?;
writeln!(f, " - Locales directory: {}", self.locales.display())?;

match &self.images_source {
Some(s) => writeln!(f, " - Images source: {}", s.display())?,
None => writeln!(
f,
" - Images source: * unset, using source directory *"
)?,
}
match &self.redirect_page {
Some(s) => writeln!(f, " - Redirect page: {}", s.display())?,
None => writeln!(

if self.default_language_at_root {
writeln!(f, " - Root URLs: Default language")?;

writeln!(
f,
" - Redirect page: * unset, using default redirect template *"
)?,
" - Redirect page: * ignored, root urls are default language *"
)?
} else {
writeln!(f, " - Root URLs: Generated redirect page")?;

match &self.redirect_page {
Some(s) => writeln!(f, " - Redirect page: {}", s.display())?,
None => writeln!(
f,
" - Redirect page: * unset, using default redirect template *"
)?,
}
}

writeln!(f, " Options:")?;
Expand Down
46 changes: 34 additions & 12 deletions rosey/src/runners/builder/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl RoseyBuilder {
&config.tag,
images_source.to_owned(),
&config.default_language,
config.default_language_at_root,
&self.translations,
&config.wrap,
&config.wrap_class,
Expand Down Expand Up @@ -82,16 +83,21 @@ impl RoseyBuilder {
.map(Into::into)
.unwrap_or_else(|| relative_path.to_owned());

let output_path = dest_folder
.join(&config.default_language)
.join(translated_default_url);
page.output_file(&output_path);
if config.default_language_at_root {
let output_path = dest_folder.join(translated_default_url);
page.output_file(&output_path);
} else {
let output_path = dest_folder
.join(&config.default_language)
.join(translated_default_url);
page.output_file(&output_path);

self.output_redirect_file(
&config.default_language,
relative_path,
&self.url_translations,
);
self.output_redirect_file(
&config.default_language,
relative_path,
&self.url_translations,
);
}

self.translations.keys().for_each(|key| {
let url_translations = self.url_translations.get(key);
Expand Down Expand Up @@ -216,6 +222,7 @@ struct RoseyPage<'a> {
assets: Vec<(String, String, NodeRef)>,
locale_key: Option<&'a str>,
should_wrap: bool,
default_language_at_root: bool,
wrap: &'a Option<Vec<String>>,
wrap_class: &'a Option<String>,
pub tag: String,
Expand All @@ -232,6 +239,7 @@ impl<'a> RoseyPage<'a> {
tag: &str,
images_source: PathBuf,
default_language: &str,
default_language_at_root: bool,
translations: &'a BTreeMap<String, RoseyTranslation>,
wrap: &'a Option<Vec<String>>,
wrap_class: &'a Option<String>,
Expand All @@ -255,6 +263,7 @@ impl<'a> RoseyPage<'a> {
translations,
locale_key: None,
should_wrap: false,
default_language_at_root,
wrap,
wrap_class,
}
Expand Down Expand Up @@ -344,8 +353,15 @@ impl<'a> RoseyPage<'a> {

let output = parsed.as_str().trim_start_matches(base_url.as_str());

let output_href =
if locale_key == self.default_language && self.default_language_at_root {
format!("/{output}")
} else {
format!("/{locale_key}/{output}")
};

attributes.remove("href");
attributes.insert("href", format!("/{locale_key}/{output}"));
attributes.insert("href", output_href);
}
}

Expand Down Expand Up @@ -605,10 +621,16 @@ impl<'a> RoseyPage<'a> {
attributes.insert("hreflang", String::from(key));
}

let output_href = if key == self.default_language && self.default_language_at_root {
format!("/{translated_path}")
} else {
format!("/{key}/{translated_path}")
};

if let Some(href) = attributes.get_mut("href") {
*href = format!("/{key}/{translated_path}");
*href = output_href;
} else {
attributes.insert("href", format!("/{key}/{translated_path}"));
attributes.insert("href", output_href);
}
}
}
Expand Down

0 comments on commit cdb0467

Please sign in to comment.