diff --git a/src/main/java/se/citerus/dddsample/infrastructure/i18n/QueryParamLocaleResolver.java b/src/main/java/se/citerus/dddsample/infrastructure/i18n/QueryParamLocaleResolver.java new file mode 100644 index 000000000..18b3f9ef4 --- /dev/null +++ b/src/main/java/se/citerus/dddsample/infrastructure/i18n/QueryParamLocaleResolver.java @@ -0,0 +1,81 @@ +package se.citerus.dddsample.infrastructure.i18n; + +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.SimpleLocaleContext; +import org.springframework.util.StringUtils; +import org.springframework.web.servlet.i18n.AbstractLocaleContextResolver; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; + +public class QueryParamLocaleResolver extends AbstractLocaleContextResolver { + private List supportedLocales; + + @Override + public LocaleContext resolveLocaleContext(HttpServletRequest request) { + String[] locales = request.getParameterMap().get("lang"); + String localeName; + if (locales != null && locales.length > 0) { + localeName = locales[0]; + } else { + return new SimpleLocaleContext(getDefaultLocale()); + } + + Locale requestLocale = convertLocaleName(localeName); + List supportedLocales = getSupportedLocales(); + if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) { + return new SimpleLocaleContext(requestLocale); + } + + Locale supportedLocale = findSupportedLocale(request, supportedLocales); + if (supportedLocale != null) { + return new SimpleLocaleContext(supportedLocale); + } + return new SimpleLocaleContext(getDefaultLocale() != null ? getDefaultLocale() : requestLocale); + } + + private Locale findSupportedLocale(HttpServletRequest request, List supportedLocales) { + Enumeration requestLocales = request.getLocales(); + Locale languageMatch = null; + while (requestLocales.hasMoreElements()) { + Locale locale = requestLocales.nextElement(); + if (supportedLocales.contains(locale)) { + if (languageMatch == null || languageMatch.getLanguage().equals(locale.getLanguage())) { + // Full match: language + country, possibly narrowed from earlier language-only match + return locale; + } + } + else if (languageMatch == null) { + // Let's try to find a language-only match as a fallback + for (Locale candidate : supportedLocales) { + if (!StringUtils.hasLength(candidate.getCountry()) && + candidate.getLanguage().equals(locale.getLanguage())) { + languageMatch = candidate; + break; + } + } + } + } + return languageMatch; + } + + private Locale convertLocaleName(String localeName) { + return localeName.contains("_") ? new Locale(localeName.split("_")[0], localeName.split("_")[1]) : new Locale(localeName); + } + + @Override + public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) { + // intentionally left blank + } + + public List getSupportedLocales() { + return supportedLocales; + } + + public void setSupportedLocales(List supportedLocales) { + this.supportedLocales = supportedLocales; + } +} diff --git a/src/main/java/se/citerus/dddsample/interfaces/InterfacesApplicationContext.java b/src/main/java/se/citerus/dddsample/interfaces/InterfacesApplicationContext.java index 3b959a8b8..19d9b2b0c 100644 --- a/src/main/java/se/citerus/dddsample/interfaces/InterfacesApplicationContext.java +++ b/src/main/java/se/citerus/dddsample/interfaces/InterfacesApplicationContext.java @@ -12,15 +12,17 @@ import org.springframework.lang.Nullable; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import org.springframework.web.servlet.i18n.FixedLocaleResolver; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import se.citerus.dddsample.application.ApplicationEvents; import se.citerus.dddsample.application.BookingService; import se.citerus.dddsample.domain.model.cargo.CargoRepository; import se.citerus.dddsample.domain.model.handling.HandlingEventRepository; import se.citerus.dddsample.domain.model.location.LocationRepository; import se.citerus.dddsample.domain.model.voyage.VoyageRepository; +import se.citerus.dddsample.infrastructure.i18n.QueryParamLocaleResolver; import se.citerus.dddsample.interfaces.booking.facade.BookingServiceFacade; import se.citerus.dddsample.interfaces.booking.facade.internal.BookingServiceFacadeImpl; import se.citerus.dddsample.interfaces.handling.file.UploadDirectoryScanner; @@ -29,6 +31,7 @@ import java.io.File; import java.lang.invoke.MethodHandles; +import java.util.List; import java.util.Locale; @Configuration @@ -48,14 +51,25 @@ public class InterfacesApplicationContext implements WebMvcConfigurer { public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); + messageSource.setDefaultEncoding("UTF-8"); return messageSource; } @Bean - public FixedLocaleResolver localeResolver() { - FixedLocaleResolver fixedLocaleResolver = new FixedLocaleResolver(); - fixedLocaleResolver.setDefaultLocale(Locale.ENGLISH); - return fixedLocaleResolver; + public LocaleResolver localeResolver() { + QueryParamLocaleResolver localeResolver = new QueryParamLocaleResolver(); + localeResolver.setSupportedLocales(List.of(Locale.ENGLISH, + Locale.SIMPLIFIED_CHINESE, + new Locale("sv", "SE"))); // add new locales here when available + localeResolver.setDefaultLocale(Locale.ENGLISH); + return localeResolver; + } + + @Bean + public LocaleChangeInterceptor localeChangeInterceptor() { + LocaleChangeInterceptor lci = new LocaleChangeInterceptor(); + lci.setParamName("lang"); + return lci; } @Bean @@ -85,6 +99,7 @@ public void addInterceptors(InterceptorRegistry registry) { OpenEntityManagerInViewInterceptor openSessionInViewInterceptor = new OpenEntityManagerInViewInterceptor(); openSessionInViewInterceptor.setEntityManagerFactory(entityManager.getEntityManagerFactory()); registry.addWebRequestInterceptor(openSessionInViewInterceptor); + registry.addInterceptor(localeChangeInterceptor()); } @Bean diff --git a/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java b/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java index 868d1723a..f66b9744c 100644 --- a/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java +++ b/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminController.java @@ -3,11 +3,13 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.context.MessageSource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.ServletRequestDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.support.RequestContextUtils; import se.citerus.dddsample.interfaces.booking.facade.BookingServiceFacade; import se.citerus.dddsample.interfaces.booking.facade.dto.CargoRoutingDTO; import se.citerus.dddsample.interfaces.booking.facade.dto.LegDTO; @@ -40,9 +42,11 @@ public final class CargoAdminController { private final BookingServiceFacade bookingServiceFacade; + private final MessageSource messageSource; - public CargoAdminController(BookingServiceFacade bookingServiceFacade) { + public CargoAdminController(BookingServiceFacade bookingServiceFacade, MessageSource messageSource) { this.bookingServiceFacade = bookingServiceFacade; + this.messageSource = messageSource; } @InitBinder @@ -54,7 +58,7 @@ private void initBinder(HttpServletRequest request, ServletRequestDataBinder bin public String registration(HttpServletRequest request, HttpServletResponse response, Map model) throws Exception { List dtoList = bookingServiceFacade.listShippingLocations(); - List unLocodeStrings = new ArrayList(); + List unLocodeStrings = new ArrayList<>(); for (LocationDTO dto : dtoList) { unLocodeStrings.add(dto.getUnLocode()); @@ -94,6 +98,7 @@ public String show(HttpServletRequest request, HttpServletResponse response, Map @RequestMapping("/selectItinerary") public String selectItinerary(HttpServletRequest request, HttpServletResponse response, Map model) throws Exception { + model.put("viewAdapter", new CargoAdminViewAdapter(messageSource, RequestContextUtils.getLocale(request))); String trackingId = request.getParameter("trackingId"); List routeCandidates = bookingServiceFacade.requestPossibleRoutesForCargo(trackingId); @@ -107,7 +112,7 @@ public String selectItinerary(HttpServletRequest request, HttpServletResponse re @RequestMapping(value = "/assignItinerary", method = RequestMethod.POST) public void assignItinerary(HttpServletRequest request, HttpServletResponse response, RouteAssignmentCommand command) throws Exception { - List legDTOs = new ArrayList(command.getLegs().size()); + List legDTOs = new ArrayList<>(command.getLegs().size()); for (RouteAssignmentCommand.LegCommand leg : command.getLegs()) { legDTOs.add(new LegDTO( leg.getVoyageNumber(), diff --git a/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminViewAdapter.java b/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminViewAdapter.java new file mode 100644 index 000000000..bc47c8377 --- /dev/null +++ b/src/main/java/se/citerus/dddsample/interfaces/booking/web/CargoAdminViewAdapter.java @@ -0,0 +1,24 @@ +package se.citerus.dddsample.interfaces.booking.web; + +import org.springframework.context.MessageSource; +import se.citerus.dddsample.interfaces.booking.facade.dto.CargoRoutingDTO; + +import java.util.Locale; + +public class CargoAdminViewAdapter { + private final MessageSource messageSource; + private final Locale locale; + + public CargoAdminViewAdapter(MessageSource messageSource, Locale locale) { + this.messageSource = messageSource; + this.locale = locale; + } + + public String getSelectItinerarySummaryText(CargoRoutingDTO cargo) { + return messageSource.getMessage("cargo.admin.itinerary.summary", new Object[]{cargo.getTrackingId(), cargo.getOrigin(), cargo.getFinalDestination()}, locale); + } + + public String getRouteCandidateCaption(Integer index) { + return messageSource.getMessage("cargo.admin.itinerary.routecandidatecaption", new Object[]{index}, locale); + } +} diff --git a/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingController.java b/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingController.java index b7eb1b604..30740deff 100644 --- a/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingController.java +++ b/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingController.java @@ -29,7 +29,7 @@ * helps us shield the domain model classes. *

* - * @see CargoTrackingViewAdapter + * @see se.citerus.dddsample.interfaces.tracking.CargoTrackingViewAdapter * @see se.citerus.dddsample.interfaces.booking.web.CargoAdminController */ @Controller @@ -63,17 +63,21 @@ private String onSubmit(final HttpServletRequest request, final TrackCommand command, final Map model, final BindingResult bindingResult) { + final Locale locale = RequestContextUtils.getLocale(request); trackCommandValidator.validate(command, bindingResult); + if (bindingResult.hasErrors()) { + bindingResult.rejectValue("trackingId", "error.required"); + return "track"; + } final TrackingId trackingId = new TrackingId(command.getTrackingId()); final Cargo cargo = cargoRepository.find(trackingId); if (cargo != null) { - final Locale locale = RequestContextUtils.getLocale(request); final List handlingEvents = handlingEventRepository.lookupHandlingHistoryOfCargo(trackingId).distinctEventsByCompletionTime(); model.put("cargo", new CargoTrackingViewAdapter(cargo, messageSource, locale, handlingEvents)); } else { - bindingResult.rejectValue("trackingId", "cargo.unknown_id", new Object[]{command.getTrackingId()}, "Unknown tracking id"); + bindingResult.rejectValue("trackingId", "cargo.unknown_id", new Object[]{command.getTrackingId()}, ""); } return "track"; } diff --git a/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingViewAdapter.java b/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingViewAdapter.java index 04ff20a57..72353fc8a 100644 --- a/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingViewAdapter.java +++ b/src/main/java/se/citerus/dddsample/interfaces/tracking/CargoTrackingViewAdapter.java @@ -24,7 +24,7 @@ public final class CargoTrackingViewAdapter { private final String FORMAT = "yyyy-MM-dd hh:mm"; private final TimeZone timeZone; - /** + /** * Constructor. * * @param cargo @@ -97,6 +97,14 @@ public String getStatusText() { return messageSource.getMessage(code, args, "[Unknown status]", locale); } + public String getEtaText() { + return messageSource.getMessage("cargo.routing.eta", new Object[]{getDestination(), getEta()}, locale); + } + + public String getStatusDescriptionText() { + return messageSource.getMessage("cargo.routing.result", new Object[]{getTrackingId(), getStatusText()}, locale); + } + /** * @return Cargo destination location. */ @@ -131,19 +139,20 @@ public String getNextExpectedActivity() { return ""; } - String text = "Next expected activity is to "; HandlingEvent.Type type = activity.type(); if (type.sameValueAs(HandlingEvent.Type.LOAD)) { - return - text + type.name().toLowerCase() + " cargo onto voyage " + activity.voyage().voyageNumber() + - " in " + activity.location().name(); - } else if (type.sameValueAs(HandlingEvent.Type.UNLOAD)) { - return - text + type.name().toLowerCase() + " cargo off of " + activity.voyage().voyageNumber() + - " in " + activity.location().name(); - } else { - return text + type.name().toLowerCase() + " cargo in " + activity.location().name(); - } + return messageSource.getMessage("cargo.routing.nextexpact." + type.name(), new Object[]{activity.voyage().voyageNumber(), activity.location().name()}, "Missing translation string", locale); + } else if (type.sameValueAs(HandlingEvent.Type.UNLOAD)) { + return messageSource.getMessage("cargo.routing.nextexpact." + type.name(), new Object[]{activity.voyage().voyageNumber(), activity.location().name()}, "Missing translation string", locale); + } else if (type.sameValueAs(HandlingEvent.Type.RECEIVE)) { + return messageSource.getMessage("cargo.routing.nextexpact." + type.name(), new Object[]{activity.location().name()}, "Missing translation string", locale); + } else if (type.sameValueAs(HandlingEvent.Type.CLAIM)) { + return messageSource.getMessage("cargo.routing.nextexpact." + type.name(), new Object[]{activity.location().name()}, "Missing translation string", locale); + } else if (type.sameValueAs(HandlingEvent.Type.CUSTOMS)) { + return messageSource.getMessage("cargo.routing.nextexpact." + type.name(), new Object[]{activity.location().name()}, "Missing translation string", locale); + } else { + return messageSource.getMessage("cargo.routing.nextexpact.unknown", null, "Missing translation string", locale); + } } /** diff --git a/src/main/java/se/citerus/dddsample/interfaces/tracking/TrackCommandValidator.java b/src/main/java/se/citerus/dddsample/interfaces/tracking/TrackCommandValidator.java index 8f8d39ebd..9d470468d 100644 --- a/src/main/java/se/citerus/dddsample/interfaces/tracking/TrackCommandValidator.java +++ b/src/main/java/se/citerus/dddsample/interfaces/tracking/TrackCommandValidator.java @@ -17,6 +17,5 @@ public boolean supports(@NonNull final Class clazz) { public void validate(@NonNull final Object object,@NonNull final Errors errors) { ValidationUtils.rejectIfEmptyOrWhitespace(errors, "trackingId", "error.required", "Required"); } - } diff --git a/src/main/resources/messages_en.properties b/src/main/resources/messages_en.properties index 356c2c2f6..47d985acd 100644 --- a/src/main/resources/messages_en.properties +++ b/src/main/resources/messages_en.properties @@ -1,13 +1,74 @@ +# this is the default language/locale cargo.status.NOT_RECEIVED=Not received cargo.status.IN_PORT=In port {0} cargo.status.ONBOARD_CARRIER=Onboard voyage {0} cargo.status.CLAIMED=Claimed cargo.status.UNKNOWN=Unknown +cargo.misrouted=Misrouted +cargo.notrouted=Not routed + deliveryHistory.eventDescription.NOT_RECEIVED=Cargo has not yet been received. deliveryHistory.eventDescription.LOAD=Loaded onto voyage {0} in {1}, at {2}. deliveryHistory.eventDescription.UNLOAD=Unloaded off voyage {0} in {1}, at {2}. deliveryHistory.eventDescription.RECEIVE=Received in {0}, at {1}. deliveryHistory.eventDescription.CLAIM=Claimed in {0}, at {1}. -deliveryHistory.eventDescription.CUSTOMS=Cleared customs in {0}, at {1}. \ No newline at end of file +deliveryHistory.eventDescription.CUSTOMS=Cleared customs in {0}, at {1}. + +booking.header=Cargo Booking and Routing +booking.listall=List all cargos +booking.booknew=Book new cargo +cargo.tracking.header=Tracking cargo +cargo.tracking.footer=This application is written by +cargo.tracking.idinput=Enter your tracking id: +cargo.tracking.submitbutton=Track! +cargo.tracking.hint=Hint: try tracking "ABC123" or "JKL567". +cargo.tracking.handlinghistory=Handling History +cargo.tracking.misdirected=Cargo is misdirected +cargo.routing.result=Cargo {0} is now: {1} +cargo.routing.eta=Estimated time of arrival in {0}: {1} +cargo.routing.nextexpact.LOAD=Next expected activity is to load cargo onto voyage {0} in {1} +cargo.routing.nextexpact.UNLOAD=Next expected activity is to unload cargo off of voyage {0} in {1} +cargo.routing.nextexpact.RECEIVE=Next expected activity is to receive cargo in {0} +cargo.routing.nextexpact.CLAIM=Next expected activity is to claim cargo in {0} +cargo.routing.nextexpact.CUSTOMS=Next expected activity is to customs cargo in {0} +cargo.routing.nextexpact.unknown=Next expected activity is unknown + +cargo.admin.header=Cargo Administration +cargo.admin.tablecaption=All cargos +cargo.admin.tableheader.trackingid=Tracking ID +cargo.admin.tableheader.origin=Origin +cargo.admin.tableheader.destination=Destination +cargo.admin.tableheader.routed=Routed +cargo.admin.tableheader.arrivaldeadline=Arrival deadline: +cargo.admin.details.caption=Details for cargo +cargo.admin.details.picknewdest=Change destination +cargo.admin.details.arrivaldeadline=Arrival deadline +cargo.admin.details.selectitinerary=Route this cargo +cargo.admin.details.reroute=reroute this cargo +cargo.admin.details.misrouted=Cargo is misrouted +cargo.admin.details.itinerary=Itinerary +cargo.admin.details.voyageno=Voyage number +cargo.admin.details.load=Load +cargo.admin.details.unload=Unload +cargo.admin.newdest.change=Change destination for cargo +cargo.admin.newdest.currentdest=Current destination +cargo.admin.newdest.newdest=New destination +cargo.admin.newdest.submit=Change destination +cargo.admin.register.caption=Book new cargo +cargo.admin.register.book=Book +cargo.admin.itinerary.caption=Select route +cargo.admin.itinerary.summary=Cargo {0} is going from {1} to {2} +cargo.admin.itinerary.noroutecandidates=No routes found that satisfy the route specification. Try setting an arrival deadline further into the future (a few weeks at least). +cargo.admin.itinerary.routecandidatecaption=Route candidate {0} +cargo.admin.itinerary.voyage=Voyage +cargo.admin.itinerary.submit=Assign cargo to this route + +misc.yes=Yes +misc.no=No +misc.from=From +misc.to=To + +error.required=The tracking id must not be empty +cargo.unknown_id=Unknown tracking id \ No newline at end of file diff --git a/src/main/resources/messages_sv.properties b/src/main/resources/messages_sv.properties new file mode 100644 index 000000000..fb231362f --- /dev/null +++ b/src/main/resources/messages_sv.properties @@ -0,0 +1,74 @@ +# Note: file encoding must be UTF-8 +cargo.status.NOT_RECEIVED=Ej mottagen +cargo.status.IN_PORT=I hamn {0} +cargo.status.ONBOARD_CARRIER=Ombord på resa {0} +cargo.status.CLAIMED=Upphämtad +cargo.status.UNKNOWN=Okänt + +cargo.misrouted=Rutt felplanerad +cargo.notrouted=Ej ruttplanerad + +deliveryHistory.eventDescription.NOT_RECEIVED=Godset har ännu ej anlänt. + +deliveryHistory.eventDescription.LOAD=Lastad på resa {0} i {1}, vid {2}. +deliveryHistory.eventDescription.UNLOAD=Avlastad från resa {0} i {1}, vid {2}. +deliveryHistory.eventDescription.RECEIVE=Mottagen i {0}, vid {1}. +deliveryHistory.eventDescription.CLAIM=Upphämtad i {0}, vid {1}. +deliveryHistory.eventDescription.CUSTOMS=Har förtullats i {0}, vid {1}. + +booking.header=Godsbokning och ruttplanering +booking.listall=Lista allt gods +booking.booknew=Boka nytt gods +cargo.tracking.header=Godsspårning +cargo.tracking.footer=Den här applikation är skapad av +cargo.tracking.idinput=Skriv in spårningsid: +cargo.tracking.submitbutton=Spåra! +cargo.tracking.hint=Tips: Prova att söka på "ABC123" eller "JKL567". +cargo.tracking.handlinghistory=Hanteringshistorik +cargo.tracking.misdirected=Godset är felskickat +cargo.routing.result=Godset {0} är nu: {1} +cargo.routing.eta=Beräknad ankomsttid till {0}: {1} +cargo.routing.nextexpact.LOAD=Nästa förväntade aktivitet är att lasta godset ombord på resa {0} i {1} +cargo.routing.nextexpact.UNLOAD=Nästa förväntade aktivitet är att lasta av godset från resa {0} i {1} +cargo.routing.nextexpact.RECEIVE=Nästa förväntade aktivitet är att motta godset in {0} +cargo.routing.nextexpact.CLAIM=Nästa förväntade aktivitet är att upphämta godset i {0} +cargo.routing.nextexpact.CUSTOMS=Nästa förväntade aktivitet är att förtulla godset i {0} +cargo.routing.nextexpact.unknown=Nästa förväntade aktivitet är okänd + +cargo.admin.header=Godsadministration +cargo.admin.tablecaption=Allt gods +cargo.admin.tableheader.trackingid=Spårningsid +cargo.admin.tableheader.origin=Ursprung +cargo.admin.tableheader.destination=Destination +cargo.admin.tableheader.routed=Ruttplanerad +cargo.admin.tableheader.arrivaldeadline=Ankomstdeadline: +cargo.admin.details.caption=Detaljer för godset +cargo.admin.details.picknewdest=Ändra destination +cargo.admin.details.arrivaldeadline=Ankomstdeadline +cargo.admin.details.selectitinerary=Ruttplanera detta gods +cargo.admin.details.reroute=omplanera rutt för detta gods +cargo.admin.details.misrouted=Godsets rutt är felplanerad +cargo.admin.details.itinerary=Resplan +cargo.admin.details.voyageno=Resenummer +cargo.admin.details.load=Lasta +cargo.admin.details.unload=Lasta av +cargo.admin.newdest.change=Ändra destination för godset {0} +cargo.admin.newdest.currentdest=Nuvarande destination +cargo.admin.newdest.newdest=Ny destination +cargo.admin.newdest.submit=Ändra destination +cargo.admin.register.caption=Boka nytt gods +cargo.admin.register.book=Boka +cargo.admin.itinerary.caption=Välj rutt +cargo.admin.itinerary.summary=Godset {0} färdas från {1} till {2} +cargo.admin.itinerary.noroutecandidates=Inga rutter hittades som uppfyller ruttspecifikationen. Prova att välja en ankomstdeadline längre in i framtiden (åtminstone ett par veckor fram). +cargo.admin.itinerary.routecandidatecaption=Ruttkandidater {0} +cargo.admin.itinerary.voyage=Resa +cargo.admin.itinerary.submit=Tilldela rutten till godset + +misc.yes=Ja +misc.no=Nej +misc.from=Från +misc.to=Till + +error.required=Spårningsid:t får inte vara tomt +cargo.unknown_id=Okänt spårningsid \ No newline at end of file diff --git a/src/main/resources/messages_zh.properties b/src/main/resources/messages_zh.properties new file mode 100644 index 000000000..fb2cae713 --- /dev/null +++ b/src/main/resources/messages_zh.properties @@ -0,0 +1,74 @@ +# Note: file encoding must be UTF-8 +cargo.status.NOT_RECEIVED=未接收 +cargo.status.IN_PORT=停泊在{0} +cargo.status.ONBOARD_CARRIER=正在上传{0} +cargo.status.CLAIMED=要求 +cargo.status.UNKNOWN=未知 + +cargo.misrouted=无效航线 +cargo.notrouted=缺乏航线 + +deliveryHistory.eventDescription.NOT_RECEIVED=船货未接收. + +deliveryHistory.eventDescription.LOAD=加货到航程{0}在{1}于{2}. +deliveryHistory.eventDescription.UNLOAD=下货从航程{0}在{1}于{2}. +deliveryHistory.eventDescription.RECEIVE=接收在{0}于{1}. +deliveryHistory.eventDescription.CLAIM=要求在{0}于{1}. +deliveryHistory.eventDescription.CUSTOMS=通关在{0}于{1}. + +booking.header=船货约定与航程管理 +booking.listall=罗列船货 +booking.booknew=约定新船货 +cargo.tracking.header=追踪船货 +cargo.tracking.footer=这个项目的作者是 +cargo.tracking.idinput=填空追踪号码: +cargo.tracking.submitbutton=追踪! +cargo.tracking.hint=提示:试试索"ABC123"或"JKL567". +cargo.tracking.handlinghistory=船货管理记录 +cargo.tracking.misdirected=无效航线的船货 +cargo.routing.result=船货{0}正在到达:{1} +cargo.routing.eta=开往{0}的预计到达时间: {1} +cargo.routing.nextexpact.LOAD=下一活动是在{1}加货到{0}航程 +cargo.routing.nextexpact.UNLOAD=下一活动是在{1}下货从{0}航程 +cargo.routing.nextexpact.RECEIVE=下一活动是在{0}接受船货 +cargo.routing.nextexpact.CLAIM=下一活动是在{0}要求船货 +cargo.routing.nextexpact.CUSTOMS=下一活动是在{0}通关 +cargo.routing.nextexpact.unknown=下一活动未知 + +cargo.admin.header=船货管理 +cargo.admin.tablecaption=所有船货 +cargo.admin.tableheader.trackingid=追踪号码 +cargo.admin.tableheader.origin=本源 +cargo.admin.tableheader.destination=终点 +cargo.admin.tableheader.routed=行程约定了 +cargo.admin.tableheader.arrivaldeadline=到达期限: +cargo.admin.details.caption=船货细节 +cargo.admin.details.picknewdest=改变终点 +cargo.admin.details.arrivaldeadline=到达期限 +cargo.admin.details.selectitinerary=选择旅程表 +cargo.admin.details.reroute=改道 +cargo.admin.details.misrouted=无效航线的船货 +cargo.admin.details.itinerary=旅程表 +cargo.admin.details.voyageno=航程号码 +cargo.admin.details.load=加货 +cargo.admin.details.unload=下货 +cargo.admin.newdest.change=改变船货的终点 +cargo.admin.newdest.currentdest=目前终点 +cargo.admin.newdest.newdest=新终点 +cargo.admin.newdest.submit=改道 +cargo.admin.register.caption=约定新船货 +cargo.admin.register.book=约定 +cargo.admin.itinerary.caption=选择航线 +cargo.admin.itinerary.summary=船货{0}从{1}到{2}途中 +cargo.admin.itinerary.noroutecandidates=找不到合格行程条件的行程。请试试选择晚一点的到达期限。 +cargo.admin.itinerary.routecandidatecaption=候选行程{0} +cargo.admin.itinerary.voyage=航程 +cargo.admin.itinerary.submit=将船货分配到行程 + +misc.yes=是 +misc.no=否 +misc.from=来自 +misc.to=开往 + +error.required=追踪号码不能空白 +cargo.unknown_id=追踪号码未知 \ No newline at end of file diff --git a/src/main/resources/static/index.html b/src/main/resources/static/index.html index beb15e274..8e8fca07c 100644 --- a/src/main/resources/static/index.html +++ b/src/main/resources/static/index.html @@ -1,20 +1,45 @@ - + - + + DDDSample + + +

+

Welcome to the DDDSample application.

+ +Select language: + +

There are two web interfaces available:

+

The Incident Logging application, that is used to register handling events, is a stand-alone application and a separate download.

Please visit the project website for more information and a screencast demonstration of how the application works.

+

This project is a joint effort by Eric Evans' company Domain Language and the Swedish software consulting company Citerus.

diff --git a/src/main/resources/static/style.css b/src/main/resources/static/style.css index b26d11128..f0073f9f7 100644 --- a/src/main/resources/static/style.css +++ b/src/main/resources/static/style.css @@ -165,7 +165,7 @@ input.button { background: #ccc; border-width: 1px; border-style: solid; - border-color: #888 #888 #8880 #888; + border-color: #888 #888 #888 #888; } input.radio { diff --git a/src/main/resources/templates/admin/list.html b/src/main/resources/templates/admin/list.html index 934f75f2b..cfb7beefc 100644 --- a/src/main/resources/templates/admin/list.html +++ b/src/main/resources/templates/admin/list.html @@ -1,10 +1,12 @@ - + - Cargo Administration + + + Cargo Administration @@ -13,13 +15,13 @@
- + - - - - + + + + @@ -30,7 +32,7 @@ - +
All cargosAll cargos
Tracking IDOriginDestinationRoutedTracking IDOriginDestinationRouted
Origin Final destinationRouted
diff --git a/src/main/resources/templates/admin/pickNewDestination.html b/src/main/resources/templates/admin/pickNewDestination.html index 92cfc426e..a7b165ccf 100644 --- a/src/main/resources/templates/admin/pickNewDestination.html +++ b/src/main/resources/templates/admin/pickNewDestination.html @@ -1,10 +1,12 @@ - + - Cargo Administration + + + Cargo Administration