Skip to content

🍞 Check for old / stale translations#117

Open
Jasper-Bekkers wants to merge 1 commit into
longbridge:mainfrom
Traverse-Research:stale-translations
Open

🍞 Check for old / stale translations#117
Jasper-Bekkers wants to merge 1 commit into
longbridge:mainfrom
Traverse-Research:stale-translations

Conversation

@Jasper-Bekkers

Copy link
Copy Markdown
Contributor

I noticed in our application we had some phrases that still existed in our app.yml file, but weren't used in the application anymore, causing unnecessary work for our translators. This PR adds a bit of code to detect these and write out a STALE.yml file (next to TODO.yml) so they can be manually removed.

@huacnlee

Copy link
Copy Markdown
Member

I'd like this feature.

But I think, if we can instead to use print with line of number of the stale I18n keys will be better.

- locales/en.yml:120     hello_world

@huacnlee huacnlee requested a review from Copilot July 15, 2025 01:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a feature to detect unused translation keys and output them to a STALE.yml file, helping translators remove obsolete entries.

  • Introduces a stale function in generator.rs that scans existing locale files and identifies keys no longer used.
  • Adds a find_stale_translations helper to collect stale entries per locale.
  • Hooks the stale check into the CLI (main.rs) so CI fails when stale translations are found.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
crates/extract/src/generator.rs Added stale and find_stale_translations functions to emit STALE.yml
crates/cli/src/main.rs Invoked generator::stale before generate and handled its error flag

write_file(&output_path, filename, &text)?;

// Finally, return error for let CI fail
let err = std::io::Error::new(std::io::ErrorKind::Other, "");

Copilot AI Jul 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Providing an empty error message makes CI failures hard to debug; include a descriptive message like "Found stale translations" to clarify the failure reason.

Suggested change
let err = std::io::Error::new(std::io::ErrorKind::Other, "");
let err = std::io::Error::new(std::io::ErrorKind::Other, "Stale translations detected. Please review the generated file.");

Copilot uses AI. Check for mistakes.
Comment on lines +105 to +108
let output_path = output_path.as_ref().display().to_string();

let ignore_file = |fname: &str| fname.ends_with(&output_filename);
let data = load_locales(&output_path, ignore_file);

Copilot AI Jul 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] This shadows the output_path parameter with a String, which can be confusing; consider renaming the local variable or performing this conversion outside of the loop.

Suggested change
let output_path = output_path.as_ref().display().to_string();
let ignore_file = |fname: &str| fname.ends_with(&output_filename);
let data = load_locales(&output_path, ignore_file);
let output_path_str = output_path.as_ref().display().to_string();
let ignore_file = |fname: &str| fname.ends_with(&output_filename);
let data = load_locales(&output_path_str, ignore_file);

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +108
for locale in all_locales {
println!("Checking [{}] for stale translations...", locale);

// ~/work/my-project/locales
let output_path = output_path.as_ref().display().to_string();

let ignore_file = |fname: &str| fname.ends_with(&output_filename);
let data = load_locales(&output_path, ignore_file);

Copilot AI Jul 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Converting output_path to a String on every iteration incurs unnecessary overhead; move this conversion before the for locale loop.

Suggested change
for locale in all_locales {
println!("Checking [{}] for stale translations...", locale);
// ~/work/my-project/locales
let output_path = output_path.as_ref().display().to_string();
let ignore_file = |fname: &str| fname.ends_with(&output_filename);
let data = load_locales(&output_path, ignore_file);
// Convert output_path to a String once before the loop
let output_path_str = output_path.as_ref().display().to_string();
for locale in all_locales {
println!("Checking [{}] for stale translations...", locale);
let ignore_file = |fname: &str| fname.ends_with(&output_filename);
let data = load_locales(&output_path_str, ignore_file);

Copilot uses AI. Check for mistakes.
/// Check for stale translation (translations that aren't used by the app anymore)
pub fn stale<'a, P: AsRef<Path>>(
output_path: P,
all_locales: &Vec<String>,

Copilot AI Jul 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Accepting &Vec<String> ties the function to a vector; consider using a slice &[String] or a generic impl AsRef<str> for more flexibility.

Suggested change
all_locales: &Vec<String>,
all_locales: &[String],

Copilot uses AI. Check for mistakes.
Comment thread crates/cli/src/main.rs

let output_path = Path::new(&source_path).join(&cfg.load_path);

let result = generator::stale(&output_path, &cfg.available_locales, messages.clone());

Copilot AI Jul 15, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Shadowing the variable result in the same scope can reduce readability; consider using distinct names or chaining results to avoid shadowing.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants