Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion framework/pym/play/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import shutil
import socket
import glob

from play.utils import *

Expand Down Expand Up @@ -46,7 +47,7 @@ def __init__(self, application_path, env, ignoreMissingModules = False):

def check(self):
try:
assert os.path.exists(os.path.join(self.path, 'conf', 'routes'))
assert (os.path.exists(os.path.join(self.path, 'conf', 'routes')) or len(glob.glob(os.path.join(self.path, 'conf', 'routes.??')))>0)
assert os.path.exists(os.path.join(self.path, 'conf', 'application.conf'))
except AssertionError:
print "~ Oops. conf/routes or conf/application.conf missing."
Expand Down
23 changes: 21 additions & 2 deletions framework/src/play/Play.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public boolean isProd() {
/**
* Main routes file
*/
public static VirtualFile routes;
public static List<VirtualFile> routes;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It breaks backward compatibility.
I suggest leaving VirtualFile routes untouched and adding a new field List<VirtualFile> internationalizedRoutes. In this case you don't need field multilangRouteFiles.

/**
* Plugin routes files
*/
Expand Down Expand Up @@ -182,6 +182,11 @@ public boolean isProd() {
*/
public static boolean standalonePlayServer = true;

/**
* This flag indicates that app has multiple routes files for different locales
*/
public static boolean multilangRouteFiles = false;

/**
* Init the framework
*
Expand Down Expand Up @@ -276,7 +281,7 @@ public static void init(File root, String id) {
}

// Main route file
routes = appRoot.child("conf/routes");
routes = loadRoutesFiles(appRoot);

// Plugin route files
modulesRoutes = new HashMap<>(16);
Expand Down Expand Up @@ -321,6 +326,20 @@ public static void init(File root, String id) {
Play.initialized = true;
}

private static List<VirtualFile> loadRoutesFiles(VirtualFile appRoot) {
List<VirtualFile> routes = new ArrayList<VirtualFile>();
for (VirtualFile vf: appRoot.child("conf").list()) {
String virtualFileName = vf.getName();
if(virtualFileName !=null && virtualFileName.equals("routes")){
routes.add(vf);
} else if(virtualFileName !=null && virtualFileName.matches("routes\\.[A-Za-z]{2}")){

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

language can be defined on mode character to handle country specific code ex: en_US, en_UK

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@xael-fry So routes files can have also names like that routes.en_US ?
I will do tests.

routes.add(vf);
Play.multilangRouteFiles = true;
}
}
return routes;
}

public static void guessFrameworkPath() {
// Guess the framework path
try {
Expand Down
60 changes: 51 additions & 9 deletions framework/src/play/mvc/Router.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import play.Play;
import play.Play.Mode;
import play.exceptions.NoRouteFoundException;
import play.i18n.Lang;
import play.mvc.results.NotFound;
import play.mvc.results.RenderStatic;
import play.templates.TemplateLoader;
Expand All @@ -19,6 +20,7 @@
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
Expand Down Expand Up @@ -50,7 +52,9 @@ public class Router {
public static void load(String prefix) {
routes.clear();
actionRoutesCache.clear();
parse(Play.routes, prefix);
for (VirtualFile routeFile : Play.routes) {
parse(routeFile, prefix);
}
lastLoading = System.currentTimeMillis();
// Plugins
Play.pluginCollection.onRoutesLoaded();
Expand Down Expand Up @@ -139,6 +143,7 @@ public static Route getRoute(String method, String path, String action, String p
route.routesFileLine = line;
route.addFormat(headers);
route.addParams(params);
route.setLocaleBasedOnMultilangualRoutesFile(sourceFile);
route.compute();
if (Logger.isTraceEnabled()) {
Logger.trace("Adding [" + route.toString() + "] with params [" + params + "] and headers [" + headers + "]");
Expand Down Expand Up @@ -228,14 +233,16 @@ public static void detectChanges(String prefix) {
if (Play.mode == Mode.PROD && lastLoading > 0) {
return;
}
if (Play.routes.lastModified() > lastLoading) {
load(prefix);
} else {
for (VirtualFile file : Play.modulesRoutes.values()) {
if (file.lastModified() > lastLoading) {
load(prefix);
return;
}
for (VirtualFile route : Play.routes) {
if (route.lastModified() > lastLoading) {
load(prefix);
return;
}
}
for (VirtualFile file : Play.modulesRoutes.values()) {
if (file.lastModified() > lastLoading) {
load(prefix);
return;
}
}
}
Expand Down Expand Up @@ -293,6 +300,9 @@ public static Route route(Http.Request request) {
if (request.action.equals("404")) {
throw new NotFound(route.path);
}
if(Play.multilangRouteFiles && StringUtils.isNotEmpty(route.locale) && !route.locale.equals(Lang.get())){
Lang.change(route.locale);
}
return route;
}
}
Expand Down Expand Up @@ -591,6 +601,9 @@ private static List<ActionRoute> getActionRoutes(String action) {
matchingRoutes = findActionRoutes(action);
actionRoutesCache.put(action, matchingRoutes);
}
if(Play.multilangRouteFiles){
prioritizeActionRoutesBasedOnActiveLocale(matchingRoutes);
}
return matchingRoutes;
}

Expand All @@ -617,6 +630,24 @@ private static List<ActionRoute> findActionRoutes(String action) {
return matchingRoutes;
}

private static void prioritizeActionRoutesBasedOnActiveLocale(List<Router.ActionRoute> matchingRoutes) {
if(matchingRoutes.size()==0) return;
String locale = Lang.get();
if(StringUtils.isEmpty(locale)) return;
for (int i = 0; i < matchingRoutes.size(); i++) {
Router.ActionRoute actionRoute = matchingRoutes.get(i);
if(locale.equals(actionRoute.route.locale)){
prioritizeMultilangActionRoute(matchingRoutes,i);
}
}
}

private static <ActionRoute> void prioritizeMultilangActionRoute(List<ActionRoute> t, int position){
if(position!=0) {
t.add(0, t.remove(position));
}
}

private static final class ActionRoute {
private Route route;
private Map<String, String> args = new HashMap<>(2);
Expand Down Expand Up @@ -736,6 +767,7 @@ public static class Route {
static Pattern customRegexPattern = new Pattern("\\{([a-zA-Z_][a-zA-Z_0-9]*)\\}");
static Pattern argsPattern = new Pattern("\\{<([^>]+)>([a-zA-Z_0-9]+)\\}");
static Pattern paramPattern = new Pattern("([a-zA-Z_0-9]+):'(.*)'");
String locale;

public void compute() {
this.host = "";
Expand Down Expand Up @@ -980,5 +1012,15 @@ static class Arg {
public String toString() {
return method + " " + path + " -> " + action;
}

private void setLocaleBasedOnMultilangualRoutesFile(String absolutePath){
if(StringUtils.isEmpty(absolutePath)){
return;
}
String fileName = Paths.get(absolutePath).getFileName().toString();
if(StringUtils.isNotEmpty(fileName) && fileName.matches("routes\\.[A-Za-z]{2}")){
this.locale = fileName.split("\\.")[1];
}
}
}
}